diff --git a/src/helpers/attributeParser.ts b/src/helpers/attributeParser.ts index 7bba61e..18f6659 100644 --- a/src/helpers/attributeParser.ts +++ b/src/helpers/attributeParser.ts @@ -160,7 +160,13 @@ export const parseJsonAttributes = ({ return finalAttributes; } catch (error) { console.error(error); - throw new Error("Error parsing new json_attrs. Original string: " + attrs); + if (error instanceof SyntaxError) { + throw new Error( + "Error parsing new json_attrs. Original string: " + attrs, + ); + } else { + throw error; + } } }; @@ -169,21 +175,18 @@ const evaluateAttributes = ({ values, fields, widgetType, + fallbackMode = true, }: { tagAttributes: any; values: any; fields: any; widgetType?: string; + fallbackMode?: boolean; }) => { - let newTagAttributes = {}; - - if (tagAttributes.json_attrs) { - newTagAttributes = parseJsonAttributes({ - attrs: tagAttributes.json_attrs, - values, - }); - } else if (tagAttributes.attrs) { - newTagAttributes = parseAttributes({ + let finalTagAttributes = {}; + let oldTagAttributes = {}; + if (tagAttributes.attrs) { + oldTagAttributes = parseAttributes({ attrs: tagAttributes.attrs, values, fields, @@ -191,9 +194,26 @@ const evaluateAttributes = ({ }); } + if (tagAttributes.json_attrs) { + try { + finalTagAttributes = parseJsonAttributes({ + attrs: tagAttributes.json_attrs, + values, + }); + } catch (error) { + if (fallbackMode && tagAttributes.attrs) { + finalTagAttributes = oldTagAttributes; + } else { + throw error; + } + } + } else if (tagAttributes.attrs) { + finalTagAttributes = oldTagAttributes; + } + return { ...tagAttributes, - ...newTagAttributes, + ...finalTagAttributes, attrs: undefined, json_attrs: undefined, }; diff --git a/src/spec/Form.spec.ts b/src/spec/Form.spec.ts index 3a4a4df..f9b2f67 100644 --- a/src/spec/Form.spec.ts +++ b/src/spec/Form.spec.ts @@ -3259,4 +3259,33 @@ describe("A Form", () => { const buttonWidget = form.findById("example_button") as Button; expect(buttonWidget.readOnly).toBeFalsy(); }); + it("Should be able to parse a specifically enabled button even though in the form is disabled, with json_attrs", () => { + const arch = `
`; + const form = new Form({ + state: { + selection: [ + ["esborrany", "Esborrany"], + ["actiu", "Actiu"], + ["pendent", "Pendent d'activació"], + ["baixa", "Baixa"], + ["baixa2", "Baixa per modificació"], + ["baixa3", "Baixa per renovació"], + ["baixa4", "Baixa per nova pòlissa"], + ], + string: "Estat", + type: "selection", + views: {}, + }, + }); + form.parse(arch, { + readOnly: true, + values: { + state: "actiu", + }, + }); + const buttonWidget = form.findById("example_button") as Button; + expect(buttonWidget.readOnly).toBeFalsy(); + }); }); diff --git a/src/spec/attributeParser.spec.ts b/src/spec/attributeParser.spec.ts index 9a86a0d..e0814e8 100644 --- a/src/spec/attributeParser.spec.ts +++ b/src/spec/attributeParser.spec.ts @@ -39,7 +39,7 @@ const fields = { }; describe("An Attribute Parser", () => { - describe("in evaluateAttributes method", () => { + describe("in evaluateAttributes method with attrs", () => { it("should properly parse a simple attribute with = operator", () => { const tagAttributes = { attrs: "{'invisible':[('per_enviar', '=', 'postal')]}", @@ -277,4 +277,215 @@ describe("An Attribute Parser", () => { ).toStrictEqual({ invisible: true }); }); }); + describe("in evaluateAttributes method with json_attrs", () => { + it("should properly parse a simple attribute with = operator", () => { + const tagAttributes = { + json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "per_enviar", "operator": "=", "value": "postal"}]}}`, + }; + const values = { + per_enviar: "postal", + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + it("should properly parse a simple attribute with == operator and numeric value", () => { + const tagAttributes = { + json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "check_total", "operator": "==", "value": 0.0}]}}`, + }; + const values = { + check_total: 0.0, + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + it("should properly parse a simple attribute with 'in' operator", () => { + const tagAttributes = { + json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "rectificative_type", "operator": "in", "value": ["N", "C", "G"]}]}}`, + }; + const values = { + rectificative_type: "G", + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + it("should properly parse a simple attribute with 'not_in' operator", () => { + const tagAttributes = { + json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "type", "operator": "not in", "value": ["in_refund", "in_invoice"]}]}}`, + }; + const values = { + type: "not_found_type", + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + it("should properly parse a boolean attribute with '>' operator", () => { + const tagAttributes = { + json_attrs: `{"readonly": {"condition": "AND", "rules": [{"field": "force_potencia_adscrita", "operator": ">", "value": 0}]}}`, + }; + const values = { + force_potencia_adscrita: 10, + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.readonly).toBeTruthy(); + }); + it("should properly parse a boolean attribute with '<' operator", () => { + const tagAttributes = { + json_attrs: `{"readonly": {"condition": "AND", "rules": [{"field": "force_potencia_adscrita", "operator": "<", "value": 10}]}}`, + }; + const values = { + force_potencia_adscrita: 5, + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.readonly).toBeTruthy(); + }); + it("should properly parse a boolean attribute with '=' operator", () => { + const tagAttributes = { + json_attrs: `{"readonly": {"condition": "AND", "rules": [{"field": "force_potencia_adscrita", "operator": "=", "value": 0}]}}`, + }; + const values = { + force_potencia_adscrita: true, + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.readonly).toBeFalsy(); + }); + it("should properly parse a boolean attribute with '=' operator with True", () => { + const tagAttributes = { + json_attrs: `{"readonly": {"condition": "AND", "rules": [{"field": "force_potencia_adscrita", "operator": "=", "value": true}]}}`, + }; + const values = { + force_potencia_adscrita: true, + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.readonly).toBeTruthy(); + }); + it("should properly parse a boolean attribute with several conditions", () => { + const tagAttributes = { + json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "id", "operator": "!=", "value": false}, {"field": "link", "operator": "!=", "value": false}]}}`, + }; + const values = { + id: 1, + link: false, + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeFalsy(); + }); + it("should properly parse a boolean attribute without value (default false)", () => { + const tagAttributes = { + json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "change_adm", "operator": "!=", "value": true}]}}`, + }; + const values = {}; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + // TODO: This test is failing + it.skip("should properly parse a boolean attribute without value (default true)", () => { + const tagAttributes = { + json_attrs: `{"invisible": {"condition": "AND", "rules": [{"field": "change_adm", "operator": "=", "value": false}]}}`, + }; + const values = {}; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + it("should properly parse a many2one attribute with false value", () => { + const tagAttributes = { + json_attrs: + '{"invisible":{"condition":"AND","rules":[{"field":"autoconsum_id","operator":"=","value":false}]}}', + }; + const values = { autoconsum_id: false }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + // TODO: This test is failing + it.skip("should properly parse a many2one attribute with undefined value", () => { + const tagAttributes = { + json_attrs: + '{"invisible":{"condition":"AND","rules":[{"field":"autoconsum_id","operator":"=","value":false}]}}', + }; + const values = { autoconsum_id: undefined }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + fallbackMode: false, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + }); + describe("in evaluateAttributes method with faulty json_attrs and attrs ", () => { + it("it should fallback to use attrs when json_attrs is faulty", () => { + const tagAttributes = { + attrs: "{'invisible':[('per_enviar', '=', 'postal')]}", + json_attrs: "faulty", + }; + const values = { + per_enviar: "postal", + }; + const evaluatedAttrs = evaluateAttributes({ + tagAttributes, + values, + fields, + }); + expect(evaluatedAttrs.invisible).toBeTruthy(); + }); + }); });