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:
@@ -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", () => {
|
||||
|
||||
Reference in New Issue
Block a user