forked from mirrors/gecko-dev
Bug 1715158 - Remove tests and ASRouterAdmin capabilities for snippets / ASRouterUISurface. r=pdahiya
Differential Revision: https://phabricator.services.mozilla.com/D193851
This commit is contained in:
parent
e2e35a1b69
commit
898169df2a
33 changed files with 71 additions and 3637 deletions
|
|
@ -1662,10 +1662,6 @@ pref("browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
|
||||||
pref("browser.newtabpage.activity-stream.asrouter.providers.cfr", "{\"id\":\"cfr\",\"enabled\":true,\"type\":\"remote-settings\",\"collection\":\"cfr\",\"updateCycleInMs\":3600000}");
|
pref("browser.newtabpage.activity-stream.asrouter.providers.cfr", "{\"id\":\"cfr\",\"enabled\":true,\"type\":\"remote-settings\",\"collection\":\"cfr\",\"updateCycleInMs\":3600000}");
|
||||||
pref("browser.newtabpage.activity-stream.asrouter.providers.whats-new-panel", "{\"id\":\"whats-new-panel\",\"enabled\":false,\"type\":\"remote-settings\",\"collection\":\"whats-new-panel\",\"updateCycleInMs\":3600000}");
|
pref("browser.newtabpage.activity-stream.asrouter.providers.whats-new-panel", "{\"id\":\"whats-new-panel\",\"enabled\":false,\"type\":\"remote-settings\",\"collection\":\"whats-new-panel\",\"updateCycleInMs\":3600000}");
|
||||||
pref("browser.newtabpage.activity-stream.asrouter.providers.message-groups", "{\"id\":\"message-groups\",\"enabled\":true,\"type\":\"remote-settings\",\"collection\":\"message-groups\",\"updateCycleInMs\":3600000}");
|
pref("browser.newtabpage.activity-stream.asrouter.providers.message-groups", "{\"id\":\"message-groups\",\"enabled\":true,\"type\":\"remote-settings\",\"collection\":\"message-groups\",\"updateCycleInMs\":3600000}");
|
||||||
// This url, if changed, MUST continue to point to an https url. Pulling arbitrary content to inject into
|
|
||||||
// this page over http opens us up to a man-in-the-middle attack that we'd rather not face. If you are a downstream
|
|
||||||
// repackager of this code using an alternate snippet url, please keep your users safe
|
|
||||||
pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", "{\"id\":\"snippets\",\"enabled\":false,\"type\":\"remote\",\"url\":\"https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/\",\"updateCycleInMs\":14400000}");
|
|
||||||
pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"updateCycleInMs\":3600000}");
|
pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"updateCycleInMs\":3600000}");
|
||||||
|
|
||||||
// ASRouter user prefs
|
// ASRouter user prefs
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
||||||
PanelTestProvider: "resource://activity-stream/lib/PanelTestProvider.sys.mjs",
|
PanelTestProvider: "resource://activity-stream/lib/PanelTestProvider.sys.mjs",
|
||||||
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.sys.mjs",
|
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.sys.mjs",
|
||||||
SnippetsTestMessageProvider:
|
|
||||||
"resource://activity-stream/lib/SnippetsTestMessageProvider.sys.mjs",
|
|
||||||
SpecialMessageActions:
|
SpecialMessageActions:
|
||||||
"resource://messaging-system/lib/SpecialMessageActions.sys.mjs",
|
"resource://messaging-system/lib/SpecialMessageActions.sys.mjs",
|
||||||
TargetingContext: "resource://messaging-system/targeting/Targeting.sys.mjs",
|
TargetingContext: "resource://messaging-system/targeting/Targeting.sys.mjs",
|
||||||
|
|
@ -1131,7 +1129,6 @@ class _ASRouter {
|
||||||
if (lazy.ASRouterPreferences.devtoolsEnabled) {
|
if (lazy.ASRouterPreferences.devtoolsEnabled) {
|
||||||
this._localProviders = {
|
this._localProviders = {
|
||||||
...this._localProviders,
|
...this._localProviders,
|
||||||
SnippetsTestMessageProvider: lazy.SnippetsTestMessageProvider,
|
|
||||||
PanelTestProvider: lazy.PanelTestProvider,
|
PanelTestProvider: lazy.PanelTestProvider,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ const DEFAULT_STATE = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const USER_PREFERENCES = {
|
const USER_PREFERENCES = {
|
||||||
snippets: "browser.newtabpage.activity-stream.feeds.snippets",
|
|
||||||
cfrAddons: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
|
cfrAddons: "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
|
||||||
cfrFeatures:
|
cfrFeatures:
|
||||||
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
|
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
|
||||||
|
|
@ -41,12 +40,6 @@ const USER_PREFERENCES = {
|
||||||
const TARGETING_PREFERENCES = [FXA_USERNAME_PREF];
|
const TARGETING_PREFERENCES = [FXA_USERNAME_PREF];
|
||||||
|
|
||||||
const TEST_PROVIDERS = [
|
const TEST_PROVIDERS = [
|
||||||
{
|
|
||||||
id: "snippets_local_testing",
|
|
||||||
type: "local",
|
|
||||||
localProvider: "SnippetsTestMessageProvider",
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "panel_local_testing",
|
id: "panel_local_testing",
|
||||||
type: "local",
|
type: "local",
|
||||||
|
|
|
||||||
|
|
@ -1,688 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
const TEST_ICON = "chrome://branding/content/icon64.png";
|
|
||||||
const TEST_ICON_16 = "chrome://branding/content/icon16.png";
|
|
||||||
const TEST_ICON_BW =
|
|
||||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfjBQ8QDifrKGc/AAABf0lEQVQoz4WRO08UUQCFvztzd1AgG9jRgGwkhEoMIYGSygYt+A00tpZGY0jYxAJKEwkNjX9AK2xACx4dhFiQQCiMMRr2kYXdnQcz7L0z91qAMVac6hTfSU7OgVsk/prtyfSNfRb7ge2cd7dmVucP/wM2lwqVqoyICahRx9Nz71+8AnAAvlTct+dSYDBYcgJ+Fj68XFu/AfamnIoWFoHFYrAUuYMSn55/fAIOxIs1t4MhQpNxRYsUD0ld7r8DCfZph4QecrqkhCREgMLSeISQkAy0UBgE0CYgIkeRA9HdsCQhpEGCxichpItHigEcPH4XJLRbTf8STY0iiiuu60Ifxexx04F0N+aCgJCAhPQmD/cp/RC5A79WvUyhUHSIidAIoESv9VfAhW9n8+XqTCoyMsz1cviMMrGz9BrjAuboYHZajyXCInEocI8yvccbC+0muABanR4/tONjQz3DzgNKtj9sfv66XD9B/3tT9g/akb7h0bJwzxqqmlRHLr4rLPwBlYWoYj77l2AAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDUtMTVUMTY6MTQ6MzkrMDA6MDD5/4XBAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTA1LTE1VDE2OjE0OjM5KzAwOjAwiKI9fQAAAABJRU5ErkJggg==";
|
|
||||||
|
|
||||||
const MESSAGES = () => [
|
|
||||||
{
|
|
||||||
template: "simple_snippet",
|
|
||||||
template_version: "1.1.2",
|
|
||||||
content: {
|
|
||||||
text: "This is for <link0>preferences</link0> and <link1>about</link1>",
|
|
||||||
icon: "https://snippets.cdn.mozilla.net/media/icons/1a8bb10e-8166-4e14-9e41-c1f85a41bcd2.png",
|
|
||||||
button_label: "Button Label",
|
|
||||||
section_title_icon:
|
|
||||||
"https://snippets.cdn.mozilla.net/media/icons/5878847e-a1fb-4204-aad9-09f6cf7f99ee.png",
|
|
||||||
section_title_text: "Messages from Firefox",
|
|
||||||
section_title_url:
|
|
||||||
"https://support.mozilla.org/kb/snippets-firefox-faq?utm_source=desktop-snippet&utm_medium=snippet&utm_campaign=&utm_term=&utm_content=",
|
|
||||||
tall: false,
|
|
||||||
block_button_text: "Remove this",
|
|
||||||
do_not_autoblock: true,
|
|
||||||
links: {
|
|
||||||
link0: {
|
|
||||||
action: "OPEN_PREFERENCES_PAGE",
|
|
||||||
entrypoint_value: "snippet",
|
|
||||||
args: "sync",
|
|
||||||
},
|
|
||||||
link1: {
|
|
||||||
action: "OPEN_ABOUT_PAGE",
|
|
||||||
args: "about",
|
|
||||||
entrypoint_name: "entryPoint",
|
|
||||||
entrypoint_value: "snippet",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
button_action: "OPEN_PREFERENCES_PAGE",
|
|
||||||
button_entrypoint_value: "snippet",
|
|
||||||
},
|
|
||||||
id: "preview-13516_button_preferences",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
template: "simple_snippet",
|
|
||||||
template_version: "1.1.2",
|
|
||||||
content: {
|
|
||||||
text: "This is for <link0>preferences</link0> and <link1>about</link1>",
|
|
||||||
icon: "https://snippets.cdn.mozilla.net/media/icons/1a8bb10e-8166-4e14-9e41-c1f85a41bcd2.png",
|
|
||||||
button_label: "Button Label",
|
|
||||||
section_title_icon:
|
|
||||||
"https://snippets.cdn.mozilla.net/media/icons/5878847e-a1fb-4204-aad9-09f6cf7f99ee.png",
|
|
||||||
section_title_text: "Messages from Firefox",
|
|
||||||
section_title_url:
|
|
||||||
"https://support.mozilla.org/kb/snippets-firefox-faq?utm_source=desktop-snippet&utm_medium=snippet&utm_campaign=&utm_term=&utm_content=",
|
|
||||||
tall: false,
|
|
||||||
block_button_text: "Remove this",
|
|
||||||
do_not_autoblock: true,
|
|
||||||
links: {
|
|
||||||
link0: {
|
|
||||||
action: "OPEN_PREFERENCES_PAGE",
|
|
||||||
entrypoint_value: "snippet",
|
|
||||||
},
|
|
||||||
link1: {
|
|
||||||
action: "OPEN_ABOUT_PAGE",
|
|
||||||
args: "about",
|
|
||||||
entrypoint_name: "entryPoint",
|
|
||||||
entrypoint_value: "snippet",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
button_action: "OPEN_ABOUT_PAGE",
|
|
||||||
button_action_args: "logins",
|
|
||||||
button_entrypoint_name: "entryPoint",
|
|
||||||
button_entrypoint_value: "snippet",
|
|
||||||
},
|
|
||||||
id: "preview-13517_button_about",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_1",
|
|
||||||
template: "simple_snippet",
|
|
||||||
campaign: "test_campaign_blocking",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
title: "Firefox Account!",
|
|
||||||
title_icon: TEST_ICON_16,
|
|
||||||
title_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
text: "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_1_NO_DARK_THEME",
|
|
||||||
template: "simple_snippet",
|
|
||||||
campaign: "test_campaign_blocking",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: "",
|
|
||||||
title: "Firefox Account!",
|
|
||||||
title_icon: TEST_ICON_16,
|
|
||||||
title_icon_dark_theme: "",
|
|
||||||
text: "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_1_SAME_CAMPAIGN",
|
|
||||||
template: "simple_snippet",
|
|
||||||
campaign: "test_campaign_blocking",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
text: "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_TALL",
|
|
||||||
template: "simple_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
text: "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
button_label: "Get one now!",
|
|
||||||
button_url: "https://www.mozilla.org/en-US/firefox/accounts",
|
|
||||||
block_button_text: "Block",
|
|
||||||
tall: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_BUTTON_URL_1",
|
|
||||||
template: "simple_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
button_label: "Get one now!",
|
|
||||||
button_url: "https://www.mozilla.org/en-US/firefox/accounts",
|
|
||||||
text: "Sync it, link it, take it with you. All this and more with a Firefox Account.",
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_BUTTON_ACTION_1",
|
|
||||||
template: "simple_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
button_label: "Open about:config",
|
|
||||||
button_action: "OPEN_ABOUT_PAGE",
|
|
||||||
button_action_args: "config",
|
|
||||||
text: "Testing the OPEN_ABOUT_PAGE action",
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_WITH_TITLE_TEST_1",
|
|
||||||
template: "simple_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
title: "Ready to sync?",
|
|
||||||
text: "Get connected with a <syncLink>Firefox account</syncLink>.",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "NEWSLETTER_TEST_DEFAULTS",
|
|
||||||
template: "newsletter_snippet",
|
|
||||||
content: {
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_title: "Be a part of a movement.",
|
|
||||||
scene1_title_icon: TEST_ICON_16,
|
|
||||||
scene1_title_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_text:
|
|
||||||
"Internet shutdowns, hackers, harassment – the health of the internet is on the line. Sign up and Mozilla will keep you updated on how you can help.",
|
|
||||||
scene1_button_label: "Continue",
|
|
||||||
scene1_button_color: "#712b00",
|
|
||||||
scene1_button_background_color: "#ff9400",
|
|
||||||
scene2_title: "Let's do this!",
|
|
||||||
locale: "en-CA",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
scene2_text:
|
|
||||||
"Sign up for the Mozilla newsletter and we will keep you updated on how you can help.",
|
|
||||||
scene2_privacy_html:
|
|
||||||
"I'm okay with Mozilla handling my info as explained in this <privacyLink>Privacy Notice</privacyLink>.",
|
|
||||||
scene2_newsletter: "mozilla-foundation",
|
|
||||||
success_text: "Check your inbox for the confirmation!",
|
|
||||||
error_text: "Error!",
|
|
||||||
retry_button_label: "Try again?",
|
|
||||||
links: {
|
|
||||||
privacyLink: {
|
|
||||||
url: "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "NEWSLETTER_TEST_1",
|
|
||||||
template: "newsletter_snippet",
|
|
||||||
content: {
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_title: "Be a part of a movement.",
|
|
||||||
scene1_title_icon: "",
|
|
||||||
scene1_text:
|
|
||||||
"Internet shutdowns, hackers, harassment – the health of the internet is on the line. Sign up and Mozilla will keep you updated on how you can help.",
|
|
||||||
scene1_button_label: "Continue",
|
|
||||||
scene1_button_color: "#712b00",
|
|
||||||
scene1_button_background_color: "#ff9400",
|
|
||||||
scene2_title: "Let's do this!",
|
|
||||||
locale: "en-CA",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
scene2_text:
|
|
||||||
"Sign up for the Mozilla newsletter and we will keep you updated on how you can help.",
|
|
||||||
scene2_privacy_html:
|
|
||||||
"I'm okay with Mozilla handling my info as explained in this <privacyLink>Privacy Notice</privacyLink>.",
|
|
||||||
scene2_button_label: "Sign Me up",
|
|
||||||
scene2_email_placeholder_text: "Your email here",
|
|
||||||
scene2_newsletter: "mozilla-foundation",
|
|
||||||
success_text: "Check your inbox for the confirmation!",
|
|
||||||
error_text: "Error!",
|
|
||||||
links: {
|
|
||||||
privacyLink: {
|
|
||||||
url: "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "NEWSLETTER_TEST_SCENE1_SECTION_TITLE_ICON",
|
|
||||||
template: "newsletter_snippet",
|
|
||||||
content: {
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_title: "Be a part of a movement.",
|
|
||||||
scene1_title_icon: "",
|
|
||||||
scene1_text:
|
|
||||||
"Internet shutdowns, hackers, harassment – the health of the internet is on the line. Sign up and Mozilla will keep you updated on how you can help.",
|
|
||||||
scene1_button_label: "Continue",
|
|
||||||
scene1_button_color: "#712b00",
|
|
||||||
scene1_button_background_color: "#ff9400",
|
|
||||||
scene1_section_title_icon: "chrome://global/skin/icons/pocket.svg",
|
|
||||||
scene1_section_title_text:
|
|
||||||
"All the Firefox news that's fit to Firefox print!",
|
|
||||||
scene2_title: "Let's do this!",
|
|
||||||
locale: "en-CA",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
scene2_text:
|
|
||||||
"Sign up for the Mozilla newsletter and we will keep you updated on how you can help.",
|
|
||||||
scene2_privacy_html:
|
|
||||||
"I'm okay with Mozilla handling my info as explained in this <privacyLink>Privacy Notice</privacyLink>.",
|
|
||||||
scene2_button_label: "Sign Me up",
|
|
||||||
scene2_email_placeholder_text: "Your email here",
|
|
||||||
scene2_newsletter: "mozilla-foundation",
|
|
||||||
success_text: "Check your inbox for the confirmation!",
|
|
||||||
error_text: "Error!",
|
|
||||||
links: {
|
|
||||||
privacyLink: {
|
|
||||||
url: "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "FXA_SNIPPET_TEST_1",
|
|
||||||
template: "fxa_signup_snippet",
|
|
||||||
content: {
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_button_label: "Get connected with sync!",
|
|
||||||
scene1_button_color: "#712b00",
|
|
||||||
scene1_button_background_color: "#ff9400",
|
|
||||||
|
|
||||||
scene1_text:
|
|
||||||
"Connect to Firefox by securely syncing passwords, bookmarks, and open tabs.",
|
|
||||||
scene1_title: "Browser better.",
|
|
||||||
scene1_title_icon: TEST_ICON_16,
|
|
||||||
scene1_title_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
|
|
||||||
scene2_text:
|
|
||||||
"Connect to your Firefox account to securely sync passwords, bookmarks, and open tabs.",
|
|
||||||
scene2_title: "Title 123",
|
|
||||||
scene2_email_placeholder_text: "Your email",
|
|
||||||
scene2_button_label: "Continue",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "FXA_SNIPPET_TEST_TITLE_ICON",
|
|
||||||
template: "fxa_signup_snippet",
|
|
||||||
content: {
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_button_label: "Get connected with sync!",
|
|
||||||
scene1_button_color: "#712b00",
|
|
||||||
scene1_button_background_color: "#ff9400",
|
|
||||||
|
|
||||||
scene1_text:
|
|
||||||
"Connect to Firefox by securely syncing passwords, bookmarks, and open tabs.",
|
|
||||||
scene1_title: "Browser better.",
|
|
||||||
scene1_title_icon: TEST_ICON_16,
|
|
||||||
scene1_title_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
|
|
||||||
scene1_section_title_icon: "chrome://global/skin/icons/pocket.svg",
|
|
||||||
scene1_section_title_text: "Firefox Accounts: Receivable benefits",
|
|
||||||
|
|
||||||
scene2_text:
|
|
||||||
"Connect to your Firefox account to securely sync passwords, bookmarks, and open tabs.",
|
|
||||||
scene2_title: "Title 123",
|
|
||||||
scene2_email_placeholder_text: "Your email",
|
|
||||||
scene2_button_label: "Continue",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SNIPPETS_SEND_TO_DEVICE_TEST",
|
|
||||||
template: "send_to_device_snippet",
|
|
||||||
content: {
|
|
||||||
include_sms: true,
|
|
||||||
locale: "en-CA",
|
|
||||||
country: "us",
|
|
||||||
message_id_sms: "ff-mobilesn-download",
|
|
||||||
message_id_email: "download-firefox-mobile",
|
|
||||||
|
|
||||||
scene1_button_background_color: "#6200a4",
|
|
||||||
scene1_button_color: "#FFFFFF",
|
|
||||||
scene1_button_label: "Install now",
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_text: "Browse without compromise with Firefox Mobile.",
|
|
||||||
scene1_title: "Full-featured. Customizable. Lightning fast",
|
|
||||||
scene1_title_icon: TEST_ICON_16,
|
|
||||||
scene1_title_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
|
|
||||||
scene2_button_label: "Send",
|
|
||||||
scene2_disclaimer_html:
|
|
||||||
"The intended recipient of the email must have consented. <privacyLink>Learn more</privacyLink>.",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
scene2_icon: TEST_ICON,
|
|
||||||
scene2_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene2_input_placeholder: "Your email address or phone number",
|
|
||||||
scene2_text:
|
|
||||||
"Send Firefox to your phone and take a powerful independent browser with you.",
|
|
||||||
scene2_title: "Let's do this!",
|
|
||||||
|
|
||||||
error_text: "Oops, there was a problem.",
|
|
||||||
success_title: "Your download link was sent.",
|
|
||||||
success_text: "Check your device for the email message!",
|
|
||||||
links: {
|
|
||||||
privacyLink: {
|
|
||||||
url: "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SNIPPETS_SCENE2_SEND_TO_DEVICE_TEST",
|
|
||||||
template: "send_to_device_scene2_snippet",
|
|
||||||
content: {
|
|
||||||
include_sms: true,
|
|
||||||
locale: "en-CA",
|
|
||||||
country: "us",
|
|
||||||
message_id_sms: "ff-mobilesn-download",
|
|
||||||
message_id_email: "download-firefox-mobile",
|
|
||||||
scene2_icon: TEST_ICON,
|
|
||||||
section_title_icon:
|
|
||||||
"https://snippets.cdn.mozilla.net/media/icons/094b0707-ab65-4b2e-99a1-a84122b6ab26.png",
|
|
||||||
section_title_text: "Messages from Firefox",
|
|
||||||
section_title_url: "https://support.mozilla.org/kb",
|
|
||||||
scene2_button_label: "Send",
|
|
||||||
scene2_disclaimer_html:
|
|
||||||
"The intended recipient of the email must have consented. <privacyLink>Learn more</privacyLink>.",
|
|
||||||
scene2_input_placeholder: "Your email address or phone number",
|
|
||||||
scene2_text:
|
|
||||||
"Send Firefox to your phone and take a powerful independent browser with you.",
|
|
||||||
error_text: "Oops, there was a problem.",
|
|
||||||
success_title: "Your download link was sent.",
|
|
||||||
success_text: "Check your device for the email message!",
|
|
||||||
links: {
|
|
||||||
privacyLink: {
|
|
||||||
url: "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SNIPPETS_SEND_TO_DEVICE_TEST_NO_DARK_THEME",
|
|
||||||
template: "send_to_device_snippet",
|
|
||||||
content: {
|
|
||||||
include_sms: true,
|
|
||||||
locale: "en-CA",
|
|
||||||
country: "us",
|
|
||||||
message_id_sms: "ff-mobilesn-download",
|
|
||||||
message_id_email: "download-firefox-mobile",
|
|
||||||
|
|
||||||
scene1_button_background_color: "#6200a4",
|
|
||||||
scene1_button_color: "#FFFFFF",
|
|
||||||
scene1_button_label: "Install now",
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: "",
|
|
||||||
scene1_text: "Browse without compromise with Firefox Mobile.",
|
|
||||||
scene1_title: "Full-featured. Customizable. Lightning fast",
|
|
||||||
scene1_title_icon: TEST_ICON_16,
|
|
||||||
scene1_title_icon_dark_theme: "",
|
|
||||||
|
|
||||||
scene2_button_label: "Send",
|
|
||||||
scene2_disclaimer_html:
|
|
||||||
"The intended recipient of the email must have consented. <privacyLink>Learn more</privacyLink>.",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
scene2_icon: TEST_ICON,
|
|
||||||
scene2_icon_dark_theme: "",
|
|
||||||
scene2_input_placeholder: "Your email address or phone number",
|
|
||||||
scene2_text:
|
|
||||||
"Send Firefox to your phone and take a powerful independent browser with you.",
|
|
||||||
scene2_title: "Let's do this!",
|
|
||||||
|
|
||||||
error_text: "Oops, there was a problem.",
|
|
||||||
success_title: "Your download link was sent.",
|
|
||||||
success_text: "Check your device for the email message!",
|
|
||||||
links: {
|
|
||||||
privacyLink: {
|
|
||||||
url: "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SNIPPETS_SEND_TO_DEVICE_TEST_SECTION_TITLE_ICON",
|
|
||||||
template: "send_to_device_snippet",
|
|
||||||
content: {
|
|
||||||
include_sms: true,
|
|
||||||
locale: "en-CA",
|
|
||||||
country: "us",
|
|
||||||
message_id_sms: "ff-mobilesn-download",
|
|
||||||
message_id_email: "download-firefox-mobile",
|
|
||||||
|
|
||||||
scene1_button_background_color: "#6200a4",
|
|
||||||
scene1_button_color: "#FFFFFF",
|
|
||||||
scene1_button_label: "Install now",
|
|
||||||
scene1_icon: TEST_ICON,
|
|
||||||
scene1_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_text: "Browse without compromise with Firefox Mobile.",
|
|
||||||
scene1_title: "Full-featured. Customizable. Lightning fast",
|
|
||||||
scene1_title_icon: TEST_ICON_16,
|
|
||||||
scene1_title_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene1_section_title_icon: "chrome://global/skin/icons/pocket.svg",
|
|
||||||
scene1_section_title_text: "Send Firefox to your mobile device!",
|
|
||||||
|
|
||||||
scene2_button_label: "Send",
|
|
||||||
scene2_disclaimer_html:
|
|
||||||
"The intended recipient of the email must have consented. <privacyLink>Learn more</privacyLink>.",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
scene2_icon: TEST_ICON,
|
|
||||||
scene2_icon_dark_theme: TEST_ICON_BW,
|
|
||||||
scene2_input_placeholder: "Your email address or phone number",
|
|
||||||
scene2_text:
|
|
||||||
"Send Firefox to your phone and take a powerful independent browser with you.",
|
|
||||||
scene2_title: "Let's do this!",
|
|
||||||
|
|
||||||
error_text: "Oops, there was a problem.",
|
|
||||||
success_title: "Your download link was sent.",
|
|
||||||
success_text: "Check your device for the email message!",
|
|
||||||
links: {
|
|
||||||
privacyLink: {
|
|
||||||
url: "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "EOY_TEST_1",
|
|
||||||
template: "eoy_snippet",
|
|
||||||
content: {
|
|
||||||
highlight_color: "#f05",
|
|
||||||
background_color: "#ddd",
|
|
||||||
text_color: "yellow",
|
|
||||||
selected_button: "donation_amount_first",
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
button_label: "Donate",
|
|
||||||
monthly_checkbox_label_text: "Make my donation monthly",
|
|
||||||
currency_code: "usd",
|
|
||||||
donation_amount_first: 50,
|
|
||||||
donation_amount_second: 25,
|
|
||||||
donation_amount_third: 10,
|
|
||||||
donation_amount_fourth: 5,
|
|
||||||
donation_form_url:
|
|
||||||
"https://donate.mozilla.org/pl/?utm_source=desktop-snippet&utm_medium=snippet&utm_campaign=donate&utm_term=7556",
|
|
||||||
text: "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The <em>not-for-profit Mozilla Foundation</em> fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; <b>will you donate today</b>?",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "EOY_BOLD_TEST_1",
|
|
||||||
template: "eoy_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
selected_button: "donation_amount_second",
|
|
||||||
button_label: "Donate",
|
|
||||||
monthly_checkbox_label_text: "Make my donation monthly",
|
|
||||||
currency_code: "usd",
|
|
||||||
donation_amount_first: 50,
|
|
||||||
donation_amount_second: 25,
|
|
||||||
donation_amount_third: 10,
|
|
||||||
donation_amount_fourth: 5,
|
|
||||||
donation_form_url: "https://donate.mozilla.org",
|
|
||||||
text: "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The <em>not-for-profit Mozilla Foundation</em> fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; <b>will you donate today</b>?",
|
|
||||||
test: "bold",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "EOY_TAKEOVER_TEST_1",
|
|
||||||
template: "eoy_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
button_label: "Donate",
|
|
||||||
monthly_checkbox_label_text: "Make my donation monthly",
|
|
||||||
currency_code: "usd",
|
|
||||||
donation_amount_first: 50,
|
|
||||||
donation_amount_second: 25,
|
|
||||||
donation_amount_third: 10,
|
|
||||||
donation_amount_fourth: 5,
|
|
||||||
donation_form_url: "https://donate.mozilla.org",
|
|
||||||
text: "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The <em>not-for-profit Mozilla Foundation</em> fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; <b>will you donate today</b>?",
|
|
||||||
test: "takeover",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_WITH_SECTION_HEADING",
|
|
||||||
template: "simple_snippet",
|
|
||||||
content: {
|
|
||||||
button_label: "Get one now!",
|
|
||||||
button_url: "https://www.mozilla.org/en-US/firefox/accounts",
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
title: "Firefox Account!",
|
|
||||||
text: "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
section_title_icon: "chrome://global/skin/icons/pocket.svg",
|
|
||||||
section_title_text: "Messages from Mozilla",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_TEST_WITH_SECTION_HEADING_AND_LINK",
|
|
||||||
template: "simple_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
title: "Firefox Account!",
|
|
||||||
text: "Sync it, link it, take it with you. All this and more with a Firefox Account.",
|
|
||||||
block_button_text: "Block",
|
|
||||||
section_title_icon: "chrome://global/skin/icons/pocket.svg",
|
|
||||||
section_title_text: "Messages from Mozilla (click for info)",
|
|
||||||
section_title_url: "https://www.mozilla.org/about",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_BELOW_SEARCH_TEST_1",
|
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
text: "Securely store passwords, bookmarks, and more with a Firefox Account. <syncLink>Sign up</syncLink>",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_BELOW_SEARCH_TEST_2",
|
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
text: "<syncLink>Connect your Firefox Account to Sync</syncLink> your protected passwords, open tabs and bookmarks, and they'll always be available to you - on all of your devices.",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SIMPLE_BELOW_SEARCH_TEST_TITLE",
|
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
title: "See if you've been part of an online data breach.",
|
|
||||||
text: "Securely store passwords, bookmarks, and more with a Firefox Account. <syncLink>Sign up</syncLink>",
|
|
||||||
links: {
|
|
||||||
syncLink: { url: "https://www.mozilla.org/en-US/firefox/accounts" },
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SPECIAL_SNIPPET_BUTTON_1",
|
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
button_label: "Find Out Now",
|
|
||||||
button_url: "https://www.mozilla.org/en-US/firefox/accounts",
|
|
||||||
title: "See if you've been part of an online data breach.",
|
|
||||||
text: "Firefox Monitor tells you what hackers already know about you.",
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SPECIAL_SNIPPET_LONG_CONTENT",
|
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
button_label: "Find Out Now",
|
|
||||||
button_url: "https://www.mozilla.org/en-US/firefox/accounts",
|
|
||||||
title: "See if you've been part of an online data breach.",
|
|
||||||
text: "Firefox Monitor tells you what hackers already know about you. Here's some extra text to make the content really long.",
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SPECIAL_SNIPPET_NO_TITLE",
|
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
icon_dark_theme: TEST_ICON_BW,
|
|
||||||
button_label: "Find Out Now",
|
|
||||||
button_url: "https://www.mozilla.org/en-US/firefox/accounts",
|
|
||||||
text: "Firefox Monitor tells you what hackers already know about you.",
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "SPECIAL_SNIPPET_MONITOR",
|
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: {
|
|
||||||
icon: TEST_ICON,
|
|
||||||
title: "See if you've been part of an online data breach.",
|
|
||||||
text: "Firefox Monitor tells you what hackers already know about you.",
|
|
||||||
button_label: "Get monitor",
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
block_button_text: "Block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const SnippetsTestMessageProvider = {
|
|
||||||
getMessages() {
|
|
||||||
return Promise.resolve(
|
|
||||||
MESSAGES()
|
|
||||||
// Ensures we never actually show test except when triggered by debug tools
|
|
||||||
.map(message => ({
|
|
||||||
...message,
|
|
||||||
targeting: `providerCohorts.snippets_local_testing == "SHOW_TEST"`,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -7,9 +7,6 @@ support-files = [
|
||||||
"annotation_third.html",
|
"annotation_third.html",
|
||||||
"head.js",
|
"head.js",
|
||||||
"redirect_to.sjs",
|
"redirect_to.sjs",
|
||||||
"snippet.json",
|
|
||||||
"snippet_below_search_test.json",
|
|
||||||
"snippet_simple_test.json",
|
|
||||||
"topstories.json",
|
"topstories.json",
|
||||||
"file_pdf.PDF",
|
"file_pdf.PDF",
|
||||||
]
|
]
|
||||||
|
|
@ -48,12 +45,6 @@ skip-if = ["os == 'linux' && bits == 64 && !debug"] # Bug 1643036
|
||||||
["browser_asrouter_momentspagehub.js"]
|
["browser_asrouter_momentspagehub.js"]
|
||||||
tags = "remote-settings"
|
tags = "remote-settings"
|
||||||
|
|
||||||
["browser_asrouter_snippets.js"]
|
|
||||||
https_first_disabled = true
|
|
||||||
|
|
||||||
["browser_asrouter_snippets_dismiss.js"]
|
|
||||||
support-files = ["../../../../base/content/aboutRobots-icon.png"]
|
|
||||||
|
|
||||||
["browser_asrouter_targeting.js"]
|
["browser_asrouter_targeting.js"]
|
||||||
|
|
||||||
["browser_asrouter_toast_notification.js"]
|
["browser_asrouter_toast_notification.js"]
|
||||||
|
|
|
||||||
|
|
@ -742,7 +742,6 @@ add_task(async function test_providerNames() {
|
||||||
for (const prefName of cfrProviderPrefs) {
|
for (const prefName of cfrProviderPrefs) {
|
||||||
const prefValue = JSON.parse(Services.prefs.getStringPref(prefName));
|
const prefValue = JSON.parse(Services.prefs.getStringPref(prefName));
|
||||||
if (prefValue && prefValue.id) {
|
if (prefValue && prefValue.id) {
|
||||||
// Snippets are disabled in tests and value is set to []
|
|
||||||
Assert.equal(
|
Assert.equal(
|
||||||
prefValue.id,
|
prefValue.id,
|
||||||
prefName.slice(providersBranch.length),
|
prefName.slice(providersBranch.length),
|
||||||
|
|
|
||||||
|
|
@ -1,196 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// Ask for more time for Verify.
|
|
||||||
requestLongerTimeout(5);
|
|
||||||
|
|
||||||
const { ASRouter } = ChromeUtils.import(
|
|
||||||
"resource://activity-stream/lib/ASRouter.jsm"
|
|
||||||
);
|
|
||||||
|
|
||||||
const { TelemetryFeed } = ChromeUtils.import(
|
|
||||||
"resource://activity-stream/lib/TelemetryFeed.jsm"
|
|
||||||
);
|
|
||||||
|
|
||||||
add_task(async function render_below_search_snippet() {
|
|
||||||
ASRouter._validPreviewEndpoint = () => true;
|
|
||||||
await BrowserTestUtils.withNewTab(
|
|
||||||
{
|
|
||||||
gBrowser,
|
|
||||||
url: "about:newtab?endpoint=https://example.com/browser/browser/components/newtab/test/browser/snippet_below_search_test.json",
|
|
||||||
},
|
|
||||||
async browser => {
|
|
||||||
await waitForPreloaded(browser);
|
|
||||||
|
|
||||||
const complete = await SpecialPowers.spawn(browser, [], async () => {
|
|
||||||
// Verify the simple_below_search_snippet renders in container below searchbox
|
|
||||||
// and nothing is rendered in the footer.
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
content.document.querySelector(
|
|
||||||
".below-search-snippet .SimpleBelowSearchSnippet"
|
|
||||||
),
|
|
||||||
"Should find the snippet inside the below search container"
|
|
||||||
);
|
|
||||||
|
|
||||||
is(
|
|
||||||
0,
|
|
||||||
content.document.querySelector("#footer-asrouter-container")
|
|
||||||
.childNodes.length,
|
|
||||||
"Should not find any snippets in the footer container"
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.ok(complete, "Test complete.");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function render_snippets_icon_and_link() {
|
|
||||||
await BrowserTestUtils.withNewTab(
|
|
||||||
{
|
|
||||||
gBrowser,
|
|
||||||
url: "about:newtab?endpoint=https://example.com/browser/browser/components/newtab/test/browser/snippet_simple_test.json",
|
|
||||||
},
|
|
||||||
async browser => {
|
|
||||||
await waitForPreloaded(browser);
|
|
||||||
|
|
||||||
const complete = await SpecialPowers.spawn(browser, [], async () => {
|
|
||||||
const syncLink = "https://www.mozilla.org/en-US/firefox/accounts";
|
|
||||||
// Verify the simple_snippet renders in the footer and the container below
|
|
||||||
// searchbox is not rendered.
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
),
|
|
||||||
"Should find the snippet inside the footer container"
|
|
||||||
);
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet .icon"
|
|
||||||
),
|
|
||||||
"Should render an icon"
|
|
||||||
);
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
content.document.querySelector(
|
|
||||||
`#footer-asrouter-container .SimpleSnippet a[href='${syncLink}']`
|
|
||||||
),
|
|
||||||
"Should render an anchor with the correct href"
|
|
||||||
);
|
|
||||||
|
|
||||||
ok(
|
|
||||||
!content.document.querySelector(".below-search-snippet"),
|
|
||||||
"Should not find any snippets below search"
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.ok(complete, "Test complete.");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function render_preview_snippet() {
|
|
||||||
ASRouter._validPreviewEndpoint = () => true;
|
|
||||||
await BrowserTestUtils.withNewTab(
|
|
||||||
{
|
|
||||||
gBrowser,
|
|
||||||
url: "about:newtab?endpoint=https://example.com/browser/browser/components/newtab/test/browser/snippet.json",
|
|
||||||
},
|
|
||||||
async browser => {
|
|
||||||
let text = await SpecialPowers.spawn(browser, [], async () => {
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() => content.document.querySelector(".activity-stream"),
|
|
||||||
`Should render Activity Stream`
|
|
||||||
);
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
),
|
|
||||||
"Should find the snippet inside the footer container"
|
|
||||||
);
|
|
||||||
|
|
||||||
return content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
).innerText;
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
text,
|
|
||||||
"On January 30th Nightly will introduce dedicated profiles, making it simpler to run different installations of Firefox side by side. Learn what this means for you.",
|
|
||||||
"Snippet content match"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_snippets_telemetry() {
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
|
||||||
set: [
|
|
||||||
[
|
|
||||||
"browser.newtabpage.activity-stream.asrouter.providers.snippets",
|
|
||||||
`{"id":"snippets","enabled":true,"type":"remote","url":"https://example.com/browser/browser/components/newtab/test/browser/snippet.json","updateCycleInMs":0}`,
|
|
||||||
],
|
|
||||||
["browser.newtabpage.activity-stream.feeds.snippets", true],
|
|
||||||
["browser.newtabpage.activity-stream.telemetry", true],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
registerCleanupFunction(() => {
|
|
||||||
Services.prefs.clearUserPref(
|
|
||||||
"browser.newtabpage.activity-stream.telemetry"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Services.fog.testResetFOG();
|
|
||||||
let pingSubmitted = false;
|
|
||||||
GleanPings.messagingSystem.testBeforeNextSubmit(() => {
|
|
||||||
pingSubmitted = true;
|
|
||||||
Assert.equal(Glean.messagingSystem.pingType.testGetValue(), "snippets");
|
|
||||||
});
|
|
||||||
|
|
||||||
await BrowserTestUtils.withNewTab(
|
|
||||||
{
|
|
||||||
gBrowser,
|
|
||||||
// Work around any issues caching might introduce by navigating to
|
|
||||||
// about blank first
|
|
||||||
url: "about:blank",
|
|
||||||
},
|
|
||||||
async browser => {
|
|
||||||
BrowserTestUtils.startLoadingURIString(browser, "about:home");
|
|
||||||
await BrowserTestUtils.browserLoaded(browser);
|
|
||||||
let text = await SpecialPowers.spawn(browser, [], async () => {
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() => content.document.querySelector(".activity-stream"),
|
|
||||||
`Should render Activity Stream`
|
|
||||||
);
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
),
|
|
||||||
"Should find the snippet inside the footer container"
|
|
||||||
);
|
|
||||||
|
|
||||||
return content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
).innerText;
|
|
||||||
});
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
text,
|
|
||||||
"On January 30th Nightly will introduce dedicated profiles, making it simpler to run different installations of Firefox side by side. Learn what this means for you.",
|
|
||||||
"Snippet content match"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await Services.fog.testFlushAllChildren();
|
|
||||||
Assert.ok(pingSubmitted, "Submitted Glean ping");
|
|
||||||
});
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Snippets endpoint has two snippets that share the same campaign id.
|
|
||||||
* We want to make sure that dismissing the snippet on the first about:newtab
|
|
||||||
* will clear the snippet on the next (preloaded) about:newtab.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { ASRouter } = ChromeUtils.import(
|
|
||||||
"resource://activity-stream/lib/ASRouter.jsm"
|
|
||||||
);
|
|
||||||
|
|
||||||
async function setup() {
|
|
||||||
await SpecialPowers.pushPrefEnv({
|
|
||||||
set: [
|
|
||||||
[
|
|
||||||
"browser.newtabpage.activity-stream.asrouter.providers.snippets",
|
|
||||||
'{"id":"snippets","enabled":true,"type":"remote","url":"https://example.com/browser/browser/components/newtab/test/browser/snippet.json","updateCycleInMs":14400000}',
|
|
||||||
],
|
|
||||||
["browser.newtabpage.activity-stream.feeds.snippets", true],
|
|
||||||
// Disable onboarding, this would prevent snippets from showing up
|
|
||||||
[
|
|
||||||
"browser.newtabpage.activity-stream.asrouter.providers.onboarding",
|
|
||||||
'{"id":"onboarding","type":"local","localProvider":"OnboardingMessageProvider","enabled":false,"exclude":[]}',
|
|
||||||
],
|
|
||||||
// Ensure this is true, this is the main behavior we want to test for
|
|
||||||
["browser.newtab.preload", true],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(async function test_campaign_dismiss() {
|
|
||||||
await setup();
|
|
||||||
let tab1 = await BrowserTestUtils.openNewForegroundTab({
|
|
||||||
gBrowser,
|
|
||||||
opening: "about:home",
|
|
||||||
});
|
|
||||||
await ContentTask.spawn(gBrowser.selectedBrowser, {}, async () => {
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() => content.document.querySelector(".activity-stream"),
|
|
||||||
`Should render Activity Stream`
|
|
||||||
);
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
),
|
|
||||||
"Should find the snippet inside the footer container"
|
|
||||||
);
|
|
||||||
|
|
||||||
content.document
|
|
||||||
.querySelector("#footer-asrouter-container .blockButton")
|
|
||||||
.click();
|
|
||||||
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() =>
|
|
||||||
!content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
),
|
|
||||||
"Should wait for the snippet to block"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
ok(
|
|
||||||
ASRouter.state.messageBlockList.length,
|
|
||||||
"Should have the campaign blocked"
|
|
||||||
);
|
|
||||||
|
|
||||||
let tab2 = await BrowserTestUtils.openNewForegroundTab({
|
|
||||||
gBrowser,
|
|
||||||
opening: "about:newtab",
|
|
||||||
// This is important because the newtab is preloaded and doesn't behave
|
|
||||||
// like a regular page load
|
|
||||||
waitForLoad: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
await ContentTask.spawn(gBrowser.selectedBrowser, {}, async () => {
|
|
||||||
await ContentTaskUtils.waitForCondition(
|
|
||||||
() => content.document.querySelector(".activity-stream"),
|
|
||||||
`Should render Activity Stream`
|
|
||||||
);
|
|
||||||
let snippet = content.document.querySelector(
|
|
||||||
"#footer-asrouter-container .SimpleSnippet"
|
|
||||||
);
|
|
||||||
Assert.equal(
|
|
||||||
snippet,
|
|
||||||
null,
|
|
||||||
"No snippets shown because campaign is blocked"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
BrowserTestUtils.removeTab(tab1);
|
|
||||||
BrowserTestUtils.removeTab(tab2);
|
|
||||||
await ASRouter.unblockMessageById(["10533", "10534"]);
|
|
||||||
await SpecialPowers.popPrefEnv();
|
|
||||||
});
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
{
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"weight": 50,
|
|
||||||
"id": "10533",
|
|
||||||
"template": "simple_snippet",
|
|
||||||
"template_version": "1.0.0",
|
|
||||||
"content": {
|
|
||||||
"icon": "",
|
|
||||||
"text": "On January 30th Nightly will introduce dedicated profiles, making it simpler to run different installations of Firefox side by side. <link0> Learn what this means for you</link0>.",
|
|
||||||
"tall": false,
|
|
||||||
"do_not_autoblock": false,
|
|
||||||
"links": {
|
|
||||||
"link0": {
|
|
||||||
"url": "https://example.com/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"campaign": "nightly-profile-management",
|
|
||||||
"targeting": "true",
|
|
||||||
"provider_url": "https://snippets.cdn.mozilla.net/6/Firefox/66.0a1/20190122215349/Darwin_x86_64-gcc3/en-US/default/Darwin%2018.0.0/default/default/",
|
|
||||||
"provider": "snippets"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"weight": 50,
|
|
||||||
"id": "10534",
|
|
||||||
"template": "simple_snippet",
|
|
||||||
"template_version": "1.0.0",
|
|
||||||
"content": {
|
|
||||||
"icon": "",
|
|
||||||
"text": "On January 30th Nightly will introduce dedicated profiles, making it simpler to run different installations of Firefox side by side. <link0> Learn what this means for you</link0>.",
|
|
||||||
"tall": false,
|
|
||||||
"do_not_autoblock": false,
|
|
||||||
"links": {
|
|
||||||
"link0": {
|
|
||||||
"url": "https://example.com/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"campaign": "nightly-profile-management",
|
|
||||||
"targeting": "true",
|
|
||||||
"provider_url": "https://snippets.cdn.mozilla.net/6/Firefox/66.0a1/20190122215349/Darwin_x86_64-gcc3/en-US/default/Darwin%2018.0.0/default/default/",
|
|
||||||
"provider": "snippets"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"id": "SIMPLE_BELOW_SEARCH_TEST_1",
|
|
||||||
"template": "simple_below_search_snippet",
|
|
||||||
"content": {
|
|
||||||
"icon": "chrome://branding/content/icon64.png",
|
|
||||||
"icon_dark_theme": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfjBQ8QDifrKGc/AAABf0lEQVQoz4WRO08UUQCFvztzd1AgG9jRgGwkhEoMIYGSygYt+A00tpZGY0jYxAJKEwkNjX9AK2xACx4dhFiQQCiMMRr2kYXdnQcz7L0z91qAMVac6hTfSU7OgVsk/prtyfSNfRb7ge2cd7dmVucP/wM2lwqVqoyICahRx9Nz71+8AnAAvlTct+dSYDBYcgJ+Fj68XFu/AfamnIoWFoHFYrAUuYMSn55/fAIOxIs1t4MhQpNxRYsUD0ld7r8DCfZph4QecrqkhCREgMLSeISQkAy0UBgE0CYgIkeRA9HdsCQhpEGCxichpItHigEcPH4XJLRbTf8STY0iiiuu60Ifxexx04F0N+aCgJCAhPQmD/cp/RC5A79WvUyhUHSIidAIoESv9VfAhW9n8+XqTCoyMsz1cviMMrGz9BrjAuboYHZajyXCInEocI8yvccbC+0muABanR4/tONjQz3DzgNKtj9sfv66XD9B/3tT9g/akb7h0bJwzxqqmlRHLr4rLPwBlYWoYj77l2AAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDUtMTVUMTY6MTQ6MzkrMDA6MDD5/4XBAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTA1LTE1VDE2OjE0OjM5KzAwOjAwiKI9fQAAAABJRU5ErkJggg==",
|
|
||||||
"text": "Securely store passwords, bookmarks, and more with a Firefox Account. <syncLink>Sign up</syncLink>",
|
|
||||||
"links": {
|
|
||||||
"syncLink": {
|
|
||||||
"url": "https://www.mozilla.org/en-US/firefox/accounts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"block_button_text": "Block"
|
|
||||||
},
|
|
||||||
"targeting": "true"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
{
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"id": "SIMPLE_TEST_1",
|
|
||||||
"template": "simple_snippet",
|
|
||||||
"campaign": "test_campaign_blocking",
|
|
||||||
"content": {
|
|
||||||
"icon": "chrome://branding/content/icon64.png",
|
|
||||||
"icon_dark_theme": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfjBQ8QDifrKGc/AAABf0lEQVQoz4WRO08UUQCFvztzd1AgG9jRgGwkhEoMIYGSygYt+A00tpZGY0jYxAJKEwkNjX9AK2xACx4dhFiQQCiMMRr2kYXdnQcz7L0z91qAMVac6hTfSU7OgVsk/prtyfSNfRb7ge2cd7dmVucP/wM2lwqVqoyICahRx9Nz71+8AnAAvlTct+dSYDBYcgJ+Fj68XFu/AfamnIoWFoHFYrAUuYMSn55/fAIOxIs1t4MhQpNxRYsUD0ld7r8DCfZph4QecrqkhCREgMLSeISQkAy0UBgE0CYgIkeRA9HdsCQhpEGCxichpItHigEcPH4XJLRbTf8STY0iiiuu60Ifxexx04F0N+aCgJCAhPQmD/cp/RC5A79WvUyhUHSIidAIoESv9VfAhW9n8+XqTCoyMsz1cviMMrGz9BrjAuboYHZajyXCInEocI8yvccbC+0muABanR4/tONjQz3DzgNKtj9sfv66XD9B/3tT9g/akb7h0bJwzxqqmlRHLr4rLPwBlYWoYj77l2AAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDUtMTVUMTY6MTQ6MzkrMDA6MDD5/4XBAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTA1LTE1VDE2OjE0OjM5KzAwOjAwiKI9fQAAAABJRU5ErkJggg==",
|
|
||||||
"title": "Firefox Account!",
|
|
||||||
"title_icon": "chrome://branding/content/icon16.png",
|
|
||||||
"title_icon_dark_theme": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfjBQ8QDifrKGc/AAABf0lEQVQoz4WRO08UUQCFvztzd1AgG9jRgGwkhEoMIYGSygYt+A00tpZGY0jYxAJKEwkNjX9AK2xACx4dhFiQQCiMMRr2kYXdnQcz7L0z91qAMVac6hTfSU7OgVsk/prtyfSNfRb7ge2cd7dmVucP/wM2lwqVqoyICahRx9Nz71+8AnAAvlTct+dSYDBYcgJ+Fj68XFu/AfamnIoWFoHFYrAUuYMSn55/fAIOxIs1t4MhQpNxRYsUD0ld7r8DCfZph4QecrqkhCREgMLSeISQkAy0UBgE0CYgIkeRA9HdsCQhpEGCxichpItHigEcPH4XJLRbTf8STY0iiiuu60Ifxexx04F0N+aCgJCAhPQmD/cp/RC5A79WvUyhUHSIidAIoESv9VfAhW9n8+XqTCoyMsz1cviMMrGz9BrjAuboYHZajyXCInEocI8yvccbC+0muABanR4/tONjQz3DzgNKtj9sfv66XD9B/3tT9g/akb7h0bJwzxqqmlRHLr4rLPwBlYWoYj77l2AAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDUtMTVUMTY6MTQ6MzkrMDA6MDD5/4XBAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTA1LTE1VDE2OjE0OjM5KzAwOjAwiKI9fQAAAABJRU5ErkJggg==",
|
|
||||||
"text": "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
|
|
||||||
"links": {
|
|
||||||
"syncLink": {
|
|
||||||
"url": "https://www.mozilla.org/en-US/firefox/accounts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"block_button_text": "Block"
|
|
||||||
},
|
|
||||||
"targeting": "true"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -17,10 +17,9 @@ import { CFRPageActions } from "lib/CFRPageActions.jsm";
|
||||||
import { GlobalOverrider } from "test/unit/utils";
|
import { GlobalOverrider } from "test/unit/utils";
|
||||||
import { PanelTestProvider } from "lib/PanelTestProvider.sys.mjs";
|
import { PanelTestProvider } from "lib/PanelTestProvider.sys.mjs";
|
||||||
import ProviderResponseSchema from "content-src/asrouter/schemas/provider-response.schema.json";
|
import ProviderResponseSchema from "content-src/asrouter/schemas/provider-response.schema.json";
|
||||||
import { SnippetsTestMessageProvider } from "lib/SnippetsTestMessageProvider.sys.mjs";
|
|
||||||
|
|
||||||
const MESSAGE_PROVIDER_PREF_NAME =
|
const MESSAGE_PROVIDER_PREF_NAME =
|
||||||
"browser.newtabpage.activity-stream.asrouter.providers.snippets";
|
"browser.newtabpage.activity-stream.asrouter.providers.cfr";
|
||||||
const FAKE_PROVIDERS = [
|
const FAKE_PROVIDERS = [
|
||||||
FAKE_LOCAL_PROVIDER,
|
FAKE_LOCAL_PROVIDER,
|
||||||
FAKE_REMOTE_PROVIDER,
|
FAKE_REMOTE_PROVIDER,
|
||||||
|
|
@ -153,7 +152,6 @@ describe("ASRouter", () => {
|
||||||
cfr: "",
|
cfr: "",
|
||||||
"message-groups": "",
|
"message-groups": "",
|
||||||
"messaging-experiments": "",
|
"messaging-experiments": "",
|
||||||
snippets: "",
|
|
||||||
"whats-new-panel": "",
|
"whats-new-panel": "",
|
||||||
},
|
},
|
||||||
totalBookmarksCount: {},
|
totalBookmarksCount: {},
|
||||||
|
|
@ -166,7 +164,6 @@ describe("ASRouter", () => {
|
||||||
userPrefs: {
|
userPrefs: {
|
||||||
cfrFeatures: true,
|
cfrFeatures: true,
|
||||||
cfrAddons: true,
|
cfrAddons: true,
|
||||||
snippets: true,
|
|
||||||
},
|
},
|
||||||
totalBlockedCount: {},
|
totalBlockedCount: {},
|
||||||
blockedCountByType: {},
|
blockedCountByType: {},
|
||||||
|
|
@ -253,7 +250,6 @@ describe("ASRouter", () => {
|
||||||
gURLBar: {},
|
gURLBar: {},
|
||||||
isSeparateAboutWelcome: true,
|
isSeparateAboutWelcome: true,
|
||||||
AttributionCode: fakeAttributionCode,
|
AttributionCode: fakeAttributionCode,
|
||||||
SnippetsTestMessageProvider,
|
|
||||||
PanelTestProvider,
|
PanelTestProvider,
|
||||||
MacAttribution: { applicationPath: "" },
|
MacAttribution: { applicationPath: "" },
|
||||||
ToolbarBadgeHub: FakeToolbarBadgeHub,
|
ToolbarBadgeHub: FakeToolbarBadgeHub,
|
||||||
|
|
@ -494,11 +490,6 @@ describe("ASRouter", () => {
|
||||||
await createRouterAndInit();
|
await createRouterAndInit();
|
||||||
|
|
||||||
assert.lengthOf(Object.keys(Router.ALLOWLIST_HOSTS), 2);
|
assert.lengthOf(Object.keys(Router.ALLOWLIST_HOSTS), 2);
|
||||||
assert.propertyVal(
|
|
||||||
Router.ALLOWLIST_HOSTS,
|
|
||||||
"snippets-admin.mozilla.org",
|
|
||||||
"preview"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
assert.propertyVal(
|
||||||
Router.ALLOWLIST_HOSTS,
|
Router.ALLOWLIST_HOSTS,
|
||||||
"activity-stream-icons.services.mozilla.com",
|
"activity-stream-icons.services.mozilla.com",
|
||||||
|
|
@ -545,7 +536,6 @@ describe("ASRouter", () => {
|
||||||
|
|
||||||
await createRouterAndInit();
|
await createRouterAndInit();
|
||||||
|
|
||||||
assert.property(Router._localProviders, "SnippetsTestMessageProvider");
|
|
||||||
assert.property(Router._localProviders, "PanelTestProvider");
|
assert.property(Router._localProviders, "PanelTestProvider");
|
||||||
});
|
});
|
||||||
it("should not add the local test providers on init if devtools are disabled", async () => {
|
it("should not add the local test providers on init if devtools are disabled", async () => {
|
||||||
|
|
@ -553,10 +543,6 @@ describe("ASRouter", () => {
|
||||||
|
|
||||||
await createRouterAndInit();
|
await createRouterAndInit();
|
||||||
|
|
||||||
assert.notProperty(
|
|
||||||
Router._localProviders,
|
|
||||||
"SnippetsTestMessageProvider"
|
|
||||||
);
|
|
||||||
assert.notProperty(Router._localProviders, "PanelTestProvider");
|
assert.notProperty(Router._localProviders, "PanelTestProvider");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -580,18 +566,18 @@ describe("ASRouter", () => {
|
||||||
id: "1",
|
id: "1",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
targeting: "true",
|
targeting: "true",
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
const messageNotTargeted = {
|
const messageNotTargeted = {
|
||||||
id: "2",
|
id: "2",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
await Router.setState({
|
await Router.setState({
|
||||||
messages: [messageTargeted, messageNotTargeted],
|
messages: [messageTargeted, messageNotTargeted],
|
||||||
providers: [{ id: "snippets" }],
|
providers: [{ id: "cfr" }],
|
||||||
});
|
});
|
||||||
fakeTargetingContext.evalWithDefault.resolves(false);
|
fakeTargetingContext.evalWithDefault.resolves(false);
|
||||||
|
|
||||||
|
|
@ -813,7 +799,12 @@ describe("ASRouter", () => {
|
||||||
assert.notCalled(FakeMomentsPageHub.executeAction);
|
assert.notCalled(FakeMomentsPageHub.executeAction);
|
||||||
});
|
});
|
||||||
it("should route default to sending to content", () => {
|
it("should route default to sending to content", () => {
|
||||||
Router.routeCFRMessage({ template: "snippets" }, browser, {}, true);
|
Router.routeCFRMessage(
|
||||||
|
{ template: "some_other_template" },
|
||||||
|
browser,
|
||||||
|
{},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
assert.notCalled(FakeToolbarPanelHub.forceShowMessage);
|
assert.notCalled(FakeToolbarPanelHub.forceShowMessage);
|
||||||
assert.notCalled(CFRPageActions.forceRecommendation);
|
assert.notCalled(CFRPageActions.forceRecommendation);
|
||||||
|
|
@ -1154,23 +1145,23 @@ describe("ASRouter", () => {
|
||||||
describe("#handleMessageRequest", () => {
|
describe("#handleMessageRequest", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await Router.setState(() => ({
|
await Router.setState(() => ({
|
||||||
providers: [{ id: "snippets" }, { id: "badge" }],
|
providers: [{ id: "cfr" }, { id: "badge" }],
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
it("should not return a blocked message", async () => {
|
it("should not return a blocked message", async () => {
|
||||||
// Block all messages except the first
|
// Block all messages except the first
|
||||||
await Router.setState(() => ({
|
await Router.setState(() => ({
|
||||||
messages: [
|
messages: [
|
||||||
{ id: "foo", provider: "snippets", groups: ["snippets"] },
|
{ id: "foo", provider: "cfr", groups: ["cfr"] },
|
||||||
{ id: "bar", provider: "snippets", groups: ["snippets"] },
|
{ id: "bar", provider: "cfr", groups: ["cfr"] },
|
||||||
],
|
],
|
||||||
messageBlockList: ["foo"],
|
messageBlockList: ["foo"],
|
||||||
}));
|
}));
|
||||||
await Router.handleMessageRequest({
|
await Router.handleMessageRequest({
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
});
|
});
|
||||||
assert.calledWithMatch(ASRouterTargeting.findMatchingMessage, {
|
assert.calledWithMatch(ASRouterTargeting.findMatchingMessage, {
|
||||||
messages: [{ id: "bar", provider: "snippets", groups: ["snippets"] }],
|
messages: [{ id: "bar", provider: "cfr", groups: ["cfr"] }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("should not return a message from a disabled group", async () => {
|
it("should not return a message from a disabled group", async () => {
|
||||||
|
|
@ -1180,13 +1171,13 @@ describe("ASRouter", () => {
|
||||||
// Block all messages except the first
|
// Block all messages except the first
|
||||||
await Router.setState(() => ({
|
await Router.setState(() => ({
|
||||||
messages: [
|
messages: [
|
||||||
{ id: "foo", provider: "snippets", groups: ["snippets"] },
|
{ id: "foo", provider: "cfr", groups: ["cfr"] },
|
||||||
{ id: "bar", provider: "snippets", groups: ["snippets"] },
|
{ id: "bar", provider: "cfr", groups: ["cfr"] },
|
||||||
],
|
],
|
||||||
groups: [{ id: "snippets", enabled: false }],
|
groups: [{ id: "cfr", enabled: false }],
|
||||||
}));
|
}));
|
||||||
const result = await Router.handleMessageRequest({
|
const result = await Router.handleMessageRequest({
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
});
|
});
|
||||||
assert.isNull(result);
|
assert.isNull(result);
|
||||||
});
|
});
|
||||||
|
|
@ -1196,46 +1187,46 @@ describe("ASRouter", () => {
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
id: "foo",
|
id: "foo",
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
},
|
},
|
||||||
{ id: "bar", provider: "snippets", groups: ["snippets"] },
|
{ id: "bar", provider: "cfr", groups: ["cfr"] },
|
||||||
],
|
],
|
||||||
messageBlockList: ["foocampaign"],
|
messageBlockList: ["foocampaign"],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await Router.handleMessageRequest({
|
await Router.handleMessageRequest({
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
});
|
});
|
||||||
assert.calledWithMatch(ASRouterTargeting.findMatchingMessage, {
|
assert.calledWithMatch(ASRouterTargeting.findMatchingMessage, {
|
||||||
messages: [{ id: "bar", provider: "snippets", groups: ["snippets"] }],
|
messages: [{ id: "bar", provider: "cfr", groups: ["cfr"] }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("should not return a message excluded by the provider", async () => {
|
it("should not return a message excluded by the provider", async () => {
|
||||||
// There are only two providers; block the FAKE_LOCAL_PROVIDER, leaving
|
// There are only two providers; block the FAKE_LOCAL_PROVIDER, leaving
|
||||||
// only FAKE_REMOTE_PROVIDER unblocked, which provides only one message
|
// only FAKE_REMOTE_PROVIDER unblocked, which provides only one message
|
||||||
await Router.setState(() => ({
|
await Router.setState(() => ({
|
||||||
providers: [{ id: "snippets", exclude: ["foo"] }],
|
providers: [{ id: "cfr", exclude: ["foo"] }],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await Router.setState(() => ({
|
await Router.setState(() => ({
|
||||||
messages: [{ id: "foo", provider: "snippets" }],
|
messages: [{ id: "foo", provider: "cfr" }],
|
||||||
messageBlockList: ["foocampaign"],
|
messageBlockList: ["foocampaign"],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const result = await Router.handleMessageRequest({
|
const result = await Router.handleMessageRequest({
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
});
|
});
|
||||||
assert.isNull(result);
|
assert.isNull(result);
|
||||||
});
|
});
|
||||||
it("should not return a message if the frequency cap has been hit", async () => {
|
it("should not return a message if the frequency cap has been hit", async () => {
|
||||||
sandbox.stub(Router, "isBelowFrequencyCaps").returns(false);
|
sandbox.stub(Router, "isBelowFrequencyCaps").returns(false);
|
||||||
await Router.setState(() => ({
|
await Router.setState(() => ({
|
||||||
messages: [{ id: "foo", provider: "snippets" }],
|
messages: [{ id: "foo", provider: "cfr" }],
|
||||||
}));
|
}));
|
||||||
const result = await Router.handleMessageRequest({
|
const result = await Router.handleMessageRequest({
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
});
|
});
|
||||||
assert.isNull(result);
|
assert.isNull(result);
|
||||||
});
|
});
|
||||||
|
|
@ -1244,15 +1235,15 @@ describe("ASRouter", () => {
|
||||||
id: "1",
|
id: "1",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
trigger: { id: "foo" },
|
trigger: { id: "foo" },
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
const message2 = {
|
const message2 = {
|
||||||
id: "2",
|
id: "2",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
trigger: { id: "bar" },
|
trigger: { id: "bar" },
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
await Router.setState({ messages: [message2, message1] });
|
await Router.setState({ messages: [message2, message1] });
|
||||||
// Just return the first message provided as arg
|
// Just return the first message provided as arg
|
||||||
|
|
@ -1276,10 +1267,10 @@ describe("ASRouter", () => {
|
||||||
const message2 = {
|
const message2 = {
|
||||||
id: "2",
|
id: "2",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
template: "snippet",
|
template: "test_template",
|
||||||
trigger: { id: "foo" },
|
trigger: { id: "foo" },
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
await Router.setState({ messages: [message2, message1] });
|
await Router.setState({ messages: [message2, message1] });
|
||||||
// Just return the first message provided as arg
|
// Just return the first message provided as arg
|
||||||
|
|
@ -1348,8 +1339,8 @@ describe("ASRouter", () => {
|
||||||
id: "1",
|
id: "1",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
trigger: { id: "foo" },
|
trigger: { id: "foo" },
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
const message2 = {
|
const message2 = {
|
||||||
id: "2",
|
id: "2",
|
||||||
|
|
@ -1370,34 +1361,6 @@ describe("ASRouter", () => {
|
||||||
assert.propertyVal(options.trigger, "param", trigger.triggerParam);
|
assert.propertyVal(options.trigger, "param", trigger.triggerParam);
|
||||||
assert.propertyVal(options.trigger, "context", trigger.triggerContext);
|
assert.propertyVal(options.trigger, "context", trigger.triggerContext);
|
||||||
});
|
});
|
||||||
it("should cache snippets messages", async () => {
|
|
||||||
const trigger = {
|
|
||||||
triggerId: "foo",
|
|
||||||
triggerParam: "bar",
|
|
||||||
triggerContext: "context",
|
|
||||||
};
|
|
||||||
const message1 = {
|
|
||||||
id: "1",
|
|
||||||
provider: "snippets",
|
|
||||||
campaign: "foocampaign",
|
|
||||||
trigger: { id: "foo" },
|
|
||||||
groups: ["snippets"],
|
|
||||||
};
|
|
||||||
const message2 = {
|
|
||||||
id: "2",
|
|
||||||
campaign: "foocampaign",
|
|
||||||
trigger: { id: "bar" },
|
|
||||||
groups: ["snippets"],
|
|
||||||
};
|
|
||||||
await Router.setState({ messages: [message2, message1] });
|
|
||||||
|
|
||||||
Router.handleMessageRequest(trigger);
|
|
||||||
|
|
||||||
assert.calledOnce(ASRouterTargeting.findMatchingMessage);
|
|
||||||
|
|
||||||
const [options] = ASRouterTargeting.findMatchingMessage.firstCall.args;
|
|
||||||
assert.propertyVal(options, "shouldCache", true);
|
|
||||||
});
|
|
||||||
it("should not cache badge messages", async () => {
|
it("should not cache badge messages", async () => {
|
||||||
const trigger = {
|
const trigger = {
|
||||||
triggerId: "bar",
|
triggerId: "bar",
|
||||||
|
|
@ -1406,10 +1369,10 @@ describe("ASRouter", () => {
|
||||||
};
|
};
|
||||||
const message1 = {
|
const message1 = {
|
||||||
id: "1",
|
id: "1",
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
trigger: { id: "foo" },
|
trigger: { id: "foo" },
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
};
|
};
|
||||||
const message2 = {
|
const message2 = {
|
||||||
id: "2",
|
id: "2",
|
||||||
|
|
@ -1434,25 +1397,25 @@ describe("ASRouter", () => {
|
||||||
id: "1",
|
id: "1",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
trigger: { id: "foo" },
|
trigger: { id: "foo" },
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
const message2 = {
|
const message2 = {
|
||||||
id: "2",
|
id: "2",
|
||||||
campaign: "foocampaign",
|
campaign: "foocampaign",
|
||||||
trigger: { id: "bar" },
|
trigger: { id: "bar" },
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
const message3 = {
|
const message3 = {
|
||||||
id: "3",
|
id: "3",
|
||||||
campaign: "bazcampaign",
|
campaign: "bazcampaign",
|
||||||
groups: ["snippets"],
|
groups: ["cfr"],
|
||||||
provider: "snippets",
|
provider: "cfr",
|
||||||
};
|
};
|
||||||
await Router.setState({
|
await Router.setState({
|
||||||
messages: [message2, message1, message3],
|
messages: [message2, message1, message3],
|
||||||
groups: [{ id: "snippets", enabled: true }],
|
groups: [{ id: "cfr", enabled: true }],
|
||||||
});
|
});
|
||||||
// Just return the first message provided as arg
|
// Just return the first message provided as arg
|
||||||
ASRouterTargeting.findMatchingMessage.callsFake(args => args.messages);
|
ASRouterTargeting.findMatchingMessage.callsFake(args => args.messages);
|
||||||
|
|
@ -1512,163 +1475,6 @@ describe("ASRouter", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("sendNewTabMessage", () => {
|
|
||||||
it("should construct an appropriate response message", async () => {
|
|
||||||
Router.loadMessagesFromAllProviders.resetHistory();
|
|
||||||
Router.loadMessagesFromAllProviders.onFirstCall().resolves();
|
|
||||||
|
|
||||||
let message = {
|
|
||||||
id: "foo",
|
|
||||||
provider: "snippets",
|
|
||||||
groups: ["snippets"],
|
|
||||||
};
|
|
||||||
|
|
||||||
await Router.setState({
|
|
||||||
messages: [message],
|
|
||||||
providers: [{ id: "snippets" }],
|
|
||||||
});
|
|
||||||
|
|
||||||
ASRouterTargeting.findMatchingMessage.callsFake(
|
|
||||||
({ messages }) => messages[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
let response = await Router.sendNewTabMessage({
|
|
||||||
tabId: 0,
|
|
||||||
browser: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.deepEqual(response.message, message);
|
|
||||||
});
|
|
||||||
it("should send an empty object message if no messages are available", async () => {
|
|
||||||
await Router.setState({ messages: [] });
|
|
||||||
let response = await Router.sendNewTabMessage({
|
|
||||||
tabId: 0,
|
|
||||||
browser: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.deepEqual(response.message, {});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#addPreviewEndpoint", () => {
|
|
||||||
it("should make a request to the provided endpoint", async () => {
|
|
||||||
const url = "https://snippets-admin.mozilla.org/foo";
|
|
||||||
const browser = {};
|
|
||||||
browser.sendMessageToActor = sandbox.stub();
|
|
||||||
|
|
||||||
await Router.sendNewTabMessage({
|
|
||||||
endpoint: { url },
|
|
||||||
tabId: 0,
|
|
||||||
browser,
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.calledWith(global.fetch, url);
|
|
||||||
assert.lengthOf(
|
|
||||||
Router.state.providers.filter(p => p.url === url),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should send EnterSnippetPreviewMode when adding a preview endpoint", async () => {
|
|
||||||
const url = "https://snippets-admin.mozilla.org/foo";
|
|
||||||
const browser = {};
|
|
||||||
browser.sendMessageToActor = sandbox.stub();
|
|
||||||
|
|
||||||
await Router.addPreviewEndpoint(url, browser);
|
|
||||||
|
|
||||||
assert.calledWithExactly(
|
|
||||||
browser.sendMessageToActor,
|
|
||||||
"EnterSnippetsPreviewMode",
|
|
||||||
{},
|
|
||||||
"ASRouter"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should not add a url that is not from an allowed host", async () => {
|
|
||||||
const url = "https://mozilla.org";
|
|
||||||
const browser = {};
|
|
||||||
browser.sendMessageToActor = sandbox.stub();
|
|
||||||
|
|
||||||
await Router.addPreviewEndpoint(url, browser);
|
|
||||||
|
|
||||||
assert.lengthOf(
|
|
||||||
Router.state.providers.filter(p => p.url === url),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should reject bad urls", async () => {
|
|
||||||
const url = "foo";
|
|
||||||
const browser = {};
|
|
||||||
browser.sendMessageToActor = sandbox.stub();
|
|
||||||
|
|
||||||
await Router.addPreviewEndpoint(url, browser);
|
|
||||||
|
|
||||||
assert.lengthOf(
|
|
||||||
Router.state.providers.filter(p => p.url === url),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should record telemetry for message request duration", async () => {
|
|
||||||
const startTelemetryStopwatch = sandbox.stub(
|
|
||||||
global.TelemetryStopwatch,
|
|
||||||
"start"
|
|
||||||
);
|
|
||||||
const finishTelemetryStopwatch = sandbox.stub(
|
|
||||||
global.TelemetryStopwatch,
|
|
||||||
"finish"
|
|
||||||
);
|
|
||||||
sandbox.stub(Router, "handleMessageRequest");
|
|
||||||
const tabId = 123;
|
|
||||||
await Router.sendNewTabMessage({
|
|
||||||
tabId,
|
|
||||||
browser: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Called once for the messagesLoaded trigger and once for the above call.
|
|
||||||
assert.calledTwice(startTelemetryStopwatch);
|
|
||||||
assert.calledWithExactly(
|
|
||||||
startTelemetryStopwatch,
|
|
||||||
"MS_MESSAGE_REQUEST_TIME_MS",
|
|
||||||
{ tabId }
|
|
||||||
);
|
|
||||||
assert.calledTwice(finishTelemetryStopwatch);
|
|
||||||
assert.calledWithExactly(
|
|
||||||
finishTelemetryStopwatch,
|
|
||||||
"MS_MESSAGE_REQUEST_TIME_MS",
|
|
||||||
{ tabId }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should return the preview message if that's available and remove it from Router.state", async () => {
|
|
||||||
const expectedObj = {
|
|
||||||
id: "foo",
|
|
||||||
groups: ["preview"],
|
|
||||||
provider: "preview",
|
|
||||||
};
|
|
||||||
await Router.setState({
|
|
||||||
messages: [expectedObj],
|
|
||||||
providers: [{ id: "preview" }],
|
|
||||||
});
|
|
||||||
|
|
||||||
ASRouterTargeting.findMatchingMessage.callsFake(
|
|
||||||
({ messages }) => expectedObj
|
|
||||||
);
|
|
||||||
|
|
||||||
Router.loadMessagesFromAllProviders.resetHistory();
|
|
||||||
Router.loadMessagesFromAllProviders.onFirstCall().resolves();
|
|
||||||
|
|
||||||
let response = await Router.sendNewTabMessage({
|
|
||||||
endpoint: { url: "foo.com" },
|
|
||||||
tabId: 0,
|
|
||||||
browser: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.deepEqual(response.message, expectedObj);
|
|
||||||
|
|
||||||
assert.isUndefined(
|
|
||||||
Router.state.messages.find(m => m.provider === "preview")
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#setMessageById", async () => {
|
describe("#setMessageById", async () => {
|
||||||
it("should send an empty message if provided id did not resolve to a message", async () => {
|
it("should send an empty message if provided id did not resolve to a message", async () => {
|
||||||
let response = await Router.setMessageById({ id: -1 }, true, {});
|
let response = await Router.setMessageById({ id: -1 }, true, {});
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ describe("ASRouterNewTabHook", () => {
|
||||||
describe("connect", () => {
|
describe("connect", () => {
|
||||||
it("before connection messageHandler methods are not called", async () => {
|
it("before connection messageHandler methods are not called", async () => {
|
||||||
routerParams.clearChildMessages([1]);
|
routerParams.clearChildMessages([1]);
|
||||||
routerParams.clearChildProviders(["snippets"]);
|
routerParams.clearChildProviders(["test_provider"]);
|
||||||
routerParams.updateAdminState({ messages: {} });
|
routerParams.updateAdminState({ messages: {} });
|
||||||
assert.notCalled(messageHandler.clearChildMessages);
|
assert.notCalled(messageHandler.clearChildMessages);
|
||||||
assert.notCalled(messageHandler.clearChildProviders);
|
assert.notCalled(messageHandler.clearChildProviders);
|
||||||
|
|
@ -90,7 +90,7 @@ describe("ASRouterNewTabHook", () => {
|
||||||
it("after connect updateAdminState and clearChildMessages calls are forwarded to handler", async () => {
|
it("after connect updateAdminState and clearChildMessages calls are forwarded to handler", async () => {
|
||||||
instance.connect(messageHandler);
|
instance.connect(messageHandler);
|
||||||
routerParams.clearChildMessages([1]);
|
routerParams.clearChildMessages([1]);
|
||||||
routerParams.clearChildProviders(["snippets"]);
|
routerParams.clearChildProviders(["test_provider"]);
|
||||||
routerParams.updateAdminState({ messages: {} });
|
routerParams.updateAdminState({ messages: {} });
|
||||||
assert.called(messageHandler.clearChildMessages);
|
assert.called(messageHandler.clearChildMessages);
|
||||||
assert.called(messageHandler.clearChildProviders);
|
assert.called(messageHandler.clearChildProviders);
|
||||||
|
|
@ -98,11 +98,11 @@ describe("ASRouterNewTabHook", () => {
|
||||||
});
|
});
|
||||||
it("calls from before connection are dropped", async () => {
|
it("calls from before connection are dropped", async () => {
|
||||||
routerParams.clearChildMessages([1]);
|
routerParams.clearChildMessages([1]);
|
||||||
routerParams.clearChildProviders(["snippets"]);
|
routerParams.clearChildProviders(["test_provider"]);
|
||||||
routerParams.updateAdminState({ messages: {} });
|
routerParams.updateAdminState({ messages: {} });
|
||||||
instance.connect(messageHandler);
|
instance.connect(messageHandler);
|
||||||
routerParams.clearChildMessages([1]);
|
routerParams.clearChildMessages([1]);
|
||||||
routerParams.clearChildProviders(["snippets"]);
|
routerParams.clearChildProviders(["test_provider"]);
|
||||||
routerParams.updateAdminState({ messages: {} });
|
routerParams.updateAdminState({ messages: {} });
|
||||||
assert.calledOnce(messageHandler.clearChildMessages);
|
assert.calledOnce(messageHandler.clearChildMessages);
|
||||||
assert.calledOnce(messageHandler.clearChildProviders);
|
assert.calledOnce(messageHandler.clearChildProviders);
|
||||||
|
|
@ -114,7 +114,7 @@ describe("ASRouterNewTabHook", () => {
|
||||||
instance.connect(messageHandler);
|
instance.connect(messageHandler);
|
||||||
instance.disconnect();
|
instance.disconnect();
|
||||||
routerParams.clearChildMessages([1]);
|
routerParams.clearChildMessages([1]);
|
||||||
routerParams.clearChildProviders(["snippets"]);
|
routerParams.clearChildProviders(["test_provider"]);
|
||||||
routerParams.updateAdminState({ messages: {} });
|
routerParams.updateAdminState({ messages: {} });
|
||||||
assert.notCalled(messageHandler.clearChildMessages);
|
assert.notCalled(messageHandler.clearChildMessages);
|
||||||
assert.notCalled(messageHandler.clearChildProviders);
|
assert.notCalled(messageHandler.clearChildProviders);
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@ describe("ASRouterParent", () => {
|
||||||
ASRouterParent.tabs.messageAll,
|
ASRouterParent.tabs.messageAll,
|
||||||
"ClearMessages",
|
"ClearMessages",
|
||||||
// When blocking an id the entire campaign is blocked
|
// When blocking an id the entire campaign is blocked
|
||||||
// and all other snippets become invalid
|
|
||||||
["message-campaign"]
|
["message-campaign"]
|
||||||
);
|
);
|
||||||
assert.equal(result, "handle-message-result");
|
assert.equal(result, "handle-message-result");
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ const PROVIDER_PREF_BRANCH =
|
||||||
"browser.newtabpage.activity-stream.asrouter.providers.";
|
"browser.newtabpage.activity-stream.asrouter.providers.";
|
||||||
const DEVTOOLS_PREF =
|
const DEVTOOLS_PREF =
|
||||||
"browser.newtabpage.activity-stream.asrouter.devtoolsEnabled";
|
"browser.newtabpage.activity-stream.asrouter.devtoolsEnabled";
|
||||||
const SNIPPETS_USER_PREF = "browser.newtabpage.activity-stream.feeds.snippets";
|
|
||||||
const CFR_USER_PREF_ADDONS =
|
const CFR_USER_PREF_ADDONS =
|
||||||
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons";
|
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons";
|
||||||
const CFR_USER_PREF_FEATURES =
|
const CFR_USER_PREF_FEATURES =
|
||||||
|
|
@ -18,12 +17,11 @@ const CFR_USER_PREF_FEATURES =
|
||||||
/** NUMBER_OF_PREFS_TO_OBSERVE includes:
|
/** NUMBER_OF_PREFS_TO_OBSERVE includes:
|
||||||
* 1. asrouter.providers. pref branch
|
* 1. asrouter.providers. pref branch
|
||||||
* 2. asrouter.devtoolsEnabled
|
* 2. asrouter.devtoolsEnabled
|
||||||
* 3. browser.newtabpage.activity-stream.feeds.snippets (user preference - snippets)
|
* 3. browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons (user preference - cfr)
|
||||||
* 4. browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons (user preference - cfr)
|
|
||||||
* 4. browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features (user preference - cfr)
|
* 4. browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features (user preference - cfr)
|
||||||
* 5. services.sync.username
|
* 5. services.sync.username
|
||||||
*/
|
*/
|
||||||
const NUMBER_OF_PREFS_TO_OBSERVE = 6;
|
const NUMBER_OF_PREFS_TO_OBSERVE = 5;
|
||||||
|
|
||||||
describe("ASRouterPreferences", () => {
|
describe("ASRouterPreferences", () => {
|
||||||
let ASRouterPreferences;
|
let ASRouterPreferences;
|
||||||
|
|
@ -324,20 +322,12 @@ describe("ASRouterPreferences", () => {
|
||||||
assert.calledTwice(boolPrefStub);
|
assert.calledTwice(boolPrefStub);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("#getUserPreference(providerId)", () => {
|
|
||||||
it("should return the user preference for snippets", () => {
|
|
||||||
boolPrefStub.withArgs(SNIPPETS_USER_PREF).returns(true);
|
|
||||||
assert.isTrue(ASRouterPreferences.getUserPreference("snippets"));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe("#getAllUserPreferences", () => {
|
describe("#getAllUserPreferences", () => {
|
||||||
it("should return all user preferences", () => {
|
it("should return all user preferences", () => {
|
||||||
boolPrefStub.withArgs(SNIPPETS_USER_PREF).returns(true);
|
|
||||||
boolPrefStub.withArgs(CFR_USER_PREF_ADDONS).returns(false);
|
boolPrefStub.withArgs(CFR_USER_PREF_ADDONS).returns(false);
|
||||||
boolPrefStub.withArgs(CFR_USER_PREF_FEATURES).returns(true);
|
boolPrefStub.withArgs(CFR_USER_PREF_FEATURES).returns(true);
|
||||||
const result = ASRouterPreferences.getAllUserPreferences();
|
const result = ASRouterPreferences.getAllUserPreferences();
|
||||||
assert.deepEqual(result, {
|
assert.deepEqual(result, {
|
||||||
snippets: true,
|
|
||||||
cfrAddons: false,
|
cfrAddons: false,
|
||||||
cfrFeatures: true,
|
cfrFeatures: true,
|
||||||
});
|
});
|
||||||
|
|
@ -389,8 +379,8 @@ describe("ASRouterPreferences", () => {
|
||||||
});
|
});
|
||||||
it("should set the given pref", () => {
|
it("should set the given pref", () => {
|
||||||
const setStub = sandbox.stub(global.Services.prefs, "setBoolPref");
|
const setStub = sandbox.stub(global.Services.prefs, "setBoolPref");
|
||||||
ASRouterPreferences.setUserPreference("snippets", true);
|
ASRouterPreferences.setUserPreference("cfrAddons", true);
|
||||||
assert.calledWith(setStub, SNIPPETS_USER_PREF, true);
|
assert.calledWith(setStub, CFR_USER_PREF_ADDONS, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("#resetProviderPref", () => {
|
describe("#resetProviderPref", () => {
|
||||||
|
|
@ -399,7 +389,6 @@ describe("ASRouterPreferences", () => {
|
||||||
FAKE_PROVIDERS.forEach(provider => {
|
FAKE_PROVIDERS.forEach(provider => {
|
||||||
assert.calledWith(resetStub, getPrefNameForProvider(provider.id));
|
assert.calledWith(resetStub, getPrefNameForProvider(provider.id));
|
||||||
});
|
});
|
||||||
assert.calledWith(resetStub, SNIPPETS_USER_PREF);
|
|
||||||
assert.calledWith(resetStub, CFR_USER_PREF_ADDONS);
|
assert.calledWith(resetStub, CFR_USER_PREF_ADDONS);
|
||||||
assert.calledWith(resetStub, CFR_USER_PREF_FEATURES);
|
assert.calledWith(resetStub, CFR_USER_PREF_FEATURES);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import EOYSnippetSchema from "../../../content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json";
|
|
||||||
import SimpleBelowSearchSnippetSchema from "../../../content-src/asrouter/templates/SimpleBelowSearchSnippet/SimpleBelowSearchSnippet.schema.json";
|
|
||||||
import SimpleSnippetSchema from "../../../content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json";
|
|
||||||
import { SnippetsTestMessageProvider } from "../../../lib/SnippetsTestMessageProvider.sys.mjs";
|
|
||||||
import SubmitFormSnippetSchema from "../../../content-src/asrouter/templates/SubmitFormSnippet/SubmitFormSnippet.schema.json";
|
|
||||||
import SubmitFormScene2SnippetSchema from "../../../content-src/asrouter/templates/SubmitFormSnippet/SubmitFormScene2Snippet.schema.json";
|
|
||||||
|
|
||||||
const schemas = {
|
|
||||||
simple_snippet: SimpleSnippetSchema,
|
|
||||||
newsletter_snippet: SubmitFormSnippetSchema,
|
|
||||||
fxa_signup_snippet: SubmitFormSnippetSchema,
|
|
||||||
send_to_device_snippet: SubmitFormSnippetSchema,
|
|
||||||
send_to_device_scene2_snippet: SubmitFormScene2SnippetSchema,
|
|
||||||
eoy_snippet: EOYSnippetSchema,
|
|
||||||
simple_below_search_snippet: SimpleBelowSearchSnippetSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("SnippetsTestMessageProvider", async () => {
|
|
||||||
let messages = await SnippetsTestMessageProvider.getMessages();
|
|
||||||
|
|
||||||
it("should return an array of messages", () => {
|
|
||||||
assert.isArray(messages);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have a valid example of each schema", () => {
|
|
||||||
Object.keys(schemas).forEach(templateName => {
|
|
||||||
const example = messages.find(
|
|
||||||
message => message.template === templateName
|
|
||||||
);
|
|
||||||
assert.ok(example, `has a ${templateName} example`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have examples that are valid", () => {
|
|
||||||
messages.forEach(example => {
|
|
||||||
assert.jsonSchema(
|
|
||||||
example.content,
|
|
||||||
schemas[example.template],
|
|
||||||
`${example.id} should be valid`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,516 +0,0 @@
|
||||||
import { ASRouterUISurface } from "content-src/asrouter/asrouter-content";
|
|
||||||
import { ASRouterUtils } from "content-src/asrouter/asrouter-utils";
|
|
||||||
import { GlobalOverrider } from "test/unit/utils";
|
|
||||||
import { FAKE_LOCAL_MESSAGES } from "./constants";
|
|
||||||
import React from "react";
|
|
||||||
import { mount } from "enzyme";
|
|
||||||
|
|
||||||
let [FAKE_MESSAGE] = FAKE_LOCAL_MESSAGES;
|
|
||||||
const FAKE_NEWSLETTER_SNIPPET = FAKE_LOCAL_MESSAGES.find(
|
|
||||||
msg => msg.id === "newsletter"
|
|
||||||
);
|
|
||||||
const FAKE_FXA_SNIPPET = FAKE_LOCAL_MESSAGES.find(msg => msg.id === "fxa");
|
|
||||||
const FAKE_BELOW_SEARCH_SNIPPET = FAKE_LOCAL_MESSAGES.find(
|
|
||||||
msg => msg.id === "belowsearch"
|
|
||||||
);
|
|
||||||
|
|
||||||
FAKE_MESSAGE = Object.assign({}, FAKE_MESSAGE, { provider: "fakeprovider" });
|
|
||||||
|
|
||||||
describe("ASRouterUtils", () => {
|
|
||||||
let globalOverrider;
|
|
||||||
let sandbox;
|
|
||||||
let globals;
|
|
||||||
beforeEach(() => {
|
|
||||||
globalOverrider = new GlobalOverrider();
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
globals = {
|
|
||||||
ASRouterMessage: sandbox.stub(),
|
|
||||||
};
|
|
||||||
globalOverrider.set(globals);
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
globalOverrider.restore();
|
|
||||||
});
|
|
||||||
it("should send a message with the right payload data", () => {
|
|
||||||
ASRouterUtils.sendTelemetry({ id: 1, event: "CLICK" });
|
|
||||||
|
|
||||||
assert.calledOnce(globals.ASRouterMessage);
|
|
||||||
assert.calledWith(globals.ASRouterMessage, {
|
|
||||||
type: "AS_ROUTER_TELEMETRY_USER_EVENT",
|
|
||||||
meta: { from: "ActivityStream:Content", to: "ActivityStream:Main" },
|
|
||||||
data: {
|
|
||||||
id: 1,
|
|
||||||
event: "CLICK",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("ASRouterUISurface", () => {
|
|
||||||
let wrapper;
|
|
||||||
let globalOverrider;
|
|
||||||
let sandbox;
|
|
||||||
let headerPortal;
|
|
||||||
let footerPortal;
|
|
||||||
let root;
|
|
||||||
let fakeDocument;
|
|
||||||
let globals;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
headerPortal = document.createElement("div");
|
|
||||||
footerPortal = document.createElement("div");
|
|
||||||
root = document.createElement("div");
|
|
||||||
sandbox.stub(footerPortal, "querySelector").returns(footerPortal);
|
|
||||||
fakeDocument = {
|
|
||||||
location: { href: "" },
|
|
||||||
_listeners: new Set(),
|
|
||||||
_visibilityState: "hidden",
|
|
||||||
head: {
|
|
||||||
appendChild(el) {
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
get visibilityState() {
|
|
||||||
return this._visibilityState;
|
|
||||||
},
|
|
||||||
set visibilityState(value) {
|
|
||||||
if (this._visibilityState === value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._visibilityState = value;
|
|
||||||
this._listeners.forEach(l => l());
|
|
||||||
},
|
|
||||||
addEventListener(event, listener) {
|
|
||||||
this._listeners.add(listener);
|
|
||||||
},
|
|
||||||
removeEventListener(event, listener) {
|
|
||||||
this._listeners.delete(listener);
|
|
||||||
},
|
|
||||||
get body() {
|
|
||||||
return document.createElement("body");
|
|
||||||
},
|
|
||||||
getElementById(id) {
|
|
||||||
switch (id) {
|
|
||||||
case "header-asrouter-container":
|
|
||||||
return headerPortal;
|
|
||||||
case "root":
|
|
||||||
return root;
|
|
||||||
default:
|
|
||||||
return footerPortal;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
createElement(tag) {
|
|
||||||
return document.createElement(tag);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
globals = {
|
|
||||||
ASRouterMessage: sandbox.stub().resolves(),
|
|
||||||
ASRouterAddParentListener: sandbox.stub(),
|
|
||||||
ASRouterRemoveParentListener: sandbox.stub(),
|
|
||||||
fetch: sandbox.stub().resolves({
|
|
||||||
ok: true,
|
|
||||||
status: 200,
|
|
||||||
json: () => Promise.resolve({}),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
globalOverrider = new GlobalOverrider();
|
|
||||||
globalOverrider.set(globals);
|
|
||||||
sandbox.stub(ASRouterUtils, "sendTelemetry");
|
|
||||||
|
|
||||||
wrapper = mount(<ASRouterUISurface document={fakeDocument} />);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
globalOverrider.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render the component if a message id is defined", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.isTrue(wrapper.exists());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should pass in the correct form_method for newsletter snippets", () => {
|
|
||||||
wrapper.setState({ message: FAKE_NEWSLETTER_SNIPPET });
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.find("SubmitFormSnippet").exists());
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.find("SubmitFormSnippet").props(),
|
|
||||||
"form_method",
|
|
||||||
"POST"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should pass in the correct form_method for fxa snippets", () => {
|
|
||||||
wrapper.setState({ message: FAKE_FXA_SNIPPET });
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.find("SubmitFormSnippet").exists());
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.find("SubmitFormSnippet").props(),
|
|
||||||
"form_method",
|
|
||||||
"GET"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render a preview banner if message provider is preview", () => {
|
|
||||||
wrapper.setState({ message: { ...FAKE_MESSAGE, provider: "preview" } });
|
|
||||||
assert.isTrue(wrapper.find(".snippets-preview-banner").exists());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not render a preview banner if message provider is not preview", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.isFalse(wrapper.find(".snippets-preview-banner").exists());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render a SimpleSnippet in the footer portal", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.isTrue(footerPortal.childElementCount > 0);
|
|
||||||
assert.equal(headerPortal.childElementCount, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not render a SimpleBelowSearchSnippet in a portal", () => {
|
|
||||||
wrapper.setState({ message: FAKE_BELOW_SEARCH_SNIPPET });
|
|
||||||
assert.equal(headerPortal.childElementCount, 0);
|
|
||||||
assert.equal(footerPortal.childElementCount, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should dispatch an event to select the correct theme", () => {
|
|
||||||
const stub = sandbox.stub(window, "dispatchEvent");
|
|
||||||
sandbox
|
|
||||||
.stub(ASRouterUtils, "getPreviewEndpoint")
|
|
||||||
.returns({ theme: "dark" });
|
|
||||||
|
|
||||||
wrapper = mount(<ASRouterUISurface document={fakeDocument} />);
|
|
||||||
|
|
||||||
assert.calledOnce(stub);
|
|
||||||
assert.property(stub.firstCall.args[0].detail.data, "ntp_background");
|
|
||||||
assert.property(stub.firstCall.args[0].detail.data, "ntp_text");
|
|
||||||
assert.property(stub.firstCall.args[0].detail.data, "sidebar");
|
|
||||||
assert.property(stub.firstCall.args[0].detail.data, "sidebar_text");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set `dir=rtl` on the page's <html> element if the dir param is set", () => {
|
|
||||||
assert.notPropertyVal(fakeDocument, "dir", "rtl");
|
|
||||||
sandbox.stub(ASRouterUtils, "getPreviewEndpoint").returns({ dir: "rtl" });
|
|
||||||
|
|
||||||
wrapper = mount(<ASRouterUISurface document={fakeDocument} />);
|
|
||||||
assert.propertyVal(fakeDocument, "dir", "rtl");
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("snippets", () => {
|
|
||||||
it("should send correct event and source when snippet is blocked", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
|
|
||||||
wrapper.find(".blockButton").simulate("click");
|
|
||||||
assert.propertyVal(
|
|
||||||
ASRouterUtils.sendTelemetry.firstCall.args[0],
|
|
||||||
"event",
|
|
||||||
"BLOCK"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
|
||||||
ASRouterUtils.sendTelemetry.firstCall.args[0],
|
|
||||||
"source",
|
|
||||||
"NEWTAB_FOOTER_BAR"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not send telemetry when a preview snippet is blocked", () => {
|
|
||||||
wrapper.setState({ message: { ...FAKE_MESSAGE, provider: "preview" } });
|
|
||||||
|
|
||||||
wrapper.find(".blockButton").simulate("click");
|
|
||||||
assert.notCalled(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("impressions", () => {
|
|
||||||
function simulateVisibilityChange(value) {
|
|
||||||
fakeDocument.visibilityState = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
it("should call blockById after CTA link is clicked", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
sandbox.stub(ASRouterUtils, "blockById").resolves();
|
|
||||||
wrapper.instance().sendClick({ target: { dataset: { metric: "" } } });
|
|
||||||
|
|
||||||
assert.calledOnce(ASRouterUtils.blockById);
|
|
||||||
assert.calledWith(ASRouterUtils.blockById, FAKE_MESSAGE.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should executeAction if defined on the anchor", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
sandbox.spy(ASRouterUtils, "executeAction");
|
|
||||||
wrapper.instance().sendClick({
|
|
||||||
target: { dataset: { action: "OPEN_MENU", args: "appMenu" } },
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.calledOnce(ASRouterUtils.executeAction);
|
|
||||||
assert.calledWithExactly(ASRouterUtils.executeAction, {
|
|
||||||
type: "OPEN_MENU",
|
|
||||||
data: { args: "appMenu" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not call blockById if do_not_autoblock is true", () => {
|
|
||||||
wrapper.setState({
|
|
||||||
message: {
|
|
||||||
...FAKE_MESSAGE,
|
|
||||||
...{ content: { ...FAKE_MESSAGE.content, do_not_autoblock: true } },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
sandbox.stub(ASRouterUtils, "blockById");
|
|
||||||
wrapper.instance().sendClick({ target: { dataset: { metric: "" } } });
|
|
||||||
|
|
||||||
assert.notCalled(ASRouterUtils.blockById);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not send an impression if no message exists", () => {
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
|
|
||||||
assert.notCalled(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not send an impression if the page is not visible", () => {
|
|
||||||
simulateVisibilityChange("hidden");
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
|
|
||||||
assert.notCalled(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not send an impression for a preview message", () => {
|
|
||||||
wrapper.setState({ message: { ...FAKE_MESSAGE, provider: "preview" } });
|
|
||||||
assert.notCalled(ASRouterUtils.sendTelemetry);
|
|
||||||
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
assert.notCalled(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should send an impression ping when there is a message and the page becomes visible", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.notCalled(ASRouterUtils.sendTelemetry);
|
|
||||||
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should send the correct impression source", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
assert.propertyVal(
|
|
||||||
ASRouterUtils.sendTelemetry.firstCall.args[0],
|
|
||||||
"event",
|
|
||||||
"IMPRESSION"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
|
||||||
ASRouterUtils.sendTelemetry.firstCall.args[0],
|
|
||||||
"source",
|
|
||||||
"NEWTAB_FOOTER_BAR"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should send an impression ping when the page is visible and a message gets loaded", () => {
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
wrapper.setState({ message: {} });
|
|
||||||
assert.notCalled(ASRouterUtils.sendTelemetry);
|
|
||||||
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should send another impression ping if the message id changes", () => {
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
|
|
||||||
wrapper.setState({ message: FAKE_LOCAL_MESSAGES[1] });
|
|
||||||
assert.calledTwice(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not send another impression ping if the message id has not changed", () => {
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
|
|
||||||
wrapper.setState({ somethingElse: 123 });
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not send another impression ping if the message is cleared", () => {
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
|
|
||||||
wrapper.setState({ message: {} });
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call .sendTelemetry with the right message data", () => {
|
|
||||||
simulateVisibilityChange("visible");
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
|
|
||||||
assert.calledOnce(ASRouterUtils.sendTelemetry);
|
|
||||||
const [payload] = ASRouterUtils.sendTelemetry.firstCall.args;
|
|
||||||
|
|
||||||
assert.propertyVal(payload, "message_id", FAKE_MESSAGE.id);
|
|
||||||
assert.propertyVal(payload, "event", "IMPRESSION");
|
|
||||||
assert.propertyVal(
|
|
||||||
payload,
|
|
||||||
"action",
|
|
||||||
`${FAKE_MESSAGE.provider}_user_event`
|
|
||||||
);
|
|
||||||
assert.propertyVal(payload, "source", "NEWTAB_FOOTER_BAR");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should construct a OPEN_ABOUT_PAGE action with attribution", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
const stub = sandbox.stub(ASRouterUtils, "executeAction");
|
|
||||||
|
|
||||||
wrapper.instance().sendClick({
|
|
||||||
target: {
|
|
||||||
dataset: {
|
|
||||||
metric: "",
|
|
||||||
entrypoint_value: "snippet",
|
|
||||||
action: "OPEN_PREFERENCES_PAGE",
|
|
||||||
args: "home",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.calledOnce(stub);
|
|
||||||
assert.calledWithExactly(stub, {
|
|
||||||
type: "OPEN_PREFERENCES_PAGE",
|
|
||||||
data: { args: "home", entrypoint: "snippet" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should construct a OPEN_ABOUT_PAGE action with attribution", () => {
|
|
||||||
wrapper.setState({ message: FAKE_MESSAGE });
|
|
||||||
const stub = sandbox.stub(ASRouterUtils, "executeAction");
|
|
||||||
|
|
||||||
wrapper.instance().sendClick({
|
|
||||||
target: {
|
|
||||||
dataset: {
|
|
||||||
metric: "",
|
|
||||||
entrypoint_name: "entryPoint",
|
|
||||||
entrypoint_value: "snippet",
|
|
||||||
action: "OPEN_ABOUT_PAGE",
|
|
||||||
args: "logins",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.calledOnce(stub);
|
|
||||||
assert.calledWithExactly(stub, {
|
|
||||||
type: "OPEN_ABOUT_PAGE",
|
|
||||||
data: { args: "logins", entrypoint: "entryPoint=snippet" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(".fetchFlowParams", () => {
|
|
||||||
let dispatchStub;
|
|
||||||
const assertCalledWithURL = url =>
|
|
||||||
assert.calledWith(globals.fetch, new URL(url).toString(), {
|
|
||||||
credentials: "omit",
|
|
||||||
});
|
|
||||||
beforeEach(() => {
|
|
||||||
dispatchStub = sandbox.stub();
|
|
||||||
wrapper = mount(
|
|
||||||
<ASRouterUISurface
|
|
||||||
dispatch={dispatchStub}
|
|
||||||
fxaEndpoint="https://accounts.firefox.com"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should use the base url returned from the endpoint pref", async () => {
|
|
||||||
wrapper = mount(
|
|
||||||
<ASRouterUISurface
|
|
||||||
dispatch={dispatchStub}
|
|
||||||
fxaEndpoint="https://foo.com"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
await wrapper.instance().fetchFlowParams();
|
|
||||||
|
|
||||||
assertCalledWithURL("https://foo.com/metrics-flow");
|
|
||||||
});
|
|
||||||
it("should add given search params to the URL", async () => {
|
|
||||||
const params = { foo: "1", bar: "2" };
|
|
||||||
|
|
||||||
await wrapper.instance().fetchFlowParams(params);
|
|
||||||
|
|
||||||
assertCalledWithURL(
|
|
||||||
"https://accounts.firefox.com/metrics-flow?foo=1&bar=2"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should return flowId, flowBeginTime, deviceId on a 200 response", async () => {
|
|
||||||
const flowInfo = { flowId: "foo", flowBeginTime: 123, deviceId: "bar" };
|
|
||||||
globals.fetch
|
|
||||||
.withArgs("https://accounts.firefox.com/metrics-flow")
|
|
||||||
.resolves({
|
|
||||||
ok: true,
|
|
||||||
status: 200,
|
|
||||||
json: () => Promise.resolve(flowInfo),
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await wrapper.instance().fetchFlowParams();
|
|
||||||
assert.deepEqual(result, flowInfo);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(".onUserAction", () => {
|
|
||||||
it("if the action.type is ENABLE_FIREFOX_MONITOR, it should generate the right monitor URL given some flowParams", async () => {
|
|
||||||
const flowInfo = { flowId: "foo", flowBeginTime: 123, deviceId: "bar" };
|
|
||||||
globals.fetch
|
|
||||||
.withArgs(
|
|
||||||
"https://accounts.firefox.com/metrics-flow?utm_term=avocado"
|
|
||||||
)
|
|
||||||
.resolves({
|
|
||||||
ok: true,
|
|
||||||
status: 200,
|
|
||||||
json: () => Promise.resolve(flowInfo),
|
|
||||||
});
|
|
||||||
|
|
||||||
sandbox.spy(ASRouterUtils, "executeAction");
|
|
||||||
|
|
||||||
const msg = {
|
|
||||||
type: "ENABLE_FIREFOX_MONITOR",
|
|
||||||
data: {
|
|
||||||
args: {
|
|
||||||
url: "https://monitor.firefox.com?foo=bar",
|
|
||||||
flowRequestParams: {
|
|
||||||
utm_term: "avocado",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
await wrapper.instance().onUserAction(msg);
|
|
||||||
|
|
||||||
assertCalledWithURL(
|
|
||||||
"https://accounts.firefox.com/metrics-flow?utm_term=avocado"
|
|
||||||
);
|
|
||||||
assert.calledWith(ASRouterUtils.executeAction, {
|
|
||||||
type: "OPEN_URL",
|
|
||||||
data: {
|
|
||||||
args: new URL(
|
|
||||||
"https://monitor.firefox.com?foo=bar&deviceId=bar&flowId=foo&flowBeginTime=123"
|
|
||||||
).toString(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it("if the action.type is not ENABLE_FIREFOX_MONITOR, it should just call ASRouterUtils.executeAction", async () => {
|
|
||||||
const msg = {
|
|
||||||
type: "FOO",
|
|
||||||
data: {
|
|
||||||
args: "bar",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
sandbox.spy(ASRouterUtils, "executeAction");
|
|
||||||
await wrapper.instance().onUserAction(msg);
|
|
||||||
assert.calledWith(ASRouterUtils.executeAction, msg);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
import EOYSnippetSchema from "content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json";
|
|
||||||
import { expectedValues } from "./snippets-fx57";
|
|
||||||
import SimpleSnippetSchema from "content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json";
|
|
||||||
import SubmitFormSchema from "content-src/asrouter/templates/SubmitFormSnippet/SubmitFormSnippet.schema.json";
|
|
||||||
|
|
||||||
export const SnippetsSchemas = {
|
|
||||||
eoy_snippet: EOYSnippetSchema,
|
|
||||||
simple_snippet: SimpleSnippetSchema,
|
|
||||||
newsletter_snippet: SubmitFormSchema,
|
|
||||||
fxa_signup_snippet: SubmitFormSchema,
|
|
||||||
send_to_device_snippet: SubmitFormSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("Firefox 57 compatibility test", () => {
|
|
||||||
Object.keys(expectedValues).forEach(template => {
|
|
||||||
describe(template, () => {
|
|
||||||
const schema = SnippetsSchemas[template];
|
|
||||||
it(`should have a schema for ${template}`, () => {
|
|
||||||
assert.ok(schema);
|
|
||||||
});
|
|
||||||
it(`should validate with the schema for ${template}`, () => {
|
|
||||||
assert.jsonSchema(expectedValues[template], schema);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
/**
|
|
||||||
* IMPORTANT NOTE!!!
|
|
||||||
*
|
|
||||||
* Please DO NOT introduce breaking changes file without contacting snippets endpoint engineers
|
|
||||||
* and changing the schema version to reflect a breaking change.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
const DATA_URI_IMAGE =
|
|
||||||
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
||||||
|
|
||||||
export const expectedValues = {
|
|
||||||
// Simple Snippet (https://github.com/mozmeao/snippets/blob/master/activity-stream/simple-snippet.html)
|
|
||||||
simple_snippet: {
|
|
||||||
icon: DATA_URI_IMAGE,
|
|
||||||
button_label: "Click me",
|
|
||||||
button_url: "https://mozilla.org",
|
|
||||||
button_background_color: "#FF0000",
|
|
||||||
button_color: "#FFFFFF",
|
|
||||||
text: "Hello world",
|
|
||||||
title: "Hi!",
|
|
||||||
title_icon: DATA_URI_IMAGE,
|
|
||||||
tall: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
// FXA Snippet (https://github.com/mozmeao/snippets/blob/master/activity-stream/fxa.html)
|
|
||||||
fxa_signup_snippet: {
|
|
||||||
scene1_icon: DATA_URI_IMAGE,
|
|
||||||
scene1_button_label: "Click me",
|
|
||||||
scene1_button_background_color: "#FF0000",
|
|
||||||
scene1_button_color: "#FFFFFF",
|
|
||||||
scene1_text: "Hello <em>world</em>",
|
|
||||||
scene1_title: "Hi!",
|
|
||||||
scene1_title_icon: DATA_URI_IMAGE,
|
|
||||||
|
|
||||||
scene2_text: "Second scene",
|
|
||||||
scene2_title: "Second scene title",
|
|
||||||
scene2_email_placeholder_text: "Email here",
|
|
||||||
scene2_button_label: "Sign Me Up",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
|
|
||||||
utm_campaign: "snippets123",
|
|
||||||
utm_term: "123term",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Send To Device Snippet (https://github.com/mozmeao/snippets/blob/master/activity-stream/send-to-device.html)
|
|
||||||
send_to_device_snippet: {
|
|
||||||
include_sms: true,
|
|
||||||
locale: "de",
|
|
||||||
country: "DE",
|
|
||||||
message_id_sms: "foo",
|
|
||||||
message_id_email: "foo",
|
|
||||||
scene1_button_background_color: "#FF0000",
|
|
||||||
scene1_button_color: "#FFFFFF",
|
|
||||||
scene1_button_label: "Click me",
|
|
||||||
scene1_icon: DATA_URI_IMAGE,
|
|
||||||
scene1_text: "Hello world",
|
|
||||||
scene1_title: "Hi!",
|
|
||||||
scene1_title_icon: DATA_URI_IMAGE,
|
|
||||||
|
|
||||||
scene2_button_label: "Sign Me Up",
|
|
||||||
scene2_disclaimer_html: "Hello <em>world</em>",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
scene2_icon: DATA_URI_IMAGE,
|
|
||||||
scene2_input_placeholder: "Email here",
|
|
||||||
|
|
||||||
scene2_text: "Second scene",
|
|
||||||
scene2_title: "Second scene title",
|
|
||||||
|
|
||||||
error_text: "error",
|
|
||||||
success_text: "all good",
|
|
||||||
success_title: "Ok!",
|
|
||||||
},
|
|
||||||
|
|
||||||
// Newsletter Snippet (https://github.com/mozmeao/snippets/blob/master/activity-stream/newsletter-subscribe.html)
|
|
||||||
newsletter_snippet: {
|
|
||||||
scene1_icon: DATA_URI_IMAGE,
|
|
||||||
scene1_button_label: "Click me",
|
|
||||||
scene1_button_background_color: "#FF0000",
|
|
||||||
scene1_button_color: "#FFFFFF",
|
|
||||||
scene1_text: "Hello world",
|
|
||||||
scene1_title: "Hi!",
|
|
||||||
scene1_title_icon: DATA_URI_IMAGE,
|
|
||||||
|
|
||||||
scene2_text: "Second scene",
|
|
||||||
scene2_title: "Second scene title",
|
|
||||||
scene2_newsletter: "foo",
|
|
||||||
scene2_email_placeholder_text: "Email here",
|
|
||||||
scene2_button_label: "Sign Me Up",
|
|
||||||
scene2_privacy_html: "Hello <em>world</em>",
|
|
||||||
scene2_dismiss_button_text: "Dismiss",
|
|
||||||
|
|
||||||
locale: "de",
|
|
||||||
|
|
||||||
error_text: "error",
|
|
||||||
success_text: "all good",
|
|
||||||
},
|
|
||||||
|
|
||||||
// EOY Snippet (https://github.com/mozmeao/snippets/blob/master/activity-stream/mofo-eoy-2017.html)
|
|
||||||
eoy_snippet: {
|
|
||||||
block_button_text: "Block",
|
|
||||||
|
|
||||||
donation_form_url: "https://donate.mozilla.org/",
|
|
||||||
text: "Big corporations want to restrict how we access the web. Fake news is making it harder for us to find the truth. Online bullies are silencing inspired voices. The not-for-profit Mozilla Foundation fights for a healthy internet with programs like our Tech Policy Fellowships and Internet Health Report; will you donate today?",
|
|
||||||
icon: DATA_URI_IMAGE,
|
|
||||||
button_label: "Donate",
|
|
||||||
monthly_checkbox_label_text: "Make my donation monthly",
|
|
||||||
button_background_color: "#0060DF",
|
|
||||||
button_color: "#FFFFFF",
|
|
||||||
background_color: "#FFFFFF",
|
|
||||||
text_color: "#000000",
|
|
||||||
highlight_color: "#FFE900",
|
|
||||||
|
|
||||||
locale: "en-US",
|
|
||||||
currency_code: "usd",
|
|
||||||
|
|
||||||
donation_amount_first: 50,
|
|
||||||
donation_amount_second: 25,
|
|
||||||
donation_amount_third: 10,
|
|
||||||
donation_amount_fourth: 3,
|
|
||||||
selected_button: "donation_amount_second",
|
|
||||||
|
|
||||||
test: "bold",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -4,22 +4,19 @@ export const PARENT_TO_CHILD_MESSAGE_NAME = "ASRouter:parent-to-child";
|
||||||
export const FAKE_LOCAL_MESSAGES = [
|
export const FAKE_LOCAL_MESSAGES = [
|
||||||
{
|
{
|
||||||
id: "foo",
|
id: "foo",
|
||||||
provider: "snippets",
|
template: "milestone_message",
|
||||||
template: "simple_snippet",
|
|
||||||
content: { title: "Foo", body: "Foo123" },
|
content: { title: "Foo", body: "Foo123" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "foo1",
|
id: "foo1",
|
||||||
template: "simple_snippet",
|
template: "fancy_template",
|
||||||
provider: "snippets",
|
|
||||||
bundled: 2,
|
bundled: 2,
|
||||||
order: 1,
|
order: 1,
|
||||||
content: { title: "Foo1", body: "Foo123-1" },
|
content: { title: "Foo1", body: "Foo123-1" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "foo2",
|
id: "foo2",
|
||||||
template: "simple_snippet",
|
template: "fancy_template",
|
||||||
provider: "snippets",
|
|
||||||
bundled: 2,
|
bundled: 2,
|
||||||
order: 2,
|
order: 2,
|
||||||
content: { title: "Foo2", body: "Foo123-2" },
|
content: { title: "Foo2", body: "Foo123-2" },
|
||||||
|
|
@ -32,20 +29,17 @@ export const FAKE_LOCAL_MESSAGES = [
|
||||||
{ id: "baz", content: { title: "Foo", body: "Foo123" } },
|
{ id: "baz", content: { title: "Foo", body: "Foo123" } },
|
||||||
{
|
{
|
||||||
id: "newsletter",
|
id: "newsletter",
|
||||||
provider: "snippets",
|
template: "fancy_template",
|
||||||
template: "newsletter_snippet",
|
|
||||||
content: { title: "Foo", body: "Foo123" },
|
content: { title: "Foo", body: "Foo123" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "fxa",
|
id: "fxa",
|
||||||
provider: "snippets",
|
template: "fancy_template",
|
||||||
template: "fxa_signup_snippet",
|
|
||||||
content: { title: "Foo", body: "Foo123" },
|
content: { title: "Foo", body: "Foo123" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "belowsearch",
|
id: "belowsearch",
|
||||||
provider: "snippets",
|
template: "fancy_template",
|
||||||
template: "simple_below_search_snippet",
|
|
||||||
content: { text: "Foo" },
|
content: { text: "Foo" },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -65,7 +59,7 @@ export const FAKE_LOCAL_PROVIDERS = {
|
||||||
export const FAKE_REMOTE_MESSAGES = [
|
export const FAKE_REMOTE_MESSAGES = [
|
||||||
{
|
{
|
||||||
id: "qux",
|
id: "qux",
|
||||||
template: "simple_snippet",
|
template: "fancy_template",
|
||||||
content: { title: "Qux", body: "hello world" },
|
content: { title: "Qux", body: "hello world" },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,213 +0,0 @@
|
||||||
import { EOYSnippet } from "content-src/asrouter/templates/EOYSnippet/EOYSnippet";
|
|
||||||
import { GlobalOverrider } from "test/unit/utils";
|
|
||||||
import { mount } from "enzyme";
|
|
||||||
import React from "react";
|
|
||||||
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
||||||
import { LocalizationProvider, ReactLocalization } from "@fluent/react";
|
|
||||||
import schema from "content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json";
|
|
||||||
|
|
||||||
const DEFAULT_CONTENT = {
|
|
||||||
text: "foo",
|
|
||||||
donation_amount_first: 50,
|
|
||||||
donation_amount_second: 25,
|
|
||||||
donation_amount_third: 10,
|
|
||||||
donation_amount_fourth: 5,
|
|
||||||
donation_form_url: "https://submit.form",
|
|
||||||
button_label: "Donate",
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("EOYSnippet", () => {
|
|
||||||
let sandbox;
|
|
||||||
let wrapper;
|
|
||||||
|
|
||||||
function mockL10nWrapper(content) {
|
|
||||||
const bundle = new FluentBundle("en-US");
|
|
||||||
for (const [id, value] of Object.entries(content)) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
bundle.addResource(new FluentResource(`${id} = ${value}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const l10n = new ReactLocalization([bundle]);
|
|
||||||
return {
|
|
||||||
wrappingComponent: LocalizationProvider,
|
|
||||||
wrappingComponentProps: { l10n },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mountAndCheckProps - Mounts a EOYSnippet with DEFAULT_CONTENT extended with any props
|
|
||||||
* passed in the content param and validates props against the schema.
|
|
||||||
* @param {obj} content Object containing custom message content (e.g. {text, icon, title})
|
|
||||||
* @returns enzyme wrapper for EOYSnippet
|
|
||||||
*/
|
|
||||||
function mountAndCheckProps(content = {}, provider = "test-provider") {
|
|
||||||
const props = {
|
|
||||||
content: Object.assign({}, DEFAULT_CONTENT, content),
|
|
||||||
provider,
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
onBlock: sandbox.stub(),
|
|
||||||
sendClick: sandbox.stub(),
|
|
||||||
};
|
|
||||||
const comp = mount(
|
|
||||||
<EOYSnippet {...props} />,
|
|
||||||
mockL10nWrapper(props.content)
|
|
||||||
);
|
|
||||||
// Check schema with the final props the component receives (including defaults)
|
|
||||||
assert.jsonSchema(comp.children().get(0).props.content, schema);
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
wrapper = mountAndCheckProps();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have the correct defaults", () => {
|
|
||||||
wrapper = mountAndCheckProps();
|
|
||||||
// SendToDeviceSnippet is a wrapper around SubmitFormSnippet
|
|
||||||
const { props } = wrapper.children().get(0);
|
|
||||||
|
|
||||||
const defaultProperties = Object.keys(schema.properties).filter(
|
|
||||||
prop => schema.properties[prop].default
|
|
||||||
);
|
|
||||||
assert.lengthOf(defaultProperties, 4);
|
|
||||||
defaultProperties.forEach(prop =>
|
|
||||||
assert.propertyVal(props.content, prop, schema.properties[prop].default)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render 4 donation options", () => {
|
|
||||||
assert.lengthOf(wrapper.find("input[type='radio']"), 4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have a data-metric field", () => {
|
|
||||||
assert.ok(wrapper.find("form[data-metric='EOYSnippetForm']").exists());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should select the second donation option", () => {
|
|
||||||
wrapper = mountAndCheckProps({ selected_button: "donation_amount_second" });
|
|
||||||
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.find("input[type='radio']").get(1).props,
|
|
||||||
"defaultChecked",
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set frequency value to monthly", () => {
|
|
||||||
const form = wrapper.find("form").instance();
|
|
||||||
assert.equal(form.querySelector("[name='frequency']").value, "single");
|
|
||||||
|
|
||||||
form.querySelector("#monthly-checkbox").checked = true;
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
|
|
||||||
assert.equal(form.querySelector("[name='frequency']").value, "monthly");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should block after submitting the form", () => {
|
|
||||||
const onBlockStub = sandbox.stub();
|
|
||||||
wrapper.setProps({ onBlock: onBlockStub });
|
|
||||||
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
|
|
||||||
assert.calledOnce(onBlockStub);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not block if do_not_autoblock is true", () => {
|
|
||||||
const onBlockStub = sandbox.stub();
|
|
||||||
wrapper = mountAndCheckProps({ do_not_autoblock: true });
|
|
||||||
wrapper.setProps({ onBlock: onBlockStub });
|
|
||||||
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
|
|
||||||
assert.notCalled(onBlockStub);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should report form submissions", () => {
|
|
||||||
wrapper = mountAndCheckProps();
|
|
||||||
const { sendClick } = wrapper.props();
|
|
||||||
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
|
|
||||||
assert.calledOnce(sendClick);
|
|
||||||
assert.equal(
|
|
||||||
sendClick.firstCall.args[0].target.dataset.metric,
|
|
||||||
"EOYSnippetForm"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("it should preserve URL GET params as hidden inputs", () => {
|
|
||||||
wrapper = mountAndCheckProps({
|
|
||||||
donation_form_url:
|
|
||||||
"https://donate.mozilla.org/pl/?utm_source=desktop-snippet&utm_medium=snippet&utm_campaign=donate&utm_term=7556",
|
|
||||||
});
|
|
||||||
|
|
||||||
const hiddenInputs = wrapper.find("input[type='hidden']");
|
|
||||||
|
|
||||||
assert.propertyVal(
|
|
||||||
hiddenInputs.find("[name='utm_source']").props(),
|
|
||||||
"value",
|
|
||||||
"desktop-snippet"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
|
||||||
hiddenInputs.find("[name='amp;utm_medium']").props(),
|
|
||||||
"value",
|
|
||||||
"snippet"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
|
||||||
hiddenInputs.find("[name='amp;utm_campaign']").props(),
|
|
||||||
"value",
|
|
||||||
"donate"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
|
||||||
hiddenInputs.find("[name='amp;utm_term']").props(),
|
|
||||||
"value",
|
|
||||||
"7556"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("locale", () => {
|
|
||||||
let stub;
|
|
||||||
let globals;
|
|
||||||
beforeEach(() => {
|
|
||||||
globals = new GlobalOverrider();
|
|
||||||
stub = sandbox.stub().returns({ format: () => {} });
|
|
||||||
|
|
||||||
globals = new GlobalOverrider();
|
|
||||||
globals.set({ Intl: { NumberFormat: stub } });
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
globals.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should use content.locale for Intl", () => {
|
|
||||||
// triggers component rendering and calls the function we're testing
|
|
||||||
wrapper.setProps({
|
|
||||||
content: {
|
|
||||||
locale: "locale-foo",
|
|
||||||
donation_form_url: DEFAULT_CONTENT.donation_form_url,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.calledOnce(stub);
|
|
||||||
assert.calledWithExactly(stub, "locale-foo", sinon.match.object);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should use navigator.language as locale fallback", () => {
|
|
||||||
// triggers component rendering and calls the function we're testing
|
|
||||||
wrapper.setProps({
|
|
||||||
content: {
|
|
||||||
locale: null,
|
|
||||||
donation_form_url: DEFAULT_CONTENT.donation_form_url,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.calledOnce(stub);
|
|
||||||
assert.calledWithExactly(stub, navigator.language, sinon.match.object);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
import { FXASignupSnippet } from "content-src/asrouter/templates/FXASignupSnippet/FXASignupSnippet";
|
|
||||||
import { mount } from "enzyme";
|
|
||||||
import React from "react";
|
|
||||||
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
||||||
import { LocalizationProvider, ReactLocalization } from "@fluent/react";
|
|
||||||
import schema from "content-src/asrouter/templates/FXASignupSnippet/FXASignupSnippet.schema.json";
|
|
||||||
import { SnippetsTestMessageProvider } from "lib/SnippetsTestMessageProvider.sys.mjs";
|
|
||||||
|
|
||||||
describe("FXASignupSnippet", () => {
|
|
||||||
let DEFAULT_CONTENT;
|
|
||||||
let sandbox;
|
|
||||||
|
|
||||||
function mockL10nWrapper(content) {
|
|
||||||
const bundle = new FluentBundle("en-US");
|
|
||||||
for (const [id, value] of Object.entries(content)) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
bundle.addResource(new FluentResource(`${id} = ${value}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const l10n = new ReactLocalization([bundle]);
|
|
||||||
return {
|
|
||||||
wrappingComponent: LocalizationProvider,
|
|
||||||
wrappingComponentProps: { l10n },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mountAndCheckProps(content = {}) {
|
|
||||||
const props = {
|
|
||||||
id: "foo123",
|
|
||||||
content: Object.assign(
|
|
||||||
{ utm_campaign: "foo", utm_term: "bar" },
|
|
||||||
DEFAULT_CONTENT,
|
|
||||||
content
|
|
||||||
),
|
|
||||||
onBlock() {},
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
const comp = mount(
|
|
||||||
<FXASignupSnippet {...props} />,
|
|
||||||
mockL10nWrapper(props.content)
|
|
||||||
);
|
|
||||||
// Check schema with the final props the component receives (including defaults)
|
|
||||||
assert.jsonSchema(comp.children().get(0).props.content, schema);
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
DEFAULT_CONTENT = (await SnippetsTestMessageProvider.getMessages()).find(
|
|
||||||
msg => msg.template === "fxa_signup_snippet"
|
|
||||||
).content;
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have the correct defaults", () => {
|
|
||||||
const defaults = {
|
|
||||||
id: "foo123",
|
|
||||||
onBlock() {},
|
|
||||||
content: {},
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
const wrapper = mount(
|
|
||||||
<FXASignupSnippet {...defaults} />,
|
|
||||||
mockL10nWrapper(DEFAULT_CONTENT)
|
|
||||||
);
|
|
||||||
// FXASignupSnippet is a wrapper around SubmitFormSnippet
|
|
||||||
const { props } = wrapper.children().get(0);
|
|
||||||
|
|
||||||
const defaultProperties = Object.keys(schema.properties).filter(
|
|
||||||
prop => schema.properties[prop].default
|
|
||||||
);
|
|
||||||
assert.lengthOf(defaultProperties, 5);
|
|
||||||
defaultProperties.forEach(prop =>
|
|
||||||
assert.propertyVal(props.content, prop, schema.properties[prop].default)
|
|
||||||
);
|
|
||||||
|
|
||||||
const defaultHiddenProperties = Object.keys(
|
|
||||||
schema.properties.hidden_inputs.properties
|
|
||||||
).filter(prop => schema.properties.hidden_inputs.properties[prop].default);
|
|
||||||
assert.lengthOf(defaultHiddenProperties, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have a form_action", () => {
|
|
||||||
const wrapper = mountAndCheckProps();
|
|
||||||
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.children().get(0).props,
|
|
||||||
"form_action",
|
|
||||||
"https://accounts.firefox.com/"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should navigate to scene2", () => {
|
|
||||||
const wrapper = mountAndCheckProps({});
|
|
||||||
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
|
|
||||||
assert.lengthOf(wrapper.find(".mainInput"), 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
import { mount } from "enzyme";
|
|
||||||
import { NewsletterSnippet } from "content-src/asrouter/templates/NewsletterSnippet/NewsletterSnippet";
|
|
||||||
import React from "react";
|
|
||||||
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
||||||
import { LocalizationProvider, ReactLocalization } from "@fluent/react";
|
|
||||||
import schema from "content-src/asrouter/templates/NewsletterSnippet/NewsletterSnippet.schema.json";
|
|
||||||
import { SnippetsTestMessageProvider } from "lib/SnippetsTestMessageProvider.sys.mjs";
|
|
||||||
|
|
||||||
describe("NewsletterSnippet", () => {
|
|
||||||
let sandbox;
|
|
||||||
let DEFAULT_CONTENT;
|
|
||||||
|
|
||||||
function mockL10nWrapper(content) {
|
|
||||||
const bundle = new FluentBundle("en-US");
|
|
||||||
for (const [id, value] of Object.entries(content)) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
bundle.addResource(new FluentResource(`${id} = ${value}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const l10n = new ReactLocalization([bundle]);
|
|
||||||
return {
|
|
||||||
wrappingComponent: LocalizationProvider,
|
|
||||||
wrappingComponentProps: { l10n },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mountAndCheckProps(content = {}) {
|
|
||||||
const props = {
|
|
||||||
id: "foo123",
|
|
||||||
content: Object.assign({}, DEFAULT_CONTENT, content),
|
|
||||||
onBlock() {},
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
const comp = mount(
|
|
||||||
<NewsletterSnippet {...props} />,
|
|
||||||
mockL10nWrapper(props.content)
|
|
||||||
);
|
|
||||||
// Check schema with the final props the component receives (including defaults)
|
|
||||||
assert.jsonSchema(comp.children().get(0).props.content, schema);
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
DEFAULT_CONTENT = (await SnippetsTestMessageProvider.getMessages()).find(
|
|
||||||
msg => msg.template === "newsletter_snippet"
|
|
||||||
).content;
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("schema test", () => {
|
|
||||||
it("should validate the schema and defaults", () => {
|
|
||||||
const wrapper = mountAndCheckProps();
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
assert.equal(wrapper.find(".mainInput").instance().type, "email");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have all of the default fields", () => {
|
|
||||||
const defaults = {
|
|
||||||
id: "foo123",
|
|
||||||
content: {},
|
|
||||||
onBlock() {},
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
const wrapper = mount(
|
|
||||||
<NewsletterSnippet {...defaults} />,
|
|
||||||
mockL10nWrapper(DEFAULT_CONTENT)
|
|
||||||
);
|
|
||||||
// NewsletterSnippet is a wrapper around SubmitFormSnippet
|
|
||||||
const { props } = wrapper.children().get(0);
|
|
||||||
|
|
||||||
// the `locale` properties gets used as part of hidden_fields so we
|
|
||||||
// check for it separately
|
|
||||||
const properties = { ...schema.properties };
|
|
||||||
const { locale } = properties;
|
|
||||||
delete properties.locale;
|
|
||||||
|
|
||||||
const defaultProperties = Object.keys(properties).filter(
|
|
||||||
prop => properties[prop].default
|
|
||||||
);
|
|
||||||
assert.lengthOf(defaultProperties, 6);
|
|
||||||
defaultProperties.forEach(prop =>
|
|
||||||
assert.propertyVal(props.content, prop, properties[prop].default)
|
|
||||||
);
|
|
||||||
|
|
||||||
const defaultHiddenProperties = Object.keys(
|
|
||||||
schema.properties.hidden_inputs.properties
|
|
||||||
).filter(
|
|
||||||
prop => schema.properties.hidden_inputs.properties[prop].default
|
|
||||||
);
|
|
||||||
assert.lengthOf(defaultHiddenProperties, 1);
|
|
||||||
defaultHiddenProperties.forEach(prop =>
|
|
||||||
assert.propertyVal(
|
|
||||||
props.content.hidden_inputs,
|
|
||||||
prop,
|
|
||||||
schema.properties.hidden_inputs.properties[prop].default
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert.propertyVal(props.content.hidden_inputs, "lang", locale.default);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,277 +0,0 @@
|
||||||
import { mount } from "enzyme";
|
|
||||||
import React from "react";
|
|
||||||
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
||||||
import { LocalizationProvider, ReactLocalization } from "@fluent/react";
|
|
||||||
import schema from "content-src/asrouter/templates/SendToDeviceSnippet/SendToDeviceSnippet.schema.json";
|
|
||||||
import {
|
|
||||||
SendToDeviceSnippet,
|
|
||||||
SendToDeviceScene2Snippet,
|
|
||||||
} from "content-src/asrouter/templates/SendToDeviceSnippet/SendToDeviceSnippet";
|
|
||||||
import { SnippetsTestMessageProvider } from "lib/SnippetsTestMessageProvider.sys.mjs";
|
|
||||||
|
|
||||||
async function testBodyContains(body, key, value) {
|
|
||||||
const regex = new RegExp(
|
|
||||||
`Content-Disposition: form-data; name="${key}"${value}`
|
|
||||||
);
|
|
||||||
const match = regex.exec(body);
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simulates opening the second panel (form view), filling in the input, and submitting
|
|
||||||
* @param {EnzymeWrapper} wrapper A SendToDevice wrapper
|
|
||||||
* @param {string} value Email or phone number
|
|
||||||
* @param {function?} setCustomValidity setCustomValidity stub
|
|
||||||
*/
|
|
||||||
function openFormAndSetValue(wrapper, value, setCustomValidity = () => {}) {
|
|
||||||
// expand
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
// Fill in email
|
|
||||||
const input = wrapper.find(".mainInput");
|
|
||||||
input.instance().value = value;
|
|
||||||
input.simulate("change", { target: { value, setCustomValidity } });
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("SendToDeviceSnippet", () => {
|
|
||||||
let sandbox;
|
|
||||||
let fetchStub;
|
|
||||||
let jsonResponse;
|
|
||||||
let DEFAULT_CONTENT;
|
|
||||||
let DEFAULT_SCENE2_CONTENT;
|
|
||||||
|
|
||||||
function mockL10nWrapper(content) {
|
|
||||||
const bundle = new FluentBundle("en-US");
|
|
||||||
for (const [id, value] of Object.entries(content)) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
bundle.addResource(new FluentResource(`${id} = ${value}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const l10n = new ReactLocalization([bundle]);
|
|
||||||
return {
|
|
||||||
wrappingComponent: LocalizationProvider,
|
|
||||||
wrappingComponentProps: { l10n },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mountAndCheckProps(content = {}) {
|
|
||||||
const props = {
|
|
||||||
id: "foo123",
|
|
||||||
content: Object.assign({}, DEFAULT_CONTENT, content),
|
|
||||||
onBlock() {},
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
const comp = mount(
|
|
||||||
<SendToDeviceSnippet {...props} />,
|
|
||||||
mockL10nWrapper(props.content)
|
|
||||||
);
|
|
||||||
// Check schema with the final props the component receives (including defaults)
|
|
||||||
assert.jsonSchema(comp.children().get(0).props.content, schema);
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
DEFAULT_CONTENT = (await SnippetsTestMessageProvider.getMessages()).find(
|
|
||||||
msg => msg.template === "send_to_device_snippet"
|
|
||||||
).content;
|
|
||||||
DEFAULT_SCENE2_CONTENT = (
|
|
||||||
await SnippetsTestMessageProvider.getMessages()
|
|
||||||
).find(msg => msg.template === "send_to_device_scene2_snippet").content;
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
jsonResponse = { status: "ok" };
|
|
||||||
fetchStub = sandbox
|
|
||||||
.stub(global, "fetch")
|
|
||||||
.returns(Promise.resolve({ json: () => Promise.resolve(jsonResponse) }));
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have the correct defaults", () => {
|
|
||||||
const defaults = {
|
|
||||||
id: "foo123",
|
|
||||||
onBlock() {},
|
|
||||||
content: {},
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
form_method: "POST",
|
|
||||||
};
|
|
||||||
const wrapper = mount(
|
|
||||||
<SendToDeviceSnippet {...defaults} />,
|
|
||||||
mockL10nWrapper(DEFAULT_CONTENT)
|
|
||||||
);
|
|
||||||
// SendToDeviceSnippet is a wrapper around SubmitFormSnippet
|
|
||||||
const { props } = wrapper.children().get(0);
|
|
||||||
|
|
||||||
const defaultProperties = Object.keys(schema.properties).filter(
|
|
||||||
prop => schema.properties[prop].default
|
|
||||||
);
|
|
||||||
assert.lengthOf(defaultProperties, 7);
|
|
||||||
defaultProperties.forEach(prop =>
|
|
||||||
assert.propertyVal(props.content, prop, schema.properties[prop].default)
|
|
||||||
);
|
|
||||||
|
|
||||||
const defaultHiddenProperties = Object.keys(
|
|
||||||
schema.properties.hidden_inputs.properties
|
|
||||||
).filter(prop => schema.properties.hidden_inputs.properties[prop].default);
|
|
||||||
assert.lengthOf(defaultHiddenProperties, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("form input", () => {
|
|
||||||
it("should set the input type to text if content.include_sms is true", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ include_sms: true });
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
assert.equal(wrapper.find(".mainInput").instance().type, "text");
|
|
||||||
});
|
|
||||||
it("should set the input type to email if content.include_sms is false", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ include_sms: false });
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
assert.equal(wrapper.find(".mainInput").instance().type, "email");
|
|
||||||
});
|
|
||||||
it("should validate the input with isEmailOrPhoneNumber if include_sms is true", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ include_sms: true });
|
|
||||||
const setCustomValidity = sandbox.stub();
|
|
||||||
openFormAndSetValue(wrapper, "foo", setCustomValidity);
|
|
||||||
assert.calledWith(
|
|
||||||
setCustomValidity,
|
|
||||||
"Must be an email or a phone number."
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should not custom validate the input if include_sms is false", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ include_sms: false });
|
|
||||||
const setCustomValidity = sandbox.stub();
|
|
||||||
openFormAndSetValue(wrapper, "foo", setCustomValidity);
|
|
||||||
assert.notCalled(setCustomValidity);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("submitting", () => {
|
|
||||||
it("should send the right information to basket.mozilla.org/news/subscribe for an email", async () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
locale: "fr-CA",
|
|
||||||
include_sms: true,
|
|
||||||
message_id_email: "foo",
|
|
||||||
});
|
|
||||||
|
|
||||||
openFormAndSetValue(wrapper, "foo@bar.com");
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
|
|
||||||
assert.calledOnce(fetchStub);
|
|
||||||
const [request] = fetchStub.firstCall.args;
|
|
||||||
|
|
||||||
assert.equal(request.url, "https://basket.mozilla.org/news/subscribe/");
|
|
||||||
const body = await request.text();
|
|
||||||
assert.ok(testBodyContains(body, "email", "foo@bar.com"), "has email");
|
|
||||||
assert.ok(testBodyContains(body, "lang", "fr-CA"), "has lang");
|
|
||||||
assert.ok(
|
|
||||||
testBodyContains(body, "newsletters", "foo"),
|
|
||||||
"has newsletters"
|
|
||||||
);
|
|
||||||
assert.ok(
|
|
||||||
testBodyContains(body, "source_url", "foo"),
|
|
||||||
"https%3A%2F%2Fsnippets.mozilla.com%2Fshow%2Ffoo123"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should send the right information for an sms", async () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
locale: "fr-CA",
|
|
||||||
include_sms: true,
|
|
||||||
message_id_sms: "foo",
|
|
||||||
country: "CA",
|
|
||||||
});
|
|
||||||
|
|
||||||
openFormAndSetValue(wrapper, "5371283767");
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
|
|
||||||
assert.calledOnce(fetchStub);
|
|
||||||
const [request] = fetchStub.firstCall.args;
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
request.url,
|
|
||||||
"https://basket.mozilla.org/news/subscribe_sms/"
|
|
||||||
);
|
|
||||||
const body = await request.text();
|
|
||||||
assert.ok(
|
|
||||||
testBodyContains(body, "mobile_number", "5371283767"),
|
|
||||||
"has number"
|
|
||||||
);
|
|
||||||
assert.ok(testBodyContains(body, "lang", "fr-CA"), "has lang");
|
|
||||||
assert.ok(testBodyContains(body, "country", "CA"), "CA");
|
|
||||||
assert.ok(testBodyContains(body, "msg_name", "foo"), "has msg_name");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("SendToDeviceScene2Snippet", () => {
|
|
||||||
function mountWithProps(content = {}) {
|
|
||||||
const props = {
|
|
||||||
id: "foo123",
|
|
||||||
content: Object.assign({}, DEFAULT_SCENE2_CONTENT, content),
|
|
||||||
onBlock() {},
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
return mount(
|
|
||||||
<SendToDeviceScene2Snippet {...props} />,
|
|
||||||
mockL10nWrapper(props.content)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
it("should render scene 2", () => {
|
|
||||||
const wrapper = mountWithProps();
|
|
||||||
|
|
||||||
assert.lengthOf(wrapper.find(".scene2Icon"), 1, "Found scene 2 icon");
|
|
||||||
assert.lengthOf(
|
|
||||||
wrapper.find(".scene2Title"),
|
|
||||||
0,
|
|
||||||
"Should not have a large header"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should have block button", () => {
|
|
||||||
const wrapper = mountWithProps();
|
|
||||||
|
|
||||||
assert.lengthOf(
|
|
||||||
wrapper.find(".blockButton"),
|
|
||||||
1,
|
|
||||||
"Found the block button"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render title text", () => {
|
|
||||||
const wrapper = mountWithProps();
|
|
||||||
|
|
||||||
assert.lengthOf(
|
|
||||||
wrapper.find(".section-title-text"),
|
|
||||||
1,
|
|
||||||
"Found the section title"
|
|
||||||
);
|
|
||||||
assert.lengthOf(
|
|
||||||
wrapper.find(".section-title .icon"),
|
|
||||||
2, // light and dark theme
|
|
||||||
"Found scene 2 title"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should wrap the header in an anchor tag if condition is defined", () => {
|
|
||||||
const sectionTitleProp = {
|
|
||||||
section_title_url: "https://support.mozilla.org",
|
|
||||||
};
|
|
||||||
let wrapper = mountWithProps(sectionTitleProp);
|
|
||||||
|
|
||||||
const element = wrapper.find(".section-title a");
|
|
||||||
assert.lengthOf(element, 1);
|
|
||||||
});
|
|
||||||
it("should render a header without an anchor", () => {
|
|
||||||
const sectionTitleProp = {
|
|
||||||
section_title_url: undefined,
|
|
||||||
};
|
|
||||||
let wrapper = mountWithProps(sectionTitleProp);
|
|
||||||
assert.lengthOf(wrapper.find(".section-title a"), 0);
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".section-title").instance().innerText,
|
|
||||||
DEFAULT_SCENE2_CONTENT.section_title_text
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
import { mount } from "enzyme";
|
|
||||||
import React from "react";
|
|
||||||
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
||||||
import { LocalizationProvider, ReactLocalization } from "@fluent/react";
|
|
||||||
import schema from "content-src/asrouter/templates/SimpleBelowSearchSnippet/SimpleBelowSearchSnippet.schema.json";
|
|
||||||
import { SimpleBelowSearchSnippet } from "content-src/asrouter/templates/SimpleBelowSearchSnippet/SimpleBelowSearchSnippet.jsx";
|
|
||||||
|
|
||||||
const DEFAULT_CONTENT = { text: "foo" };
|
|
||||||
|
|
||||||
describe("SimpleBelowSearchSnippet", () => {
|
|
||||||
let sandbox;
|
|
||||||
let sendUserActionTelemetryStub;
|
|
||||||
|
|
||||||
function mockL10nWrapper(content) {
|
|
||||||
const bundle = new FluentBundle("en-US");
|
|
||||||
for (const [id, value] of Object.entries(content)) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
bundle.addResource(new FluentResource(`${id} = ${value}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const l10n = new ReactLocalization([bundle]);
|
|
||||||
return {
|
|
||||||
wrappingComponent: LocalizationProvider,
|
|
||||||
wrappingComponentProps: { l10n },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mountAndCheckProps - Mounts a SimpleBelowSearchSnippet with DEFAULT_CONTENT extended with any props
|
|
||||||
* passed in the content param and validates props against the schema.
|
|
||||||
* @param {obj} content Object containing custom message content (e.g. {text, icon})
|
|
||||||
* @returns enzyme wrapper for SimpleSnippet
|
|
||||||
*/
|
|
||||||
function mountAndCheckProps(content = {}, provider = "test-provider") {
|
|
||||||
const props = {
|
|
||||||
content: { ...DEFAULT_CONTENT, ...content },
|
|
||||||
provider,
|
|
||||||
sendUserActionTelemetry: sendUserActionTelemetryStub,
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
assert.jsonSchema(props.content, schema);
|
|
||||||
return mount(
|
|
||||||
<SimpleBelowSearchSnippet {...props} />,
|
|
||||||
mockL10nWrapper(props.content)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
sendUserActionTelemetryStub = sandbox.stub();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render .text", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ text: "bar" });
|
|
||||||
assert.equal(wrapper.find(".body").text(), "bar");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render .icon (light theme)", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
icon: "data:image/gif;base64,R0lGODl",
|
|
||||||
});
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".icon-light-theme").prop("src"),
|
|
||||||
"data:image/gif;base64,R0lGODl"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render .icon (dark theme)", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
icon_dark_theme: "data:image/gif;base64,R0lGODl",
|
|
||||||
});
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".icon-dark-theme").prop("src"),
|
|
||||||
"data:image/gif;base64,R0lGODl"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,259 +0,0 @@
|
||||||
import { mount } from "enzyme";
|
|
||||||
import React from "react";
|
|
||||||
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
||||||
import { LocalizationProvider, ReactLocalization } from "@fluent/react";
|
|
||||||
import schema from "content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json";
|
|
||||||
import { SimpleSnippet } from "content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx";
|
|
||||||
|
|
||||||
const DEFAULT_CONTENT = { text: "foo" };
|
|
||||||
|
|
||||||
describe("SimpleSnippet", () => {
|
|
||||||
let sandbox;
|
|
||||||
let onBlockStub;
|
|
||||||
let sendUserActionTelemetryStub;
|
|
||||||
|
|
||||||
function mockL10nWrapper(content) {
|
|
||||||
const bundle = new FluentBundle("en-US");
|
|
||||||
for (const [id, value] of Object.entries(content)) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
bundle.addResource(new FluentResource(`${id} = ${value}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const l10n = new ReactLocalization([bundle]);
|
|
||||||
return {
|
|
||||||
wrappingComponent: LocalizationProvider,
|
|
||||||
wrappingComponentProps: { l10n },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mountAndCheckProps - Mounts a SimpleSnippet with DEFAULT_CONTENT extended with any props
|
|
||||||
* passed in the content param and validates props against the schema.
|
|
||||||
* @param {obj} content Object containing custom message content (e.g. {text, icon, title})
|
|
||||||
* @returns enzyme wrapper for SimpleSnippet
|
|
||||||
*/
|
|
||||||
function mountAndCheckProps(content = {}, provider = "test-provider") {
|
|
||||||
const props = {
|
|
||||||
content: Object.assign({}, DEFAULT_CONTENT, content),
|
|
||||||
provider,
|
|
||||||
onBlock: onBlockStub,
|
|
||||||
sendUserActionTelemetry: sendUserActionTelemetryStub,
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
};
|
|
||||||
assert.jsonSchema(props.content, schema);
|
|
||||||
return mount(<SimpleSnippet {...props} />, mockL10nWrapper(props.content));
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
onBlockStub = sandbox.stub();
|
|
||||||
sendUserActionTelemetryStub = sandbox.stub();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should have the correct defaults", () => {
|
|
||||||
const wrapper = mountAndCheckProps();
|
|
||||||
[["button", "title", "block_button_text"]].forEach(prop => {
|
|
||||||
const props = wrapper.find(prop[0]).props();
|
|
||||||
assert.propertyVal(props, prop[1], schema.properties[prop[2]].default);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render .text", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ text: "bar" });
|
|
||||||
assert.equal(wrapper.find(".body").text(), "bar");
|
|
||||||
});
|
|
||||||
it("should not render title element if no .title prop is supplied", () => {
|
|
||||||
const wrapper = mountAndCheckProps();
|
|
||||||
assert.lengthOf(wrapper.find(".title"), 0);
|
|
||||||
});
|
|
||||||
it("should render .title", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ title: "Foo" });
|
|
||||||
assert.equal(wrapper.find(".title").text().trim(), "Foo");
|
|
||||||
});
|
|
||||||
it("should render a light theme variant .icon", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
icon: "data:image/gif;base64,R0lGODl",
|
|
||||||
});
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".icon-light-theme").prop("src"),
|
|
||||||
"data:image/gif;base64,R0lGODl"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render a dark theme variant .icon", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
icon_dark_theme: "data:image/gif;base64,R0lGODl",
|
|
||||||
});
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".icon-dark-theme").prop("src"),
|
|
||||||
"data:image/gif;base64,R0lGODl"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render a light theme variant .icon as fallback", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
icon_dark_theme: "",
|
|
||||||
icon: "data:image/gif;base64,R0lGODp",
|
|
||||||
});
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".icon-dark-theme").prop("src"),
|
|
||||||
"data:image/gif;base64,R0lGODp"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render .button_label and default className", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
button_label: "Click here",
|
|
||||||
button_action: "OPEN_APPLICATIONS_MENU",
|
|
||||||
button_action_args: "appMenu",
|
|
||||||
});
|
|
||||||
|
|
||||||
const button = wrapper.find("button.ASRouterButton");
|
|
||||||
button.simulate("click");
|
|
||||||
|
|
||||||
assert.equal(button.text(), "Click here");
|
|
||||||
assert.equal(button.prop("className"), "ASRouterButton secondary");
|
|
||||||
assert.calledOnce(wrapper.props().onAction);
|
|
||||||
assert.calledWithExactly(wrapper.props().onAction, {
|
|
||||||
type: "OPEN_APPLICATIONS_MENU",
|
|
||||||
data: { args: "appMenu" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it("should not wrap the main content if a section header is not present", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ text: "bar" });
|
|
||||||
assert.lengthOf(wrapper.find(".innerContentWrapper"), 0);
|
|
||||||
});
|
|
||||||
it("should wrap the main content if a section header is present", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
section_title_icon: "data:image/gif;base64,R0lGODl",
|
|
||||||
section_title_text: "Messages from Mozilla",
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.lengthOf(wrapper.find(".innerContentWrapper"), 1);
|
|
||||||
});
|
|
||||||
it("should render a section header if text and icon (light-theme) are specified", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
section_title_icon: "data:image/gif;base64,R0lGODl",
|
|
||||||
section_title_text: "Messages from Mozilla",
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".section-title .icon-light-theme").prop("style")
|
|
||||||
.backgroundImage,
|
|
||||||
'url("data:image/gif;base64,R0lGODl")'
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".section-title-text").text().trim(),
|
|
||||||
"Messages from Mozilla"
|
|
||||||
);
|
|
||||||
// ensure there is no <a> when a section_title_url is not specified
|
|
||||||
assert.lengthOf(wrapper.find(".section-title a"), 0);
|
|
||||||
});
|
|
||||||
it("should render a section header if text and icon (light-theme) are specified", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
section_title_icon: "data:image/gif;base64,R0lGODl",
|
|
||||||
section_title_icon_dark_theme: "data:image/gif;base64,R0lGODl",
|
|
||||||
section_title_text: "Messages from Mozilla",
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".section-title .icon-dark-theme").prop("style")
|
|
||||||
.backgroundImage,
|
|
||||||
'url("data:image/gif;base64,R0lGODl")'
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".section-title-text").text().trim(),
|
|
||||||
"Messages from Mozilla"
|
|
||||||
);
|
|
||||||
// ensure there is no <a> when a section_title_url is not specified
|
|
||||||
assert.lengthOf(wrapper.find(".section-title a"), 0);
|
|
||||||
});
|
|
||||||
it("should render a section header wrapped in an <a> tag if a url is provided", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
section_title_icon: "data:image/gif;base64,R0lGODl",
|
|
||||||
section_title_text: "Messages from Mozilla",
|
|
||||||
section_title_url: "https://www.mozilla.org",
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".section-title a").prop("href"),
|
|
||||||
"https://www.mozilla.org"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should send an OPEN_URL action when button_url is defined and button is clicked", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
button_label: "Button",
|
|
||||||
button_url: "https://mozilla.org",
|
|
||||||
});
|
|
||||||
|
|
||||||
const button = wrapper.find("button.ASRouterButton");
|
|
||||||
button.simulate("click");
|
|
||||||
|
|
||||||
assert.calledOnce(wrapper.props().onAction);
|
|
||||||
assert.calledWithExactly(wrapper.props().onAction, {
|
|
||||||
type: "OPEN_URL",
|
|
||||||
data: { args: "https://mozilla.org" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it("should send an OPEN_ABOUT_PAGE action with entrypoint when the button is clicked", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
button_label: "Button",
|
|
||||||
button_action: "OPEN_ABOUT_PAGE",
|
|
||||||
button_entrypoint_value: "snippet",
|
|
||||||
button_entrypoint_name: "entryPoint",
|
|
||||||
button_action_args: "logins",
|
|
||||||
});
|
|
||||||
|
|
||||||
const button = wrapper.find("button.ASRouterButton");
|
|
||||||
button.simulate("click");
|
|
||||||
|
|
||||||
assert.calledOnce(wrapper.props().onAction);
|
|
||||||
assert.calledWithExactly(wrapper.props().onAction, {
|
|
||||||
type: "OPEN_ABOUT_PAGE",
|
|
||||||
data: { args: "logins", entrypoint: "entryPoint=snippet" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it("should send an OPEN_PREFERENCE_PAGE action with entrypoint when the button is clicked", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
button_label: "Button",
|
|
||||||
button_action: "OPEN_PREFERENCE_PAGE",
|
|
||||||
button_entrypoint_value: "entry=snippet",
|
|
||||||
button_action_args: "home",
|
|
||||||
});
|
|
||||||
|
|
||||||
const button = wrapper.find("button.ASRouterButton");
|
|
||||||
button.simulate("click");
|
|
||||||
|
|
||||||
assert.calledOnce(wrapper.props().onAction);
|
|
||||||
assert.calledWithExactly(wrapper.props().onAction, {
|
|
||||||
type: "OPEN_PREFERENCE_PAGE",
|
|
||||||
data: { args: "home", entrypoint: "entry=snippet" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it("should call props.onBlock and sendUserActionTelemetry when CTA button is clicked", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ text: "bar" });
|
|
||||||
|
|
||||||
wrapper.instance().onButtonClick();
|
|
||||||
|
|
||||||
assert.calledOnce(onBlockStub);
|
|
||||||
assert.calledOnce(sendUserActionTelemetryStub);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not call props.onBlock if do_not_autoblock is true", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ text: "bar", do_not_autoblock: true });
|
|
||||||
|
|
||||||
wrapper.instance().onButtonClick();
|
|
||||||
|
|
||||||
assert.notCalled(onBlockStub);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not call sendUserActionTelemetry for preview message when CTA button is clicked", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ text: "bar" }, "preview");
|
|
||||||
|
|
||||||
wrapper.instance().onButtonClick();
|
|
||||||
|
|
||||||
assert.calledOnce(onBlockStub);
|
|
||||||
assert.notCalled(sendUserActionTelemetryStub);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,354 +0,0 @@
|
||||||
import { mount } from "enzyme";
|
|
||||||
import React from "react";
|
|
||||||
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
||||||
import { LocalizationProvider, ReactLocalization } from "@fluent/react";
|
|
||||||
import { RichText } from "content-src/asrouter/components/RichText/RichText.jsx";
|
|
||||||
import schema from "content-src/asrouter/templates/SubmitFormSnippet/SubmitFormSnippet.schema.json";
|
|
||||||
import { SubmitFormSnippet } from "content-src/asrouter/templates/SubmitFormSnippet/SubmitFormSnippet.jsx";
|
|
||||||
|
|
||||||
const DEFAULT_CONTENT = {
|
|
||||||
scene1_text: "foo",
|
|
||||||
scene2_text: "bar",
|
|
||||||
scene1_button_label: "Sign Up",
|
|
||||||
retry_button_label: "Try again",
|
|
||||||
form_action: "foo.com",
|
|
||||||
hidden_inputs: { foo: "foo" },
|
|
||||||
error_text: "error",
|
|
||||||
success_text: "success",
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("SubmitFormSnippet", () => {
|
|
||||||
let sandbox;
|
|
||||||
let onBlockStub;
|
|
||||||
|
|
||||||
function mockL10nWrapper(content) {
|
|
||||||
const bundle = new FluentBundle("en-US");
|
|
||||||
for (const [id, value] of Object.entries(content)) {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
bundle.addResource(new FluentResource(`${id} = ${value}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const l10n = new ReactLocalization([bundle]);
|
|
||||||
return {
|
|
||||||
wrappingComponent: LocalizationProvider,
|
|
||||||
wrappingComponentProps: { l10n },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mountAndCheckProps - Mounts a SubmitFormSnippet with DEFAULT_CONTENT extended with any props
|
|
||||||
* passed in the content param and validates props against the schema.
|
|
||||||
* @param {obj} content Object containing custom message content (e.g. {text, icon, title})
|
|
||||||
* @returns enzyme wrapper for SubmitFormSnippet
|
|
||||||
*/
|
|
||||||
function mountAndCheckProps(content = {}) {
|
|
||||||
const props = {
|
|
||||||
content: Object.assign({}, DEFAULT_CONTENT, content),
|
|
||||||
onBlock: onBlockStub,
|
|
||||||
onDismiss: sandbox.stub(),
|
|
||||||
sendUserActionTelemetry: sandbox.stub(),
|
|
||||||
onAction: sandbox.stub(),
|
|
||||||
form_method: "POST",
|
|
||||||
};
|
|
||||||
assert.jsonSchema(props.content, schema);
|
|
||||||
return mount(
|
|
||||||
<SubmitFormSnippet {...props} />,
|
|
||||||
mockL10nWrapper(props.content)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
sandbox = sinon.createSandbox();
|
|
||||||
onBlockStub = sandbox.stub();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
sandbox.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render .text", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ scene1_text: "bar" });
|
|
||||||
assert.equal(wrapper.find(".body").text(), "bar");
|
|
||||||
});
|
|
||||||
it("should not render title element if no .title prop is supplied", () => {
|
|
||||||
const wrapper = mountAndCheckProps();
|
|
||||||
assert.lengthOf(wrapper.find(".title"), 0);
|
|
||||||
});
|
|
||||||
it("should render .title", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ scene1_title: "Foo" });
|
|
||||||
assert.equal(wrapper.find(".title").text().trim(), "Foo");
|
|
||||||
});
|
|
||||||
it("should render light-theme .icon", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
scene1_icon: "data:image/gif;base64,R0lGODl",
|
|
||||||
});
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".icon-light-theme").prop("src"),
|
|
||||||
"data:image/gif;base64,R0lGODl"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render dark-theme .icon", () => {
|
|
||||||
const wrapper = mountAndCheckProps({
|
|
||||||
scene1_icon_dark_theme: "data:image/gif;base64,R0lGODl",
|
|
||||||
});
|
|
||||||
assert.equal(
|
|
||||||
wrapper.find(".icon-dark-theme").prop("src"),
|
|
||||||
"data:image/gif;base64,R0lGODl"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render .button_label and default className", () => {
|
|
||||||
const wrapper = mountAndCheckProps({ scene1_button_label: "Click here" });
|
|
||||||
|
|
||||||
const button = wrapper.find("button.ASRouterButton");
|
|
||||||
assert.equal(button.text(), "Click here");
|
|
||||||
assert.equal(button.prop("className"), "ASRouterButton secondary");
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#SignupView", () => {
|
|
||||||
let wrapper;
|
|
||||||
const fetchOk = { json: () => Promise.resolve({ status: "ok" }) };
|
|
||||||
const fetchFail = { json: () => Promise.resolve({ status: "fail" }) };
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper = mountAndCheckProps({
|
|
||||||
scene1_text: "bar",
|
|
||||||
scene2_email_placeholder_text: "Email",
|
|
||||||
scene2_text: "signup",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set the input type if provided through props.inputType", () => {
|
|
||||||
wrapper.setProps({ inputType: "number" });
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
assert.equal(wrapper.find(".mainInput").instance().type, "number");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should validate via props.validateInput if provided", () => {
|
|
||||||
function validateInput(value, content) {
|
|
||||||
if (content.country === "CA" && value === "poutine") {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return "Must be poutine";
|
|
||||||
}
|
|
||||||
const setCustomValidity = sandbox.stub();
|
|
||||||
wrapper.setProps({
|
|
||||||
validateInput,
|
|
||||||
content: { ...DEFAULT_CONTENT, country: "CA" },
|
|
||||||
});
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
const input = wrapper.find(".mainInput");
|
|
||||||
input.instance().value = "poutine";
|
|
||||||
input.simulate("change", {
|
|
||||||
target: { value: "poutine", setCustomValidity },
|
|
||||||
});
|
|
||||||
assert.calledWith(setCustomValidity, "");
|
|
||||||
|
|
||||||
input.instance().value = "fried chicken";
|
|
||||||
input.simulate("change", {
|
|
||||||
target: { value: "fried chicken", setCustomValidity },
|
|
||||||
});
|
|
||||||
assert.calledWith(setCustomValidity, "Must be poutine");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should show the signup form if state.expanded is true", () => {
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.find("form").exists());
|
|
||||||
});
|
|
||||||
it("should dismiss the snippet", () => {
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
wrapper.find(".ASRouterButton.secondary").simulate("click");
|
|
||||||
|
|
||||||
assert.calledOnce(wrapper.props().onDismiss);
|
|
||||||
});
|
|
||||||
it("should send a DISMISS event ping", () => {
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
wrapper.find(".ASRouterButton.secondary").simulate("click");
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.props().sendUserActionTelemetry.firstCall.args[0].event,
|
|
||||||
"DISMISS"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render hidden inputs + email input", () => {
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
assert.lengthOf(wrapper.find("input[type='hidden']"), 1);
|
|
||||||
});
|
|
||||||
it("should open the SignupView when the action button is clicked", () => {
|
|
||||||
assert.isFalse(wrapper.find("form").exists());
|
|
||||||
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.state().expanded);
|
|
||||||
assert.isTrue(wrapper.find("form").exists());
|
|
||||||
});
|
|
||||||
it("should submit telemetry when the action button is clicked", () => {
|
|
||||||
assert.isFalse(wrapper.find("form").exists());
|
|
||||||
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.props().sendUserActionTelemetry.firstCall.args[0].event_context,
|
|
||||||
"scene1-button-learn-more"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should submit form data when submitted", () => {
|
|
||||||
sandbox.stub(window, "fetch").resolves(fetchOk);
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
assert.calledOnce(window.fetch);
|
|
||||||
});
|
|
||||||
it("should send user telemetry when submitted", () => {
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
wrapper.find("form").simulate("submit");
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.props().sendUserActionTelemetry.firstCall.args[0].event_context,
|
|
||||||
"conversion-subscribe-activation"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should set signupSuccess when submission status is ok", async () => {
|
|
||||||
sandbox.stub(window, "fetch").resolves(fetchOk);
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
await wrapper.instance().handleSubmit({ preventDefault: sandbox.stub() });
|
|
||||||
|
|
||||||
assert.equal(wrapper.state().signupSuccess, true);
|
|
||||||
assert.equal(wrapper.state().signupSubmitted, true);
|
|
||||||
assert.calledOnce(onBlockStub);
|
|
||||||
assert.calledWithExactly(onBlockStub, { preventDismiss: true });
|
|
||||||
});
|
|
||||||
it("should send user telemetry when submission status is ok", async () => {
|
|
||||||
sandbox.stub(window, "fetch").resolves(fetchOk);
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
await wrapper.instance().handleSubmit({ preventDefault: sandbox.stub() });
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.props().sendUserActionTelemetry.secondCall.args[0]
|
|
||||||
.event_context,
|
|
||||||
"subscribe-success"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should not block the snippet if submission failed", async () => {
|
|
||||||
sandbox.stub(window, "fetch").resolves(fetchFail);
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
await wrapper.instance().handleSubmit({ preventDefault: sandbox.stub() });
|
|
||||||
|
|
||||||
assert.equal(wrapper.state().signupSuccess, false);
|
|
||||||
assert.equal(wrapper.state().signupSubmitted, true);
|
|
||||||
assert.notCalled(onBlockStub);
|
|
||||||
});
|
|
||||||
it("should not block if do_not_autoblock is true", async () => {
|
|
||||||
sandbox.stub(window, "fetch").resolves(fetchOk);
|
|
||||||
wrapper = mountAndCheckProps({
|
|
||||||
scene1_text: "bar",
|
|
||||||
scene2_email_placeholder_text: "Email",
|
|
||||||
scene2_text: "signup",
|
|
||||||
do_not_autoblock: true,
|
|
||||||
});
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
await wrapper.instance().handleSubmit({ preventDefault: sandbox.stub() });
|
|
||||||
|
|
||||||
assert.equal(wrapper.state().signupSuccess, true);
|
|
||||||
assert.equal(wrapper.state().signupSubmitted, true);
|
|
||||||
assert.notCalled(onBlockStub);
|
|
||||||
});
|
|
||||||
it("should send user telemetry if submission failed", async () => {
|
|
||||||
sandbox.stub(window, "fetch").resolves(fetchFail);
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
await wrapper.instance().handleSubmit({ preventDefault: sandbox.stub() });
|
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
wrapper.props().sendUserActionTelemetry.secondCall.args[0]
|
|
||||||
.event_context,
|
|
||||||
"subscribe-error"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should render the signup success message", () => {
|
|
||||||
wrapper.setProps({ content: { success_text: "success" } });
|
|
||||||
wrapper.setState({ signupSuccess: true, signupSubmitted: true });
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.find(".submissionStatus").exists());
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.find(RichText).props(),
|
|
||||||
"localization_id",
|
|
||||||
"success_text"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.find(RichText).props(),
|
|
||||||
"success_text",
|
|
||||||
"success"
|
|
||||||
);
|
|
||||||
assert.isFalse(wrapper.find(".ASRouterButton").exists());
|
|
||||||
});
|
|
||||||
it("should render the signup error message", () => {
|
|
||||||
wrapper.setProps({ content: { error_text: "trouble" } });
|
|
||||||
wrapper.setState({ signupSuccess: false, signupSubmitted: true });
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.find(".submissionStatus").exists());
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.find(RichText).props(),
|
|
||||||
"localization_id",
|
|
||||||
"error_text"
|
|
||||||
);
|
|
||||||
assert.propertyVal(
|
|
||||||
wrapper.find(RichText).props(),
|
|
||||||
"error_text",
|
|
||||||
"trouble"
|
|
||||||
);
|
|
||||||
assert.isTrue(wrapper.find(".ASRouterButton").exists());
|
|
||||||
});
|
|
||||||
it("should render the button to return to the signup form if there was an error", () => {
|
|
||||||
wrapper.setState({ signupSubmitted: true, signupSuccess: false });
|
|
||||||
|
|
||||||
const button = wrapper.find("button.ASRouterButton");
|
|
||||||
assert.equal(button.text(), "Try again");
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
|
|
||||||
assert.equal(wrapper.state().signupSubmitted, false);
|
|
||||||
});
|
|
||||||
it("should not render the privacy notice checkbox if prop is missing", () => {
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
assert.isFalse(wrapper.find(".privacyNotice").exists());
|
|
||||||
});
|
|
||||||
it("should render the privacy notice checkbox if prop is provided", () => {
|
|
||||||
wrapper.setProps({
|
|
||||||
content: { ...DEFAULT_CONTENT, scene2_privacy_html: "privacy notice" },
|
|
||||||
});
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.find(".privacyNotice").exists());
|
|
||||||
});
|
|
||||||
it("should not call fetch if form_method is GET", async () => {
|
|
||||||
sandbox.stub(window, "fetch").resolves(fetchOk);
|
|
||||||
wrapper.setProps({ form_method: "GET" });
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
await wrapper.instance().handleSubmit({ preventDefault: sandbox.stub() });
|
|
||||||
|
|
||||||
assert.notCalled(window.fetch);
|
|
||||||
});
|
|
||||||
it("should block the snippet when form_method is GET", () => {
|
|
||||||
wrapper.setProps({ form_method: "GET" });
|
|
||||||
wrapper.setState({ expanded: true });
|
|
||||||
|
|
||||||
wrapper.instance().handleSubmit({ preventDefault: sandbox.stub() });
|
|
||||||
|
|
||||||
assert.calledOnce(onBlockStub);
|
|
||||||
assert.calledWithExactly(onBlockStub, { preventDismiss: true });
|
|
||||||
});
|
|
||||||
it("should return to scene 2 alt when clicking the retry button", async () => {
|
|
||||||
wrapper.setState({ signupSubmitted: true });
|
|
||||||
wrapper.setProps({ expandedAlt: true });
|
|
||||||
|
|
||||||
wrapper.find(".ASRouterButton").simulate("click");
|
|
||||||
|
|
||||||
assert.isTrue(wrapper.find(".scene2Alt").exists());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
import { isEmailOrPhoneNumber } from "content-src/asrouter/templates/SendToDeviceSnippet/isEmailOrPhoneNumber";
|
|
||||||
|
|
||||||
const CONTENT = {};
|
|
||||||
|
|
||||||
describe("isEmailOrPhoneNumber", () => {
|
|
||||||
it("should return 'email' for emails", () => {
|
|
||||||
assert.equal(isEmailOrPhoneNumber("foobar@asd.com", CONTENT), "email");
|
|
||||||
assert.equal(isEmailOrPhoneNumber("foobar@asd.co.uk", CONTENT), "email");
|
|
||||||
});
|
|
||||||
it("should return 'phone' for valid en-US/en-CA phone numbers", () => {
|
|
||||||
assert.equal(
|
|
||||||
isEmailOrPhoneNumber("14582731273", { locale: "en-US" }),
|
|
||||||
"phone"
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
isEmailOrPhoneNumber("4582731273", { locale: "en-CA" }),
|
|
||||||
"phone"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should return an empty string for invalid phone number lengths in en-US/en-CA", () => {
|
|
||||||
// Not enough digits
|
|
||||||
assert.equal(isEmailOrPhoneNumber("4522", { locale: "en-US" }), "");
|
|
||||||
assert.equal(isEmailOrPhoneNumber("4522", { locale: "en-CA" }), "");
|
|
||||||
});
|
|
||||||
it("should return 'phone' for valid German phone numbers", () => {
|
|
||||||
assert.equal(
|
|
||||||
isEmailOrPhoneNumber("145827312732", { locale: "de" }),
|
|
||||||
"phone"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should return 'phone' for any number of digits in other locales", () => {
|
|
||||||
assert.equal(isEmailOrPhoneNumber("4", CONTENT), "phone");
|
|
||||||
});
|
|
||||||
it("should return an empty string for other invalid inputs", () => {
|
|
||||||
assert.equal(
|
|
||||||
isEmailOrPhoneNumber("abc", CONTENT),
|
|
||||||
"",
|
|
||||||
"abc should be invalid"
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
isEmailOrPhoneNumber("abc@", CONTENT),
|
|
||||||
"",
|
|
||||||
"abc@ should be invalid"
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
isEmailOrPhoneNumber("abc@foo", CONTENT),
|
|
||||||
"",
|
|
||||||
"abc@foo should be invalid"
|
|
||||||
);
|
|
||||||
assert.equal(
|
|
||||||
isEmailOrPhoneNumber("123d1232", CONTENT),
|
|
||||||
"",
|
|
||||||
"123d1232 should be invalid"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -2,7 +2,6 @@ import { INITIAL_STATE, insertPinned, reducers } from "common/Reducers.sys.mjs";
|
||||||
const {
|
const {
|
||||||
TopSites,
|
TopSites,
|
||||||
App,
|
App,
|
||||||
Snippets,
|
|
||||||
Prefs,
|
Prefs,
|
||||||
Dialog,
|
Dialog,
|
||||||
Sections,
|
Sections,
|
||||||
|
|
@ -257,11 +256,6 @@ describe("Reducers", () => {
|
||||||
});
|
});
|
||||||
assert.deepEqual(shortcuts, nextState.searchShortcuts);
|
assert.deepEqual(shortcuts, nextState.searchShortcuts);
|
||||||
});
|
});
|
||||||
it("should remove all content on SNIPPETS_PREVIEW_MODE", () => {
|
|
||||||
const oldState = { rows: [{ url: "foo.com" }, { url: "bar.com" }] };
|
|
||||||
const nextState = TopSites(oldState, { type: at.SNIPPETS_PREVIEW_MODE });
|
|
||||||
assert.lengthOf(nextState.rows, 0);
|
|
||||||
});
|
|
||||||
it("should set sov positions and state", () => {
|
it("should set sov positions and state", () => {
|
||||||
const positions = [
|
const positions = [
|
||||||
{ position: 0, assignedPartner: "amp" },
|
{ position: 0, assignedPartner: "amp" },
|
||||||
|
|
@ -741,13 +735,6 @@ describe("Reducers", () => {
|
||||||
// old row is unchanged
|
// old row is unchanged
|
||||||
assert.equal(oldRow, oldState[0].rows[1]);
|
assert.equal(oldRow, oldState[0].rows[1]);
|
||||||
});
|
});
|
||||||
it("should remove all content on SNIPPETS_PREVIEW_MODE", () => {
|
|
||||||
const previewMode = { type: at.SNIPPETS_PREVIEW_MODE };
|
|
||||||
const newState = Sections(oldState, previewMode);
|
|
||||||
newState.forEach(section => {
|
|
||||||
assert.lengthOf(section.rows, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe("#insertPinned", () => {
|
describe("#insertPinned", () => {
|
||||||
let links;
|
let links;
|
||||||
|
|
@ -819,45 +806,6 @@ describe("Reducers", () => {
|
||||||
assert.equal(typeof pinned[0].isPinned, "undefined");
|
assert.equal(typeof pinned[0].isPinned, "undefined");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("Snippets", () => {
|
|
||||||
it("should return INITIAL_STATE by default", () => {
|
|
||||||
assert.equal(
|
|
||||||
Snippets(undefined, { type: "some_action" }),
|
|
||||||
INITIAL_STATE.Snippets
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it("should set initialized to true on a SNIPPETS_DATA action", () => {
|
|
||||||
const state = Snippets(undefined, { type: at.SNIPPETS_DATA, data: {} });
|
|
||||||
assert.isTrue(state.initialized);
|
|
||||||
});
|
|
||||||
it("should set the snippet data on a SNIPPETS_DATA action", () => {
|
|
||||||
const data = { snippetsURL: "foo.com", version: 4 };
|
|
||||||
const state = Snippets(undefined, { type: at.SNIPPETS_DATA, data });
|
|
||||||
assert.propertyVal(state, "snippetsURL", data.snippetsURL);
|
|
||||||
assert.propertyVal(state, "version", data.version);
|
|
||||||
});
|
|
||||||
it("should reset to the initial state on a SNIPPETS_RESET action", () => {
|
|
||||||
const state = Snippets(
|
|
||||||
{ initialized: true, foo: "bar" },
|
|
||||||
{ type: at.SNIPPETS_RESET }
|
|
||||||
);
|
|
||||||
assert.equal(state, INITIAL_STATE.Snippets);
|
|
||||||
});
|
|
||||||
it("should set the new blocklist on SNIPPET_BLOCKED", () => {
|
|
||||||
const state = Snippets(
|
|
||||||
{ blockList: [] },
|
|
||||||
{ type: at.SNIPPET_BLOCKED, data: 1 }
|
|
||||||
);
|
|
||||||
assert.deepEqual(state.blockList, [1]);
|
|
||||||
});
|
|
||||||
it("should clear the blocklist on SNIPPETS_BLOCKLIST_CLEARED", () => {
|
|
||||||
const state = Snippets(
|
|
||||||
{ blockList: [1, 2] },
|
|
||||||
{ type: at.SNIPPETS_BLOCKLIST_CLEARED }
|
|
||||||
);
|
|
||||||
assert.deepEqual(state.blockList, []);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe("Pocket", () => {
|
describe("Pocket", () => {
|
||||||
it("should return INITIAL_STATE by default", () => {
|
it("should return INITIAL_STATE by default", () => {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,16 @@ describe("ASRouterAdmin", () => {
|
||||||
let FAKE_PROVIDER_PREF = [
|
let FAKE_PROVIDER_PREF = [
|
||||||
{
|
{
|
||||||
enabled: true,
|
enabled: true,
|
||||||
id: "snippets_local_testing",
|
id: "local_testing",
|
||||||
localProvider: "SnippetsProvider",
|
localProvider: "TestProvider",
|
||||||
type: "local",
|
type: "local",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let FAKE_PROVIDER = [
|
let FAKE_PROVIDER = [
|
||||||
{
|
{
|
||||||
enabled: true,
|
enabled: true,
|
||||||
id: "snippets_local_testing",
|
id: "local_testing",
|
||||||
localProvider: "SnippetsProvider",
|
localProvider: "TestProvider",
|
||||||
messages: [],
|
messages: [],
|
||||||
type: "local",
|
type: "local",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1053,20 +1053,6 @@ describe("TelemetryFeed", () => {
|
||||||
assert.propertyVal(ping, "message_id", "moments_message_01");
|
assert.propertyVal(ping, "message_id", "moments_message_01");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("#applySnippetsPolicy", () => {
|
|
||||||
it("should include client_id", async () => {
|
|
||||||
const data = {
|
|
||||||
action: "snippets_user_event",
|
|
||||||
event: "IMPRESSION",
|
|
||||||
message_id: "snippets_message_01",
|
|
||||||
};
|
|
||||||
const { ping, pingType } = await instance.applySnippetsPolicy(data);
|
|
||||||
|
|
||||||
assert.equal(pingType, "snippets");
|
|
||||||
assert.propertyVal(ping, "client_id", FAKE_TELEMETRY_ID);
|
|
||||||
assert.propertyVal(ping, "message_id", "snippets_message_01");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe("#applyOnboardingPolicy", () => {
|
describe("#applyOnboardingPolicy", () => {
|
||||||
it("should include client_id", async () => {
|
it("should include client_id", async () => {
|
||||||
const data = {
|
const data = {
|
||||||
|
|
@ -1177,9 +1163,9 @@ describe("TelemetryFeed", () => {
|
||||||
describe("#createASRouterEvent", () => {
|
describe("#createASRouterEvent", () => {
|
||||||
it("should create a valid AS Router event", async () => {
|
it("should create a valid AS Router event", async () => {
|
||||||
const data = {
|
const data = {
|
||||||
action: "snippets_user_event",
|
action: "cfr_user_event",
|
||||||
event: "CLICK",
|
event: "CLICK",
|
||||||
message_id: "snippets_message_01",
|
message_id: "cfr_message_01",
|
||||||
};
|
};
|
||||||
const action = ac.ASRouterUserEvent(data);
|
const action = ac.ASRouterUserEvent(data);
|
||||||
const { ping } = await instance.createASRouterEvent(action);
|
const { ping } = await instance.createASRouterEvent(action);
|
||||||
|
|
@ -1199,30 +1185,6 @@ describe("TelemetryFeed", () => {
|
||||||
|
|
||||||
assert.calledOnce(instance.applyCFRPolicy);
|
assert.calledOnce(instance.applyCFRPolicy);
|
||||||
});
|
});
|
||||||
it("should call applySnippetsPolicy if action equals to snippets_user_event", async () => {
|
|
||||||
const data = {
|
|
||||||
action: "snippets_user_event",
|
|
||||||
event: "IMPRESSION",
|
|
||||||
message_id: "snippets_message_01",
|
|
||||||
};
|
|
||||||
sandbox.stub(instance, "applySnippetsPolicy");
|
|
||||||
const action = ac.ASRouterUserEvent(data);
|
|
||||||
await instance.createASRouterEvent(action);
|
|
||||||
|
|
||||||
assert.calledOnce(instance.applySnippetsPolicy);
|
|
||||||
});
|
|
||||||
it("should call applySnippetsPolicy if action equals to snippets_local_testing_user_event", async () => {
|
|
||||||
const data = {
|
|
||||||
action: "snippets_local_testing_user_event",
|
|
||||||
event: "IMPRESSION",
|
|
||||||
message_id: "snippets_message_01",
|
|
||||||
};
|
|
||||||
sandbox.stub(instance, "applySnippetsPolicy");
|
|
||||||
const action = ac.ASRouterUserEvent(data);
|
|
||||||
await instance.createASRouterEvent(action);
|
|
||||||
|
|
||||||
assert.calledOnce(instance.applySnippetsPolicy);
|
|
||||||
});
|
|
||||||
it("should call applyOnboardingPolicy if action equals to onboarding_user_event", async () => {
|
it("should call applyOnboardingPolicy if action equals to onboarding_user_event", async () => {
|
||||||
const data = {
|
const data = {
|
||||||
action: "onboarding_user_event",
|
action: "onboarding_user_event",
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,10 @@ user_pref("browser.dom.window.dump.enabled", true);
|
||||||
user_pref("devtools.console.stdout.chrome", true);
|
user_pref("devtools.console.stdout.chrome", true);
|
||||||
// asrouter expects a plain object or null
|
// asrouter expects a plain object or null
|
||||||
user_pref("browser.newtabpage.activity-stream.asrouter.providers.cfr", "null");
|
user_pref("browser.newtabpage.activity-stream.asrouter.providers.cfr", "null");
|
||||||
user_pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", "null");
|
|
||||||
user_pref("browser.newtabpage.activity-stream.asrouter.providers.message-groups", "null");
|
user_pref("browser.newtabpage.activity-stream.asrouter.providers.message-groups", "null");
|
||||||
user_pref("browser.newtabpage.activity-stream.asrouter.providers.whats-new-panel", "null");
|
user_pref("browser.newtabpage.activity-stream.asrouter.providers.whats-new-panel", "null");
|
||||||
user_pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "null");
|
user_pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "null");
|
||||||
user_pref("browser.newtabpage.activity-stream.feeds.system.topstories", false);
|
user_pref("browser.newtabpage.activity-stream.feeds.system.topstories", false);
|
||||||
user_pref("browser.newtabpage.activity-stream.feeds.snippets", false);
|
|
||||||
user_pref("browser.newtabpage.activity-stream.tippyTop.service.endpoint", "");
|
user_pref("browser.newtabpage.activity-stream.tippyTop.service.endpoint", "");
|
||||||
user_pref("browser.newtabpage.activity-stream.discoverystream.config", "[]");
|
user_pref("browser.newtabpage.activity-stream.discoverystream.config", "[]");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,6 @@
|
||||||
"resource://activity-stream/lib/SectionsManager.jsm": "browser/components/newtab/lib/SectionsManager.jsm",
|
"resource://activity-stream/lib/SectionsManager.jsm": "browser/components/newtab/lib/SectionsManager.jsm",
|
||||||
"resource://activity-stream/lib/ShortURL.jsm": "browser/components/newtab/lib/ShortURL.jsm",
|
"resource://activity-stream/lib/ShortURL.jsm": "browser/components/newtab/lib/ShortURL.jsm",
|
||||||
"resource://activity-stream/lib/SiteClassifier.jsm": "browser/components/newtab/lib/SiteClassifier.jsm",
|
"resource://activity-stream/lib/SiteClassifier.jsm": "browser/components/newtab/lib/SiteClassifier.jsm",
|
||||||
"resource://activity-stream/lib/SnippetsTestMessageProvider.jsm": "browser/components/newtab/lib/SnippetsTestMessageProvider.jsm",
|
|
||||||
"resource://activity-stream/lib/Spotlight.jsm": "browser/components/newtab/lib/Spotlight.jsm",
|
"resource://activity-stream/lib/Spotlight.jsm": "browser/components/newtab/lib/Spotlight.jsm",
|
||||||
"resource://activity-stream/lib/Store.jsm": "browser/components/newtab/lib/Store.jsm",
|
"resource://activity-stream/lib/Store.jsm": "browser/components/newtab/lib/Store.jsm",
|
||||||
"resource://activity-stream/lib/SystemTickFeed.jsm": "browser/components/newtab/lib/SystemTickFeed.jsm",
|
"resource://activity-stream/lib/SystemTickFeed.jsm": "browser/components/newtab/lib/SystemTickFeed.jsm",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue