diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index 29e89f28ae32e..fb99cf6c03593 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -3688,4 +3688,130 @@ describe("FreeText Editor", () => { ); }); }); + + describe("Undo deletion popup has the expected behaviour", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer"); + }); + + afterEach(async () => { + await closePages(pages); + }); + + it("must check that deleting a FreeText editor can be undone using the undo button", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToFreeText(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + const data = "Hello PDF.js World !!"; + await page.mouse.click(rect.x + 100, rect.y + 100); + await page.waitForSelector(getEditorSelector(0), { + visible: true, + }); + await page.type(`${getEditorSelector(0)} .internal`, data); + + // Commit. + await page.keyboard.press("Escape"); + await page.waitForSelector( + `${getEditorSelector(0)} .overlay.enabled` + ); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForSelector("#editorUndoBar:not([hidden])"); + await page.click("#editorUndoBarUndoButton"); + await waitForSerialized(page, 1); + await page.waitForSelector(getEditorSelector(0)); + }) + ); + }); + + it("must check that the undo deletion popup displays the correct message", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToFreeText(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + const data = "Hello PDF.js World !!"; + await page.mouse.click(rect.x + 100, rect.y + 100); + await page.waitForSelector(getEditorSelector(0), { + visible: true, + }); + await page.type(`${getEditorSelector(0)} .internal`, data); + + // Commit. + await page.keyboard.press("Escape"); + await page.waitForSelector( + `${getEditorSelector(0)} .overlay.enabled` + ); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForFunction(() => { + const messageElement = document.querySelector( + "#editorUndoBarMessage" + ); + return messageElement && messageElement.textContent.trim() !== ""; + }); + const message = await page.waitForSelector("#editorUndoBarMessage"); + const messageText = await page.evaluate( + el => el.textContent, + message + ); + expect(messageText).toContain("Text removed"); + }) + ); + }); + + it("must check that the popup disappears when a new textbox is created", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToFreeText(page); + + let rect = await getRect(page, ".annotationEditorLayer"); + const data = "Hello PDF.js World !!"; + await page.mouse.click(rect.x + 100, rect.y + 100); + await page.waitForSelector(getEditorSelector(0), { + visible: true, + }); + await page.type(`${getEditorSelector(0)} .internal`, data); + + await page.keyboard.press("Escape"); + await page.waitForSelector( + `${getEditorSelector(0)} .overlay.enabled` + ); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForSelector("#editorUndoBar:not([hidden])"); + rect = await getRect(page, ".annotationEditorLayer"); + const newData = "This is a new text box!"; + await page.mouse.click(rect.x + 150, rect.y + 150); + await page.waitForSelector(getEditorSelector(1), { + visible: true, + }); + await page.type(`${getEditorSelector(1)} .internal`, newData); + + await page.keyboard.press("Escape"); + await page.waitForSelector( + `${getEditorSelector(1)} .overlay.enabled` + ); + await waitForSerialized(page, 1); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + }); }); diff --git a/test/integration/highlight_editor_spec.mjs b/test/integration/highlight_editor_spec.mjs index 13d30c31aae71..d2ac1b5530827 100644 --- a/test/integration/highlight_editor_spec.mjs +++ b/test/integration/highlight_editor_spec.mjs @@ -26,6 +26,7 @@ import { kbBigMoveUp, kbFocusNext, kbFocusPrevious, + kbSave, kbSelectAll, kbUndo, loadAndWait, @@ -37,6 +38,11 @@ import { waitForSelectedEditor, waitForSerialized, } from "./test_utils.mjs"; +import { fileURLToPath } from "url"; +import fs from "fs"; +import path from "path"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); const selectAll = async page => { await kbSelectAll(page); @@ -2158,4 +2164,380 @@ describe("Highlight Editor", () => { ); }); }); + + describe("Undo deletion popup has the expected behaviour", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait( + "tracemonkey.pdf", + ".annotationEditorLayer", + null, + null, + { + highlightEditorColors: + "yellow=#FFFF00,green=#00FF00,blue=#0000FF,pink=#FF00FF,red=#FF0000", + } + ); + }); + + afterEach(async () => { + await closePages(pages); + }); + + it("must check that deleting a highlight can be undone using the undo button", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await page.click("#editorUndoBarUndoButton"); + await waitForSerialized(page, 1); + await page.waitForSelector(getEditorSelector(0)); + await page.waitForSelector( + `.page[data-page-number = "1"] svg.highlight[fill = "#FFFF00"]` + ); + }) + ); + }); + + it("must check that the popup disappears when the undo button is clicked", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await page.click("#editorUndoBarUndoButton"); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when the close button is clicked", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await page.waitForSelector("#editorUndoBarCloseButton"); + await page.click("#editorUndoBarCloseButton"); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when a new annotation is created", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + const newRect = await getSpanRectFromText(page, 1, "Introduction"); + const newX = newRect.x + newRect.width / 2; + const newY = newRect.y + newRect.height / 2; + await page.mouse.click(newX, newY, { count: 2, delay: 100 }); + + await page.waitForSelector(getEditorSelector(1)); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when the print dialog is opened", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await page.evaluate(() => window.print()); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when the user clicks on the print button", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await page.click("#printButton"); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when the save dialog is opened", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await kbSave(page); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when an option from the secondaryToolbar is used", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await page.click("#secondaryToolbarToggleButton"); + await page.click("#lastPage"); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when highlight mode is disabled", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + await switchToHighlight(page, /* disable */ true); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the popup disappears when a PDF is drag-and-dropped", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + const pdfPath = path.join(__dirname, "../pdfs/basicapi.pdf"); + const pdfData = fs.readFileSync(pdfPath).toString("base64"); + const dataTransfer = await page.evaluateHandle(data => { + const transfer = new DataTransfer(); + const view = Uint8Array.from(atob(data), code => + code.charCodeAt(0) + ); + const file = new File([view], "basicapi.pdf", { + type: "application/pdf", + }); + transfer.items.add(file); + return transfer; + }, pdfData); + + const dropSelector = "#viewer"; + await page.evaluate( + (transfer, selector) => { + const dropTarget = document.querySelector(selector); + const event = new DragEvent("dragstart", { + dataTransfer: transfer, + }); + dropTarget.dispatchEvent(event); + }, + dataTransfer, + dropSelector + ); + + await page.evaluate( + (transfer, selector) => { + const dropTarget = document.querySelector(selector); + const event = new DragEvent("drop", { + dataTransfer: transfer, + bubbles: true, + }); + dropTarget.dispatchEvent(event); + }, + dataTransfer, + dropSelector + ); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + + it("must check that the undo deletion popup displays the correct message", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + const rect = await getSpanRectFromText(page, 1, "Abstract"); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForFunction(() => { + const messageElement = document.querySelector( + "#editorUndoBarMessage" + ); + return messageElement && messageElement.textContent.trim() !== ""; + }); + + const message = await page.waitForSelector("#editorUndoBarMessage"); + const messageText = await page.evaluate( + el => el.textContent, + message + ); + expect(messageText).toContain("Highlight removed"); + }) + ); + }); + + it("must display correct message for multiple highlights", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToHighlight(page); + + let rect = await getSpanRectFromText(page, 1, "Abstract"); + let x = rect.x + rect.width / 2; + let y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(0)); + + rect = await getSpanRectFromText(page, 1, "Languages"); + x = rect.x + rect.width / 2; + y = rect.y + rect.height / 2; + await page.mouse.click(x, y, { count: 2, delay: 100 }); + await page.waitForSelector(getEditorSelector(1)); + + await selectAll(page); + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForFunction(() => { + const messageElement = document.querySelector( + "#editorUndoBarMessage" + ); + return messageElement && messageElement.textContent.trim() !== ""; + }); + + const message = await page.waitForSelector("#editorUndoBarMessage"); + const messageText = await page.evaluate( + el => el.textContent, + message + ); + + // Cleans the message text by removing all non-ASCII characters. + // It eliminates any invisible characters such as directional marks + // that interfere with string comparisons + const cleanMessage = messageText.replaceAll(/\P{ASCII}/gu, ""); + expect(cleanMessage).toContain(`2 annotations removed`); + }) + ); + }); + }); }); diff --git a/test/integration/ink_editor_spec.mjs b/test/integration/ink_editor_spec.mjs index 8cf5059dfb2ae..c6a646fa01b49 100644 --- a/test/integration/ink_editor_spec.mjs +++ b/test/integration/ink_editor_spec.mjs @@ -453,4 +453,129 @@ describe("Ink Editor", () => { ); }); }); + + describe("Undo deletion popup has the expected behaviour", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer"); + }); + + afterEach(async () => { + await closePages(pages); + }); + + it("must check that deleting a drawing can be undone using the undo button", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToInk(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + const xStart = rect.x + 300; + const yStart = rect.y + 300; + const clickHandle = await waitForPointerUp(page); + await page.mouse.move(xStart, yStart); + await page.mouse.down(); + await page.mouse.move(xStart + 50, yStart + 50); + await page.mouse.up(); + await awaitPromise(clickHandle); + await commit(page); + + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForSelector("#editorUndoBar:not([hidden])"); + await page.click("#editorUndoBarUndoButton"); + await waitForSerialized(page, 1); + await page.waitForSelector(getEditorSelector(0)); + }) + ); + }); + + it("must check that the undo deletion popup displays the correct message", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToInk(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + const xStart = rect.x + 300; + const yStart = rect.y + 300; + const clickHandle = await waitForPointerUp(page); + await page.mouse.move(xStart, yStart); + await page.mouse.down(); + await page.mouse.move(xStart + 50, yStart + 50); + await page.mouse.up(); + await awaitPromise(clickHandle); + await commit(page); + + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForFunction(() => { + const messageElement = document.querySelector( + "#editorUndoBarMessage" + ); + return messageElement && messageElement.textContent.trim() !== ""; + }); + const message = await page.waitForSelector("#editorUndoBarMessage"); + const messageText = await page.evaluate( + el => el.textContent, + message + ); + expect(messageText).toContain("Drawing removed"); + }) + ); + }); + + it("must check that the popup disappears when a new drawing is created", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToInk(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + const xStart = rect.x + 300; + const yStart = rect.y + 300; + const clickHandle = await waitForPointerUp(page); + await page.mouse.move(xStart, yStart); + await page.mouse.down(); + await page.mouse.move(xStart + 50, yStart + 50); + await page.mouse.up(); + await awaitPromise(clickHandle); + await commit(page); + + await page.waitForSelector(getEditorSelector(0)); + await waitForSerialized(page, 1); + + await page.waitForSelector(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + await page.waitForSelector("#editorUndoBar:not([hidden])"); + + const newRect = await getRect(page, ".annotationEditorLayer"); + const newXStart = newRect.x + 300; + const newYStart = newRect.y + 300; + const newClickHandle = await waitForPointerUp(page); + await page.mouse.move(newXStart, newYStart); + await page.mouse.down(); + await page.mouse.move(newXStart + 50, newYStart + 50); + await page.mouse.up(); + await awaitPromise(newClickHandle); + await commit(page); + + await page.waitForSelector(getEditorSelector(1)); + await waitForSerialized(page, 1); + await page.waitForSelector(getEditorSelector(1)); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + }); }); diff --git a/test/integration/stamp_editor_spec.mjs b/test/integration/stamp_editor_spec.mjs index c8c4275e3c011..0371e0dc97668 100644 --- a/test/integration/stamp_editor_spec.mjs +++ b/test/integration/stamp_editor_spec.mjs @@ -1492,4 +1492,97 @@ describe("Stamp Editor", () => { ); }); }); + + describe("Undo deletion popup has the expected behaviour", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer"); + }); + + afterEach(async () => { + await closePages(pages); + }); + + it("must check that deleting an image can be undone using the undo button", 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 page.waitForSelector("#editorUndoBar:not([hidden])"); + + await page.click("#editorUndoBarUndoButton"); + await waitForSerialized(page, 1); + await page.waitForSelector(getEditorSelector(0)); + await page.waitForSelector(`${selector} canvas`); + }) + ); + }); + + it("must check that the undo deletion popup displays the correct message", 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 page.waitForFunction(() => { + const messageElement = document.querySelector( + "#editorUndoBarMessage" + ); + return messageElement && messageElement.textContent.trim() !== ""; + }); + const message = await page.waitForSelector("#editorUndoBarMessage"); + const messageText = await page.evaluate( + el => el.textContent, + message + ); + expect(messageText).toContain("Image removed"); + }) + ); + }); + + it("must check that the popup disappears when a new image is inserted", 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(`${getEditorSelector(0)} button.delete`); + await page.click(`${getEditorSelector(0)} button.delete`); + await waitForSerialized(page, 0); + + await page.waitForSelector("#editorUndoBar:not([hidden])"); + await page.click("#editorStampAddImage"); + const newInput = await page.$("#stampEditorFileInput"); + await newInput.uploadFile( + `${path.join(__dirname, "../images/firefox_logo.png")}` + ); + await waitForImage(page, getEditorSelector(1)); + await waitForSerialized(page, 1); + await page.waitForSelector("#editorUndoBar", { hidden: true }); + }) + ); + }); + }); }); diff --git a/test/integration/test_utils.mjs b/test/integration/test_utils.mjs index 7e6ec548b0f22..d90ff6376e02a 100644 --- a/test/integration/test_utils.mjs +++ b/test/integration/test_utils.mjs @@ -745,6 +745,12 @@ async function kbFocusPrevious(page) { await awaitPromise(handle); } +async function kbSave(page) { + await page.keyboard.down(modifier); + await page.keyboard.press("s"); + await page.keyboard.up(modifier); +} + async function switchToEditor(name, page, disable = false) { const modeChangedHandle = await createPromise(page, resolve => { window.PDFViewerApplication.eventBus.on( @@ -800,6 +806,7 @@ export { kbModifierDown, kbModifierUp, kbRedo, + kbSave, kbSelectAll, kbUndo, loadAndWait,