Skip to content

Commit

Permalink
Merge branch 'feature/json-attrs-testing-and-improvement' into alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
mguellsegarra committed Nov 27, 2023
2 parents 4d36201 + 9b68836 commit d31bea8
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 61 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"analyze": "npx vite-bundle-visualizer"
},
"dependencies": {
"@gisce/conscheck": "1.0.5",
"@gisce/conscheck": "1.0.7",
"html-entities": "^2.3.3",
"moment": "^2.29.3",
"txml": "^5.1.1"
Expand Down
156 changes: 108 additions & 48 deletions src/helpers/attributeParser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { decode } from "html-entities";
import {
Condition,
FieldComparisonParams,
FieldComparisonResult,
evaluateCondition as evaluateConscheckCondition,
} from "@gisce/conscheck";

Expand All @@ -20,79 +22,122 @@ const evaluateCondition = ({
values: any;
fields: any;
}) => {
const [fieldName, operator, expectedValue] = entry;
let [fieldName, operator, expectedValue] = entry;
let valueInObject = values[fieldName];

const comparisonResult = evaluateFieldComparison({
fieldName,
valueInObject,
expectedValue,
fields,
});

if (comparisonResult.directOutcome !== undefined) {
return comparisonResult.directOutcome;
}
if (comparisonResult.modifiedValueInObject !== null) {
valueInObject = comparisonResult.modifiedValueInObject;
}
if (comparisonResult.modifiedExpectedValue !== null) {
expectedValue = comparisonResult.modifiedExpectedValue;
}

switch (operator.toLowerCase()) {
case "=":
case "==":
return valueInObject == expectedValue;
case "<>":
case "!=":
return valueInObject != expectedValue;
case ">":
return valueInObject > expectedValue;
case ">=":
return valueInObject >= expectedValue;
case "<":
return valueInObject < expectedValue;
case "<=":
return valueInObject <= expectedValue;
case "in":
return expectedValue.includes(valueInObject);
case "not in":
return !expectedValue.includes(valueInObject);
default:
return false;
}
};

const replaceEntities = (string: string): string => {
return decode(string, { level: "xml" });
};

const evaluateFieldComparison = ({
fieldName,
valueInObject,
expectedValue,
fields = {},
}: FieldComparisonParams & { fields: any }): FieldComparisonResult => {
const result: FieldComparisonResult = {
modifiedValueInObject: valueInObject,
modifiedExpectedValue: null,
directOutcome: undefined,
};

if (fields[fieldName] === undefined) {
return false;
return {
modifiedValueInObject: null,
modifiedExpectedValue: null,
directOutcome: false,
};
}

if (
values[fieldName] === undefined &&
valueInObject === undefined &&
fields[fieldName].type !== "boolean" &&
fields[fieldName].type !== "many2one"
) {
return false;
return {
modifiedValueInObject: null,
modifiedExpectedValue: null,
directOutcome: false,
};
}

let filteredExpectedValue = expectedValue;

let value =
fields[fieldName].type === "boolean"
? !!values[fieldName]
: values[fieldName];
result.modifiedValueInObject =
fields[fieldName].type === "boolean" ? !!valueInObject : valueInObject;

if (
fields[fieldName].type === "many2one" &&
expectedValue === false &&
values[fieldName] === undefined
valueInObject === undefined
) {
filteredExpectedValue = undefined;
result.modifiedExpectedValue = undefined;
} else {
value = value === undefined ? false : value;
value = value === null ? false : value;
result.modifiedValueInObject =
result.modifiedValueInObject === undefined
? false
: result.modifiedValueInObject;
result.modifiedValueInObject =
result.modifiedValueInObject === null
? false
: result.modifiedValueInObject;
}

if (
fields[fieldName].type === "many2one" &&
Array.isArray(value) &&
value[0] === undefined
Array.isArray(result.modifiedValueInObject) &&
result.modifiedValueInObject[0] === undefined
) {
value = false;
result.modifiedValueInObject = false;
}

if (
fields[fieldName].type === "boolean" &&
(expectedValue === 0 || expectedValue === 1)
) {
filteredExpectedValue = expectedValue !== 0;
result.modifiedExpectedValue = expectedValue !== 0;
}

switch (operator.toLowerCase()) {
case "=":
case "==":
return value == filteredExpectedValue;
case "<>":
case "!=":
return value != filteredExpectedValue;
case ">":
return value > filteredExpectedValue;
case ">=":
return value >= filteredExpectedValue;
case "<":
return value < filteredExpectedValue;
case "<=":
return value <= filteredExpectedValue;
case "in":
return filteredExpectedValue.includes(value);
case "not in":
return !filteredExpectedValue.includes(value);
default:
return false;
}
};

const replaceEntities = (string: string): string => {
return decode(string, { level: "xml" });
return result;
};

const parseAttributes = ({
Expand Down Expand Up @@ -140,9 +185,11 @@ const parseAttributes = ({
export const parseJsonAttributes = ({
attrs,
values,
fields,
}: {
attrs: string;
values: any;
fields: any;
}) => {
try {
const attrsWithReplacedEntities = replaceEntities(attrs);
Expand All @@ -151,10 +198,22 @@ export const parseJsonAttributes = ({
) as JsonAttributes;
const finalAttributes: Record<string, boolean> = {};
for (const attrField of Object.keys(jsonAttributes)) {
finalAttributes[attrField] = evaluateConscheckCondition(
values,
jsonAttributes[attrField],
);
finalAttributes[attrField] = evaluateConscheckCondition({
object: values,
condition: jsonAttributes[attrField],
evaluateFieldComparison: ({
fieldName,
valueInObject,
expectedValue,
}: FieldComparisonParams) => {
return evaluateFieldComparison({
fieldName,
valueInObject,
expectedValue,
fields,
});
},
});
}

return finalAttributes;
Expand Down Expand Up @@ -199,6 +258,7 @@ const evaluateAttributes = ({
finalTagAttributes = parseJsonAttributes({
attrs: tagAttributes.json_attrs,
values,
fields,
});
} catch (error) {
if (fallbackMode && tagAttributes.attrs) {
Expand Down
33 changes: 28 additions & 5 deletions src/spec/attributeParser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,22 +257,47 @@ describe("An Attribute Parser", () => {
'{"invisible":{"condition":"OR","rules":[{"field":"age","operator":"<","value":18},{"field":"citizenship","operator":"=","value":false}]}}';
const sampleObject = { age: 17, citizenship: false };
expect(
parseJsonAttributes({ attrs: stringJson, values: sampleObject }),
parseJsonAttributes({
attrs: stringJson,
values: sampleObject,
fields: {
age: { type: "integer" },
citizenship: { type: "boolean" },
},
}),
).toStrictEqual({ invisible: true });
});
it("should properly parse attributes with special entities and singlequotes", () => {
const fields = {
state: {
selection: [
["esborrany", "Esborrany"],
["actiu", "Actiu"],
["pending", "Pendent d'activació"],
["baixa", "Baixa"],
["installed", "instalat"],
["baixa3", "Baixa per renovació"],
["baixa4", "Baixa per nova pòlissa"],
],
string: "Estat",
type: "selection",
views: {},
},
};
const stringJson =
"{&quot;invisible&quot;: {&quot;rules&quot;: [{&quot;operator&quot;: &quot;!=&quot;, &quot;field&quot;: &quot;state&quot;, &quot;value&quot;: &quot;installed&quot;}], &quot;condition&quot;: &quot;AND&quot;}}";
expect(
parseJsonAttributes({
attrs: stringJson,
values: { state: "installed" },
fields,
}),
).toStrictEqual({ invisible: false });
expect(
parseJsonAttributes({
attrs: stringJson,
values: { state: "pending" },
fields,
}),
).toStrictEqual({ invisible: true });
});
Expand Down Expand Up @@ -427,8 +452,7 @@ describe("An Attribute Parser", () => {
});
expect(evaluatedAttrs.invisible).toBeTruthy();
});
// TODO: This test is failing
it.skip("should properly parse a boolean attribute without value (default true)", () => {
it("should properly parse a boolean attribute without value (default true)", () => {
const tagAttributes = {
json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "change_adm", "operator": "=", "value": false}]}}`,
};
Expand All @@ -455,8 +479,7 @@ describe("An Attribute Parser", () => {
});
expect(evaluatedAttrs.invisible).toBeTruthy();
});
// TODO: This test is failing
it.skip("should properly parse a many2one attribute with undefined value", () => {
it("should properly parse a many2one attribute with undefined value", () => {
const tagAttributes = {
json_attrs:
'{"invisible":{"condition":"AND","rules":[{"field":"autoconsum_id","operator":"=","value":false}]}}',
Expand Down

0 comments on commit d31bea8

Please sign in to comment.