Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
const { PdfJsTelemetry } = ChromeUtils.importESModule(
"resource://pdf.js/PdfJsTelemetry.sys.mjs"
);
const { PdfjsParent } = ChromeUtils.importESModule(
"resource://pdf.js/PdfjsParent.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
);
const RELATIVE_DIR = "toolkit/components/pdfjs/test/";
const TESTROOT = "https://example.com/browser/" + RELATIVE_DIR;
const sandbox = sinon.createSandbox();
registerCleanupFunction(() => sandbox.restore());
const original = PdfJsTelemetry.report.bind(PdfJsTelemetry);
const resolvers = new Map();
sandbox.stub(PdfJsTelemetry, "report").callsFake(aData => {
if (aData.type === "pageOrganization") {
resolvers.get(aData.data?.action)?.resolve();
}
original(aData);
});
sandbox.stub(PdfjsParent.prototype, "_saveURL");
function getPromise(action) {
const resolver = Promise.withResolvers();
resolvers.set(action, resolver);
return resolver.promise;
}
async function selectPage(browser, index) {
await SpecialPowers.spawn(browser, [index], async function (idx) {
const { ContentTaskUtils } = ChromeUtils.importESModule(
);
const { document } = content;
await ContentTaskUtils.waitForCondition(
() =>
!!document.querySelectorAll(
"#thumbnailsView .thumbnail input[type=checkbox]"
)[idx],
"Checkbox must be present"
);
const checkbox = document.querySelectorAll(
"#thumbnailsView .thumbnail input[type=checkbox]"
)[idx];
if (!checkbox.checked) {
checkbox.click();
}
await ContentTaskUtils.waitForCondition(
() => checkbox.checked,
"Checkbox must be checked"
);
});
}
async function organizerKey(browser, key, ctrlKey = false) {
await SpecialPowers.spawn(browser, [key, ctrlKey], function (k, ctrl) {
const container = content.document.querySelector("#thumbnailsView");
container.dispatchEvent(
new content.KeyboardEvent("keydown", {
key: k,
ctrlKey: ctrl,
bubbles: true,
cancelable: true,
})
);
});
await TestUtils.waitForTick();
}
async function organizerAction(browser, selector) {
await SpecialPowers.spawn(browser, [selector], function (sel) {
content.document.querySelector(sel).click();
});
await TestUtils.waitForTick();
}
async function openOrganizePdf(browser) {
await SpecialPowers.pushPrefEnv({
set: [["pdfjs.enableSplitMerge", true]],
});
await Services.fog.testFlushAllChildren();
Services.fog.testResetFOG();
await waitForPdfJSAllLayers(
browser,
TESTROOT + "file_pdfjs_numbered_pages.pdf",
[
[
"annotationEditorLayer",
"annotationLayer",
"textLayer",
"canvasWrapper",
],
[
"annotationEditorLayer",
"annotationLayer",
"textLayer",
"canvasWrapper",
],
]
);
await click(browser, "#viewsManagerToggleButton");
await waitForSelector(
browser,
"#thumbnailsView .thumbnail input[type=checkbox]"
);
}
// Test page organization telemetry. The actions are performed in an order that
// avoids any undo, keeping the state machine simple:
// export_selected (2 pages) → copy (paste mode) → paste (3 pages)
// → delete (2 pages) → save → cut (1 page)
add_task(async function test_page_organization_telemetry() {
makePDFJSHandler();
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:blank" },
async function (browser) {
await openOrganizePdf(browser);
// Test export_selected: select page 0 and click the export button.
await selectPage(browser, 0);
let telemetryPromise = getPromise("exportSelected");
const saveExtractedPromise = BrowserTestUtils.waitForContentEvent(
browser,
"saveextractedpages",
false,
null,
true
);
await organizerAction(browser, "#viewsManagerStatusActionExport");
await saveExtractedPromise;
await telemetryPromise;
await Services.fog.testFlushAllChildren();
Assert.equal(
Glean.pdfjsOrganize.action.export_selected.testGetValue(),
1,
"export_selected counter should be 1"
);
// Test copy: Ctrl+C on the thumbnail container with page 0 selected.
await selectPage(browser, 0);
telemetryPromise = getPromise("copy");
let pagesEditedPromise = BrowserTestUtils.waitForContentEvent(
browser,
"pagesedited",
false,
null,
true
);
await organizerKey(browser, "c", true);
await pagesEditedPromise;
await telemetryPromise;
await Services.fog.testFlushAllChildren();
Assert.equal(
Glean.pdfjsOrganize.action.copy.testGetValue(),
1,
"copy counter should be 1"
);
// Test paste: click the paste button that appeared after copy.
await waitForSelector(browser, ".thumbnailPasteButton");
telemetryPromise = getPromise("paste");
pagesEditedPromise = BrowserTestUtils.waitForContentEvent(
browser,
"pagesedited",
false,
null,
true
);
await organizerAction(browser, ".thumbnailPasteButton");
await pagesEditedPromise;
await telemetryPromise;
await Services.fog.testFlushAllChildren();
Assert.equal(
Glean.pdfjsOrganize.action.paste.testGetValue(),
1,
"paste counter should be 1"
);
// There are now 3 pages. Test delete: Delete key with page 0 selected.
await selectPage(browser, 0);
telemetryPromise = getPromise("delete");
pagesEditedPromise = BrowserTestUtils.waitForContentEvent(
browser,
"pagesedited",
false,
null,
true
);
await organizerKey(browser, "Delete");
await pagesEditedPromise;
await telemetryPromise;
await Services.fog.testFlushAllChildren();
Assert.equal(
Glean.pdfjsOrganize.action.delete.testGetValue(),
1,
"delete counter should be 1"
);
// Test save: the PDF now has structural changes (paste + delete) so
// downloadOrSave takes the page-organization save path.
telemetryPromise = getPromise("save");
await SpecialPowers.spawn(browser, [], function () {
content.wrappedJSObject.PDFViewerApplication.downloadOrSave();
});
await telemetryPromise;
await Services.fog.testFlushAllChildren();
Assert.equal(
Glean.pdfjsOrganize.action.save.testGetValue(),
1,
"save counter should be 1"
);
// There are now 2 pages. Test cut: Ctrl+X with page 0 selected.
await selectPage(browser, 0);
telemetryPromise = getPromise("cut");
pagesEditedPromise = BrowserTestUtils.waitForContentEvent(
browser,
"pagesedited",
false,
null,
true
);
await organizerKey(browser, "x", true);
await pagesEditedPromise;
await telemetryPromise;
await Services.fog.testFlushAllChildren();
Assert.equal(
Glean.pdfjsOrganize.action.cut.testGetValue(),
1,
"cut counter should be 1"
);
await waitForPdfJSClose(browser);
await SpecialPowers.popPrefEnv();
}
);
});