mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-24 21:41:33 +01:00
[PM-5189] Implementing jest tests for the OverlayBackground
This commit is contained in:
parent
81e2cd3e1f
commit
d3ba598a45
@ -30,6 +30,13 @@ export type WebsiteIconData = {
|
||||
icon: string;
|
||||
};
|
||||
|
||||
export type FocusedFieldData = {
|
||||
focusedFieldStyles: Partial<CSSStyleDeclaration>;
|
||||
focusedFieldRects: Partial<DOMRect>;
|
||||
tabId?: number;
|
||||
frameId?: number;
|
||||
};
|
||||
|
||||
export type OverlayAddNewItemMessage = {
|
||||
login?: {
|
||||
uri?: string;
|
||||
@ -39,11 +46,9 @@ export type OverlayAddNewItemMessage = {
|
||||
};
|
||||
};
|
||||
|
||||
export type FocusedFieldData = {
|
||||
focusedFieldStyles: Partial<CSSStyleDeclaration>;
|
||||
focusedFieldRects: Partial<DOMRect>;
|
||||
tabId?: number;
|
||||
frameId?: number;
|
||||
export type CloseInlineMenuMessage = {
|
||||
forceCloseAutofillInlineMenu?: boolean;
|
||||
overlayElement?: string;
|
||||
};
|
||||
|
||||
export type OverlayBackgroundExtensionMessage = {
|
||||
@ -52,8 +57,6 @@ export type OverlayBackgroundExtensionMessage = {
|
||||
tab?: chrome.tabs.Tab;
|
||||
sender?: string;
|
||||
details?: AutofillPageDetails;
|
||||
overlayElement?: string;
|
||||
forceCloseAutofillInlineMenu?: boolean;
|
||||
isAutofillInlineMenuHidden?: boolean;
|
||||
setTransparentInlineMenu?: boolean;
|
||||
isFieldCurrentlyFocused?: boolean;
|
||||
@ -62,7 +65,8 @@ export type OverlayBackgroundExtensionMessage = {
|
||||
focusedFieldData?: FocusedFieldData;
|
||||
styles?: Partial<CSSStyleDeclaration>;
|
||||
data?: LockedVaultPendingNotificationsData;
|
||||
} & OverlayAddNewItemMessage;
|
||||
} & OverlayAddNewItemMessage &
|
||||
CloseInlineMenuMessage;
|
||||
|
||||
export type OverlayPortMessage = {
|
||||
[key: string]: any;
|
||||
@ -116,7 +120,9 @@ export type OverlayBackgroundExtensionMessageHandlers = {
|
||||
rebuildSubFrameOffsets: ({ sender }: BackgroundSenderParam) => void;
|
||||
collectPageDetailsResponse: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
|
||||
unlockCompleted: ({ message }: BackgroundMessageParam) => void;
|
||||
addedCipher: () => void;
|
||||
addEditCipherSubmitted: () => void;
|
||||
editedCipher: () => void;
|
||||
deletedCipher: () => void;
|
||||
};
|
||||
|
||||
|
@ -742,7 +742,7 @@ describe("OverlayBackground", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("openAutofillInlineMenu", () => {
|
||||
describe("openAutofillInlineMenu message handler", () => {
|
||||
let sender: chrome.runtime.MessageSender;
|
||||
|
||||
beforeEach(() => {
|
||||
@ -787,6 +787,161 @@ describe("OverlayBackground", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("closeAutofillInlineMenu", () => {
|
||||
let sender: chrome.runtime.MessageSender;
|
||||
|
||||
beforeEach(() => {
|
||||
sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
||||
sendMockExtensionMessage({
|
||||
command: "updateIsFieldCurrentlyFilling",
|
||||
isFieldCurrentlyFilling: false,
|
||||
});
|
||||
sendMockExtensionMessage({
|
||||
command: "updateIsFieldCurrentlyFocused",
|
||||
isFieldCurrentlyFocused: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("sends a message to close the inline menu without checking field focus state if forcing the closure", async () => {
|
||||
sendMockExtensionMessage({
|
||||
command: "updateIsFieldCurrentlyFocused",
|
||||
isFieldCurrentlyFocused: true,
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
sendMockExtensionMessage(
|
||||
{
|
||||
command: "closeAutofillInlineMenu",
|
||||
forceCloseAutofillInlineMenu: true,
|
||||
overlayElement: AutofillOverlayElement.Button,
|
||||
},
|
||||
sender,
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
||||
sender.tab,
|
||||
{
|
||||
command: "closeInlineMenu",
|
||||
overlayElement: AutofillOverlayElement.Button,
|
||||
},
|
||||
{ frameId: 0 },
|
||||
);
|
||||
});
|
||||
|
||||
it("skips sending a message to close the inline menu if a form field is currently focused", async () => {
|
||||
sendMockExtensionMessage({
|
||||
command: "updateIsFieldCurrentlyFocused",
|
||||
isFieldCurrentlyFocused: true,
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
sendMockExtensionMessage(
|
||||
{
|
||||
command: "closeAutofillInlineMenu",
|
||||
forceCloseAutofillInlineMenu: false,
|
||||
overlayElement: AutofillOverlayElement.Button,
|
||||
},
|
||||
sender,
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
expect(tabsSendMessageSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sends a message to close the inline menu list only if the field is currently filling", async () => {
|
||||
sendMockExtensionMessage({
|
||||
command: "updateIsFieldCurrentlyFilling",
|
||||
isFieldCurrentlyFilling: true,
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
sendMockExtensionMessage({ command: "closeAutofillInlineMenu" }, sender);
|
||||
await flushPromises();
|
||||
|
||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
||||
sender.tab,
|
||||
{
|
||||
command: "closeInlineMenu",
|
||||
overlayElement: AutofillOverlayElement.List,
|
||||
},
|
||||
{ frameId: 0 },
|
||||
);
|
||||
expect(tabsSendMessageSpy).not.toHaveBeenCalledWith(
|
||||
sender.tab,
|
||||
{
|
||||
command: "closeInlineMenu",
|
||||
overlayElement: AutofillOverlayElement.Button,
|
||||
},
|
||||
{ frameId: 0 },
|
||||
);
|
||||
});
|
||||
|
||||
it("sends a message to close the inline menu if the form field is not focused and not filling", async () => {
|
||||
sendMockExtensionMessage({ command: "closeAutofillInlineMenu" }, sender);
|
||||
await flushPromises();
|
||||
|
||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
||||
sender.tab,
|
||||
{
|
||||
command: "closeInlineMenu",
|
||||
overlayElement: undefined,
|
||||
},
|
||||
{ frameId: 0 },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("checkAutofillInlineMenuFocused message handler", () => {
|
||||
beforeEach(async () => {
|
||||
await initOverlayElementPorts();
|
||||
});
|
||||
|
||||
it("will check if the inline menu list is focused if the list port is open", () => {
|
||||
sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" });
|
||||
|
||||
expect(listPortSpy.postMessage).toHaveBeenCalledWith({
|
||||
command: "checkAutofillInlineMenuListFocused",
|
||||
});
|
||||
expect(buttonPortSpy.postMessage).not.toHaveBeenCalledWith({
|
||||
command: "checkAutofillInlineMenuButtonFocused",
|
||||
});
|
||||
});
|
||||
|
||||
it("will check if the overlay button is focused if the list port is not open", () => {
|
||||
overlayBackground["inlineMenuListPort"] = undefined;
|
||||
|
||||
sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" });
|
||||
|
||||
expect(buttonPortSpy.postMessage).toHaveBeenCalledWith({
|
||||
command: "checkAutofillInlineMenuButtonFocused",
|
||||
});
|
||||
expect(listPortSpy.postMessage).not.toHaveBeenCalledWith({
|
||||
command: "checkAutofillInlineMenuListFocused",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("extension messages that trigger an update of the inline menu ciphers", () => {
|
||||
const extensionMessages = [
|
||||
"addedCipher",
|
||||
"addEditCipherSubmitted",
|
||||
"editedCipher",
|
||||
"deletedCipher",
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(overlayBackground, "updateOverlayCiphers").mockImplementation();
|
||||
});
|
||||
|
||||
extensionMessages.forEach((message) => {
|
||||
it(`triggers an update of the overlay ciphers when the ${message} message is received`, () => {
|
||||
sendMockExtensionMessage({ command: message });
|
||||
expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("inline menu button message handlers", () => {});
|
||||
|
@ -43,6 +43,7 @@ import {
|
||||
PageDetailsForTab,
|
||||
SubFrameOffsetData,
|
||||
SubFrameOffsetsForTab,
|
||||
CloseInlineMenuMessage,
|
||||
} from "./abstractions/overlay.background";
|
||||
|
||||
export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
@ -91,7 +92,9 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender),
|
||||
collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender),
|
||||
unlockCompleted: ({ message }) => this.unlockCompleted(message),
|
||||
addedCipher: () => this.updateOverlayCiphers(),
|
||||
addEditCipherSubmitted: () => this.updateOverlayCiphers(),
|
||||
editedCipher: () => this.updateOverlayCiphers(),
|
||||
deletedCipher: () => this.updateOverlayCiphers(),
|
||||
};
|
||||
private readonly inlineMenuButtonPortMessageHandlers: InlineMenuButtonPortMessageHandlers = {
|
||||
@ -470,10 +473,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
*/
|
||||
private closeInlineMenu(
|
||||
sender: chrome.runtime.MessageSender,
|
||||
{
|
||||
forceCloseAutofillInlineMenu,
|
||||
overlayElement,
|
||||
}: { forceCloseAutofillInlineMenu?: boolean; overlayElement?: string } = {},
|
||||
{ forceCloseAutofillInlineMenu, overlayElement }: CloseInlineMenuMessage = {},
|
||||
) {
|
||||
if (forceCloseAutofillInlineMenu) {
|
||||
void BrowserApi.tabSendMessage(
|
||||
@ -507,6 +507,13 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the sender tab to trigger a delayed closure of the inline menu.
|
||||
* This is used to ensure that we capture click events on the inline menu in the case
|
||||
* that some on page programmatic method attempts to force focus redirection.
|
||||
*
|
||||
* @param sender - The sender of the port message
|
||||
*/
|
||||
private triggerDelayedInlineMenuClosure(sender: chrome.runtime.MessageSender) {
|
||||
if (this.isFieldCurrentlyFocused) {
|
||||
return;
|
||||
@ -589,6 +596,10 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles updating the opacity of both the inline menu button and list.
|
||||
* This is used to simultaneously fade in the inline menu elements.
|
||||
*/
|
||||
private setInlineMenuFadeInTimeout() {
|
||||
if (this.inlineMenuFadeInTimeout) {
|
||||
globalThis.clearTimeout(this.inlineMenuFadeInTimeout);
|
||||
@ -598,7 +609,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
this.inlineMenuFadeInTimeout = globalThis.setTimeout(() => {
|
||||
this.inlineMenuButtonPort?.postMessage(message);
|
||||
this.inlineMenuListPort?.postMessage(message);
|
||||
}, 75);
|
||||
}, 50);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -977,6 +988,11 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
return this.isFieldCurrentlyFilling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the top level frame of the sender to check if the inline menu button is visible.
|
||||
*
|
||||
* @param sender - The sender of the message
|
||||
*/
|
||||
private async checkIsAutofillInlineMenuButtonVisible(sender: chrome.runtime.MessageSender) {
|
||||
return await BrowserApi.tabSendMessage(
|
||||
sender.tab,
|
||||
@ -985,6 +1001,11 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the top level frame of the sender to check if the inline menu list is visible.
|
||||
*
|
||||
* @param sender - The sender of the message
|
||||
*/
|
||||
private async checkIsAutofillInlineMenuListVisible(sender: chrome.runtime.MessageSender) {
|
||||
return await BrowserApi.tabSendMessage(
|
||||
sender.tab,
|
||||
@ -993,16 +1014,34 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to the content script's request to check if the inline menu ciphers are populated.
|
||||
* This will return true only if the sender is the focused field's tab and the inline menu
|
||||
* ciphers are populated.
|
||||
*
|
||||
* @param sender - The sender of the message
|
||||
*/
|
||||
private checkIsInlineMenuCiphersPopulated(sender: chrome.runtime.MessageSender) {
|
||||
return sender.tab.id === this.focusedFieldData.tabId && this.inlineMenuCiphers.size > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an update in the meta "color-scheme" value within the inline menu button.
|
||||
* This is done to ensure that the button element has a transparent background, which
|
||||
* is accomplished by setting the "color-scheme" meta value of the button iframe to
|
||||
* the same value as the page's meta "color-scheme" value.
|
||||
*/
|
||||
private updateInlineMenuButtonColorScheme() {
|
||||
this.inlineMenuButtonPort?.postMessage({
|
||||
command: "updateAutofillInlineMenuColorScheme",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an update in the inline menu list's height.
|
||||
*
|
||||
* @param message - Contains the dimensions of the inline menu list
|
||||
*/
|
||||
private updateInlineMenuListHeight(message: OverlayBackgroundExtensionMessage) {
|
||||
this.inlineMenuListPort?.postMessage({
|
||||
command: "updateInlineMenuIframePosition",
|
||||
@ -1160,6 +1199,12 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
handler({ message, port });
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures that the inline menu list and button port
|
||||
* references are reset when they are disconnected.
|
||||
*
|
||||
* @param port - The port that was disconnected
|
||||
*/
|
||||
private handlePortOnDisconnect = (port: chrome.runtime.Port) => {
|
||||
if (port.name === AutofillOverlayPort.List) {
|
||||
this.inlineMenuListPort = null;
|
||||
|
Loading…
Reference in New Issue
Block a user