1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 22:03:36 +00:00

[PM-5880] Refactor browser platform utils service to remove window references (#7885)

* [PM-5880] Refactor Browser Platform Utils Service to Remove Window Service

* [PM-5880] Implementing BrowserClipboardService to handle clipboard logic between the BrowserPlatformUtils and offscreen document

* [PM-5880] Adjusting how readText is handled within BrowserClipboardService

* [PM-5880] Adjusting how readText is handled within BrowserClipboardService

* [PM-5880] Working through implementation of chrome offscreen API usage

* [PM-5880] Implementing jest tests for the methods added to the BrowserApi class

* [PM-5880] Implementing jest tests for the OffscreenDocument class

* [PM-5880] Working through jest tests for BrowserClipboardService

* [PM-5880] Adding typing information to the clipboard methods present within the BrowserPlatformUtilsService

* [PM-5880] Working on adding ServiceWorkerGlobalScope typing information

* [PM-5880] Updating window references when calling BrowserPlatformUtils methods

* [PM-5880] Finishing out jest tests for the BrowserClipboardService

* [PM-5880] Finishing out jest tests for the BrowserClipboardService

* [PM-5880] Implementing jest tests to validate the changes within BrowserApi

* [PM-5880] Implementing jest tests to ensure coverage within OffscreenDocument

* [PM-5880] Implementing jest tests for the BrowserPlatformUtilsService

* [PM-5880] Removing unused catch statements

* [PM-5880] Implementing jest tests for the BrowserPlatformUtilsService

* [PM-5880] Implementing jest tests for the BrowserPlatformUtilsService

* [PM-5880] Fixing broken tests
This commit is contained in:
Cesar Gonzalez
2024-03-06 10:33:38 -06:00
committed by GitHub
parent 940fd21ac4
commit 51f482dde9
25 changed files with 936 additions and 139 deletions

View File

@@ -1,14 +1,24 @@
import { DeviceType } from "@bitwarden/common/enums";
import { flushPromises } from "../../autofill/spec/testing-utils";
import { SafariApp } from "../../browser/safariApp";
import { BrowserApi } from "../browser/browser-api";
import BrowserClipboardService from "./browser-clipboard.service";
import BrowserPlatformUtilsService from "./browser-platform-utils.service";
describe("Browser Utils Service", () => {
let browserPlatformUtilsService: BrowserPlatformUtilsService;
const clipboardWriteCallbackSpy = jest.fn();
beforeEach(() => {
(window as any).matchMedia = jest.fn().mockReturnValueOnce({});
browserPlatformUtilsService = new BrowserPlatformUtilsService(null, null, null, window);
browserPlatformUtilsService = new BrowserPlatformUtilsService(
null,
clipboardWriteCallbackSpy,
null,
window,
);
});
describe("getBrowser", () => {
@@ -26,7 +36,6 @@ describe("Browser Utils Service", () => {
afterEach(() => {
window.matchMedia = undefined;
(window as any).chrome = undefined;
(BrowserPlatformUtilsService as any).deviceCache = null;
});
@@ -37,8 +46,6 @@ describe("Browser Utils Service", () => {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
});
(window as any).chrome = {};
expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.ChromeExtension);
});
@@ -90,6 +97,29 @@ describe("Browser Utils Service", () => {
expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.VivaldiExtension);
});
it("returns a previously determined device using a cached value", () => {
Object.defineProperty(navigator, "userAgent", {
configurable: true,
value: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0",
});
jest.spyOn(BrowserPlatformUtilsService, "isFirefox");
browserPlatformUtilsService.getDevice();
expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.FirefoxExtension);
expect(BrowserPlatformUtilsService.isFirefox).toHaveBeenCalledTimes(1);
});
});
describe("getDeviceString", () => {
it("returns a string value indicating the device type", () => {
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
expect(browserPlatformUtilsService.getDeviceString()).toBe("chrome");
});
});
describe("isViewOpen", () => {
@@ -113,6 +143,176 @@ describe("Browser Utils Service", () => {
expect(isViewOpen).toBe(true);
});
});
describe("copyToClipboard", () => {
const getManifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get");
const sendMessageToAppSpy = jest.spyOn(SafariApp, "sendMessageToApp");
const clipboardServiceCopySpy = jest.spyOn(BrowserClipboardService, "copy");
let triggerOffscreenCopyToClipboardSpy: jest.SpyInstance;
beforeEach(() => {
getManifestVersionSpy.mockReturnValue(2);
triggerOffscreenCopyToClipboardSpy = jest.spyOn(
browserPlatformUtilsService as any,
"triggerOffscreenCopyToClipboard",
);
});
afterEach(() => {
jest.resetAllMocks();
});
it("sends a copy to clipboard message to the desktop application if a user is using the safari browser", async () => {
const text = "test";
const clearMs = 1000;
sendMessageToAppSpy.mockResolvedValueOnce("success");
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.SafariExtension);
browserPlatformUtilsService.copyToClipboard(text, { clearMs });
await flushPromises();
expect(sendMessageToAppSpy).toHaveBeenCalledWith("copyToClipboard", text);
expect(clipboardWriteCallbackSpy).toHaveBeenCalledWith(text, clearMs);
expect(clipboardServiceCopySpy).not.toHaveBeenCalled();
expect(triggerOffscreenCopyToClipboardSpy).not.toHaveBeenCalled();
});
it("sets the copied text to a unicode placeholder when the user is using Chrome if the passed text is an empty string", async () => {
const text = "";
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
browserPlatformUtilsService.copyToClipboard(text);
await flushPromises();
expect(clipboardServiceCopySpy).toHaveBeenCalledWith(window, "\u0000");
});
it("copies the passed text using the BrowserClipboardService", async () => {
const text = "test";
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
browserPlatformUtilsService.copyToClipboard(text, { window: self });
await flushPromises();
expect(clipboardServiceCopySpy).toHaveBeenCalledWith(self, text);
expect(triggerOffscreenCopyToClipboardSpy).not.toHaveBeenCalled();
});
it("copies the passed text using the offscreen document if the extension is using manifest v3", async () => {
const text = "test";
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
getManifestVersionSpy.mockReturnValue(3);
jest.spyOn(BrowserApi, "createOffscreenDocument");
jest.spyOn(BrowserApi, "sendMessageWithResponse").mockResolvedValue(undefined);
jest.spyOn(BrowserApi, "closeOffscreenDocument");
browserPlatformUtilsService.copyToClipboard(text);
await flushPromises();
expect(triggerOffscreenCopyToClipboardSpy).toHaveBeenCalledWith(text);
expect(clipboardServiceCopySpy).not.toHaveBeenCalled();
expect(BrowserApi.createOffscreenDocument).toHaveBeenCalledWith(
[chrome.offscreen.Reason.CLIPBOARD],
"Write text to the clipboard.",
);
expect(BrowserApi.sendMessageWithResponse).toHaveBeenCalledWith("offscreenCopyToClipboard", {
text,
});
expect(BrowserApi.closeOffscreenDocument).toHaveBeenCalled();
});
it("skips the clipboardWriteCallback if the clipboard is clearing", async () => {
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
browserPlatformUtilsService.copyToClipboard("test", { window: self, clearing: true });
await flushPromises();
expect(clipboardWriteCallbackSpy).not.toHaveBeenCalled();
});
});
describe("readFromClipboard", () => {
const getManifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get");
const sendMessageToAppSpy = jest.spyOn(SafariApp, "sendMessageToApp");
const clipboardServiceReadSpy = jest.spyOn(BrowserClipboardService, "read");
beforeEach(() => {
getManifestVersionSpy.mockReturnValue(2);
});
afterEach(() => {
jest.resetAllMocks();
});
it("sends a ready from clipboard message to the desktop application if a user is using the safari browser", async () => {
sendMessageToAppSpy.mockResolvedValueOnce("test");
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.SafariExtension);
const result = await browserPlatformUtilsService.readFromClipboard();
expect(sendMessageToAppSpy).toHaveBeenCalledWith("readFromClipboard");
expect(clipboardServiceReadSpy).not.toHaveBeenCalled();
expect(result).toBe("test");
});
it("reads text from the clipboard using the ClipboardService", async () => {
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
clipboardServiceReadSpy.mockResolvedValueOnce("test");
const result = await browserPlatformUtilsService.readFromClipboard({ window: self });
expect(clipboardServiceReadSpy).toHaveBeenCalledWith(self);
expect(sendMessageToAppSpy).not.toHaveBeenCalled();
expect(result).toBe("test");
});
it("reads the clipboard text using the offscreen document", async () => {
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
getManifestVersionSpy.mockReturnValue(3);
jest.spyOn(BrowserApi, "createOffscreenDocument");
jest.spyOn(BrowserApi, "sendMessageWithResponse").mockResolvedValue("test");
jest.spyOn(BrowserApi, "closeOffscreenDocument");
await browserPlatformUtilsService.readFromClipboard();
expect(BrowserApi.createOffscreenDocument).toHaveBeenCalledWith(
[chrome.offscreen.Reason.CLIPBOARD],
"Read text from the clipboard.",
);
expect(BrowserApi.sendMessageWithResponse).toHaveBeenCalledWith("offscreenReadFromClipboard");
expect(BrowserApi.closeOffscreenDocument).toHaveBeenCalled();
});
it("returns an empty string from the offscreen document if the response is not of type string", async () => {
jest
.spyOn(browserPlatformUtilsService, "getDevice")
.mockReturnValue(DeviceType.ChromeExtension);
getManifestVersionSpy.mockReturnValue(3);
jest.spyOn(BrowserApi, "createOffscreenDocument");
jest.spyOn(BrowserApi, "sendMessageWithResponse").mockResolvedValue(1);
jest.spyOn(BrowserApi, "closeOffscreenDocument");
const result = await browserPlatformUtilsService.readFromClipboard();
expect(result).toBe("");
});
});
});
describe("Safari Height Fix", () => {