summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/mochitest/test_ext_tabs_captureTab.html
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/mochitest/test_ext_tabs_captureTab.html')
-rw-r--r--toolkit/components/extensions/test/mochitest/test_ext_tabs_captureTab.html324
1 files changed, 324 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/mochitest/test_ext_tabs_captureTab.html b/toolkit/components/extensions/test/mochitest/test_ext_tabs_captureTab.html
new file mode 100644
index 0000000000..ab06a965ed
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_tabs_captureTab.html
@@ -0,0 +1,324 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Tests tabs.captureTab and tabs.captureVisibleTab</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+ <script type="text/javascript" src="head.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script type="text/javascript">
+"use strict";
+
+async function runTest({ html, fullZoom, coords, rect, scale }) {
+ let url = `data:text/html,${encodeURIComponent(html)}#scroll`;
+
+ async function background({ coords, rect, scale, method, fullZoom }) {
+ try {
+ // Wait for the page to load
+ await new Promise(resolve => {
+ browser.webNavigation.onCompleted.addListener(
+ () => resolve(),
+ {url: [{schemes: ["data"]}]});
+ });
+
+ let [tab] = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ // TODO: Bug 1665429 - on mobile we ignore zoom for now
+ if (browser.tabs.setZoom) {
+ await browser.tabs.setZoom(tab.id, fullZoom ?? 1);
+ }
+
+ let id = method === "captureVisibleTab" ? tab.windowId : tab.id;
+
+ let [jpeg, png, ...pngs] = await Promise.all([
+ browser.tabs[method](id, { format: "jpeg", quality: 95, rect, scale }),
+ browser.tabs[method](id, { format: "png", quality: 95, rect, scale }),
+ browser.tabs[method](id, { quality: 95, rect, scale }),
+ browser.tabs[method](id, { rect, scale }),
+ ]);
+
+ browser.test.assertTrue(
+ pngs.every(url => url == png),
+ "All PNGs are identical"
+ );
+
+ browser.test.assertTrue(
+ jpeg.startsWith("data:image/jpeg;base64,"),
+ "jpeg is JPEG"
+ );
+ browser.test.assertTrue(
+ png.startsWith("data:image/png;base64,"),
+ "png is PNG"
+ );
+
+ let promises = [jpeg, png].map(
+ url =>
+ new Promise(resolve => {
+ let img = new Image();
+ img.src = url;
+ img.onload = () => resolve(img);
+ })
+ );
+
+ let width = (rect?.width ?? tab.width) * (scale ?? devicePixelRatio);
+ let height = (rect?.height ?? tab.height) * (scale ?? devicePixelRatio);
+
+ [jpeg, png] = await Promise.all(promises);
+ let images = { jpeg, png };
+ for (let format of Object.keys(images)) {
+ let img = images[format];
+
+ // WGP.drawSnapshot() deals in int coordinates, and rounds down.
+ browser.test.assertTrue(
+ Math.abs(width - img.width) <= 1,
+ `${format} ok image width: ${img.width}, expected: ${width}`
+ );
+ browser.test.assertTrue(
+ Math.abs(height - img.height) <= 1,
+ `${format} ok image height ${img.height}, expected: ${height}`
+ );
+
+ let canvas = document.createElement("canvas");
+ canvas.width = img.width;
+ canvas.height = img.height;
+ canvas.mozOpaque = true;
+
+ let ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0);
+
+ for (let { x, y, color } of coords) {
+ x = (x + img.width) % img.width;
+ y = (y + img.height) % img.height;
+ let imageData = ctx.getImageData(x, y, 1, 1).data;
+
+ if (format == "png") {
+ browser.test.assertEq(
+ `rgba(${color},255)`,
+ `rgba(${[...imageData]})`,
+ `${format} image color is correct at (${x}, ${y})`
+ );
+ } else {
+ // Allow for some deviation in JPEG version due to lossy compression.
+ const SLOP = 3;
+
+ browser.test.log(
+ `Testing ${format} image color at (${x}, ${y}), have rgba(${[
+ ...imageData,
+ ]}), expecting approx. rgba(${color},255)`
+ );
+
+ browser.test.assertTrue(
+ Math.abs(color[0] - imageData[0]) <= SLOP,
+ `${format} image color.red is correct at (${x}, ${y})`
+ );
+ browser.test.assertTrue(
+ Math.abs(color[1] - imageData[1]) <= SLOP,
+ `${format} image color.green is correct at (${x}, ${y})`
+ );
+ browser.test.assertTrue(
+ Math.abs(color[2] - imageData[2]) <= SLOP,
+ `${format} image color.blue is correct at (${x}, ${y})`
+ );
+ browser.test.assertEq(
+ 255,
+ imageData[3],
+ `${format} image color.alpha is correct at (${x}, ${y})`
+ );
+ }
+ }
+ }
+
+ browser.test.notifyPass("captureTab");
+ } catch (e) {
+ browser.test.fail(`Error: ${e} :: ${e.stack}`);
+ browser.test.notifyFail("captureTab");
+ }
+ }
+
+ for (let method of ["captureTab", "captureVisibleTab"]) {
+ let options = { coords, rect, scale, method, fullZoom };
+ info(`Testing configuration: ${JSON.stringify(options)}`);
+
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["<all_urls>", "webNavigation"],
+ },
+
+ background: `(${background})(${JSON.stringify(options)})`,
+ });
+
+ await extension.startup();
+
+ let testWindow = window.open(url);
+ await extension.awaitFinish("captureTab");
+
+ testWindow.close();
+ await extension.unload();
+ }
+}
+
+async function testEdgeToEdge({ color, fullZoom }) {
+ let neutral = [0xaa, 0xaa, 0xaa];
+
+ let html = `
+ <!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ </head>
+ <body style="background-color: rgb(${color})">
+ <!-- Fill most of the image with a neutral color to test edge-to-edge scaling. -->
+ <div style="position: absolute;
+ left: 2px;
+ right: 2px;
+ top: 2px;
+ bottom: 2px;
+ background: rgb(${neutral});"></div>
+ </body>
+ </html>
+ `;
+
+ // Check the colors of the first and last pixels of the image, to make
+ // sure we capture the entire frame, and scale it correctly.
+ let coords = [
+ { x: 0, y: 0, color },
+ { x: -1, y: -1, color },
+ { x: 300, y: 200, color: neutral },
+ ];
+
+ info(`Test edge to edge color ${color} at fullZoom=${fullZoom}`);
+ await runTest({ html, fullZoom, coords });
+}
+
+add_task(async function testCaptureEdgeToEdge() {
+ await testEdgeToEdge({ color: [0, 0, 0], fullZoom: 1 });
+ await testEdgeToEdge({ color: [0, 0, 0], fullZoom: 2 });
+ await testEdgeToEdge({ color: [0, 0, 0], fullZoom: 0.5 });
+ await testEdgeToEdge({ color: [255, 255, 255], fullZoom: 1 });
+});
+
+const tallDoc = `<!DOCTYPE html>
+ <meta charset=utf-8>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <div style="background: yellow; width: 50%; height: 500px;"></div>
+ <div id=scroll style="background: red; width: 25%; height: 5000px;"></div>
+ Opened with the #scroll fragment, scrolls the div ^ into view.
+`;
+
+// Test currently visible viewport is captured if scrolling is involved.
+add_task(async function testScrolledViewport() {
+ await runTest({
+ html: tallDoc,
+ coords: [
+ { x: 50, y: 50, color: [255, 0, 0] },
+ { x: 50, y: -50, color: [255, 0, 0] },
+ { x: -50, y: -50, color: [255, 255, 255] },
+ ],
+ });
+});
+
+// Test rect and scale options.
+add_task(async function testRectAndScale() {
+ await runTest({
+ html: tallDoc,
+ rect: { x: 50, y: 50, width: 10, height: 1000 },
+ scale: 4,
+ coords: [
+ { x: 0, y: 0, color: [255, 255, 0] },
+ { x: -1, y: 0, color: [255, 255, 0] },
+ { x: 0, y: -1, color: [255, 0, 0] },
+ { x: -1, y: -1, color: [255, 0, 0] },
+ ],
+ });
+});
+
+// Test OOP iframes are captured, for Fission compatibility.
+add_task(async function testOOPiframe() {
+ await runTest({
+ html: `<!DOCTYPE html>
+ <meta charset=utf-8>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <iframe src="http://example.net/tests/toolkit/components/extensions/test/mochitest/file_green.html"></iframe>
+ `,
+ coords: [
+ { x: 50, y: 50, color: [0, 255, 0] },
+ { x: 50, y: -50, color: [255, 255, 255] },
+ { x: -50, y: 50, color: [255, 255, 255] },
+ ],
+ });
+});
+
+add_task(async function testOOPiframeScale() {
+ let scale = 2;
+ await runTest({
+ html: `<!DOCTYPE html>
+ <meta charset=utf-8>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <style>
+ body {
+ background: yellow;
+ margin: 0;
+ }
+ </style>
+ <iframe frameborder="0" style="width: 300px; height: 300px" src="http://example.net/tests/toolkit/components/extensions/test/mochitest/file_green_blue.html"></iframe>
+ `,
+ coords: [
+ { x: 20 * scale, y: 20 * scale, color: [0, 255, 0] },
+ { x: 200 * scale, y: 20 * scale, color: [0, 0, 255] },
+ { x: 20 * scale, y: 200 * scale, color: [0, 0, 255] },
+ ],
+ scale,
+ });
+});
+
+add_task(async function testCaptureTabPermissions() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["tabs"],
+ },
+
+ background() {
+ browser.test.assertEq(
+ undefined,
+ browser.tabs.captureTab,
+ 'Extension without "<all_urls>" permission should not have access to captureTab'
+ );
+ browser.test.notifyPass("captureTabPermissions");
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("captureTabPermissions");
+ await extension.unload();
+});
+
+add_task(async function testCaptureVisibleTabPermissions() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: ["tabs"],
+ },
+
+ background() {
+ browser.test.assertEq(
+ undefined,
+ browser.tabs.captureVisibleTab,
+ 'Extension without "<all_urls>" permission should not have access to captureVisibleTab'
+ );
+ browser.test.notifyPass("captureVisibleTabPermissions");
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("captureVisibleTabPermissions");
+ await extension.unload();
+});
+</script>
+</body>
+</html>