diff options
Diffstat (limited to 'browser/components/screenshots/tests')
17 files changed, 2675 insertions, 0 deletions
diff --git a/browser/components/screenshots/tests/browser/browser.ini b/browser/components/screenshots/tests/browser/browser.ini new file mode 100644 index 0000000000..47cafe5bb2 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser.ini @@ -0,0 +1,25 @@ +[DEFAULT] +support-files = + head.js + test-page.html + short-test-page.html + +prefs = + extensions.screenshots.disabled=false + screenshots.browser.component.enabled=true + +[browser_screenshots_drag_scroll_test.js] +[browser_screenshots_drag_test.js] +[browser_screenshots_focus_test.js] +[browser_screenshots_overlay_panel_sync.js] +[browser_screenshots_page_unload.js] +[browser_screenshots_short_page_test.js] +[browser_screenshots_test_downloads.js] +[browser_screenshots_test_escape.js] +[browser_screenshots_test_full_page.js] +skip-if = (!debug && os == 'win' && os_version == '6.1') # Bug 1746281 +[browser_screenshots_test_page_crash.js] +skip-if = !crashreporter +[browser_screenshots_test_toggle_pref.js] +[browser_screenshots_test_toolbar_button.js] +[browser_screenshots_test_visible.js] diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_drag_scroll_test.js b/browser/components/screenshots/tests/browser/browser_screenshots_drag_scroll_test.js new file mode 100644 index 0000000000..77d361b26b --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_drag_scroll_test.js @@ -0,0 +1,317 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Test that screenshots overlay covers the entire page + */ +add_task(async function test_overlayCoversEntirePage() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 500, 500); + + let dimensions = await helper.getSelectionLayerDimensions(); + info(JSON.stringify(dimensions)); + is( + dimensions.scrollWidth, + 4000, + "The overlay spans the entire width of the page" + ); + + is( + dimensions.scrollHeight, + 4000, + "The overlay spans the entire height of the page" + ); + } + ); +}); + +/** + * Test dragging screenshots box off top left of screen + */ +add_task(async function test_draggingBoxOffTopLeft() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + let startX = 10; + let startY = 10; + let endX = 500; + let endY = 500; + await helper.dragOverlay(startX, startY, endX, endY); + + mouse.down( + startX + Math.floor((endX - startX) / 2), + startY + Math.floor((endY - startY) / 2) + ); + + await helper.waitForStateChange("resizing"); + let state = await helper.getOverlayState(); + is(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(10, 10); + + // We moved the box to the edge of the screen so we need to wait until the box size is updated + await helper.waitForSelectionBoxSizeChange(490); + + let dimensions = await helper.getSelectionBoxDimensions(); + + is(dimensions.x1, 0, "The box x1 position is now 0"); + is(dimensions.y1, 0, "The box y1 position is now 0"); + is(dimensions.width, 255, "The box width is now 255"); + is(dimensions.height, 255, "The box height is now 255"); + + mouse.move( + startX + Math.floor((endX - startX) / 2), + startY + Math.floor((endY - startY) / 2) + ); + + mouse.up( + startX + Math.floor((endX - startX) / 2), + startY + Math.floor((endY - startY) / 2) + ); + + // We moved the box off the edge of the screen so we need to wait until the box size is updated + await helper.waitForSelectionBoxSizeChange(255); + + dimensions = await helper.getSelectionBoxDimensions(); + + is(dimensions.x1, 10, "The box x1 position is now 10 again"); + is(dimensions.y1, 10, "The box y1 position is now 10 again"); + is(dimensions.width, 490, "The box width is now 490 again"); + is(dimensions.height, 490, "The box height is now 490 again"); + } + ); +}); + +/** + * Test dragging screenshots box off bottom right of screen + */ +add_task(async function test_draggingBoxOffBottomRight() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + info(JSON.stringify(contentInfo)); + ok(contentInfo, "Got dimensions back from the content"); + + await helper.scrollContentWindow(4000, 4000); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + let startX = contentInfo.scrollWidth - 500; + let startY = contentInfo.scrollHeight - 500; + let endX = contentInfo.scrollWidth - 20; + let endY = contentInfo.scrollHeight - 20; + + await helper.dragOverlay(startX, startY, endX, endY); + + // move box off the bottom right of the screen + mouse.down( + startX + Math.floor((endX - startX) / 2), + startY + Math.floor((endY - startY) / 2) + ); + mouse.move( + startX + 50 + Math.floor((endX - startX) / 2), + startY + 50 + Math.floor((endY - startY) / 2) + ); + + await helper.waitForStateChange("resizing"); + let state = await helper.getOverlayState(); + is(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(endX, endY); + + // We moved the box to the edge of the screen so we need to wait until the box size is updated + await helper.waitForSelectionBoxSizeChange(480); + + let dimensions = await helper.getSelectionBoxDimensions(); + + is(dimensions.x1, startX + 240, "The box x1 position is now 3748"); + is(dimensions.y1, startY + 240, "The box y1 position is now 3756"); + is(dimensions.width, 252, "The box width is now 252"); + is(dimensions.height, 244, "The box height is now 244"); + + mouse.move( + startX + Math.floor((endX - startX) / 2), + startY + Math.floor((endY - startY) / 2) + ); + + mouse.up( + startX + Math.floor((endX - startX) / 2), + startY + Math.floor((endY - startY) / 2) + ); + + // We moved the box off the edge of the screen so we need to wait until the box size is updated + await helper.waitForSelectionBoxSizeChange(252); + + dimensions = await helper.getSelectionBoxDimensions(); + + is(dimensions.x1, startX, "The box x1 position is now 3508 again"); + is(dimensions.y1, startY, "The box y1 position is now 3516 again"); + is(dimensions.width, 480, "The box width is now 480 again"); + is(dimensions.height, 480, "The box height is now 480 again"); + } + ); +}); + +/** + * test scrolling while screenshots is open + */ +add_task(async function test_scrollingScreenshotsOpen() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + info(JSON.stringify(contentInfo)); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + let startX = 10; + let startY = 10; + let endX = 100; + let endY = 100; + + await helper.dragOverlay(startX, startY, endX, endY); + + let scrollX = 1000; + let scrollY = 1000; + + await helper.scrollContentWindow(scrollX, scrollY); + + let dimensions = await helper.getSelectionBoxDimensions(); + + is(dimensions.x1, startX, "The box x1 position is 10"); + is(dimensions.y1, startY, "The box y1 position is 10"); + is(dimensions.width, endX - startX, "The box width is now 90"); + is(dimensions.height, endY - startY, "The box height is now 90"); + + // reset screenshots box + mouse.click(scrollX + startX, scrollY + endY); + await helper.waitForStateChange("crosshairs"); + + await helper.dragOverlay( + scrollX + startX, + scrollY + startY, + scrollX + endX, + scrollY + endY + ); + + await helper.scrollContentWindow(0, 0); + + dimensions = await helper.getSelectionBoxDimensions(); + + is(dimensions.x1, scrollX + startX, "The box x1 position is 1010"); + is(dimensions.y1, scrollY + startY, "The box y1 position is 1010"); + is(dimensions.width, endX - startX, "The box width is now 90"); + is(dimensions.height, endY - startY, "The box height is now 90"); + + // reset screenshots box + mouse.click(10, 10); + await helper.waitForStateChange("crosshairs"); + + await helper.dragOverlay( + startX, + startY, + contentInfo.clientWidth - 10, + contentInfo.clientHeight - 10 + ); + + await helper.scrollContentWindow( + contentInfo.clientWidth - 20, + contentInfo.clientHeight - 20 + ); + + mouse.down(contentInfo.clientWidth - 10, contentInfo.clientHeight - 10); + + await helper.waitForStateChange("resizing"); + + mouse.move( + contentInfo.clientWidth * 2 - 30, + contentInfo.clientHeight * 2 - 30 + ); + + mouse.up( + contentInfo.clientWidth * 2 - 30, + contentInfo.clientHeight * 2 - 30 + ); + + await helper.waitForStateChange("selected"); + + dimensions = await helper.getSelectionLayerDimensions(); + info(JSON.stringify(dimensions)); + is(dimensions.boxLeft, startX, "The box left is 10"); + is(dimensions.boxTop, startY, "The box top is 10"); + is( + dimensions.boxRight, + contentInfo.clientWidth * 2 - 30, + "The box right is 2 x clientWidth - 30" + ); + is( + dimensions.boxBottom, + contentInfo.clientHeight * 2 - 30, + "The box right is 2 x clientHeight - 30" + ); + is( + dimensions.boxWidth, + contentInfo.clientWidth * 2 - 40, + "The box right is 2 x clientWidth - 40" + ); + is( + dimensions.boxHeight, + contentInfo.clientHeight * 2 - 40, + "The box right is 2 x clientHeight - 40" + ); + is( + dimensions.scrollWidth, + 4000, + "The overlay spans the entire width of the page" + ); + is( + dimensions.scrollHeight, + 4000, + "The overlay spans the entire height of the page" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_drag_test.js b/browser/components/screenshots/tests/browser/browser_screenshots_drag_test.js new file mode 100644 index 0000000000..aba38dccc0 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_drag_test.js @@ -0,0 +1,475 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This function drags to a 490x490 area and copies to the clipboard + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 500, 500); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + helper.clickCopyButton(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + + info("result: " + JSON.stringify(result, null, 2)); + + let expected = Math.floor( + 490 * (await getContentDevicePixelRatio(browser)) + ); + + Assert.equal( + result.width, + expected, + `The copied image from the overlay is ${expected}px in width` + ); + Assert.equal( + result.height, + expected, + `The copied image from the overlay is ${expected}px in height` + ); + } + ); +}); + +/** + * This function drags a 1.5 zoomed browser to a 490x490 area and copies to the clipboard + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + const zoom = 1.5; + let helper = new ScreenshotsHelper(browser); + helper.zoomBrowser(zoom); + + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 500, 500); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + helper.clickCopyButton(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + result.zoom = zoom; + result.devicePixelRatio = window.devicePixelRatio; + result.contentDevicePixelRatio = await getContentDevicePixelRatio( + browser + ); + + info("result: " + JSON.stringify(result, null, 2)); + + let expected = Math.floor( + 490 * (await getContentDevicePixelRatio(browser)) + ); + + Assert.equal( + result.width, + expected, + `The copied image from the overlay is ${expected}px in width` + ); + Assert.equal( + result.height, + expected, + `The copied image from the overlay is ${expected}px in height` + ); + } + ); +}); + +/** + * This function drags an area and clicks elsewhere + * on the overlay to go back to the crosshairs state + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 100, 100); + + // click outside overlay + mouse.click(200, 200); + + await helper.waitForStateChange("crosshairs"); + let state = await helper.getOverlayState(); + Assert.equal(state, "crosshairs", "The state is back to crosshairs"); + } + ); +}); + +/** + * This function drags an area and clicks the + * cancel button to cancel the overlay + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 300, 300); + + helper.clickCancelButton(); + + await helper.waitForOverlayClosed(); + + ok(!(await helper.isOverlayInitialized()), "Overlay is not initialized"); + } + ); +}); + +/** + * This function drags a 490x490 area and moves it along the edges + * and back to the center to confirm that the original size is preserved + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 500, 500); + + let startX = 10; + let startY = 10; + let endX = 500; + let endY = 500; + + mouse.down( + Math.floor((endX - startX) / 2), + Math.floor((endY - startY) / 2) + ); + + await helper.waitForStateChange("resizing"); + let state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(10, 10); + + mouse.move(contentInfo.clientWidth - 10, contentInfo.clientHeight - 10); + + mouse.up( + Math.floor((endX - startX) / 2), + Math.floor((endY - startY) / 2) + ); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + helper.clickCopyButton(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + + info("result: " + JSON.stringify(result, null, 2)); + + let expected = Math.floor( + 490 * (await getContentDevicePixelRatio(browser)) + ); + + Assert.equal( + result.width, + expected, + `The copied image from the overlay is ${expected}px in width` + ); + Assert.equal( + result.height, + expected, + `The copied image from the overlay is ${expected}px in height` + ); + } + ); +}); + +/** + * This function drags a 490x490 area and resizes it to a 300x300 area + * with the 4 sides of the box + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 500, 500); + + let startX = 10; + let startY = 10; + let endX = 500; + let endY = 500; + + let x = Math.floor((endX - startX) / 2); + + // drag top + mouse.down(x, 10); + + await helper.waitForStateChange("resizing"); + let state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(x, 100); + mouse.up(x, 100); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + // drag bottom + mouse.down(x, 500); + + await helper.waitForStateChange("resizing"); + state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(x, 400); + mouse.up(x, 400); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + // drag right + let y = Math.floor((endY - startY) / 2); + mouse.down(500, y); + + await helper.waitForStateChange("resizing"); + state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(400, y); + mouse.up(400, y); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + // drag left + mouse.down(10, y); + + await helper.waitForStateChange("resizing"); + state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(100, y); + mouse.up(100, y); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + helper.endX = 400; + helper.endY = 400; + + helper.clickCopyButton(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + + info("result: " + JSON.stringify(result, null, 2)); + + let expected = Math.floor( + 300 * (await getContentDevicePixelRatio(browser)) + ); + + Assert.equal( + result.width, + expected, + `The copied image from the overlay is ${expected}px in width` + ); + Assert.equal( + result.height, + expected, + `The copied image from the overlay is ${expected}px in height` + ); + } + ); +}); + +/** + * This function drags a 490x490 area and resizes it to a 300x300 area + * with the 4 corners of the box + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 500, 500); + + // drag topright + mouse.down(500, 10); + + await helper.waitForStateChange("resizing"); + let state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(450, 50); + mouse.up(450, 50); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + // drag bottomright + mouse.down(450, 500); + + await helper.waitForStateChange("resizing"); + state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(400, 450); + mouse.up(400, 450); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + // drag bottomleft + mouse.down(10, 450); + + await helper.waitForStateChange("resizing"); + state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(50, 400); + mouse.up(50, 400); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + // drag topleft + mouse.down(50, 50); + + await helper.waitForStateChange("resizing"); + state = await helper.getOverlayState(); + Assert.equal(state, "resizing", "The overlay is in the resizing state"); + + mouse.move(100, 100); + mouse.up(100, 100); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + helper.endX = 400; + helper.endY = 400; + + helper.clickCopyButton(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + + info("result: " + JSON.stringify(result, null, 2)); + + let expected = Math.floor( + 300 * (await getContentDevicePixelRatio(browser)) + ); + + Assert.equal( + result.width, + expected, + `The copied image from the overlay is ${expected}px in width` + ); + Assert.equal( + result.height, + expected, + `The copied image from the overlay is ${expected}px in height` + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_focus_test.js b/browser/components/screenshots/tests/browser/browser_screenshots_focus_test.js new file mode 100644 index 0000000000..d992327128 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_focus_test.js @@ -0,0 +1,34 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function testPanelFocused() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + EventUtils.synthesizeKey("KEY_Tab"); + + let screenshotsButtons = gBrowser.selectedBrowser.ownerDocument + .querySelector("#screenshotsPagePanel") + .querySelector("screenshots-buttons").shadowRoot; + + let focusedElement = screenshotsButtons.querySelector(".visible-page"); + + is( + focusedElement, + screenshotsButtons.activeElement, + "Visible button is focused" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_overlay_panel_sync.js b/browser/components/screenshots/tests/browser/browser_screenshots_overlay_panel_sync.js new file mode 100644 index 0000000000..b66a4d2b57 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_overlay_panel_sync.js @@ -0,0 +1,82 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +async function waitOnTabSwitch() { + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(r => setTimeout(r, 300)); +} + +add_task(async function test_overlay_and_panel_state() { + let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE); + + let screenshotsTab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + TEST_PAGE + ); + let browser = screenshotsTab.linkedBrowser; + + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + helper.assertPanelVisible(); + + await helper.dragOverlay(10, 10, 500, 500); + + await helper.waitForStateChange("selected"); + let state = await helper.getOverlayState(); + is(state, "selected", "The overlay is in the selected state"); + + helper.assertPanelNotVisible(); + + mouse.click(600, 600); + + await helper.waitForStateChange("crosshairs"); + state = await helper.getOverlayState(); + is(state, "crosshairs", "The overlay is in the crosshairs state"); + + await helper.waitForOverlay(); + + helper.assertPanelVisible(); + + await BrowserTestUtils.switchTab(gBrowser, tab1); + await BrowserTestUtils.switchTab(gBrowser, screenshotsTab); + + await helper.waitForOverlayClosed(); + + Assert.ok(!(await helper.isOverlayInitialized()), "Overlay is closed"); + helper.assertPanelNotVisible(); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + helper.assertPanelVisible(); + + await helper.dragOverlay(10, 10, 500, 500); + + await helper.waitForStateChange("selected"); + state = await helper.getOverlayState(); + is(state, "selected", "The overlay is in the selected state"); + + await BrowserTestUtils.switchTab(gBrowser, tab1); + await BrowserTestUtils.switchTab(gBrowser, screenshotsTab); + + Assert.ok(await helper.isOverlayInitialized(), "Overlay is open"); + helper.assertPanelNotVisible(); + state = await helper.getOverlayState(); + is(state, "selected", "The overlay is in the selected state"); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlayClosed(); + + Assert.ok(!(await helper.isOverlayInitialized()), "Overlay is closed"); + helper.assertPanelNotVisible(); + + gBrowser.removeTab(tab1); + gBrowser.removeTab(screenshotsTab); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_page_unload.js b/browser/components/screenshots/tests/browser/browser_screenshots_page_unload.js new file mode 100644 index 0000000000..dea97978e4 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_page_unload.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + await SpecialPowers.spawn(browser, [TEST_PAGE], url => { + let a = content.document.createElement("a"); + a.id = "clickMe"; + a.href = url; + a.textContent = "Click me to unload page"; + content.document.querySelector("body").appendChild(a); + }); + + let helper = new ScreenshotsHelper(browser); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + await ContentTask.spawn(browser, null, async () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + Assert.ok(screenshotsChild._overlay._initialized, "The overlay exists"); + }); + + await SpecialPowers.spawn(browser, [], () => { + content.document.querySelector("#clickMe").click(); + }); + + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_hidden(panel); + } + ); + ok( + BrowserTestUtils.is_hidden(panel), + "Panel buttons are hidden after page unload" + ); + + await ContentTask.spawn(browser, null, async () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + Assert.ok( + !screenshotsChild._overlay._initialized, + "The overlay doesn't exist" + ); + }); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_short_page_test.js b/browser/components/screenshots/tests/browser/browser_screenshots_short_page_test.js new file mode 100644 index 0000000000..5772eeb7c3 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_short_page_test.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * This test ensures the overlay is covering the entire window event thought the body is only 100px by 100px + */ +add_task(async function() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: SHORT_TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + await helper.dragOverlay(10, 10, 500, 500); + + let dimensions = await helper.getSelectionLayerDimensions(); + Assert.equal( + dimensions.scrollWidth, + contentInfo.clientWidth, + "The overlay spans the width of the window" + ); + + Assert.equal( + dimensions.scrollHeight, + contentInfo.clientHeight, + "The overlay spans the height of the window" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_downloads.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_downloads.js new file mode 100644 index 0000000000..45dc960fc6 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_downloads.js @@ -0,0 +1,137 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const MockFilePicker = SpecialPowers.MockFilePicker; + +add_setup(async function() { + let tmpDir = PathUtils.join( + PathUtils.tempDir, + "testsavedir" + Math.floor(Math.random() * 2 ** 32) + ); + // Create this dir if it doesn't exist (ignores existing dirs) + await IOUtils.makeDirectory(tmpDir); + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.download.start_downloads_in_tmp_dir", true], + ["browser.helperApps.deleteTempFileOnExit", true], + ["browser.download.folderList", 2], + ["browser.download.dir", tmpDir], + ], + }); + + MockFilePicker.init(window); + MockFilePicker.useAnyFile(); + MockFilePicker.returnValue = MockFilePicker.returnOK; + + registerCleanupFunction(async () => { + Services.prefs.clearUserPref("browser.download.dir"); + Services.prefs.clearUserPref("browser.download.folderList"); + + MockFilePicker.cleanup(); + }); +}); + +function waitForFilePicker() { + return new Promise(resolve => { + MockFilePicker.showCallback = () => { + MockFilePicker.showCallback = null; + ok(true, "Saw the file picker"); + resolve(); + }; + }); +} + +add_task(async function test_download_without_filepicker() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.useDownloadDir", true]], + }); + + let publicDownloads = await Downloads.getList(Downloads.PUBLIC); + // First ensure we catch the download finishing. + let downloadFinishedPromise = new Promise(resolve => { + publicDownloads.addView({ + onDownloadChanged(download) { + info("Download changed!"); + if (download.succeeded || download.error) { + info("Download succeeded or errored"); + publicDownloads.removeView(this); + resolve(download); + } + }, + }); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + await helper.dragOverlay(10, 10, 500, 500); + + helper.clickDownloadButton(); + + info("wait for download to finish"); + let download = await downloadFinishedPromise; + + ok(download.succeeded, "Download should succeed"); + + await publicDownloads.removeFinished(); + } + ); +}); + +add_task(async function test_download_with_filepicker() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.useDownloadDir", false]], + }); + + let publicDownloads = await Downloads.getList(Downloads.PUBLIC); + // First ensure we catch the download finishing. + let downloadFinishedPromise = new Promise(resolve => { + publicDownloads.addView({ + onDownloadChanged(download) { + info("Download changed!"); + if (download.succeeded || download.error) { + info("Download succeeded or errored"); + publicDownloads.removeView(this); + resolve(download); + } + }, + }); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + await helper.waitForOverlay(); + await helper.dragOverlay(10, 10, 500, 500); + + let filePicker = waitForFilePicker(); + + helper.clickDownloadButton(); + + await filePicker; + ok(true, "Export file picker opened"); + + info("wait for download to finish"); + let download = await downloadFinishedPromise; + + ok(download.succeeded, "Download should succeed"); + + await publicDownloads.removeFinished(); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_escape.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_escape.js new file mode 100644 index 0000000000..09605fd316 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_escape.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_fullpageScreenshot() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + EventUtils.synthesizeKey("KEY_Escape"); + + await helper.waitForOverlayClosed(); + } + ); +}); 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 new file mode 100644 index 0000000000..cf83537d87 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_full_page.js @@ -0,0 +1,192 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_fullpageScreenshot() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + // click the full page button in panel + let visiblePage = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector(".full-page"); + visiblePage.click(); + + let dialog = helper.getDialog(); + + await screenshotReady; + + let copyButton = dialog._frame.contentDocument.querySelector( + ".highlight-button-copy" + ); + ok(copyButton, "Got the copy button"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + Assert.equal( + contentInfo.scrollWidth, + result.width, + "Widths should be equal" + ); + + Assert.equal( + contentInfo.scrollHeight, + result.height, + "Heights should be equal" + ); + + // top left + Assert.equal(111, result.color.topLeft[0], "R color value"); + Assert.equal(111, result.color.topLeft[1], "G color value"); + Assert.equal(111, result.color.topLeft[2], "B color value"); + + // top right + Assert.equal(55, result.color.topRight[0], "R color value"); + Assert.equal(155, result.color.topRight[1], "G color value"); + Assert.equal(155, result.color.topRight[2], "B color value"); + + // bottom left + Assert.equal(105, result.color.bottomLeft[0], "R color value"); + Assert.equal(55, result.color.bottomLeft[1], "G color value"); + Assert.equal(105, result.color.bottomLeft[2], "B color value"); + + // bottom right + Assert.equal(52, result.color.bottomRight[0], "R color value"); + Assert.equal(127, result.color.bottomRight[1], "G color value"); + Assert.equal(152, result.color.bottomRight[2], "B color value"); + } + ); +}); + +add_task(async function test_fullpageScreenshotScrolled() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + await SpecialPowers.spawn(browser, [], () => { + content.scrollTo(0, 2008); + }); + + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + // click the full page button in panel + let visiblePage = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector(".full-page"); + visiblePage.click(); + + let dialog = helper.getDialog(); + + await screenshotReady; + + let copyButton = dialog._frame.contentDocument.querySelector( + ".highlight-button-copy" + ); + ok(copyButton, "Got the copy button"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + Assert.equal( + contentInfo.scrollWidth, + result.width, + "Widths should be equal" + ); + + Assert.equal( + contentInfo.scrollHeight, + result.height, + "Heights should be equal" + ); + + // top left + Assert.equal(111, result.color.topLeft[0], "R color value"); + Assert.equal(111, result.color.topLeft[1], "G color value"); + Assert.equal(111, result.color.topLeft[2], "B color value"); + + // top right + Assert.equal(55, result.color.topRight[0], "R color value"); + Assert.equal(155, result.color.topRight[1], "G color value"); + Assert.equal(155, result.color.topRight[2], "B color value"); + + // bottom left + Assert.equal(105, result.color.bottomLeft[0], "R color value"); + Assert.equal(55, result.color.bottomLeft[1], "G color value"); + Assert.equal(105, result.color.bottomLeft[2], "B color value"); + + // bottom right + Assert.equal(52, result.color.bottomRight[0], "R color value"); + Assert.equal(127, result.color.bottomRight[1], "G color value"); + Assert.equal(152, result.color.bottomRight[2], "B color value"); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_page_crash.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_page_crash.js new file mode 100644 index 0000000000..ab5afe49a1 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_page_crash.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_fullpageScreenshot() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + let helper = new ScreenshotsHelper(browser); + + // click toolbar button so UI shows + helper.triggerUIFromToolbar(); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + await ContentTask.spawn(browser, null, async () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + Assert.ok(screenshotsChild._overlay._initialized, "The overlay exists"); + }); + + let waitForPanelHide = BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_hidden(panel); + } + ); + + await BrowserTestUtils.crashFrame(browser); + + await waitForPanelHide; + ok( + BrowserTestUtils.is_hidden(panel), + "Panel buttons are hidden after page crash" + ); + + await ContentTask.spawn(browser, null, async () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + Assert.ok(!screenshotsChild._overlay, "The overlay doesn't exist"); + }); + + let tab = gBrowser.getTabForBrowser(browser); + + SessionStore.reviveCrashedTab(tab); + + ok( + BrowserTestUtils.is_hidden(panel), + "Panel buttons are hidden after page crash" + ); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_toggle_pref.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_toggle_pref.js new file mode 100644 index 0000000000..b778c63163 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_toggle_pref.js @@ -0,0 +1,288 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm"); +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +ChromeUtils.defineESModuleGetters(this, { + ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", +}); +XPCOMUtils.defineLazyGetter(this, "ExtensionManagement", () => { + const { Management } = ChromeUtils.import( + "resource://gre/modules/Extension.jsm" + ); + return Management; +}); + +add_task(async function test() { + let observerSpy = sinon.spy(); + let notifierSpy = sinon.spy(); + + let observerStub = sinon + .stub(ScreenshotsUtils, "observe") + .callsFake(observerSpy); + let notifierStub = sinon + .stub(ScreenshotsUtils, "notify") + .callsFake(function(window, type) { + notifierSpy(); + ScreenshotsUtils.notify.wrappedMethod.apply(this, arguments); + }); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + function awaitExtensionEvent(eventName, id) { + return new Promise(resolve => { + let listener = (_eventName, ...args) => { + let extension = args[0]; + if (_eventName === eventName && extension.id == id) { + ExtensionManagement.off(eventName, listener); + resolve(); + } + }; + ExtensionManagement.on(eventName, listener); + }); + } + const SCREENSHOT_EXTENSION = "screenshots@mozilla.org"; + + let helper = new ScreenshotsHelper(browser); + + ok(observerSpy.notCalled, "Observer not called"); + helper.triggerUIFromToolbar(); + Assert.equal(observerSpy.callCount, 1, "Observer function called once"); + + ok(notifierSpy.notCalled, "Notifier not called"); + EventUtils.synthesizeKey("s", { accelKey: true, shiftKey: true }); + + await TestUtils.waitForCondition(() => notifierSpy.callCount == 1); + Assert.equal(notifierSpy.callCount, 1, "Notify function called once"); + + await TestUtils.waitForCondition(() => observerSpy.callCount == 2); + Assert.equal(observerSpy.callCount, 2, "Observer function called twice"); + + let menu = document.getElementById("contentAreaContextMenu"); + let popupshown = BrowserTestUtils.waitForPopupEvent(menu, "shown"); + EventUtils.synthesizeMouseAtCenter(document.body, { + type: "contextmenu", + }); + await popupshown; + Assert.equal(menu.state, "open", "Context menu is open"); + + let popuphidden = BrowserTestUtils.waitForPopupEvent(menu, "hidden"); + menu.activateItem(menu.querySelector("#context-take-screenshot")); + await popuphidden; + + Assert.equal(observerSpy.callCount, 3, "Observer function called thrice"); + + const COMPONENT_PREF = "screenshots.browser.component.enabled"; + await SpecialPowers.pushPrefEnv({ + set: [[COMPONENT_PREF, false]], + }); + ok(!Services.prefs.getBoolPref(COMPONENT_PREF), "Extension enabled"); + await awaitExtensionEvent("ready", SCREENSHOT_EXTENSION); + + helper.triggerUIFromToolbar(); + Assert.equal( + observerSpy.callCount, + 3, + "Observer function still called thrice" + ); + + await SpecialPowers.spawn( + browser, + ["#firefox-screenshots-preselection-iframe"], + async function(iframeSelector) { + info( + `in waitForUIContent content function, iframeSelector: ${iframeSelector}` + ); + let iframe; + await ContentTaskUtils.waitForCondition(() => { + iframe = content.document.querySelector(iframeSelector); + if (!iframe || !ContentTaskUtils.is_visible(iframe)) { + info("in waitForUIContent, no visible iframe yet"); + return false; + } + return true; + }); + // wait a frame for the screenshots UI to finish any init + await new content.Promise(res => content.requestAnimationFrame(res)); + } + ); + + helper.triggerUIFromToolbar(); + await SpecialPowers.spawn( + browser, + ["#firefox-screenshots-preselection-iframe"], + async function(iframeSelector) { + info( + `in waitForUIContent content function, iframeSelector: ${iframeSelector}` + ); + let iframe; + await ContentTaskUtils.waitForCondition(() => { + iframe = content.document.querySelector(iframeSelector); + if (!iframe || !ContentTaskUtils.is_visible(iframe)) { + info("in waitForUIContent, no visible iframe yet"); + return true; + } + return false; + }); + // wait a frame for the screenshots UI to finish any init + await new content.Promise(res => content.requestAnimationFrame(res)); + } + ); + + popupshown = BrowserTestUtils.waitForPopupEvent(menu, "shown"); + EventUtils.synthesizeMouseAtCenter(document.body, { + type: "contextmenu", + }); + await popupshown; + Assert.equal(menu.state, "open", "Context menu is open"); + + popuphidden = BrowserTestUtils.waitForPopupEvent(menu, "hidden"); + menu.activateItem(menu.querySelector("#context-take-screenshot")); + await popuphidden; + + Assert.equal( + observerSpy.callCount, + 3, + "Observer function still called thrice" + ); + + await SpecialPowers.spawn( + browser, + ["#firefox-screenshots-preselection-iframe"], + async function(iframeSelector) { + info( + `in waitForUIContent content function, iframeSelector: ${iframeSelector}` + ); + let iframe; + await ContentTaskUtils.waitForCondition(() => { + iframe = content.document.querySelector(iframeSelector); + if (!iframe || !ContentTaskUtils.is_visible(iframe)) { + info("in waitForUIContent, no visible iframe yet"); + return false; + } + return true; + }); + // wait a frame for the screenshots UI to finish any init + await new content.Promise(res => content.requestAnimationFrame(res)); + } + ); + + helper.triggerUIFromToolbar(); + await SpecialPowers.spawn( + browser, + ["#firefox-screenshots-preselection-iframe"], + async function(iframeSelector) { + info( + `in waitForUIContent content function, iframeSelector: ${iframeSelector}` + ); + let iframe; + await ContentTaskUtils.waitForCondition(() => { + iframe = content.document.querySelector(iframeSelector); + if (!iframe || !ContentTaskUtils.is_visible(iframe)) { + return true; + } + info("in waitForUIContent, iframe still visible"); + info(iframe); + return false; + }); + // wait a frame for the screenshots UI to finish any init + await new content.Promise(res => content.requestAnimationFrame(res)); + } + ); + + let componentReady = TestUtils.topicObserved( + "screenshots-component-initialized" + ); + + await SpecialPowers.pushPrefEnv({ + set: [[COMPONENT_PREF, true]], + }); + ok(Services.prefs.getBoolPref(COMPONENT_PREF), "Component enabled"); + // Needed for component to initialize + await componentReady; + + helper.triggerUIFromToolbar(); + Assert.equal( + observerSpy.callCount, + 4, + "Observer function called four times" + ); + + const SCREENSHOTS_PREF = "extensions.screenshots.disabled"; + await SpecialPowers.pushPrefEnv({ + set: [[SCREENSHOTS_PREF, true]], + }); + ok(Services.prefs.getBoolPref(SCREENSHOTS_PREF), "Screenshots disabled"); + } + ); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + const SCREENSHOTS_PREF = "extensions.screenshots.disabled"; + ok(Services.prefs.getBoolPref(SCREENSHOTS_PREF), "Screenshots disabled"); + + ok( + document.getElementById("screenshot-button").disabled, + "Toolbar button disabled" + ); + + let menu = document.getElementById("contentAreaContextMenu"); + let popupshown = BrowserTestUtils.waitForPopupEvent(menu, "shown"); + EventUtils.synthesizeMouseAtCenter(document.body, { + type: "contextmenu", + }); + await popupshown; + Assert.equal(menu.state, "open", "Context menu is open"); + + ok( + menu.querySelector("#context-take-screenshot").hidden, + "Take screenshot is not in context menu" + ); + + let popuphidden = BrowserTestUtils.waitForPopupEvent(menu, "hidden"); + menu.hidePopup(); + await popuphidden; + + await SpecialPowers.pushPrefEnv({ + set: [[SCREENSHOTS_PREF, false]], + }); + ok(!Services.prefs.getBoolPref(SCREENSHOTS_PREF), "Screenshots enabled"); + } + ); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + const SCREENSHOTS_PREF = "extensions.screenshots.disabled"; + ok(!Services.prefs.getBoolPref(SCREENSHOTS_PREF), "Screenshots enabled"); + + let helper = new ScreenshotsHelper(browser); + + helper.triggerUIFromToolbar(); + Assert.equal( + observerSpy.callCount, + 5, + "Observer function called for the fifth time" + ); + } + ); + + observerStub.restore(); + notifierStub.restore(); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_toolbar_button.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_toolbar_button.js new file mode 100644 index 0000000000..5ad7d32192 --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_toolbar_button.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function testScreenshotButtonDisabled() { + info("Test the Screenshots button in the panel"); + + let screenshotBtn = document.getElementById("screenshot-button"); + Assert.ok(screenshotBtn, "The screenshots button was added to the nav bar"); + + await BrowserTestUtils.withNewTab("https://example.com/", () => { + Assert.equal( + screenshotBtn.disabled, + false, + "Screenshots button is enabled" + ); + }); + await BrowserTestUtils.withNewTab("about:home", () => { + Assert.equal( + screenshotBtn.disabled, + false, + "Screenshots button is still enabled on about pages" + ); + }); +}); diff --git a/browser/components/screenshots/tests/browser/browser_screenshots_test_visible.js b/browser/components/screenshots/tests/browser/browser_screenshots_test_visible.js new file mode 100644 index 0000000000..a23d07140e --- /dev/null +++ b/browser/components/screenshots/tests/browser/browser_screenshots_test_visible.js @@ -0,0 +1,374 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_visibleScreenshot() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: 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); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + await helper.waitForOverlay(); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + + // click the visible page button in panel + let visiblePageButton = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector(".visible-page"); + visiblePageButton.click(); + + let dialog = helper.getDialog(); + + await screenshotReady; + + let copyButton = dialog._frame.contentDocument.querySelector( + ".highlight-button-copy" + ); + ok(copyButton, "Got the copy button"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + let expectedWidth = Math.floor( + devicePixelRatio * contentInfo.clientWidth + ); + Assert.equal(result.width, expectedWidth, "Widths should be equal"); + + let expectedHeight = Math.floor( + devicePixelRatio * contentInfo.clientHeight + ); + Assert.equal(result.height, expectedHeight, "Heights should be equal"); + + // top left + Assert.equal(111, result.color.topLeft[0], "R color value"); + Assert.equal(111, result.color.topLeft[1], "G color value"); + Assert.equal(111, result.color.topLeft[2], "B color value"); + + // top right + Assert.equal(111, result.color.topRight[0], "R color value"); + Assert.equal(111, result.color.topRight[1], "G color value"); + Assert.equal(111, result.color.topRight[2], "B color value"); + + // bottom left + Assert.equal(111, result.color.bottomLeft[0], "R color value"); + Assert.equal(111, result.color.bottomLeft[1], "G color value"); + Assert.equal(111, result.color.bottomLeft[2], "B color value"); + + // bottom right + Assert.equal(111, result.color.bottomRight[0], "R color value"); + Assert.equal(111, result.color.bottomRight[1], "G color value"); + Assert.equal(111, result.color.bottomRight[2], "B color value"); + } + ); +}); + +add_task(async function test_visibleScreenshotScrolled() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + await SpecialPowers.spawn(browser, [], () => { + content.scrollTo(0, 2008); + }); + + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + // click the visible page button in panel + let visiblePageButton = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector(".visible-page"); + visiblePageButton.click(); + + let dialog = helper.getDialog(); + + await screenshotReady; + + let copyButton = dialog._frame.contentDocument.querySelector( + ".highlight-button-copy" + ); + ok(copyButton, "Got the copy button"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + let expectedWidth = Math.floor( + devicePixelRatio * contentInfo.clientWidth + ); + Assert.equal(result.width, expectedWidth, "Widths should be equal"); + + let expectedHeight = Math.floor( + devicePixelRatio * contentInfo.clientHeight + ); + Assert.equal(result.height, expectedHeight, "Heights should be equal"); + + // top left + Assert.equal(105, result.color.topLeft[0], "R color value"); + Assert.equal(55, result.color.topLeft[1], "G color value"); + Assert.equal(105, result.color.topLeft[2], "B color value"); + + // top right + Assert.equal(105, result.color.topRight[0], "R color value"); + Assert.equal(55, result.color.topRight[1], "G color value"); + Assert.equal(105, result.color.topRight[2], "B color value"); + + // bottom left + Assert.equal(105, result.color.bottomLeft[0], "R color value"); + Assert.equal(55, result.color.bottomLeft[1], "G color value"); + Assert.equal(105, result.color.bottomLeft[2], "B color value"); + + // bottom right + Assert.equal(105, result.color.bottomRight[0], "R color value"); + Assert.equal(55, result.color.bottomRight[1], "G color value"); + Assert.equal(105, result.color.bottomRight[2], "B color value"); + } + ); +}); + +add_task(async function test_visibleScreenshotScrolled() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + await SpecialPowers.spawn(browser, [], () => { + content.scrollTo(2004, 0); + }); + + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + // click the visible page button in panel + let visiblePageButton = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector(".visible-page"); + visiblePageButton.click(); + + let dialog = helper.getDialog(); + + await screenshotReady; + + let copyButton = dialog._frame.contentDocument.querySelector( + ".highlight-button-copy" + ); + ok(copyButton, "Got the copy button"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + let expectedWidth = Math.floor( + devicePixelRatio * contentInfo.clientWidth + ); + Assert.equal(result.width, expectedWidth, "Widths should be equal"); + + let expectedHeight = Math.floor( + devicePixelRatio * contentInfo.clientHeight + ); + Assert.equal(result.height, expectedHeight, "Heights should be equal"); + + // top left + Assert.equal(55, result.color.topLeft[0], "R color value"); + Assert.equal(155, result.color.topLeft[1], "G color value"); + Assert.equal(155, result.color.topLeft[2], "B color value"); + + // top right + Assert.equal(55, result.color.topRight[0], "R color value"); + Assert.equal(155, result.color.topRight[1], "G color value"); + Assert.equal(155, result.color.topRight[2], "B color value"); + + // bottom left + Assert.equal(55, result.color.bottomLeft[0], "R color value"); + Assert.equal(155, result.color.bottomLeft[1], "G color value"); + Assert.equal(155, result.color.bottomLeft[2], "B color value"); + + // bottom right + Assert.equal(55, result.color.bottomRight[0], "R color value"); + Assert.equal(155, result.color.bottomRight[1], "G color value"); + Assert.equal(155, result.color.bottomRight[2], "B color value"); + } + ); +}); + +add_task(async function test_visibleScreenshotScrolled() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: TEST_PAGE, + }, + async browser => { + await SpecialPowers.spawn(browser, [], () => { + content.scrollTo(2004, 2008); + }); + + let helper = new ScreenshotsHelper(browser); + let contentInfo = await helper.getContentDimensions(); + ok(contentInfo, "Got dimensions back from the content"); + + // click toolbar button so panel shows + helper.triggerUIFromToolbar(); + + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + let screenshotReady = TestUtils.topicObserved( + "screenshots-preview-ready" + ); + + // click the visible page button in panel + let visiblePageButton = panel + .querySelector("screenshots-buttons") + .shadowRoot.querySelector(".visible-page"); + visiblePageButton.click(); + + let dialog = helper.getDialog(); + + await screenshotReady; + + let copyButton = dialog._frame.contentDocument.querySelector( + ".highlight-button-copy" + ); + ok(copyButton, "Got the copy button"); + + let clipboardChanged = helper.waitForRawClipboardChange(); + + // click copy button on dialog box + copyButton.click(); + + info("Waiting for clipboard change"); + await clipboardChanged; + + let result = await helper.getImageSizeAndColorFromClipboard(); + + info("result: " + JSON.stringify(result, null, 2)); + info("contentInfo: " + JSON.stringify(contentInfo, null, 2)); + + let expectedWidth = Math.floor( + devicePixelRatio * contentInfo.clientWidth + ); + Assert.equal(result.width, expectedWidth, "Widths should be equal"); + + let expectedHeight = Math.floor( + devicePixelRatio * contentInfo.clientHeight + ); + Assert.equal(result.height, expectedHeight, "Heights should be equal"); + + // top left + Assert.equal(52, result.color.topLeft[0], "R color value"); + Assert.equal(127, result.color.topLeft[1], "G color value"); + Assert.equal(152, result.color.topLeft[2], "B color value"); + + // top right + Assert.equal(52, result.color.topRight[0], "R color value"); + Assert.equal(127, result.color.topRight[1], "G color value"); + Assert.equal(152, result.color.topRight[2], "B color value"); + + // bottom left + Assert.equal(52, result.color.bottomLeft[0], "R color value"); + Assert.equal(127, result.color.bottomLeft[1], "G color value"); + Assert.equal(152, result.color.bottomLeft[2], "B color value"); + + // bottom right + Assert.equal(52, result.color.bottomRight[0], "R color value"); + Assert.equal(127, result.color.bottomRight[1], "G color value"); + Assert.equal(152, result.color.bottomRight[2], "B color value"); + } + ); +}); diff --git a/browser/components/screenshots/tests/browser/head.js b/browser/components/screenshots/tests/browser/head.js new file mode 100644 index 0000000000..cda6aed601 --- /dev/null +++ b/browser/components/screenshots/tests/browser/head.js @@ -0,0 +1,496 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_ROOT = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +const TEST_PAGE = TEST_ROOT + "test-page.html"; +const SHORT_TEST_PAGE = TEST_ROOT + "short-test-page.html"; + +const gScreenshotUISelectors = { + panelButtons: "#screenshotsPagePanel", + fullPageButton: "button.full-page", + visiblePageButton: "button.visible-page", + copyButton: "button.highlight-button-copy", +}; + +// MouseEvents is for the mouse events on the Anonymous content +const MouseEvents = { + mouse: new Proxy( + {}, + { + get: (target, name) => + async function(x, y, selector = ":root") { + if (name === "click") { + this.down(x, y); + this.up(x, y); + } else { + await safeSynthesizeMouseEventInContentPage(selector, x, y, { + type: "mouse" + name, + }); + } + }, + } + ), +}; + +const { mouse } = MouseEvents; + +class ScreenshotsHelper { + constructor(browser) { + this.browser = browser; + this.selector = gScreenshotUISelectors; + } + + get toolbarButton() { + return document.getElementById("screenshot-button"); + } + + /** + * Click the screenshots button in the toolbar + */ + triggerUIFromToolbar() { + let button = this.toolbarButton; + ok( + BrowserTestUtils.is_visible(button), + "The screenshot toolbar button is visible" + ); + button.click(); + } + + async waitForPanel() { + return BrowserTestUtils.waitForCondition(async () => { + return gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + }); + } + + async waitForOverlay() { + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + if (!panel) { + panel = await this.waitForPanel(); + } + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_visible(panel); + } + ); + ok(BrowserTestUtils.is_visible(panel), "Panel buttons are visible"); + + await BrowserTestUtils.waitForCondition(async () => { + let init = await this.isOverlayInitialized(); + return init; + }); + info("Overlay is visible"); + } + + async waitForOverlayClosed() { + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + if (!panel) { + panel = await this.waitForPanel(); + } + await BrowserTestUtils.waitForMutationCondition( + panel, + { attributes: true }, + () => { + return BrowserTestUtils.is_hidden(panel); + } + ); + ok(BrowserTestUtils.is_hidden(panel), "Panel buttons are hidden"); + + await BrowserTestUtils.waitForCondition(async () => { + let init = !(await this.isOverlayInitialized()); + info("Is overlay initialized: " + !init); + return init; + }); + info("Overlay is not visible"); + } + + async isOverlayInitialized() { + return SpecialPowers.spawn(this.browser, [], () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + return screenshotsChild?._overlay?._initialized; + }); + } + + async getOverlayState() { + return ContentTask.spawn(this.browser, null, async () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + return screenshotsChild._overlay.stateHandler.getState(); + }); + } + + async waitForStateChange(newState) { + await BrowserTestUtils.waitForCondition(async () => { + let state = await this.getOverlayState(); + return state === newState; + }); + } + + async waitForSelectionBoxSizeChange(currentWidth) { + await ContentTask.spawn( + this.browser, + [currentWidth], + async ([currWidth]) => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + + let dimensions = screenshotsChild._overlay.screenshotsContainer.getSelectionLayerDimensions(); + // return dimensions.boxWidth; + await ContentTaskUtils.waitForCondition(() => { + dimensions = screenshotsChild._overlay.screenshotsContainer.getSelectionLayerDimensions(); + return dimensions.boxWidth !== currWidth; + }, "Wait for selection box width change"); + } + ); + } + + async dragOverlay(startX, startY, endX, endY) { + await this.waitForStateChange("crosshairs"); + let state = await this.getOverlayState(); + Assert.equal(state, "crosshairs", "The overlay is in the crosshairs state"); + + mouse.down(startX, startY); + + await this.waitForStateChange("draggingReady"); + state = await this.getOverlayState(); + Assert.equal( + state, + "draggingReady", + "The overlay is in the draggingReady state" + ); + + mouse.move(endX, endY); + + await this.waitForStateChange("dragging"); + state = await this.getOverlayState(); + Assert.equal(state, "dragging", "The overlay is in the dragging state"); + + mouse.up(endX, endY); + + await this.waitForStateChange("selected"); + state = await this.getOverlayState(); + Assert.equal(state, "selected", "The overlay is in the selected state"); + + this.endX = endX; + this.endY = endY; + } + + async scrollContentWindow(x, y) { + await ContentTask.spawn(this.browser, [x, y], async ([xPos, yPos]) => { + content.window.scroll(xPos, yPos); + }); + } + + clickDownloadButton() { + mouse.click(this.endX - 60, this.endY + 30); + } + + clickCopyButton(overrideX = null, overrideY = null) { + // click copy button with last x and y position from dragOverlay + // the middle of the copy button is last X - 163 and last Y + 30. + // Ex. 500, 500 would be 336, 530 + if (overrideX && overrideY) { + mouse.click(overrideX - 166, overrideY + 30); + } else { + mouse.click(this.endX - 166, this.endY + 30); + } + } + + clickCancelButton() { + // click copy button with last x and y position from dragOverlay + // the middle of the copy button is last X - 230 and last Y + 30. + // Ex. 500, 500 would be 270, 530 + mouse.click(this.endX - 230, this.endY + 30); + } + + async zoomBrowser(zoom) { + await SpecialPowers.spawn(this.browser, [zoom], zoomLevel => { + const { Layout } = ChromeUtils.import( + "chrome://mochitests/content/browser/accessible/tests/browser/Layout.jsm" + ); + Layout.zoomDocument(content.document, zoomLevel); + }); + } + + /** + * Gets the dialog box + * @returns The dialog box + */ + getDialog() { + let currDialogBox = this.browser.tabDialogBox; + let manager = currDialogBox.getTabDialogManager(); + let dialogs = manager.hasDialogs && manager.dialogs; + return dialogs[0]; + } + + assertPanelVisible() { + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + Assert.ok( + BrowserTestUtils.is_visible(panel), + "Screenshots panel is visible" + ); + } + + assertPanelNotVisible() { + let panel = gBrowser.selectedBrowser.ownerDocument.querySelector( + "#screenshotsPagePanel" + ); + Assert.ok( + BrowserTestUtils.is_hidden(panel), + "Screenshots panel is not visible" + ); + } + + /** + * Copied from screenshots extension + * Returns a promise that resolves when the clipboard data has changed + * Otherwise rejects + */ + waitForRawClipboardChange() { + const initialClipboardData = Date.now().toString(); + SpecialPowers.clipboardCopyString(initialClipboardData); + + let promiseChanged = TestUtils.waitForCondition(() => { + let data; + try { + data = getRawClipboardData("image/png"); + } catch (e) { + console.log("Failed to get image/png clipboard data:", e); + return false; + } + return data && initialClipboardData !== data; + }); + return promiseChanged; + } + + /** + * Gets the client and scroll demensions on the window + * @returns { Object } + * clientHeight The visible height + * clientWidth The visible width + * scrollHeight The scrollable height + * scrollWidth The scrollable width + */ + getContentDimensions() { + return SpecialPowers.spawn(this.browser, [], async function() { + let doc = content.document.documentElement; + return { + clientHeight: doc.clientHeight, + clientWidth: doc.clientWidth, + scrollHeight: doc.scrollHeight, + scrollWidth: doc.scrollWidth, + }; + }); + } + + getSelectionLayerDimensions() { + return ContentTask.spawn(this.browser, null, async () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + Assert.ok(screenshotsChild._overlay._initialized, "The overlay exists"); + + return screenshotsChild._overlay.screenshotsContainer.getSelectionLayerDimensions(); + }); + } + + getSelectionBoxDimensions() { + return ContentTask.spawn(this.browser, null, async () => { + let screenshotsChild = content.windowGlobalChild.getActor( + "ScreenshotsComponent" + ); + Assert.ok(screenshotsChild._overlay._initialized, "The overlay exists"); + + return screenshotsChild._overlay.screenshotsContainer.getSelectionLayerBoxDimensions(); + }); + } + + /** + * Clicks an element on the screen + * @param eleSel The selector for the element to click + */ + async clickUIElement(eleSel) { + await SpecialPowers.spawn(this.browser, [eleSel], async function( + eleSelector + ) { + info( + `in clickScreenshotsUIElement content function, eleSelector: ${eleSelector}` + ); + const EventUtils = ContentTaskUtils.getEventUtils(content); + let ele = content.document.querySelector(eleSelector); + info(`Found the thing to click: ${eleSelector}: ${!!ele}`); + + EventUtils.synthesizeMouseAtCenter(ele, {}); + // wait a frame for the screenshots UI to finish any init + await new content.Promise(res => content.requestAnimationFrame(res)); + }); + } + + /** + * Copied from screenshots extension + * A helper that returns the size of the image that was just put into the clipboard by the + * :screenshot command. + * @return The {width, height, color} dimension and color object. + */ + async getImageSizeAndColorFromClipboard() { + let flavor = "image/png"; + let image = getRawClipboardData(flavor); + ok(image, "screenshot data exists on the clipboard"); + + // Due to the differences in how images could be stored in the clipboard the + // checks below are needed. The clipboard could already provide the image as + // byte streams or as image container. If it's not possible obtain a + // byte stream, the function throws. + + if (image instanceof Ci.imgIContainer) { + image = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .encodeImage(image, flavor); + } + + if (!(image instanceof Ci.nsIInputStream)) { + throw new Error("Unable to read image data"); + } + + const binaryStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance( + Ci.nsIBinaryInputStream + ); + binaryStream.setInputStream(image); + const available = binaryStream.available(); + const buffer = new ArrayBuffer(available); + is( + binaryStream.readArrayBuffer(available, buffer), + available, + "Read expected amount of data" + ); + + // We are going to load the image in the content page to measure its size. + // We don't want to insert the image directly in the browser's document + // which could mess all sorts of things up + return SpecialPowers.spawn(this.browser, [buffer], async function(_buffer) { + const img = content.document.createElement("img"); + const loaded = new Promise(r => { + img.addEventListener("load", r, { once: true }); + }); + const url = content.URL.createObjectURL( + new Blob([_buffer], { type: "image/png" }) + ); + + img.src = url; + content.document.documentElement.appendChild(img); + + info("Waiting for the clipboard image to load in the content page"); + await loaded; + + let canvas = content.document.createElementNS( + "http://www.w3.org/1999/xhtml", + "html:canvas" + ); + let context = canvas.getContext("2d"); + canvas.width = img.width; + canvas.height = img.height; + context.drawImage(img, 0, 0); + let topLeft = context.getImageData(0, 0, 1, 1); + let topRight = context.getImageData(img.width - 1, 0, 1, 1); + let bottomLeft = context.getImageData(0, img.height - 1, 1, 1); + let bottomRight = context.getImageData( + img.width - 1, + img.height - 1, + 1, + 1 + ); + + img.remove(); + content.URL.revokeObjectURL(url); + + return { + width: img.width, + height: img.height, + color: { + topLeft: topLeft.data, + topRight: topRight.data, + bottomLeft: bottomLeft.data, + bottomRight: bottomRight.data, + }, + }; + }); + } +} + +/** + * Get the raw clipboard data + * @param flavor Type of data to get from clipboard + * @returns The data from the clipboard + */ +function getRawClipboardData(flavor) { + const whichClipboard = Services.clipboard.kGlobalClipboard; + const xferable = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + xferable.init(null); + xferable.addDataFlavor(flavor); + Services.clipboard.getData(xferable, whichClipboard); + let data = {}; + try { + // xferable.getTransferData(flavor, data); + xferable.getAnyTransferData({}, data); + info(JSON.stringify(data, null, 2)); + } catch (e) { + info(e); + } + data = data.value || null; + return data; +} + +/** + * Synthesize a mouse event on an element, after ensuring that it is visible + * in the viewport. + * + * @param {String} selector: The node selector to get the node target for the event. + * @param {number} x + * @param {number} y + * @param {object} options: Options that will be passed to BrowserTestUtils.synthesizeMouse + */ +async function safeSynthesizeMouseEventInContentPage( + selector, + x, + y, + options = {} +) { + let context = gBrowser.selectedBrowser.browsingContext; + BrowserTestUtils.synthesizeMouse(selector, x, y, options, context); +} + +add_setup(async () => { + CustomizableUI.addWidgetToArea( + "screenshot-button", + CustomizableUI.AREA_NAVBAR + ); + let screenshotBtn = document.getElementById("screenshot-button"); + Assert.ok(screenshotBtn, "The screenshots button was added to the nav bar"); +}); + +function getContentDevicePixelRatio(browser) { + return SpecialPowers.spawn(browser, [], async function() { + return content.window.devicePixelRatio; + }); +} diff --git a/browser/components/screenshots/tests/browser/short-test-page.html b/browser/components/screenshots/tests/browser/short-test-page.html new file mode 100644 index 0000000000..4ba4f10394 --- /dev/null +++ b/browser/components/screenshots/tests/browser/short-test-page.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Screenshots</title> +</head> +<body style="height:100px; width:100px;"> +</body> +</html> diff --git a/browser/components/screenshots/tests/browser/test-page.html b/browser/components/screenshots/tests/browser/test-page.html new file mode 100644 index 0000000000..9f9ae8d652 --- /dev/null +++ b/browser/components/screenshots/tests/browser/test-page.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Screenshots</title> +</head> +<body style="height:4000px; width:4000px; background-repeat: no-repeat; background-size: 4008px 4016px; background-color: rgb(111, 111, 111); background-image:linear-gradient(to right, transparent 50%, rgba(0, 200, 200, 0.5) 50%),linear-gradient(to bottom, transparent 50%, rgba(100, 0, 100, 0.5) 50%);"> +</body> +</html> |