Bug 1571763 - Message template for tracking protection report in what's new panel (#5267)
This commit is contained in:
Родитель
84639b9959
Коммит
63a5f79e8a
|
@ -38,6 +38,7 @@ Please note that some targeting attributes require stricter controls on the tele
|
|||
* [isWhatsNewPanelEnabled](#iswhatsnewpanelenabled)
|
||||
* [earliestFirefoxVersion](#earliestfirefoxversion)
|
||||
* [isFxABadgeEnabled](#isfxabadgeenabled)
|
||||
* [totalBlockedCount](#totalblockedcount)
|
||||
|
||||
## Detailed usage
|
||||
|
||||
|
@ -518,3 +519,13 @@ Boolean pref that controls if the FxA toolbar button is badged by Messaging Syst
|
|||
```ts
|
||||
declare const isFxABadgeEnabled: boolean;
|
||||
```
|
||||
|
||||
### `totalBlockedCount`
|
||||
|
||||
Total number of events from the content blocking database
|
||||
|
||||
#### Definition
|
||||
|
||||
```ts
|
||||
declare const totalBlockedCount: number;
|
||||
```
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
}
|
||||
},
|
||||
"properties": {
|
||||
"layout": {
|
||||
"description": "Different message layouts",
|
||||
"enum": ["tracking-protections"]
|
||||
},
|
||||
"published_date": {
|
||||
"type": "integer",
|
||||
"description": "The date/time (number of milliseconds elapsed since January 1, 1970 00:00:00 UTC) the message was published."
|
||||
|
@ -34,6 +38,12 @@
|
|||
{"description": "Id of localized string or message override of What's New message title"}
|
||||
]
|
||||
},
|
||||
"subtitle": {
|
||||
"allOf": [
|
||||
{"$ref": "#/definitions/localizableText"},
|
||||
{"description": "Id of localized string or message override of What's New message subtitle"}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"allOf": [
|
||||
{"$ref": "#/definitions/localizableText"},
|
||||
|
@ -51,6 +61,10 @@
|
|||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"cta_type": {
|
||||
"description": "Type of url open action",
|
||||
"enum": ["OPEN_URL", "OPEN_ABOUT_PAGE"]
|
||||
},
|
||||
"icon_url": {
|
||||
"description": "(optional) URL for the What's New message icon.",
|
||||
"type": "string",
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 4.2 KiB |
|
@ -742,6 +742,7 @@ class _ASRouter {
|
|||
ToolbarPanelHub.init(this.waitForInitialized, {
|
||||
getMessages: this.handleMessageRequest,
|
||||
dispatch: this.dispatch,
|
||||
handleUserAction: this.handleUserAction,
|
||||
});
|
||||
|
||||
this._loadLocalProviders();
|
||||
|
|
|
@ -56,6 +56,12 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
"@mozilla.org/updates/update-manager;1",
|
||||
"nsIUpdateManager"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"TrackingDBService",
|
||||
"@mozilla.org/tracking-db-service;1",
|
||||
"nsITrackingDBService"
|
||||
);
|
||||
|
||||
const FXA_USERNAME_PREF = "services.sync.username";
|
||||
const FXA_ENABLED_PREF = "identity.fxaccounts.enabled";
|
||||
|
@ -422,6 +428,9 @@ const TargetingGetters = {
|
|||
false
|
||||
);
|
||||
},
|
||||
get totalBlockedCount() {
|
||||
return TrackingDBService.sumAllEvents();
|
||||
},
|
||||
};
|
||||
|
||||
this.ASRouterTargeting = {
|
||||
|
|
|
@ -407,6 +407,7 @@ const ONBOARDING_MESSAGES = () => [
|
|||
cta_url: `${Services.urlFormatter.formatURLPref(
|
||||
"app.support.baseURL"
|
||||
)}etp-promotions?as=u&utm_source=inproduct`,
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
trigger: { id: "protectionsPanelOpen" },
|
||||
},
|
||||
|
|
|
@ -66,6 +66,7 @@ const MESSAGES = () => [
|
|||
{
|
||||
id: "WHATS_NEW_70_1",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 3,
|
||||
content: {
|
||||
published_date: 1560969794394,
|
||||
title: "Protection Is Our Focus",
|
||||
|
@ -75,6 +76,7 @@ const MESSAGES = () => [
|
|||
body:
|
||||
"The New Enhanced Tracking Protection, gives you the best level of protection and performance. Discover how this version is the safest version of firefox ever made.",
|
||||
cta_url: "https://blog.mozilla.org/",
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
targeting: `firefoxVersion > 69`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
|
@ -82,6 +84,7 @@ const MESSAGES = () => [
|
|||
{
|
||||
id: "WHATS_NEW_70_2",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 1,
|
||||
content: {
|
||||
published_date: 1560969794394,
|
||||
title: "Another thing new in Firefox 70",
|
||||
|
@ -89,6 +92,7 @@ const MESSAGES = () => [
|
|||
"The New Enhanced Tracking Protection, gives you the best level of protection and performance. Discover how this version is the safest version of firefox ever made.",
|
||||
link_text: "Learn more on our blog",
|
||||
cta_url: "https://blog.mozilla.org/",
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
targeting: `firefoxVersion > 69`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
|
@ -96,6 +100,7 @@ const MESSAGES = () => [
|
|||
{
|
||||
id: "WHATS_NEW_69_1",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 1,
|
||||
content: {
|
||||
published_date: 1557346235089,
|
||||
title: "Something new in Firefox 69",
|
||||
|
@ -103,10 +108,31 @@ const MESSAGES = () => [
|
|||
"The New Enhanced Tracking Protection, gives you the best level of protection and performance. Discover how this version is the safest version of firefox ever made.",
|
||||
link_text: "Learn more on our blog",
|
||||
cta_url: "https://blog.mozilla.org/",
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
targeting: `firefoxVersion > 68`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
},
|
||||
{
|
||||
id: "WHATS_NEW_70_3",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 2,
|
||||
content: {
|
||||
published_date: 1560969794394,
|
||||
layout: "tracking-protections",
|
||||
title: { string_id: "cfr-whatsnew-tracking-blocked-title" },
|
||||
subtitle: { string_id: "cfr-whatsnew-tracking-blocked-subtitle" },
|
||||
icon_url:
|
||||
"resource://activity-stream/data/content/assets/protection-report-icon.png",
|
||||
icon_alt: "Protection Report icon",
|
||||
body: { string_id: "cfr-whatsnew-tracking-protect-body" },
|
||||
link_text: { string_id: "cfr-whatsnew-tracking-blocked-link-text" },
|
||||
cta_url: "protections",
|
||||
cta_type: "OPEN_ABOUT_PAGE",
|
||||
},
|
||||
targeting: `firefoxVersion > 69 && totalBlockedCount > 0`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
},
|
||||
];
|
||||
|
||||
const PanelTestProvider = {
|
||||
|
|
|
@ -3,20 +3,19 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
EveryWindow: "resource:///modules/EveryWindow.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
});
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"EveryWindow",
|
||||
"resource:///modules/EveryWindow.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
||||
"TrackingDBService",
|
||||
"@mozilla.org/tracking-db-service;1",
|
||||
"nsITrackingDBService"
|
||||
);
|
||||
|
||||
const WHATSNEW_ENABLED_PREF = "browser.messaging-system.whatsNewPanel.enabled";
|
||||
|
@ -43,9 +42,10 @@ class _ToolbarPanelHub {
|
|||
this.state = null;
|
||||
}
|
||||
|
||||
async init(waitForInitialized, { getMessages, dispatch }) {
|
||||
async init(waitForInitialized, { getMessages, dispatch, handleUserAction }) {
|
||||
this._getMessages = getMessages;
|
||||
this._dispatch = dispatch;
|
||||
this._handleUserAction = handleUserAction;
|
||||
// Wait for ASRouter messages to become available in order to know
|
||||
// if we can show the What's New panel
|
||||
await waitForInitialized;
|
||||
|
@ -137,23 +137,45 @@ class _ToolbarPanelHub {
|
|||
});
|
||||
}
|
||||
|
||||
// Newer messages first and use `order` field to decide between messages
|
||||
// with the same timestamp
|
||||
_sortWhatsNewMessages(m1, m2) {
|
||||
// Sort by published_date in descending order.
|
||||
if (m1.content.published_date === m2.content.published_date) {
|
||||
// Ascending order
|
||||
return m1.order - m2.order;
|
||||
}
|
||||
if (m1.content.published_date > m2.content.published_date) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Render what's new messages into the panel.
|
||||
async renderMessages(win, doc, containerId) {
|
||||
const messages = (await this.messages).sort((m1, m2) => {
|
||||
// Sort by published_date in descending order.
|
||||
if (m1.content.published_date === m2.content.published_date) {
|
||||
return 0;
|
||||
}
|
||||
if (m1.content.published_date > m2.content.published_date) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
const messages = (await this.messages).sort(this._sortWhatsNewMessages);
|
||||
const container = doc.getElementById(containerId);
|
||||
|
||||
if (messages && !container.querySelector(".whatsNew-message")) {
|
||||
let previousDate = 0;
|
||||
// Get and store any variable part of the message content
|
||||
this.state.contentArguments = await this._contentArguments();
|
||||
for (let message of messages) {
|
||||
// Only render date if it is different from the one rendered before.
|
||||
if (message.content.published_date !== previousDate) {
|
||||
container.appendChild(
|
||||
this._createElement(doc, "p", {
|
||||
classList: "whatsNew-message-date",
|
||||
content: new Date(
|
||||
message.content.published_date
|
||||
).toLocaleDateString("default", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
}),
|
||||
})
|
||||
);
|
||||
}
|
||||
container.appendChild(
|
||||
this._createMessageElements(win, doc, message, previousDate)
|
||||
);
|
||||
|
@ -181,34 +203,36 @@ class _ToolbarPanelHub {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach click event listener defined in message payload
|
||||
*/
|
||||
_attachClickListener(win, element, message) {
|
||||
element.addEventListener("click", () => {
|
||||
this._handleUserAction({
|
||||
target: win,
|
||||
data: {
|
||||
type: message.content.cta_type,
|
||||
data: {
|
||||
args: message.content.cta_url,
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.sendUserEventTelemetry(win, "CLICK", message);
|
||||
});
|
||||
}
|
||||
|
||||
_createMessageElements(win, doc, message, previousDate) {
|
||||
const { content } = message;
|
||||
const messageEl = this._createElement(doc, "div");
|
||||
messageEl.classList.add("whatsNew-message");
|
||||
|
||||
// Only render date if it is different from the one rendered before.
|
||||
if (content.published_date !== previousDate) {
|
||||
messageEl.appendChild(
|
||||
this._createDateElement(doc, content.published_date)
|
||||
);
|
||||
}
|
||||
|
||||
const wrapperEl = this._createElement(doc, "button");
|
||||
// istanbul ignore next
|
||||
wrapperEl.doCommand = () => {};
|
||||
wrapperEl.classList.add("whatsNew-message-body");
|
||||
messageEl.appendChild(wrapperEl);
|
||||
wrapperEl.addEventListener("click", () => {
|
||||
win.ownerGlobal.openLinkIn(content.cta_url, "tabshifted", {
|
||||
private: false,
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
|
||||
{}
|
||||
),
|
||||
csp: null,
|
||||
});
|
||||
|
||||
this.sendUserEventTelemetry(win, "CLICK", message);
|
||||
});
|
||||
|
||||
if (content.icon_url) {
|
||||
wrapperEl.classList.add("has-icon");
|
||||
|
@ -219,81 +243,141 @@ class _ToolbarPanelHub {
|
|||
wrapperEl.appendChild(iconEl);
|
||||
}
|
||||
|
||||
const titleEl = this._createElement(doc, "h2");
|
||||
titleEl.classList.add("whatsNew-message-title");
|
||||
this._setString(doc, titleEl, content.title);
|
||||
wrapperEl.appendChild(titleEl);
|
||||
|
||||
const bodyEl = this._createElement(doc, "p");
|
||||
this._setString(doc, bodyEl, content.body);
|
||||
wrapperEl.appendChild(bodyEl);
|
||||
wrapperEl.appendChild(this._createMessageContent(win, doc, content));
|
||||
|
||||
if (content.link_text) {
|
||||
const linkEl = this._createElement(doc, "a");
|
||||
linkEl.classList.add("text-link");
|
||||
this._setString(doc, linkEl, content.link_text);
|
||||
wrapperEl.appendChild(linkEl);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "a", {
|
||||
classList: "text-link",
|
||||
content: content.link_text,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Attach event listener on entire message container
|
||||
this._attachClickListener(win, wrapperEl, message);
|
||||
|
||||
return messageEl;
|
||||
}
|
||||
|
||||
_createHeroElement(win, doc, content) {
|
||||
/**
|
||||
* Return message title (optional subtitle) and body
|
||||
*/
|
||||
_createMessageContent(win, doc, content) {
|
||||
const wrapperEl = new win.DocumentFragment();
|
||||
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title",
|
||||
content: content.title,
|
||||
})
|
||||
);
|
||||
|
||||
switch (content.layout) {
|
||||
case "tracking-protections":
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h4", {
|
||||
classList: "whatsNew-message-subtitle",
|
||||
content: content.subtitle,
|
||||
})
|
||||
);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title-large",
|
||||
content: this.state.contentArguments.blockedCount,
|
||||
})
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "p", { content: content.body })
|
||||
);
|
||||
|
||||
return wrapperEl;
|
||||
}
|
||||
|
||||
_createHeroElement(win, doc, message) {
|
||||
const messageEl = this._createElement(doc, "div");
|
||||
messageEl.setAttribute("id", "protections-popup-message");
|
||||
messageEl.classList.add("whatsNew-hero-message");
|
||||
const wrapperEl = this._createElement(doc, "div");
|
||||
wrapperEl.classList.add("whatsNew-message-body");
|
||||
messageEl.appendChild(wrapperEl);
|
||||
wrapperEl.addEventListener("click", () => {
|
||||
win.ownerGlobal.openLinkIn(content.cta_url, "tabshifted", {
|
||||
private: false,
|
||||
relatedToCurrent: true,
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
|
||||
{}
|
||||
),
|
||||
csp: null,
|
||||
});
|
||||
});
|
||||
const titleEl = this._createElement(doc, "h2");
|
||||
titleEl.classList.add("whatsNew-message-title");
|
||||
this._setString(doc, titleEl, content.title);
|
||||
wrapperEl.appendChild(titleEl);
|
||||
|
||||
const bodyEl = this._createElement(doc, "p");
|
||||
this._setString(doc, bodyEl, content.body);
|
||||
wrapperEl.appendChild(bodyEl);
|
||||
this._attachClickListener(win, wrapperEl, message);
|
||||
|
||||
if (content.link_text) {
|
||||
const linkEl = this._createElement(doc, "a");
|
||||
linkEl.classList.add("text-link");
|
||||
this._setString(doc, linkEl, content.link_text);
|
||||
wrapperEl.appendChild(linkEl);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title",
|
||||
content: message.content.title,
|
||||
})
|
||||
);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "p", { content: message.content.body })
|
||||
);
|
||||
|
||||
if (message.content.link_text) {
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "a", {
|
||||
classList: "text-link",
|
||||
content: message.content.link_text,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return messageEl;
|
||||
}
|
||||
|
||||
_createElement(doc, elem) {
|
||||
return doc.createElementNS("http://www.w3.org/1999/xhtml", elem);
|
||||
_createElement(doc, elem, options = {}) {
|
||||
const node = doc.createElementNS("http://www.w3.org/1999/xhtml", elem);
|
||||
if (options.classList) {
|
||||
node.classList.add(options.classList);
|
||||
}
|
||||
if (options.content) {
|
||||
this._setString(doc, node, options.content);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
_createDateElement(doc, date) {
|
||||
const dateEl = this._createElement(doc, "p");
|
||||
dateEl.classList.add("whatsNew-message-date");
|
||||
dateEl.textContent = new Date(date).toLocaleDateString("default", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
return dateEl;
|
||||
async _contentArguments() {
|
||||
// Between now and 6 weeks ago
|
||||
const dateTo = new Date();
|
||||
const dateFrom = new Date(dateTo.getTime() - 42 * 24 * 60 * 60 * 1000);
|
||||
const eventsByDate = await TrackingDBService.getEventsByDateRange(
|
||||
dateFrom,
|
||||
dateTo
|
||||
);
|
||||
// Count all events in the past 6 weeks
|
||||
const totalEvents = eventsByDate.reduce(
|
||||
(acc, day) => acc + day.getResultByName("count"),
|
||||
0
|
||||
);
|
||||
return {
|
||||
// Keys need to match variable names used in asrouter.ftl
|
||||
// `earliestDate` will be either 6 weeks ago or when tracking recording
|
||||
// started. Whichever is more recent.
|
||||
earliestDate: new Date(
|
||||
Math.max(
|
||||
new Date(await TrackingDBService.getEarliestRecordedDate()),
|
||||
dateFrom
|
||||
)
|
||||
).getTime(),
|
||||
blockedCount: totalEvents.toLocaleString(),
|
||||
};
|
||||
}
|
||||
|
||||
// If `string_id` is present it means we are relying on fluent for translations.
|
||||
// Otherwise, we have a vanilla string.
|
||||
_setString(doc, el, stringObj) {
|
||||
if (stringObj.string_id) {
|
||||
doc.l10n.setAttributes(el, stringObj.string_id);
|
||||
doc.l10n.setAttributes(
|
||||
el,
|
||||
stringObj.string_id,
|
||||
// Pass all available arguments to Fluent
|
||||
this.state.contentArguments
|
||||
);
|
||||
} else {
|
||||
el.textContent = stringObj;
|
||||
}
|
||||
|
@ -396,7 +480,7 @@ class _ToolbarPanelHub {
|
|||
triggerId: "protectionsPanelOpen",
|
||||
});
|
||||
if (message) {
|
||||
const messageEl = this._createHeroElement(win, doc, message.content);
|
||||
const messageEl = this._createHeroElement(win, doc, message);
|
||||
container.appendChild(messageEl);
|
||||
infoButton.addEventListener("click", toggleMessage);
|
||||
this.sendUserEventTelemetry(win, "IMPRESSION", message.id);
|
||||
|
|
|
@ -214,6 +214,7 @@ describe("ASRouter", () => {
|
|||
{
|
||||
getMessages: Router.handleMessageRequest,
|
||||
dispatch: Router.dispatch,
|
||||
handleUserAction: Router.handleUserAction,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { PanelTestProvider } from "lib/PanelTestProvider.jsm";
|
||||
import schema from "content-src/asrouter/schemas/panel/cfr-fxa-bookmark.schema.json";
|
||||
import update_schema from "content-src/asrouter/templates/OnboardingMessage/UpdateAction.schema.json";
|
||||
import whats_new_schema from "content-src/asrouter/templates/OnboardingMessage/WhatsNewMessage.schema.json";
|
||||
const messages = PanelTestProvider.getMessages();
|
||||
|
||||
describe("PanelTestProvider", () => {
|
||||
it("should have a message", () => {
|
||||
// Careful: when changing this number make sure that new messages also go
|
||||
// through schema verifications.
|
||||
assert.lengthOf(messages, 6);
|
||||
assert.lengthOf(messages, 7);
|
||||
});
|
||||
it("should be a valid message", () => {
|
||||
const fxaMessages = messages.filter(
|
||||
|
@ -25,4 +26,14 @@ describe("PanelTestProvider", () => {
|
|||
assert.jsonSchema(message.content, update_schema);
|
||||
}
|
||||
});
|
||||
it("should be a valid message", () => {
|
||||
const whatsNewMessages = messages.filter(
|
||||
({ template }) => template === "whatsnew_panel_message"
|
||||
);
|
||||
for (let message of whatsNewMessages) {
|
||||
assert.jsonSchema(message.content, whats_new_schema);
|
||||
// Not part of `message.content` so it can't be enforced through schema
|
||||
assert.property(message, "order");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,6 +20,9 @@ describe("ToolbarPanelHub", () => {
|
|||
let waitForInitializedStub;
|
||||
let isBrowserPrivateStub;
|
||||
let fakeDispatch;
|
||||
let getEarliestRecordedDateStub;
|
||||
let getEventsByDateRangeStub;
|
||||
let handleUserActionStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.createSandbox();
|
||||
|
@ -58,6 +61,10 @@ describe("ToolbarPanelHub", () => {
|
|||
},
|
||||
};
|
||||
fakeWindow = {
|
||||
// eslint-disable-next-line object-shorthand
|
||||
DocumentFragment: function() {
|
||||
return fakeElementById;
|
||||
},
|
||||
document: fakeDocument,
|
||||
browser: {
|
||||
ownerDocument: fakeDocument,
|
||||
|
@ -94,6 +101,16 @@ describe("ToolbarPanelHub", () => {
|
|||
globals.set("PrivateBrowsingUtils", {
|
||||
isBrowserPrivate: isBrowserPrivateStub,
|
||||
});
|
||||
getEarliestRecordedDateStub = sandbox.stub();
|
||||
getEventsByDateRangeStub = sandbox.stub();
|
||||
globals.set("TrackingDBService", {
|
||||
getEarliestRecordedDate: getEarliestRecordedDateStub.returns(
|
||||
// A random date that's not the current timestamp
|
||||
new Date() - 500
|
||||
),
|
||||
getEventsByDateRange: getEventsByDateRangeStub.returns([]),
|
||||
});
|
||||
handleUserActionStub = sandbox.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
instance.uninit();
|
||||
|
@ -242,6 +259,7 @@ describe("ToolbarPanelHub", () => {
|
|||
instance.init(waitForInitializedStub, {
|
||||
getMessages: getMessagesStub,
|
||||
dispatch: fakeDispatch,
|
||||
handleUserAction: handleUserActionStub,
|
||||
});
|
||||
});
|
||||
it("should render messages to the panel on renderMessages()", async () => {
|
||||
|
@ -250,32 +268,50 @@ describe("ToolbarPanelHub", () => {
|
|||
);
|
||||
messages[0].content.link_text = { string_id: "link_text_id" };
|
||||
|
||||
getMessagesStub.returns([messages[0], messages[2], messages[1]]);
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
for (let message of messages) {
|
||||
assert.ok(
|
||||
createdElements.find(
|
||||
el =>
|
||||
el.tagName === "h2" && el.textContent === message.content.title
|
||||
)
|
||||
);
|
||||
assert.ok(
|
||||
createdElements.find(
|
||||
el => el.tagName === "p" && el.textContent === message.content.body
|
||||
)
|
||||
);
|
||||
assert.ok(createdElements.find(el => el.tagName === "h2"));
|
||||
if (message.content.layout === "tracking-protections") {
|
||||
assert.ok(createdElements.find(el => el.tagName === "h4"));
|
||||
}
|
||||
assert.ok(createdElements.find(el => el.tagName === "p"));
|
||||
}
|
||||
// Call the click handler to make coverage happy.
|
||||
eventListeners.click();
|
||||
assert.calledOnce(fakeWindow.ownerGlobal.openLinkIn);
|
||||
assert.calledOnce(handleUserActionStub);
|
||||
});
|
||||
it("should sort based on order field value", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m =>
|
||||
m.template === "whatsnew_panel_message" &&
|
||||
m.content.published_date === 1560969794394
|
||||
);
|
||||
|
||||
messages.forEach(m => (m.content.title = m.order));
|
||||
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
// Select the title elements that are supposed to be set to the same
|
||||
// value as the `order` field of the message
|
||||
const titleEls = createdElements
|
||||
.filter(
|
||||
el =>
|
||||
el.classList.add.firstCall &&
|
||||
el.classList.add.firstCall.args[0] === "whatsNew-message-title"
|
||||
)
|
||||
.map(el => el.textContent);
|
||||
assert.deepEqual(titleEls, [1, 2, 3]);
|
||||
});
|
||||
it("should accept string for image attributes", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
m => m.id === "WHATS_NEW_70_1"
|
||||
);
|
||||
getMessagesStub.returns([messages[0], messages[2], messages[1]]);
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
|
@ -289,19 +325,55 @@ describe("ToolbarPanelHub", () => {
|
|||
});
|
||||
it("should accept fluent ids for image attributes", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
m => m.id === "WHATS_NEW_70_1"
|
||||
);
|
||||
messages[0].content.icon_alt = { string_id: "foo" };
|
||||
getMessagesStub.returns([messages[0], messages[2], messages[1]]);
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
const imageEl = createdElements.find(el => el.tagName === "img");
|
||||
assert.calledOnce(fakeDocument.l10n.setAttributes);
|
||||
assert.calledWithExactly(fakeDocument.l10n.setAttributes, imageEl, "foo");
|
||||
});
|
||||
it("should accept fluent ids for elements attributes", async () => {
|
||||
const [message] = (await PanelTestProvider.getMessages()).filter(
|
||||
m =>
|
||||
m.template === "whatsnew_panel_message" &&
|
||||
m.content.layout === "tracking-protections"
|
||||
);
|
||||
getMessagesStub.returns([message]);
|
||||
instance.state.contentArguments = { foo: "foo", bar: "bar" };
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
const subtitle = createdElements.find(el => el.tagName === "h4");
|
||||
assert.calledWithExactly(
|
||||
fakeDocument.l10n.setAttributes,
|
||||
subtitle,
|
||||
message.content.subtitle.string_id,
|
||||
instance.state.contentArguments
|
||||
);
|
||||
});
|
||||
it("should correctly compute blocker trackers and date", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
getMessagesStub.returns(messages);
|
||||
getEventsByDateRangeStub.returns([
|
||||
{ getResultByName: sandbox.stub().returns(2) },
|
||||
{ getResultByName: sandbox.stub().returns(3) },
|
||||
]);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledWithExactly(
|
||||
fakeDocument.l10n.setAttributes,
|
||||
sinon.match.object,
|
||||
sinon.match.string,
|
||||
{ blockedCount: "5", earliestDate: getEarliestRecordedDateStub() }
|
||||
);
|
||||
});
|
||||
it("should only render unique dates (no duplicates)", async () => {
|
||||
instance._createDateElement = sandbox.stub();
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
|
@ -312,7 +384,13 @@ describe("ToolbarPanelHub", () => {
|
|||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.callCount(instance._createDateElement, uniqueDates.length);
|
||||
const dateElements = createdElements.filter(
|
||||
el =>
|
||||
el.tagName === "p" &&
|
||||
el.classList.add.firstCall &&
|
||||
el.classList.add.firstCall.args[0] === "whatsNew-message-date"
|
||||
);
|
||||
assert.lengthOf(dateElements, uniqueDates.length);
|
||||
});
|
||||
it("should listen for panelhidden and remove the toolbar button", async () => {
|
||||
getMessagesStub.returns([]);
|
||||
|
@ -492,6 +570,7 @@ describe("ToolbarPanelHub", () => {
|
|||
dispatch: fakeDispatch,
|
||||
getMessages: () =>
|
||||
onboardingMsgs.find(msg => msg.template === "protections_panel"),
|
||||
handleUserAction: handleUserActionStub,
|
||||
});
|
||||
});
|
||||
it("should remember it showed", async () => {
|
||||
|
@ -522,7 +601,17 @@ describe("ToolbarPanelHub", () => {
|
|||
|
||||
eventListeners.click();
|
||||
|
||||
assert.calledOnce(fakeWindow.ownerGlobal.openLinkIn);
|
||||
assert.calledOnce(handleUserActionStub);
|
||||
assert.calledWithExactly(handleUserActionStub, {
|
||||
target: fakeWindow,
|
||||
data: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: sinon.match.string,
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче