summaryrefslogtreecommitdiffstats
path: root/browser/extensions/report-site-issue/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /browser/extensions/report-site-issue/test
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/extensions/report-site-issue/test')
-rw-r--r--browser/extensions/report-site-issue/test/browser/browser.ini14
-rw-r--r--browser/extensions/report-site-issue/test/browser/browser_button_state.js52
-rw-r--r--browser/extensions/report-site-issue/test/browser/browser_disabled_cleanup.js41
-rw-r--r--browser/extensions/report-site-issue/test/browser/browser_report_site_issue.js300
-rw-r--r--browser/extensions/report-site-issue/test/browser/fastclick.html11
-rw-r--r--browser/extensions/report-site-issue/test/browser/frameworks.html8
-rw-r--r--browser/extensions/report-site-issue/test/browser/head.js119
-rw-r--r--browser/extensions/report-site-issue/test/browser/test.html40
-rw-r--r--browser/extensions/report-site-issue/test/browser/webcompat.html85
9 files changed, 670 insertions, 0 deletions
diff --git a/browser/extensions/report-site-issue/test/browser/browser.ini b/browser/extensions/report-site-issue/test/browser/browser.ini
new file mode 100644
index 0000000000..9c0b4c5968
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/browser.ini
@@ -0,0 +1,14 @@
+[DEFAULT]
+support-files =
+ frameworks.html
+ fastclick.html
+ head.js
+ test.html
+ webcompat.html
+
+[browser_button_state.js]
+skip-if = true # Disabled until we figure out why it is failing in bug 1775526
+[browser_disabled_cleanup.js]
+skip-if = true # Disabled until we figure out why it is failing in bug 1775526
+[browser_report_site_issue.js]
+skip-if = true # Disabled until we figure out why it is failing in bug 1775526
diff --git a/browser/extensions/report-site-issue/test/browser/browser_button_state.js b/browser/extensions/report-site-issue/test/browser/browser_button_state.js
new file mode 100644
index 0000000000..6111a26975
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/browser_button_state.js
@@ -0,0 +1,52 @@
+"use strict";
+
+const REPORTABLE_PAGE = "http://example.com/";
+const REPORTABLE_PAGE2 = "https://example.com/";
+const NONREPORTABLE_PAGE = "about:mozilla";
+
+/* Test that the Report Site Issue help menu item is enabled for http and https tabs,
+ on page load, or TabSelect, and disabled for everything else. */
+add_task(async function test_button_state_disabled() {
+ await SpecialPowers.pushPrefEnv({ set: [[PREF_WC_REPORTER_ENABLED, true]] });
+
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ REPORTABLE_PAGE
+ );
+ const menu = new HelpMenuHelper();
+ await menu.open();
+ is(
+ menu.isItemEnabled(),
+ true,
+ "Check that panel item is enabled for reportable schemes on tab load"
+ );
+ await menu.close();
+
+ let tab2 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ NONREPORTABLE_PAGE
+ );
+ await menu.open();
+ is(
+ menu.isItemEnabled(),
+ false,
+ "Check that panel item is disabled for non-reportable schemes on tab load"
+ );
+ await menu.close();
+
+ let tab3 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ REPORTABLE_PAGE2
+ );
+ await menu.open();
+ is(
+ menu.isItemEnabled(),
+ true,
+ "Check that panel item is enabled for reportable schemes on tab load"
+ );
+ await menu.close();
+
+ await BrowserTestUtils.removeTab(tab1);
+ await BrowserTestUtils.removeTab(tab2);
+ await BrowserTestUtils.removeTab(tab3);
+});
diff --git a/browser/extensions/report-site-issue/test/browser/browser_disabled_cleanup.js b/browser/extensions/report-site-issue/test/browser/browser_disabled_cleanup.js
new file mode 100644
index 0000000000..65b6ff7369
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/browser_disabled_cleanup.js
@@ -0,0 +1,41 @@
+"use strict";
+
+// Test the addon is cleaning up after itself when disabled.
+add_task(async function test_disabled() {
+ await promiseAddonEnabled();
+
+ SpecialPowers.Services.prefs.setBoolPref(PREF_WC_REPORTER_ENABLED, false);
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "http://example.com" },
+ async function () {
+ const menu = new HelpMenuHelper();
+ await menu.open();
+ is(
+ menu.isItemHidden(),
+ true,
+ "Report Site Issue help menu item is hidden."
+ );
+ await menu.close();
+ }
+ );
+
+ await promiseAddonEnabled();
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "http://example.com" },
+ async function () {
+ const menu = new HelpMenuHelper();
+ await menu.open();
+ is(
+ await menu.isItemHidden(),
+ false,
+ "Report Site Issue help menu item is visible."
+ );
+ await menu.close();
+ }
+ );
+
+ // Shut down the addon at the end,or the new instance started when we re-enabled it will "leak".
+ SpecialPowers.Services.prefs.setBoolPref(PREF_WC_REPORTER_ENABLED, false);
+});
diff --git a/browser/extensions/report-site-issue/test/browser/browser_report_site_issue.js b/browser/extensions/report-site-issue/test/browser/browser_report_site_issue.js
new file mode 100644
index 0000000000..62d3516c46
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/browser_report_site_issue.js
@@ -0,0 +1,300 @@
+"use strict";
+
+async function clickToReportAndAwaitReportTabLoad() {
+ const helpMenu = new HelpMenuHelper();
+ await helpMenu.open();
+
+ // click on "report site issue" and wait for the new tab to open
+ const tab = await new Promise(resolve => {
+ gBrowser.tabContainer.addEventListener(
+ "TabOpen",
+ event => {
+ resolve(event.target);
+ },
+ { once: true }
+ );
+ document.getElementById("help_reportSiteIssue").click();
+ });
+
+ // wait for the new tab to acknowledge that it received a screenshot
+ await BrowserTestUtils.waitForContentEvent(
+ gBrowser.selectedBrowser,
+ "ScreenshotReceived",
+ false,
+ null,
+ true
+ );
+
+ await helpMenu.close();
+
+ return tab;
+}
+
+add_task(async function start_issue_server() {
+ requestLongerTimeout(2);
+
+ const serverLanding = await startIssueServer();
+
+ // ./head.js sets the value for PREF_WC_REPORTER_ENDPOINT
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["datareporting.healthreport.uploadEnabled", true],
+ [PREF_WC_REPORTER_ENABLED, true],
+ [PREF_WC_REPORTER_ENDPOINT, serverLanding],
+ ],
+ });
+});
+
+/* Test that clicking on the Report Site Issue button opens a new tab
+ and sends a postMessaged blob to it. */
+add_task(async function test_opened_page() {
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE);
+ let tab2 = await clickToReportAndAwaitReportTabLoad();
+
+ await SpecialPowers.spawn(
+ tab2.linkedBrowser,
+ [{ TEST_PAGE }],
+ async function (args) {
+ async function isGreen(dataUrl) {
+ const getPixel = await new Promise(resolve => {
+ const myCanvas = content.document.createElement("canvas");
+ const ctx = myCanvas.getContext("2d");
+ const img = new content.Image();
+ img.onload = () => {
+ ctx.drawImage(img, 0, 0);
+ resolve((x, y) => {
+ return ctx.getImageData(x, y, 1, 1).data;
+ });
+ };
+ img.src = dataUrl;
+ });
+ function isPixelGreenFuzzy(p) {
+ // jpeg, so it will be off slightly
+ const fuzz = 4;
+ return p[0] < fuzz && Math.abs(p[1] - 128) < fuzz && p[2] < fuzz;
+ }
+ ok(isPixelGreenFuzzy(getPixel(0, 0)), "The pixels were green");
+ }
+
+ let doc = content.document;
+ let urlParam = doc.getElementById("url").innerText;
+ let preview = doc.getElementById("screenshot-preview");
+ const URL =
+ "http://example.com/browser/browser/extensions/report-site-issue/test/browser/test.html";
+ is(
+ urlParam,
+ args.TEST_PAGE,
+ "Reported page is correctly added to the url param"
+ );
+
+ let docShell = content.docShell;
+ is(
+ typeof docShell.getHasTrackingContentBlocked,
+ "function",
+ "docShell.hasTrackingContentBlocked is available"
+ );
+
+ let detailsParam = doc.getElementById("details").innerText;
+ const details = JSON.parse(detailsParam);
+ ok(
+ typeof details == "object",
+ "Details param is a stringified JSON object."
+ );
+ ok(Array.isArray(details.consoleLog), "Details has a consoleLog array.");
+
+ const log1 = details.consoleLog[0];
+ is(log1.log[0], null, "Can handle degenerate console logs");
+ is(log1.level, "log", "Reports correct log level");
+ is(log1.uri, URL, "Reports correct url");
+ is(log1.pos, "7:13", "Reports correct line and column");
+
+ const log2 = details.consoleLog[1];
+ is(log2.log[0], "colored message", "Can handle fancy console logs");
+ is(log2.level, "error", "Reports correct log level");
+ is(log2.uri, URL, "Reports correct url");
+ is(log2.pos, "8:13", "Reports correct line and column");
+
+ const log3 = details.consoleLog[2];
+ const loggedObject = log3.log[0];
+ is(loggedObject.testobj, "{...}", "Reports object inside object");
+ is(
+ loggedObject.testSymbol,
+ "Symbol(sym)",
+ "Reports symbol inside object"
+ );
+ is(loggedObject.testnumber, 1, "Reports number inside object");
+ is(loggedObject.testArray, "(4)[...]", "Reports array inside object");
+ is(loggedObject.testUndf, "undefined", "Reports undefined inside object");
+ is(loggedObject.testNull, null, "Reports null inside object");
+ is(
+ loggedObject.testFunc,
+ undefined,
+ "Reports function inside object as undefined due to security reasons"
+ );
+ is(loggedObject.testString, "string", "Reports string inside object");
+ is(loggedObject.c, "{...}", "Reports circular reference inside object");
+ is(
+ Object.keys(loggedObject).length,
+ 10,
+ "Preview has 10 keys inside object"
+ );
+ is(log3.level, "log", "Reports correct log level");
+ is(log3.uri, URL, "Reports correct url");
+ is(log3.pos, "24:13", "Reports correct line and column");
+
+ const log4 = details.consoleLog[3];
+ const loggedArray = log4.log[0];
+ is(loggedArray[0], "string", "Reports string inside array");
+ is(loggedArray[1], "{...}", "Reports object inside array");
+ is(loggedArray[2], null, "Reports null inside array");
+ is(loggedArray[3], 90, "Reports number inside array");
+ is(loggedArray[4], "undefined", "Reports undefined inside array");
+ is(
+ loggedArray[5],
+ "undefined",
+ "Reports function inside array as undefined due to security reasons"
+ );
+ is(loggedArray[6], "(4)[...]", "Reports array inside array");
+ is(loggedArray[7], "(8)[...]", "Reports circular array inside array");
+
+ const log5 = details.consoleLog[4];
+ ok(
+ log5.log[0].match(/TypeError: .*document\.access is undefined/),
+ "Script errors are logged"
+ );
+ is(log5.level, "error", "Reports correct log level");
+ is(log5.uri, URL, "Reports correct url");
+ is(log5.pos, "36:5", "Reports correct line and column");
+
+ ok(typeof details.buildID == "string", "Details has a buildID string.");
+ ok(typeof details.channel == "string", "Details has a channel string.");
+ ok(
+ typeof details.hasTouchScreen == "boolean",
+ "Details has a hasTouchScreen flag."
+ );
+ ok(
+ typeof details.hasFastClick == "undefined",
+ "Details does not have FastClick if not found."
+ );
+ ok(
+ typeof details.hasMobify == "undefined",
+ "Details does not have Mobify if not found."
+ );
+ ok(
+ typeof details.hasMarfeel == "undefined",
+ "Details does not have Marfeel if not found."
+ );
+ ok(
+ typeof details["mixed active content blocked"] == "boolean",
+ "Details has a mixed active content blocked flag."
+ );
+ ok(
+ typeof details["mixed passive content blocked"] == "boolean",
+ "Details has a mixed passive content blocked flag."
+ );
+ ok(
+ typeof details["tracking content blocked"] == "string",
+ "Details has a tracking content blocked string."
+ );
+ ok(
+ typeof details["gfx.webrender.all"] == "boolean",
+ "Details has gfx.webrender.all."
+ );
+ ok(
+ typeof details["gfx.webrender.blob-images"] == "boolean",
+ "Details has gfx.webrender.blob-images."
+ );
+ ok(
+ typeof details["gfx.webrender.enabled"] == "boolean",
+ "Details has gfx.webrender.enabled."
+ );
+ ok(
+ typeof details["image.mem.shared"] == "boolean",
+ "Details has image.mem.shared."
+ );
+
+ is(
+ preview.innerText,
+ "Pass",
+ "A Blob object was successfully transferred to the test page."
+ );
+
+ const bgUrl = preview.style.backgroundImage.match(/url\(\"(.*)\"\)/)[1];
+ ok(
+ bgUrl.startsWith("data:image/jpeg;base64,"),
+ "A jpeg screenshot was successfully postMessaged"
+ );
+ await isGreen(bgUrl);
+ }
+ );
+
+ BrowserTestUtils.removeTab(tab2);
+ BrowserTestUtils.removeTab(tab1);
+});
+
+add_task(async function test_framework_detection() {
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ FRAMEWORKS_TEST_PAGE
+ );
+ let tab2 = await clickToReportAndAwaitReportTabLoad();
+
+ await SpecialPowers.spawn(tab2.linkedBrowser, [], async function (args) {
+ let doc = content.document;
+ let detailsParam = doc.getElementById("details").innerText;
+ const details = JSON.parse(detailsParam);
+ ok(
+ typeof details == "object",
+ "Details param is a stringified JSON object."
+ );
+ is(details.hasFastClick, true, "FastClick was found.");
+ is(details.hasMobify, true, "Mobify was found.");
+ is(details.hasMarfeel, true, "Marfeel was found.");
+ });
+
+ BrowserTestUtils.removeTab(tab2);
+ BrowserTestUtils.removeTab(tab1);
+});
+
+add_task(async function test_fastclick_detection() {
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ FASTCLICK_TEST_PAGE
+ );
+ let tab2 = await clickToReportAndAwaitReportTabLoad();
+
+ await SpecialPowers.spawn(tab2.linkedBrowser, [], async function (args) {
+ let doc = content.document;
+ let detailsParam = doc.getElementById("details").innerText;
+ const details = JSON.parse(detailsParam);
+ ok(
+ typeof details == "object",
+ "Details param is a stringified JSON object."
+ );
+ is(details.hasFastClick, true, "FastClick was found.");
+ });
+
+ BrowserTestUtils.removeTab(tab2);
+ BrowserTestUtils.removeTab(tab1);
+});
+
+add_task(async function test_framework_label() {
+ let tab1 = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ FRAMEWORKS_TEST_PAGE
+ );
+ let tab2 = await clickToReportAndAwaitReportTabLoad();
+
+ await SpecialPowers.spawn(tab2.linkedBrowser, [], async function (args) {
+ let doc = content.document;
+ let labelParam = doc.getElementById("label").innerText;
+ const label = JSON.parse(labelParam);
+ ok(typeof label == "object", "Label param is a stringified JSON object.");
+ is(label.includes("type-fastclick"), true, "FastClick was found.");
+ is(label.includes("type-mobify"), true, "Mobify was found.");
+ is(label.includes("type-marfeel"), true, "Marfeel was found.");
+ });
+
+ BrowserTestUtils.removeTab(tab2);
+ BrowserTestUtils.removeTab(tab1);
+});
diff --git a/browser/extensions/report-site-issue/test/browser/fastclick.html b/browser/extensions/report-site-issue/test/browser/fastclick.html
new file mode 100644
index 0000000000..e13329dfd7
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/fastclick.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script>
+ "use strict";
+ function ObscuredFastClick() {
+ }
+ ObscuredFastClick.prototype = {
+ needsClick: () => {},
+ };
+ window.someRandomVar = new ObscuredFastClick();
+</script>
diff --git a/browser/extensions/report-site-issue/test/browser/frameworks.html b/browser/extensions/report-site-issue/test/browser/frameworks.html
new file mode 100644
index 0000000000..14df387ec9
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/frameworks.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script>
+ "use strict";
+ function FastClick() {}
+ function marfeel() {}
+ var Mobify = {Tag: "something"};
+</script>
diff --git a/browser/extensions/report-site-issue/test/browser/head.js b/browser/extensions/report-site-issue/test/browser/head.js
new file mode 100644
index 0000000000..8fd4e91406
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/head.js
@@ -0,0 +1,119 @@
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
+});
+
+const { Management } = ChromeUtils.importESModule(
+ "resource://gre/modules/Extension.sys.mjs"
+);
+
+const PREF_WC_REPORTER_ENABLED = "extensions.webcompat-reporter.enabled";
+const PREF_WC_REPORTER_ENDPOINT =
+ "extensions.webcompat-reporter.newIssueEndpoint";
+
+const TEST_ROOT = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://example.com"
+);
+const TEST_PAGE = TEST_ROOT + "test.html";
+const FRAMEWORKS_TEST_PAGE = TEST_ROOT + "frameworks.html";
+const FASTCLICK_TEST_PAGE = TEST_ROOT + "fastclick.html";
+const NEW_ISSUE_PAGE = TEST_ROOT + "webcompat.html";
+
+const WC_ADDON_ID = "webcompat-reporter@mozilla.org";
+
+async function promiseAddonEnabled() {
+ const addon = await AddonManager.getAddonByID(WC_ADDON_ID);
+ if (addon.isActive) {
+ return;
+ }
+ const pref = SpecialPowers.Services.prefs.getBoolPref(
+ PREF_WC_REPORTER_ENABLED,
+ false
+ );
+ if (!pref) {
+ SpecialPowers.Services.prefs.setBoolPref(PREF_WC_REPORTER_ENABLED, true);
+ }
+}
+
+class HelpMenuHelper {
+ #popup = null;
+
+ async open() {
+ this.popup = document.getElementById("menu_HelpPopup");
+ ok(this.popup, "Help menu should exist");
+
+ const menuOpen = BrowserTestUtils.waitForEvent(this.popup, "popupshown");
+
+ // This event-faking method was copied from browser_title_case_menus.js so
+ // this can be tested on MacOS (where the actual menus cannot be opened in
+ // tests, but we only need the help menu to populate itself).
+ this.popup.dispatchEvent(new MouseEvent("popupshowing", { bubbles: true }));
+ this.popup.dispatchEvent(new MouseEvent("popupshown", { bubbles: true }));
+
+ await menuOpen;
+ }
+
+ async close() {
+ if (this.popup) {
+ const menuClose = BrowserTestUtils.waitForEvent(
+ this.popup,
+ "popuphidden"
+ );
+
+ // (Also copied from browser_title_case_menus.js)
+ // Just for good measure, we'll fire the popuphiding/popuphidden events
+ // after we close the menupopups.
+ this.popup.dispatchEvent(
+ new MouseEvent("popuphiding", { bubbles: true })
+ );
+ this.popup.dispatchEvent(
+ new MouseEvent("popuphidden", { bubbles: true })
+ );
+
+ await menuClose;
+ this.popup = null;
+ }
+ }
+
+ isItemHidden() {
+ const item = document.getElementById("help_reportSiteIssue");
+ return item && item.hidden;
+ }
+
+ isItemEnabled() {
+ const item = document.getElementById("help_reportSiteIssue");
+ return item && !item.hidden && !item.disabled;
+ }
+}
+
+async function startIssueServer() {
+ const landingTemplate = await new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET", NEW_ISSUE_PAGE);
+ xhr.onload = () => {
+ resolve(xhr.responseText);
+ };
+ xhr.onerror = reject;
+ xhr.send();
+ });
+
+ const { HttpServer } = ChromeUtils.import(
+ "resource://testing-common/httpd.js"
+ );
+ const server = new HttpServer();
+
+ registerCleanupFunction(async function cleanup() {
+ await new Promise(resolve => server.stop(resolve));
+ });
+
+ server.registerPathHandler("/new", function (request, response) {
+ response.setHeader("Content-Type", "text/html", false);
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.write(landingTemplate);
+ });
+
+ server.start(-1);
+ return `http://localhost:${server.identity.primaryPort}/new`;
+}
diff --git a/browser/extensions/report-site-issue/test/browser/test.html b/browser/extensions/report-site-issue/test/browser/test.html
new file mode 100644
index 0000000000..ed1844f530
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/test.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script>
+ /* eslint-disable no-console */
+ /* eslint-disable no-unused-expressions */
+ "use strict";
+ console.log(null);
+ console.error("%ccolored message", "background:green; color:white");
+ const obj = {
+ testSymbol: Symbol("sym"),
+ testobj: {},
+ testnumber: 1,
+ testArray: [1, {}, 2, 555],
+ testUndf: undefined,
+ testNull: null,
+ testFunc() {},
+ testString: 'string',
+ prop1: 'prop1',
+ prop2: 'prop2'
+ };
+ obj.c = obj;
+ obj.prop3 = 'prop3';
+ obj.prop4 = 'prop4';
+ console.log(obj);
+ const arr = [
+ 'string',
+ {test: 'obj'},
+ null,
+ 90,
+ undefined,
+ function() {},
+ [1, {}, 2, 555]
+ ];
+ arr.push(arr);
+ console.log(arr);
+ document.access.non.existent.property.to.trigger.error;
+</script>
+<style>
+ body {background: rgb(0, 128, 0);}
+</style>
diff --git a/browser/extensions/report-site-issue/test/browser/webcompat.html b/browser/extensions/report-site-issue/test/browser/webcompat.html
new file mode 100644
index 0000000000..872c8917b7
--- /dev/null
+++ b/browser/extensions/report-site-issue/test/browser/webcompat.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+ #screenshot-preview {width: 200px; height: 200px;}
+</style>
+<div id="url">$$URL$$</div>
+<div id="details">$$DETAILS$$</div>
+<div id="label">$$LABEL$$</div>
+<div id="screenshot-preview">Fail</div>
+<script>
+"use strict";
+let preview = document.getElementById("screenshot-preview");
+const CONFIG = {
+ url: {
+ element: document.getElementById("url")
+ },
+ details: {
+ element: document.getElementById("details"),
+ toStringify: true
+ },
+ extra_labels: {
+ element: document.getElementById("label"),
+ toStringify: true
+ },
+};
+
+function getBlobAsDataURL(blob) {
+ return new Promise((resolve, reject) => {
+ let reader = new FileReader();
+
+ // eslint-disable-next-line mozilla/balanced-listeners
+ reader.addEventListener("error", (e) => {
+ reject(`There was an error reading the blob: ${e.type}`);
+ });
+
+ // eslint-disable-next-line mozilla/balanced-listeners
+ reader.addEventListener("load", (e) => {
+ resolve(e.target.result);
+ });
+
+ reader.readAsDataURL(blob);
+ });
+}
+
+function setPreviewBG(backgroundData) {
+ return new Promise((resolve) => {
+ preview.style.background = `url(${backgroundData})`;
+ resolve();
+ });
+}
+
+function sendReceivedEvent() {
+ window.dispatchEvent(new CustomEvent("ScreenshotReceived", {bubbles: true}));
+}
+
+function prepareContent(toStringify, content) {
+ if (toStringify) {
+ return JSON.stringify(content)
+ }
+
+ return content;
+}
+
+function appendMessage(message) {
+ for (const key in CONFIG) {
+ if (key in message) {
+ const field = CONFIG[key];
+ field.element.innerText = prepareContent(field.toStringify, message[key]);
+ }
+ }
+}
+
+// eslint-disable-next-line mozilla/balanced-listeners
+window.addEventListener("message", function(event) {
+ if (event.data.screenshot instanceof Blob) {
+ preview.innerText = "Pass";
+ }
+
+ if (event.data.message) {
+ appendMessage(event.data.message);
+ }
+
+ getBlobAsDataURL(event.data.screenshot).then(setPreviewBG).then(sendReceivedEvent);
+});
+</script>