diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas')
21 files changed, 1281 insertions, 0 deletions
diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/SpecialMessageActionSchemas.json b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/SpecialMessageActionSchemas.json new file mode 100644 index 0000000000..f7fe9c9406 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/SpecialMessageActionSchemas.json @@ -0,0 +1,396 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/SpecialMessageActionSchemas", + "definitions": { + "SpecialMessageActionSchemas": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["DISABLE_STP_DOORHANGERS"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Disables all STP doorhangers." + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "args": { + "type": "string", + "description": "The element to highlight" + } + }, + "required": ["args"], + "additionalProperties": false + }, + "type": { + "type": "string", + "enum": ["HIGHLIGHT_FEATURE"] + } + }, + "required": ["data", "type"], + "additionalProperties": false, + "description": "Highlights an element, such as a menu item" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "telemetrySource": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": ["telemetrySource", "url"], + "additionalProperties": false + }, + "type": { + "type": "string", + "enum": ["INSTALL_ADDON_FROM_URL"] + } + }, + "required": ["data", "type"], + "additionalProperties": false, + "description": "Install an add-on from AMO" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "args": { + "type": "string", + "description": "The about page. E.g. \"welcome\" for about:welcome'" + }, + "where": { + "type": "string", + "enum": ["current", "save", "tab", "tabshifted", "window"], + "description": "Where the URL is opened", + "default": "tab" + }, + "entrypoint": { + "type": "string", + "description": "Any optional entrypoint value that will be added to the search. E.g. \"foo=bar\" would result in about:welcome?foo=bar'" + } + }, + "required": ["args", "where", "entrypoint"], + "additionalProperties": false + }, + "type": { + "type": "string", + "enum": ["OPEN_ABOUT_PAGE"] + } + }, + "required": ["data", "type"], + "additionalProperties": false, + "description": "Opens an about: page in Firefox" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "args": { + "type": "string", + "description": "The menu name, e.g. \"appMenu\"" + } + }, + "required": ["args"], + "additionalProperties": false + }, + "type": { + "type": "string", + "enum": ["OPEN_APPLICATIONS_MENU"] + } + }, + "required": ["data", "type"], + "additionalProperties": false, + "description": "Opens an application menu" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["OPEN_AWESOME_BAR"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Focuses and expands the awesome bar" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "category": { + "type": "string", + "description": "Section of about:preferences, e.g. \"privacy-reports\"" + }, + "entrypoint": { + "type": "string", + "description": "Add a queryparam for metrics" + } + }, + "required": ["category"], + "additionalProperties": false + }, + "type": { + "type": "string", + "enum": ["OPEN_PREFERENCES_PAGE"] + } + }, + "required": ["data", "type"], + "additionalProperties": false, + "description": "Opens a preference page" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["OPEN_PRIVATE_BROWSER_WINDOW"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Opens a private browsing window." + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["OPEN_PROTECTION_PANEL"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Opens the protections panel" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["OPEN_PROTECTION_REPORT"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Opens the protections panel report" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "args": { + "type": "string", + "description": "URL to open" + }, + "where": { + "type": "string", + "enum": ["current", "save", "tab", "tabshifted", "window"], + "description": "Where the URL is opened", + "default": "tab" + } + }, + "required": ["args", "where"], + "additionalProperties": false + }, + "type": { + "type": "string", + "enum": ["OPEN_URL"] + } + }, + "required": ["data", "type"], + "additionalProperties": false, + "description": "Opens given URL" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["PIN_CURRENT_TAB"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Pin the current tab" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["SHOW_FIREFOX_ACCOUNTS"] + }, + "data": { + "type": "object", + "properties": { + "entrypoint": { + "type": "string", + "description": "Adds entrypoint={your value} to the FXA URL" + }, + "extraParams": { + "type": "object", + "description": "Any extra parameter that will be added to the FXA URL. E.g. {foo: bar} would result in <FXA_url>?foo=bar'" + } + }, + "required": ["entrypoint"], + "additionalProperties": false + } + }, + "required": ["type", "data"], + "additionalProperties": false, + "description": "Show Firefox Accounts" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["SHOW_MIGRATION_WIZARD"] + }, + "data": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "Identitifer of the browser that should be pre-selected in the import migration wizard popup (e.g. 'chrome'), See https://searchfox.org/mozilla-central/rev/8dae1cc76a6b45e05198bc0d5d4edb7bf1003265/browser/components/migration/MigrationUtils.jsm#917" + } + }, + "additionalProperties": false + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Shows the Migration Wizard to import data from another Browser. See https://support.mozilla.org/en-US/kb/import-data-another-browser\"" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["CANCEL"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Minimize the CFR doorhanger back into the URLbar" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["ACCEPT_DOH"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Accept DOH doorhanger notification" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["DISABLE_DOH"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Dismiss DOH doorhanger notification" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["SET_DEFAULT_BROWSER"] + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "Message action to set Firefox as default browser" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "homePage": { + "type": "string", + "description": "Should reset homepage pref", + "enum": ["default"] + }, + "newtab": { + "type": "string", + "enum": ["default"], + "description": "Should reset newtab pref" + }, + "layout": { + "type": "object", + "description": "Section name and boolean value that specifies if the section should be on or off.", + "properties": { + "search": { + "type": "boolean" + }, + "topsites": { + "type": "boolean" + }, + "highlights": { + "type": "boolean" + }, + "snippets": { + "type": "boolean" + }, + "topstories": { + "type": "boolean" + } + }, + "required": [ + "search", + "topsites", + "highlights", + "snippets", + "topstories" + ], + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "type": { + "type": "string", + "enum": ["CONFIGURE_HOMEPAGE"] + } + }, + "required": ["data", "type"], + "additionalProperties": false, + "description": "Resets homepage pref and sections layout" + } + ] + } + } +} diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/index.md b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/index.md new file mode 100644 index 0000000000..b4af53ba67 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/index.md @@ -0,0 +1,243 @@ +# User Actions + +A subset of actions are available to messages via fields like `button_action` for snippets, or `primary_action` for CFRs. + +## Usage + +For snippets, you should add the action type in `button_action` and any additional parameters in `button_action_args. For example: + +```json +{ + "button_action": "OPEN_ABOUT_PAGE", + "button_action_args": "config" +} +``` + +## How to update + +Make a pull request against [mozilla/nimbus-shared](https://github.com/mozilla/nimbus-shared/) repo with your changes. +Build and copy over resulting schema from `nimbus-shared/schemas/messaging/` to `toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas.json`. + +## Available Actions + +### `OPEN_APPLICATIONS_MENU` + +* args: (none) + +Opens the applications menu. + +### `OPEN_PRIVATE_BROWSER_WINDOW` + +* args: (none) + +Opens a new private browsing window. + + +### `OPEN_URL` + +* args: `string` (a url) + +Opens a given url. + +Example: + +```json +{ + "button_action": "OPEN_URL", + "button_action_args": "https://foo.com" +} +``` + +### `OPEN_ABOUT_PAGE` + +* args: +```ts +{ + args: string, // (a valid about page without the `about:` prefix) + entrypoint?: string, // URL search param used for referrals +} +``` + +Opens a given about page + +Example: + +```json +{ + "button_action": "OPEN_ABOUT_PAGE", + "button_action_args": "config" +} +``` + +### `OPEN_PREFERENCES_PAGE` + +* args: +``` +{ + args?: string, // (a category accessible via a `#`) + entrypoint?: string // URL search param used to referrals + +Opens `about:preferences` with an optional category accessible via a `#` in the URL (e.g. `about:preferences#home`). + +Example: + +```json +{ + "button_action": "OPEN_PREFERENCES_PAGE", + "button_action_args": "home" +} +``` + +### `SHOW_FIREFOX_ACCOUNTS` + +* args: (none) + +Opens Firefox accounts sign-up page. Encodes some information that the origin was from snippets by default. + +### `SHOW_MIGRATION_WIZARD` + +* args: (none) + +Opens import wizard to bring in settings and data from another browser. + +### `PIN_CURRENT_TAB` + +* args: (none) + +Pins the currently focused tab. + +### `ENABLE_FIREFOX_MONITOR` + +* args: +```ts +{ + url: string; + flowRequestParams: { + entrypoint: string; + utm_term: string; + form_type: string; + } +} +``` + +Opens an oauth flow to enable Firefox Monitor at a given `url` and adds Firefox metrics that user given a set of `flowRequestParams`. + +#### `url` + +The URL should start with `https://monitor.firefox.com/oauth/init` and add various metrics tags as search params, including: + +* `utm_source` +* `utm_campaign` +* `form_type` +* `entrypoint` + +You should verify the values of these search params with whoever is doing the data analysis (e.g. Leif Oines). + +#### `flowRequestParams` + +These params are used by Firefox to add information specific to that individual user to the final oauth URL. You should include: + +* `entrypoint` +* `utm_term` +* `form_type` + +The `entrypoint` and `form_type` values should match the encoded values in your `url`. + +You should verify the values with whoever is doing the data analysis (e.g. Leif Oines). + +#### Example + +```json +{ + "button_action": "ENABLE_FIREFOX_MONITOR", + "button_action_args": { + "url": "https://monitor.firefox.com/oauth/init?utm_source=snippets&utm_campaign=monitor-snippet-test&form_type=email&entrypoint=newtab", + "flowRequestParams": { + "entrypoint": "snippets", + "utm_term": "monitor", + "form_type": "email" + } + } +} +``` + +### `HIGHLIGHT_FEATURE` + +Can be used to highlight (show a light blue overlay) a certain button or part of the browser UI. + +* args: `string` a [valid targeting defined in the UITour](https://searchfox.org/mozilla-central/rev/7fd1c1c34923ece7ad8c822bee062dd0491d64dc/browser/components/uitour/UITour.jsm#108) + +### `INSTALL_ADDON_FROM_URL` + +Can be used to install an addon from addons.mozilla.org. + +* args: +```ts +{ + url: string, + telemetrySource?: string +}; +``` + +### `OPEN_PROTECTION_REPORT` + +Opens `about:protections` + +### `OPEN_PROTECTION_PANEL` + +Opens the protection panel behind on the lock icon of the awesomebar + +### `DISABLE_STP_DOORHANGERS` + +Disables all Social Tracking Protection messages + +* args: (none) + +### `OPEN_AWESOME_BAR` + +Focuses and expands the awesome bar. + +* args: (none) + +### `CANCEL` + +No-op action used to dismiss CFR notifications (but not remove or block them) + +* args: (none) + +### `DISABLE_DOH` + +User action for turning off the DoH feature + +* args: (none) + +### `ACCEPT_DOH` + +User action for continuing to use the DoH feature + +* args: (none) + +### `CONFIGURE_HOMEPAGE` + +Action for configuring the user homepage and restoring defaults. + +* args: +```ts +{ + homePage: "default" | null; + newtab: "default" | null; + layout: { + search: boolean; + topsites: boolean; + highlights: boolean; + topstories: boolean; + snippets: boolean; + } +} +``` + +### `SET_DEFAULT_BROWSER` + +Action for configuring the default browser to Firefox on the user's system. + +* args: (none) diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser.ini b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser.ini new file mode 100644 index 0000000000..32bcff6a4d --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser.ini @@ -0,0 +1,23 @@ +[DEFAULT] +prefs = + identity.fxaccounts.remote.root=https://example.com/ +support-files = + head.js + ../../index.md + +[browser_sma_open_about_page.js] +[browser_sma_open_awesome_bar.js] +[browser_sma_open_private_browser_window.js] +[browser_sma_open_protection_panel.js] +[browser_sma_open_protection_report.js] +[browser_sma_open_url.js] +[browser_sma_pin_current_tab.js] +[browser_sma_show_firefox_accounts.js] +[browser_sma_show_migration_wizard.js] +[browser_sma.js] +[browser_sma_docs.js] +[browser_sma_accept_doh.js] +[browser_sma_disable_doh.js] +[browser_sma_cfrmessageprovider.js] +[browser_sma_configure_homepage.js] +[browser_sma_default_browser.js] diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma.js new file mode 100644 index 0000000000..b46b3730e9 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_unknown_event() { + let error; + try { + await SpecialMessageActions.handleAction( + { type: "UNKNOWN_EVENT_123" }, + gBrowser + ); + } catch (e) { + error = e; + } + ok(error, "should throw if an unexpected event is handled"); + Assert.equal( + error.message, + "Special message action with type UNKNOWN_EVENT_123 is unsupported." + ); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_accept_doh.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_accept_doh.js new file mode 100644 index 0000000000..f9255b17ec --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_accept_doh.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +const DOH_DOORHANGER_DECISION_PREF = "doh-rollout.doorhanger-decision"; + +add_task(async function test_disable_doh() { + await SpecialPowers.pushPrefEnv({ + set: [[DOH_DOORHANGER_DECISION_PREF, ""]], + }); + await SMATestUtils.executeAndValidateAction({ type: "ACCEPT_DOH" }); + Assert.equal( + Services.prefs.getStringPref(DOH_DOORHANGER_DECISION_PREF, ""), + "UIOk", + "Pref should be set on accept" + ); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_cancel.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_cancel.js new file mode 100644 index 0000000000..ca42dac563 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_cancel.js @@ -0,0 +1,14 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_cancel_event() { + let error = null; + try { + await SMATestUtils.executeAndValidateAction({ type: "CANCEL" }); + } catch (e) { + error = e; + } + ok(!error, "should not throw for CANCEL"); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_cfrmessageprovider.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_cfrmessageprovider.js new file mode 100644 index 0000000000..93f3cc851f --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_cfrmessageprovider.js @@ -0,0 +1,31 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { CFRMessageProvider } = ChromeUtils.import( + "resource://activity-stream/lib/CFRMessageProvider.jsm" +); + +add_task(async function test_all_test_messages() { + let messagesWithButtons = (await CFRMessageProvider.getMessages()).filter( + m => m.content.buttons + ); + + for (let message of messagesWithButtons) { + info(`Testing ${message.id}`); + if (message.template === "infobar") { + for (let button of message.content.buttons) { + await SMATestUtils.validateAction(button.action); + } + } else { + let { primary, secondary } = message.content.buttons; + await SMATestUtils.validateAction(primary.action); + for (let secondaryBtn of secondary) { + if (secondaryBtn.action) { + await SMATestUtils.validateAction(secondaryBtn.action); + } + } + } + } +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_configure_homepage.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_configure_homepage.js new file mode 100644 index 0000000000..8bc734cece --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_configure_homepage.js @@ -0,0 +1,141 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PromiseUtils } = ChromeUtils.import( + "resource://gre/modules/PromiseUtils.jsm" +); + +const HOMEPAGE_PREF = "browser.startup.homepage"; +const NEWTAB_PREF = "browser.newtabpage.enabled"; +const HIGHLIGHTS_PREF = + "browser.newtabpage.activity-stream.feeds.section.highlights"; +const HIGHLIGHTS_ROWS_PREF = + "browser.newtabpage.activity-stream.section.highlights.rows"; +const SEARCH_PREF = "browser.newtabpage.activity-stream.showSearch"; +const TOPSITES_PREF = "browser.newtabpage.activity-stream.feeds.topsites"; +const SNIPPETS_PREF = "browser.newtabpage.activity-stream.feeds.snippets"; +const TOPSTORIES_PREF = + "browser.newtabpage.activity-stream.feeds.system.topstories"; + +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({ + // Highlights are preffed off by default. + set: [[HIGHLIGHTS_PREF, true]], + }); + + registerCleanupFunction(async () => { + await SpecialPowers.popPrefEnv(); + [ + HOMEPAGE_PREF, + NEWTAB_PREF, + HIGHLIGHTS_PREF, + HIGHLIGHTS_ROWS_PREF, + SEARCH_PREF, + TOPSITES_PREF, + SNIPPETS_PREF, + ].forEach(prefName => Services.prefs.clearUserPref(prefName)); + }); +}); + +function waitForHomeNavigation() { + let deferred = PromiseUtils.defer(); + let navigation = { + observe(subject) { + if (subject === "browser-open-homepage-start") { + deferred.resolve(); + Services.obs.removeObserver(navigation, "browser-open-homepage-start"); + } + }, + }; + Services.obs.addObserver(navigation, "browser-open-homepage-start"); + + return deferred; +} + +add_task(async function test_CONFIGURE_HOMEPAGE_newtab_home_prefs() { + const action = { + type: "CONFIGURE_HOMEPAGE", + data: { homePage: "default", newtab: "default" }, + }; + await SpecialPowers.pushPrefEnv({ + set: [ + [HOMEPAGE_PREF, "about:blank"], + [NEWTAB_PREF, false], + ], + }); + + Assert.ok(Services.prefs.prefHasUserValue(HOMEPAGE_PREF), "Test setup ok"); + Assert.ok(Services.prefs.prefHasUserValue(NEWTAB_PREF), "Test setup ok"); + + await SMATestUtils.executeAndValidateAction(action); + + Assert.ok( + !Services.prefs.prefHasUserValue(HOMEPAGE_PREF), + "Homepage pref should be back to default" + ); + Assert.ok( + !Services.prefs.prefHasUserValue(NEWTAB_PREF), + "Newtab pref should be back to default" + ); +}); + +add_task(async function test_CONFIGURE_HOMEPAGE_layout_prefs() { + const action = { + type: "CONFIGURE_HOMEPAGE", + data: { + layout: { + search: true, + topsites: false, + highlights: false, + snippets: false, + topstories: false, + }, + }, + }; + await SpecialPowers.pushPrefEnv({ + set: [ + [HIGHLIGHTS_ROWS_PREF, 3], + [SEARCH_PREF, false], + ], + }); + + await SMATestUtils.executeAndValidateAction(action); + + Assert.ok(Services.prefs.getBoolPref(SEARCH_PREF), "Search is turned on"); + Assert.ok( + !Services.prefs.getBoolPref(TOPSITES_PREF), + "Topsites are turned off" + ); + Assert.ok( + Services.prefs.getBoolPref(HIGHLIGHTS_PREF), + "HIGHLIGHTS_PREF are on because they have been customized" + ); + Assert.ok( + !Services.prefs.getBoolPref(TOPSTORIES_PREF), + "Topstories are turned off" + ); + Assert.ok( + !Services.prefs.getBoolPref(SNIPPETS_PREF), + "Snippets are turned off" + ); +}); + +add_task(async function test_CONFIGURE_HOMEPAGE_home_redirect() { + const action = { + type: "CONFIGURE_HOMEPAGE", + data: { homePage: "default", newtab: "default" }, + }; + + let browser = gBrowser.selectedBrowser; + // Wait for any other navigation events from previous tests + await BrowserTestUtils.browserLoaded(browser, false, "about:home"); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:config"); + await BrowserTestUtils.browserLoaded(browser, false, "about:config"); + + await SMATestUtils.executeAndValidateAction(action); + + await waitForHomeNavigation(); + Assert.ok(true, "Redirected to about:home"); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_default_browser.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_default_browser.js new file mode 100644 index 0000000000..2d919456cd --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_default_browser.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_set_default_browser() { + const sandbox = sinon.createSandbox(); + const stub = sandbox.stub(); + + await SMATestUtils.executeAndValidateAction( + { type: "SET_DEFAULT_BROWSER" }, + { + ownerGlobal: { + getShellService: () => ({ + setAsDefault: stub, + }), + }, + } + ); + + Assert.equal(stub.callCount, 1, "setAsDefault was called by the action"); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_disable_doh.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_disable_doh.js new file mode 100644 index 0000000000..aa61214360 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_disable_doh.js @@ -0,0 +1,28 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +const DOH_DOORHANGER_DECISION_PREF = "doh-rollout.doorhanger-decision"; +const NETWORK_TRR_MODE_PREF = "network.trr.mode"; + +add_task(async function test_disable_doh() { + await SpecialPowers.pushPrefEnv({ + set: [ + [DOH_DOORHANGER_DECISION_PREF, "mochitest"], + [NETWORK_TRR_MODE_PREF, 0], + ], + }); + + await SMATestUtils.executeAndValidateAction({ type: "DISABLE_DOH" }); + + Assert.equal( + Services.prefs.getStringPref(DOH_DOORHANGER_DECISION_PREF, ""), + "UIDisabled", + "Pref should be set on disabled" + ); + Assert.equal( + Services.prefs.getIntPref(NETWORK_TRR_MODE_PREF, 0), + 5, + "Pref should be set on disabled" + ); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_docs.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_docs.js new file mode 100644 index 0000000000..d67843db74 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_docs.js @@ -0,0 +1,30 @@ +const TEST_URL = + "https://example.com/browser/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/index.md"; + +function getHeadingsFromDocs(docs) { + const re = /### `(\w+)`/g; + const found = []; + let match = 1; + while (match) { + match = re.exec(docs); + if (match) { + found.push(match[1]); + } + } + return found; +} + +add_task(async function test_sma_docs() { + let request = await fetch(TEST_URL); + let docs = await request.text(); + let headings = getHeadingsFromDocs(docs); + const schemaTypes = (await fetchSMASchema).anyOf.map( + s => s.properties.type.enum[0] + ); + for (let schemaType of schemaTypes) { + Assert.ok( + headings.includes(schemaType), + `${schemaType} not found in SpecialMessageActionSchemas/index.md` + ); + } +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_about_page.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_about_page.js new file mode 100644 index 0000000000..264646bd0e --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_about_page.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 test_OPEN_ABOUT_PAGE() { + const tabPromise = BrowserTestUtils.waitForNewTab( + gBrowser, + "about:logins?foo=bar" + ); + await SMATestUtils.executeAndValidateAction({ + type: "OPEN_ABOUT_PAGE", + data: { args: "logins", entrypoint: "foo=bar", where: "tabshifted" }, + }); + + const tab = await tabPromise; + ok(tab, "should open about page with entrypoint in a new tab by default"); + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function test_OPEN_ABOUT_PAGE_NEW_WINDOW() { + const newWindowPromise = BrowserTestUtils.waitForNewWindow( + gBrowser, + "about:robots?foo=bar" + ); + await SMATestUtils.executeAndValidateAction({ + type: "OPEN_ABOUT_PAGE", + data: { args: "robots", entrypoint: "foo=bar", where: "window" }, + }); + + const win = await newWindowPromise; + ok(win, "should open about page in a new window"); + BrowserTestUtils.closeWindow(win); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_awesome_bar.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_awesome_bar.js new file mode 100644 index 0000000000..62f7d8bb68 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_awesome_bar.js @@ -0,0 +1,9 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_OPEN_AWESOME_BAR() { + await SMATestUtils.executeAndValidateAction({ type: "OPEN_AWESOME_BAR" }); + Assert.ok(gURLBar.focused, "Focus should be on awesome bar"); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_private_browser_window.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_private_browser_window.js new file mode 100644 index 0000000000..b6c933fbcf --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_private_browser_window.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_OPEN_PRIVATE_BROWSER_WINDOW() { + const newWindowPromise = BrowserTestUtils.waitForNewWindow(); + await SMATestUtils.executeAndValidateAction({ + type: "OPEN_PRIVATE_BROWSER_WINDOW", + }); + const win = await newWindowPromise; + ok( + PrivateBrowsingUtils.isWindowPrivate(win), + "should open a private browsing window" + ); + await BrowserTestUtils.closeWindow(win); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_protection_panel.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_protection_panel.js new file mode 100644 index 0000000000..c9522426a2 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_protection_panel.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_OPEN_PROTECTION_PANEL() { + await BrowserTestUtils.withNewTab(EXAMPLE_URL, async browser => { + const popupshown = BrowserTestUtils.waitForEvent( + window, + "popupshown", + true, + e => e.target.id == "protections-popup" + ); + + await SMATestUtils.executeAndValidateAction({ + type: "OPEN_PROTECTION_PANEL", + }); + + let { target: popupEl } = await popupshown; + Assert.equal(popupEl.state, "open", "Protections popup is open."); + }); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_protection_report.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_protection_report.js new file mode 100644 index 0000000000..f9d4fa1252 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_protection_report.js @@ -0,0 +1,29 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_OPEN_PROTECTION_REPORT() { + await BrowserTestUtils.withNewTab("about:blank", async browser => { + let loaded = BrowserTestUtils.browserLoaded( + browser, + false, + "about:protections" + ); + + await SMATestUtils.executeAndValidateAction({ + type: "OPEN_PROTECTION_REPORT", + }); + + await loaded; + + // When the graph is built it means any messaging has finished, + // we can close the tab. + await SpecialPowers.spawn(browser, [], async function() { + await ContentTaskUtils.waitForCondition(() => { + let bars = content.document.querySelectorAll(".graph-bar"); + return bars.length; + }, "The graph has been built"); + }); + }); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_url.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_url.js new file mode 100644 index 0000000000..876193b7ad --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_open_url.js @@ -0,0 +1,33 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_OPEN_URL() { + const action = { + type: "OPEN_URL", + data: { args: EXAMPLE_URL, where: "current" }, + }; + await BrowserTestUtils.withNewTab("about:blank", async browser => { + const loaded = BrowserTestUtils.browserLoaded(browser); + await SMATestUtils.executeAndValidateAction(action); + const url = await loaded; + Assert.equal( + url, + "https://example.com/", + "should open URL in the same tab" + ); + }); +}); + +add_task(async function test_OPEN_URL_new_tab() { + const action = { + type: "OPEN_URL", + data: { args: EXAMPLE_URL, where: "tab" }, + }; + const tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, EXAMPLE_URL); + await SpecialMessageActions.handleAction(action, gBrowser); + const browser = await tabPromise; + ok(browser, "should open URL in a new tab"); + BrowserTestUtils.removeTab(browser); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_pin_current_tab.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_pin_current_tab.js new file mode 100644 index 0000000000..4425325526 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_pin_current_tab.js @@ -0,0 +1,14 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_PIN_CURRENT_TAB() { + await BrowserTestUtils.withNewTab("about:blank", async browser => { + await SMATestUtils.executeAndValidateAction({ type: "PIN_CURRENT_TAB" }); + + ok(gBrowser.selectedTab.pinned, "should pin current tab"); + + gBrowser.unpinTab(gBrowser.selectedTab); + }); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_show_firefox_accounts.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_show_firefox_accounts.js new file mode 100644 index 0000000000..3f99fa77ef --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_show_firefox_accounts.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Note: "identity.fxaccounts.remote.root" is set to https://example.com in browser.ini +add_task(async function test_SHOW_FIREFOX_ACCOUNTS() { + await BrowserTestUtils.withNewTab("about:blank", async browser => { + let loaded = BrowserTestUtils.browserLoaded(browser); + await SMATestUtils.executeAndValidateAction({ + type: "SHOW_FIREFOX_ACCOUNTS", + data: { entrypoint: "snippets" }, + }); + Assert.equal( + await loaded, + "https://example.com/?context=fx_desktop_v3&entrypoint=snippets&action=email&service=sync", + "should load fxa with endpoint=snippets" + ); + + // Open a URL + loaded = BrowserTestUtils.browserLoaded(browser); + await SMATestUtils.executeAndValidateAction({ + type: "SHOW_FIREFOX_ACCOUNTS", + data: { entrypoint: "aboutwelcome" }, + }); + + Assert.equal( + await loaded, + "https://example.com/?context=fx_desktop_v3&entrypoint=aboutwelcome&action=email&service=sync", + "should load fxa with a custom endpoint" + ); + + // Open a URL with extra parameters + loaded = BrowserTestUtils.browserLoaded(browser); + await SMATestUtils.executeAndValidateAction({ + type: "SHOW_FIREFOX_ACCOUNTS", + data: { entrypoint: "test", extraParams: { foo: "bar" } }, + }); + + Assert.equal( + await loaded, + "https://example.com/?context=fx_desktop_v3&entrypoint=test&action=email&service=sync&foo=bar", + "should load fxa with a custom endpoint and extra parameters in url" + ); + }); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_show_migration_wizard.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_show_migration_wizard.js new file mode 100644 index 0000000000..e9123c0b36 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_show_migration_wizard.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { MigrationUtils } = ChromeUtils.import( + "resource:///modules/MigrationUtils.jsm" +); + +add_task(async function test_SHOW_MIGRATION_WIZARD() { + let migratorOpen = TestUtils.waitForCondition(() => { + let win = Services.wm.getMostRecentWindow("Browser:MigrationWizard"); + return win && win.document && win.document.readyState == "complete"; + }, "Migrator window loaded"); + + // We can't call this code directly or our JS execution will get blocked on Windows/Linux where + // the dialog is modal. + executeSoon(() => + SMATestUtils.executeAndValidateAction({ type: "SHOW_MIGRATION_WIZARD" }) + ); + + await migratorOpen; + let migratorWindow = Services.wm.getMostRecentWindow( + "Browser:MigrationWizard" + ); + ok(migratorWindow, "Migrator window opened"); + await BrowserTestUtils.closeWindow(migratorWindow); +}); + +add_task(async function test_SHOW_MIGRATION_WIZARD_WITH_SOURCE() { + let migratorOpen = TestUtils.waitForCondition(() => { + let win = Services.wm.getMostRecentWindow("Browser:MigrationWizard"); + return win && win.document && win.document.readyState == "complete"; + }, "Migrator window loaded"); + + // We can't call this code directly or our JS execution will get blocked on Windows/Linux where + // the dialog is modal. + executeSoon(() => + SMATestUtils.executeAndValidateAction({ + type: "SHOW_MIGRATION_WIZARD", + data: { source: "chrome" }, + }) + ); + + await migratorOpen; + let migratorWindow = Services.wm.getMostRecentWindow( + "Browser:MigrationWizard" + ); + ok(migratorWindow, "Migrator window opened when source param specified"); + await BrowserTestUtils.closeWindow(migratorWindow); +}); diff --git a/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/head.js b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/head.js new file mode 100644 index 0000000000..46a11275f3 --- /dev/null +++ b/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/head.js @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); +const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm"); + +ChromeUtils.defineModuleGetter( + this, + "SpecialMessageActions", + "resource://messaging-system/lib/SpecialMessageActions.jsm" +); + +ChromeUtils.defineModuleGetter( + this, + "Ajv", + "resource://testing-common/ajv-4.1.1.js" +); + +XPCOMUtils.defineLazyGetter(this, "fetchSMASchema", async () => { + const response = await fetch( + "resource://testing-common/SpecialMessageActionSchemas.json" + ); + const schema = await response.json(); + if (!schema) { + throw new Error("Failed to load SpecialMessageActionSchemas"); + } + return schema.definitions.SpecialMessageActionSchemas; +}); + +const EXAMPLE_URL = "https://example.com/"; + +const SMATestUtils = { + /** + * Checks if an action is valid acording to existing schemas + * @param {SpecialMessageAction} action + */ + async validateAction(action) { + const schema = await fetchSMASchema; + const ajv = new Ajv({ async: "co*" }); + const validator = ajv.compile(schema); + if (!validator(action)) { + throw new Error(`Action with type ${action.type} was not valid.`); + } + ok(!validator.errors, `should be a valid action of type ${action.type}`); + }, + + /** + * Executes a Special Message Action after validating it + * @param {SpecialMessageAction} action + * @param {Browser} browser + */ + async executeAndValidateAction(action, browser = gBrowser) { + await SMATestUtils.validateAction(action); + await SpecialMessageActions.handleAction(action, browser); + }, +}; |