diff options
Diffstat (limited to 'browser/components/newtab/test/unit/lib/BookmarkPanelHub.test.js')
-rw-r--r-- | browser/components/newtab/test/unit/lib/BookmarkPanelHub.test.js | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/browser/components/newtab/test/unit/lib/BookmarkPanelHub.test.js b/browser/components/newtab/test/unit/lib/BookmarkPanelHub.test.js new file mode 100644 index 0000000000..dfcfecb2be --- /dev/null +++ b/browser/components/newtab/test/unit/lib/BookmarkPanelHub.test.js @@ -0,0 +1,514 @@ +import { _BookmarkPanelHub } from "lib/BookmarkPanelHub.jsm"; +import { GlobalOverrider } from "test/unit/utils"; +import { PanelTestProvider } from "lib/PanelTestProvider.jsm"; + +describe("BookmarkPanelHub", () => { + let globals; + let sandbox; + let instance; + let fakeAddImpression; + let fakeHandleMessageRequest; + let fakeL10n; + let fakeMessage; + let fakeMessageFluent; + let fakeTarget; + let fakeContainer; + let fakeSendTelemetry; + let fakeWindow; + let isBrowserPrivateStub; + beforeEach(async () => { + sandbox = sinon.createSandbox(); + globals = new GlobalOverrider(); + + fakeL10n = { + setAttributes: sandbox.stub(), + translateElements: sandbox.stub().resolves(), + }; + globals.set("DOMLocalization", function() { + return fakeL10n; + }); // eslint-disable-line prefer-arrow-callback + globals.set("FxAccounts", { + config: { promiseConnectAccountURI: sandbox.stub() }, + }); + isBrowserPrivateStub = sandbox.stub().returns(false); + globals.set("PrivateBrowsingUtils", { + isBrowserPrivate: isBrowserPrivateStub, + }); + + instance = new _BookmarkPanelHub(); + fakeAddImpression = sandbox.stub(); + fakeHandleMessageRequest = sandbox.stub(); + [ + { content: fakeMessageFluent }, + { content: fakeMessage }, + ] = await PanelTestProvider.getMessages(); + fakeContainer = { + addEventListener: sandbox.stub(), + setAttribute: sandbox.stub(), + removeAttribute: sandbox.stub(), + classList: { add: sandbox.stub() }, + appendChild: sandbox.stub(), + querySelector: sandbox.stub(), + children: [], + style: {}, + getBoundingClientRect: sandbox.stub(), + }; + const document = { + createElementNS: sandbox.stub().returns(fakeContainer), + getElementById: sandbox.stub().returns(fakeContainer), + l10n: fakeL10n, + }; + fakeWindow = { + ownerGlobal: { + openLinkIn: sandbox.stub(), + gBrowser: { selectedBrowser: "browser" }, + }, + MozXULElement: { insertFTLIfNeeded: sandbox.stub() }, + document, + requestAnimationFrame: x => x(), + }; + fakeTarget = { + document, + container: { + querySelector: sandbox.stub(), + appendChild: sandbox.stub(), + setAttribute: sandbox.stub(), + removeAttribute: sandbox.stub(), + }, + hidePopup: sandbox.stub(), + infoButton: {}, + close: sandbox.stub(), + browser: { + ownerGlobal: { + gBrowser: { ownerDocument: document }, + window: fakeWindow, + }, + }, + }; + fakeSendTelemetry = sandbox.stub(); + }); + afterEach(() => { + instance.uninit(); + sandbox.restore(); + globals.restore(); + }); + it("should create an instance", () => { + assert.ok(instance); + }); + it("should uninit", () => { + instance.uninit(); + + assert.isFalse(instance._initialized); + assert.isNull(instance._addImpression); + assert.isNull(instance._handleMessageRequest); + }); + it("should instantiate handleMessageRequest and addImpression and l10n", () => { + instance.init( + fakeHandleMessageRequest, + fakeAddImpression, + fakeSendTelemetry + ); + + assert.equal(instance._addImpression, fakeAddImpression); + assert.equal(instance._handleMessageRequest, fakeHandleMessageRequest); + assert.equal(instance._sendTelemetry, fakeSendTelemetry); + assert.ok(instance._l10n); + assert.isTrue(instance._initialized); + }); + it("should return early if not initialized", async () => { + assert.isFalse(await instance.messageRequest()); + }); + describe("#messageRequest", () => { + beforeEach(() => { + sandbox.stub(instance, "onResponse"); + instance.init( + fakeHandleMessageRequest, + fakeAddImpression, + fakeSendTelemetry + ); + }); + afterEach(() => { + sandbox.restore(); + }); + it("should not re-request messages for the same URL", async () => { + instance._response = { url: "foo.com", content: true }; + fakeTarget.url = "foo.com"; + sandbox.stub(instance, "showMessage"); + + await instance.messageRequest(fakeTarget); + + assert.notCalled(fakeHandleMessageRequest); + assert.calledOnce(instance.showMessage); + }); + it("should call handleMessageRequest", async () => { + fakeHandleMessageRequest.resolves(fakeMessage); + + await instance.messageRequest(fakeTarget, {}); + + assert.calledOnce(fakeHandleMessageRequest); + assert.calledWithExactly(fakeHandleMessageRequest, { + triggerId: instance._trigger.id, + }); + }); + it("should call onResponse", async () => { + fakeHandleMessageRequest.resolves(fakeMessage); + + await instance.messageRequest(fakeTarget, {}); + + assert.calledOnce(instance.onResponse); + assert.calledWithExactly( + instance.onResponse, + fakeMessage, + fakeTarget, + {} + ); + }); + }); + describe("#onResponse", () => { + beforeEach(() => { + instance.init( + fakeHandleMessageRequest, + fakeAddImpression, + fakeSendTelemetry + ); + sandbox.stub(instance, "showMessage"); + sandbox.stub(instance, "sendImpression"); + sandbox.stub(instance, "hideMessage"); + fakeTarget = { infoButton: { disabled: true } }; + }); + it("should show a message when called with a response", () => { + instance.onResponse({ content: "content" }, fakeTarget, fakeWindow); + + assert.calledOnce(instance.showMessage); + assert.calledWithExactly( + instance.showMessage, + "content", + fakeTarget, + fakeWindow + ); + assert.calledOnce(instance.sendImpression); + }); + it("should insert the appropriate ftl files with translations", () => { + instance.onResponse({ content: "content" }, fakeTarget, fakeWindow); + + assert.calledTwice(fakeWindow.MozXULElement.insertFTLIfNeeded); + assert.calledWith( + fakeWindow.MozXULElement.insertFTLIfNeeded, + "browser/newtab/asrouter.ftl" + ); + assert.calledWith( + fakeWindow.MozXULElement.insertFTLIfNeeded, + "browser/branding/sync-brand.ftl" + ); + }); + it("should dispatch a user impression", () => { + sandbox.spy(instance, "sendUserEventTelemetry"); + + instance.onResponse({ content: "content" }, fakeTarget, fakeWindow); + + assert.calledOnce(instance.sendUserEventTelemetry); + assert.calledWithExactly( + instance.sendUserEventTelemetry, + "IMPRESSION", + fakeWindow + ); + assert.calledOnce(fakeSendTelemetry); + + const [ping] = fakeSendTelemetry.firstCall.args; + + assert.equal(ping.type, "DOORHANGER_TELEMETRY"); + assert.equal(ping.data.event, "IMPRESSION"); + }); + it("should not dispatch a user impression if the window is private", () => { + isBrowserPrivateStub.returns(true); + sandbox.spy(instance, "sendUserEventTelemetry"); + + instance.onResponse({ content: "content" }, fakeTarget, fakeWindow); + + assert.calledOnce(instance.sendUserEventTelemetry); + assert.calledWithExactly( + instance.sendUserEventTelemetry, + "IMPRESSION", + fakeWindow + ); + assert.notCalled(fakeSendTelemetry); + }); + it("should hide existing messages if no response is provided", () => { + instance.onResponse(null, fakeTarget); + + assert.calledOnce(instance.hideMessage); + assert.calledWithExactly(instance.hideMessage, fakeTarget); + }); + }); + describe("#showMessage.collapsed=false", () => { + beforeEach(() => { + instance.init( + fakeHandleMessageRequest, + fakeAddImpression, + fakeSendTelemetry + ); + sandbox.stub(instance, "toggleRecommendation"); + sandbox.stub(instance, "_response").value({ collapsed: false }); + }); + it("should create a container", () => { + fakeTarget.container.querySelector.returns(false); + + instance.showMessage(fakeMessage, fakeTarget); + + assert.equal(fakeTarget.document.createElementNS.callCount, 6); + assert.calledOnce(fakeTarget.container.appendChild); + assert.notCalled(fakeL10n.setAttributes); + }); + it("should create a container (fluent message)", () => { + fakeTarget.container.querySelector.returns(false); + + instance.showMessage(fakeMessageFluent, fakeTarget); + + assert.equal(fakeTarget.document.createElementNS.callCount, 6); + assert.calledOnce(fakeTarget.container.appendChild); + }); + it("should set l10n attributes", () => { + fakeTarget.container.querySelector.returns(false); + + instance.showMessage(fakeMessageFluent, fakeTarget); + + assert.equal(fakeL10n.setAttributes.callCount, 4); + }); + it("call adjust panel height when height is > 150px", async () => { + fakeTarget.container.querySelector.returns(false); + fakeContainer.getBoundingClientRect.returns({ height: 160 }); + + await instance._adjustPanelHeight(fakeWindow, fakeContainer); + + assert.calledOnce(fakeWindow.document.l10n.translateElements); + assert.calledTwice(fakeContainer.getBoundingClientRect); + assert.calledWithExactly( + fakeContainer.classList.add, + "longMessagePadding" + ); + }); + it("should reuse the container", () => { + fakeTarget.container.querySelector.returns(true); + + instance.showMessage(fakeMessage, fakeTarget); + + assert.notCalled(fakeTarget.container.appendChild); + }); + it("should open a tab with FxA signup", async () => { + fakeTarget.container.querySelector.returns(false); + + instance.showMessage(fakeMessage, fakeTarget, fakeWindow); + // Call the event listener cb + await fakeContainer.addEventListener.firstCall.args[1](); + + assert.calledOnce(fakeWindow.ownerGlobal.openLinkIn); + }); + it("should send a click event", async () => { + sandbox.stub(instance, "sendUserEventTelemetry"); + fakeTarget.container.querySelector.returns(false); + + instance.showMessage(fakeMessage, fakeTarget, fakeWindow); + // Call the event listener cb + await fakeContainer.addEventListener.firstCall.args[1](); + + assert.calledOnce(instance.sendUserEventTelemetry); + assert.calledWithExactly( + instance.sendUserEventTelemetry, + "CLICK", + fakeWindow + ); + }); + it("should send a click event", async () => { + sandbox.stub(instance, "sendUserEventTelemetry"); + fakeTarget.container.querySelector.returns(false); + + instance.showMessage(fakeMessage, fakeTarget, fakeWindow); + // Call the event listener cb + await fakeContainer.addEventListener.firstCall.args[1](); + + assert.calledOnce(instance.sendUserEventTelemetry); + assert.calledWithExactly( + instance.sendUserEventTelemetry, + "CLICK", + fakeWindow + ); + }); + it("should collapse the message", () => { + fakeTarget.container.querySelector.returns(false); + sandbox.spy(instance, "collapseMessage"); + instance._response.collapsed = false; + + instance.showMessage(fakeMessage, fakeTarget, fakeWindow); + // Show message calls it once so we need to reset + instance.toggleRecommendation.reset(); + // Call the event listener cb + fakeContainer.addEventListener.secondCall.args[1](); + + assert.calledOnce(instance.collapseMessage); + assert.calledOnce(fakeTarget.close); + assert.isTrue(instance._response.collapsed); + assert.calledOnce(instance.toggleRecommendation); + }); + it("should send a dismiss event", () => { + sandbox.stub(instance, "sendUserEventTelemetry"); + sandbox.spy(instance, "collapseMessage"); + instance._response.collapsed = false; + + instance.showMessage(fakeMessage, fakeTarget, fakeWindow); + // Call the event listener cb + fakeContainer.addEventListener.secondCall.args[1](); + + assert.calledOnce(instance.sendUserEventTelemetry); + assert.calledWithExactly( + instance.sendUserEventTelemetry, + "DISMISS", + fakeWindow + ); + }); + it("should call toggleRecommendation `true`", () => { + instance.showMessage(fakeMessage, fakeTarget, fakeWindow); + + assert.calledOnce(instance.toggleRecommendation); + assert.calledWithExactly(instance.toggleRecommendation, true); + }); + }); + describe("#showMessage.collapsed=true", () => { + beforeEach(() => { + sandbox + .stub(instance, "_response") + .value({ collapsed: true, target: fakeTarget }); + sandbox.stub(instance, "toggleRecommendation"); + }); + it("should return early if the message is collapsed", () => { + instance.showMessage(); + + assert.calledOnce(instance.toggleRecommendation); + assert.calledWithExactly(instance.toggleRecommendation, false); + }); + }); + describe("#hideMessage", () => { + let removeStub; + beforeEach(() => { + sandbox.stub(instance, "toggleRecommendation"); + removeStub = sandbox.stub(); + fakeTarget = { + container: { + querySelector: sandbox.stub().returns({ remove: removeStub }), + }, + }; + instance._response = { win: fakeWindow }; + }); + it("should remove the message", () => { + instance.hideMessage(fakeTarget); + + assert.calledOnce(removeStub); + }); + it("should call toggleRecommendation `false`", () => { + instance.hideMessage(fakeTarget); + + assert.calledOnce(instance.toggleRecommendation); + assert.calledWithExactly(instance.toggleRecommendation, false); + }); + }); + describe("#toggleRecommendation", () => { + let target; + beforeEach(() => { + target = { + infoButton: {}, + container: { + setAttribute: sandbox.stub(), + removeAttribute: sandbox.stub(), + }, + }; + sandbox.stub(instance, "_response").value({ target }); + }); + it("should check infoButton", () => { + instance.toggleRecommendation(true); + + assert.isTrue(target.infoButton.checked); + }); + it("should uncheck infoButton", () => { + instance.toggleRecommendation(false); + + assert.isFalse(target.infoButton.checked); + }); + it("should uncheck infoButton", () => { + target.infoButton.checked = true; + + instance.toggleRecommendation(); + + assert.isFalse(target.infoButton.checked); + }); + it("should disable the container", () => { + target.infoButton.checked = true; + + instance.toggleRecommendation(); + + assert.calledOnce(target.container.setAttribute); + }); + it("should enable container", () => { + target.infoButton.checked = false; + + instance.toggleRecommendation(); + + assert.calledOnce(target.container.removeAttribute); + }); + }); + describe("#forceShowMessage", () => { + it("should call showMessage with the correct args", () => { + sandbox.spy(instance, "showMessage"); + sandbox.stub(instance, "hideMessage"); + + instance.forceShowMessage(fakeTarget.browser, { content: fakeMessage }); + + assert.calledOnce(instance.showMessage); + assert.calledOnce(instance.hideMessage); + assert.calledWithExactly( + instance.showMessage, + fakeMessage, + sinon.match.object, + fakeWindow + ); + }); + it("should insert required fluent files", () => { + sandbox.stub(instance, "showMessage"); + + instance.forceShowMessage(fakeTarget.browser, { content: fakeMessage }); + + assert.calledTwice(fakeWindow.MozXULElement.insertFTLIfNeeded); + }); + it("should insert a message you can collapse", () => { + sandbox.spy(instance, "showMessage"); + sandbox.stub(instance, "toggleRecommendation"); + sandbox.stub(instance, "sendUserEventTelemetry"); + + instance.forceShowMessage(fakeTarget.browser, { content: fakeMessage }); + + const [ + , + eventListenerCb, + ] = fakeContainer.addEventListener.secondCall.args; + // Called with `true` to show the message + instance.toggleRecommendation.reset(); + eventListenerCb({ stopPropagation: sandbox.stub() }); + + assert.calledWithExactly(instance.toggleRecommendation, false); + }); + }); + describe("#sendImpression", () => { + beforeEach(() => { + instance.init( + fakeHandleMessageRequest, + fakeAddImpression, + fakeSendTelemetry + ); + instance._response = "foo"; + }); + it("should dispatch an impression", () => { + instance.sendImpression(); + + assert.calledOnce(fakeAddImpression); + assert.equal(fakeAddImpression.firstCall.args[0], "foo"); + }); + }); +}); |