From 4ecbfb3d49c7f62155b7a318fb993365f5b15418 Mon Sep 17 00:00:00 2001 From: Cesar Gonzalez Date: Tue, 4 Jun 2024 17:47:04 -0500 Subject: [PATCH] [PM-5189] Working through jest tests for OverlayBackground --- .../background/overlay.background.spec.ts | 143 ++++++++++++++---- .../autofill/background/overlay.background.ts | 7 + 2 files changed, 124 insertions(+), 26 deletions(-) diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index 7f746abcbc8..dbece263aaa 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -30,6 +30,7 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi import { BrowserApi } from "../../platform/browser/browser-api"; import { BrowserPlatformUtilsService } from "../../platform/services/platform-utils/browser-platform-utils.service"; +import { AutofillOverlayElement } from "../enums/autofill-overlay.enum"; import { AutofillService } from "../services/abstractions/autofill.service"; import { createChromeTabMock, createAutofillPageDetailsMock } from "../spec/autofill-mocks"; import { flushPromises, sendMockExtensionMessage } from "../spec/testing-utils"; @@ -259,33 +260,33 @@ describe("OverlayBackground", () => { }); describe("re-positioning the inline menu within sub frames", () => { - describe("rebuildSubFrameOffsets", () => { - const tabId = 1; - const topFrameId = 0; - const middleFrameId = 10; - const bottomFrameId = 20; - let tab: chrome.tabs.Tab; + const tabId = 1; + const topFrameId = 0; + const middleFrameId = 10; + const bottomFrameId = 20; + let tab: chrome.tabs.Tab; - beforeEach(() => { - tab = createChromeTabMock({ id: tabId }); - overlayBackground["focusedFieldData"] = mock({ - tabId, - frameId: bottomFrameId, - }); - subFrameOffsetsSpy[tabId] = new Map([ - [topFrameId, { left: 1, top: 1, url: "https://top-frame.com" }], - [middleFrameId, { left: 2, top: 2, url: "https://middle-frame.com" }], - [bottomFrameId, { left: 3, top: 3, url: "https://bottom-frame.com" }], - ]); - tabsSendMessageSpy.mockResolvedValue( - mock({ - left: getFrameCounter, - top: getFrameCounter, - url: "url", - }), - ); + beforeEach(() => { + tab = createChromeTabMock({ id: tabId }); + overlayBackground["focusedFieldData"] = mock({ + tabId, + frameId: bottomFrameId, }); + subFrameOffsetsSpy[tabId] = new Map([ + [topFrameId, { left: 1, top: 1, url: "https://top-frame.com" }], + [middleFrameId, { left: 2, top: 2, url: "https://middle-frame.com" }], + [bottomFrameId, { left: 3, top: 3, url: "https://bottom-frame.com" }], + ]); + tabsSendMessageSpy.mockResolvedValue( + mock({ + left: getFrameCounter, + top: getFrameCounter, + url: "url", + }), + ); + }); + describe("rebuildSubFrameOffsets", () => { it("skips rebuilding sub frame offsets if the sender contains the currently focused field", () => { const sender = mock({ tab, frameId: bottomFrameId }); @@ -318,7 +319,7 @@ describe("OverlayBackground", () => { it("triggers an update of the inline menu position after rebuilding sub frames", async () => { jest.useFakeTimers(); - overlayBackground["updateInlineMenuPositionTimeout"] = 1; + overlayBackground["updateInlineMenuPositionTimeout"] = setTimeout(jest.fn, 650); const sender = mock({ tab, frameId: middleFrameId }); jest.spyOn(overlayBackground as any, "updateInlineMenuPositionAfterSubFrameRebuild"); @@ -332,6 +333,96 @@ describe("OverlayBackground", () => { }); }); - describe("updateInlineMenuPositionAfterSubFrameRebuild", () => {}); + describe("updateInlineMenuPositionAfterSubFrameRebuild", () => { + let sender: chrome.runtime.MessageSender; + + async function flushInlineMenuUpdatePromises() { + await flushPromises(); + jest.advanceTimersByTime(650); + await flushPromises(); + } + + beforeEach(() => { + sender = mock({ tab, frameId: middleFrameId }); + jest.useFakeTimers(); + overlayBackground["isFieldCurrentlyFocused"] = true; + }); + + it("skips updating the position of either inline menu element if a field is not currently focused", async () => { + overlayBackground["isFieldCurrentlyFocused"] = false; + + sendMockExtensionMessage({ command: "rebuildSubFrameOffsets" }, sender); + await flushInlineMenuUpdatePromises(); + + expect(tabsSendMessageSpy).not.toHaveBeenCalledWith( + sender.tab, + { + command: "appendInlineMenuElementsToDom", + overlayElement: AutofillOverlayElement.Button, + }, + { frameId: 0 }, + ); + expect(tabsSendMessageSpy).not.toHaveBeenCalledWith( + sender.tab, + { + command: "appendInlineMenuElementsToDom", + overlayElement: AutofillOverlayElement.List, + }, + { frameId: 0 }, + ); + }); + + it("updates the position of the inline menu elements", async () => { + sendMockExtensionMessage({ command: "rebuildSubFrameOffsets" }, sender); + await flushInlineMenuUpdatePromises(); + + expect(tabsSendMessageSpy).toHaveBeenCalledWith( + sender.tab, + { + command: "appendInlineMenuElementsToDom", + overlayElement: AutofillOverlayElement.Button, + }, + { frameId: 0 }, + ); + expect(tabsSendMessageSpy).toHaveBeenCalledWith( + sender.tab, + { + command: "appendInlineMenuElementsToDom", + overlayElement: AutofillOverlayElement.List, + }, + { frameId: 0 }, + ); + }); + + it("skips updating the inline menu list if the focused field has a value and the user status is not unlocked", async () => { + overlayBackground["userAuthStatus"] = AuthenticationStatus.Locked; + tabsSendMessageSpy.mockImplementation((_tab, message, _options) => { + if (message.command === "checkMostRecentlyFocusedFieldHasValue") { + return Promise.resolve(true); + } + return Promise.resolve(); + }); + + sendMockExtensionMessage({ command: "rebuildSubFrameOffsets" }, sender); + await flushInlineMenuUpdatePromises(); + + expect(tabsSendMessageSpy).toHaveBeenCalledWith( + sender.tab, + { + command: "appendInlineMenuElementsToDom", + overlayElement: AutofillOverlayElement.Button, + }, + { frameId: 0 }, + ); + expect(tabsSendMessageSpy).not.toHaveBeenCalledWith( + sender.tab, + { + command: "appendInlineMenuElementsToDom", + overlayElement: AutofillOverlayElement.List, + }, + { frameId: 0 }, + ); + }); + }); }); }); diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 8eb5389a4bd..3b9ea490fd7 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -371,6 +371,13 @@ export class OverlayBackground implements OverlayBackgroundInterface { ); } + /** + * Handles updating the inline menu's position after rebuilding the sub frames + * for the provided tab. Will skip repositioning the inline menu if the field + * is not currently focused, or if the focused field has a value. + * + * @param sender - The sender of the message + */ private async updateInlineMenuPositionAfterSubFrameRebuild(sender: chrome.runtime.MessageSender) { if (!this.isFieldCurrentlyFocused) { return;