diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index 1677ebf859..13059970c3 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -633,6 +633,28 @@ describe("OverlayBackground", () => { expect(repositionInlineMenuSpy).toHaveBeenCalled(); }); }); + + describe("toggleInlineMenuHidden", () => { + beforeEach(async () => { + await initOverlayElementPorts(); + }); + + it("skips adjusting the hidden status of the inline menu if the sender tab does not contain the focused field", async () => { + const focusedFieldData = createFocusedFieldDataMock({ tabId: 2 }); + sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }, sender); + const otherSender = mock({ tab: { id: 2 } }); + + await overlayBackground["toggleInlineMenuHidden"]( + { isInlineMenuHidden: true }, + otherSender, + ); + + expect(buttonPortSpy.postMessage).not.toHaveBeenCalledWith({ + command: "toggleAutofillInlineMenuHidden", + styles: { display: "none" }, + }); + }); + }); }); }); @@ -1087,6 +1109,9 @@ describe("OverlayBackground", () => { }); it("sends a message to close the inline menu if the form field is not focused and not filling", async () => { + overlayBackground["isInlineMenuButtonVisible"] = true; + overlayBackground["isInlineMenuListVisible"] = true; + sendMockExtensionMessage({ command: "closeAutofillInlineMenu" }, sender); await flushPromises(); @@ -1098,6 +1123,32 @@ describe("OverlayBackground", () => { }, { frameId: 0 }, ); + expect(overlayBackground["isInlineMenuButtonVisible"]).toBe(false); + expect(overlayBackground["isInlineMenuListVisible"]).toBe(false); + }); + + it("sets a property indicating that the inline menu button is not visible", async () => { + overlayBackground["isInlineMenuButtonVisible"] = true; + + sendMockExtensionMessage( + { command: "closeAutofillInlineMenu", overlayElement: AutofillOverlayElement.Button }, + sender, + ); + await flushPromises(); + + expect(overlayBackground["isInlineMenuButtonVisible"]).toBe(false); + }); + + it("sets a property indicating that the inline menu list is not visible", async () => { + overlayBackground["isInlineMenuListVisible"] = true; + + sendMockExtensionMessage( + { command: "closeAutofillInlineMenu", overlayElement: AutofillOverlayElement.List }, + sender, + ); + await flushPromises(); + + expect(overlayBackground["isInlineMenuListVisible"]).toBe(false); }); }); @@ -1106,6 +1157,21 @@ describe("OverlayBackground", () => { await initOverlayElementPorts(); }); + it("skips checking if the inline menu is focused if the sender does not contain the focused field", async () => { + const sender = mock({ tab: { id: 1 } }); + const focusedFieldData = createFocusedFieldDataMock(); + sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }); + + sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" }, sender); + + expect(listPortSpy.postMessage).not.toHaveBeenCalledWith({ + command: "checkAutofillInlineMenuListFocused", + }); + expect(buttonPortSpy.postMessage).not.toHaveBeenCalledWith({ + command: "checkAutofillInlineMenuButtonFocused", + }); + }); + it("will check if the inline menu list is focused if the list port is open", () => { sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" }); @@ -1314,6 +1380,70 @@ describe("OverlayBackground", () => { }); }); + describe("updateAutofillInlineMenuElementIsVisibleStatus message handler", () => { + let sender: chrome.runtime.MessageSender; + let focusedFieldData: FocusedFieldData; + + beforeEach(() => { + sender = mock({ tab: { id: 1 } }); + focusedFieldData = createFocusedFieldDataMock(); + overlayBackground["isInlineMenuButtonVisible"] = true; + overlayBackground["isInlineMenuListVisible"] = false; + }); + + it("skips updating the inline menu visibility status if the sender tab does not contain the focused field", async () => { + const otherSender = mock({ tab: { id: 2 } }); + sendMockExtensionMessage( + { command: "updateFocusedFieldData", focusedFieldData }, + otherSender, + ); + + sendMockExtensionMessage( + { + command: "updateAutofillInlineMenuElementIsVisibleStatus", + overlayElement: AutofillOverlayElement.Button, + isInlineMenuElementVisible: false, + }, + sender, + ); + + expect(overlayBackground["isInlineMenuButtonVisible"]).toBe(true); + expect(overlayBackground["isInlineMenuListVisible"]).toBe(false); + }); + + it("updates the visibility status of the inline menu button", async () => { + sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }, sender); + + sendMockExtensionMessage( + { + command: "updateAutofillInlineMenuElementIsVisibleStatus", + overlayElement: AutofillOverlayElement.Button, + isInlineMenuElementVisible: false, + }, + sender, + ); + + expect(overlayBackground["isInlineMenuButtonVisible"]).toBe(false); + expect(overlayBackground["isInlineMenuListVisible"]).toBe(false); + }); + + it("updates the visibility status of the inline menu list", async () => { + sendMockExtensionMessage({ command: "updateFocusedFieldData", focusedFieldData }, sender); + + sendMockExtensionMessage( + { + command: "updateAutofillInlineMenuElementIsVisibleStatus", + overlayElement: AutofillOverlayElement.List, + isInlineMenuElementVisible: true, + }, + sender, + ); + + expect(overlayBackground["isInlineMenuButtonVisible"]).toBe(true); + expect(overlayBackground["isInlineMenuListVisible"]).toBe(true); + }); + }); + describe("checkIsAutofillInlineMenuButtonVisible message handler", () => { it("returns true when the inline menu button is visible", async () => { overlayBackground["isInlineMenuButtonVisible"] = true; diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index e95e5ff9d6..7795126ecf 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -589,6 +589,11 @@ export class OverlayBackground implements OverlayBackgroundInterface { this.isInlineMenuListVisible = false; } + if (!overlayElement) { + this.isInlineMenuButtonVisible = false; + this.isInlineMenuListVisible = false; + } + void BrowserApi.tabSendMessage(sender.tab, { command, overlayElement }, sendOptions); } @@ -1233,15 +1238,25 @@ export class OverlayBackground implements OverlayBackgroundInterface { return; } - if (this.focusedFieldData.frameId > 0 && this.subFrameOffsetsForTab[sender.tab.id]) { - this.subFrameOffsetsForTab[sender.tab.id].set(this.focusedFieldData.frameId, null); - } - + this.resetFocusedFieldSubFrameOffsets(sender); this.cancelInlineMenuFadeInAndPositionUpdate(); void this.toggleInlineMenuHidden({ isInlineMenuHidden: true }, sender); this.repositionInlineMenuSubject.next(sender); } + /** + * Sets the sub frame offsets for the currently focused field's frame to a null value . + * This ensures that we can delay presentation of the inline menu after a reposition + * event if the user clicks on a field before the sub frames can be rebuilt. + * + * @param sender + */ + private resetFocusedFieldSubFrameOffsets(sender: chrome.runtime.MessageSender) { + if (this.focusedFieldData.frameId > 0 && this.subFrameOffsetsForTab[sender.tab.id]) { + this.subFrameOffsetsForTab[sender.tab.id].set(this.focusedFieldData.frameId, null); + } + } + /** * Triggers when a focus event occurs within a tab. Will reposition the inline menu * if the focused field is within the viewport.