From 23a369bdf6ca2e9594e692c9160f680b4aff9f1c Mon Sep 17 00:00:00 2001 From: Cesar Gonzalez Date: Thu, 26 Sep 2024 11:57:00 -0500 Subject: [PATCH] [PM-8833] Fixing broken jest tests for OverlayBackground --- .../background/overlay.background.spec.ts | 358 +++++------------- 1 file changed, 100 insertions(+), 258 deletions(-) diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index e600cc353a..8a4954c63f 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -43,6 +43,7 @@ import { BrowserPlatformUtilsService } from "../../platform/services/platform-ut import { AutofillOverlayElement, AutofillOverlayPort, + InlineMenuFillType, MAX_SUB_FRAME_DEPTH, RedirectFocusDirection, } from "../enums/autofill-overlay.enum"; @@ -121,6 +122,7 @@ describe("OverlayBackground", () => { const { initList, initButton } = options; if (initButton) { triggerPortOnConnectEvent(createPortSpyMock(AutofillOverlayPort.Button)); + await flushPromises(); buttonPortSpy = overlayBackground["inlineMenuButtonPort"]; buttonMessageConnectorSpy = createPortSpyMock(AutofillOverlayPort.ButtonMessageConnector); @@ -129,6 +131,7 @@ describe("OverlayBackground", () => { if (initList) { triggerPortOnConnectEvent(createPortSpyMock(AutofillOverlayPort.List)); + await flushPromises(); listPortSpy = overlayBackground["inlineMenuListPort"]; listMessageConnectorSpy = createPortSpyMock(AutofillOverlayPort.ListMessageConnector); @@ -173,7 +176,9 @@ describe("OverlayBackground", () => { selectedThemeMock$ = new BehaviorSubject(ThemeType.Light); inlineMenuFieldQualificationService = mock(); themeStateService = mock(); - passwordGenerationService = mock(); + passwordGenerationService = mock({ + getOptions: jest.fn().mockResolvedValue([null, null]), + }); themeStateService.selectedTheme$ = selectedThemeMock$; overlayBackground = new OverlayBackground( logService, @@ -560,7 +565,10 @@ describe("OverlayBackground", () => { command: "updateIsFieldCurrentlyFocused", isFieldCurrentlyFocused: false, }, - mock({ frameId: 20 }), + mock({ + tab: createChromeTabMock({ id: 1 }), + frameId: 20, + }), ); sendMockExtensionMessage({ command: "triggerAutofillOverlayReposition" }, sender); @@ -800,21 +808,6 @@ describe("OverlayBackground", () => { expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled(); }); - it("closes the inline menu on the focused field's tab if the user's auth status is not unlocked", async () => { - activeAccountStatusMock$.next(AuthenticationStatus.Locked); - const previousTab = mock({ id: 1 }); - overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({ tabId: 1 }); - getTabSpy.mockResolvedValueOnce(previousTab); - - await overlayBackground.updateOverlayCiphers(); - - expect(tabsSendMessageSpy).toHaveBeenCalledWith( - previousTab, - { command: "closeAutofillInlineMenu", overlayElement: undefined }, - { frameId: 0 }, - ); - }); - it("closes the inline menu on the focused field's tab if current tab is different", async () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); cipherService.getAllDecryptedForUrl.mockResolvedValue([loginCipher1, cardCipher]); @@ -824,6 +817,7 @@ describe("OverlayBackground", () => { getTabSpy.mockResolvedValueOnce(previousTab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(tabsSendMessageSpy).toHaveBeenCalledWith( previousTab, @@ -838,6 +832,7 @@ describe("OverlayBackground", () => { cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(BrowserApi.getTabFromCurrentWindowId).toHaveBeenCalled(); expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith(url, [ @@ -860,6 +855,7 @@ describe("OverlayBackground", () => { cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1); await overlayBackground.updateOverlayCiphers(false); + await flushPromises(); expect(BrowserApi.getTabFromCurrentWindowId).toHaveBeenCalled(); expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith(url); @@ -878,6 +874,7 @@ describe("OverlayBackground", () => { cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1); await overlayBackground.updateOverlayCiphers(false); + await flushPromises(); expect(BrowserApi.getTabFromCurrentWindowId).toHaveBeenCalled(); expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith(url, [ @@ -893,18 +890,20 @@ describe("OverlayBackground", () => { ); }); - it("posts an `updateOverlayListCiphers` message to the overlay list port, and send a `updateAutofillInlineMenuListCiphers` message to the tab indicating that the list of ciphers is populated", async () => { + it("posts an `updateAutofillInlineMenuListCiphers` message to the overlay list port, and send a `updateAutofillInlineMenuListCiphers` message to the tab indicating that the list of ciphers is populated", async () => { overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({ tabId: tab.id }); cipherService.getAllDecryptedForUrl.mockResolvedValue([loginCipher1]); cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1); getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", showInlineMenuAccountCreation: false, showPasskeysLabels: false, + focusedFieldHasValue: false, ciphers: [ { accountCreationFieldType: undefined, @@ -938,11 +937,13 @@ describe("OverlayBackground", () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", showInlineMenuAccountCreation: false, showPasskeysLabels: false, + focusedFieldHasValue: false, ciphers: [ { accountCreationFieldType: undefined, @@ -974,11 +975,13 @@ describe("OverlayBackground", () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", showInlineMenuAccountCreation: true, showPasskeysLabels: false, + focusedFieldHasValue: false, ciphers: [ { accountCreationFieldType: "text", @@ -1006,17 +1009,20 @@ describe("OverlayBackground", () => { overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({ tabId: tab.id, accountCreationFieldType: "text", + inlineMenuFillType: InlineMenuFillType.AccountCreationUsername, }); cipherService.getAllDecryptedForUrl.mockResolvedValue([loginCipher1, identityCipher]); cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1); getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", showInlineMenuAccountCreation: true, showPasskeysLabels: false, + focusedFieldHasValue: false, ciphers: [ { accountCreationFieldType: "text", @@ -1081,11 +1087,13 @@ describe("OverlayBackground", () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", showInlineMenuAccountCreation: true, showPasskeysLabels: false, + focusedFieldHasValue: false, ciphers: [ { accountCreationFieldType: "email", @@ -1119,11 +1127,13 @@ describe("OverlayBackground", () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", showInlineMenuAccountCreation: true, showPasskeysLabels: false, + focusedFieldHasValue: false, ciphers: [], }); }); @@ -1145,6 +1155,7 @@ describe("OverlayBackground", () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", @@ -1209,6 +1220,7 @@ describe("OverlayBackground", () => { ], showInlineMenuAccountCreation: false, showPasskeysLabels: true, + focusedFieldHasValue: false, }); }); @@ -1229,6 +1241,7 @@ describe("OverlayBackground", () => { neverDomainsMock$.next({ "jest-testing-website.com": null }); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", @@ -1272,6 +1285,7 @@ describe("OverlayBackground", () => { ], showInlineMenuAccountCreation: false, showPasskeysLabels: false, + focusedFieldHasValue: false, }); }); @@ -1292,6 +1306,7 @@ describe("OverlayBackground", () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); await overlayBackground.updateOverlayCiphers(); + await flushPromises(); expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "updateAutofillInlineMenuListCiphers", @@ -1335,6 +1350,7 @@ describe("OverlayBackground", () => { ], showInlineMenuAccountCreation: false, showPasskeysLabels: false, + focusedFieldHasValue: false, }); }); }); @@ -1888,6 +1904,7 @@ describe("OverlayBackground", () => { ciphers: [], showInlineMenuAccountCreation: true, showPasskeysLabels: false, + focusedFieldHasValue: false, }); }); @@ -2009,45 +2026,51 @@ describe("OverlayBackground", () => { let sender: chrome.runtime.MessageSender; beforeEach(() => { - sender = mock({ tab: { id: 1 } }); + sender = mock({ + tab: createChromeTabMock({ id: 1, url: "https://jest-testing-website.com" }), + }); getTabFromCurrentWindowIdSpy.mockResolvedValue(sender.tab); tabsSendMessageSpy.mockImplementation(); }); - it("opens the autofill inline menu by sending a message to the current tab", async () => { - sendMockExtensionMessage({ command: "openAutofillInlineMenu" }, sender); - await flushPromises(); + it.todo( + "updates the inline menu position of both button and list elements if the inline menu is being forced open", + ); - expect(tabsSendMessageSpy).toHaveBeenCalledWith( - sender.tab, - { - command: "openAutofillInlineMenu", - isFocusingFieldElement: false, - isOpeningFullInlineMenu: false, - authStatus: AuthenticationStatus.Unlocked, - }, - { frameId: 0 }, + describe("when the focused field does not have a value", () => { + beforeEach(() => { + jest + .spyOn(overlayBackground as any, "checkMostRecentlyFocusedFieldHasValue") + .mockResolvedValue(true); + }); + + it.todo( + "updates the position of the both button and list elements if the user has the inline menu set to show on field focus", + ); + + it.todo( + "closes the list if the user has the inline menu set to show on button click and the list is open", + ); + + it.todo( + "updates the position of the button if the user has the inline menu set to show on button click", ); }); - it("sends the open menu message to the focused field's frameId", async () => { - sender.frameId = 10; - sendMockExtensionMessage({ command: "updateFocusedFieldData" }, sender); - await flushPromises(); + describe("when the focused field has a value", () => { + beforeEach(() => { + jest + .spyOn(overlayBackground as any, "checkMostRecentlyFocusedFieldHasValue") + .mockResolvedValue(false); + }); - sendMockExtensionMessage({ command: "openAutofillInlineMenu" }, sender); - await flushPromises(); - - expect(tabsSendMessageSpy).toHaveBeenCalledWith( - sender.tab, - { - command: "openAutofillInlineMenu", - isFocusingFieldElement: false, - isOpeningFullInlineMenu: false, - authStatus: AuthenticationStatus.Unlocked, - }, - { frameId: 10 }, + it.todo( + "updates the position of both button and list elements if the inline menu is showing an account creation view", ); + + it.todo("closes the inline menu list if it is visible"); + + it.todo("updates the position of the inline menu button"); }); }); @@ -2242,195 +2265,6 @@ describe("OverlayBackground", () => { }); }); - describe("updateAutofillInlineMenuPosition message handler", () => { - beforeEach(async () => { - await initOverlayElementPorts(); - }); - - it("ignores updating the position if the overlay element type is not provided", () => { - sendMockExtensionMessage({ command: "updateAutofillInlineMenuPosition" }); - - expect(listPortSpy.postMessage).not.toHaveBeenCalledWith({ - command: "updateIframePosition", - styles: expect.anything(), - }); - expect(buttonPortSpy.postMessage).not.toHaveBeenCalledWith({ - command: "updateIframePosition", - styles: expect.anything(), - }); - }); - - it("skips updating the position if the most recently focused field is different than the message sender", () => { - const sender = mock({ tab: { id: 1 } }); - const focusedFieldData = createFocusedFieldDataMock({ tabId: 2 }); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); - - sendMockExtensionMessage({ command: "updateAutofillInlineMenuPosition" }, sender); - - expect(listPortSpy.postMessage).not.toHaveBeenCalledWith({ - command: "updateIframePosition", - styles: expect.anything(), - }); - expect(buttonPortSpy.postMessage).not.toHaveBeenCalledWith({ - command: "updateIframePosition", - styles: expect.anything(), - }); - }); - - it("updates the inline menu button's position", async () => { - const focusedFieldData = createFocusedFieldDataMock(); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); - - sendMockExtensionMessage({ - command: "updateAutofillInlineMenuPosition", - overlayElement: AutofillOverlayElement.Button, - }); - await flushPromises(); - - expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({ - command: "updateAutofillInlineMenuPosition", - styles: { height: "2px", left: "4px", top: "2px", width: "2px" }, - }); - }); - - it("modifies the inline menu button's height for medium sized input elements", async () => { - const focusedFieldData = createFocusedFieldDataMock({ - focusedFieldRects: { top: 1, left: 2, height: 35, width: 4 }, - }); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); - - sendMockExtensionMessage({ - command: "updateAutofillInlineMenuPosition", - overlayElement: AutofillOverlayElement.Button, - }); - await flushPromises(); - - expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({ - command: "updateAutofillInlineMenuPosition", - styles: { height: "20px", left: "-22px", top: "8px", width: "20px" }, - }); - }); - - it("modifies the inline menu button's height for large sized input elements", async () => { - const focusedFieldData = createFocusedFieldDataMock({ - focusedFieldRects: { top: 1, left: 2, height: 50, width: 4 }, - }); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); - - sendMockExtensionMessage({ - command: "updateAutofillInlineMenuPosition", - overlayElement: AutofillOverlayElement.Button, - }); - await flushPromises(); - - expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({ - command: "updateAutofillInlineMenuPosition", - styles: { height: "27px", left: "-32px", top: "13px", width: "27px" }, - }); - }); - - it("takes into account the right padding of the focused field in positioning the button if the right padding of the field is larger than the left padding", async () => { - const focusedFieldData = createFocusedFieldDataMock({ - focusedFieldStyles: { paddingRight: "20px", paddingLeft: "6px" }, - }); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); - - sendMockExtensionMessage({ - command: "updateAutofillInlineMenuPosition", - overlayElement: AutofillOverlayElement.Button, - }); - await flushPromises(); - - expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({ - command: "updateAutofillInlineMenuPosition", - styles: { height: "2px", left: "-18px", top: "2px", width: "2px" }, - }); - }); - - it("updates the inline menu list's position", async () => { - const focusedFieldData = createFocusedFieldDataMock(); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); - - sendMockExtensionMessage({ - command: "updateAutofillInlineMenuPosition", - overlayElement: AutofillOverlayElement.List, - }); - await flushPromises(); - - expect(listPortSpy.postMessage).toHaveBeenCalledWith({ - command: "updateAutofillInlineMenuPosition", - styles: { left: "2px", top: "4px", width: "4px" }, - }); - }); - - it("sends a message that triggers a simultaneous fade in for both inline menu elements", async () => { - jest.useFakeTimers(); - const focusedFieldData = createFocusedFieldDataMock(); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); - - sendMockExtensionMessage({ - command: "updateAutofillInlineMenuPosition", - overlayElement: AutofillOverlayElement.List, - }); - await flushPromises(); - jest.advanceTimersByTime(150); - - expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({ - command: "fadeInAutofillInlineMenuIframe", - }); - expect(listPortSpy.postMessage).toHaveBeenCalledWith({ - command: "fadeInAutofillInlineMenuIframe", - }); - }); - - describe("getAutofillInlineMenuPosition", () => { - it("returns the current inline menu position", async () => { - overlayBackground["inlineMenuPosition"] = { - button: { left: 1, top: 2, width: 3, height: 4 }, - }; - - sendMockExtensionMessage( - { command: "getAutofillInlineMenuPosition" }, - mock(), - sendResponse, - ); - await flushPromises(); - - expect(sendResponse).toHaveBeenCalledWith({ - button: { left: 1, top: 2, width: 3, height: 4 }, - }); - }); - }); - - it("triggers a debounced reposition of the inline menu if the sender frame has a `null` sub frame offsets value", async () => { - jest.useFakeTimers(); - const focusedFieldData = createFocusedFieldDataMock(); - const sender = mock({ - tab: { id: focusedFieldData.tabId }, - frameId: focusedFieldData.frameId, - }); - sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }, sender); - overlayBackground["subFrameOffsetsForTab"][focusedFieldData.tabId] = new Map([ - [focusedFieldData.frameId, null], - ]); - jest.spyOn(overlayBackground as any, "updateInlineMenuPositionAfterRepositionEvent"); - - sendMockExtensionMessage( - { - command: "updateAutofillInlineMenuPosition", - overlayElement: AutofillOverlayElement.List, - }, - sender, - ); - await flushPromises(); - jest.advanceTimersByTime(150); - - expect( - overlayBackground["updateInlineMenuPositionAfterRepositionEvent"], - ).toHaveBeenCalled(); - }); - }); - describe("updateAutofillInlineMenuElementIsVisibleStatus message handler", () => { let sender: chrome.runtime.MessageSender; let focusedFieldData: FocusedFieldData; @@ -2556,10 +2390,8 @@ describe("OverlayBackground", () => { }); describe("unlockCompleted", () => { - let updateInlineMenuCiphersSpy: jest.SpyInstance; - beforeEach(async () => { - updateInlineMenuCiphersSpy = jest.spyOn(overlayBackground, "updateOverlayCiphers"); + jest.spyOn(overlayBackground, "updateOverlayCiphers"); await initOverlayElementPorts(); }); @@ -2581,8 +2413,9 @@ describe("OverlayBackground", () => { expect(updateInlineMenuCiphersSpy).toHaveBeenCalled(); }); - it("opens the inline menu if a retry command is present in the message", async () => { - updateInlineMenuCiphersSpy.mockImplementation(); + it("focuses the most recently focused field if a retry command is present in the message", async () => { + activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); + cipherService.getAllDecryptedForUrl.mockResolvedValue([]); getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(createChromeTabMock({ id: 1 })); sendMockExtensionMessage({ command: "unlockCompleted", @@ -2592,16 +2425,9 @@ describe("OverlayBackground", () => { }); await flushPromises(); - expect(tabsSendMessageSpy).toHaveBeenCalledWith( - expect.any(Object), - { - command: "openAutofillInlineMenu", - isFocusingFieldElement: true, - isOpeningFullInlineMenu: false, - authStatus: AuthenticationStatus.Unlocked, - }, - { frameId: 0 }, - ); + expect(tabsSendMessageSpy).toHaveBeenCalledWith(expect.any(Object), { + command: "focusMostRecentlyFocusedField", + }); }); }); @@ -2670,12 +2496,13 @@ describe("OverlayBackground", () => { const portKey = "inlineMenuButtonPort"; beforeEach(async () => { - sender = mock({ tab: { id: 1 } }); + sender = mock({ tab: createChromeTabMock({ id: 1 }) }); portKeyForTabSpy[sender.tab.id] = portKey; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); await initOverlayElementPorts(); buttonMessageConnectorSpy.sender = sender; openUnlockPopoutSpy.mockImplementation(); + cipherService.getAllDecryptedForUrl.mockResolvedValue([]); }); describe("autofillInlineMenuButtonClicked message handler", () => { @@ -2706,6 +2533,16 @@ describe("OverlayBackground", () => { it("opens the inline menu if the user auth status is unlocked", async () => { getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(sender.tab); + sendMockExtensionMessage( + { + command: "updateFocusedFieldData", + focusedFieldData: mock(), + }, + mock({ tab: buttonMessageConnectorSpy.sender.tab }), + ); + jest + .spyOn(overlayBackground as any, "getInlineMenuButtonPosition") + .mockReturnValueOnce({ x: 0, y: 0 }); sendPortMessage(buttonMessageConnectorSpy, { command: "autofillInlineMenuButtonClicked", portKey, @@ -2715,10 +2552,8 @@ describe("OverlayBackground", () => { expect(tabsSendMessageSpy).toHaveBeenCalledWith( sender.tab, { - command: "openAutofillInlineMenu", - isFocusingFieldElement: false, - isOpeningFullInlineMenu: true, - authStatus: AuthenticationStatus.Unlocked, + command: "appendAutofillInlineMenuToDom", + overlayElement: AutofillOverlayElement.List, }, { frameId: 0 }, ); @@ -3105,10 +2940,17 @@ describe("OverlayBackground", () => { sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); await flushPromises(); - sendPortMessage(listMessageConnectorSpy, { command: "addNewVaultItem", portKey }); + sendPortMessage(listMessageConnectorSpy, { + command: "addNewVaultItem", + portKey, + addNewCipherType: CipherType.Login, + }); await flushPromises(); - expect(tabsSendMessageSpy).not.toHaveBeenCalled(); + expect(tabsSendMessageSpy).not.toHaveBeenCalledWith(sender.tab, { + command: "addNewVaultItemFromOverlay", + addNewCipherType: CipherType.Login, + }); }); it("sends a message to the tab to add a new vault item", async () => {