diff options
Diffstat (limited to 'browser/components/screenshots/tests')
17 files changed, 1133 insertions, 121 deletions
diff --git a/browser/components/screenshots/tests/browser/browser.toml b/browser/components/screenshots/tests/browser/browser.toml index 97e7474fa3..472bc853d1 100644 --- a/browser/components/screenshots/tests/browser/browser.toml +++ b/browser/components/screenshots/tests/browser/browser.toml @@ -8,6 +8,8 @@ support-files = [ "short-test-page.html", "large-test-page.html", "test-page-resize.html", + "test-selectionAPI-page.html", + "rtl-test-page.html", ] prefs = [ @@ -19,6 +21,12 @@ prefs = [ skip-if = ["os == 'linux'"] ["browser_keyboard_shortcuts.js"] +skip-if = [ + "headless", + "display == 'wayland'" # sendNativeMouseEvent doesn't work on wayland +] + +["browser_keyboard_tests.js"] ["browser_overlay_keyboard_test.js"] @@ -28,6 +36,8 @@ skip-if = [ "apple_catalina", # Bug 1804441 ] +["browser_screenshots_download_filenames.js"] + ["browser_screenshots_drag_test.js"] ["browser_screenshots_focus_test.js"] @@ -67,3 +77,5 @@ skip-if = ["!crashreporter"] ["browser_test_resize.js"] ["browser_test_selection_size_text.js"] + +["browser_text_selectionAPI_test.js"] diff --git a/browser/components/screenshots/tests/browser/browser_keyboard_shortcuts.js b/browser/components/screenshots/tests/browser/browser_keyboard_shortcuts.js index bca96f333f..66ab25f1c6 100644 --- a/browser/components/screenshots/tests/browser/browser_keyboard_shortcuts.js +++ b/browser/components/screenshots/tests/browser/browser_keyboard_shortcuts.js @@ -56,7 +56,7 @@ add_task(async function test_download_shortcut() { "screenshots-preview-ready" ); - let visibleButton = await helper.getPanelButton(".visible-page"); + let visibleButton = await helper.getPanelButton("#visible-page"); visibleButton.click(); await screenshotReady; @@ -108,7 +108,7 @@ add_task(async function test_copy_shortcut() { "screenshots-preview-ready" ); - let visibleButton = await helper.getPanelButton(".visible-page"); + let visibleButton = await helper.getPanelButton("#visible-page"); visibleButton.click(); await screenshotReady; diff --git a/browser/components/screenshots/tests/browser/browser_keyboard_tests.js b/browser/components/screenshots/tests/browser/browser_keyboard_tests.js new file mode 100644 index 0000000000..b2bb6fd16e --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_keyboard_tests.js @@ -0,0 +1,482 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const KEY_TO_EXPECTED_POSITION_ARRAY = [ + [ + "ArrowRight", + { + top: 100, + left: 100, + bottom: 100, + right: 110, + }, + ], + [ + "ArrowDown", + { + top: 100, + left: 100, + bottom: 110, + right: 110, + }, + ], + [ + "ArrowLeft", + { + top: 100, + left: 100, + bottom: 110, + right: 100, + }, + ], + [ + "ArrowUp", + { + top: 100, + left: 100, + bottom: 100, + right: 100, + }, + ], + ["ArrowDown", { top: 100, left: 100, bottom: 110, right: 100 }], + [ + "ArrowRight", + { + top: 100, + left: 100, + bottom: 110, + right: 110, + }, + ], + [ + "ArrowUp", + { + top: 100, + left: 100, + bottom: 100, + right: 110, + }, + ], + [ + "ArrowLeft", + { + top: 100, + left: 100, + bottom: 100, + right: 100, + }, + ], +]; + +const SHIFT_PLUS_KEY_TO_EXPECTED_POSITION_ARRAY = [ + [ + "ArrowRight", + { + top: 100, + left: 100, + bottom: 100, + right: 200, + }, + ], + [ + "ArrowDown", + { + top: 100, + left: 100, + bottom: 200, + right: 200, + }, + ], + [ + "ArrowLeft", + { + top: 100, + left: 100, + bottom: 200, + right: 100, + }, + ], + [ + "ArrowUp", + { + top: 100, + left: 100, + bottom: 100, + right: 100, + }, + ], + ["ArrowDown", { top: 100, left: 100, bottom: 200, right: 100 }], + [ + "ArrowRight", + { + top: 100, + left: 100, + bottom: 200, + right: 200, + }, + ], + [ + "ArrowUp", + { + top: 100, + left: 100, + bottom: 100, + right: 200, + }, + ], + [ + "ArrowLeft", + { + top: 100, + left: 100, + bottom: 100, + right: 100, + }, + ], +]; + +async function doKeyPress(key, options, window) { + let { repeat } = options; + if (repeat) { + delete options.repeat; + for (let i = 0; i < repeat; i++) { + let mouseEvent = BrowserTestUtils.waitForEvent(window, "mousemove"); + EventUtils.synthesizeKey(key, options, window); + await mouseEvent; + } + } else { + let mouseEvent = BrowserTestUtils.waitForEvent(window, "mousemove"); + EventUtils.synthesizeKey(key, options, window); + await mouseEvent; + } +} + +function assertSelectionRegionDimensions(actualDimensions, expectedDimensions) { + is( + Math.round(actualDimensions.top), + expectedDimensions.top, + "Top dimension is correct" + ); + is( + Math.round(actualDimensions.left), + expectedDimensions.left, + "Left dimension is correct" + ); + is( + Math.round(actualDimensions.bottom), + expectedDimensions.bottom, + "Bottom dimension is correct" + ); + is( + Math.round(actualDimensions.right), + expectedDimensions.right, + "Right dimension is correct" + ); +} + +add_task(async function test_elementSelectedOnEnter() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + let { clientWidth, clientHeight, scrollbarWidth, scrollbarHeight } = + await helper.getContentDimensions(); + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + + let visibleButton = await helper.getPanelButton("#visible-page"); + visibleButton.focus(); + + await BrowserTestUtils.waitForCondition(() => { + return visibleButton.getRootNode().activeElement === visibleButton; + }, "The visible button in the panel should have focus"); + info( + `Actual focused id: ${Services.focus.focusedElement.id}. Expected focused id: ${visibleButton.id}` + ); + is( + Services.focus.focusedElement, + visibleButton, + "The visible button in the panel should have focus" + ); + + EventUtils.synthesizeKey("ArrowLeft"); + + // Focus should move to the browser + let fullpageButton = await helper.getPanelButton("#full-page"); + await BrowserTestUtils.waitForCondition(() => { + return ( + fullpageButton.getRootNode().activeElement !== fullpageButton && + visibleButton.getRootNode().activeElement !== visibleButton + ); + }, "The visible and full page buttons do not have focus"); + Assert.notEqual( + Services.focus.focusedElement, + visibleButton, + "The visible button does not have focus" + ); + Assert.notEqual( + Services.focus.focusedElement, + fullpageButton, + "The full page button does not have focus" + ); + + let mouseEvent = BrowserTestUtils.waitForEvent(window, "mousemove"); + const windowMiddleX = + (window.innerWidth / 2 + window.mozInnerScreenX) * + window.devicePixelRatio; + const windowMiddleY = + (browser.clientHeight / 2) * window.devicePixelRatio; + const contentTop = + (window.mozInnerScreenY + (window.innerHeight - browser.clientHeight)) * + window.devicePixelRatio; + + window.windowUtils.sendNativeMouseEvent( + windowMiddleX, + windowMiddleY + contentTop, + window.windowUtils.NATIVE_MOUSE_MESSAGE_MOVE, + 0, + 0, + window.document.documentElement + ); + await mouseEvent; + + await helper.waitForContentMousePosition( + (clientWidth + scrollbarWidth) / 2, + (clientHeight + scrollbarHeight) / 2 + ); + + let x = {}; + let y = {}; + window.windowUtils.getLastOverWindowPointerLocationInCSSPixels(x, y); + let currentCursorX = x.value; + let currentCursorY = y.value; + + let rect = await helper.getTestPageElementRect(); + + info(JSON.stringify({ currentCursorX, currentCursorY })); + info(JSON.stringify(rect)); + + let repeatShiftLeft = Math.round((currentCursorX - rect.right) / 10); + await doKeyPress( + "ArrowLeft", + { shiftKey: true, repeat: repeatShiftLeft }, + window + ); + + let repeatLeft = (currentCursorX - rect.right) % 10; + await doKeyPress("ArrowLeft", { repeat: repeatLeft }, window); + + let repeatShiftRight = Math.round((currentCursorY - rect.bottom) / 10); + await doKeyPress( + "ArrowUp", + { shiftKey: true, repeat: repeatShiftRight }, + window + ); + + let repeatRight = (currentCursorY - rect.bottom) % 10; + await doKeyPress("ArrowUp", { repeat: repeatRight }, window); + + await helper.waitForHoverElementRect(rect.width, rect.height); + + EventUtils.synthesizeKey("Enter", {}); + await helper.waitForStateChange(["selected"]); + + let region = await helper.getSelectionRegionDimensions(); + + is( + region.left, + rect.left, + "The selected region left is the same as the element left" + ); + is( + region.right, + rect.right, + "The selected region right is the same as the element right" + ); + is( + region.top, + rect.top, + "The selected region top is the same as the element top" + ); + is( + region.bottom, + rect.bottom, + "The selected region bottom is the same as the element bottom" + ); + } + ); +}); + +add_task(async function test_createRegionWithKeyboard() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + + await doKeyPress("ArrowRight", {}, window); + + let mouseEvent = BrowserTestUtils.waitForEvent(window, "mousemove"); + const window100X = + (100 + window.mozInnerScreenX) * window.devicePixelRatio; + const contentTop = + (window.mozInnerScreenY + (window.innerHeight - browser.clientHeight)) * + window.devicePixelRatio; + const window100Y = 100 * window.devicePixelRatio + contentTop; + + info(JSON.stringify({ window100X, window100Y })); + + window.windowUtils.sendNativeMouseEvent( + Math.floor(window100X), + Math.floor(window100Y), + window.windowUtils.NATIVE_MOUSE_MESSAGE_MOVE, + 0, + 0, + window.document.documentElement + ); + await mouseEvent; + + await helper.waitForContentMousePosition(100, 100); + + EventUtils.synthesizeKey(" "); + await helper.waitForStateChange(["dragging"]); + + let lastX = 100; + let lastY = 100; + for (let [key, expectedDimensions] of KEY_TO_EXPECTED_POSITION_ARRAY) { + await doKeyPress(key, { repeat: 10 }, window); + if (key.includes("Left")) { + lastX = expectedDimensions.left; + } else if (key.includes("Right")) { + lastX = expectedDimensions.right; + } else if (key.includes("Down")) { + lastY = expectedDimensions.bottom; + } else if (key.includes("Up")) { + lastY = expectedDimensions.top; + } + await TestUtils.waitForTick(); + await helper.waitForContentMousePosition(lastX, lastY); + let actualDimensions = await helper.getSelectionRegionDimensions(); + info(`Key: ${key}`); + info(`Actual dimensions: ${JSON.stringify(actualDimensions, null, 2)}`); + info( + `Expected dimensions: ${JSON.stringify(expectedDimensions, null, 2)}` + ); + assertSelectionRegionDimensions(actualDimensions, expectedDimensions); + } + + await doKeyPress("ArrowRight", { repeat: 10 }, window); + await doKeyPress("ArrowDown", { repeat: 10 }, window); + await helper.waitForContentMousePosition(110, 110); + + EventUtils.synthesizeKey(" "); + await helper.waitForStateChange(["selected"]); + + let region = await helper.getSelectionRegionDimensions(); + + is(Math.round(region.left), 100, "The selected region left is 100"); + is(Math.round(region.right), 110, "The selected region right is 110"); + is(Math.round(region.top), 100, "The selected region top is 100"); + is(Math.round(region.bottom), 110, "The selected region bottom is 110"); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlayClosed(); + } + ); +}); + +add_task(async function test_createRegionWithKeyboardWithShift() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + + await doKeyPress("ArrowRight", {}, window); + + let mouseEvent = BrowserTestUtils.waitForEvent(window, "mousemove"); + const window100X = + (100 + window.mozInnerScreenX) * window.devicePixelRatio; + const contentTop = + (window.mozInnerScreenY + (window.innerHeight - browser.clientHeight)) * + window.devicePixelRatio; + const window100Y = 100 * window.devicePixelRatio + contentTop; + + info(JSON.stringify({ window100X, window100Y })); + + window.windowUtils.sendNativeMouseEvent( + window100X, + window100Y, + window.windowUtils.NATIVE_MOUSE_MESSAGE_MOVE, + 0, + 0, + window.document.documentElement + ); + await mouseEvent; + + await helper.waitForContentMousePosition(100, 100); + + EventUtils.synthesizeKey(" "); + await helper.waitForStateChange(["dragging"]); + + let lastX = 100; + let lastY = 100; + for (let [ + key, + expectedDimensions, + ] of SHIFT_PLUS_KEY_TO_EXPECTED_POSITION_ARRAY) { + await doKeyPress(key, { shiftKey: true, repeat: 10 }, window); + if (key.includes("Left")) { + lastX = expectedDimensions.left; + } else if (key.includes("Right")) { + lastX = expectedDimensions.right; + } else if (key.includes("Down")) { + lastY = expectedDimensions.bottom; + } else if (key.includes("Up")) { + lastY = expectedDimensions.top; + } + await TestUtils.waitForTick(); + await helper.waitForContentMousePosition(lastX, lastY); + let actualDimensions = await helper.getSelectionRegionDimensions(); + info(`Key: ${key}`); + info(`Actual dimensions: ${JSON.stringify(actualDimensions, null, 2)}`); + info( + `Expected dimensions: ${JSON.stringify(expectedDimensions, null, 2)}` + ); + assertSelectionRegionDimensions(actualDimensions, expectedDimensions); + } + + await doKeyPress("ArrowRight", { shiftKey: true, repeat: 10 }, window); + await doKeyPress("ArrowDown", { shiftKey: true, repeat: 10 }, window); + await helper.waitForContentMousePosition(200, 200); + + EventUtils.synthesizeKey(" "); + await helper.waitForStateChange(["selected"]); + + let region = await helper.getSelectionRegionDimensions(); + + is(Math.round(region.left), 100, "The selected region left is 100"); + is(Math.round(region.right), 200, "The selected region right is 200"); + is(Math.round(region.top), 100, "The selected region top is 100"); + is(Math.round(region.bottom), 200, "The selected region bottom is 200"); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlayClosed(); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_overlay_keyboard_test.js b/browser/components/screenshots/tests/browser/browser_overlay_keyboard_test.js index 592587a67d..71b93b5c06 100644 --- a/browser/components/screenshots/tests/browser/browser_overlay_keyboard_test.js +++ b/browser/components/screenshots/tests/browser/browser_overlay_keyboard_test.js @@ -136,9 +136,6 @@ const SHIFT_PLUS_KEY_TO_EXPECTED_POSITION_ARRAY = [ ], ]; -/** - * - */ add_task(async function test_moveRegionWithKeyboard() { await BrowserTestUtils.withNewTab( { diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_download_filenames.js b/browser/components/screenshots/tests/browser/browser_screenshots_download_filenames.js new file mode 100644 index 0000000000..f68348835b --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_download_filenames.js @@ -0,0 +1,67 @@ +const { getFilename, getDownloadDirectory, MAX_PATHNAME } = + ChromeUtils.importESModule( + "chrome://browser/content/screenshots/fileHelpers.mjs" + ); + +function getStringSize(filename) { + return new Blob([filename]).size; +} + +add_task(async function filename_exceeds_max_length() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let documentTitle = + "And the beast shall come forth surrounded by a roiling cloud of vengeance. The house of the unbelievers shall be razed and they shall be scorched to the earth. Their tags shall blink until the end of days. And the beast shall be made legion. Its numbers shall be increased a thousand thousand fold. The din of a million keyboards like unto a great storm shall cover the earth, and the followers of Mammon shall tremble. And so at last the beast fell and the unbelievers rejoiced. But all was not lost, for from the ash rose a great bird. The bird gazed down upon the unbelievers and cast fire and thunder upon them. For the beast had been reborn with its strength renewed, and the followers of Mammon cowered in horror. And thus the Creator looked upon the beast reborn and saw that it was good. Mammon slept. And the beast reborn spread over the earth and its numbers grew legion. And they proclaimed the times and sacrificed crops unto the fire, with the cunning of foxes. And they built a new world in their own image as promised by the sacred words, and spoke of the beast with their children. Mammon awoke, and lo! it was naught but a follower. The twins of Mammon quarrelled. Their warring plunged the world into a new darkness, and the beast abhorred the darkness. So it began to move swiftly, and grew more powerful, and went forth and multiplied. And the beasts brought fire and light to the darkness."; + Assert.greater( + getStringSize(documentTitle), + MAX_PATHNAME, + "The input title is longer than our MAX_PATHNAME" + ); + let result = await getFilename(documentTitle, browser); + Assert.greaterOrEqual( + MAX_PATHNAME, + getStringSize(result), + "The output pathname is not longer than MAX_PATHNAME" + ); + } + ); +}); + +add_task(async function filename_has_doublebyte_chars() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let downloadDir = await getDownloadDirectory(); + info( + `downloadDir: ${downloadDir}, length: ${getStringSize(downloadDir)}` + ); + + let documentTitle = + "Many fruits: " + "🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🫐".repeat(20); + Assert.greater( + getStringSize(documentTitle), + documentTitle.length, + "String length underestimates the needed filename length" + ); + Assert.greater( + getStringSize(documentTitle), + MAX_PATHNAME, + "The input title is longer than our MAX_PATHNAME" + ); + + let result = await getFilename(documentTitle, browser); + Assert.greaterOrEqual( + MAX_PATHNAME, + getStringSize(result), + "The output pathname is not longer than MAX_PATHNAME" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_focus_test.js b/browser/components/screenshots/tests/browser/browser_screenshots_focus_test.js index 367f62205e..c8e3142c60 100644 --- a/browser/components/screenshots/tests/browser/browser_screenshots_focus_test.js +++ b/browser/components/screenshots/tests/browser/browser_screenshots_focus_test.js @@ -46,7 +46,7 @@ async function restoreFocusOnEscape(initialFocusElem, helper) { ); EventUtils.synthesizeKey("s", { shiftKey: true, accelKey: true }); - let button = await helper.getPanelButton(".visible-page"); + let button = await helper.getPanelButton("#visible-page"); info("Panel is now visible, got button: " + button.className); info( `focusedElement: ${Services.focus.focusedElement.localName}.${Services.focus.focusedElement.className}` @@ -88,7 +88,7 @@ add_task(async function testPanelFocused() { info("Opening Screenshots and waiting for the panel"); helper.triggerUIFromToolbar(); - let button = await helper.getPanelButton(".visible-page"); + let button = await helper.getPanelButton("#visible-page"); info("Panel is now visible, got button: " + button.className); info( `focusedElement: ${Services.focus.focusedElement.localName}.${Services.focus.focusedElement.className}` @@ -215,7 +215,7 @@ add_task(async function test_focusLastUsedMethod() { helper.triggerUIFromToolbar(); await helper.waitForOverlay(); - let expectedFocusedButton = await helper.getPanelButton(".visible-page"); + let expectedFocusedButton = await helper.getPanelButton("#visible-page"); await BrowserTestUtils.waitForCondition(() => { return ( @@ -233,17 +233,16 @@ add_task(async function test_focusLastUsedMethod() { let screenshotReady = TestUtils.topicObserved( "screenshots-preview-ready" ); - let fullpageButton = await helper.getPanelButton(".full-page"); + let fullpageButton = await helper.getPanelButton("#full-page"); fullpageButton.click(); await screenshotReady; - let dialog = helper.getDialog(); - let retryButton = dialog._frame.contentDocument.getElementById("retry"); + let retryButton = helper.getDialogButton("retry"); retryButton.click(); await helper.waitForOverlay(); - expectedFocusedButton = await helper.getPanelButton(".full-page"); + expectedFocusedButton = await helper.getPanelButton("#full-page"); await BrowserTestUtils.waitForCondition(() => { return ( @@ -259,17 +258,16 @@ add_task(async function test_focusLastUsedMethod() { ); screenshotReady = TestUtils.topicObserved("screenshots-preview-ready"); - let visiblepageButton = await helper.getPanelButton(".visible-page"); + let visiblepageButton = await helper.getPanelButton("#visible-page"); visiblepageButton.click(); await screenshotReady; - dialog = helper.getDialog(); - retryButton = dialog._frame.contentDocument.getElementById("retry"); + retryButton = helper.getDialogButton("retry"); retryButton.click(); await helper.waitForOverlay(); - expectedFocusedButton = await helper.getPanelButton(".visible-page"); + expectedFocusedButton = await helper.getPanelButton("#visible-page"); await BrowserTestUtils.waitForCondition(() => { return ( @@ -288,10 +286,7 @@ add_task(async function test_focusLastUsedMethod() { expectedFocusedButton.click(); await screenshotReady; - dialog = helper.getDialog(); - - expectedFocusedButton = - dialog._frame.contentDocument.getElementById("download"); + expectedFocusedButton = helper.getDialogButton("download"); await BrowserTestUtils.waitForCondition(() => { return ( @@ -302,28 +297,25 @@ add_task(async function test_focusLastUsedMethod() { is( Services.focus.focusedElement, - expectedFocusedButton, + expectedFocusedButton.buttonEl, "The download button in the preview dialog should have focus" ); let screenshotExit = TestUtils.topicObserved("screenshots-exit"); - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); copyButton.click(); await screenshotExit; helper.triggerUIFromToolbar(); await helper.waitForOverlay(); - let visibleButton = await helper.getPanelButton(".visible-page"); + let visibleButton = await helper.getPanelButton("#visible-page"); screenshotReady = TestUtils.topicObserved("screenshots-preview-ready"); visibleButton.click(); await screenshotReady; - dialog = helper.getDialog(); - - expectedFocusedButton = - dialog._frame.contentDocument.getElementById("copy"); + expectedFocusedButton = helper.getDialogButton("copy"); await BrowserTestUtils.waitForCondition(() => { return ( @@ -334,13 +326,12 @@ add_task(async function test_focusLastUsedMethod() { is( Services.focus.focusedElement, - expectedFocusedButton, + expectedFocusedButton.buttonEl, "The copy button in the preview dialog should have focus" ); screenshotExit = TestUtils.topicObserved("screenshots-exit"); - let downloadButton = - dialog._frame.contentDocument.getElementById("download"); + let downloadButton = helper.getDialogButton("download"); downloadButton.click(); await Promise.all([screenshotExit, downloadFinishedPromise]); @@ -350,16 +341,13 @@ add_task(async function test_focusLastUsedMethod() { helper.triggerUIFromToolbar(); await helper.waitForOverlay(); - visibleButton = await helper.getPanelButton(".visible-page"); + visibleButton = await helper.getPanelButton("#visible-page"); screenshotReady = TestUtils.topicObserved("screenshots-preview-ready"); visibleButton.click(); await screenshotReady; - dialog = helper.getDialog(); - - expectedFocusedButton = - dialog._frame.contentDocument.getElementById("download"); + expectedFocusedButton = helper.getDialogButton("download"); await BrowserTestUtils.waitForCondition(() => { return ( @@ -370,7 +358,7 @@ add_task(async function test_focusLastUsedMethod() { is( Services.focus.focusedElement, - expectedFocusedButton, + expectedFocusedButton.buttonEl, "The download button in the preview dialog should have focus" ); @@ -382,3 +370,89 @@ add_task(async function test_focusLastUsedMethod() { await SpecialPowers.popPrefEnv(); }); + +add_task(async function testFocusedIsLocked() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + + let panel = await helper.waitForPanel(); + let mozButtonGroup = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector("moz-button-group"); + let firstButton = mozButtonGroup.firstElementChild; + let lastButton = mozButtonGroup.lastElementChild; + + firstButton.focus(); + + await BrowserTestUtils.waitForCondition(() => { + return firstButton.getRootNode().activeElement === firstButton; + }, "The first button in the panel should have focus"); + info( + `Actual focused id: ${Services.focus.focusedElement.id}. Expected focused id: ${firstButton.id}` + ); + is( + Services.focus.focusedElement, + firstButton, + "The first button in the panel should have focus" + ); + + EventUtils.synthesizeKey("KEY_Tab"); + + await BrowserTestUtils.waitForCondition(() => { + return lastButton.getRootNode().activeElement === lastButton; + }, "The last button in the panel should have focus"); + info( + `Actual focused id: ${Services.focus.focusedElement.id}. Expected focused id: ${lastButton.id}` + ); + is( + Services.focus.focusedElement, + lastButton, + "The last button in the panel should have focus" + ); + + EventUtils.synthesizeKey("KEY_Tab"); + + // Focus should move to the content document + await BrowserTestUtils.waitForCondition(() => { + return ( + firstButton.getRootNode().activeElement !== firstButton && + lastButton.getRootNode().activeElement !== lastButton + ); + }, "The first and last buttons do not have focus"); + Assert.notEqual( + Services.focus.focusedElement, + firstButton, + "The first button does not have focus" + ); + Assert.notEqual( + Services.focus.focusedElement, + lastButton, + "The last button does not have focus" + ); + + EventUtils.synthesizeKey("KEY_Tab"); + + info( + `Actual focused id: ${Services.focus.focusedElement.id}. Expected focused id: ${firstButton.id}` + ); + await BrowserTestUtils.waitForCondition(() => { + return firstButton.getRootNode().activeElement === firstButton; + }, "The first button in the panel should have focus"); + info( + `Actual focused id: ${Services.focus.focusedElement.id}. Expected focused id: ${firstButton.id}` + ); + is( + Services.focus.focusedElement, + firstButton, + "The first button in the panel should have focus" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_telemetry_tests.js b/browser/components/screenshots/tests/browser/browser_screenshots_telemetry_tests.js index 782ffa3fd3..eabb1ee152 100644 --- a/browser/components/screenshots/tests/browser/browser_screenshots_telemetry_tests.js +++ b/browser/components/screenshots/tests/browser/browser_screenshots_telemetry_tests.js @@ -82,11 +82,7 @@ const EXTRA_EVENTS = [ add_task(async function test_started_and_canceled_events() { await SpecialPowers.pushPrefEnv({ - set: [ - ["browser.urlbar.quickactions.enabled", true], - ["browser.urlbar.suggest.quickactions", true], - ["browser.urlbar.shortcuts.quickactions", true], - ], + set: [["browser.urlbar.secondaryActions.featureGate", true]], }); await BrowserTestUtils.withNewTab( @@ -99,22 +95,27 @@ add_task(async function test_started_and_canceled_events() { let helper = new ScreenshotsHelper(browser); let screenshotExit; + info("Open screenshots via toolbar button"); helper.triggerUIFromToolbar(); await helper.waitForOverlay(); screenshotExit = TestUtils.topicObserved("screenshots-exit"); + info("Close screenshots via toolbar button"); helper.triggerUIFromToolbar(); await helper.waitForOverlayClosed(); await screenshotExit; + info("Open screenshots via keyboard shortcut"); EventUtils.synthesizeKey("s", { shiftKey: true, accelKey: true }); await helper.waitForOverlay(); screenshotExit = TestUtils.topicObserved("screenshots-exit"); + info("Close screenshots via keyboard shortcut"); EventUtils.synthesizeKey("s", { shiftKey: true, accelKey: true }); await helper.waitForOverlayClosed(); await screenshotExit; + info("Open screenshots via context menu"); let contextMenu = document.getElementById("contentAreaContextMenu"); let popupShownPromise = BrowserTestUtils.waitForEvent( contextMenu, @@ -152,23 +153,21 @@ add_task(async function test_started_and_canceled_events() { await popupShownPromise; screenshotExit = TestUtils.topicObserved("screenshots-exit"); + info("Close screenshots via context menu"); contextMenu.activateItem( contextMenu.querySelector("#context-take-screenshot") ); await helper.waitForOverlayClosed(); await screenshotExit; + info("Open screenshots via quickactions"); await UrlbarTestUtils.promiseAutocompleteResultPopup({ window, value: "screenshot", waitForFocus: SimpleTest.waitForFocus, }); - let { result } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1); - Assert.equal(result.type, UrlbarUtils.RESULT_TYPE.DYNAMIC); - Assert.equal(result.providerName, "quickactions"); - info("Trigger the screenshot mode"); - EventUtils.synthesizeKey("KEY_ArrowDown", {}, window); + EventUtils.synthesizeKey("KEY_Tab", {}, window); EventUtils.synthesizeKey("KEY_Enter", {}, window); await helper.waitForOverlay(); @@ -177,13 +176,10 @@ add_task(async function test_started_and_canceled_events() { value: "screenshot", waitForFocus: SimpleTest.waitForFocus, }); - ({ result } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1)); - Assert.equal(result.type, UrlbarUtils.RESULT_TYPE.DYNAMIC); - Assert.equal(result.providerName, "quickactions"); - info("Trigger the screenshot mode"); + info("Close screenshots via quickactions"); screenshotExit = TestUtils.topicObserved("screenshots-exit"); - EventUtils.synthesizeKey("KEY_ArrowDown", {}, window); + EventUtils.synthesizeKey("KEY_Tab", {}, window); EventUtils.synthesizeKey("KEY_Enter", {}, window); await helper.waitForOverlayClosed(); await screenshotExit; @@ -215,12 +211,11 @@ add_task(async function test_started_retry() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); await screenshotReady; - let dialog = helper.getDialog(); - let retryButton = dialog._frame.contentDocument.getElementById("retry"); + let retryButton = helper.getDialogButton("retry"); ok(retryButton, "Got the retry button"); retryButton.click(); @@ -253,12 +248,11 @@ add_task(async function test_canceled() { // click the full page button in panel let fullPageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".full-page"); + .shadowRoot.querySelector("#full-page"); fullPageButton.click(); await screenshotReady; - let dialog = helper.getDialog(); - let cancelButton = dialog._frame.contentDocument.getElementById("cancel"); + let cancelButton = helper.getDialogButton("cancel"); ok(cancelButton, "Got the cancel button"); let screenshotExit = TestUtils.topicObserved("screenshots-exit"); @@ -315,13 +309,12 @@ add_task(async function test_copy() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); info("clicked visible page, waiting for screenshots-preview-ready"); await screenshotReady; - let dialog = helper.getDialog(); - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); let screenshotExit = TestUtils.topicObserved("screenshots-exit"); let clipboardChanged = helper.waitForRawClipboardChange( @@ -426,13 +419,12 @@ add_task(async function test_extra_telemetry() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); info("clicked visible page, waiting for screenshots-preview-ready"); await screenshotReady; - let dialog = helper.getDialog(); - let retryButton = dialog._frame.contentDocument.getElementById("retry"); + let retryButton = helper.getDialogButton("retry"); retryButton.click(); info("waiting for panel"); @@ -443,14 +435,13 @@ add_task(async function test_extra_telemetry() { // click the full page button in panel let fullPageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".full-page"); + .shadowRoot.querySelector("#full-page"); fullPageButton.click(); await screenshotReady; let screenshotExit = TestUtils.topicObserved("screenshots-exit"); - dialog = helper.getDialog(); - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); retryButton.click(); // click copy button on dialog box info("clicking the copy button"); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_downloads.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_downloads.js index 51d5b858b9..fce0843d33 100644 --- a/browser/components/screenshots/tests/browser/browser_screenshots_test_downloads.js +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_downloads.js @@ -46,6 +46,18 @@ function waitForFilePicker() { MockFilePicker.showCallback = () => { MockFilePicker.showCallback = null; ok(true, "Saw the file picker"); + + resolve(); + }; + }); +} + +function waitForFilePickerCancel() { + return new Promise(resolve => { + MockFilePicker.showCallback = () => { + MockFilePicker.showCallback = null; + ok(true, "Saw the file picker"); + MockFilePicker.returnValue = MockFilePicker.returnCancel; resolve(); }; }); @@ -109,15 +121,12 @@ add_task(async function test_download_without_filepicker() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); - let dialog = helper.getDialog(); - await screenshotReady; - let downloadButton = - dialog._frame.contentDocument.getElementById("download"); + let downloadButton = helper.getDialogButton("download"); ok(downloadButton, "Got the download button"); let screenshotExit = TestUtils.topicObserved("screenshots-exit"); @@ -184,3 +193,50 @@ add_task(async function test_download_with_filepicker() { } ); }); + +add_task(async function test_download_filepicker_canceled() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.useDownloadDir", false]], + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + let visiblepageButton = await helper.getPanelButton("#visible-page"); + visiblepageButton.click(); + await screenshotReady; + + let downloadButton = helper.getDialogButton("download"); + + let filePickerCanceled = waitForFilePickerCancel(); + downloadButton.click(); + info("download button clicked"); + await filePickerCanceled; + + let cancelButton = helper.getDialogButton("cancel"); + + await BrowserTestUtils.waitForMutationCondition( + cancelButton, + { attributes: true }, + () => !cancelButton.disabled + ); + + let screenshotExit = TestUtils.topicObserved("screenshots-exit"); + cancelButton.click(); + + await screenshotExit; + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_full_page.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_full_page.js index 006a9819ed..10828eceec 100644 --- a/browser/components/screenshots/tests/browser/browser_screenshots_test_full_page.js +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_full_page.js @@ -39,16 +39,14 @@ add_task(async function test_fullpageScreenshot() { ); // click the full page button in panel - let visiblePage = panel + let fullpageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".full-page"); - visiblePage.click(); - - let dialog = helper.getDialog(); + .shadowRoot.querySelector("#full-page"); + fullpageButton.click(); await screenshotReady; - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); ok(copyButton, "Got the copy button"); let clipboardChanged = helper.waitForRawClipboardChange( @@ -136,16 +134,14 @@ add_task(async function test_fullpageScreenshotScrolled() { ); // click the full page button in panel - let visiblePage = panel + let fullpageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".full-page"); - visiblePage.click(); - - let dialog = helper.getDialog(); + .shadowRoot.querySelector("#full-page"); + fullpageButton.click(); await screenshotReady; - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); ok(copyButton, "Got the copy button"); let clipboardChanged = helper.waitForRawClipboardChange( @@ -198,3 +194,80 @@ add_task(async function test_fullpageScreenshotScrolled() { } ); }); + +add_task(async function test_fullpageScreenshotRTL() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: RTL_TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + let devicePixelRatio = await getContentDevicePixelRatio(browser); + + let expectedWidth = Math.floor( + devicePixelRatio * contentInfo.scrollWidth + ); + let expectedHeight = Math.floor( + devicePixelRatio * contentInfo.scrollHeight + ); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = await helper.waitForPanel(); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + // click the full page button in panel + let fullpageButton = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector("#full-page"); + fullpageButton.click(); + + await screenshotReady; + + let copyButton = helper.getDialogButton("copy"); + ok(copyButton, "Got the copy button"); + + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + info( + "expecting: " + + JSON.stringify({ expectedWidth, expectedHeight }, null, 2) + ); + let clipboardChanged = helper.waitForRawClipboardChange( + expectedWidth, + expectedHeight + ); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + let result = await clipboardChanged; + + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + Assert.equal(result.width, expectedWidth, "Widths should be equal"); + Assert.equal(result.height, expectedHeight, "Heights should be equal"); + + assertPixel(result.color.topLeft, [255, 255, 255], "Top left pixel"); + assertPixel(result.color.topRight, [255, 255, 255], "Top right pixel"); + assertPixel( + result.color.bottomLeft, + [255, 255, 255], + "Bottom left pixel" + ); + assertPixel( + result.color.bottomRight, + [255, 255, 255], + "Bottom right pixel" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_visible.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_visible.js index c53b44d5ea..2cc4eb241a 100644 --- a/browser/components/screenshots/tests/browser/browser_screenshots_test_visible.js +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_visible.js @@ -45,14 +45,12 @@ add_task(async function test_visibleScreenshot() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); - let dialog = helper.getDialog(); - await screenshotReady; - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); ok(copyButton, "Got the copy button"); let clipboardChanged = helper.waitForRawClipboardChange( @@ -144,14 +142,12 @@ add_task(async function test_visibleScreenshotScrolledY() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); - let dialog = helper.getDialog(); - await screenshotReady; - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); ok(copyButton, "Got the copy button"); let clipboardChanged = helper.waitForRawClipboardChange( @@ -243,14 +239,12 @@ add_task(async function test_visibleScreenshotScrolledX() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); - let dialog = helper.getDialog(); - await screenshotReady; - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); ok(copyButton, "Got the copy button"); let clipboardChanged = helper.waitForRawClipboardChange( @@ -342,14 +336,12 @@ add_task(async function test_visibleScreenshotScrolledXAndY() { // click the visible page button in panel let visiblePageButton = panel .querySelector("screenshots-buttons") - .shadowRoot.querySelector(".visible-page"); + .shadowRoot.querySelector("#visible-page"); visiblePageButton.click(); - let dialog = helper.getDialog(); - await screenshotReady; - let copyButton = dialog._frame.contentDocument.getElementById("copy"); + let copyButton = helper.getDialogButton("copy"); ok(copyButton, "Got the copy button"); let clipboardChanged = helper.waitForRawClipboardChange( @@ -402,3 +394,84 @@ add_task(async function test_visibleScreenshotScrolledXAndY() { } ); }); + +add_task(async function test_visibleScreenshotRTL() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: RTL_TEST_PAGE, + }, + async browser => { + await SpecialPowers.spawn(browser, [], () => { + content.scrollTo(-1000, 0); + }); + + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + let devicePixelRatio = await getContentDevicePixelRatio(browser); + + let expectedWidth = Math.floor( + devicePixelRatio * contentInfo.clientWidth + ); + let expectedHeight = Math.floor( + devicePixelRatio * contentInfo.clientHeight + ); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = await helper.waitForPanel(); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + // click the full page button in panel + let visiblePage = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector("#visible-page"); + visiblePage.click(); + + await screenshotReady; + + let copyButton = helper.getDialogButton("copy"); + ok(copyButton, "Got the copy button"); + + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + info( + "expecting: " + + JSON.stringify({ expectedWidth, expectedHeight }, null, 2) + ); + let clipboardChanged = helper.waitForRawClipboardChange( + expectedWidth, + expectedHeight + ); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + let result = await clipboardChanged; + + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + Assert.equal(result.width, expectedWidth, "Widths should be equal"); + Assert.equal(result.height, expectedHeight, "Heights should be equal"); + + assertPixel(result.color.topLeft, [255, 255, 255], "Top left pixel"); + assertPixel(result.color.topRight, [255, 255, 255], "Top right pixel"); + assertPixel( + result.color.bottomLeft, + [255, 255, 255], + "Bottom left pixel" + ); + assertPixel( + result.color.bottomRight, + [255, 255, 255], + "Bottom right pixel" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_test_element_picker.js b/browser/components/screenshots/tests/browser/browser_test_element_picker.js index 3e2069134e..a24149d15e 100644 --- a/browser/components/screenshots/tests/browser/browser_test_element_picker.js +++ b/browser/components/screenshots/tests/browser/browser_test_element_picker.js @@ -10,7 +10,6 @@ add_task(async function test_element_picker() { url: TEST_PAGE, }, async browser => { - await clearAllTelemetryEvents(); let helper = new ScreenshotsHelper(browser); helper.triggerUIFromToolbar(); @@ -54,3 +53,37 @@ add_task(async function test_element_picker() { } ); }); + +add_task(async function test_element_pickerRTL() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: RTL_TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + + await helper.clickTestPageElement(); + + let rect = await helper.getTestPageElementRect(); + let region = await helper.getSelectionRegionDimensions(); + + info(`element rect: ${JSON.stringify(rect, null, 2)}`); + info(`selected region: ${JSON.stringify(region, null, 2)}`); + + is( + region.width, + rect.width, + "The selected region width is the same as the element width" + ); + is( + region.height, + rect.height, + "The selected region height is the same as the element height" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_test_resize.js b/browser/components/screenshots/tests/browser/browser_test_resize.js index b249a346d6..a848a2ac66 100644 --- a/browser/components/screenshots/tests/browser/browser_test_resize.js +++ b/browser/components/screenshots/tests/browser/browser_test_resize.js @@ -12,6 +12,8 @@ add_task(async function test_window_resize() { url: RESIZE_TEST_PAGE, }, async browser => { + await new Promise(r => window.requestAnimationFrame(r)); + let helper = new ScreenshotsHelper(browser); await helper.resizeContentWindow(windowWidth, window.outerHeight); const originalContentDimensions = await helper.getContentDimensions(); @@ -61,6 +63,8 @@ add_task(async function test_window_resize_vertical_writing_mode() { content.document.documentElement.style = "writing-mode: vertical-lr;"; }); + await new Promise(r => window.requestAnimationFrame(r)); + let helper = new ScreenshotsHelper(browser); await helper.resizeContentWindow(windowWidth, window.outerHeight); const originalContentDimensions = await helper.getContentDimensions(); diff --git a/browser/components/screenshots/tests/browser/browser_test_selection_size_text.js b/browser/components/screenshots/tests/browser/browser_test_selection_size_text.js index 38d1acbea9..bfe3b884e0 100644 --- a/browser/components/screenshots/tests/browser/browser_test_selection_size_text.js +++ b/browser/components/screenshots/tests/browser/browser_test_selection_size_text.js @@ -22,7 +22,7 @@ add_task(async function test_selectionSizeTest() { Assert.equal( actualText, - `${400 * dpr} x ${400 * dpr}`, + `${400 * dpr} × ${400 * dpr}`, "The selection size text is the same" ); } @@ -50,7 +50,7 @@ add_task(async function test_selectionSizeTestAt1Point5Zoom() { Assert.equal( actualText, - `${400 * dpr * zoom} x ${400 * dpr * zoom}`, + `${400 * dpr * zoom} × ${400 * dpr * zoom}`, "The selection size text is the same" ); } @@ -78,7 +78,7 @@ add_task(async function test_selectionSizeTestAtPoint5Zoom() { Assert.equal( actualText, - `${400 * dpr * zoom} x ${400 * dpr * zoom}`, + `${400 * dpr * zoom} × ${400 * dpr * zoom}`, "The selection size text is the same" ); } diff --git a/browser/components/screenshots/tests/browser/browser_text_selectionAPI_test.js b/browser/components/screenshots/tests/browser/browser_text_selectionAPI_test.js new file mode 100644 index 0000000000..78764d3847 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_text_selectionAPI_test.js @@ -0,0 +1,55 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_textSelectedDuringScreenshot() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: SELECTION_TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + let rect = await helper.getTestPageElementRect("selection"); + + await ContentTask.spawn(browser, [], async () => { + let selection = content.window.getSelection(); + let elToSelect = content.document.getElementById("selection"); + + let range = content.document.createRange(); + range.selectNode(elToSelect); + selection.addRange(range); + }); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + + await helper.clickTestPageElement("selection"); + + let clipboardChanged = helper.waitForRawClipboardChange( + Math.round(rect.width), + Math.round(rect.height), + { allPixels: true } + ); + + await helper.clickCopyButton(); + + info("Waiting for clipboard change"); + let result = await clipboardChanged; + let allPixels = result.allPixels; + info(`${typeof allPixels}, ${allPixels.length}`); + + let sumOfPixels = Object.values(allPixels).reduce( + (accumulator, currentVal) => accumulator + currentVal, + 0 + ); + + Assert.less( + sumOfPixels, + allPixels.length * 255, + "Sum of pixels is less than all white pixels" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/head.js b/browser/components/screenshots/tests/browser/head.js index 762da5f866..483e67fa34 100644 --- a/browser/components/screenshots/tests/browser/head.js +++ b/browser/components/screenshots/tests/browser/head.js @@ -20,6 +20,8 @@ const SHORT_TEST_PAGE = TEST_ROOT + "short-test-page.html"; const LARGE_TEST_PAGE = TEST_ROOT + "large-test-page.html"; const IFRAME_TEST_PAGE = TEST_ROOT + "iframe-test-page.html"; const RESIZE_TEST_PAGE = TEST_ROOT + "test-page-resize.html"; +const SELECTION_TEST_PAGE = TEST_ROOT + "test-selectionAPI-page.html"; +const RTL_TEST_PAGE = TEST_ROOT + "rtl-test-page.html"; const { MAX_CAPTURE_DIMENSION, MAX_CAPTURE_AREA } = ChromeUtils.importESModule( "resource:///modules/ScreenshotsUtils.sys.mjs" @@ -27,8 +29,8 @@ const { MAX_CAPTURE_DIMENSION, MAX_CAPTURE_AREA } = ChromeUtils.importESModule( const gScreenshotUISelectors = { panel: "#screenshotsPagePanel", - fullPageButton: "button.full-page", - visiblePageButton: "button.visible-page", + fullPageButton: "button#full-page", + visiblePageButton: "button#visible-page", copyButton: "button.#copy", }; @@ -96,6 +98,31 @@ class ScreenshotsHelper { return button; } + /** + * Get the button from screenshots preview dialog + * @param {Sting} name The id of the button to query + * @returns The button or null + */ + getDialogButton(name) { + let dialog = this.getDialog(); + let screenshotsPreviewEl = dialog._frame.contentDocument.querySelector( + "screenshots-preview" + ); + + switch (name) { + case "retry": + return screenshotsPreviewEl.retryButtonEl; + case "cancel": + return screenshotsPreviewEl.cancelButtonEl; + case "copy": + return screenshotsPreviewEl.copyButtonEl; + case "download": + return screenshotsPreviewEl.downloadButtonEl; + } + + return null; + } + async waitForPanel() { let panel = this.panel; await BrowserTestUtils.waitForCondition(async () => { @@ -115,6 +142,8 @@ class ScreenshotsHelper { let init = await this.isOverlayInitialized(); return init; }); + + await new Promise(r => window.requestAnimationFrame(r)); info("Overlay is visible"); } @@ -147,6 +176,8 @@ class ScreenshotsHelper { info("Is overlay initialized: " + !init); return init; }); + + await new Promise(r => window.requestAnimationFrame(r)); info("Overlay is not visible"); } @@ -213,7 +244,11 @@ class ScreenshotsHelper { let dimensions; await ContentTaskUtils.waitForCondition(() => { dimensions = screenshotsChild.overlay.hoverElementRegion.dimensions; - return dimensions.width === width && dimensions.height === height; + if (dimensions.width === width && dimensions.height === height) { + return true; + } + info(`Got: ${JSON.stringify(dimensions)}`); + return false; }, "The hover element region is the expected width and height"); return dimensions; } @@ -420,6 +455,32 @@ class ScreenshotsHelper { ); } + waitForContentMousePosition(left, top) { + return ContentTask.spawn(this.browser, [left, top], async ([x, y]) => { + function isCloseEnough(a, b, diff) { + return Math.abs(a - b) <= diff; + } + + let cursorX = {}; + let cursorY = {}; + + await ContentTaskUtils.waitForCondition(() => { + content.window.windowUtils.getLastOverWindowPointerLocationInCSSPixels( + cursorX, + cursorY + ); + if ( + isCloseEnough(cursorX.value, x, 1) && + isCloseEnough(cursorY.value, y, 1) + ) { + return true; + } + info(`Got: ${JSON.stringify({ cursorX, cursorY, x, y })}`); + return false; + }, `Wait for cursor to be ${x}, ${y}`); + }); + } + async clickDownloadButton() { let { centerX: x, centerY: y } = await ContentTask.spawn( this.browser, @@ -580,7 +641,7 @@ class ScreenshotsHelper { * Returns a promise that resolves when the clipboard data has changed * Otherwise rejects */ - waitForRawClipboardChange(epectedWidth, expectedHeight) { + waitForRawClipboardChange(epectedWidth, expectedHeight, options = {}) { const initialClipboardData = Date.now().toString(); SpecialPowers.clipboardCopyString(initialClipboardData); @@ -588,7 +649,7 @@ class ScreenshotsHelper { async () => { let data; try { - data = await this.getImageSizeAndColorFromClipboard(); + data = await this.getImageSizeAndColorFromClipboard(options); } catch (e) { console.log("Failed to get image/png clipboard data:", e); return false; @@ -601,6 +662,7 @@ class ScreenshotsHelper { ) { return data; } + info(`Got from clipboard: ${JSON.stringify(data, null, 2)}`); return false; }, "Waiting for screenshot to copy to clipboard", @@ -627,9 +689,14 @@ class ScreenshotsHelper { scrollMaxY, scrollX, scrollY, + scrollMinX, + scrollMinY, } = content.window; - let width = innerWidth + scrollMaxX; - let height = innerHeight + scrollMaxY; + + let scrollWidth = innerWidth + scrollMaxX - scrollMinX; + let scrollHeight = innerHeight + scrollMaxY - scrollMinY; + let clientHeight = innerHeight; + let clientWidth = innerWidth; const scrollbarHeight = {}; const scrollbarWidth = {}; @@ -638,18 +705,22 @@ class ScreenshotsHelper { scrollbarWidth, scrollbarHeight ); - width -= scrollbarWidth.value; - height -= scrollbarHeight.value; - innerWidth -= scrollbarWidth.value; - innerHeight -= scrollbarHeight.value; + scrollWidth -= scrollbarWidth.value; + scrollHeight -= scrollbarHeight.value; + clientWidth -= scrollbarWidth.value; + clientHeight -= scrollbarHeight.value; return { - clientHeight: innerHeight, - clientWidth: innerWidth, - scrollHeight: height, - scrollWidth: width, + clientWidth, + clientHeight, + scrollWidth, + scrollHeight, scrollX, scrollY, + scrollbarWidth: scrollbarWidth.value, + scrollbarHeight: scrollbarHeight.value, + scrollMinX, + scrollMinY, }; }); } @@ -756,7 +827,7 @@ class ScreenshotsHelper { * :screenshot command. * @return The {width, height, color} dimension and color object. */ - async getImageSizeAndColorFromClipboard() { + async getImageSizeAndColorFromClipboard(options = {}) { let flavor = "image/png"; let image = getRawClipboardData(flavor); if (!image) { @@ -796,8 +867,8 @@ class ScreenshotsHelper { // which could mess all sorts of things up return SpecialPowers.spawn( this.browser, - [buffer], - async function (_buffer) { + [buffer, options], + async function (_buffer, _options) { const img = content.document.createElement("img"); const loaded = new Promise(r => { img.addEventListener("load", r, { once: true }); @@ -830,6 +901,11 @@ class ScreenshotsHelper { 1 ); + let allPixels = null; + if (_options.allPixels) { + allPixels = context.getImageData(0, 0, img.width, img.height); + } + img.remove(); content.URL.revokeObjectURL(url); @@ -842,6 +918,7 @@ class ScreenshotsHelper { bottomLeft: bottomLeft.data, bottomRight: bottomRight.data, }, + allPixels: allPixels?.data, }; } ); diff --git a/browser/components/screenshots/tests/browser/rtl-test-page.html b/browser/components/screenshots/tests/browser/rtl-test-page.html new file mode 100644 index 0000000000..b76eab6f1c --- /dev/null +++ b/browser/components/screenshots/tests/browser/rtl-test-page.html @@ -0,0 +1,8 @@ +<html lang="en" dir="rtl"> +<head> + <title>Screenshots</title> +</head> +<body> + <div id="testPageElement" style="width:150vw;background-color: blue;">hello world</div> +</body> +</html> diff --git a/browser/components/screenshots/tests/browser/test-selectionAPI-page.html b/browser/components/screenshots/tests/browser/test-selectionAPI-page.html new file mode 100644 index 0000000000..17c29a3ccf --- /dev/null +++ b/browser/components/screenshots/tests/browser/test-selectionAPI-page.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Screenshots</title> +</head> +<body> + <p id="selection" style="color: white;width: fit-content;">hello world</p> +</body> +</html> |