/* Copyright 2020 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. */ import { isNodeJS } from "../../src/shared/is_node.js"; import { XFAFactory } from "../../src/core/xfa/factory.js"; describe("XFAFactory", function () { function searchHtmlNode(root, name, value, byAttributes = false, nth = [0]) { if ( (!byAttributes && root[name] === value) || (byAttributes && root.attributes && root.attributes[name] === value) ) { if (nth[0]-- === 0) { return root; } } if (!root.children) { return null; } for (const child of root.children) { const node = searchHtmlNode(child, name, value, byAttributes, nth); if (node) { return node; } } return null; } describe("toHTML", function () { it("should convert some basic properties to CSS", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); factory.setFonts([]); expect(await factory.getNumPages()).toEqual(2); const pages = await factory.getPages(); const page1 = pages.children[0]; expect(page1.attributes.style).toEqual({ height: "789px", width: "456px", }); expect(page1.children.length).toEqual(2); const container = page1.children[1]; expect(container.attributes.class).toEqual(["xfaContentarea"]); expect(container.attributes.style).toEqual({ height: "789px", width: "456px", left: "123px", top: "0px", }); const wrapper = page1.children[0]; const draw = wrapper.children[0]; expect(wrapper.attributes.class).toEqual(["xfaWrapper"]); expect(wrapper.attributes.style).toEqual({ alignSelf: "start", height: "22px", left: "2px", position: "absolute", top: "1px", transform: "rotate(-90deg)", transformOrigin: "top left", width: "11px", }); expect(draw.attributes.class).toEqual([ "xfaDraw", "xfaFont", "xfaWrapped", ]); expect(draw.attributes.title).toEqual("A tooltip !!"); expect(draw.attributes.style).toEqual({ color: "#0c1722", fontFamily: '"FooBar"', fontKerning: "none", letterSpacing: "0px", fontStyle: "normal", fontWeight: "normal", fontSize: "6.93px", padding: "1px 4px 2px 3px", verticalAlign: "2px", }); // draw element must be on each page. expect(draw.attributes.style).toEqual( pages.children[1].children[0].children[0].attributes.style ); }); it("should have an alt attribute from toolTip", async () => { if (isNodeJS) { pending("Image is not supported in Node.js."); } const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const field = searchHtmlNode(pages, "name", "img"); expect(field.attributes.alt).toEqual("alt text"); }); it("should have a aria heading role and level", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const page1 = pages.children[0]; const wrapper = page1.children[0]; const draw = wrapper.children[0]; expect(draw.attributes.role).toEqual("heading"); expect(draw.attributes["aria-level"]).toEqual("2"); }); it("should have aria table role", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); factory.setFonts([]); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const table = searchHtmlNode( pages, "xfaName", "table", /* byAttributes */ true ); expect(table.attributes.role).toEqual("table"); const headerRow = searchHtmlNode( pages, "xfaName", "row1", /* byAttributes */ true ); expect(headerRow.attributes.role).toEqual("row"); const headerCell = searchHtmlNode( pages, "xfaName", "header2", /* byAttributes */ true ); expect(headerCell.attributes.role).toEqual("columnheader"); const row = searchHtmlNode( pages, "xfaName", "row2", /* byAttributes */ true ); expect(row.attributes.role).toEqual("row"); const cell = searchHtmlNode( pages, "xfaName", "cell2", /* byAttributes */ true ); expect(cell.attributes.role).toEqual("cell"); }); it("should have a maxLength property", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const field = searchHtmlNode(pages, "name", "input"); expect(field.attributes.maxLength).toEqual(123); }); it("should have an aria-label property from speak", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const field = searchHtmlNode(pages, "name", "input"); expect(field.attributes["aria-label"]).toEqual("Screen Reader"); }); it("should have an aria-label property from toolTip", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const field = searchHtmlNode(pages, "name", "input"); expect(field.attributes["aria-label"]).toEqual("Screen Reader"); }); it("should have an input or textarea", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const field1 = searchHtmlNode(pages, "name", "input"); expect(field1).not.toEqual(null); const field2 = searchHtmlNode(pages, "name", "textarea"); expect(field2).not.toEqual(null); }); }); it("should have an input or textarea", async () => { const xml = ` 123 `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); const field1 = searchHtmlNode(pages, "name", "input"); expect(field1).not.toEqual(null); expect(field1.attributes.value).toEqual("123"); }); it("should parse URLs correctly", async () => { function getXml(href) { return ` `; } let factory, pages, a; // A valid, and complete, URL. factory = new XFAFactory({ "xdp:xdp": getXml("https://www.example.com/") }); expect(await factory.getNumPages()).toEqual(1); pages = await factory.getPages(); a = searchHtmlNode(pages, "name", "a"); expect(a.value).toEqual("https://www.example.com/"); expect(a.attributes.href).toEqual("https://www.example.com/"); // A valid, but incomplete, URL. factory = new XFAFactory({ "xdp:xdp": getXml("www.example.com/") }); expect(await factory.getNumPages()).toEqual(1); pages = await factory.getPages(); a = searchHtmlNode(pages, "name", "a"); expect(a.value).toEqual("www.example.com/"); expect(a.attributes.href).toEqual("http://www.example.com/"); // A valid email-address. factory = new XFAFactory({ "xdp:xdp": getXml("mailto:test@example.com") }); expect(await factory.getNumPages()).toEqual(1); pages = await factory.getPages(); a = searchHtmlNode(pages, "name", "a"); expect(a.value).toEqual("mailto:test@example.com"); expect(a.attributes.href).toEqual("mailto:test@example.com"); // Not a valid URL. factory = new XFAFactory({ "xdp:xdp": getXml("qwerty/") }); expect(await factory.getNumPages()).toEqual(1); pages = await factory.getPages(); a = searchHtmlNode(pages, "name", "a"); expect(a.value).toEqual("qwerty/"); expect(a.attributes.href).toEqual(""); }); it("should replace button with an URL by a link", async () => { const xml = ` `; const factory = new XFAFactory({ "xdp:xdp": xml }); expect(await factory.getNumPages()).toEqual(1); const pages = await factory.getPages(); let a = searchHtmlNode(pages, "name", "a"); expect(a.attributes.href).toEqual("https://github.com/mozilla/pdf.js"); expect(a.attributes.newWindow).toEqual(true); a = searchHtmlNode(pages, "name", "a", false, [1]); expect(a.attributes.href).toEqual("https://github.com/allizom/pdf.js"); expect(a.attributes.newWindow).toEqual(false); }); });