From c5dec6122567e100b36aec052213acd3d8297f56 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Thu, 27 Jun 2024 18:15:45 +0200 Subject: [PATCH] Fix intermittent failures with freetext and stamp tests They're potentially due to some concurrent access to the system clipboard. So this patch makes them sequential. --- test/integration/freetext_editor_spec.mjs | 205 +++--- test/integration/stamp_editor_spec.mjs | 826 +++++++++++----------- 2 files changed, 508 insertions(+), 523 deletions(-) diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index 6427ac28c72b6c..18ea77b789b86d 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -3369,132 +3369,129 @@ describe("FreeText Editor", () => { }); it("must check that pasting html just keep the text", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToFreeText(page); - - const rect = await getRect(page, ".annotationEditorLayer"); + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToFreeText(page); - let editorSelector = getEditorSelector(0); - const data = "Hello PDF.js World !!"; - await page.mouse.click(rect.x + 100, rect.y + 100); - await page.waitForSelector(editorSelector, { - visible: true, - }); - await page.type(`${editorSelector} .internal`, data); - const editorRect = await getRect(page, editorSelector); + const rect = await getRect(page, ".annotationEditorLayer"); - // Commit. - await page.keyboard.press("Escape"); - await page.waitForSelector(`${editorSelector} .overlay.enabled`); + let editorSelector = getEditorSelector(0); + const data = "Hello PDF.js World !!"; + await page.mouse.click(rect.x + 100, rect.y + 100); + await page.waitForSelector(editorSelector, { + visible: true, + }); + await page.type(`${editorSelector} .internal`, data); + const editorRect = await getRect(page, editorSelector); - const waitForTextChange = (previous, edSelector) => - page.waitForFunction( - (prev, sel) => document.querySelector(sel).innerText !== prev, - {}, - previous, - `${edSelector} .internal` - ); - const getText = edSelector => - page.$eval(`${edSelector} .internal`, el => el.innerText.trimEnd()); + // Commit. + await page.keyboard.press("Escape"); + await page.waitForSelector(`${editorSelector} .overlay.enabled`); - await page.mouse.click( - editorRect.x + editorRect.width / 2, - editorRect.y + editorRect.height / 2, - { count: 2 } - ); - await page.waitForSelector( - `${editorSelector} .overlay:not(.enabled)` + const waitForTextChange = (previous, edSelector) => + page.waitForFunction( + (prev, sel) => document.querySelector(sel).innerText !== prev, + {}, + previous, + `${edSelector} .internal` ); + const getText = edSelector => + page.$eval(`${edSelector} .internal`, el => el.innerText.trimEnd()); - const select = position => - page.evaluate( - (sel, pos) => { - const el = document.querySelector(sel); - document.getSelection().setPosition(el.firstChild, pos); - }, - `${editorSelector} .internal`, - position - ); + await page.mouse.click( + editorRect.x + editorRect.width / 2, + editorRect.y + editorRect.height / 2, + { count: 2 } + ); + await page.waitForSelector(`${editorSelector} .overlay:not(.enabled)`); - await select(0); - await copyToClipboard(page, { - "text/html": "Bold Foo", - "text/plain": "Foo", - }); - await pasteFromClipboard(page, `${editorSelector} .internal`); + const select = position => + page.evaluate( + (sel, pos) => { + const el = document.querySelector(sel); + document.getSelection().setPosition(el.firstChild, pos); + }, + `${editorSelector} .internal`, + position + ); - let lastText = data; + await select(0); + await copyToClipboard(page, { + "text/html": "Bold Foo", + "text/plain": "Foo", + }); + await pasteFromClipboard(page, `${editorSelector} .internal`); - await waitForTextChange(lastText, editorSelector); - let text = await getText(editorSelector); - lastText = `Foo${data}`; - expect(text).withContext(`In ${browserName}`).toEqual(lastText); + let lastText = data; - await select(3); - await copyToClipboard(page, { - "text/html": "Bold Bar
Oof", - "text/plain": "Bar\nOof", - }); - await pasteFromClipboard(page, `${editorSelector} .internal`); + await waitForTextChange(lastText, editorSelector); + let text = await getText(editorSelector); + lastText = `Foo${data}`; + expect(text).withContext(`In ${browserName}`).toEqual(lastText); - await waitForTextChange(lastText, editorSelector); - text = await getText(editorSelector); - lastText = `FooBar\nOof${data}`; - expect(text).withContext(`In ${browserName}`).toEqual(lastText); + await select(3); + await copyToClipboard(page, { + "text/html": "Bold Bar
Oof", + "text/plain": "Bar\nOof", + }); + await pasteFromClipboard(page, `${editorSelector} .internal`); - await select(0); - await copyToClipboard(page, { "text/html": "basic html" }); - await pasteFromClipboard(page, `${editorSelector} .internal`); + await waitForTextChange(lastText, editorSelector); + text = await getText(editorSelector); + lastText = `FooBar\nOof${data}`; + expect(text).withContext(`In ${browserName}`).toEqual(lastText); - // Nothing should change, so it's hard to wait on something. - // eslint-disable-next-line no-restricted-syntax - await waitForTimeout(100); + await select(0); + await copyToClipboard(page, { "text/html": "basic html" }); + await pasteFromClipboard(page, `${editorSelector} .internal`); - text = await getText(editorSelector); - expect(text).withContext(`In ${browserName}`).toEqual(lastText); + // Nothing should change, so it's hard to wait on something. + // eslint-disable-next-line no-restricted-syntax + await waitForTimeout(100); - const getHTML = () => - page.$eval(`${editorSelector} .internal`, el => el.innerHTML); - const prevHTML = await getHTML(); + text = await getText(editorSelector); + expect(text).withContext(`In ${browserName}`).toEqual(lastText); - // Try to paste an image. - await copyToClipboard(page, { - "image/png": - // 1x1 transparent png. - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", - }); - await pasteFromClipboard(page, `${editorSelector} .internal`); + const getHTML = () => + page.$eval(`${editorSelector} .internal`, el => el.innerHTML); + const prevHTML = await getHTML(); - // Nothing should change, so it's hard to wait on something. - // eslint-disable-next-line no-restricted-syntax - await waitForTimeout(100); + // Try to paste an image. + await copyToClipboard(page, { + "image/png": + // 1x1 transparent png. + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", + }); + await pasteFromClipboard(page, `${editorSelector} .internal`); - const html = await getHTML(); - expect(html).withContext(`In ${browserName}`).toEqual(prevHTML); + // Nothing should change, so it's hard to wait on something. + // eslint-disable-next-line no-restricted-syntax + await waitForTimeout(100); - // Commit. - await page.keyboard.press("Escape"); - await page.waitForSelector(`${editorSelector} .overlay.enabled`); + const html = await getHTML(); + expect(html).withContext(`In ${browserName}`).toEqual(prevHTML); - editorSelector = getEditorSelector(1); - await page.mouse.click(rect.x + 200, rect.y + 200); - await page.waitForSelector(editorSelector, { - visible: true, - }); + // Commit. + await page.keyboard.press("Escape"); + await page.waitForSelector(`${editorSelector} .overlay.enabled`); - const fooBar = "Foo\nBar\nOof"; - await copyToClipboard(page, { - "text/html": "html", - "text/plain": fooBar, - }); - await pasteFromClipboard(page, `${editorSelector} .internal`); + editorSelector = getEditorSelector(1); + await page.mouse.click(rect.x + 200, rect.y + 200); + await page.waitForSelector(editorSelector, { + visible: true, + }); - await waitForTextChange("", editorSelector); - text = await getText(editorSelector); - expect(text).withContext(`In ${browserName}`).toEqual(fooBar); - }) - ); + const fooBar = "Foo\nBar\nOof"; + await copyToClipboard(page, { + "text/html": "html", + "text/plain": fooBar, + }); + await pasteFromClipboard(page, `${editorSelector} .internal`); + + await waitForTextChange("", editorSelector); + text = await getText(editorSelector); + expect(text).withContext(`In ${browserName}`).toEqual(fooBar); + } }); }); diff --git a/test/integration/stamp_editor_spec.mjs b/test/integration/stamp_editor_spec.mjs index 66b2735bcfdb98..482c073cd63247 100644 --- a/test/integration/stamp_editor_spec.mjs +++ b/test/integration/stamp_editor_spec.mjs @@ -258,160 +258,159 @@ describe("Stamp Editor", () => { }); it("must check that the alt-text flow is correctly implemented", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - - await copyImage(page, "../images/firefox_logo.png", 0); - - // Wait for the alt-text button to be visible. - const buttonSelector = `${getEditorSelector(0)} button.altText`; - await page.waitForSelector(buttonSelector); - - // Click on the alt-text button. - await page.click(buttonSelector); - - // Wait for the alt-text dialog to be visible. - await page.waitForSelector("#altTextDialog", { visible: true }); - - // Click on the alt-text editor. - const textareaSelector = "#altTextDialog textarea"; - await page.click(textareaSelector); - await page.type(textareaSelector, "Hello World"); - - // Click on save button. - const saveButtonSelector = "#altTextDialog #altTextSave"; - await page.click(saveButtonSelector); - - // Check that the canvas has an aria-describedby attribute. - await page.waitForSelector( - `${getEditorSelector(0)} canvas[aria-describedby]` - ); - - // Wait for the alt-text button to have the correct icon. - await page.waitForSelector(`${buttonSelector}.done`); - - // Hover the button. - await page.hover(buttonSelector); - - // Wait for the tooltip to be visible. - const tooltipSelector = `${buttonSelector} .tooltip`; - await page.waitForSelector(tooltipSelector, { visible: true }); - - let tooltipText = await page.evaluate( - sel => document.querySelector(`${sel}`).innerText, - tooltipSelector - ); - expect(tooltipText).toEqual("Hello World"); - - // Now we change the alt-text and check that the tooltip is updated. - await page.click(buttonSelector); - await page.waitForSelector("#altTextDialog", { visible: true }); - await page.evaluate(sel => { - document.querySelector(`${sel}`).value = ""; - }, textareaSelector); - await page.click(textareaSelector); - await page.type(textareaSelector, "Dlrow Olleh"); - await page.click(saveButtonSelector); - await page.waitForSelector(`${buttonSelector}.done`); - await page.hover(buttonSelector); - await page.waitForSelector(tooltipSelector, { visible: true }); - tooltipText = await page.evaluate( - sel => document.querySelector(`${sel}`).innerText, - tooltipSelector - ); - expect(tooltipText).toEqual("Dlrow Olleh"); - - // Now we just check that cancel didn't change anything. - await page.click(buttonSelector); - await page.waitForSelector("#altTextDialog", { visible: true }); - await page.evaluate(sel => { - document.querySelector(`${sel}`).value = ""; - }, textareaSelector); - await page.click(textareaSelector); - await page.type(textareaSelector, "Hello PDF.js"); - const cancelButtonSelector = "#altTextDialog #altTextCancel"; - await page.click(cancelButtonSelector); - await page.waitForSelector(`${buttonSelector}.done`); - await page.hover(buttonSelector); - await page.waitForSelector(tooltipSelector, { visible: true }); - tooltipText = await page.evaluate( - sel => document.querySelector(`${sel}`).innerText, - tooltipSelector - ); - // The tooltip should still be "Dlrow Olleh". - expect(tooltipText).toEqual("Dlrow Olleh"); - - // Now we switch to decorative. - await page.click(buttonSelector); - await page.waitForSelector("#altTextDialog", { visible: true }); - const decorativeSelector = "#altTextDialog #decorativeButton"; - await page.click(decorativeSelector); - await page.click(saveButtonSelector); - await page.waitForSelector(`${buttonSelector}.done`); - await page.hover(buttonSelector); - await page.waitForSelector(tooltipSelector, { visible: true }); - tooltipText = await page.evaluate( - sel => document.querySelector(`${sel}`).innerText, - tooltipSelector - ); - expect(tooltipText).toEqual("Marked as decorative"); - - // Now we switch back to non-decorative. - await page.click(buttonSelector); - await page.waitForSelector("#altTextDialog", { visible: true }); - const descriptionSelector = "#altTextDialog #descriptionButton"; - await page.click(descriptionSelector); - await page.click(saveButtonSelector); - await page.waitForSelector(`${buttonSelector}.done`); - await page.hover(buttonSelector); - await page.waitForSelector(tooltipSelector, { visible: true }); - tooltipText = await page.evaluate( - sel => document.querySelector(`${sel}`).innerText, - tooltipSelector - ); - expect(tooltipText).toEqual("Dlrow Olleh"); - - // Now we remove the alt-text and check that the tooltip is removed. - await page.click(buttonSelector); - await page.waitForSelector("#altTextDialog", { visible: true }); - await page.evaluate(sel => { - document.querySelector(`${sel}`).value = ""; - }, textareaSelector); - await page.click(saveButtonSelector); - await page.waitForSelector(`${buttonSelector}:not(.done)`); - await page.hover(buttonSelector); - await page.evaluate( - sel => document.querySelector(sel) === null, - tooltipSelector - ); - - // We check that the alt-text button works correctly with the - // keyboard. - const handle = await page.evaluateHandle(sel => { - document.getElementById("viewerContainer").focus(); - return [ - new Promise(resolve => { - setTimeout(() => { - const el = document.querySelector(sel); - el.addEventListener("focus", resolve, { once: true }); - el.focus({ focusVisible: true }); - }, 0); - }), - ]; - }, buttonSelector); - await awaitPromise(handle); - await (browserName === "chrome" - ? page.waitForSelector(`${buttonSelector}:focus`) - : page.waitForSelector(`${buttonSelector}:focus-visible`)); - await page.keyboard.press("Enter"); - await page.waitForSelector("#altTextDialog", { visible: true }); - await page.keyboard.press("Escape"); - await (browserName === "chrome" - ? page.waitForSelector(`${buttonSelector}:focus`) - : page.waitForSelector(`${buttonSelector}:focus-visible`)); - }) - ); + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); + + await copyImage(page, "../images/firefox_logo.png", 0); + + // Wait for the alt-text button to be visible. + const buttonSelector = `${getEditorSelector(0)} button.altText`; + await page.waitForSelector(buttonSelector); + + // Click on the alt-text button. + await page.click(buttonSelector); + + // Wait for the alt-text dialog to be visible. + await page.waitForSelector("#altTextDialog", { visible: true }); + + // Click on the alt-text editor. + const textareaSelector = "#altTextDialog textarea"; + await page.click(textareaSelector); + await page.type(textareaSelector, "Hello World"); + + // Click on save button. + const saveButtonSelector = "#altTextDialog #altTextSave"; + await page.click(saveButtonSelector); + + // Check that the canvas has an aria-describedby attribute. + await page.waitForSelector( + `${getEditorSelector(0)} canvas[aria-describedby]` + ); + + // Wait for the alt-text button to have the correct icon. + await page.waitForSelector(`${buttonSelector}.done`); + + // Hover the button. + await page.hover(buttonSelector); + + // Wait for the tooltip to be visible. + const tooltipSelector = `${buttonSelector} .tooltip`; + await page.waitForSelector(tooltipSelector, { visible: true }); + + let tooltipText = await page.evaluate( + sel => document.querySelector(`${sel}`).innerText, + tooltipSelector + ); + expect(tooltipText).toEqual("Hello World"); + + // Now we change the alt-text and check that the tooltip is updated. + await page.click(buttonSelector); + await page.waitForSelector("#altTextDialog", { visible: true }); + await page.evaluate(sel => { + document.querySelector(`${sel}`).value = ""; + }, textareaSelector); + await page.click(textareaSelector); + await page.type(textareaSelector, "Dlrow Olleh"); + await page.click(saveButtonSelector); + await page.waitForSelector(`${buttonSelector}.done`); + await page.hover(buttonSelector); + await page.waitForSelector(tooltipSelector, { visible: true }); + tooltipText = await page.evaluate( + sel => document.querySelector(`${sel}`).innerText, + tooltipSelector + ); + expect(tooltipText).toEqual("Dlrow Olleh"); + + // Now we just check that cancel didn't change anything. + await page.click(buttonSelector); + await page.waitForSelector("#altTextDialog", { visible: true }); + await page.evaluate(sel => { + document.querySelector(`${sel}`).value = ""; + }, textareaSelector); + await page.click(textareaSelector); + await page.type(textareaSelector, "Hello PDF.js"); + const cancelButtonSelector = "#altTextDialog #altTextCancel"; + await page.click(cancelButtonSelector); + await page.waitForSelector(`${buttonSelector}.done`); + await page.hover(buttonSelector); + await page.waitForSelector(tooltipSelector, { visible: true }); + tooltipText = await page.evaluate( + sel => document.querySelector(`${sel}`).innerText, + tooltipSelector + ); + // The tooltip should still be "Dlrow Olleh". + expect(tooltipText).toEqual("Dlrow Olleh"); + + // Now we switch to decorative. + await page.click(buttonSelector); + await page.waitForSelector("#altTextDialog", { visible: true }); + const decorativeSelector = "#altTextDialog #decorativeButton"; + await page.click(decorativeSelector); + await page.click(saveButtonSelector); + await page.waitForSelector(`${buttonSelector}.done`); + await page.hover(buttonSelector); + await page.waitForSelector(tooltipSelector, { visible: true }); + tooltipText = await page.evaluate( + sel => document.querySelector(`${sel}`).innerText, + tooltipSelector + ); + expect(tooltipText).toEqual("Marked as decorative"); + + // Now we switch back to non-decorative. + await page.click(buttonSelector); + await page.waitForSelector("#altTextDialog", { visible: true }); + const descriptionSelector = "#altTextDialog #descriptionButton"; + await page.click(descriptionSelector); + await page.click(saveButtonSelector); + await page.waitForSelector(`${buttonSelector}.done`); + await page.hover(buttonSelector); + await page.waitForSelector(tooltipSelector, { visible: true }); + tooltipText = await page.evaluate( + sel => document.querySelector(`${sel}`).innerText, + tooltipSelector + ); + expect(tooltipText).toEqual("Dlrow Olleh"); + + // Now we remove the alt-text and check that the tooltip is removed. + await page.click(buttonSelector); + await page.waitForSelector("#altTextDialog", { visible: true }); + await page.evaluate(sel => { + document.querySelector(`${sel}`).value = ""; + }, textareaSelector); + await page.click(saveButtonSelector); + await page.waitForSelector(`${buttonSelector}:not(.done)`); + await page.hover(buttonSelector); + await page.evaluate( + sel => document.querySelector(sel) === null, + tooltipSelector + ); + + // We check that the alt-text button works correctly with the + // keyboard. + const handle = await page.evaluateHandle(sel => { + document.getElementById("viewerContainer").focus(); + return [ + new Promise(resolve => { + setTimeout(() => { + const el = document.querySelector(sel); + el.addEventListener("focus", resolve, { once: true }); + el.focus({ focusVisible: true }); + }, 0); + }), + ]; + }, buttonSelector); + await awaitPromise(handle); + await (browserName === "chrome" + ? page.waitForSelector(`${buttonSelector}:focus`) + : page.waitForSelector(`${buttonSelector}:focus-visible`)); + await page.keyboard.press("Enter"); + await page.waitForSelector("#altTextDialog", { visible: true }); + await page.keyboard.press("Escape"); + await (browserName === "chrome" + ? page.waitForSelector(`${buttonSelector}:focus`) + : page.waitForSelector(`${buttonSelector}:focus-visible`)); + } }); }); @@ -427,125 +426,124 @@ describe("Stamp Editor", () => { }); it("must check that the dimensions change", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - - await copyImage(page, "../images/firefox_logo.png", 0); + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); - const editorSelector = getEditorSelector(0); + await copyImage(page, "../images/firefox_logo.png", 0); - await page.click(editorSelector); - await waitForSelectedEditor(page, editorSelector); - - await page.waitForSelector( - `${editorSelector} .resizer.topLeft[tabindex="-1"]` - ); - - const getDims = async () => { - const [blX, blY, trX, trY] = await getFirstSerialized( - page, - x => x.rect - ); - return [trX - blX, trY - blY]; - }; + const editorSelector = getEditorSelector(0); - const [width, height] = await getDims(); + await page.click(editorSelector); + await waitForSelectedEditor(page, editorSelector); - // Press Enter to enter in resize-with-keyboard mode. - await page.keyboard.press("Enter"); + await page.waitForSelector( + `${editorSelector} .resizer.topLeft[tabindex="-1"]` + ); - // The resizer must become keyboard focusable. - await page.waitForSelector( - `${editorSelector} .resizer.topLeft[tabindex="0"]` + const getDims = async () => { + const [blX, blY, trX, trY] = await getFirstSerialized( + page, + x => x.rect ); + return [trX - blX, trY - blY]; + }; - let prevWidth = width; - let prevHeight = height; - - const waitForDimsChange = async (w, h) => { - await page.waitForFunction( - (prevW, prevH) => { - const [x1, y1, x2, y2] = - window.PDFViewerApplication.pdfDocument.annotationStorage.serializable.map - .values() - .next().value.rect; - const newWidth = x2 - x1; - const newHeight = y2 - y1; - return newWidth !== prevW || newHeight !== prevH; - }, - {}, - w, - h - ); - }; + const [width, height] = await getDims(); - for (let i = 0; i < 40; i++) { - await page.keyboard.press("ArrowLeft"); - await waitForDimsChange(prevWidth, prevHeight); - [prevWidth, prevHeight] = await getDims(); - } + // Press Enter to enter in resize-with-keyboard mode. + await page.keyboard.press("Enter"); - let [newWidth, newHeight] = await getDims(); - expect(newWidth > width + 30) - .withContext(`In ${browserName}`) - .toEqual(true); - expect(newHeight > height + 30) - .withContext(`In ${browserName}`) - .toEqual(true); + // The resizer must become keyboard focusable. + await page.waitForSelector( + `${editorSelector} .resizer.topLeft[tabindex="0"]` + ); - for (let i = 0; i < 4; i++) { - await kbBigMoveRight(page); - await waitForDimsChange(prevWidth, prevHeight); - [prevWidth, prevHeight] = await getDims(); - } + let prevWidth = width; + let prevHeight = height; - [newWidth, newHeight] = await getDims(); - expect(Math.abs(newWidth - width) < 2) - .withContext(`In ${browserName}`) - .toEqual(true); - expect(Math.abs(newHeight - height) < 2) - .withContext(`In ${browserName}`) - .toEqual(true); - - // Move the focus to the next resizer. - await page.keyboard.press("Tab"); + const waitForDimsChange = async (w, h) => { await page.waitForFunction( - () => !!document.activeElement?.classList.contains("topMiddle") + (prevW, prevH) => { + const [x1, y1, x2, y2] = + window.PDFViewerApplication.pdfDocument.annotationStorage.serializable.map + .values() + .next().value.rect; + const newWidth = x2 - x1; + const newHeight = y2 - y1; + return newWidth !== prevW || newHeight !== prevH; + }, + {}, + w, + h ); + }; - for (let i = 0; i < 40; i++) { - await page.keyboard.press("ArrowUp"); - await waitForDimsChange(prevWidth, prevHeight); - [prevWidth, prevHeight] = await getDims(); - } + for (let i = 0; i < 40; i++) { + await page.keyboard.press("ArrowLeft"); + await waitForDimsChange(prevWidth, prevHeight); + [prevWidth, prevHeight] = await getDims(); + } - [, newHeight] = await getDims(); - expect(newHeight > height + 50) - .withContext(`In ${browserName}`) - .toEqual(true); + let [newWidth, newHeight] = await getDims(); + expect(newWidth > width + 30) + .withContext(`In ${browserName}`) + .toEqual(true); + expect(newHeight > height + 30) + .withContext(`In ${browserName}`) + .toEqual(true); + + for (let i = 0; i < 4; i++) { + await kbBigMoveRight(page); + await waitForDimsChange(prevWidth, prevHeight); + [prevWidth, prevHeight] = await getDims(); + } - for (let i = 0; i < 4; i++) { - await kbBigMoveDown(page); - await waitForDimsChange(prevWidth, prevHeight); - [prevWidth, prevHeight] = await getDims(); - } + [newWidth, newHeight] = await getDims(); + expect(Math.abs(newWidth - width) < 2) + .withContext(`In ${browserName}`) + .toEqual(true); + expect(Math.abs(newHeight - height) < 2) + .withContext(`In ${browserName}`) + .toEqual(true); + + // Move the focus to the next resizer. + await page.keyboard.press("Tab"); + await page.waitForFunction( + () => !!document.activeElement?.classList.contains("topMiddle") + ); + + for (let i = 0; i < 40; i++) { + await page.keyboard.press("ArrowUp"); + await waitForDimsChange(prevWidth, prevHeight); + [prevWidth, prevHeight] = await getDims(); + } - [, newHeight] = await getDims(); - expect(Math.abs(newHeight - height) < 2) - .withContext(`In ${browserName}`) - .toEqual(true); + [, newHeight] = await getDims(); + expect(newHeight > height + 50) + .withContext(`In ${browserName}`) + .toEqual(true); - // Escape should remove the focus from the resizer. - await page.keyboard.press("Escape"); - await page.waitForSelector( - `${editorSelector} .resizer.topLeft[tabindex="-1"]` - ); - await page.waitForFunction( - () => !document.activeElement?.classList.contains("resizer") - ); - }) - ); + for (let i = 0; i < 4; i++) { + await kbBigMoveDown(page); + await waitForDimsChange(prevWidth, prevHeight); + [prevWidth, prevHeight] = await getDims(); + } + + [, newHeight] = await getDims(); + expect(Math.abs(newHeight - height) < 2) + .withContext(`In ${browserName}`) + .toEqual(true); + + // Escape should remove the focus from the resizer. + await page.keyboard.press("Escape"); + await page.waitForSelector( + `${editorSelector} .resizer.topLeft[tabindex="-1"]` + ); + await page.waitForFunction( + () => !document.activeElement?.classList.contains("resizer") + ); + } }); }); @@ -594,24 +592,23 @@ describe("Stamp Editor", () => { }); it("must check that a stamp can be undone", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - const selector = getEditorSelector(0); - - await copyImage(page, "../images/firefox_logo.png", 0); - await page.waitForSelector(selector); - await waitForSerialized(page, 1); - - await page.waitForSelector(`${selector} button.delete`); - await page.click(`${selector} button.delete`); - await waitForSerialized(page, 0); - - await kbUndo(page); - await waitForSerialized(page, 1); - await page.waitForSelector(`${selector} canvas`); - }) - ); + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); + const selector = getEditorSelector(0); + + await copyImage(page, "../images/firefox_logo.png", 0); + await page.waitForSelector(selector); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${selector} button.delete`); + await page.click(`${selector} button.delete`); + await waitForSerialized(page, 0); + + await kbUndo(page); + await waitForSerialized(page, 1); + await page.waitForSelector(`${selector} canvas`); + } }); }); @@ -627,37 +624,36 @@ describe("Stamp Editor", () => { }); it("must check that a stamp can be undone", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - const selector = getEditorSelector(0); - - await copyImage(page, "../images/firefox_logo.png", 0); - await page.waitForSelector(selector); - await waitForSerialized(page, 1); - - await page.waitForSelector(`${selector} button.delete`); - await page.click(`${selector} button.delete`); - await waitForSerialized(page, 0); - - const twoToFourteen = Array.from(new Array(13).keys(), n => n + 2); - for (const pageNumber of twoToFourteen) { - const pageSelector = `.page[data-page-number = "${pageNumber}"]`; - await scrollIntoView(page, pageSelector); - } + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); + const selector = getEditorSelector(0); + + await copyImage(page, "../images/firefox_logo.png", 0); + await page.waitForSelector(selector); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${selector} button.delete`); + await page.click(`${selector} button.delete`); + await waitForSerialized(page, 0); + + const twoToFourteen = Array.from(new Array(13).keys(), n => n + 2); + for (const pageNumber of twoToFourteen) { + const pageSelector = `.page[data-page-number = "${pageNumber}"]`; + await scrollIntoView(page, pageSelector); + } - await kbUndo(page); - await waitForSerialized(page, 1); + await kbUndo(page); + await waitForSerialized(page, 1); - const thirteenToOne = Array.from(new Array(13).keys(), n => 13 - n); - for (const pageNumber of thirteenToOne) { - const pageSelector = `.page[data-page-number = "${pageNumber}"]`; - await scrollIntoView(page, pageSelector); - } + const thirteenToOne = Array.from(new Array(13).keys(), n => 13 - n); + for (const pageNumber of thirteenToOne) { + const pageSelector = `.page[data-page-number = "${pageNumber}"]`; + await scrollIntoView(page, pageSelector); + } - await page.waitForSelector(`${selector} canvas`); - }) - ); + await page.waitForSelector(`${selector} canvas`); + } }); }); @@ -673,32 +669,31 @@ describe("Stamp Editor", () => { }); it("must check that a stamp can be undone", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - const selector = getEditorSelector(0); - - await copyImage(page, "../images/firefox_logo.png", 0); - await page.waitForSelector(selector); - await waitForSerialized(page, 1); - - await page.waitForSelector(`${selector} button.delete`); - await page.click(`${selector} button.delete`); - await waitForSerialized(page, 0); - - const twoToOne = Array.from(new Array(13).keys(), n => n + 2).concat( - Array.from(new Array(13).keys(), n => 13 - n) - ); - for (const pageNumber of twoToOne) { - const pageSelector = `.page[data-page-number = "${pageNumber}"]`; - await scrollIntoView(page, pageSelector); - } + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); + const selector = getEditorSelector(0); + + await copyImage(page, "../images/firefox_logo.png", 0); + await page.waitForSelector(selector); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${selector} button.delete`); + await page.click(`${selector} button.delete`); + await waitForSerialized(page, 0); + + const twoToOne = Array.from(new Array(13).keys(), n => n + 2).concat( + Array.from(new Array(13).keys(), n => 13 - n) + ); + for (const pageNumber of twoToOne) { + const pageSelector = `.page[data-page-number = "${pageNumber}"]`; + await scrollIntoView(page, pageSelector); + } - await kbUndo(page); - await waitForSerialized(page, 1); - await page.waitForSelector(`${selector} canvas`); - }) - ); + await kbUndo(page); + await waitForSerialized(page, 1); + await page.waitForSelector(`${selector} canvas`); + } }); }); @@ -714,44 +709,43 @@ describe("Stamp Editor", () => { }); it("must check that a resized stamp has its canvas at the right position", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - - await copyImage(page, "../images/firefox_logo.png", 0); - await page.waitForSelector(getEditorSelector(0)); - await waitForSerialized(page, 1); - - const serializedRect = await getFirstSerialized(page, x => x.rect); - const rect = await getRect(page, ".resizer.bottomRight"); - const centerX = rect.x + rect.width / 2; - const centerY = rect.y + rect.height / 2; - - await page.mouse.move(centerX, centerY); - await page.mouse.down(); - await page.mouse.move(centerX - 500, centerY - 500); - await page.mouse.up(); - - await waitForEntryInStorage( - page, - "rect", - serializedRect, - (x, y) => x !== y - ); - - const canvasRect = await getRect( - page, - `${getEditorSelector(0)} canvas` - ); - const stampRect = await getRect(page, getEditorSelector(0)); - - expect( - ["x", "y", "width", "height"].every( - key => Math.abs(canvasRect[key] - stampRect[key]) <= 10 - ) - ).toBeTrue(); - }) - ); + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); + + await copyImage(page, "../images/firefox_logo.png", 0); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + const serializedRect = await getFirstSerialized(page, x => x.rect); + const rect = await getRect(page, ".resizer.bottomRight"); + const centerX = rect.x + rect.width / 2; + const centerY = rect.y + rect.height / 2; + + await page.mouse.move(centerX, centerY); + await page.mouse.down(); + await page.mouse.move(centerX - 500, centerY - 500); + await page.mouse.up(); + + await waitForEntryInStorage( + page, + "rect", + serializedRect, + (x, y) => x !== y + ); + + const canvasRect = await getRect( + page, + `${getEditorSelector(0)} canvas` + ); + const stampRect = await getRect(page, getEditorSelector(0)); + + expect( + ["x", "y", "width", "height"].every( + key => Math.abs(canvasRect[key] - stampRect[key]) <= 10 + ) + ).toBeTrue(); + } }); }); @@ -775,27 +769,26 @@ describe("Stamp Editor", () => { }); it("must check that the stamp has its canvas at the right position", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - - await copyImage(page, "../images/firefox_logo.png", 0); - await page.waitForSelector(getEditorSelector(0)); - await waitForSerialized(page, 1); - - const canvasRect = await getRect( - page, - `${getEditorSelector(0)} canvas` - ); - const stampRect = await getRect(page, getEditorSelector(0)); - - expect( - ["x", "y", "width", "height"].every( - key => Math.abs(canvasRect[key] - stampRect[key]) <= 10 - ) - ).toBeTrue(); - }) - ); + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); + + await copyImage(page, "../images/firefox_logo.png", 0); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + const canvasRect = await getRect( + page, + `${getEditorSelector(0)} canvas` + ); + const stampRect = await getRect(page, getEditorSelector(0)); + + expect( + ["x", "y", "width", "height"].every( + key => Math.abs(canvasRect[key] - stampRect[key]) <= 10 + ) + ).toBeTrue(); + } }); }); @@ -811,40 +804,35 @@ describe("Stamp Editor", () => { }); it("must check that the pasted image has an alt text", async () => { - await Promise.all( - pages.map(async ([browserName, page]) => { - await switchToStamp(page); - - await copyImage(page, "../images/firefox_logo.png", 0); - await page.waitForSelector(getEditorSelector(0)); - await waitForSerialized(page, 1); - await applyFunctionToEditor( - page, - "pdfjs_internal_editor_0", - editor => { - editor.altTextData = { - altText: "Hello World", - decorative: false, - }; - } - ); - await page.waitForSelector(`${getEditorSelector(0)} .altText.done`); - - await copy(page); - await paste(page); - await page.waitForSelector(`${getEditorSelector(1)} .altText.done`); - await waitForSerialized(page, 2); - - const serialized = await getSerialized( - page, - x => x.accessibilityData?.alt - ); - - expect(serialized) - .withContext(`In ${browserName}`) - .toEqual(["Hello World", "Hello World"]); - }) - ); + // Run sequentially to avoid clipboard issues. + for (const [browserName, page] of pages) { + await switchToStamp(page); + + await copyImage(page, "../images/firefox_logo.png", 0); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + await applyFunctionToEditor(page, "pdfjs_internal_editor_0", editor => { + editor.altTextData = { + altText: "Hello World", + decorative: false, + }; + }); + await page.waitForSelector(`${getEditorSelector(0)} .altText.done`); + + await copy(page); + await paste(page); + await page.waitForSelector(`${getEditorSelector(1)} .altText.done`); + await waitForSerialized(page, 2); + + const serialized = await getSerialized( + page, + x => x.accessibilityData?.alt + ); + + expect(serialized) + .withContext(`In ${browserName}`) + .toEqual(["Hello World", "Hello World"]); + } }); }); });