/** * @licstart The following is the entire license notice for the * JavaScript code in this page * * Copyright 2022 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @licend The above is the entire license notice for the * JavaScript code in this page */ "use strict"; var _xfa_object = require("../../core/xfa/xfa_object.js"); var _bind = require("../../core/xfa/bind.js"); var _som = require("../../core/xfa/som.js"); var _parser = require("../../core/xfa/parser.js"); describe("XFAParser", function () { describe("Parse XFA", function () { it("should parse a xfa document and create an object to represent it", function () { const xml = ` 7 foobar http://a.b.c forbidden enabled http://d.e.f http://g.h.i foobar `; const attributes = { id: "", name: "", use: "", usehref: "" }; const mediumAttributes = { id: "", long: 0, orientation: "portrait", short: 0, stock: "", trayIn: "auto", trayOut: "auto", use: "", usehref: "" }; const colorAttributes = { cSpace: "SRGB", id: "", use: "", usehref: "" }; const root = new _parser.XFAParser().parse(xml); const expected = { uuid: "1234", timeStamp: "", template: { baseProfile: "full", extras: { ...attributes, float: [{ ...attributes, $content: 1.23 }, { ...attributes, $content: 2.71 }], boolean: { ...attributes, $content: 1 }, integer: { ...attributes, $content: 314 } }, subform: { access: "open", allowMacro: 0, anchorType: "topLeft", colSpan: 1, columnWidths: [0], h: "", hAlign: "left", id: "", layout: "position", locale: "", maxH: 0, maxW: 0, mergeMode: "consumeData", minH: 0, minW: 0, name: "", presence: "visible", relevant: [], restoreState: "manual", scope: "name", use: "", usehref: "", w: "", x: 0, y: 0, proto: { area: { ...attributes, colSpan: 1, x: 0, y: -226.08, relevant: [{ excluded: true, viewname: "foo" }, { excluded: false, viewname: "bar" }] }, color: [{ ...colorAttributes, value: { r: 111, g: 222, b: 123 } }, { ...colorAttributes, value: { r: 111, g: 0, b: 123 } }], medium: [{ ...mediumAttributes, imagingBBox: { x: 1, y: 144, width: 96.3779527559055, height: 5.67 } }, { ...mediumAttributes, imagingBBox: { x: -1, y: -1, width: -1, height: -1 } }] } } }, config: { acrobat: { acrobat7: { dynamicRender: { $content: "forbidden" } }, autoSave: { $content: "enabled" }, validate: { $content: "preSubmit" }, submitUrl: [{ $content: "http://a.b.c" }, { $content: "http://d.e.f" }, { $content: "http://g.h.i" }] }, present: { pdf: { name: "hello", adobeExtensionLevel: { $content: 7 } } } } }; expect(root[_xfa_object.$dump]()).toEqual(expected); }); it("should parse a xfa document and check namespaces", function () { const xml = ` 7 http://a.b.c http://c.b.a `; const root = new _parser.XFAParser().parse(xml); const expected = { uuid: "", timeStamp: "", config: { acrobat: { submitUrl: { $content: "http://c.b.a" } } } }; expect(root[_xfa_object.$dump]()).toEqual(expected); }); it("should parse a xfa document and parse CDATA when needed", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml); const exdata = (0, _som.searchNode)(root, root, "foo")[0]; const body = exdata[_xfa_object.$dump]().$content[_xfa_object.$dump](); const expected = { $name: "body", attributes: {}, children: [{ $content: "hello", $name: "span", attributes: {}, children: [] }] }; expect(body).toEqual(expected); }); it("should parse a xfa document and apply some prototypes", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml)[_xfa_object.$dump](); let font = root.template.subform.field[0].font; expect(font.typeface).toEqual("Foo"); expect(font.overline).toEqual(0); expect(font.size).toEqual(123); expect(font.weight).toEqual("bold"); expect(font.posture).toEqual("italic"); expect(font.fill.color.value).toEqual({ r: 1, g: 2, b: 3 }); expect(font.extras).toEqual(undefined); font = root.template.subform.field[1].font; expect(font.typeface).toEqual("Foo"); expect(font.overline).toEqual(0); expect(font.size).toEqual(456); expect(font.weight).toEqual("bold"); expect(font.posture).toEqual("normal"); expect(font.fill.color.value).toEqual({ r: 4, g: 5, b: 6 }); expect(font.extras.id).toEqual("id2"); }); it("should parse a xfa document and apply some prototypes through usehref", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml)[_xfa_object.$dump](); let font = root.template.subform.field[0].font; expect(font.typeface).toEqual("Foo"); expect(font.overline).toEqual(0); expect(font.size).toEqual(123); expect(font.weight).toEqual("bold"); expect(font.posture).toEqual("italic"); expect(font.fill.color.value).toEqual({ r: 1, g: 2, b: 3 }); expect(font.extras).toEqual(undefined); font = root.template.subform.field[1].font; expect(font.typeface).toEqual("Foo"); expect(font.overline).toEqual(0); expect(font.size).toEqual(456); expect(font.weight).toEqual("bold"); expect(font.posture).toEqual("normal"); expect(font.fill.color.value).toEqual({ r: 4, g: 5, b: 6 }); expect(font.extras.id).toEqual("id2"); }); it("should parse a xfa document with xhtml", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml)[_xfa_object.$dump](); const p = root.template.extras.text.$content[_xfa_object.$getChildren]()[0]; expect(p.style).toEqual("text-indent:0.5in;line-height:11px;tab-stop:left 0.5in"); expect(p[_xfa_object.$text]()).toEqual([" The first line of this paragraph is indented a half-inch.\n", " Successive lines are not indented.\n", " This is the last line of the paragraph.\n "].join("")); }); it("should parse a xfa document and apply some prototypes with cycle", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml)[_xfa_object.$dump](); const subform = root.template.subform[1]; expect(subform.id).toEqual("id1"); expect(subform.subform.id).toEqual("id1"); }); it("should parse a xfa document and apply some nested prototypes", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml)[_xfa_object.$dump](); const font = root.template.subform.field.font; expect(font.typeface).toEqual("helvetica"); expect(font.overline).toEqual(0); expect(font.size).toEqual(31); expect(font.weight).toEqual("normal"); expect(font.posture).toEqual("italic"); expect(font.fill.color.value).toEqual({ r: 7, g: 8, b: 9 }); }); it("should parse a xfa document and apply a prototype with content", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml)[_xfa_object.$dump](); let field = root.template.subform.field[0]; expect(field.value.text.$content).toEqual("default TEXT"); field = root.template.subform.field[1]; expect(field.value.text.$content).toEqual("Overriding text"); }); }); describe("Search in XFA", function () { it("should search some nodes in a template object", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml); let found = root[_xfa_object.$getChildrenByName]("subform", true); expect(found.map(x => x.id)).toEqual(["l", "m", "n", "o"]); found = root[_xfa_object.$getChildrenByName]("Total_Price", true); expect(found.map(x => x.id)).toEqual(["d", "h", "s", "k"]); found = root.template[_xfa_object.$getChildrenByName]("Receipt", false); const receipt = found[0]; found = receipt[_xfa_object.$getChildrenByName]("Total_Price", false); expect(found.map(x => x.id)).toEqual(["d", "h", "k"]); expect(receipt[_xfa_object.$getChildrenByClass]("name")).toEqual("Receipt"); const subforms = receipt[_xfa_object.$getChildrenByClass]("subform"); expect(subforms.children.map(x => x.id)).toEqual(["m", "n", "o"]); }); it("should search some nodes in a template object using SOM", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml); expect((0, _som.searchNode)(root, null, "$template..Description.id")[0][_xfa_object.$text]()).toBe("a"); expect((0, _som.searchNode)(root, null, "$template..Description.id")[0][_xfa_object.$text]()).toBe("a"); expect((0, _som.searchNode)(root, null, "$template..Description[0].id")[0][_xfa_object.$text]()).toBe("a"); expect((0, _som.searchNode)(root, null, "$template..Description[1].id")[0][_xfa_object.$text]()).toBe("e"); expect((0, _som.searchNode)(root, null, "$template..Description[2].id")[0][_xfa_object.$text]()).toBe("p"); expect((0, _som.searchNode)(root, null, "$template.Receipt.id")[0][_xfa_object.$text]()).toBe("l"); expect((0, _som.searchNode)(root, null, "$template.Receipt.Description[1].id")[0][_xfa_object.$text]()).toBe("e"); expect((0, _som.searchNode)(root, null, "$template.Receipt.Description[2]")).toBe(null); expect((0, _som.searchNode)(root, null, "$template.Receipt.foo.Description.id")[0][_xfa_object.$text]()).toBe("p"); expect((0, _som.searchNode)(root, null, "$template.#subform.Sub_Total.id")[0][_xfa_object.$text]()).toBe("i"); expect((0, _som.searchNode)(root, null, "$template.#subform.Units.id")[0][_xfa_object.$text]()).toBe("b"); expect((0, _som.searchNode)(root, null, "$template.#subform.Units.parent.id")[0][_xfa_object.$text]()).toBe("m"); }); it("should search some nodes in a datasets object", function () { const xml = ` 1 Giant Slingshot 1 250.00 250.00 2 Road Runner Bait, large bag 5 12.00 60.00 310.00 24.80 334.80 `; const root = new _parser.XFAParser().parse(xml); const data = root.datasets.data; let found = data[_xfa_object.$getChildrenByName]("Description", true); expect(found.map(x => x[_xfa_object.$text]())).toEqual(["Giant Slingshot", "Road Runner Bait, large bag"]); found = data[_xfa_object.$getChildrenByName]("Total_Price", true); expect(found.map(x => x[_xfa_object.$text]())).toEqual(["250.00", "60.00", "334.80"]); }); it("should search some nodes using SOM from a non-root node", function () { const xml = ` 1 Giant Slingshot 1 250.00 250.00 2 Road Runner Bait, large bag 5 12.00 60.00 310.00 24.80 334.80 `; const root = new _parser.XFAParser().parse(xml); const [receipt] = root.datasets.data[_xfa_object.$getChildren]("Receipt"); expect((0, _som.searchNode)(root, receipt, "Detail[*].Total_Price").map(x => x[_xfa_object.$text]())).toEqual(["250.00", "60.00"]); const [units] = (0, _som.searchNode)(root, receipt, "Detail[1].Units"); expect(units[_xfa_object.$text]()).toBe("5"); let [found] = (0, _som.searchNode)(root, units, "Total_Price"); expect(found[_xfa_object.$text]()).toBe("60.00"); found = (0, _som.searchNode)(root, units, "Total_Pric"); expect(found).toEqual(null); }); it("should search some nodes in a datasets object using SOM", function () { const xml = ` foo bar `; const root = new _parser.XFAParser().parse(xml); expect((0, _som.searchNode)(root, null, "$data.Receipt.Detail")[0][_xfa_object.$text]()).toBe("Acme"); expect((0, _som.searchNode)(root, null, "$data.Receipt.Detail[0]")[0][_xfa_object.$text]()).toBe("Acme"); expect((0, _som.searchNode)(root, null, "$data.Receipt.Detail[1]")[0][_xfa_object.$text]()).toBe("foo"); expect((0, _som.searchNode)(root, null, "$data.Receipt.Detail[2]")[0][_xfa_object.$text]()).toBe("bar"); }); }); describe("Bind data into form", function () { it("should make a basic binding", function () { const xml = ` xyz `; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "A.B.C.value.text")[0][_xfa_object.$dump]().$content).toBe("xyz"); }); it("should make a basic binding and create a non-existing node", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml); const binder = new _bind.Binder(root); const form = binder.bind(); const data = binder.getData(); expect((0, _som.searchNode)(form, form, "A.B.D.value.text")[0][_xfa_object.$dump]().$content).toBe("foobar"); const expected = { $name: "A", attributes: {}, children: [{ $name: "B", attributes: {}, children: [{ $name: "C", attributes: {}, children: [] }, { $name: "D", attributes: {}, children: [] }] }] }; expect((0, _som.searchNode)(data, data, "A")[0][_xfa_object.$dump]()).toEqual(expected); }); it("should make a basic binding and create a non-existing node with namespaceId equal to -1", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml); const binder = new _bind.Binder(root); const form = binder.bind(); const data = binder.getData(); expect((0, _som.searchNode)(form, form, "A.B.D.value.text")[0][_xfa_object.$dump]().$content).toBe("foobar"); const expected = { $name: "A", $ns: -1, attributes: {}, children: [{ $name: "B", $ns: -1, attributes: {}, children: [{ $name: "C", $ns: -1, attributes: {}, children: [] }, { $name: "D", $ns: -1, attributes: {}, children: [] }] }] }; expect((0, _som.searchNode)(data, data, "A")[0][_xfa_object.$dump](true)).toEqual(expected); }); it("should make another basic binding", function () { const xml = ` Jack Spratt 99 Candlestick Lane London UK SW1 `; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "registration.first..text")[0][_xfa_object.$dump]().$content).toBe("Jack"); expect((0, _som.searchNode)(form, form, "registration.last..text")[0][_xfa_object.$dump]().$content).toBe("Spratt"); expect((0, _som.searchNode)(form, form, "registration.apt..text")[0][_xfa_object.$dump]().$content).toBe(undefined); expect((0, _som.searchNode)(form, form, "registration.street..text")[0][_xfa_object.$dump]().$content).toBe("99 Candlestick Lane"); expect((0, _som.searchNode)(form, form, "registration.city..text")[0][_xfa_object.$dump]().$content).toBe("London"); expect((0, _som.searchNode)(form, form, "registration.country..text")[0][_xfa_object.$dump]().$content).toBe("UK"); expect((0, _som.searchNode)(form, form, "registration.postalcode..text")[0][_xfa_object.$dump]().$content).toBe("SW1"); }); it("should make basic binding with extra subform", function () { const xml = ` Jack Spratt 99 Candlestick Lane London UK SW1 `; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "registration..first..text")[0][_xfa_object.$dump]().$content).toBe("Jack"); expect((0, _som.searchNode)(form, form, "registration..last..text")[0][_xfa_object.$dump]().$content).toBe("Spratt"); expect((0, _som.searchNode)(form, form, "registration..apt..text")[0][_xfa_object.$dump]().$content).toBe(undefined); expect((0, _som.searchNode)(form, form, "registration..street..text")[0][_xfa_object.$dump]().$content).toBe("99 Candlestick Lane"); expect((0, _som.searchNode)(form, form, "registration..city..text")[0][_xfa_object.$dump]().$content).toBe("London"); expect((0, _som.searchNode)(form, form, "registration..country..text")[0][_xfa_object.$dump]().$content).toBe("UK"); expect((0, _som.searchNode)(form, form, "registration..postalcode..text")[0][_xfa_object.$dump]().$content).toBe("SW1"); }); it("should make basic binding with extra subform", function () { const xml = ` Jack Spratt
7 99 Candlestick Lane London
`; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "registration..first..text")[0][_xfa_object.$dump]().$content).toBe("Jack"); expect((0, _som.searchNode)(form, form, "registration..last..text")[0][_xfa_object.$dump]().$content).toBe("Spratt"); expect((0, _som.searchNode)(form, form, "registration..apt..text")[0][_xfa_object.$dump]().$content).toBe("7"); expect((0, _som.searchNode)(form, form, "registration..street..text")[0][_xfa_object.$dump]().$content).toBe("99 Candlestick Lane"); expect((0, _som.searchNode)(form, form, "registration..city..text")[0][_xfa_object.$dump]().$content).toBe("London"); }); it("should make basic binding with same names in different parts", function () { const xml = ` Abott Costello `; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "application.sponsor.lastname..text")[0][_xfa_object.$dump]().$content).toBe("Costello"); expect((0, _som.searchNode)(form, form, "application.lastname..text")[0][_xfa_object.$dump]().$content).toBe("Abott"); }); it("should make binding and create nodes in data", function () { const xml = ` 1 `; const root = new _parser.XFAParser().parse(xml); const binder = new _bind.Binder(root); const form = binder.bind(); const data = binder.getData(); expect((0, _som.searchNode)(form, form, "root..b..text")[0][_xfa_object.$dump]().$content).toBe("1"); expect((0, _som.searchNode)(data, data, "root.A.a")[0][_xfa_object.$dump]().$name).toBe("a"); expect((0, _som.searchNode)(data, data, "root.A.B.c")[0][_xfa_object.$dump]().$name).toBe("c"); expect((0, _som.searchNode)(data, data, "root.A.B.d")[0][_xfa_object.$dump]().$name).toBe("d"); expect((0, _som.searchNode)(data, data, "root.A.B.C.e")[0][_xfa_object.$dump]().$name).toBe("e"); expect((0, _som.searchNode)(data, data, "root.A.B.C.f")[0][_xfa_object.$dump]().$name).toBe("f"); }); it("should make binding and set properties", function () { const xml = ` foo
Give the name!
`; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "Id.LastName..text")[0][_xfa_object.$dump]().$content).toBe("foo"); expect((0, _som.searchNode)(form, form, "Id.LastName.font.typeface")[0][_xfa_object.$text]()).toBe("myfont"); expect((0, _som.searchNode)(form, form, "Id.LastName.font.size")[0][_xfa_object.$text]()).toEqual(123.4); expect((0, _som.searchNode)(form, form, "Id.LastName.assist.toolTip")[0][_xfa_object.$dump]().$content).toBe("Give the name!"); }); it("should make binding and bind items", function () { const xml = `
MC
`; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "subform.CardName.items[*].text[*]").map(x => x[_xfa_object.$text]())).toEqual(["Visa", "Mastercard", "American Express", "VISA", "MC", "AMEX"]); }); it("should make binding and bind items with a ref", function () { const xml = `
VISA MC
`; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "subform.CardName.value.text").map(x => x[_xfa_object.$text]())).toEqual(["VISA"]); expect((0, _som.searchNode)(form, form, "subform.CardName.items[*].text[*]").map(x => x[_xfa_object.$text]())).toEqual(["Visa", "Mastercard", "American Express", "VISA", "MC", "AMEX"]); }); it("should make binding with occurrences in consumeData mode", function () { const xml = `
item1
item2
`; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "root.section[*].id").map(x => x[_xfa_object.$text]())).toEqual(["section1", "section1"]); expect((0, _som.searchNode)(form, form, "root.section[*].line-item..text").map(x => x[_xfa_object.$text]())).toEqual(["item1", "item2"]); }); it("should make binding with occurrences in matchTemplate mode", function () { const xml = `
item1
item2
`; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "root.section[*].id").map(x => x[_xfa_object.$text]())).toEqual(["section1", "section1", "section2", "section2"]); expect((0, _som.searchNode)(form, form, "root.section[*].line-item..text").map(x => x[_xfa_object.$text]())).toEqual(["item1", "item2", "item1", "item2"]); }); it("should make binding and create nodes in data with some bind tag", function () { const xml = ` `; const root = new _parser.XFAParser().parse(xml); const binder = new _bind.Binder(root); binder.bind(); const data = binder.getData(); const expected = { $name: "root", children: [{ $name: "root", children: [{ $name: "foo", children: [], attributes: {} }, { $name: "bar", children: [], attributes: {} }, { $name: "bar", children: [], attributes: {} }, { $name: "bar", children: [], attributes: {} }], attributes: {} }], attributes: {} }; expect((0, _som.searchNode)(data, data, "root")[0][_xfa_object.$dump]()).toEqual(expected); }); it("should make a binding with a bindItems", function () { const xml = ` 1 2 3 4 5 `; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "A.B.C.items[0].text[*]").map(x => x[_xfa_object.$dump]().$content)).toEqual(["1", "2", "3", "4", "5"]); expect((0, _som.searchNode)(form, form, "A.B.C.items[1].text[*]").map(x => x[_xfa_object.$dump]().$content)).toEqual(["a", "b", "c", "d", "e"]); }); }); it("should make a binding with a element in an area", function () { const xml = ` foobar `; const root = new _parser.XFAParser().parse(xml); const form = new _bind.Binder(root).bind(); expect((0, _som.searchNode)(form, form, "A..B..text")[0][_xfa_object.$dump]().$content).toBe("foobar"); }); });