pdf.js/test/integration/test_utils.mjs
Calixte Denizet 09b4fe6a30 Get the field name from its parent when it doesn't have one when collecting fields (bug 1864136)
Some fields, somewhere under the Fields entry in Acroform, could have no name (in T)
but with a parent which has a name but which isn't somewhere under Fields.
As a side-effect, this patch prevents infinite loops because of potential cycles
under Fields.
2023-11-13 14:41:14 +01:00

461 lines
12 KiB
JavaScript

/* 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 os from "os";
const isMac = os.platform() === "darwin";
function loadAndWait(filename, selector, zoom, pageSetup) {
return Promise.all(
global.integrationSessions.map(async session => {
const page = await session.browser.newPage();
// In order to avoid errors because of checks which depend on
// a locale.
await page.evaluateOnNewDocument(() => {
Object.defineProperty(navigator, "language", {
get() {
return "en-US";
},
});
Object.defineProperty(navigator, "languages", {
get() {
return ["en-US", "en"];
},
});
});
const url = `${
global.integrationBaseUrl
}?file=/test/pdfs/${filename}#zoom=${zoom ?? "page-fit"}`;
await page.goto(url);
if (pageSetup) {
await pageSetup(page);
}
await page.bringToFront();
await page.waitForSelector(selector, {
timeout: 0,
});
return [session.name, page];
})
);
}
function closePages(pages) {
return Promise.all(
pages.map(async ([_, page]) => {
// Avoid to keep something from a previous test.
await page.evaluate(() => window.localStorage.clear());
await page.close();
})
);
}
async function clearInput(page, selector) {
await page.click(selector);
await kbSelectAll(page);
await page.keyboard.press("Backspace");
await page.waitForTimeout(10);
}
function getSelector(id) {
return `[data-element-id="${id}"]`;
}
function getQuerySelector(id) {
return `document.querySelector('${getSelector(id)}')`;
}
function getComputedStyleSelector(id) {
return `getComputedStyle(${getQuerySelector(id)})`;
}
function getEditorSelector(n) {
return `#pdfjs_internal_editor_${n}`;
}
function getSelectedEditors(page) {
return page.evaluate(() => {
const elements = document.querySelectorAll(".selectedEditor");
const results = [];
for (const { id } of elements) {
results.push(parseInt(id.split("_").at(-1)));
}
results.sort();
return results;
});
}
async function waitForEvent(page, eventName, timeout = 5000) {
const hasTimedout = await Promise.race([
// add event listener and wait for event to fire before returning
page.evaluate(
name =>
new Promise(resolve => {
document.addEventListener(name, () => resolve(false), { once: true });
}),
eventName
),
page.evaluate(
timeOut =>
new Promise(resolve => {
setTimeout(() => resolve(true), timeOut);
}),
timeout
),
]);
if (hasTimedout === true) {
console.log(`waitForEvent: timeout waiting for ${eventName}`);
}
}
async function waitForStorageEntries(page, nEntries) {
return page.waitForFunction(
n => window.PDFViewerApplication.pdfDocument.annotationStorage.size === n,
{},
nEntries
);
}
async function waitForSerialized(page, nEntries) {
return page.waitForFunction(
n =>
(window.PDFViewerApplication.pdfDocument.annotationStorage.serializable
.map?.size ?? 0) === n,
{},
nEntries
);
}
async function waitForSelectedEditor(page, selector) {
return page.waitForSelector(`${selector}.selectedEditor`);
}
async function waitForUnselectedEditor(page, selector) {
return page.waitForSelector(`${selector}:not(.selectedEditor)`);
}
async function mockClipboard(pages) {
return Promise.all(
pages.map(async ([_, page]) => {
await page.evaluate(() => {
let data = null;
const clipboard = {
writeText: async text => (data = text),
readText: async () => data,
};
Object.defineProperty(navigator, "clipboard", { value: clipboard });
});
})
);
}
async function getSerialized(page, filter = undefined) {
const values = await page.evaluate(() => {
const { map } =
window.PDFViewerApplication.pdfDocument.annotationStorage.serializable;
return map ? [...map.values()] : [];
});
return filter ? values.map(filter) : values;
}
async function getFirstSerialized(page, filter = undefined) {
return (await getSerialized(page, filter))[0];
}
function getAnnotationStorage(page) {
return page.evaluate(() =>
Object.fromEntries(
window.PDFViewerApplication.pdfDocument.annotationStorage.serializable.map?.entries() ||
[]
)
);
}
function waitForEntryInStorage(page, key, value) {
return page.waitForFunction(
(k, v) => {
const { map } =
window.PDFViewerApplication.pdfDocument.annotationStorage.serializable;
return map && JSON.stringify(map.get(k)) === v;
},
{},
key,
JSON.stringify(value)
);
}
function getEditors(page, kind) {
return page.evaluate(aKind => {
const elements = document.querySelectorAll(`.${aKind}Editor`);
const results = [];
for (const { id } of elements) {
results.push(id);
}
return results;
}, kind);
}
function getEditorDimensions(page, id) {
return page.evaluate(n => {
const element = document.getElementById(`pdfjs_internal_editor_${n}`);
const { style } = element;
return {
left: style.left,
top: style.top,
width: style.width,
height: style.height,
};
}, id);
}
async function serializeBitmapDimensions(page) {
await page.waitForFunction(() => {
try {
const map =
window.PDFViewerApplication.pdfDocument.annotationStorage.serializable
.map;
return !!map;
} catch {
return false;
}
});
return page.evaluate(() => {
const { map } =
window.PDFViewerApplication.pdfDocument.annotationStorage.serializable;
return map
? Array.from(map.values(), x => {
return { width: x.bitmap.width, height: x.bitmap.height };
})
: [];
});
}
async function dragAndDropAnnotation(page, startX, startY, tX, tY) {
await page.mouse.move(startX, startY);
await page.mouse.down();
await page.waitForTimeout(10);
await page.mouse.move(startX + tX, startY + tY);
await page.mouse.up();
await page.waitForSelector("#viewer:not(.noUserSelect)");
}
async function waitForAnnotationEditorLayer(page) {
return page.evaluate(() => {
return new Promise(resolve => {
window.PDFViewerApplication.eventBus.on(
"annotationeditorlayerrendered",
resolve
);
});
});
}
async function waitForTextLayer(page) {
return page.evaluate(() => {
return new Promise(resolve => {
window.PDFViewerApplication.eventBus.on("textlayerrendered", resolve);
});
});
}
async function scrollIntoView(page, selector) {
await page.evaluate(sel => {
const element = document.querySelector(sel);
element.scrollIntoView({ behavior: "instant", block: "start" });
return new Promise(resolve => {
document
.getElementById("viewerContainer")
.addEventListener("scrollend", resolve, { once: true });
});
}, selector);
}
async function hover(page, selector) {
const rect = await page.$eval(selector, el => {
const { x, y, width, height } = el.getBoundingClientRect();
return { x, y, width, height };
});
await page.mouse.move(rect.x + rect.width / 2, rect.y + rect.height / 2);
}
const modifier = isMac ? "Meta" : "Control";
async function kbCopy(page) {
await page.keyboard.down(modifier);
await page.keyboard.press("c", { commands: ["Copy"] });
await page.keyboard.up(modifier);
}
async function kbPaste(page) {
await page.keyboard.down(modifier);
await page.keyboard.press("v", { commands: ["Paste"] });
await page.keyboard.up(modifier);
}
async function kbUndo(page) {
await page.keyboard.down(modifier);
await page.keyboard.press("z");
await page.keyboard.up(modifier);
}
async function kbRedo(page) {
if (isMac) {
await page.keyboard.down("Meta");
await page.keyboard.down("Shift");
await page.keyboard.press("z");
await page.keyboard.up("Shift");
await page.keyboard.up("Meta");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("y");
await page.keyboard.up("Control");
}
}
async function kbSelectAll(page) {
await page.keyboard.down(modifier);
await page.keyboard.press("a", { commands: ["SelectAll"] });
await page.keyboard.up(modifier);
}
async function kbModifierDown(page) {
await page.keyboard.down(modifier);
}
async function kbModifierUp(page) {
await page.keyboard.up(modifier);
}
async function kbGoToEnd(page) {
if (isMac) {
await page.keyboard.down("Meta");
await page.keyboard.press("ArrowDown", {
commands: ["MoveToEndOfDocument"],
});
await page.keyboard.up("Meta");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("End");
await page.keyboard.up("Control");
}
}
async function kbGoToBegin(page) {
if (isMac) {
await page.keyboard.down("Meta");
await page.keyboard.press("ArrowUp", {
commands: ["MoveToBeginningOfDocument"],
});
await page.keyboard.up("Meta");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("Home");
await page.keyboard.up("Control");
}
}
async function kbBigMoveLeft(page) {
if (isMac) {
await page.keyboard.down("Shift");
await page.keyboard.press("ArrowLeft");
await page.keyboard.up("Shift");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("ArrowLeft");
await page.keyboard.up("Control");
}
}
async function kbBigMoveRight(page) {
if (isMac) {
await page.keyboard.down("Shift");
await page.keyboard.press("ArrowRight");
await page.keyboard.up("Shift");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("ArrowRight");
await page.keyboard.up("Control");
}
}
async function kbBigMoveUp(page) {
if (isMac) {
await page.keyboard.down("Shift");
await page.keyboard.press("ArrowUp");
await page.keyboard.up("Shift");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("ArrowUp");
await page.keyboard.up("Control");
}
}
async function kbBigMoveDown(page) {
if (isMac) {
await page.keyboard.down("Shift");
await page.keyboard.press("ArrowDown");
await page.keyboard.up("Shift");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("ArrowDown");
await page.keyboard.up("Control");
}
}
async function kbDeleteLastWord(page) {
if (isMac) {
await page.keyboard.down("Alt");
await page.keyboard.press("Backspace");
await page.keyboard.up("Alt");
} else {
await page.keyboard.down("Control");
await page.keyboard.press("Backspace");
await page.keyboard.up("Control");
}
}
export {
clearInput,
closePages,
dragAndDropAnnotation,
getAnnotationStorage,
getComputedStyleSelector,
getEditorDimensions,
getEditors,
getEditorSelector,
getFirstSerialized,
getQuerySelector,
getSelectedEditors,
getSelector,
getSerialized,
hover,
kbBigMoveDown,
kbBigMoveLeft,
kbBigMoveRight,
kbBigMoveUp,
kbCopy,
kbDeleteLastWord,
kbGoToBegin,
kbGoToEnd,
kbModifierDown,
kbModifierUp,
kbPaste,
kbRedo,
kbSelectAll,
kbUndo,
loadAndWait,
mockClipboard,
scrollIntoView,
serializeBitmapDimensions,
waitForAnnotationEditorLayer,
waitForEntryInStorage,
waitForEvent,
waitForSelectedEditor,
waitForSerialized,
waitForStorageEntries,
waitForTextLayer,
waitForUnselectedEditor,
};