From 52c8cab152322c07e1d07de4505d8ad4d7c67546 Mon Sep 17 00:00:00 2001 From: Cesar Gonzalez Date: Wed, 7 Feb 2024 16:45:41 -0600 Subject: [PATCH] [PM-5878] Rework `window` call within OverlayBackground to function within AutofillOverlayIframe service (#7770) --- .../background/overlay.background.spec.ts | 5 +- .../autofill/background/overlay.background.ts | 18 +------ .../src/autofill/jest/autofill-mocks.ts | 3 +- .../autofill-overlay-iframe.service.spec.ts | 52 +++++++++++++++++-- .../autofill-overlay-iframe.service.ts | 16 ++++-- .../autofill-overlay-list.spec.ts.snap | 6 +-- .../pages/list/autofill-overlay-list.ts | 5 +- .../src/autofill/shared/styles/variables.scss | 6 +-- 8 files changed, 75 insertions(+), 36 deletions(-) diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index e0bb7439c2..a87bea8e95 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -1028,12 +1028,13 @@ describe("OverlayBackground", () => { it("gets the system theme", async () => { jest.spyOn(overlayBackground["stateService"], "getTheme").mockResolvedValue(ThemeType.System); - window.matchMedia = jest.fn(() => mock({ matches: true })); initOverlayElementPorts({ initList: true, initButton: false }); await flushPromises(); - expect(window.matchMedia).toHaveBeenCalledWith("(prefers-color-scheme: dark)"); + expect(listPortSpy.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ theme: ThemeType.System }), + ); }); }); diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index a51b641175..0bfef2d295 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -5,7 +5,6 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { ThemeType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherType } from "@bitwarden/common/vault/enums"; @@ -482,21 +481,6 @@ class OverlayBackground implements OverlayBackgroundInterface { return this.userAuthStatus; } - /** - * Gets the currently set theme for the user. - */ - private async getCurrentTheme() { - const theme = await this.stateService.getTheme(); - - if (theme !== ThemeType.System) { - return theme; - } - - return window.matchMedia("(prefers-color-scheme: dark)").matches - ? ThemeType.Dark - : ThemeType.Light; - } - /** * Sends a message to the overlay button to update its authentication status. */ @@ -744,7 +728,7 @@ class OverlayBackground implements OverlayBackgroundInterface { command: `initAutofillOverlay${isOverlayListPort ? "List" : "Button"}`, authStatus: await this.getAuthStatus(), styleSheetUrl: chrome.runtime.getURL(`overlay/${isOverlayListPort ? "list" : "button"}.css`), - theme: `theme_${await this.getCurrentTheme()}`, + theme: await this.stateService.getTheme(), translations: this.getTranslations(), ciphers: isOverlayListPort ? this.getOverlayCipherData() : null, }); diff --git a/apps/browser/src/autofill/jest/autofill-mocks.ts b/apps/browser/src/autofill/jest/autofill-mocks.ts index 655727697d..b580977a37 100644 --- a/apps/browser/src/autofill/jest/autofill-mocks.ts +++ b/apps/browser/src/autofill/jest/autofill-mocks.ts @@ -1,6 +1,7 @@ import { mock } from "jest-mock-extended"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { ThemeType } from "@bitwarden/common/platform/enums"; import { UriMatchType, CipherType } from "@bitwarden/common/vault/enums"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; @@ -199,7 +200,7 @@ function createInitAutofillOverlayListMessageMock( command: "initAutofillOverlayList", translations: overlayPagesTranslations, styleSheetUrl: "https://jest-testing-website.com", - theme: "light", + theme: ThemeType.Light, authStatus: AuthenticationStatus.Unlocked, ciphers: [ createAutofillOverlayCipherDataMock(1, { diff --git a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts index d15404b5b0..554822a9af 100644 --- a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts +++ b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.spec.ts @@ -1,3 +1,7 @@ +import { mock } from "jest-mock-extended"; + +import { ThemeType } from "@bitwarden/common/platform/enums"; + import { EVENTS } from "../../constants"; import { createPortSpyMock } from "../../jest/autofill-mocks"; import { @@ -208,10 +212,10 @@ describe("AutofillOverlayIframeService", () => { ); }); - it("passed the message on to the iframe element", () => { + it("passes the message on to the iframe element", () => { const message = { command: "initAutofillOverlayList", - theme: "theme_light", + theme: ThemeType.Light, }; sendPortMessage(portSpy, message); @@ -223,10 +227,48 @@ describe("AutofillOverlayIframeService", () => { ); }); + it("sets a light theme based on the user's system preferences", () => { + window.matchMedia = jest.fn(() => mock({ matches: false })); + const message = { + command: "initAutofillOverlayList", + theme: ThemeType.System, + }; + + sendPortMessage(portSpy, message); + + expect(window.matchMedia).toHaveBeenCalledWith("(prefers-color-scheme: dark)"); + expect(autofillOverlayIframeService["iframe"].contentWindow.postMessage).toBeCalledWith( + { + command: "initAutofillOverlayList", + theme: ThemeType.Light, + }, + "*", + ); + }); + + it("sets a dark theme based on the user's system preferences", () => { + window.matchMedia = jest.fn(() => mock({ matches: true })); + const message = { + command: "initAutofillOverlayList", + theme: ThemeType.System, + }; + + sendPortMessage(portSpy, message); + + expect(window.matchMedia).toHaveBeenCalledWith("(prefers-color-scheme: dark)"); + expect(autofillOverlayIframeService["iframe"].contentWindow.postMessage).toBeCalledWith( + { + command: "initAutofillOverlayList", + theme: ThemeType.Dark, + }, + "*", + ); + }); + it("updates the border to match the `dark` theme", () => { const message = { command: "initAutofillOverlayList", - theme: "theme_dark", + theme: ThemeType.Dark, }; sendPortMessage(portSpy, message); @@ -239,7 +281,7 @@ describe("AutofillOverlayIframeService", () => { it("updates the border to match the `nord` theme", () => { const message = { command: "initAutofillOverlayList", - theme: "theme_nord", + theme: ThemeType.Nord, }; sendPortMessage(portSpy, message); @@ -252,7 +294,7 @@ describe("AutofillOverlayIframeService", () => { it("updates the border to match the `solarizedDark` theme", () => { const message = { command: "initAutofillOverlayList", - theme: "theme_solarizedDark", + theme: ThemeType.SolarizedDark, }; sendPortMessage(portSpy, message); diff --git a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts index 29efc3cdc5..9cf235ab9f 100644 --- a/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts +++ b/apps/browser/src/autofill/overlay/iframe-content/autofill-overlay-iframe.service.ts @@ -1,3 +1,5 @@ +import { ThemeType } from "@bitwarden/common/platform/enums"; + import { EVENTS } from "../../constants"; import { setElementStyles } from "../../utils"; import { @@ -207,19 +209,27 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf private initAutofillOverlayList(message: AutofillOverlayIframeExtensionMessage) { const { theme } = message; let borderColor: string; - if (theme === "theme_dark") { + let verifiedTheme = theme; + if (verifiedTheme === ThemeType.System) { + verifiedTheme = window.matchMedia("(prefers-color-scheme: dark)").matches + ? ThemeType.Dark + : ThemeType.Light; + } + + if (verifiedTheme === ThemeType.Dark) { borderColor = "#4c525f"; } - if (theme === "theme_nord") { + if (theme === ThemeType.Nord) { borderColor = "#2E3440"; } - if (theme === "theme_solarizedDark") { + if (theme === ThemeType.SolarizedDark) { borderColor = "#073642"; } if (borderColor) { this.updateElementStyles(this.iframe, { borderColor }); } + message.theme = verifiedTheme; this.iframe.contentWindow?.postMessage(message, "*"); } diff --git a/apps/browser/src/autofill/overlay/pages/list/__snapshots__/autofill-overlay-list.spec.ts.snap b/apps/browser/src/autofill/overlay/pages/list/__snapshots__/autofill-overlay-list.spec.ts.snap index ddee3d5ee3..da9a0c53bf 100644 --- a/apps/browser/src/autofill/overlay/pages/list/__snapshots__/autofill-overlay-list.spec.ts.snap +++ b/apps/browser/src/autofill/overlay/pages/list/__snapshots__/autofill-overlay-list.spec.ts.snap @@ -3,7 +3,7 @@ exports[`AutofillOverlayList initAutofillOverlayList the list of ciphers for an authenticated user creates the view for a list of ciphers 1`] = `