From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/unit/asrouter/asrouter-content.test.jsx | 516 +++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 browser/components/newtab/test/unit/asrouter/asrouter-content.test.jsx (limited to 'browser/components/newtab/test/unit/asrouter/asrouter-content.test.jsx') diff --git a/browser/components/newtab/test/unit/asrouter/asrouter-content.test.jsx b/browser/components/newtab/test/unit/asrouter/asrouter-content.test.jsx new file mode 100644 index 0000000000..b581886111 --- /dev/null +++ b/browser/components/newtab/test/unit/asrouter/asrouter-content.test.jsx @@ -0,0 +1,516 @@ +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(); + }); + + 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(); + + 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 element if the dir param is set", () => { + assert.notPropertyVal(fakeDocument, "dir", "rtl"); + sandbox.stub(ASRouterUtils, "getPreviewEndpoint").returns({ dir: "rtl" }); + + wrapper = mount(); + 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( + + ); + }); + it("should use the base url returned from the endpoint pref", async () => { + wrapper = mount( + + ); + 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); + }); + }); + }); +}); -- cgit v1.2.3