[PM-5189] Reworking project structure to ensure we can better differentiate the inline menu feature from other features
This commit is contained in:
parent
4aebbc0a64
commit
4038939f46
|
@ -236,7 +236,7 @@ describe("OverlayBackground", () => {
|
|||
expect(overlayBackground["getOverlayCipherData"]).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("posts an `updateOverlayListCiphers` message to the overlay list port with the updated ciphers", async () => {
|
||||
it("posts an `updateAutofillInlineMenuListCiphers` message to the overlay list port with the updated ciphers", async () => {
|
||||
overlayBackground["inlineMenuListPort"] = mock<chrome.runtime.Port>();
|
||||
cipherService.getAllDecryptedForUrl.mockResolvedValue([cipher1, cipher2]);
|
||||
cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1);
|
||||
|
@ -246,7 +246,7 @@ describe("OverlayBackground", () => {
|
|||
await overlayBackground.updateOverlayCiphers();
|
||||
|
||||
expect(overlayBackground["inlineMenuListPort"].postMessage).toHaveBeenCalledWith({
|
||||
command: "updateOverlayListCiphers",
|
||||
command: "updateAutofillInlineMenuListCiphers",
|
||||
ciphers: [
|
||||
{
|
||||
card: null,
|
||||
|
|
|
@ -190,7 +190,10 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||
}
|
||||
|
||||
const ciphers = await this.getOverlayCipherData();
|
||||
this.inlineMenuListPort?.postMessage({ command: "updateOverlayListCiphers", ciphers });
|
||||
this.inlineMenuListPort?.postMessage({
|
||||
command: "updateAutofillInlineMenuListCiphers",
|
||||
ciphers,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
const AutofillOverlayElement = {
|
||||
Button: "autofill-inline-menu-button",
|
||||
List: "autofill-overlay-list",
|
||||
List: "autofill-inline-menu-list",
|
||||
} as const;
|
||||
|
||||
const AutofillOverlayPort = {
|
||||
Button: "autofill-inline-menu-button-port",
|
||||
ButtonMessageConnector: "autofill-inline-menu-button-message-connector",
|
||||
List: "autofill-overlay-list-port",
|
||||
ListMessageConnector: "autofill-overlay-list-message-connector",
|
||||
List: "autofill-inline-menu-list-port",
|
||||
ListMessageConnector: "autofill-inline-menu-list-message-connector",
|
||||
} as const;
|
||||
|
||||
const RedirectFocusDirection = {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
|
||||
type AutofillInlineMenuButtonMessage = { command: string; colorScheme?: string };
|
||||
export type AutofillInlineMenuButtonMessage = { command: string; colorScheme?: string };
|
||||
|
||||
type UpdateAuthStatusMessage = AutofillInlineMenuButtonMessage & {
|
||||
export type UpdateAuthStatusMessage = AutofillInlineMenuButtonMessage & {
|
||||
authStatus: AuthenticationStatus;
|
||||
};
|
||||
|
||||
type InitAutofillInlineMenuButtonMessage = UpdateAuthStatusMessage & {
|
||||
export type InitAutofillInlineMenuButtonMessage = UpdateAuthStatusMessage & {
|
||||
styleSheetUrl: string;
|
||||
translations: Record<string, string>;
|
||||
portKey: string;
|
||||
};
|
||||
|
||||
type AutofillInlineMenuButtonWindowMessageHandlers = {
|
||||
export type AutofillInlineMenuButtonWindowMessageHandlers = {
|
||||
[key: string]: CallableFunction;
|
||||
initAutofillInlineMenuButton: ({
|
||||
message,
|
||||
|
@ -31,10 +31,3 @@ type AutofillInlineMenuButtonWindowMessageHandlers = {
|
|||
message: AutofillInlineMenuButtonMessage;
|
||||
}) => void;
|
||||
};
|
||||
|
||||
export {
|
||||
UpdateAuthStatusMessage,
|
||||
AutofillInlineMenuButtonMessage,
|
||||
InitAutofillInlineMenuButtonMessage,
|
||||
AutofillInlineMenuButtonWindowMessageHandlers,
|
||||
};
|
||||
|
|
|
@ -2,12 +2,12 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
|
|||
|
||||
import { OverlayCipherData } from "../../../background/abstractions/overlay.background";
|
||||
|
||||
type AutofillOverlayMenuContainerMessage = {
|
||||
type AutofillInlineMenuMenuContainerMessage = {
|
||||
command: string;
|
||||
portKey: string;
|
||||
};
|
||||
|
||||
export type InitOverlayElementMessage = AutofillOverlayMenuContainerMessage & {
|
||||
export type InitInlineMenuElementMessage = AutofillInlineMenuMenuContainerMessage & {
|
||||
iframeUrl?: string;
|
||||
pageTitle?: string;
|
||||
authStatus?: AuthenticationStatus;
|
||||
|
@ -18,8 +18,8 @@ export type InitOverlayElementMessage = AutofillOverlayMenuContainerMessage & {
|
|||
portName?: string;
|
||||
};
|
||||
|
||||
export type AutofillOverlayMenuContainerWindowMessageHandlers = {
|
||||
export type AutofillInlineMenuMenuContainerWindowMessageHandlers = {
|
||||
[key: string]: CallableFunction;
|
||||
initAutofillInlineMenuList: (message: InitOverlayElementMessage) => void;
|
||||
initAutofillInlineMenuButton: (message: InitOverlayElementMessage) => void;
|
||||
initAutofillInlineMenuList: (message: InitInlineMenuElementMessage) => void;
|
||||
initAutofillInlineMenuButton: (message: InitInlineMenuElementMessage) => void;
|
||||
};
|
||||
|
|
|
@ -1,35 +1,25 @@
|
|||
type AutofillOverlayIframeExtensionMessage = {
|
||||
export type AutofillInlineMenuIframeExtensionMessage = {
|
||||
command: string;
|
||||
styles?: Partial<CSSStyleDeclaration>;
|
||||
theme?: string;
|
||||
portKey?: string;
|
||||
};
|
||||
|
||||
type AutofillOverlayIframeWindowMessageHandlers = {
|
||||
[key: string]: CallableFunction;
|
||||
updateAutofillInlineMenuListHeight: (message: AutofillOverlayIframeExtensionMessage) => void;
|
||||
export type AutofillInlineMenuIframeExtensionMessageParam = {
|
||||
message: AutofillInlineMenuIframeExtensionMessage;
|
||||
};
|
||||
|
||||
type AutofillOverlayIframeExtensionMessageParam = {
|
||||
message: AutofillOverlayIframeExtensionMessage;
|
||||
};
|
||||
|
||||
type BackgroundPortMessageHandlers = {
|
||||
export type BackgroundPortMessageHandlers = {
|
||||
[key: string]: CallableFunction;
|
||||
initAutofillInlineMenuButton: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
||||
initAutofillInlineMenuList: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
||||
updateIframePosition: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
||||
updateInlineMenuHidden: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
||||
initAutofillInlineMenuButton: ({
|
||||
message,
|
||||
}: AutofillInlineMenuIframeExtensionMessageParam) => void;
|
||||
initAutofillInlineMenuList: ({ message }: AutofillInlineMenuIframeExtensionMessageParam) => void;
|
||||
updateIframePosition: ({ message }: AutofillInlineMenuIframeExtensionMessageParam) => void;
|
||||
updateInlineMenuHidden: ({ message }: AutofillInlineMenuIframeExtensionMessageParam) => void;
|
||||
updateAutofillInlineMenuColorScheme: () => void;
|
||||
};
|
||||
|
||||
interface AutofillInlineMenuIframeService {
|
||||
export interface AutofillInlineMenuIframeService {
|
||||
initMenuIframe(): void;
|
||||
}
|
||||
|
||||
export {
|
||||
AutofillOverlayIframeExtensionMessage,
|
||||
AutofillOverlayIframeWindowMessageHandlers,
|
||||
BackgroundPortMessageHandlers,
|
||||
AutofillInlineMenuIframeService,
|
||||
};
|
||||
|
|
|
@ -2,13 +2,13 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
|
|||
|
||||
import { OverlayCipherData } from "../../../background/abstractions/overlay.background";
|
||||
|
||||
type OverlayListMessage = { command: string };
|
||||
type AutofillInlineMenuListMessage = { command: string };
|
||||
|
||||
type UpdateOverlayListCiphersMessage = OverlayListMessage & {
|
||||
export type UpdateAutofillInlineMenuListCiphersMessage = AutofillInlineMenuListMessage & {
|
||||
ciphers: OverlayCipherData[];
|
||||
};
|
||||
|
||||
type InitAutofillOverlayListMessage = OverlayListMessage & {
|
||||
export type InitAutofillInlineMenuListMessage = AutofillInlineMenuListMessage & {
|
||||
authStatus: AuthenticationStatus;
|
||||
styleSheetUrl: string;
|
||||
theme: string;
|
||||
|
@ -17,16 +17,14 @@ type InitAutofillOverlayListMessage = OverlayListMessage & {
|
|||
portKey: string;
|
||||
};
|
||||
|
||||
type OverlayListWindowMessageHandlers = {
|
||||
export type AutofillInlineMenuListWindowMessageHandlers = {
|
||||
[key: string]: CallableFunction;
|
||||
initAutofillInlineMenuList: ({ message }: { message: InitAutofillOverlayListMessage }) => void;
|
||||
initAutofillInlineMenuList: ({ message }: { message: InitAutofillInlineMenuListMessage }) => void;
|
||||
checkAutofillInlineMenuListFocused: () => void;
|
||||
updateOverlayListCiphers: ({ message }: { message: UpdateOverlayListCiphersMessage }) => void;
|
||||
updateAutofillInlineMenuListCiphers: ({
|
||||
message,
|
||||
}: {
|
||||
message: UpdateAutofillInlineMenuListCiphersMessage;
|
||||
}) => void;
|
||||
focusInlineMenuList: () => void;
|
||||
};
|
||||
|
||||
export {
|
||||
UpdateOverlayListCiphersMessage,
|
||||
InitAutofillOverlayListMessage,
|
||||
OverlayListWindowMessageHandlers,
|
||||
};
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
import { AutofillInlineMenuButtonWindowMessageHandlers } from "./autofill-inline-menu-button";
|
||||
import { OverlayListWindowMessageHandlers } from "./autofill-inline-menu-list";
|
||||
import { AutofillInlineMenuListWindowMessageHandlers } from "./autofill-inline-menu-list";
|
||||
|
||||
type AutofillInlineMenuPageElementWindowMessageHandlers =
|
||||
export type AutofillInlineMenuPageElementWindowMessageHandlers =
|
||||
| AutofillInlineMenuButtonWindowMessageHandlers
|
||||
| OverlayListWindowMessageHandlers;
|
||||
| AutofillInlineMenuListWindowMessageHandlers;
|
||||
|
||||
type AutofillInlineMenuPageElementWindowMessage = {
|
||||
export type AutofillInlineMenuPageElementWindowMessage = {
|
||||
[key: string]: any;
|
||||
command: string;
|
||||
overlayCipherId?: string;
|
||||
height?: number;
|
||||
};
|
||||
|
||||
export {
|
||||
AutofillInlineMenuPageElementWindowMessageHandlers,
|
||||
AutofillInlineMenuPageElementWindowMessage,
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
AutofillInlineMenuContentService as AutofillInlineMenuContentServiceInterface,
|
||||
} from "../abstractions/autofill-inline-menu-content.service";
|
||||
import { AutofillInlineMenuButtonIframe } from "../iframe-content/autofill-inline-menu-button-iframe";
|
||||
import AutofillInlineMenuListIframe from "../iframe-content/autofill-inline-menu-list-iframe";
|
||||
import { AutofillInlineMenuListIframe } from "../iframe-content/autofill-inline-menu-list-iframe";
|
||||
|
||||
export class AutofillInlineMenuContentService implements AutofillInlineMenuContentServiceInterface {
|
||||
private readonly sendExtensionMessage = sendExtensionMessage;
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AutofillInlineMenuIframeService initMenuIframe sets up the iframe's attributes 1`] = `
|
||||
<iframe
|
||||
allowtransparency="true"
|
||||
src="chrome-extension://id/overlay/menu.html"
|
||||
style="all: initial !important; position: fixed !important; display: block !important; z-index: 2147483647 !important; line-height: 0 !important; overflow: hidden !important; transition: opacity 125ms ease-out 0s !important; visibility: visible !important; clip-path: none !important; pointer-events: auto !important; margin: 0px !important; padding: 0px !important; color-scheme: normal !important; opacity: 0 !important; height: 0px;"
|
||||
tabindex="-1"
|
||||
title="title"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`AutofillOverlayIframeService initMenuIframe sets up the iframe's attributes 1`] = `
|
||||
<iframe
|
||||
allowtransparency="true"
|
||||
|
|
|
@ -15,7 +15,7 @@ describe("AutofillInlineMenuIframeElement", () => {
|
|||
this,
|
||||
AutofillOverlayPort.Button,
|
||||
{ background: "transparent", border: "none" },
|
||||
"bitwardenOverlayButton",
|
||||
"bitwardenInlineMenuButton",
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -41,7 +41,7 @@ describe("AutofillInlineMenuIframeElement", () => {
|
|||
expect(iframe.shadowRoot).toBeNull();
|
||||
});
|
||||
|
||||
it("instantiates the autofill overlay iframe service for each attached custom element", () => {
|
||||
it("instantiates the autofill inline menu iframe service for each attached custom element", () => {
|
||||
expect(AutofillInlineMenuIframeService).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,13 +9,13 @@ export class AutofillInlineMenuIframeElement {
|
|||
ariaAlert?: string,
|
||||
) {
|
||||
const shadow: ShadowRoot = element.attachShadow({ mode: "closed" });
|
||||
const autofillOverlayIframeService = new AutofillInlineMenuIframeService(
|
||||
const autofillInlineMenuIframeService = new AutofillInlineMenuIframeService(
|
||||
shadow,
|
||||
portName,
|
||||
initStyles,
|
||||
iframeTitle,
|
||||
ariaAlert,
|
||||
);
|
||||
autofillOverlayIframeService.initMenuIframe();
|
||||
autofillInlineMenuIframeService.initMenuIframe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ import {
|
|||
|
||||
import { AutofillInlineMenuIframeService } from "./autofill-inline-menu-iframe.service";
|
||||
|
||||
describe("AutofillOverlayIframeService", () => {
|
||||
let autofillOverlayIframeService: AutofillInlineMenuIframeService;
|
||||
describe("AutofillInlineMenuIframeService", () => {
|
||||
let autofillInlineMenuIframeService: AutofillInlineMenuIframeService;
|
||||
let portSpy: chrome.runtime.Port;
|
||||
let shadowAppendSpy: jest.SpyInstance;
|
||||
let handlePortDisconnectSpy: jest.SpyInstance;
|
||||
|
@ -23,7 +23,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
const shadow = document.createElement("div").attachShadow({ mode: "open" });
|
||||
autofillOverlayIframeService = new AutofillInlineMenuIframeService(
|
||||
autofillInlineMenuIframeService = new AutofillInlineMenuIframeService(
|
||||
shadow,
|
||||
AutofillOverlayPort.Button,
|
||||
{ height: "0px" },
|
||||
|
@ -32,15 +32,15 @@ describe("AutofillOverlayIframeService", () => {
|
|||
);
|
||||
shadowAppendSpy = jest.spyOn(shadow, "appendChild");
|
||||
handlePortDisconnectSpy = jest.spyOn(
|
||||
autofillOverlayIframeService as any,
|
||||
autofillInlineMenuIframeService as any,
|
||||
"handlePortDisconnect",
|
||||
);
|
||||
handlePortMessageSpy = jest.spyOn(autofillOverlayIframeService as any, "handlePortMessage");
|
||||
handlePortMessageSpy = jest.spyOn(autofillInlineMenuIframeService as any, "handlePortMessage");
|
||||
chrome.runtime.connect = jest.fn((connectInfo: chrome.runtime.ConnectInfo) =>
|
||||
createPortSpyMock(connectInfo.name),
|
||||
) as unknown as typeof chrome.runtime.connect;
|
||||
sendExtensionMessageSpy = jest.spyOn(
|
||||
autofillOverlayIframeService as any,
|
||||
autofillInlineMenuIframeService as any,
|
||||
"sendExtensionMessage",
|
||||
);
|
||||
});
|
||||
|
@ -51,44 +51,44 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
describe("initMenuIframe", () => {
|
||||
it("sets up the iframe's attributes", () => {
|
||||
autofillOverlayIframeService.initMenuIframe();
|
||||
autofillInlineMenuIframeService.initMenuIframe();
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"]).toMatchSnapshot();
|
||||
expect(autofillInlineMenuIframeService["iframe"]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("appends the iframe to the shadowDom", () => {
|
||||
jest.spyOn(autofillOverlayIframeService["shadow"], "appendChild");
|
||||
jest.spyOn(autofillInlineMenuIframeService["shadow"], "appendChild");
|
||||
|
||||
autofillOverlayIframeService.initMenuIframe();
|
||||
autofillInlineMenuIframeService.initMenuIframe();
|
||||
|
||||
expect(autofillOverlayIframeService["shadow"].appendChild).toHaveBeenCalledWith(
|
||||
autofillOverlayIframeService["iframe"],
|
||||
expect(autofillInlineMenuIframeService["shadow"].appendChild).toHaveBeenCalledWith(
|
||||
autofillInlineMenuIframeService["iframe"],
|
||||
);
|
||||
});
|
||||
|
||||
// TODO CG - This test is brittle and failing due to how we are calling the private method. This needs to be reworked
|
||||
it.skip("creates an aria alert element if the ariaAlert param is passed", () => {
|
||||
const ariaAlert = "aria alert";
|
||||
jest.spyOn(autofillOverlayIframeService as any, "createAriaAlertElement");
|
||||
jest.spyOn(autofillInlineMenuIframeService as any, "createAriaAlertElement");
|
||||
|
||||
autofillOverlayIframeService.initMenuIframe();
|
||||
autofillInlineMenuIframeService.initMenuIframe();
|
||||
|
||||
expect(autofillOverlayIframeService["createAriaAlertElement"]).toHaveBeenCalledWith(
|
||||
expect(autofillInlineMenuIframeService["createAriaAlertElement"]).toHaveBeenCalledWith(
|
||||
ariaAlert,
|
||||
);
|
||||
expect(autofillOverlayIframeService["ariaAlertElement"]).toMatchSnapshot();
|
||||
expect(autofillInlineMenuIframeService["ariaAlertElement"]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("on load of the iframe source", () => {
|
||||
beforeEach(() => {
|
||||
autofillOverlayIframeService.initMenuIframe();
|
||||
autofillInlineMenuIframeService.initMenuIframe();
|
||||
});
|
||||
|
||||
it("sets up and connects the port message listener to the extension background", () => {
|
||||
jest.spyOn(globalThis, "addEventListener");
|
||||
|
||||
autofillOverlayIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
portSpy = autofillOverlayIframeService["port"];
|
||||
autofillInlineMenuIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
portSpy = autofillInlineMenuIframeService["port"];
|
||||
|
||||
expect(chrome.runtime.connect).toHaveBeenCalledWith({ name: AutofillOverlayPort.Button });
|
||||
expect(portSpy.onDisconnect.addListener).toHaveBeenCalledWith(handlePortDisconnectSpy);
|
||||
|
@ -97,9 +97,9 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
it("skips announcing the aria alert if the aria alert element is not populated", () => {
|
||||
jest.spyOn(globalThis, "setTimeout");
|
||||
autofillOverlayIframeService["ariaAlertElement"] = undefined;
|
||||
autofillInlineMenuIframeService["ariaAlertElement"] = undefined;
|
||||
|
||||
autofillOverlayIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
autofillInlineMenuIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
|
||||
expect(globalThis.setTimeout).not.toHaveBeenCalled();
|
||||
});
|
||||
|
@ -107,16 +107,16 @@ describe("AutofillOverlayIframeService", () => {
|
|||
it("announces the aria alert if the aria alert element is populated", () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(globalThis, "setTimeout");
|
||||
autofillOverlayIframeService["ariaAlertElement"] = document.createElement("div");
|
||||
autofillOverlayIframeService["ariaAlertTimeout"] = setTimeout(jest.fn(), 2000);
|
||||
autofillInlineMenuIframeService["ariaAlertElement"] = document.createElement("div");
|
||||
autofillInlineMenuIframeService["ariaAlertTimeout"] = setTimeout(jest.fn(), 2000);
|
||||
|
||||
autofillOverlayIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
autofillInlineMenuIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
|
||||
expect(globalThis.setTimeout).toHaveBeenCalled();
|
||||
jest.advanceTimersByTime(2000);
|
||||
|
||||
expect(shadowAppendSpy).toHaveBeenCalledWith(
|
||||
autofillOverlayIframeService["ariaAlertElement"],
|
||||
autofillInlineMenuIframeService["ariaAlertElement"],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -124,16 +124,16 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
describe("event listeners", () => {
|
||||
beforeEach(() => {
|
||||
autofillOverlayIframeService.initMenuIframe();
|
||||
autofillOverlayIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
Object.defineProperty(autofillOverlayIframeService["iframe"], "contentWindow", {
|
||||
autofillInlineMenuIframeService.initMenuIframe();
|
||||
autofillInlineMenuIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
Object.defineProperty(autofillInlineMenuIframeService["iframe"], "contentWindow", {
|
||||
value: {
|
||||
postMessage: jest.fn(),
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
jest.spyOn(autofillOverlayIframeService["iframe"].contentWindow, "postMessage");
|
||||
portSpy = autofillOverlayIframeService["port"];
|
||||
jest.spyOn(autofillInlineMenuIframeService["iframe"].contentWindow, "postMessage");
|
||||
portSpy = autofillInlineMenuIframeService["port"];
|
||||
});
|
||||
|
||||
describe("handlePortDisconnect", () => {
|
||||
|
@ -141,15 +141,15 @@ describe("AutofillOverlayIframeService", () => {
|
|||
portSpy.name = "wrong-port-name";
|
||||
triggerPortOnDisconnectEvent(portSpy);
|
||||
|
||||
expect(autofillOverlayIframeService["port"]).not.toBeNull();
|
||||
expect(autofillInlineMenuIframeService["port"]).not.toBeNull();
|
||||
});
|
||||
|
||||
it("resets the iframe element's opacity, height, and display styles", () => {
|
||||
triggerPortOnDisconnectEvent(portSpy);
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].style.opacity).toBe("0");
|
||||
expect(autofillOverlayIframeService["iframe"].style.height).toBe("0px");
|
||||
expect(autofillOverlayIframeService["iframe"].style.display).toBe("block");
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.opacity).toBe("0");
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.height).toBe("0px");
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.display).toBe("block");
|
||||
});
|
||||
|
||||
it("removes the port's onMessage listener", () => {
|
||||
|
@ -168,7 +168,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
triggerPortOnDisconnectEvent(portSpy);
|
||||
|
||||
expect(portSpy.disconnect).toHaveBeenCalled();
|
||||
expect(autofillOverlayIframeService["port"]).toBeNull();
|
||||
expect(autofillInlineMenuIframeService["port"]).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -178,7 +178,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
sendPortMessage(portSpy, {});
|
||||
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -188,22 +188,22 @@ describe("AutofillOverlayIframeService", () => {
|
|||
sendPortMessage(portSpy, message);
|
||||
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).toHaveBeenCalledWith(message, "*");
|
||||
});
|
||||
|
||||
it("handles port messages that are registered with the message handlers and does not pass the message on to the iframe", () => {
|
||||
jest.spyOn(autofillOverlayIframeService as any, "updateIframePosition");
|
||||
jest.spyOn(autofillInlineMenuIframeService as any, "updateIframePosition");
|
||||
|
||||
sendPortMessage(portSpy, { command: "updateIframePosition" });
|
||||
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("initializing the overlay button", () => {
|
||||
it("sets the port key and posts the message to the overlay page iframe", () => {
|
||||
describe("initializing the inline menu button", () => {
|
||||
it("sets the port key and posts the message to the inline menu page iframe", () => {
|
||||
const portKey = "portKey";
|
||||
const message = {
|
||||
command: "initAutofillInlineMenuButton",
|
||||
|
@ -212,19 +212,19 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
sendPortMessage(portSpy, message);
|
||||
|
||||
expect(autofillOverlayIframeService["portKey"]).toBe(portKey);
|
||||
expect(autofillInlineMenuIframeService["portKey"]).toBe(portKey);
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).toHaveBeenCalledWith(message, "*");
|
||||
});
|
||||
});
|
||||
|
||||
describe("initializing the overlay list", () => {
|
||||
describe("initializing the inline menu list", () => {
|
||||
let updateElementStylesSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
updateElementStylesSpy = jest.spyOn(
|
||||
autofillOverlayIframeService as any,
|
||||
autofillInlineMenuIframeService as any,
|
||||
"updateElementStyles",
|
||||
);
|
||||
});
|
||||
|
@ -239,7 +239,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
expect(updateElementStylesSpy).not.toHaveBeenCalled();
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).toHaveBeenCalledWith(message, "*");
|
||||
});
|
||||
|
||||
|
@ -254,7 +254,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
expect(window.matchMedia).toHaveBeenCalledWith("(prefers-color-scheme: dark)");
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).toHaveBeenCalledWith(
|
||||
{
|
||||
command: "initAutofillInlineMenuList",
|
||||
|
@ -275,7 +275,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
expect(window.matchMedia).toHaveBeenCalledWith("(prefers-color-scheme: dark)");
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).toHaveBeenCalledWith(
|
||||
{
|
||||
command: "initAutofillInlineMenuList",
|
||||
|
@ -294,7 +294,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
sendPortMessage(portSpy, message);
|
||||
|
||||
expect(updateElementStylesSpy).toHaveBeenCalledWith(
|
||||
autofillOverlayIframeService["iframe"],
|
||||
autofillInlineMenuIframeService["iframe"],
|
||||
{
|
||||
borderColor: "#4c525f",
|
||||
},
|
||||
|
@ -310,7 +310,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
sendPortMessage(portSpy, message);
|
||||
|
||||
expect(updateElementStylesSpy).toHaveBeenCalledWith(
|
||||
autofillOverlayIframeService["iframe"],
|
||||
autofillInlineMenuIframeService["iframe"],
|
||||
{
|
||||
borderColor: "#2E3440",
|
||||
},
|
||||
|
@ -326,7 +326,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
sendPortMessage(portSpy, message);
|
||||
|
||||
expect(updateElementStylesSpy).toHaveBeenCalledWith(
|
||||
autofillOverlayIframeService["iframe"],
|
||||
autofillInlineMenuIframeService["iframe"],
|
||||
{
|
||||
borderColor: "#073642",
|
||||
},
|
||||
|
@ -340,7 +340,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
});
|
||||
|
||||
it("ignores updating the iframe position if the document does not have focus", () => {
|
||||
jest.spyOn(autofillOverlayIframeService as any, "updateElementStyles");
|
||||
jest.spyOn(autofillInlineMenuIframeService as any, "updateElementStyles");
|
||||
jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(false);
|
||||
|
||||
sendPortMessage(portSpy, {
|
||||
|
@ -348,7 +348,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
styles: { top: 100, left: 100 },
|
||||
});
|
||||
|
||||
expect(autofillOverlayIframeService["updateElementStyles"]).not.toHaveBeenCalled();
|
||||
expect(autofillInlineMenuIframeService["updateElementStyles"]).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("updates the iframe position if the document has focus", () => {
|
||||
|
@ -359,8 +359,8 @@ describe("AutofillOverlayIframeService", () => {
|
|||
styles,
|
||||
});
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].style.top).toBe(styles.top);
|
||||
expect(autofillOverlayIframeService["iframe"].style.left).toBe(styles.left);
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.top).toBe(styles.top);
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.left).toBe(styles.left);
|
||||
});
|
||||
|
||||
it("fades the iframe element in after positioning the element", () => {
|
||||
|
@ -372,9 +372,9 @@ describe("AutofillOverlayIframeService", () => {
|
|||
styles,
|
||||
});
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].style.opacity).toBe("0");
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.opacity).toBe("0");
|
||||
jest.advanceTimersByTime(10);
|
||||
expect(autofillOverlayIframeService["iframe"].style.opacity).toBe("1");
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.opacity).toBe("1");
|
||||
});
|
||||
|
||||
it("announces the opening of the iframe using an aria alert", () => {
|
||||
|
@ -388,7 +388,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
jest.advanceTimersByTime(2000);
|
||||
expect(shadowAppendSpy).toHaveBeenCalledWith(
|
||||
autofillOverlayIframeService["ariaAlertElement"],
|
||||
autofillInlineMenuIframeService["ariaAlertElement"],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -399,7 +399,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
styles: { display: "none" },
|
||||
});
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].style.display).toBe("none");
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.display).toBe("none");
|
||||
});
|
||||
|
||||
it("updates the button based on the web page's color scheme", () => {
|
||||
|
@ -408,7 +408,7 @@ describe("AutofillOverlayIframeService", () => {
|
|||
});
|
||||
|
||||
expect(
|
||||
autofillOverlayIframeService["iframe"].contentWindow.postMessage,
|
||||
autofillInlineMenuIframeService["iframe"].contentWindow.postMessage,
|
||||
).toHaveBeenCalledWith(
|
||||
{
|
||||
command: "updateAutofillInlineMenuColorScheme",
|
||||
|
@ -422,41 +422,41 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
describe("mutation observer", () => {
|
||||
beforeEach(() => {
|
||||
autofillOverlayIframeService.initMenuIframe();
|
||||
autofillOverlayIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
portSpy = autofillOverlayIframeService["port"];
|
||||
autofillInlineMenuIframeService.initMenuIframe();
|
||||
autofillInlineMenuIframeService["iframe"].dispatchEvent(new Event(EVENTS.LOAD));
|
||||
portSpy = autofillInlineMenuIframeService["port"];
|
||||
});
|
||||
|
||||
it("skips handling found mutations if excessive mutations are triggering", async () => {
|
||||
jest.useFakeTimers();
|
||||
jest
|
||||
.spyOn(
|
||||
autofillOverlayIframeService as any,
|
||||
autofillInlineMenuIframeService as any,
|
||||
"isTriggeringExcessiveMutationObserverIterations",
|
||||
)
|
||||
.mockReturnValue(true);
|
||||
jest.spyOn(autofillOverlayIframeService as any, "updateElementStyles");
|
||||
jest.spyOn(autofillInlineMenuIframeService as any, "updateElementStyles");
|
||||
|
||||
autofillOverlayIframeService["iframe"].style.visibility = "hidden";
|
||||
autofillInlineMenuIframeService["iframe"].style.visibility = "hidden";
|
||||
await flushPromises();
|
||||
|
||||
expect(autofillOverlayIframeService["updateElementStyles"]).not.toHaveBeenCalled();
|
||||
expect(autofillInlineMenuIframeService["updateElementStyles"]).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reverts any styles changes made directly to the iframe", async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
autofillOverlayIframeService["iframe"].style.visibility = "hidden";
|
||||
autofillInlineMenuIframeService["iframe"].style.visibility = "hidden";
|
||||
await flushPromises();
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].style.visibility).toBe("visible");
|
||||
expect(autofillInlineMenuIframeService["iframe"].style.visibility).toBe("visible");
|
||||
});
|
||||
|
||||
it("force closes the autofill overlay if more than 9 foreign mutations are triggered", async () => {
|
||||
it("force closes the autofill inline menu if more than 9 foreign mutations are triggered", async () => {
|
||||
jest.useFakeTimers();
|
||||
autofillOverlayIframeService["foreignMutationsCount"] = 10;
|
||||
autofillInlineMenuIframeService["foreignMutationsCount"] = 10;
|
||||
|
||||
autofillOverlayIframeService["iframe"].src = "http://malicious-site.com";
|
||||
autofillInlineMenuIframeService["iframe"].src = "http://malicious-site.com";
|
||||
await flushPromises();
|
||||
|
||||
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
|
||||
|
@ -464,11 +464,11 @@ describe("AutofillOverlayIframeService", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("force closes the autofill overlay if excessive mutations are being triggered", async () => {
|
||||
it("force closes the autofill overinline menulay if excessive mutations are being triggered", async () => {
|
||||
jest.useFakeTimers();
|
||||
autofillOverlayIframeService["mutationObserverIterations"] = 20;
|
||||
autofillInlineMenuIframeService["mutationObserverIterations"] = 20;
|
||||
|
||||
autofillOverlayIframeService["iframe"].src = "http://malicious-site.com";
|
||||
autofillInlineMenuIframeService["iframe"].src = "http://malicious-site.com";
|
||||
await flushPromises();
|
||||
|
||||
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("closeAutofillInlineMenu", {
|
||||
|
@ -478,24 +478,24 @@ describe("AutofillOverlayIframeService", () => {
|
|||
|
||||
it("resets the excessive mutations and foreign mutation counters", async () => {
|
||||
jest.useFakeTimers();
|
||||
autofillOverlayIframeService["foreignMutationsCount"] = 9;
|
||||
autofillOverlayIframeService["mutationObserverIterations"] = 19;
|
||||
autofillInlineMenuIframeService["foreignMutationsCount"] = 9;
|
||||
autofillInlineMenuIframeService["mutationObserverIterations"] = 19;
|
||||
|
||||
autofillOverlayIframeService["iframe"].src = "http://malicious-site.com";
|
||||
autofillInlineMenuIframeService["iframe"].src = "http://malicious-site.com";
|
||||
jest.advanceTimersByTime(2001);
|
||||
await flushPromises();
|
||||
|
||||
expect(autofillOverlayIframeService["foreignMutationsCount"]).toBe(0);
|
||||
expect(autofillOverlayIframeService["mutationObserverIterations"]).toBe(0);
|
||||
expect(autofillInlineMenuIframeService["foreignMutationsCount"]).toBe(0);
|
||||
expect(autofillInlineMenuIframeService["mutationObserverIterations"]).toBe(0);
|
||||
});
|
||||
|
||||
it("resets any mutated default attributes for the iframe", async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
autofillOverlayIframeService["iframe"].title = "some-other-title";
|
||||
autofillInlineMenuIframeService["iframe"].title = "some-other-title";
|
||||
await flushPromises();
|
||||
|
||||
expect(autofillOverlayIframeService["iframe"].title).toBe("title");
|
||||
expect(autofillInlineMenuIframeService["iframe"].title).toBe("title");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,11 +4,11 @@ import { ThemeType } from "@bitwarden/common/platform/enums";
|
|||
import { sendExtensionMessage, setElementStyles } from "../../../utils";
|
||||
import {
|
||||
BackgroundPortMessageHandlers,
|
||||
AutofillInlineMenuIframeService as AutofillOverlayIframeServiceInterface,
|
||||
AutofillOverlayIframeExtensionMessage,
|
||||
AutofillInlineMenuIframeService as AutofillInlineMenuIframeServiceInterface,
|
||||
AutofillInlineMenuIframeExtensionMessage,
|
||||
} from "../abstractions/autofill-inline-menu-iframe.service";
|
||||
|
||||
export class AutofillInlineMenuIframeService implements AutofillOverlayIframeServiceInterface {
|
||||
export class AutofillInlineMenuIframeService implements AutofillInlineMenuIframeServiceInterface {
|
||||
private sendExtensionMessage = sendExtensionMessage;
|
||||
private port: chrome.runtime.Port | null = null;
|
||||
private portKey: string;
|
||||
|
@ -167,7 +167,7 @@ export class AutofillInlineMenuIframeService implements AutofillOverlayIframeSer
|
|||
* @param port
|
||||
*/
|
||||
private handlePortMessage = (
|
||||
message: AutofillOverlayIframeExtensionMessage,
|
||||
message: AutofillInlineMenuIframeExtensionMessage,
|
||||
port: chrome.runtime.Port,
|
||||
) => {
|
||||
if (port.name !== this.portName) {
|
||||
|
@ -183,13 +183,13 @@ export class AutofillInlineMenuIframeService implements AutofillOverlayIframeSer
|
|||
};
|
||||
|
||||
/**
|
||||
* Handles the initialization of the autofill overlay. This includes setting
|
||||
* the port key and sending a message to the iframe to initialize the overlay.
|
||||
* Handles the initialization of the autofill inline menu. This includes setting
|
||||
* the port key and sending a message to the iframe to initialize the inline menu.
|
||||
*
|
||||
* @param message
|
||||
* @private
|
||||
*/
|
||||
private initAutofillInlineMenu(message: AutofillOverlayIframeExtensionMessage) {
|
||||
private initAutofillInlineMenu(message: AutofillInlineMenuIframeExtensionMessage) {
|
||||
this.portKey = message.portKey;
|
||||
if (message.command === "initAutofillInlineMenuList") {
|
||||
this.initAutofillInlineMenuList(message);
|
||||
|
@ -200,12 +200,12 @@ export class AutofillInlineMenuIframeService implements AutofillOverlayIframeSer
|
|||
}
|
||||
|
||||
/**
|
||||
* Handles initialization of the autofill overlay list. This includes setting
|
||||
* the theme and sending a message to the iframe to initialize the overlay.
|
||||
* Handles initialization of the autofill inline menu list. This includes setting
|
||||
* the theme and sending a message to the iframe to initialize the inline menu.
|
||||
*
|
||||
* @param message - The message sent from the iframe
|
||||
*/
|
||||
private initAutofillInlineMenuList(message: AutofillOverlayIframeExtensionMessage) {
|
||||
private initAutofillInlineMenuList(message: AutofillInlineMenuIframeExtensionMessage) {
|
||||
const { theme } = message;
|
||||
let borderColor: string;
|
||||
let verifiedTheme = theme;
|
||||
|
@ -320,7 +320,7 @@ export class AutofillInlineMenuIframeService implements AutofillOverlayIframeSer
|
|||
};
|
||||
|
||||
/**
|
||||
* Triggers a forced closure of the autofill overlay. This is used when the
|
||||
* Triggers a forced closure of the autofill inline menu. This is used when the
|
||||
* mutation observer is triggered excessively.
|
||||
*/
|
||||
private forceCloseAutofillInlineMenu() {
|
||||
|
@ -378,7 +378,7 @@ export class AutofillInlineMenuIframeService implements AutofillOverlayIframeSer
|
|||
|
||||
/**
|
||||
* Identifies if the mutation observer is triggering excessive iterations.
|
||||
* Will remove the autofill overlay if any set mutation observer is
|
||||
* Will remove the autofill inline menu if any set mutation observer is
|
||||
* triggering excessive iterations.
|
||||
*/
|
||||
private isTriggeringExcessiveMutationObserverIterations() {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import AutofillInlineMenuListIframe from "./autofill-inline-menu-list-iframe";
|
||||
import { AutofillInlineMenuListIframe } from "./autofill-inline-menu-list-iframe";
|
||||
|
||||
describe("AutofillOverlayListIframe", () => {
|
||||
describe("AutofillInlineMenuListIframe", () => {
|
||||
window.customElements.define(
|
||||
"autofill-overlay-list-iframe",
|
||||
"autofill-inline-menu-list-iframe",
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -16,9 +16,10 @@ describe("AutofillOverlayListIframe", () => {
|
|||
});
|
||||
|
||||
it("creates a custom element that is an instance of the AutofillIframeElement parent class", () => {
|
||||
document.body.innerHTML = "<autofill-overlay-list-iframe></autofill-overlay-list-iframe>";
|
||||
document.body.innerHTML =
|
||||
"<autofill-inline-menu-list-iframe></autofill-inline-menu-list-iframe>";
|
||||
|
||||
const iframe = document.querySelector("autofill-overlay-list-iframe");
|
||||
const iframe = document.querySelector("autofill-inline-menu-list-iframe");
|
||||
|
||||
expect(iframe).toBeInstanceOf(HTMLElement);
|
||||
expect(iframe.shadowRoot).toBeDefined();
|
||||
|
|
|
@ -2,7 +2,7 @@ import { AutofillOverlayPort } from "../../../enums/autofill-overlay.enum";
|
|||
|
||||
import { AutofillInlineMenuIframeElement } from "./autofill-inline-menu-iframe-element";
|
||||
|
||||
class AutofillInlineMenuListIframe extends AutofillInlineMenuIframeElement {
|
||||
export class AutofillInlineMenuListIframe extends AutofillInlineMenuIframeElement {
|
||||
constructor(element: HTMLElement) {
|
||||
super(
|
||||
element,
|
||||
|
@ -21,5 +21,3 @@ class AutofillInlineMenuListIframe extends AutofillInlineMenuIframeElement {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AutofillInlineMenuListIframe;
|
||||
|
|
|
@ -0,0 +1,536 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AutofillOverlayList initAutofillInlineMenuList the list of ciphers for an authenticated user creates the view for a list of ciphers 1`] = `
|
||||
<div
|
||||
class="overlay-list-container theme_light"
|
||||
>
|
||||
<ul
|
||||
class="overlay-actions-list"
|
||||
role="list"
|
||||
>
|
||||
<li
|
||||
class="overlay-actions-list-item"
|
||||
role="listitem"
|
||||
>
|
||||
<div
|
||||
class="cipher-container"
|
||||
>
|
||||
<button
|
||||
aria-description="partialUsername, username1"
|
||||
aria-label="fillCredentialsFor website login 1"
|
||||
class="fill-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="cipher-icon"
|
||||
style="background-image: url(https://jest-testing-website.com/image.png);"
|
||||
/>
|
||||
<span
|
||||
class="cipher-details"
|
||||
>
|
||||
<span
|
||||
class="cipher-name"
|
||||
title="website login 1"
|
||||
>
|
||||
website login 1
|
||||
</span>
|
||||
<span
|
||||
class="cipher-user-login"
|
||||
title="username1"
|
||||
>
|
||||
username1
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="view website login 1, opensInANewWindow"
|
||||
class="view-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M0 .113h20v19.773H0z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="overlay-actions-list-item"
|
||||
role="listitem"
|
||||
>
|
||||
<div
|
||||
class="cipher-container"
|
||||
>
|
||||
<button
|
||||
aria-description="partialUsername, username2"
|
||||
aria-label="fillCredentialsFor website login 2"
|
||||
class="fill-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="cipher-icon bwi bw-icon"
|
||||
/>
|
||||
<span
|
||||
class="cipher-details"
|
||||
>
|
||||
<span
|
||||
class="cipher-name"
|
||||
title="website login 2"
|
||||
>
|
||||
website login 2
|
||||
</span>
|
||||
<span
|
||||
class="cipher-user-login"
|
||||
title="username2"
|
||||
>
|
||||
username2
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="view website login 2, opensInANewWindow"
|
||||
class="view-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M0 .113h20v19.773H0z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="overlay-actions-list-item"
|
||||
role="listitem"
|
||||
>
|
||||
<div
|
||||
class="cipher-container"
|
||||
>
|
||||
<button
|
||||
aria-description="partialUsername, "
|
||||
aria-label="fillCredentialsFor "
|
||||
class="fill-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="cipher-icon bwi bw-icon"
|
||||
/>
|
||||
<span
|
||||
class="cipher-details"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-label="view , opensInANewWindow"
|
||||
class="view-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M0 .113h20v19.773H0z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="overlay-actions-list-item"
|
||||
role="listitem"
|
||||
>
|
||||
<div
|
||||
class="cipher-container"
|
||||
>
|
||||
<button
|
||||
aria-description="partialUsername, username4"
|
||||
aria-label="fillCredentialsFor website login 4"
|
||||
class="fill-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="cipher-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="25"
|
||||
viewBox="0 0 24 25"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M18.026 17.842c-1.418 1.739-3.517 2.84-5.86 2.84a7.364 7.364 0 0 1-3.431-.848l.062-.15.062-.151.063-.157c.081-.203.17-.426.275-.646.133-.28.275-.522.426-.68.026-.028.101-.075.275-.115.165-.037.376-.059.629-.073.138-.008.288-.014.447-.02.399-.016.847-.034 1.266-.092.314-.044.566-.131.755-.271a.884.884 0 0 0 .352-.555c.037-.2.008-.392-.03-.543-.035-.135-.084-.264-.12-.355l-.01-.03a4.26 4.26 0 0 0-.145-.33c-.126-.264-.237-.497-.288-1.085-.03-.344.09-.73.251-1.138l.089-.22c.05-.123.1-.247.14-.355.064-.171.129-.375.129-.566a1.51 1.51 0 0 0-.134-.569 2.573 2.573 0 0 0-.319-.547c-.246-.323-.635-.669-1.093-.669-.44 0-1.006.169-1.487.368-.246.102-.48.216-.68.33-.192.111-.372.235-.492.359-.93.96-1.48 1.239-1.81 1.258-.277.017-.478-.15-.736-.525a9.738 9.738 0 0 1-.19-.29l-.006-.01a11.568 11.568 0 0 0-.198-.305 2.76 2.76 0 0 0-.521-.6 1.39 1.39 0 0 0-1.088-.314 8.302 8.302 0 0 1 1.987-3.936c.055.342.146.626.272.856.23.42.561.64.926.716.406.086.857-.061 1.26-.216.125-.047.248-.097.372-.147.309-.125.618-.25.947-.341.26-.072.581-.057.959.012.264.049.529.118.8.19l.36.091c.379.094.782.178 1.135.148.374-.032.733-.197.934-.623a.874.874 0 0 0 .024-.752c-.087-.197-.24-.355-.35-.47-.26-.267-.412-.427-.412-.685 0-.125.037-.2.09-.263a.982.982 0 0 1 .303-.211c.059-.03.119-.058.183-.089l.036-.016a3.79 3.79 0 0 0 .236-.118c.047-.026.098-.056.148-.093 1.936.747 3.51 2.287 4.368 4.249a7.739 7.739 0 0 0-.031-.004c-.38-.047-.738-.056-1.063.061-.34.123-.603.368-.817.74-.122.211-.284.43-.463.67l-.095.129c-.207.281-.431.595-.58.92-.15.326-.245.705-.142 1.103.104.397.387.738.837 1.036.099.065.225.112.314.145l.02.008c.108.04.195.074.268.117.07.042.106.08.124.114.017.03.037.087.022.206-.047.376-.069.73-.052 1.034.017.292.071.59.218.809.118.174.12.421.108.786v.01a2.46 2.46 0 0 0 .021.518.809.809 0 0 0 .15.35Zm1.357.059a9.654 9.654 0 0 0 1.62-5.386c0-5.155-3.957-9.334-8.836-9.334-4.88 0-8.836 4.179-8.836 9.334 0 3.495 1.82 6.543 4.513 8.142v.093h.161a8.426 8.426 0 0 0 4.162 1.098c2.953 0 5.568-1.53 7.172-3.882a.569.569 0 0 0 .048-.062l-.004-.003ZM8.152 19.495a43.345 43.345 0 0 1 .098-.238l.057-.142c.082-.205.182-.455.297-.698.143-.301.323-.624.552-.864.163-.172.392-.254.602-.302.219-.05.473-.073.732-.088.162-.01.328-.016.495-.023.386-.015.782-.03 1.168-.084.255-.036.392-.099.461-.15.06-.045.076-.084.083-.12a.534.534 0 0 0-.02-.223 2.552 2.552 0 0 0-.095-.278l-.01-.027a3.128 3.128 0 0 0-.104-.232c-.134-.282-.31-.65-.374-1.381-.046-.533.138-1.063.3-1.472.035-.09.069-.172.1-.249.046-.11.086-.21.123-.31.062-.169.083-.264.083-.312a.812.812 0 0 0-.076-.283 1.867 1.867 0 0 0-.23-.394c-.21-.274-.428-.408-.577-.408-.315 0-.788.13-1.246.32a5.292 5.292 0 0 0-.603.293 1.727 1.727 0 0 0-.347.244c-.936.968-1.641 1.421-2.235 1.457-.646.04-1.036-.413-1.31-.813-.07-.103-.139-.21-.203-.311l-.005-.007c-.064-.101-.125-.197-.188-.29a2.098 2.098 0 0 0-.387-.453.748.748 0 0 0-.436-.18c-.1-.006-.22.005-.365.046a8.707 8.707 0 0 0-.056.992c0 2.957 1.488 5.547 3.716 6.98Zm10.362-2.316.003-.192.002-.046c.01-.305.026-.786-.232-1.169-.036-.054-.082-.189-.096-.444-.014-.243.003-.55.047-.9a1.051 1.051 0 0 0-.105-.649.987.987 0 0 0-.374-.374 2.285 2.285 0 0 0-.367-.166h-.003a1.243 1.243 0 0 1-.205-.088c-.369-.244-.505-.46-.549-.629-.044-.168-.015-.364.099-.61.115-.25.297-.511.507-.796l.089-.12c.178-.239.368-.495.512-.745.152-.263.302-.382.466-.441.18-.065.416-.073.77-.03.142.018.275.04.397.063.274.837.423 1.736.423 2.671a8.45 8.45 0 0 1-1.384 4.665Zm-4.632-12.63a7.362 7.362 0 0 0-1.715-.201c-1.89 0-3.621.716-4.965 1.905.025.54.12.887.24 1.105.13.238.295.34.482.38.2.042.484-.027.905-.188l.328-.13c.32-.13.681-.275 1.048-.377.398-.111.833-.075 1.24 0 .289.053.59.132.871.205l.326.084c.383.094.694.151.932.13.216-.017.326-.092.395-.237.039-.083.027-.114.014-.144-.027-.062-.088-.136-.212-.264l-.043-.044c-.218-.222-.567-.578-.567-1.142 0-.305.101-.547.262-.734.137-.159.308-.267.46-.347Z"
|
||||
fill="#777"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="cipher-details"
|
||||
>
|
||||
<span
|
||||
class="cipher-name"
|
||||
title="website login 4"
|
||||
>
|
||||
website login 4
|
||||
</span>
|
||||
<span
|
||||
class="cipher-user-login"
|
||||
title="username4"
|
||||
>
|
||||
username4
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="view website login 4, opensInANewWindow"
|
||||
class="view-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M0 .113h20v19.773H0z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="overlay-actions-list-item"
|
||||
role="listitem"
|
||||
>
|
||||
<div
|
||||
class="cipher-container"
|
||||
>
|
||||
<button
|
||||
aria-description="partialUsername, username5"
|
||||
aria-label="fillCredentialsFor website login 5"
|
||||
class="fill-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="cipher-icon"
|
||||
style="background-image: url(https://jest-testing-website.com/image.png);"
|
||||
/>
|
||||
<span
|
||||
class="cipher-details"
|
||||
>
|
||||
<span
|
||||
class="cipher-name"
|
||||
title="website login 5"
|
||||
>
|
||||
website login 5
|
||||
</span>
|
||||
<span
|
||||
class="cipher-user-login"
|
||||
title="username5"
|
||||
>
|
||||
username5
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="view website login 5, opensInANewWindow"
|
||||
class="view-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M0 .113h20v19.773H0z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="overlay-actions-list-item"
|
||||
role="listitem"
|
||||
>
|
||||
<div
|
||||
class="cipher-container"
|
||||
>
|
||||
<button
|
||||
aria-description="partialUsername, username6"
|
||||
aria-label="fillCredentialsFor website login 6"
|
||||
class="fill-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="cipher-icon"
|
||||
style="background-image: url(https://jest-testing-website.com/image.png);"
|
||||
/>
|
||||
<span
|
||||
class="cipher-details"
|
||||
>
|
||||
<span
|
||||
class="cipher-name"
|
||||
title="website login 6"
|
||||
>
|
||||
website login 6
|
||||
</span>
|
||||
<span
|
||||
class="cipher-user-login"
|
||||
title="username6"
|
||||
>
|
||||
username6
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="view website login 6, opensInANewWindow"
|
||||
class="view-cipher-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M16.587 7.932H5.9a.455.455 0 0 1-.31-.12.393.393 0 0 1-.127-.287c0-.108.046-.211.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.076.128.179.128.287a.393.393 0 0 1-.128.288.455.455 0 0 1-.31.119Zm0 2.474H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm0 2.468H5.9a.455.455 0 0 1-.31-.119.393.393 0 0 1-.127-.287c0-.108.046-.212.128-.288a.455.455 0 0 1 .309-.119h10.687c.117 0 .228.043.31.12.082.075.128.179.128.287a.393.393 0 0 1-.128.287.455.455 0 0 1-.31.12Zm2.163-8.103v10.457H1.25V4.771h17.5Zm0-1.162H1.25a1.3 1.3 0 0 0-.884.34A1.122 1.122 0 0 0 0 4.772v10.457c0 .308.132.604.366.822a1.3 1.3 0 0 0 .884.34h17.5a1.3 1.3 0 0 0 .884-.34c.234-.218.366-.514.366-.822V4.771c0-.308-.132-.603-.366-.821a1.3 1.3 0 0 0-.884-.34ZM3.213 8.01c.287 0 .52-.217.52-.484s-.234-.483-.52-.483c-.288 0-.52.216-.52.483s.233.483.52.483Zm0 4.903c.287 0 .52-.217.52-.484 0-.266-.234-.483-.52-.483-.287 0-.52.216-.52.483s.233.484.52.484Zm0-2.452c.287 0 .52-.216.52-.483 0-.268-.234-.484-.52-.484-.288 0-.52.216-.52.484 0 .267.233.483.52.483Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M0 .113h20v19.773H0z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AutofillOverlayList initAutofillInlineMenuList the locked overlay for an unauthenticated user creates the views for the locked overlay 1`] = `
|
||||
<div
|
||||
class="overlay-list-container theme_light"
|
||||
>
|
||||
<div
|
||||
class="locked-overlay overlay-list-message"
|
||||
id="locked-overlay-description"
|
||||
>
|
||||
unlockYourAccount
|
||||
</div>
|
||||
<div
|
||||
class="overlay-list-button-container"
|
||||
>
|
||||
<button
|
||||
aria-label="unlockAccount, opensInANewWindow"
|
||||
class="unlock-button overlay-list-button"
|
||||
id="unlock-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="17"
|
||||
viewBox="0 0 17 17"
|
||||
width="17"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M8.799 11.633a.68.68 0 0 0-.639.422.695.695 0 0 0-.054.264.682.682 0 0 0 .374.6v1.13a.345.345 0 1 0 .693 0v-1.17a.68.68 0 0 0 .315-.56.695.695 0 0 0-.204-.486.682.682 0 0 0-.485-.2Zm4.554-4.657h-7.11a.438.438 0 0 1-.406-.26A3.81 3.81 0 0 1 5.584 4.3c.112-.435.312-.842.588-1.195A3.196 3.196 0 0 1 7.19 2.25a3.468 3.468 0 0 1 3.225-.059A3.62 3.62 0 0 1 11.94 3.71l.327.59a.502.502 0 1 0 .885-.483l-.307-.552a4.689 4.689 0 0 0-2.209-2.078 4.466 4.466 0 0 0-3.936.185A4.197 4.197 0 0 0 5.37 2.49a4.234 4.234 0 0 0-.768 1.565 4.714 4.714 0 0 0 .162 2.682.182.182 0 0 1-.085.22.173.173 0 0 1-.082.02h-.353a1.368 1.368 0 0 0-1.277.842c-.07.168-.107.348-.109.53v7.1a1.392 1.392 0 0 0 .412.974 1.352 1.352 0 0 0 .974.394h9.117c.363.001.711-.142.97-.4a1.39 1.39 0 0 0 .407-.972v-7.1a1.397 1.397 0 0 0-.414-.973 1.368 1.368 0 0 0-.972-.396Zm.37 8.469a.373.373 0 0 1-.11.26.364.364 0 0 1-.26.107H4.246a.366.366 0 0 1-.26-.107.374.374 0 0 1-.11-.261V8.349a.374.374 0 0 1 .11-.26.366.366 0 0 1 .26-.108h9.116a.366.366 0 0 1 .37.367l-.008 7.097Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M.798.817h16v16h-16z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
unlockAccount
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AutofillOverlayList initAutofillInlineMenuList the overlay with an empty list of ciphers creates the views for the no results overlay 1`] = `
|
||||
<div
|
||||
class="overlay-list-container theme_light"
|
||||
>
|
||||
<div
|
||||
class="no-items overlay-list-message"
|
||||
>
|
||||
noItemsToShow
|
||||
</div>
|
||||
<div
|
||||
class="overlay-list-button-container"
|
||||
>
|
||||
<button
|
||||
aria-label="addNewVaultItem, opensInANewWindow"
|
||||
class="add-new-item-button overlay-list-button"
|
||||
id="new-item-button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
height="17"
|
||||
viewBox="0 0 16 17"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#a)"
|
||||
>
|
||||
<path
|
||||
d="M15.222 7.914H8.963a.471.471 0 0 1-.34-.147.512.512 0 0 1-.142-.353V.99c0-.133-.05-.26-.14-.354a.471.471 0 0 0-.68 0 .51.51 0 0 0-.142.354v6.424c0 .132-.051.26-.142.353a.474.474 0 0 1-.34.147H.777a.47.47 0 0 0-.34.146.5.5 0 0 0-.14.354.522.522 0 0 0 .14.353.48.48 0 0 0 .34.147h6.26c.128 0 .25.052.34.146.09.094.142.221.142.354v6.576c0 .132.05.26.14.353a.471.471 0 0 0 .68 0 .512.512 0 0 0 .142-.353V9.414c0-.133.051-.26.142-.354a.474.474 0 0 1 .34-.146h6.26c.127 0 .25-.053.34-.147a.511.511 0 0 0 0-.707.472.472 0 0 0-.34-.146Z"
|
||||
fill="#175DDC"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="a"
|
||||
>
|
||||
<path
|
||||
d="M0 .49h16v16H0z"
|
||||
fill="#fff"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
newItem
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -5,22 +5,22 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
|
|||
import { createInitAutofillOverlayListMessageMock } from "../../../../spec/autofill-mocks";
|
||||
import { flushPromises, postWindowMessage } from "../../../../spec/testing-utils";
|
||||
|
||||
import AutofillOverlayList from "./autofill-overlay-list";
|
||||
import { AutofillInlineMenuList } from "./autofill-inline-menu-list";
|
||||
|
||||
describe("AutofillOverlayList", () => {
|
||||
globalThis.customElements.define("autofill-overlay-list", AutofillOverlayList);
|
||||
globalThis.customElements.define("autofill-inline-menu-list", AutofillInlineMenuList);
|
||||
global.ResizeObserver = jest.fn().mockImplementation(() => ({
|
||||
observe: jest.fn(),
|
||||
unobserve: jest.fn(),
|
||||
disconnect: jest.fn(),
|
||||
}));
|
||||
|
||||
let autofillOverlayList: AutofillOverlayList;
|
||||
let autofillOverlayList: AutofillInlineMenuList;
|
||||
const portKey: string = "overlayListPortKey";
|
||||
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = `<autofill-overlay-list></autofill-overlay-list>`;
|
||||
autofillOverlayList = document.querySelector("autofill-overlay-list");
|
||||
document.body.innerHTML = `<autofill-inline-menu-list></autofill-inline-menu-list>`;
|
||||
autofillOverlayList = document.querySelector("autofill-inline-menu-list");
|
||||
jest.spyOn(globalThis.document, "createElement");
|
||||
jest.spyOn(globalThis.parent, "postMessage");
|
||||
});
|
||||
|
@ -312,7 +312,7 @@ describe("AutofillOverlayList", () => {
|
|||
postWindowMessage(createInitAutofillOverlayListMessageMock());
|
||||
const updateCiphersSpy = jest.spyOn(autofillOverlayList as any, "updateListItems");
|
||||
|
||||
postWindowMessage({ command: "updateOverlayListCiphers" });
|
||||
postWindowMessage({ command: "updateAutofillInlineMenuListCiphers" });
|
||||
|
||||
expect(updateCiphersSpy).toHaveBeenCalled();
|
||||
});
|
|
@ -7,12 +7,12 @@ import { OverlayCipherData } from "../../../../background/abstractions/overlay.b
|
|||
import { buildSvgDomElement } from "../../../../utils";
|
||||
import { globeIcon, lockIcon, plusIcon, viewCipherIcon } from "../../../../utils/svg-icons";
|
||||
import {
|
||||
InitAutofillOverlayListMessage,
|
||||
OverlayListWindowMessageHandlers,
|
||||
InitAutofillInlineMenuListMessage,
|
||||
AutofillInlineMenuListWindowMessageHandlers,
|
||||
} from "../../abstractions/autofill-inline-menu-list";
|
||||
import { AutofillInlineMenuPageElement } from "../shared/autofill-inline-menu-page-element";
|
||||
|
||||
class AutofillOverlayList extends AutofillInlineMenuPageElement {
|
||||
export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
|
||||
private overlayListContainer: HTMLDivElement;
|
||||
private resizeObserver: ResizeObserver;
|
||||
private eventHandlersMemo: { [key: string]: EventListener } = {};
|
||||
|
@ -22,10 +22,10 @@ class AutofillOverlayList extends AutofillInlineMenuPageElement {
|
|||
private cipherListScrollDebounceTimeout: number | NodeJS.Timeout;
|
||||
private currentCipherIndex = 0;
|
||||
private readonly showCiphersPerPage = 6;
|
||||
private readonly overlayListWindowMessageHandlers: OverlayListWindowMessageHandlers = {
|
||||
private readonly overlayListWindowMessageHandlers: AutofillInlineMenuListWindowMessageHandlers = {
|
||||
initAutofillInlineMenuList: ({ message }) => this.initAutofillInlineMenuList(message),
|
||||
checkAutofillInlineMenuListFocused: () => this.checkInlineMenuListFocused(),
|
||||
updateOverlayListCiphers: ({ message }) => this.updateListItems(message.ciphers),
|
||||
updateAutofillInlineMenuListCiphers: ({ message }) => this.updateListItems(message.ciphers),
|
||||
focusInlineMenuList: () => this.focusInlineMenuList(),
|
||||
};
|
||||
|
||||
|
@ -53,7 +53,7 @@ class AutofillOverlayList extends AutofillInlineMenuPageElement {
|
|||
authStatus,
|
||||
ciphers,
|
||||
portKey,
|
||||
}: InitAutofillOverlayListMessage) {
|
||||
}: InitAutofillInlineMenuListMessage) {
|
||||
const linkElement = await this.initAutofillInlineMenuPage(
|
||||
"list",
|
||||
styleSheetUrl,
|
||||
|
@ -619,5 +619,3 @@ class AutofillOverlayList extends AutofillInlineMenuPageElement {
|
|||
nextSibling?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
export default AutofillOverlayList;
|
|
@ -1,9 +1,9 @@
|
|||
import { AutofillOverlayElement } from "../../../../enums/autofill-overlay.enum";
|
||||
|
||||
import AutofillOverlayList from "./autofill-overlay-list";
|
||||
import { AutofillInlineMenuList } from "./autofill-inline-menu-list";
|
||||
|
||||
require("./list.scss");
|
||||
|
||||
(function () {
|
||||
globalThis.customElements.define(AutofillOverlayElement.List, AutofillOverlayList);
|
||||
globalThis.customElements.define(AutofillOverlayElement.List, AutofillInlineMenuList);
|
||||
})();
|
|
@ -7,6 +7,6 @@
|
|||
<meta name="color-scheme" content="normal" />
|
||||
</head>
|
||||
<body>
|
||||
<autofill-overlay-list></autofill-overlay-list>
|
||||
<autofill-inline-menu-list></autofill-inline-menu-list>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,11 +2,11 @@ import { EVENTS } from "@bitwarden/common/autofill/constants";
|
|||
|
||||
import { setElementStyles } from "../../../../utils";
|
||||
import {
|
||||
InitOverlayElementMessage,
|
||||
AutofillOverlayMenuContainerWindowMessageHandlers,
|
||||
InitInlineMenuElementMessage,
|
||||
AutofillInlineMenuMenuContainerWindowMessageHandlers,
|
||||
} from "../../abstractions/autofill-inline-menu-container";
|
||||
|
||||
export class AutofillOverlayMenuContainer {
|
||||
export class AutofillInlineMenuContainer {
|
||||
private extensionOriginsSet: Set<string>;
|
||||
private port: chrome.runtime.Port | null = null;
|
||||
private portName: string;
|
||||
|
@ -36,9 +36,9 @@ export class AutofillOverlayMenuContainer {
|
|||
allowtransparency: "true",
|
||||
tabIndex: "-1",
|
||||
};
|
||||
private windowMessageHandlers: AutofillOverlayMenuContainerWindowMessageHandlers = {
|
||||
initAutofillInlineMenuList: (message) => this.handleInitOverlayIframe(message),
|
||||
initAutofillInlineMenuButton: (message) => this.handleInitOverlayIframe(message),
|
||||
private windowMessageHandlers: AutofillInlineMenuMenuContainerWindowMessageHandlers = {
|
||||
initAutofillInlineMenuList: (message) => this.handleInitInlineMenuIframe(message),
|
||||
initAutofillInlineMenuButton: (message) => this.handleInitInlineMenuIframe(message),
|
||||
};
|
||||
|
||||
constructor() {
|
||||
|
@ -50,7 +50,7 @@ export class AutofillOverlayMenuContainer {
|
|||
globalThis.addEventListener("message", this.handleWindowMessage);
|
||||
}
|
||||
|
||||
private handleInitOverlayIframe(message: InitOverlayElementMessage) {
|
||||
private handleInitInlineMenuIframe(message: InitInlineMenuElementMessage) {
|
||||
this.defaultIframeAttributes.src = message.iframeUrl;
|
||||
this.defaultIframeAttributes.title = message.pageTitle;
|
||||
this.portName = message.portName;
|
||||
|
@ -67,7 +67,7 @@ export class AutofillOverlayMenuContainer {
|
|||
globalThis.document.body.appendChild(this.overlayPageIframe);
|
||||
}
|
||||
|
||||
private setupPortMessageListener = (message: InitOverlayElementMessage) => {
|
||||
private setupPortMessageListener = (message: InitInlineMenuElementMessage) => {
|
||||
this.port = chrome.runtime.connect({ name: this.portName });
|
||||
this.port.onMessage.addListener(this.handlePortMessage);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { AutofillInlineMenuContainer } from "./autofill-inline-menu-container";
|
||||
|
||||
(() => new AutofillInlineMenuContainer())();
|
|
@ -1,3 +0,0 @@
|
|||
import { AutofillOverlayMenuContainer } from "./autofill-overlay-menu-container";
|
||||
|
||||
(() => new AutofillOverlayMenuContainer())();
|
|
@ -13,7 +13,7 @@ import AutofillForm from "../models/autofill-form";
|
|||
import AutofillPageDetails from "../models/autofill-page-details";
|
||||
import AutofillScript, { FillScript } from "../models/autofill-script";
|
||||
import { InitAutofillInlineMenuButtonMessage } from "../overlay/inline-menu/abstractions/autofill-inline-menu-button";
|
||||
import { InitAutofillOverlayListMessage } from "../overlay/inline-menu/abstractions/autofill-inline-menu-list";
|
||||
import { InitAutofillInlineMenuListMessage } from "../overlay/inline-menu/abstractions/autofill-inline-menu-list";
|
||||
import { GenerateFillScriptOptions, PageDetail } from "../services/abstractions/autofill.service";
|
||||
|
||||
function createAutofillFormMock(customFields = {}): AutofillForm {
|
||||
|
@ -197,7 +197,7 @@ function createAutofillOverlayCipherDataMock(index: number, customFields = {}):
|
|||
|
||||
function createInitAutofillOverlayListMessageMock(
|
||||
customFields = {},
|
||||
): InitAutofillOverlayListMessage {
|
||||
): InitAutofillInlineMenuListMessage {
|
||||
return {
|
||||
command: "initAutofillInlineMenuList",
|
||||
translations: overlayPagesTranslations,
|
||||
|
|
|
@ -177,9 +177,9 @@ const mainConfig = {
|
|||
"overlay/button":
|
||||
"./src/autofill/overlay/inline-menu/pages/button/bootstrap-autofill-inline-menu-button.ts",
|
||||
"overlay/list":
|
||||
"./src/autofill/overlay/inline-menu/pages/list/bootstrap-autofill-overlay-list.ts",
|
||||
"./src/autofill/overlay/inline-menu/pages/list/bootstrap-autofill-inline-menu-list.ts",
|
||||
"overlay/menu":
|
||||
"./src/autofill/overlay/inline-menu/pages/menu/bootstrap-autofill-overlay-menu-container.ts",
|
||||
"./src/autofill/overlay/inline-menu/pages/menu/bootstrap-autofill-inline-menu-container.ts",
|
||||
"encrypt-worker": "../../libs/common/src/platform/services/cryptography/encrypt.worker.ts",
|
||||
"content/lp-fileless-importer": "./src/tools/content/lp-fileless-importer.ts",
|
||||
"content/send-on-installed-message": "./src/vault/content/send-on-installed-message.ts",
|
||||
|
|
Loading…
Reference in New Issue