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:
Mike Conley 2023-12-06 16:15:13 +00:00
parent e2e35a1b69
commit 898169df2a
33 changed files with 71 additions and 3637 deletions

View file

@ -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

View file

@ -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,
}; };
} }

View file

@ -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",

View file

@ -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 &ndash; 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 &ndash; 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 &ndash; 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&amp;utm_medium=snippet&amp;utm_campaign=donate&amp;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"`,
}))
);
},
};

View file

@ -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"]

View file

@ -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),

View file

@ -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");
});

View file

@ -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();
});

View file

@ -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"
}
]
}

View file

@ -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"
}
]
}

View file

@ -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"
}
]
}

View file

@ -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, {});

View file

@ -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);

View file

@ -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");

View file

@ -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);
}); });

View file

@ -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`
);
});
});
});

View file

@ -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);
});
});
});
});

View file

@ -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);
});
});
});
});

View file

@ -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",
},
};

View file

@ -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" },
}, },
]; ];

View file

@ -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&amp;utm_medium=snippet&amp;utm_campaign=donate&amp;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);
});
});
});

View file

@ -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);
});
});

View file

@ -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);
});
});
});

View file

@ -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
);
});
});
});

View file

@ -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"
);
});
});

View file

@ -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);
});
});

View file

@ -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());
});
});
});

View file

@ -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"
);
});
});

View file

@ -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(

View file

@ -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",
}, },

View file

@ -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",

View file

@ -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", "[]");

View file

@ -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",