summaryrefslogtreecommitdiffstats
path: root/browser/components/reportbrokensite/test/browser/send.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/reportbrokensite/test/browser/send.js')
-rw-r--r--browser/components/reportbrokensite/test/browser/send.js290
1 files changed, 290 insertions, 0 deletions
diff --git a/browser/components/reportbrokensite/test/browser/send.js b/browser/components/reportbrokensite/test/browser/send.js
new file mode 100644
index 0000000000..a8599741ac
--- /dev/null
+++ b/browser/components/reportbrokensite/test/browser/send.js
@@ -0,0 +1,290 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* Helper methods for testing sending reports with
+ * the Report Broken Site feature.
+ */
+
+/* import-globals-from head.js */
+
+"use strict";
+
+const { Troubleshoot } = ChromeUtils.importESModule(
+ "resource://gre/modules/Troubleshoot.sys.mjs"
+);
+
+function getSysinfoProperty(propertyName, defaultValue) {
+ try {
+ return Services.sysinfo.getProperty(propertyName);
+ } catch (e) {}
+ return defaultValue;
+}
+
+function securityStringToArray(str) {
+ return str ? str.split(";") : null;
+}
+
+function getExpectedGraphicsDevices(snapshot) {
+ const { graphics } = snapshot;
+ return [
+ graphics.adapterDeviceID,
+ graphics.adapterVendorID,
+ graphics.adapterDeviceID2,
+ graphics.adapterVendorID2,
+ ]
+ .filter(i => i)
+ .sort();
+}
+
+function compareGraphicsDevices(expected, rawActual) {
+ const actual = rawActual
+ .map(({ deviceID, vendorID }) => [deviceID, vendorID])
+ .flat()
+ .filter(i => i)
+ .sort();
+ return areObjectsEqual(actual, expected);
+}
+
+function getExpectedGraphicsDrivers(snapshot) {
+ const { graphics } = snapshot;
+ const expected = [];
+ for (let i = 1; i < 3; ++i) {
+ const version = graphics[`webgl${i}Version`];
+ if (version && version != "-") {
+ expected.push(graphics[`webgl${i}Renderer`]);
+ expected.push(version);
+ }
+ }
+ return expected.filter(i => i).sort();
+}
+
+function compareGraphicsDrivers(expected, rawActual) {
+ const actual = rawActual
+ .map(({ renderer, version }) => [renderer, version])
+ .flat()
+ .filter(i => i)
+ .sort();
+ return areObjectsEqual(actual, expected);
+}
+
+function getExpectedGraphicsFeatures(snapshot) {
+ const expected = {};
+ for (let { name, log, status } of snapshot.graphics.featureLog.features) {
+ for (const item of log?.reverse() ?? []) {
+ if (item.failureId && item.status == status) {
+ status = `${status} (${item.message || item.failureId})`;
+ }
+ }
+ expected[name] = status;
+ }
+ return expected;
+}
+
+async function getExpectedWebCompatInfo(tab, snapshot, fullAppData = false) {
+ const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
+
+ const { application, graphics, intl, securitySoftware } = snapshot;
+
+ const { fissionAutoStart, memorySizeBytes, updateChannel, userAgent } =
+ application;
+
+ const app = {
+ defaultLocales: intl.localeService.available,
+ defaultUseragentString: userAgent,
+ fissionEnabled: fissionAutoStart,
+ };
+ if (fullAppData) {
+ app.applicationName = application.name;
+ app.osArchitecture = getSysinfoProperty("arch", null);
+ app.osName = getSysinfoProperty("name", null);
+ app.osVersion = getSysinfoProperty("version", null);
+ app.updateChannel = updateChannel;
+ app.version = application.version;
+ }
+
+ const hasTouchScreen = graphics.info.ApzTouchInput == 1;
+
+ const { registeredAntiVirus, registeredAntiSpyware, registeredFirewall } =
+ securitySoftware;
+
+ const browserInfo = {
+ app,
+ graphics: {
+ devicesJson(actualStr) {
+ const expected = getExpectedGraphicsDevices(snapshot);
+ // If undefined is saved to the Glean value here, we'll get the string "undefined" (invalid JSON).
+ // We should stop using JSON like this in bug 1875185.
+ if (!actualStr || actualStr == "undefined") {
+ return !expected.length;
+ }
+ return compareGraphicsDevices(expected, JSON.parse(actualStr));
+ },
+ driversJson(actualStr) {
+ const expected = getExpectedGraphicsDrivers(snapshot);
+ // If undefined is saved to the Glean value here, we'll get the string "undefined" (invalid JSON).
+ // We should stop using JSON like this in bug 1875185.
+ if (!actualStr || actualStr == "undefined") {
+ return !expected.length;
+ }
+ return compareGraphicsDrivers(expected, JSON.parse(actualStr));
+ },
+ featuresJson(actualStr) {
+ const expected = getExpectedGraphicsFeatures(snapshot);
+ // If undefined is saved to the Glean value here, we'll get the string "undefined" (invalid JSON).
+ // We should stop using JSON like this in bug 1875185.
+ if (!actualStr || actualStr == "undefined") {
+ return !expected.length;
+ }
+ return areObjectsEqual(JSON.parse(actualStr), expected);
+ },
+ hasTouchScreen,
+ monitorsJson(actualStr) {
+ // We don't care about monitor data on Android right now.
+ if (AppConstants.platform == "android") {
+ return actualStr == "undefined";
+ }
+ return actualStr == JSON.stringify(gfxInfo.getMonitors());
+ },
+ },
+ prefs: {
+ cookieBehavior: Services.prefs.getIntPref(
+ "network.cookie.cookieBehavior",
+ -1
+ ),
+ forcedAcceleratedLayers: Services.prefs.getBoolPref(
+ "layers.acceleration.force-enabled",
+ false
+ ),
+ globalPrivacyControlEnabled: Services.prefs.getBoolPref(
+ "privacy.globalprivacycontrol.enabled",
+ false
+ ),
+ installtriggerEnabled: Services.prefs.getBoolPref(
+ "extensions.InstallTrigger.enabled",
+ false
+ ),
+ opaqueResponseBlocking: Services.prefs.getBoolPref(
+ "browser.opaqueResponseBlocking",
+ false
+ ),
+ resistFingerprintingEnabled: Services.prefs.getBoolPref(
+ "privacy.resistFingerprinting",
+ false
+ ),
+ softwareWebrender: Services.prefs.getBoolPref(
+ "gfx.webrender.software",
+ false
+ ),
+ },
+ security: {
+ antispyware: securityStringToArray(registeredAntiSpyware),
+ antivirus: securityStringToArray(registeredAntiVirus),
+ firewall: securityStringToArray(registeredFirewall),
+ },
+ system: {
+ isTablet: getSysinfoProperty("tablet", false),
+ memory: Math.round(memorySizeBytes / 1024 / 1024),
+ },
+ };
+
+ const tabInfo = await tab.linkedBrowser.ownerGlobal.SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ async function () {
+ return {
+ devicePixelRatio: `${content.devicePixelRatio}`,
+ antitracking: {
+ blockList: "basic",
+ isPrivateBrowsing: false,
+ hasTrackingContentBlocked: false,
+ hasMixedActiveContentBlocked: false,
+ hasMixedDisplayContentBlocked: false,
+ },
+ frameworks: {
+ fastclick: false,
+ marfeel: false,
+ mobify: false,
+ },
+ languages: content.navigator.languages,
+ useragentString: content.navigator.userAgent,
+ };
+ }
+ );
+
+ browserInfo.graphics.devicePixelRatio = tabInfo.devicePixelRatio;
+ delete tabInfo.devicePixelRatio;
+
+ return { browserInfo, tabInfo };
+}
+
+function extractPingData(branch) {
+ const data = {};
+ for (const [name, value] of Object.entries(branch)) {
+ data[name] = value.testGetValue();
+ }
+ return data;
+}
+
+function extractBrokenSiteReportFromGleanPing(Glean) {
+ const ping = extractPingData(Glean.brokenSiteReport);
+ ping.tabInfo = extractPingData(Glean.brokenSiteReportTabInfo);
+ ping.tabInfo.antitracking = extractPingData(
+ Glean.brokenSiteReportTabInfoAntitracking
+ );
+ ping.tabInfo.frameworks = extractPingData(
+ Glean.brokenSiteReportTabInfoFrameworks
+ );
+ ping.browserInfo = {
+ app: extractPingData(Glean.brokenSiteReportBrowserInfoApp),
+ graphics: extractPingData(Glean.brokenSiteReportBrowserInfoGraphics),
+ prefs: extractPingData(Glean.brokenSiteReportBrowserInfoPrefs),
+ security: extractPingData(Glean.brokenSiteReportBrowserInfoSecurity),
+ system: extractPingData(Glean.brokenSiteReportBrowserInfoSystem),
+ };
+ return ping;
+}
+
+async function testSend(tab, menu, expectedOverrides = {}) {
+ const url = expectedOverrides.url ?? menu.win.gBrowser.currentURI.spec;
+ const description = expectedOverrides.description ?? "";
+ const breakageCategory = expectedOverrides.breakageCategory ?? null;
+
+ let rbs = await menu.openAndPrefillReportBrokenSite(url, description);
+
+ const snapshot = await Troubleshoot.snapshot();
+ const expected = await getExpectedWebCompatInfo(tab, snapshot);
+
+ expected.url = url;
+ expected.description = description;
+ expected.breakageCategory = breakageCategory;
+
+ if (expectedOverrides.antitracking) {
+ expected.tabInfo.antitracking = expectedOverrides.antitracking;
+ }
+
+ if (expectedOverrides.frameworks) {
+ expected.tabInfo.frameworks = expectedOverrides.frameworks;
+ }
+
+ if (breakageCategory) {
+ rbs.chooseReason(breakageCategory);
+ }
+
+ const pingCheck = new Promise(resolve => {
+ Services.fog.testResetFOG();
+ GleanPings.brokenSiteReport.testBeforeNextSubmit(() => {
+ const ping = extractBrokenSiteReportFromGleanPing(Glean);
+ ok(areObjectsEqual(ping, expected), "ping matches expectations");
+ resolve();
+ });
+ });
+
+ await rbs.clickSend();
+ await pingCheck;
+ await rbs.clickOkay();
+
+ // re-opening the panel, the url and description should be reset
+ rbs = await menu.openReportBrokenSite();
+ rbs.isMainViewResetToCurrentTab();
+ rbs.close();
+}