1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +00:00

[PM-5189] Refactoring implementation

This commit is contained in:
Cesar Gonzalez
2024-05-02 17:17:05 -05:00
parent b8ab84882d
commit 7355e63d0c
15 changed files with 239 additions and 220 deletions

View File

@@ -53,8 +53,8 @@ type OverlayBackgroundExtensionMessage = {
sender?: string;
details?: AutofillPageDetails;
overlayElement?: string;
forceCloseOverlay?: boolean;
isOverlayHidden?: boolean;
forceCloseAutofillInlineMenu?: boolean;
isAutofillInlineMenuHidden?: boolean;
setTransparentOverlay?: boolean;
isFieldCurrentlyFocused?: boolean;
isFieldCurrentlyFilling?: boolean;
@@ -97,13 +97,13 @@ type OverlayBackgroundExtensionMessageHandlers = {
autofillOverlayElementClosed: ({ message }: BackgroundMessageParam) => void;
autofillOverlayAddNewVaultItem: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
getInlineMenuVisibilitySetting: () => void;
checkAutofillOverlayMenuFocused: () => void;
focusAutofillOverlayMenuList: () => void;
updateAutofillOverlayMenuPosition: ({
checkAutofillInlineMenuFocused: () => void;
focusAutofillInlineMenuList: () => void;
updateAutofillInlineMenuPosition: ({
message,
sender,
}: BackgroundOnMessageHandlerParams) => Promise<void>;
updateAutofillOverlayMenuHidden: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
updateAutofillInlineMenuHidden: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
updateFocusedFieldData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
updateIsFieldCurrentlyFocused: ({ message }: BackgroundMessageParam) => void;
checkIsFieldCurrentlyFocused: () => boolean;
@@ -134,7 +134,7 @@ type OverlayButtonPortMessageHandlers = {
closeAutofillInlineMenu: ({ port }: PortConnectionParam) => void;
forceCloseAutofillOverlay: ({ port }: PortConnectionParam) => void;
overlayPageBlurred: () => void;
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
redirectInlineMenuFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
updateOverlayPageColorScheme: () => void;
};
@@ -147,7 +147,7 @@ type OverlayListPortMessageHandlers = {
fillSelectedListItem: ({ message, port }: PortOnMessageHandlerParams) => void;
addNewVaultItem: ({ port }: PortConnectionParam) => void;
viewSelectedCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
redirectInlineMenuFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
updateAutofillOverlayListHeight: ({ message, port }: PortOnMessageHandlerParams) => void;
};

View File

@@ -564,7 +564,7 @@ describe("OverlayBackground", () => {
expect(BrowserApi.tabSendMessage).not.toHaveBeenCalledWith(sender.tab, {
command: "openAutofillInlineMenu",
isFocusingFieldElement: false,
isOpeningFullOverlay: false,
isOpeningFullAutofillInlineMenu: false,
authStatus: AuthenticationStatus.Unlocked,
});
});
@@ -668,13 +668,13 @@ describe("OverlayBackground", () => {
});
});
describe("checkAutofillOverlayMenuFocused message handler", () => {
describe("checkAutofillInlineMenuFocused message handler", () => {
beforeEach(async () => {
await initOverlayElementPorts();
});
it("will check if the overlay list is focused if the list port is open", () => {
sendMockExtensionMessage({ command: "checkAutofillOverlayMenuFocused" });
sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" });
expect(listPortSpy.postMessage).toHaveBeenCalledWith({
command: "checkAutofillOverlayListFocused",
@@ -687,7 +687,7 @@ describe("OverlayBackground", () => {
it("will check if the overlay button is focused if the list port is not open", () => {
overlayBackground["overlayListPort"] = undefined;
sendMockExtensionMessage({ command: "checkAutofillOverlayMenuFocused" });
sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" });
expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({
command: "checkAutofillOverlayButtonFocused",
@@ -698,8 +698,8 @@ describe("OverlayBackground", () => {
});
});
describe("focusAutofillOverlayMenuList message handler", () => {
it("will send a `focusOverlayMenuList` message to the overlay list port", async () => {
describe("focusAutofillInlineMenuList message handler", () => {
it("will send a `focusInlineMenuList` message to the overlay list port", async () => {
await initOverlayElementPorts({
initList: true,
initButton: false,
@@ -707,13 +707,13 @@ describe("OverlayBackground", () => {
initListMessageConnectorSpy: false,
});
sendMockExtensionMessage({ command: "focusAutofillOverlayMenuList" });
sendMockExtensionMessage({ command: "focusAutofillInlineMenuList" });
expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "focusOverlayMenuList" });
expect(listPortSpy.postMessage).toHaveBeenCalledWith({ command: "focusInlineMenuList" });
});
});
describe("updateAutofillOverlayMenuPosition message handler", () => {
describe("updateAutofillInlineMenuPosition message handler", () => {
let sender: MockProxy<chrome.runtime.MessageSender>;
beforeEach(async () => {
@@ -731,7 +731,7 @@ describe("OverlayBackground", () => {
});
it("ignores updating the position if the overlay element type is not provided", () => {
sendMockExtensionMessage({ command: "updateAutofillOverlayMenuPosition" }, sender);
sendMockExtensionMessage({ command: "updateAutofillInlineMenuPosition" }, sender);
expect(listPortSpy.postMessage).not.toHaveBeenCalledWith({
command: "updateIframePosition",
@@ -749,7 +749,7 @@ describe("OverlayBackground", () => {
sendMockExtensionMessage(
{
command: "updateAutofillOverlayMenuPosition",
command: "updateAutofillInlineMenuPosition",
overlayElement: AutofillOverlayElement.Button,
},
sender,
@@ -770,7 +770,7 @@ describe("OverlayBackground", () => {
sendMockExtensionMessage(
{
command: "updateAutofillOverlayMenuPosition",
command: "updateAutofillInlineMenuPosition",
overlayElement: AutofillOverlayElement.Button,
},
sender,
@@ -791,7 +791,7 @@ describe("OverlayBackground", () => {
sendMockExtensionMessage(
{
command: "updateAutofillOverlayMenuPosition",
command: "updateAutofillInlineMenuPosition",
overlayElement: AutofillOverlayElement.Button,
},
sender,
@@ -812,7 +812,7 @@ describe("OverlayBackground", () => {
sendMockExtensionMessage(
{
command: "updateAutofillOverlayMenuPosition",
command: "updateAutofillInlineMenuPosition",
overlayElement: AutofillOverlayElement.Button,
},
sender,
@@ -831,7 +831,7 @@ describe("OverlayBackground", () => {
sendMockExtensionMessage(
{
command: "updateAutofillOverlayMenuPosition",
command: "updateAutofillInlineMenuPosition",
overlayElement: AutofillOverlayElement.List,
},
sender,
@@ -851,7 +851,10 @@ describe("OverlayBackground", () => {
});
it("sets the `display` CSS value on the overlay button and list", () => {
const message = { command: "updateAutofillOverlayMenuHidden", isOverlayHidden: true };
const message = {
command: "updateAutofillInlineMenuHidden",
isAutofillInlineMenuHidden: true,
};
sendMockExtensionMessage(message);
@@ -871,7 +874,7 @@ describe("OverlayBackground", () => {
it("sets the `opacity` CSS value on the overlay button and list", () => {
const message = {
command: "updateAutofillOverlayMenuHidden",
command: "updateAutofillInlineMenuHidden",
setTransparentOverlay: true,
};
@@ -998,7 +1001,7 @@ describe("OverlayBackground", () => {
{
command: "openAutofillInlineMenu",
isFocusingFieldElement: true,
isOpeningFullOverlay: false,
isOpeningFullAutofillInlineMenu: false,
authStatus: AuthenticationStatus.Unlocked,
},
{ frameId: 0 },
@@ -1036,7 +1039,7 @@ describe("OverlayBackground", () => {
describe("handlePortOnConnect", () => {
beforeEach(() => {
jest.spyOn(overlayBackground as any, "updateOverlayMenuPosition").mockImplementation();
jest.spyOn(overlayBackground as any, "updateInlineMenuPosition").mockImplementation();
jest.spyOn(overlayBackground as any, "getAuthStatus").mockImplementation();
jest.spyOn(overlayBackground as any, "getTranslations").mockImplementation();
jest.spyOn(overlayBackground as any, "getOverlayCipherData").mockImplementation();
@@ -1066,7 +1069,7 @@ describe("OverlayBackground", () => {
expect(chrome.runtime.getURL).toHaveBeenCalledWith("overlay/list.css");
expect(overlayBackground["getTranslations"]).toHaveBeenCalled();
expect(overlayBackground["getOverlayCipherData"]).toHaveBeenCalled();
expect(overlayBackground["updateOverlayMenuPosition"]).toHaveBeenCalledWith(
expect(overlayBackground["updateInlineMenuPosition"]).toHaveBeenCalledWith(
{ overlayElement: AutofillOverlayElement.List },
listPortSpy.sender,
);
@@ -1086,7 +1089,7 @@ describe("OverlayBackground", () => {
expect(overlayBackground["getAuthStatus"]).toHaveBeenCalled();
expect(chrome.runtime.getURL).toHaveBeenCalledWith("overlay/button.css");
expect(overlayBackground["getTranslations"]).toHaveBeenCalled();
expect(overlayBackground["updateOverlayMenuPosition"]).toHaveBeenCalledWith(
expect(overlayBackground["updateInlineMenuPosition"]).toHaveBeenCalledWith(
{ overlayElement: AutofillOverlayElement.Button },
buttonPortSpy.sender,
);
@@ -1176,7 +1179,7 @@ describe("OverlayBackground", () => {
});
describe("forceCloseAutofillOverlay", () => {
it("sends a `closeOverlay` message to the sender tab with a `forceCloseOverlay` flag of `true` set", () => {
it("sends a `closeOverlay` message to the sender tab with a `forceCloseAutofillInlineMenu` flag of `true` set", () => {
jest.spyOn(BrowserApi, "tabSendMessage");
sendPortMessage(buttonMessageConnectorPortSpy, {
@@ -1205,14 +1208,14 @@ describe("OverlayBackground", () => {
});
});
describe("redirectOverlayFocusOut", () => {
describe("redirectInlineMenuFocusOut", () => {
beforeEach(() => {
jest.spyOn(BrowserApi, "tabSendMessageData");
});
it("ignores the redirect message if the direction is not provided", () => {
sendPortMessage(buttonMessageConnectorPortSpy, {
command: "redirectOverlayFocusOut",
command: "redirectInlineMenuFocusOut",
portKey,
});
@@ -1221,14 +1224,14 @@ describe("OverlayBackground", () => {
it("sends the redirect message if the direction is provided", () => {
sendPortMessage(buttonMessageConnectorPortSpy, {
command: "redirectOverlayFocusOut",
command: "redirectInlineMenuFocusOut",
direction: RedirectFocusDirection.Next,
portKey,
});
expect(BrowserApi.tabSendMessageData).toHaveBeenCalledWith(
buttonMessageConnectorPortSpy.sender.tab,
"redirectOverlayFocusOut",
"redirectInlineMenuFocusOut",
{ direction: RedirectFocusDirection.Next },
);
});
@@ -1256,7 +1259,7 @@ describe("OverlayBackground", () => {
});
describe("forceCloseAutofillOverlay", () => {
it("sends a `closeOverlay` message to the sender tab with a `forceCloseOverlay` flag of `true` set", () => {
it("sends a `closeOverlay` message to the sender tab with a `forceCloseAutofillInlineMenu` flag of `true` set", () => {
jest.spyOn(BrowserApi, "tabSendMessage");
sendPortMessage(listMessageConnectorPortSpy, {
@@ -1518,16 +1521,16 @@ describe("OverlayBackground", () => {
});
});
describe("redirectOverlayFocusOut", () => {
describe("redirectInlineMenuFocusOut", () => {
it("redirects focus out of the overlay list", async () => {
const message = {
command: "redirectOverlayFocusOut",
command: "redirectInlineMenuFocusOut",
direction: RedirectFocusDirection.Next,
portKey,
};
const redirectOverlayFocusOutSpy = jest.spyOn(
overlayBackground as any,
"redirectOverlayFocusOut",
"redirectInlineMenuFocusOut",
);
sendPortMessage(listMessageConnectorPortSpy, message);

View File

@@ -69,11 +69,11 @@ class OverlayBackground implements OverlayBackgroundInterface {
autofillOverlayElementClosed: ({ message }) => this.overlayElementClosed(message),
autofillOverlayAddNewVaultItem: ({ message, sender }) => this.addNewVaultItem(message, sender),
getInlineMenuVisibilitySetting: () => this.getInlineMenuVisibility(),
checkAutofillOverlayMenuFocused: () => this.checkOverlayMenuFocused(),
focusAutofillOverlayMenuList: () => this.focusOverlayMenuList(),
updateAutofillOverlayMenuPosition: ({ message, sender }) =>
this.updateOverlayMenuPosition(message, sender),
updateAutofillOverlayMenuHidden: ({ message, sender }) =>
checkAutofillInlineMenuFocused: () => this.checkInlineMenuFocused(),
focusAutofillInlineMenuList: () => this.focusInlineMenuList(),
updateAutofillInlineMenuPosition: ({ message, sender }) =>
this.updateInlineMenuPosition(message, sender),
updateAutofillInlineMenuHidden: ({ message, sender }) =>
this.updateOverlayMenuHidden(message, sender),
updateFocusedFieldData: ({ message, sender }) => this.setFocusedFieldData(message, sender),
updateIsFieldCurrentlyFocused: ({ message }) => this.updateIsFieldCurrentlyFocused(message),
@@ -95,21 +95,23 @@ class OverlayBackground implements OverlayBackgroundInterface {
overlayButtonClicked: ({ port }) => this.handleOverlayButtonClicked(port),
closeAutofillInlineMenu: ({ port }) => this.closeInlineMenu(port.sender),
forceCloseAutofillOverlay: ({ port }) =>
this.closeInlineMenu(port.sender, { forceCloseOverlay: true }),
this.closeInlineMenu(port.sender, { forceCloseAutofillInlineMenu: true }),
overlayPageBlurred: () => this.checkOverlayListFocused(),
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
redirectInlineMenuFocusOut: ({ message, port }) =>
this.redirectInlineMenuFocusOut(message, port),
updateOverlayPageColorScheme: () => this.updateButtonPageColorScheme(),
};
private readonly overlayListPortMessageHandlers: OverlayListPortMessageHandlers = {
checkAutofillOverlayButtonFocused: () => this.checkOverlayButtonFocused(),
forceCloseAutofillOverlay: ({ port }) =>
this.closeInlineMenu(port.sender, { forceCloseOverlay: true }),
this.closeInlineMenu(port.sender, { forceCloseAutofillInlineMenu: true }),
overlayPageBlurred: () => this.checkOverlayButtonFocused(),
unlockVault: ({ port }) => this.unlockVault(port),
fillSelectedListItem: ({ message, port }) => this.fillSelectedOverlayListItem(message, port),
addNewVaultItem: ({ port }) => this.getNewVaultItemDetails(port),
viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port),
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
redirectInlineMenuFocusOut: ({ message, port }) =>
this.redirectInlineMenuFocusOut(message, port),
updateAutofillOverlayListHeight: ({ message }) => this.updateOverlayListHeight(message),
};
@@ -333,11 +335,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
this.updateOverlayMenuPositionTimeout = setTimeout(() => {
if (this.isFieldCurrentlyFocused) {
void this.updateOverlayMenuPosition(
{ overlayElement: AutofillOverlayElement.List },
sender,
);
void this.updateOverlayMenuPosition(
void this.updateInlineMenuPosition({ overlayElement: AutofillOverlayElement.List }, sender);
void this.updateInlineMenuPosition(
{ overlayElement: AutofillOverlayElement.Button },
sender,
);
@@ -385,7 +384,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
* Checks if the overlay is focused. Will check the overlay list
* if it is open, otherwise it will check the overlay button.
*/
private checkOverlayMenuFocused() {
private checkInlineMenuFocused() {
if (this.overlayListPort) {
this.checkOverlayListFocused();
@@ -413,17 +412,17 @@ class OverlayBackground implements OverlayBackgroundInterface {
* Sends a message to the sender tab to close the autofill overlay.
*
* @param sender - The sender of the port message
* @param forceCloseOverlay - Identifies whether the overlay should be forced closed
* @param forceCloseAutofillInlineMenu - Identifies whether the overlay should be forced closed
* @param overlayElement - The overlay element to close, either the list or button
*/
private closeInlineMenu(
sender: chrome.runtime.MessageSender,
{
forceCloseOverlay,
forceCloseAutofillInlineMenu,
overlayElement,
}: { forceCloseOverlay?: boolean; overlayElement?: string } = {},
}: { forceCloseAutofillInlineMenu?: boolean; overlayElement?: string } = {},
) {
if (forceCloseOverlay) {
if (forceCloseAutofillInlineMenu) {
void BrowserApi.tabSendMessage(
sender.tab,
{ command: "closeInlineMenu", overlayElement },
@@ -480,7 +479,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
* @param overlayElement - The overlay element to update, either the list or button
* @param sender - The sender of the extension message
*/
private async updateOverlayMenuPosition(
private async updateInlineMenuPosition(
{ overlayElement }: { overlayElement?: string },
sender: chrome.runtime.MessageSender,
) {
@@ -592,10 +591,10 @@ class OverlayBackground implements OverlayBackgroundInterface {
* @param sender - The sender of the extension message
*/
private updateOverlayMenuHidden(
{ isOverlayHidden, setTransparentOverlay }: OverlayBackgroundExtensionMessage,
{ isAutofillInlineMenuHidden, setTransparentOverlay }: OverlayBackgroundExtensionMessage,
sender: chrome.runtime.MessageSender,
) {
const display = isOverlayHidden ? "none" : "block";
const display = isAutofillInlineMenuHidden ? "none" : "block";
let styles: { display: string; opacity?: number } = { display };
if (typeof setTransparentOverlay !== "undefined") {
@@ -607,7 +606,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
void BrowserApi.tabSendMessage(
sender.tab,
{ command: "toggleInlineMenuHidden", isInlineMenuHidden: isOverlayHidden },
{ command: "toggleInlineMenuHidden", isInlineMenuHidden: isAutofillInlineMenuHidden },
{ frameId: 0 },
);
@@ -619,9 +618,12 @@ class OverlayBackground implements OverlayBackgroundInterface {
* Sends a message to the currently active tab to open the autofill overlay.
*
* @param isFocusingFieldElement - Identifies whether the field element should be focused when the overlay is opened
* @param isOpeningFullOverlay - Identifies whether the full overlay should be forced open regardless of other states
* @param isOpeningFullAutofillInlineMenu - Identifies whether the full overlay should be forced open regardless of other states
*/
private async openInlineMenu(isFocusingFieldElement = false, isOpeningFullOverlay = false) {
private async openInlineMenu(
isFocusingFieldElement = false,
isOpeningFullAutofillInlineMenu = false,
) {
const currentTab = await BrowserApi.getTabFromCurrentWindowId();
await BrowserApi.tabSendMessage(
@@ -629,7 +631,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
{
command: "openAutofillInlineMenu",
isFocusingFieldElement,
isOpeningFullOverlay,
isOpeningFullAutofillInlineMenu,
authStatus: await this.getAuthStatus(),
},
{
@@ -736,8 +738,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
/**
* Facilitates redirecting focus to the overlay list.
*/
private focusOverlayMenuList() {
this.overlayListPort?.postMessage({ command: "focusOverlayMenuList" });
private focusInlineMenuList() {
this.overlayListPort?.postMessage({ command: "focusInlineMenuList" });
}
/**
@@ -786,7 +788,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
* @param direction - The direction to redirect focus to (either "next", "previous" or "current)
* @param sender - The sender of the port message
*/
private redirectOverlayFocusOut(
private redirectInlineMenuFocusOut(
{ direction }: OverlayPortMessage,
{ sender }: chrome.runtime.Port,
) {
@@ -794,7 +796,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
return;
}
void BrowserApi.tabSendMessageData(sender.tab, "redirectOverlayFocusOut", { direction });
void BrowserApi.tabSendMessageData(sender.tab, "redirectInlineMenuFocusOut", { direction });
}
/**
@@ -983,7 +985,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
? AutofillOverlayPort.ListMessageConnector
: AutofillOverlayPort.ButtonMessageConnector,
});
void this.updateOverlayMenuPosition(
void this.updateInlineMenuPosition(
{
overlayElement: isOverlayListPort
? AutofillOverlayElement.List

View File

@@ -16,11 +16,11 @@ export type AutofillExtensionMessage = {
overlayElement?: string;
isFocusingFieldElement?: boolean;
authStatus?: AuthenticationStatus;
isOpeningFullOverlay?: boolean;
isOpeningFullAutofillInlineMenu?: boolean;
data?: {
isOverlayCiphersPopulated?: boolean;
direction?: "previous" | "next" | "current";
forceCloseOverlay?: boolean;
forceCloseAutofillInlineMenu?: boolean;
inlineMenuVisibility?: number;
};
};

View File

@@ -22,7 +22,7 @@ type OverlayListWindowMessageHandlers = {
initAutofillOverlayList: ({ message }: { message: InitAutofillOverlayListMessage }) => void;
checkAutofillOverlayListFocused: () => void;
updateOverlayListCiphers: ({ message }: { message: UpdateOverlayListCiphersMessage }) => void;
focusOverlayMenuList: () => void;
focusInlineMenuList: () => void;
};
export {

View File

@@ -330,7 +330,7 @@ describe("AutofillOverlayList", () => {
"setAttribute",
);
postWindowMessage({ command: "focusOverlayMenuList" });
postWindowMessage({ command: "focusInlineMenuList" });
expect(overlayContainerSetAttributeSpy).toHaveBeenCalledWith("role", "dialog");
expect(overlayContainerSetAttributeSpy).toHaveBeenCalledWith("aria-modal", "true");
@@ -348,7 +348,7 @@ describe("AutofillOverlayList", () => {
autofillOverlayList["overlayListContainer"].querySelector("#unlock-button");
jest.spyOn(unlockButton as HTMLElement, "focus");
postWindowMessage({ command: "focusOverlayMenuList" });
postWindowMessage({ command: "focusInlineMenuList" });
expect((unlockButton as HTMLElement).focus).toBeCalled();
});
@@ -360,7 +360,7 @@ describe("AutofillOverlayList", () => {
autofillOverlayList["overlayListContainer"].querySelector("#new-item-button");
jest.spyOn(newItemButton as HTMLElement, "focus");
postWindowMessage({ command: "focusOverlayMenuList" });
postWindowMessage({ command: "focusInlineMenuList" });
expect((newItemButton as HTMLElement).focus).toBeCalled();
});
@@ -371,7 +371,7 @@ describe("AutofillOverlayList", () => {
autofillOverlayList["overlayListContainer"].querySelector(".fill-cipher-button");
jest.spyOn(firstCipherItem as HTMLElement, "focus");
postWindowMessage({ command: "focusOverlayMenuList" });
postWindowMessage({ command: "focusInlineMenuList" });
expect((firstCipherItem as HTMLElement).focus).toBeCalled();
});
@@ -407,7 +407,7 @@ describe("AutofillOverlayList", () => {
);
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "redirectOverlayFocusOut", direction: "previous", portKey },
{ command: "redirectInlineMenuFocusOut", direction: "previous", portKey },
"*",
);
});
@@ -416,7 +416,7 @@ describe("AutofillOverlayList", () => {
globalThis.document.dispatchEvent(new KeyboardEvent("keydown", { code: "Tab" }));
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "redirectOverlayFocusOut", direction: "next", portKey },
{ command: "redirectInlineMenuFocusOut", direction: "next", portKey },
"*",
);
});
@@ -425,7 +425,7 @@ describe("AutofillOverlayList", () => {
globalThis.document.dispatchEvent(new KeyboardEvent("keydown", { code: "Escape" }));
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "redirectOverlayFocusOut", direction: "current", portKey },
{ command: "redirectInlineMenuFocusOut", direction: "current", portKey },
"*",
);
});

View File

@@ -26,7 +26,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
checkAutofillOverlayListFocused: () => this.checkOverlayListFocused(),
updateOverlayListCiphers: ({ message }) => this.updateListItems(message.ciphers),
focusOverlayMenuList: () => this.focusOverlayMenuList(),
focusInlineMenuList: () => this.focusInlineMenuList(),
};
constructor() {
@@ -495,7 +495,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
* determined by the presence of the unlock button, new item button, or
* the first cipher button.
*/
private focusOverlayMenuList() {
private focusInlineMenuList() {
this.overlayListContainer.setAttribute("role", "dialog");
this.overlayListContainer.setAttribute("aria-modal", "true");

View File

@@ -150,7 +150,7 @@ class AutofillOverlayPageElement extends HTMLElement {
* @param direction - The direction to redirect the focus out
*/
private redirectOverlayFocusOutMessage(direction: string) {
this.postMessageToParent({ command: "redirectOverlayFocusOut", direction });
this.postMessageToParent({ command: "redirectInlineMenuFocusOut", direction });
}
}

View File

@@ -5,9 +5,9 @@ import { AutofillExtensionMessageParam } from "../../content/abstractions/autofi
import AutofillField from "../../models/autofill-field";
import { ElementWithOpId, FormFieldElement } from "../../types";
export type OpenAutofillOverlayOptions = {
export type OpenAutofillInlineMenuOptions = {
isFocusingFieldElement?: boolean;
isOpeningFullOverlay?: boolean;
isOpeningFullAutofillInlineMenu?: boolean;
authStatus?: AuthenticationStatus;
};
@@ -18,8 +18,8 @@ export type AutofillOverlayContentExtensionMessageHandlers = {
blurMostRecentOverlayField: () => void;
bgUnlockPopoutOpened: () => void;
bgVaultItemRepromptPopoutOpened: () => void;
redirectOverlayFocusOut: ({ message }: AutofillExtensionMessageParam) => void;
updateInlineMenuVisibility: ({ message }: AutofillExtensionMessageParam) => void;
redirectInlineMenuFocusOut: ({ message }: AutofillExtensionMessageParam) => void;
updateAutofillInlineMenuVisibility: ({ message }: AutofillExtensionMessageParam) => void;
getSubFrameOffsets: ({ message }: AutofillExtensionMessageParam) => Promise<SubFrameOffsetData>;
getSubFrameOffsetsFromWindowMessage: ({ message }: AutofillExtensionMessageParam) => void;
};
@@ -28,7 +28,7 @@ export interface AutofillOverlayContentService {
pageDetailsUpdateRequired: boolean;
extensionMessageHandlers: AutofillOverlayContentExtensionMessageHandlers;
init(): void;
setupAutofillOverlayListenerOnField(
setupAutofillInlineMenuListenerOnField(
autofillFieldElement: ElementWithOpId<FormFieldElement>,
autofillFieldData: AutofillField,
): Promise<void>;

View File

@@ -98,7 +98,7 @@ describe("AutofillOverlayContentService", () => {
});
});
describe("setupAutofillOverlayListenerOnField", () => {
describe("setupAutofillInlineMenuListenerOnField", () => {
let autofillFieldElement: ElementWithOpId<FormFieldElement>;
let autofillFieldData: AutofillField;
@@ -131,7 +131,7 @@ describe("AutofillOverlayContentService", () => {
it("ignores fields that are readonly", async () => {
autofillFieldData.readonly = true;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -142,7 +142,7 @@ describe("AutofillOverlayContentService", () => {
it("ignores fields that contain a disabled attribute", async () => {
autofillFieldData.disabled = true;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -153,7 +153,7 @@ describe("AutofillOverlayContentService", () => {
it("ignores fields that are not viewable", async () => {
autofillFieldData.viewable = false;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -165,7 +165,7 @@ describe("AutofillOverlayContentService", () => {
AutoFillConstants.ExcludedOverlayTypes.forEach(async (excludedType) => {
autofillFieldData.type = excludedType;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -177,7 +177,7 @@ describe("AutofillOverlayContentService", () => {
it("ignores fields that contain the keyword `search`", async () => {
autofillFieldData.placeholder = "search";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -188,7 +188,7 @@ describe("AutofillOverlayContentService", () => {
it("ignores fields that contain the keyword `captcha` ", async () => {
autofillFieldData.placeholder = "captcha";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -200,7 +200,7 @@ describe("AutofillOverlayContentService", () => {
it.skip("ignores fields that do not appear as a login field", async () => {
autofillFieldData.placeholder = "not-a-login-field";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -212,7 +212,7 @@ describe("AutofillOverlayContentService", () => {
it("skips setup on fields that have been previously set up", async () => {
autofillOverlayContentService["formFieldElements"].add(autofillFieldElement);
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -225,7 +225,7 @@ describe("AutofillOverlayContentService", () => {
sendExtensionMessageSpy.mockResolvedValueOnce(undefined);
autofillOverlayContentService["inlineMenuVisibility"] = undefined;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -240,7 +240,7 @@ describe("AutofillOverlayContentService", () => {
sendExtensionMessageSpy.mockResolvedValueOnce(AutofillOverlayVisibility.OnFieldFocus);
autofillOverlayContentService["inlineMenuVisibility"] = undefined;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -264,7 +264,7 @@ describe("AutofillOverlayContentService", () => {
"op-1-username-field-focus-handler": focusHandler,
};
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -288,7 +288,7 @@ describe("AutofillOverlayContentService", () => {
describe("form field blur event listener", () => {
beforeEach(async () => {
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -305,13 +305,13 @@ describe("AutofillOverlayContentService", () => {
it("sends a message to the background to check if the overlay is focused", () => {
autofillFieldElement.dispatchEvent(new Event("blur"));
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("checkAutofillOverlayMenuFocused");
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("checkAutofillInlineMenuFocused");
});
});
describe("form field keyup event listener", () => {
beforeEach(async () => {
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -322,7 +322,7 @@ describe("AutofillOverlayContentService", () => {
autofillFieldElement.dispatchEvent(new KeyboardEvent("keyup", { code: "Escape" }));
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
@@ -374,12 +374,14 @@ describe("AutofillOverlayContentService", () => {
await flushPromises();
expect(updateMostRecentlyFocusedFieldSpy).toHaveBeenCalledWith(autofillFieldElement);
expect(openAutofillOverlaySpy).toHaveBeenCalledWith({ isOpeningFullOverlay: true });
expect(sendExtensionMessageSpy).not.toHaveBeenCalledWith("focusAutofillOverlayMenuList");
expect(openAutofillOverlaySpy).toHaveBeenCalledWith({
isOpeningFullAutofillInlineMenu: true,
});
expect(sendExtensionMessageSpy).not.toHaveBeenCalledWith("focusAutofillInlineMenuList");
jest.advanceTimersByTime(150);
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("focusAutofillOverlayMenuList");
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("focusAutofillInlineMenuList");
});
it("focuses the overlay list when the `ArrowDown` key is pressed", async () => {
@@ -390,7 +392,7 @@ describe("AutofillOverlayContentService", () => {
autofillFieldElement.dispatchEvent(new KeyboardEvent("keyup", { code: "ArrowDown" }));
await flushPromises();
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("focusAutofillOverlayMenuList");
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("focusAutofillInlineMenuList");
});
});
@@ -405,7 +407,7 @@ describe("AutofillOverlayContentService", () => {
) as ElementWithOpId<HTMLSpanElement>;
jest.spyOn(autofillOverlayContentService as any, "storeModifiedFormElement");
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
spanAutofillFieldElement,
autofillFieldData,
);
@@ -416,7 +418,7 @@ describe("AutofillOverlayContentService", () => {
});
it("stores the field as a user filled field if the form field data indicates that it is for a username", async () => {
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -432,7 +434,7 @@ describe("AutofillOverlayContentService", () => {
"password-field",
) as ElementWithOpId<FormFieldElement>;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
passwordFieldElement,
autofillFieldData,
);
@@ -447,7 +449,7 @@ describe("AutofillOverlayContentService", () => {
jest.spyOn(autofillOverlayContentService as any, "isUserAuthed").mockReturnValue(false);
(autofillFieldElement as HTMLInputElement).value = "test";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -456,7 +458,7 @@ describe("AutofillOverlayContentService", () => {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
overlayElement: AutofillOverlayElement.List,
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
@@ -468,7 +470,7 @@ describe("AutofillOverlayContentService", () => {
(autofillFieldElement as HTMLInputElement).value = "test";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -477,7 +479,7 @@ describe("AutofillOverlayContentService", () => {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
overlayElement: AutofillOverlayElement.List,
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
@@ -485,7 +487,7 @@ describe("AutofillOverlayContentService", () => {
jest.spyOn(autofillOverlayContentService as any, "openAutofillInlineMenu");
(autofillFieldElement as HTMLInputElement).value = "";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -500,7 +502,7 @@ describe("AutofillOverlayContentService", () => {
jest.spyOn(autofillOverlayContentService as any, "openAutofillInlineMenu");
(autofillFieldElement as HTMLInputElement).value = "";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -518,7 +520,7 @@ describe("AutofillOverlayContentService", () => {
jest.spyOn(autofillOverlayContentService as any, "openAutofillInlineMenu");
(autofillFieldElement as HTMLInputElement).value = "";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -542,7 +544,7 @@ describe("AutofillOverlayContentService", () => {
jest
.spyOn(autofillOverlayContentService as any, "isInlineMenuListVisible")
.mockResolvedValue(false);
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -596,7 +598,7 @@ describe("AutofillOverlayContentService", () => {
autofillOverlayContentService["mostRecentlyFocusedField"] = autofillFieldElement;
autofillOverlayContentService["inlineMenuVisibility"] =
AutofillOverlayVisibility.OnFieldFocus;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -608,7 +610,7 @@ describe("AutofillOverlayContentService", () => {
});
it("updates the most recently focused field", async () => {
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -625,7 +627,7 @@ describe("AutofillOverlayContentService", () => {
it("removes the overlay list if the autofill visibility is set to onClick", async () => {
autofillOverlayContentService["inlineMenuVisibility"] =
AutofillOverlayVisibility.OnButtonClick;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -635,7 +637,7 @@ describe("AutofillOverlayContentService", () => {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
overlayElement: AutofillOverlayElement.List,
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
@@ -644,7 +646,7 @@ describe("AutofillOverlayContentService", () => {
"input",
) as ElementWithOpId<HTMLInputElement>;
(autofillFieldElement as HTMLInputElement).value = "test";
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -654,7 +656,7 @@ describe("AutofillOverlayContentService", () => {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
overlayElement: AutofillOverlayElement.List,
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
@@ -662,7 +664,7 @@ describe("AutofillOverlayContentService", () => {
(autofillFieldElement as HTMLInputElement).value = "";
autofillOverlayContentService["inlineMenuVisibility"] =
AutofillOverlayVisibility.OnFieldFocus;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -678,7 +680,7 @@ describe("AutofillOverlayContentService", () => {
autofillOverlayContentService["inlineMenuVisibility"] =
AutofillOverlayVisibility.OnFieldFocus;
jest.spyOn(autofillOverlayContentService as any, "isUserAuthed").mockReturnValue(true);
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -696,7 +698,7 @@ describe("AutofillOverlayContentService", () => {
jest
.spyOn(autofillOverlayContentService as any, "isInlineMenuCiphersPopulated")
.mockReturnValue(true);
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -704,12 +706,9 @@ describe("AutofillOverlayContentService", () => {
autofillFieldElement.dispatchEvent(new Event("focus"));
await flushPromises();
expect(sendExtensionMessageSpy).toHaveBeenCalledWith(
"updateAutofillOverlayMenuPosition",
{
overlayElement: AutofillOverlayElement.Button,
},
);
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.Button,
});
});
});
});
@@ -721,7 +720,7 @@ describe("AutofillOverlayContentService", () => {
writable: true,
});
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -735,7 +734,7 @@ describe("AutofillOverlayContentService", () => {
it("sets the most recently focused field to the passed form field element if the value is not set", async () => {
autofillOverlayContentService["mostRecentlyFocusedField"] = undefined;
await autofillOverlayContentService.setupAutofillOverlayListenerOnField(
await autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);
@@ -819,10 +818,10 @@ describe("AutofillOverlayContentService", () => {
autofillOverlayContentService["openAutofillInlineMenu"]();
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuPosition", {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.Button,
});
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuPosition", {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.List,
});
});
@@ -831,29 +830,30 @@ describe("AutofillOverlayContentService", () => {
autofillOverlayContentService["inlineMenuVisibility"] =
AutofillOverlayVisibility.OnButtonClick;
autofillOverlayContentService["openAutofillInlineMenu"]({ isOpeningFullOverlay: false });
autofillOverlayContentService["openAutofillInlineMenu"]({
isOpeningFullAutofillInlineMenu: false,
});
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuPosition", {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.Button,
});
expect(sendExtensionMessageSpy).not.toHaveBeenCalledWith(
"updateAutofillOverlayMenuPosition",
{
overlayElement: AutofillOverlayElement.List,
},
);
expect(sendExtensionMessageSpy).not.toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.List,
});
});
it("overrides the onButtonClick visibility setting to open both overlay elements", () => {
autofillOverlayContentService["inlineMenuVisibility"] =
AutofillOverlayVisibility.OnButtonClick;
autofillOverlayContentService["openAutofillInlineMenu"]({ isOpeningFullOverlay: true });
autofillOverlayContentService["openAutofillInlineMenu"]({
isOpeningFullAutofillInlineMenu: true,
});
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuPosition", {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.Button,
});
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuPosition", {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.List,
});
});
@@ -962,7 +962,7 @@ describe("AutofillOverlayContentService", () => {
});
});
describe("redirectOverlayFocusOut", () => {
describe("redirectInlineMenuFocusOut", () => {
let autofillFieldElement: ElementWithOpId<FormFieldElement>;
let autofillFieldFocusSpy: jest.SpyInstance;
let findTabsSpy: jest.SpyInstance;
@@ -1003,7 +1003,7 @@ describe("AutofillOverlayContentService", () => {
it("skips focusing an element if the overlay is not visible", async () => {
isInlineMenuListVisibleSpy.mockResolvedValue(false);
await autofillOverlayContentService.redirectOverlayFocusOut(RedirectFocusDirection.Next);
await autofillOverlayContentService.redirectInlineMenuFocusOut(RedirectFocusDirection.Next);
expect(findTabsSpy).not.toHaveBeenCalled();
});
@@ -1011,13 +1011,15 @@ describe("AutofillOverlayContentService", () => {
it("skips focusing an element if no recently focused field exists", async () => {
autofillOverlayContentService["mostRecentlyFocusedField"] = undefined;
await autofillOverlayContentService.redirectOverlayFocusOut(RedirectFocusDirection.Next);
await autofillOverlayContentService.redirectInlineMenuFocusOut(RedirectFocusDirection.Next);
expect(findTabsSpy).not.toHaveBeenCalled();
});
it("focuses the most recently focused field if the focus direction is `Current`", async () => {
await autofillOverlayContentService.redirectOverlayFocusOut(RedirectFocusDirection.Current);
await autofillOverlayContentService.redirectInlineMenuFocusOut(
RedirectFocusDirection.Current,
);
expect(findTabsSpy).not.toHaveBeenCalled();
expect(autofillFieldFocusSpy).toHaveBeenCalled();
@@ -1025,7 +1027,9 @@ describe("AutofillOverlayContentService", () => {
it("removes the overlay if the focus direction is `Current`", async () => {
jest.useFakeTimers();
await autofillOverlayContentService.redirectOverlayFocusOut(RedirectFocusDirection.Current);
await autofillOverlayContentService.redirectInlineMenuFocusOut(
RedirectFocusDirection.Current,
);
jest.advanceTimersByTime(150);
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu");
@@ -1039,7 +1043,7 @@ describe("AutofillOverlayContentService", () => {
nextFocusableElement,
]);
await autofillOverlayContentService.redirectOverlayFocusOut(RedirectFocusDirection.Next);
await autofillOverlayContentService.redirectInlineMenuFocusOut(RedirectFocusDirection.Next);
expect(findTabsSpy).toHaveBeenCalledWith(globalThis.document.body, { getShadowRoot: true });
});
@@ -1047,7 +1051,9 @@ describe("AutofillOverlayContentService", () => {
it("focuses the previous focusable element if the focus direction is `Previous`", async () => {
jest.spyOn(previousFocusableElement, "focus");
await autofillOverlayContentService.redirectOverlayFocusOut(RedirectFocusDirection.Previous);
await autofillOverlayContentService.redirectInlineMenuFocusOut(
RedirectFocusDirection.Previous,
);
expect(autofillFieldFocusSpy).not.toHaveBeenCalled();
expect(previousFocusableElement.focus).toHaveBeenCalled();
@@ -1056,7 +1062,7 @@ describe("AutofillOverlayContentService", () => {
it("focuses the next focusable element if the focus direction is `Next`", async () => {
jest.spyOn(nextFocusableElement, "focus");
await autofillOverlayContentService.redirectOverlayFocusOut(RedirectFocusDirection.Next);
await autofillOverlayContentService.redirectInlineMenuFocusOut(RedirectFocusDirection.Next);
expect(autofillFieldFocusSpy).not.toHaveBeenCalled();
expect(nextFocusableElement.focus).toHaveBeenCalled();
@@ -1104,8 +1110,8 @@ describe("AutofillOverlayContentService", () => {
globalThis.dispatchEvent(new Event(EVENTS.SCROLL));
await flushPromises();
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuHidden", {
isOverlayHidden: true,
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuHidden", {
isAutofillInlineMenuHidden: true,
setTransparentOverlay: false,
});
});
@@ -1132,12 +1138,12 @@ describe("AutofillOverlayContentService", () => {
await flushPromises();
jest.advanceTimersByTime(800);
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuHidden", {
isOverlayHidden: false,
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuHidden", {
isAutofillInlineMenuHidden: false,
setTransparentOverlay: true,
});
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
@@ -1163,10 +1169,10 @@ describe("AutofillOverlayContentService", () => {
jest.advanceTimersByTime(800);
await flushPromises();
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuPosition", {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.Button,
});
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillOverlayMenuPosition", {
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.List,
});
expect(clearUserInteractionEventTimeoutSpy).toHaveBeenCalled();
@@ -1191,7 +1197,7 @@ describe("AutofillOverlayContentService", () => {
await flushPromises();
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
});
@@ -1201,7 +1207,7 @@ describe("AutofillOverlayContentService", () => {
autofillOverlayContentService["handleVisibilityChangeEvent"]();
expect(sendExtensionMessageSpy).not.toHaveBeenCalledWith("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
@@ -1215,7 +1221,7 @@ describe("AutofillOverlayContentService", () => {
autofillOverlayContentService["handleVisibilityChangeEvent"]();
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
});
});
@@ -1244,7 +1250,7 @@ describe("AutofillOverlayContentService", () => {
});
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
autofillOverlayContentService.setupAutofillOverlayListenerOnField(
autofillOverlayContentService.setupAutofillInlineMenuListenerOnField(
autofillFieldElement,
autofillFieldData,
);

View File

@@ -18,7 +18,7 @@ import { elementIsFillableFormField, getAttributeBoolean, sendExtensionMessage }
import {
AutofillOverlayContentExtensionMessageHandlers,
AutofillOverlayContentService as AutofillOverlayContentServiceInterface,
OpenAutofillOverlayOptions,
OpenAutofillInlineMenuOptions,
} from "./abstractions/autofill-overlay-content.service";
import { AutoFillConstants } from "./autofill-constants";
@@ -46,9 +46,10 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
blurMostRecentOverlayField: () => this.blurMostRecentOverlayField(),
bgUnlockPopoutOpened: () => this.blurMostRecentOverlayField(true),
bgVaultItemRepromptPopoutOpened: () => this.blurMostRecentOverlayField(true),
redirectOverlayFocusOut: ({ message }) =>
this.redirectOverlayFocusOut(message?.data?.direction),
updateInlineMenuVisibility: ({ message }) => this.updateInlineMenuVisibility(message),
redirectInlineMenuFocusOut: ({ message }) =>
this.redirectInlineMenuFocusOut(message?.data?.direction),
updateAutofillInlineMenuVisibility: ({ message }) =>
this.updateAutofillInlineMenuVisibility(message),
getSubFrameOffsets: ({ message }) => this.getSubFrameOffsets(message),
getSubFrameOffsetsFromWindowMessage: ({ message }) =>
this.getSubFrameOffsetsFromWindowMessage(message),
@@ -68,13 +69,13 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
}
/**
* Sets up the autofill overlay listener on the form field element. This method is called
* Sets up the autofill inline menu listener on the form field element. This method is called
* during the page details collection process.
*
* @param formFieldElement - Form field elements identified during the page details collection process.
* @param autofillFieldData - Autofill field data captured from the form field element.
*/
async setupAutofillOverlayListenerOnField(
async setupAutofillInlineMenuListenerOnField(
formFieldElement: ElementWithOpId<FormFieldElement>,
autofillFieldData: AutofillField,
) {
@@ -111,8 +112,8 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
*
* @param options - Options for opening the autofill overlay.
*/
openAutofillInlineMenu(options: OpenAutofillOverlayOptions = {}) {
const { isFocusingFieldElement, isOpeningFullOverlay, authStatus } = options;
openAutofillInlineMenu(options: OpenAutofillInlineMenuOptions = {}) {
const { isFocusingFieldElement, isOpeningFullAutofillInlineMenu, authStatus } = options;
if (!this.mostRecentlyFocusedField) {
return;
}
@@ -134,13 +135,13 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
if (
this.inlineMenuVisibility === AutofillOverlayVisibility.OnButtonClick &&
!isOpeningFullOverlay
!isOpeningFullAutofillInlineMenu
) {
this.updateOverlayButtonPosition();
this.updateAutofillInlineMenuButtonPosition();
return;
}
this.updateOverlayElementsPosition();
this.updateAutofillInlineMenuElementsPosition();
}
/**
@@ -187,7 +188,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
*
* @param direction - The direction to redirect the focus out.
*/
async redirectOverlayFocusOut(direction?: string) {
async redirectInlineMenuFocusOut(direction?: string) {
if (!direction || !this.mostRecentlyFocusedField || !(await this.isInlineMenuListVisible())) {
return;
}
@@ -290,7 +291,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
void this.sendExtensionMessage("updateIsFieldCurrentlyFocused", {
isFieldCurrentlyFocused: false,
});
void this.sendExtensionMessage("checkAutofillOverlayMenuFocused");
void this.sendExtensionMessage("checkAutofillInlineMenuFocused");
};
/**
@@ -305,7 +306,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
const eventCode = event.code;
if (eventCode === "Escape") {
void this.sendExtensionMessage("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
return;
}
@@ -319,7 +320,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
event.preventDefault();
event.stopPropagation();
void this.focusOverlayMenuList();
void this.focusInlineMenuList();
}
};
@@ -328,15 +329,15 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
* the overlay will be opened and the list will be focused after a short delay. Ensures
* that the overlay list is focused when the user presses the down arrow key.
*/
private async focusOverlayMenuList() {
private async focusInlineMenuList() {
if (this.mostRecentlyFocusedField && !(await this.isInlineMenuListVisible())) {
await this.updateMostRecentlyFocusedField(this.mostRecentlyFocusedField);
this.openAutofillInlineMenu({ isOpeningFullOverlay: true });
setTimeout(() => this.sendExtensionMessage("focusAutofillOverlayMenuList"), 125);
this.openAutofillInlineMenu({ isOpeningFullAutofillInlineMenu: true });
setTimeout(() => this.sendExtensionMessage("focusAutofillInlineMenuList"), 125);
return;
}
void this.sendExtensionMessage("focusAutofillOverlayMenuList");
void this.sendExtensionMessage("focusAutofillInlineMenuList");
}
/**
@@ -365,10 +366,10 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
this.storeModifiedFormElement(formFieldElement);
if (await this.hideOverlayListOnFilledField(formFieldElement)) {
if (await this.hideAutofillInlineMenuListOnFilledField(formFieldElement)) {
void this.sendExtensionMessage("closeAutofillInlineMenu", {
overlayElement: AutofillOverlayElement.List,
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
return;
}
@@ -461,12 +462,16 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
) {
await this.sendExtensionMessage("closeAutofillInlineMenu", {
overlayElement: AutofillOverlayElement.List,
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
}
if (await this.hideOverlayListOnFilledField(formFieldElement as FillableFormFieldElement)) {
this.updateOverlayButtonPosition();
if (
await this.hideAutofillInlineMenuListOnFilledField(
formFieldElement as FillableFormFieldElement,
)
) {
this.updateAutofillInlineMenuButtonPosition();
return;
}
@@ -538,16 +543,16 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
/**
* Updates the position of both the overlay button and overlay list.
*/
private updateOverlayElementsPosition() {
this.updateOverlayButtonPosition();
this.updateOverlayListPosition();
private updateAutofillInlineMenuElementsPosition() {
this.updateAutofillInlineMenuButtonPosition();
this.updateAutofillInlineMenuListPosition();
}
/**
* Updates the position of the overlay button.
*/
private updateOverlayButtonPosition() {
void this.sendExtensionMessage("updateAutofillOverlayMenuPosition", {
private updateAutofillInlineMenuButtonPosition() {
void this.sendExtensionMessage("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.Button,
});
}
@@ -555,8 +560,8 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
/**
* Updates the position of the overlay list.
*/
private updateOverlayListPosition() {
void this.sendExtensionMessage("updateAutofillOverlayMenuPosition", {
private updateAutofillInlineMenuListPosition() {
void this.sendExtensionMessage("updateAutofillInlineMenuPosition", {
overlayElement: AutofillOverlayElement.List,
});
}
@@ -567,9 +572,12 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
* @param isHidden - Indicates if the overlay elements should be hidden.
* @param setTransparentOverlay - Indicates if the overlay is closing.
*/
private toggleOverlayHidden(isHidden: boolean, setTransparentOverlay: boolean = false) {
void this.sendExtensionMessage("updateAutofillOverlayMenuHidden", {
isOverlayHidden: isHidden,
private toggleAutofillInlineMenuHidden(
isHidden: boolean,
setTransparentOverlay: boolean = false,
) {
void this.sendExtensionMessage("updateAutofillInlineMenuHidden", {
isAutofillInlineMenuHidden: isHidden,
setTransparentOverlay,
});
}
@@ -711,7 +719,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
autofillFieldData.readonly = getAttributeBoolean(formFieldElement, "disabled");
autofillFieldData.disabled = getAttributeBoolean(formFieldElement, "disabled");
autofillFieldData.viewable = true;
void this.setupAutofillOverlayListenerOnField(formFieldElement, autofillFieldData);
void this.setupAutofillInlineMenuListenerOnField(formFieldElement, autofillFieldData);
}
this.removeHiddenFieldFallbackListener(formFieldElement);
@@ -760,7 +768,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
return;
}
this.toggleOverlayHidden(true);
this.toggleAutofillInlineMenuHidden(true);
this.clearUserInteractionEventTimeout();
this.userInteractionEventTimeout = setTimeout(this.triggerOverlayRepositionUpdates, 750);
};
@@ -779,25 +787,25 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
*/
private triggerOverlayRepositionUpdates = async () => {
if (!this.recentlyFocusedFieldIsCurrentlyFocused()) {
this.toggleOverlayHidden(false, true);
this.toggleAutofillInlineMenuHidden(false, true);
void this.sendExtensionMessage("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
return;
}
await this.updateMostRecentlyFocusedField(this.mostRecentlyFocusedField);
this.updateOverlayElementsPosition();
this.updateAutofillInlineMenuElementsPosition();
setTimeout(async () => {
this.toggleOverlayHidden(false);
this.toggleAutofillInlineMenuHidden(false);
if (
await this.hideOverlayListOnFilledField(
await this.hideAutofillInlineMenuListOnFilledField(
this.mostRecentlyFocusedField as FillableFormFieldElement,
)
) {
void this.sendExtensionMessage("closeAutofillInlineMenu", {
overlayElement: AutofillOverlayElement.List,
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
}
}, 50);
@@ -808,7 +816,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
}
void this.sendExtensionMessage("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
};
@@ -837,7 +845,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
);
}
private async hideOverlayListOnFilledField(
private async hideAutofillInlineMenuListOnFilledField(
formFieldElement?: FillableFormFieldElement,
): Promise<boolean> {
return (
@@ -869,7 +877,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
this.mostRecentlyFocusedField = null;
void this.sendExtensionMessage("closeAutofillInlineMenu", {
forceCloseOverlay: true,
forceCloseAutofillInlineMenu: true,
});
};
@@ -981,7 +989,7 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte
});
};
private updateInlineMenuVisibility({ data }: AutofillExtensionMessage) {
private updateAutofillInlineMenuVisibility({ data }: AutofillExtensionMessage) {
if (isNaN(data?.inlineMenuVisibility)) {
return;
}

View File

@@ -2105,7 +2105,7 @@ export default class AutofillService implements AutofillServiceInterface {
if (!inlineMenuPreviouslyDisabled && !inlineMenuCurrentlyDisabled) {
const tabs = await BrowserApi.tabsQuery({});
tabs.forEach((tab) =>
BrowserApi.tabSendMessageData(tab, "updateInlineMenuVisibility", {
BrowserApi.tabSendMessageData(tab, "updateAutofillInlineMenuVisibility", {
inlineMenuVisibility: currentSetting,
}),
);

View File

@@ -2578,7 +2578,7 @@ describe("CollectAutofillContentService", () => {
);
setupAutofillOverlayListenerOnFieldSpy = jest.spyOn(
collectAutofillContentService["autofillOverlayContentService"],
"setupAutofillOverlayListenerOnField",
"setupAutofillInlineMenuListenerOnField",
);
});

View File

@@ -205,7 +205,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
autofillField.viewable = await this.domElementVisibilityService.isFormFieldViewable(element);
if (!currentViewableState && autofillField.viewable) {
await this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
await this.autofillOverlayContentService?.setupAutofillInlineMenuListenerOnField(
element,
autofillField,
);
@@ -381,7 +381,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
if (elementIsSpanElement(element)) {
this.cacheAutofillFieldElement(index, element, autofillFieldBase);
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
void this.autofillOverlayContentService?.setupAutofillInlineMenuListenerOnField(
element,
autofillFieldBase,
);
@@ -424,7 +424,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
};
this.cacheAutofillFieldElement(index, element, autofillField);
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
void this.autofillOverlayContentService?.setupAutofillInlineMenuListenerOnField(
element,
autofillField,
);
@@ -1321,7 +1321,7 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte
const cachedAutofillFieldElement = this.autofillFieldElements.get(formFieldElement);
cachedAutofillFieldElement.viewable = true;
void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField(
void this.autofillOverlayContentService?.setupAutofillInlineMenuListenerOnField(
formFieldElement,
cachedAutofillFieldElement,
);

View File

@@ -38,7 +38,7 @@ describe("generateRandomCustomElementName", () => {
describe("sendExtensionMessage", () => {
it("sends a message to the extention", () => {
const extensionMessageResponse = sendExtensionMessage("updateAutofillOverlayMenuHidden", {
const extensionMessageResponse = sendExtensionMessage("updateAutofillInlineMenuHidden", {
display: "none",
});
jest.spyOn(chrome.runtime, "sendMessage");