1 /* Any copyright is dedicated to the Public Domain.
2 * http://creativecommons.org/publicdomain/zero/1.0/ */
4 const RELATIVE_DIR = "toolkit/components/pdfjs/test/";
5 const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
7 // This is a modified version from browser_contextmenuFillLogins.js.
8 async function openContextMenuAt(browser, x, y) {
9 const contextMenu = document.getElementById("contentAreaContextMenu");
11 const contextMenuShownPromise = BrowserTestUtils.waitForEvent(
16 // Synthesize a contextmenu event to actually open the context menu.
17 await BrowserTestUtils.synthesizeMouseAtPoint(
27 await contextMenuShownPromise;
32 * Open a context menu and get the pdfjs entries
33 * @param {Object} browser
35 * @returns {Promise<Map<string,HTMLElement>>} the pdfjs menu entries.
37 function getContextMenuItems(browser, box) {
38 return new Promise(resolve => {
39 setTimeout(async () => {
40 const { x, y, width, height } = box;
44 "context-sep-pdfjs-redo",
47 "context-pdfjs-paste",
48 "context-pdfjs-delete",
49 "context-pdfjs-selectall",
50 "context-sep-pdfjs-selectall",
51 "context-pdfjs-highlight-selection",
54 await openContextMenuAt(browser, x + width / 2, y + height / 2);
55 const results = new Map();
56 const doc = browser.ownerDocument;
57 for (const menuitem of menuitems) {
58 const item = doc.getElementById(menuitem);
59 results.set(menuitem, item || null);
68 * Open a context menu on the element corresponding to the given selector
69 * and returs the pdfjs menu entries.
70 * @param {Object} browser
71 * @param {string} selector
72 * @returns {Promise<Map<string,HTMLElement>>} the pdfjs menu entries.
74 async function getContextMenuItemsOn(browser, selector) {
75 const box = await SpecialPowers.spawn(
78 async function (selector) {
79 const element = content.document.querySelector(selector);
80 const { x, y, width, height } = element.getBoundingClientRect();
81 return { x, y, width, height };
84 return getContextMenuItems(browser, box);
88 * Hide the context menu.
89 * @param {Object} browser
91 async function hideContextMenu(browser) {
92 await new Promise(resolve =>
93 setTimeout(async () => {
94 const doc = browser.ownerDocument;
95 const contextMenu = doc.getElementById("contentAreaContextMenu");
97 const popupHiddenPromise = BrowserTestUtils.waitForEvent(
101 contextMenu.hidePopup();
102 await popupHiddenPromise;
108 async function clickOnItem(browser, items, entry) {
109 const editingPromise = BrowserTestUtils.waitForContentEvent(
116 const contextMenu = document.getElementById("contentAreaContextMenu");
117 contextMenu.activateItem(items.get(entry));
118 await editingPromise;
122 * Asserts that the enabled pdfjs menuitems are the expected ones.
123 * @param {Map<string,HTMLElement>} menuitems
124 * @param {Array<string>} expected
126 function assertMenuitems(menuitems, expected) {
128 [...menuitems.values()]
131 !elmt.id.includes("-sep-") &&
133 [null, "false"].includes(elmt.getAttribute("disabled"))
135 .map(elmt => elmt.id),
140 async function waitAndCheckEmptyContextMenu(browser) {
141 // check that PDF is opened with internal viewer
142 await waitForPdfJSAllLayers(browser, TESTROOT + "file_pdfjs_test.pdf", [
143 ["annotationEditorLayer", "annotationLayer", "textLayer", "canvasWrapper"],
144 ["annotationEditorLayer", "textLayer", "canvasWrapper"],
147 const spanBox = await getSpanBox(browser, "and found references");
148 const menuitems = await getContextMenuItems(browser, spanBox);
150 // Nothing have been edited, hence the context menu doesn't contain any
153 [...menuitems.values()].every(elmt => elmt.hidden),
154 "No visible pdf menuitem"
156 await hideContextMenu(browser);
159 // Text copy, paste, undo, redo, delete and select all in using the context
161 add_task(async function test_copy_paste_undo_redo() {
164 await BrowserTestUtils.withNewTab(
165 { gBrowser, url: "about:blank" },
166 async function (browser) {
167 SpecialPowers.clipboardCopyString("");
169 await SpecialPowers.pushPrefEnv({
170 set: [["pdfjs.annotationEditorMode", 0]],
173 await waitAndCheckEmptyContextMenu(browser);
174 const spanBox = await getSpanBox(browser, "and found references");
176 await enableEditor(browser, "FreeText", 1);
177 await addFreeText(browser, "hello", spanBox);
180 await escape(browser);
182 info("Wait for the editor to be unselected");
183 await BrowserTestUtils.waitForCondition(
184 async () => (await countElements(browser, ".selectedEditor")) !== 1
186 Assert.equal(await countElements(browser, ".selectedEditor"), 0);
188 let menuitems = await getContextMenuItems(browser, spanBox);
189 assertMenuitems(menuitems, [
190 "context-pdfjs-undo", // Last created editor is undoable
191 "context-pdfjs-selectall", // and selectable.
194 await clickOnItem(browser, menuitems, "context-pdfjs-undo");
196 await BrowserTestUtils.waitForCondition(
197 async () => (await countElements(browser, ".freeTextEditor")) !== 2
201 await countElements(browser, ".freeTextEditor"),
203 "The FreeText editor must have been removed"
206 menuitems = await getContextMenuItems(browser, spanBox);
208 // The editor removed thanks to "undo" is now redoable
209 assertMenuitems(menuitems, [
210 "context-pdfjs-redo",
211 "context-pdfjs-selectall",
213 await clickOnItem(browser, menuitems, "context-pdfjs-redo");
215 await BrowserTestUtils.waitForCondition(
216 async () => (await countElements(browser, ".freeTextEditor")) !== 1
220 await countElements(browser, ".freeTextEditor"),
222 "The FreeText editor must have been added back"
225 await clickOn(browser, "#pdfjs_internal_editor_0");
226 menuitems = await getContextMenuItemsOn(
228 "#pdfjs_internal_editor_0"
231 assertMenuitems(menuitems, [
232 "context-pdfjs-undo",
234 "context-pdfjs-copy",
235 "context-pdfjs-delete",
236 "context-pdfjs-selectall",
239 await clickOnItem(browser, menuitems, "context-pdfjs-cut");
241 await BrowserTestUtils.waitForCondition(
242 async () => (await countElements(browser, ".freeTextEditor")) !== 2
246 await countElements(browser, ".freeTextEditor"),
248 "The FreeText editor must have been cut"
251 menuitems = await getContextMenuItems(browser, spanBox);
252 assertMenuitems(menuitems, [
253 "context-pdfjs-undo",
254 "context-pdfjs-paste",
255 "context-pdfjs-selectall",
258 await clickOnItem(browser, menuitems, "context-pdfjs-paste");
260 await BrowserTestUtils.waitForCondition(
261 async () => (await countElements(browser, ".freeTextEditor")) !== 1
265 await countElements(browser, ".freeTextEditor"),
267 "The FreeText editor must have been pasted"
270 await clickOn(browser, "#pdfjs_internal_editor_1");
271 menuitems = await getContextMenuItemsOn(
273 "#pdfjs_internal_editor_1"
276 assertMenuitems(menuitems, [
277 "context-pdfjs-undo",
279 "context-pdfjs-copy",
280 "context-pdfjs-paste",
281 "context-pdfjs-delete",
282 "context-pdfjs-selectall",
285 await clickOnItem(browser, menuitems, "context-pdfjs-delete");
287 await BrowserTestUtils.waitForCondition(
288 async () => (await countElements(browser, ".freeTextEditor")) !== 2
292 await countElements(browser, ".freeTextEditor"),
294 "The FreeText editor must have been deleted"
297 menuitems = await getContextMenuItems(browser, spanBox);
298 await clickOnItem(browser, menuitems, "context-pdfjs-paste");
300 await BrowserTestUtils.waitForCondition(
301 async () => (await countElements(browser, ".freeTextEditor")) !== 1
305 await countElements(browser, ".freeTextEditor"),
307 "The FreeText editor must have been pasted"
310 await clickOn(browser, "#pdfjs_internal_editor_2");
311 menuitems = await getContextMenuItemsOn(
313 "#pdfjs_internal_editor_2"
316 await clickOnItem(browser, menuitems, "context-pdfjs-copy");
318 menuitems = await getContextMenuItemsOn(
320 "#pdfjs_internal_editor_2"
322 await clickOnItem(browser, menuitems, "context-pdfjs-paste");
324 await BrowserTestUtils.waitForCondition(
325 async () => (await countElements(browser, ".freeTextEditor")) !== 2
329 await countElements(browser, ".freeTextEditor"),
331 "The FreeText editor must have been pasted"
334 menuitems = await getContextMenuItems(browser, spanBox);
335 await clickOnItem(browser, menuitems, "context-pdfjs-selectall");
336 menuitems = await getContextMenuItems(browser, spanBox);
337 await clickOnItem(browser, menuitems, "context-pdfjs-delete");
339 await BrowserTestUtils.waitForCondition(
340 async () => (await countElements(browser, ".freeTextEditor")) !== 3
344 await countElements(browser, ".freeTextEditor"),
346 "All the FreeText editors must have been deleted"
349 await waitForPdfJSClose(browser);
350 await SpecialPowers.popPrefEnv();
355 add_task(async function test_highlight_selection() {
358 await BrowserTestUtils.withNewTab(
359 { gBrowser, url: "about:blank" },
360 async function (browser) {
361 await SpecialPowers.pushPrefEnv({
362 set: [["pdfjs.annotationEditorMode", 0]],
365 await waitAndCheckEmptyContextMenu(browser);
366 const spanBox = await getSpanBox(browser, "and found references");
368 const changePromise = BrowserTestUtils.waitForContentEvent(
370 "annotationeditorstateschanged",
377 spanBox.x + spanBox.width / 2,
378 spanBox.y + spanBox.height / 2,
382 await TestUtils.waitForTick();
384 const mozBox = await getSpanBox(browser, "Mozilla automated testing");
385 const menuitems = await getContextMenuItems(browser, mozBox);
387 assertMenuitems(menuitems, ["context-pdfjs-highlight-selection"]);
389 const telemetryPromise = BrowserTestUtils.waitForContentEvent(
399 "context-pdfjs-highlight-selection"
401 await telemetryPromise;
404 await countElements(browser, ".highlightEditor"),
406 "An highlight editor must have been added"
409 await waitForPdfJSClose(browser);