summaryrefslogtreecommitdiffstats
path: root/browser/components/aboutwelcome/tests/xpcshell
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/aboutwelcome/tests/xpcshell')
-rw-r--r--browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeAttribution.js69
-rw-r--r--browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry.js90
-rw-r--r--browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry_glean.js238
-rw-r--r--browser/components/aboutwelcome/tests/xpcshell/xpcshell.toml9
4 files changed, 406 insertions, 0 deletions
diff --git a/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeAttribution.js b/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeAttribution.js
new file mode 100644
index 0000000000..3d83f473d5
--- /dev/null
+++ b/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeAttribution.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+const { AboutWelcomeDefaults } = ChromeUtils.importESModule(
+ "resource:///modules/aboutwelcome/AboutWelcomeDefaults.sys.mjs"
+);
+const { sinon } = ChromeUtils.importESModule(
+ "resource://testing-common/Sinon.sys.mjs"
+);
+const { AttributionCode } = ChromeUtils.importESModule(
+ "resource:///modules/AttributionCode.sys.mjs"
+);
+const { AddonRepository } = ChromeUtils.importESModule(
+ "resource://gre/modules/addons/AddonRepository.sys.mjs"
+);
+
+const TEST_ATTRIBUTION_DATA = {
+ source: "addons.mozilla.org",
+ medium: "referral",
+ campaign: "non-fx-button",
+ content: "rta:iridium%40particlecore.github.io",
+};
+
+add_task(async function test_handleAddonInfoNotFound() {
+ let sandbox = sinon.createSandbox();
+ const stub = sandbox.stub(AttributionCode, "getAttrDataAsync").resolves(null);
+ let result = await AboutWelcomeDefaults.getAttributionContent();
+ equal(stub.callCount, 1, "Call was made");
+ equal(result, null, "No data is returned");
+
+ sandbox.restore();
+});
+
+add_task(async function test_UAAttribution() {
+ let sandbox = sinon.createSandbox();
+ const stub = sandbox
+ .stub(AttributionCode, "getAttrDataAsync")
+ .resolves({ ua: "test" });
+ let result = await AboutWelcomeDefaults.getAttributionContent();
+ equal(stub.callCount, 1, "Call was made");
+ equal(result.template, undefined, "Template was not returned");
+ equal(result.ua, "test", "UA was returned");
+
+ sandbox.restore();
+});
+
+add_task(async function test_formatAttributionData() {
+ let sandbox = sinon.createSandbox();
+ const TEST_ADDON_INFO = {
+ sourceURI: { scheme: "https", spec: "https://test.xpi" },
+ name: "Test Add-on",
+ icons: { 64: "http://test.svg" },
+ };
+ sandbox
+ .stub(AttributionCode, "getAttrDataAsync")
+ .resolves(TEST_ATTRIBUTION_DATA);
+ sandbox.stub(AddonRepository, "getAddonsByIDs").resolves([TEST_ADDON_INFO]);
+ let result = await AboutWelcomeDefaults.getAttributionContent(
+ TEST_ATTRIBUTION_DATA
+ );
+ equal(AddonRepository.getAddonsByIDs.callCount, 1, "Retrieve addon content");
+ equal(result.template, "return_to_amo", "RTAMO template returned");
+ equal(result.name, TEST_ADDON_INFO.name, "AddonInfo returned");
+
+ sandbox.restore();
+});
diff --git a/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry.js b/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry.js
new file mode 100644
index 0000000000..b8339fb39f
--- /dev/null
+++ b/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry.js
@@ -0,0 +1,90 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+const { AboutWelcomeTelemetry } = ChromeUtils.importESModule(
+ "resource:///modules/aboutwelcome/AboutWelcomeTelemetry.sys.mjs"
+);
+const { AttributionCode } = ChromeUtils.importESModule(
+ "resource:///modules/AttributionCode.sys.mjs"
+);
+const { sinon } = ChromeUtils.importESModule(
+ "resource://testing-common/Sinon.sys.mjs"
+);
+const TELEMETRY_PREF = "browser.newtabpage.activity-stream.telemetry";
+
+add_setup(function setup() {
+ do_get_profile();
+ Services.fog.initializeFOG();
+});
+
+add_task(function test_enabled() {
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(TELEMETRY_PREF);
+ });
+ Services.prefs.setBoolPref(TELEMETRY_PREF, true);
+
+ const AWTelemetry = new AboutWelcomeTelemetry();
+
+ equal(AWTelemetry.telemetryEnabled, true, "Telemetry should be on");
+
+ Services.prefs.setBoolPref(TELEMETRY_PREF, false);
+
+ equal(AWTelemetry.telemetryEnabled, false, "Telemetry should be off");
+});
+
+add_task(async function test_pingPayload() {
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(TELEMETRY_PREF);
+ });
+ Services.prefs.setBoolPref(TELEMETRY_PREF, true);
+ const AWTelemetry = new AboutWelcomeTelemetry();
+ sinon.stub(AWTelemetry, "_createPing").resolves({ event: "MOCHITEST" });
+
+ let pingSubmitted = false;
+ GleanPings.messagingSystem.testBeforeNextSubmit(() => {
+ pingSubmitted = true;
+ Assert.equal(Glean.messagingSystem.event.testGetValue(), "MOCHITEST");
+ });
+ await AWTelemetry.sendTelemetry();
+
+ ok(pingSubmitted, "Glean ping was submitted");
+});
+
+add_task(function test_mayAttachAttribution() {
+ const sandbox = sinon.createSandbox();
+ const AWTelemetry = new AboutWelcomeTelemetry();
+
+ sandbox.stub(AttributionCode, "getCachedAttributionData").returns(null);
+
+ let ping = AWTelemetry._maybeAttachAttribution({});
+
+ equal(ping.attribution, undefined, "Should not set attribution if it's null");
+
+ sandbox.restore();
+ sandbox.stub(AttributionCode, "getCachedAttributionData").returns({});
+ ping = AWTelemetry._maybeAttachAttribution({});
+
+ equal(
+ ping.attribution,
+ undefined,
+ "Should not set attribution if it's empty"
+ );
+
+ const attr = {
+ source: "google.com",
+ medium: "referral",
+ campaign: "Firefox-Brand-US-Chrome",
+ content: "(not set)",
+ experiment: "(not set)",
+ variation: "(not set)",
+ ua: "chrome",
+ };
+ sandbox.restore();
+ sandbox.stub(AttributionCode, "getCachedAttributionData").returns(attr);
+ ping = AWTelemetry._maybeAttachAttribution({});
+
+ equal(ping.attribution, attr, "Should set attribution if it presents");
+});
diff --git a/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry_glean.js b/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry_glean.js
new file mode 100644
index 0000000000..5191f05d04
--- /dev/null
+++ b/browser/components/aboutwelcome/tests/xpcshell/test_AboutWelcomeTelemetry_glean.js
@@ -0,0 +1,238 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+const { AboutWelcomeTelemetry } = ChromeUtils.importESModule(
+ "resource:///modules/aboutwelcome/AboutWelcomeTelemetry.sys.mjs"
+);
+const TELEMETRY_PREF = "browser.newtabpage.activity-stream.telemetry";
+
+add_setup(function setup() {
+ do_get_profile();
+ Services.fog.initializeFOG();
+});
+
+// We recognize two kinds of unexpected data that might reach
+// `submitGleanPingForPing`: unknown keys, and keys with unexpectedly-complex
+// data (ie, non-scalar).
+// We report the keys in special metrics to aid in system health monitoring.
+add_task(function test_weird_data() {
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(TELEMETRY_PREF);
+ });
+ Services.prefs.setBoolPref(TELEMETRY_PREF, true);
+
+ const AWTelemetry = new AboutWelcomeTelemetry();
+
+ const unknownKey = "some_unknown_key";
+ const camelUnknownKey = AWTelemetry._snakeToCamelCase(unknownKey);
+
+ let pingSubmitted = false;
+ GleanPings.messagingSystem.testBeforeNextSubmit(() => {
+ pingSubmitted = true;
+ Assert.equal(
+ Glean.messagingSystem.unknownKeys[camelUnknownKey].testGetValue(),
+ 1,
+ "caught the unknown key"
+ );
+ // TODO(bug 1600008): Also check the for-testing overall count.
+ Assert.equal(Glean.messagingSystem.unknownKeyCount.testGetValue(), 1);
+ });
+ AWTelemetry.submitGleanPingForPing({
+ [unknownKey]: "value doesn't matter",
+ });
+
+ Assert.ok(pingSubmitted, "Ping with unknown keys was submitted");
+
+ const invalidNestedDataKey = "event";
+ pingSubmitted = false;
+ GleanPings.messagingSystem.testBeforeNextSubmit(() => {
+ pingSubmitted = true;
+ Assert.equal(
+ Glean.messagingSystem.invalidNestedData[
+ invalidNestedDataKey
+ ].testGetValue("messaging-system"),
+ 1,
+ "caught the invalid nested data"
+ );
+ });
+ AWTelemetry.submitGleanPingForPing({
+ [invalidNestedDataKey]: { this_should: "not be", complex: "data" },
+ });
+
+ Assert.ok(pingSubmitted, "Ping with invalid nested data submitted");
+});
+
+// `event_context` is weird. It's an object, but it might have been stringified
+// before being provided for recording.
+add_task(function test_event_context() {
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(TELEMETRY_PREF);
+ });
+ Services.prefs.setBoolPref(TELEMETRY_PREF, true);
+
+ const AWTelemetry = new AboutWelcomeTelemetry();
+
+ const eventContext = {
+ reason: "reason",
+ page: "page",
+ source: "source",
+ something_else: "not specifically handled",
+ screen_family: "family",
+ screen_id: "screen_id",
+ screen_index: 0,
+ screen_initlals: "screen_initials",
+ };
+ const stringifiedEC = JSON.stringify(eventContext);
+
+ let pingSubmitted = false;
+ GleanPings.messagingSystem.testBeforeNextSubmit(() => {
+ pingSubmitted = true;
+ Assert.equal(
+ Glean.messagingSystem.eventReason.testGetValue(),
+ eventContext.reason,
+ "event_context.reason also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventPage.testGetValue(),
+ eventContext.page,
+ "event_context.page also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventSource.testGetValue(),
+ eventContext.source,
+ "event_context.source also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenFamily.testGetValue(),
+ eventContext.screen_family,
+ "event_context.screen_family also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenId.testGetValue(),
+ eventContext.screen_id,
+ "event_context.screen_id also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenIndex.testGetValue(),
+ eventContext.screen_index,
+ "event_context.screen_index also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenInitials.testGetValue(),
+ eventContext.screen_initials,
+ "event_context.screen_initials also in own metric."
+ );
+
+ Assert.equal(
+ Glean.messagingSystem.eventContext.testGetValue(),
+ stringifiedEC,
+ "whole event_context added as text."
+ );
+ });
+ AWTelemetry.submitGleanPingForPing({
+ event_context: eventContext,
+ });
+ Assert.ok(pingSubmitted, "Ping with object event_context submitted");
+
+ pingSubmitted = false;
+ GleanPings.messagingSystem.testBeforeNextSubmit(() => {
+ pingSubmitted = true;
+ Assert.equal(
+ Glean.messagingSystem.eventReason.testGetValue(),
+ eventContext.reason,
+ "event_context.reason also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventPage.testGetValue(),
+ eventContext.page,
+ "event_context.page also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventSource.testGetValue(),
+ eventContext.source,
+ "event_context.source also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenFamily.testGetValue(),
+ eventContext.screen_family,
+ "event_context.screen_family also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenId.testGetValue(),
+ eventContext.screen_id,
+ "event_context.screen_id also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenIndex.testGetValue(),
+ eventContext.screen_index,
+ "event_context.screen_index also in own metric."
+ );
+ Assert.equal(
+ Glean.messagingSystem.eventScreenInitials.testGetValue(),
+ eventContext.screen_initials,
+ "event_context.screen_initials also in own metric."
+ );
+
+ Assert.equal(
+ Glean.messagingSystem.eventContext.testGetValue(),
+ stringifiedEC,
+ "whole event_context added as text."
+ );
+ });
+ AWTelemetry.submitGleanPingForPing({
+ event_context: stringifiedEC,
+ });
+ Assert.ok(pingSubmitted, "Ping with string event_context submitted");
+});
+
+// For event_context to be more useful, we want to make sure we don't error
+// in cases where it doesn't make much sense, such as a plain string that
+// doesnt attempt to represent a valid object.
+add_task(function test_context_errors() {
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref(TELEMETRY_PREF);
+ });
+ Services.prefs.setBoolPref(TELEMETRY_PREF, true);
+
+ const AWTelemetry = new AboutWelcomeTelemetry();
+
+ let weird_context_ping = {
+ event_context: "oops, this string isn't a valid JS object!",
+ };
+
+ let pingSubmitted = false;
+ GleanPings.messagingSystem.testBeforeNextSubmit(() => {
+ pingSubmitted = true;
+ Assert.equal(
+ Glean.messagingSystem.eventContextParseError.testGetValue(),
+ undefined,
+ "this poorly formed context shouldn't register because it was not an object!"
+ );
+ });
+
+ AWTelemetry.submitGleanPingForPing(weird_context_ping);
+
+ Assert.ok(pingSubmitted, "Ping with unknown keys was submitted");
+
+ weird_context_ping = {
+ event_context:
+ "{oops : {'this string isn't a valid JS object, but it sure looks like one!}}'",
+ };
+
+ pingSubmitted = false;
+ GleanPings.messagingSystem.testBeforeNextSubmit(() => {
+ pingSubmitted = true;
+ Assert.equal(
+ Glean.messagingSystem.eventContextParseError.testGetValue(),
+ 1,
+ "this poorly formed context should register because it was not an object!"
+ );
+ });
+
+ AWTelemetry.submitGleanPingForPing(weird_context_ping);
+
+ Assert.ok(pingSubmitted, "Ping with unknown keys was submitted");
+});
diff --git a/browser/components/aboutwelcome/tests/xpcshell/xpcshell.toml b/browser/components/aboutwelcome/tests/xpcshell/xpcshell.toml
new file mode 100644
index 0000000000..d68ee3e51e
--- /dev/null
+++ b/browser/components/aboutwelcome/tests/xpcshell/xpcshell.toml
@@ -0,0 +1,9 @@
+[DEFAULT]
+skip-if = ["os == 'android'"]
+firefox-appdir = "browser"
+
+["test_AboutWelcomeAttribution.js"]
+
+["test_AboutWelcomeTelemetry.js"]
+
+["test_AboutWelcomeTelemetry_glean.js"]