From 35e19b671261e48884d4c8d8a7d09da89bf8b51c Mon Sep 17 00:00:00 2001 From: Giulia Ye Date: Fri, 31 May 2024 18:54:55 +0200 Subject: [PATCH] feat: better tab management --- package.json | 1 + playwright.config.ts | 2 +- pnpm-lock.yaml | 110 ++++++++++++++++++ src/entries/background/main.ts | 20 ---- src/entries/contentScript/primary/main.ts | 9 +- src/entries/popup/App.svelte | 14 +-- src/lib/pages/page.ts | 8 +- src/lib/pages/pageFactory.test.ts | 12 -- src/lib/services/browser.ts | 25 ++++ .../messagingService/messagingService.test.ts | 22 ++++ .../messagingService/messagingService.ts | 17 +++ src/lib/services/messenger/messagingClient.ts | 21 ---- .../messenger/messengerService.test.ts | 40 ------- .../services/messenger/messengerService.ts | 21 ---- src/lib/services/tabsService.test.ts | 71 ----------- src/lib/services/tabsService.ts | 36 ------ src/manifest.ts | 2 +- src/tests/mock/webextension-polyfill.ts | 22 ++++ src/tests/setup.ts | 22 ---- tsconfig.json | 3 +- vite.config.ts | 10 ++ 21 files changed, 223 insertions(+), 265 deletions(-) create mode 100644 src/lib/services/browser.ts create mode 100644 src/lib/services/messagingService/messagingService.test.ts create mode 100644 src/lib/services/messagingService/messagingService.ts delete mode 100644 src/lib/services/messenger/messagingClient.ts delete mode 100644 src/lib/services/messenger/messengerService.test.ts delete mode 100644 src/lib/services/messenger/messengerService.ts delete mode 100644 src/lib/services/tabsService.test.ts delete mode 100644 src/lib/services/tabsService.ts create mode 100644 src/tests/mock/webextension-polyfill.ts diff --git a/package.json b/package.json index 422fc45..b623134 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "tslib": "^2.5.0", "typescript": "^5.0.4", "vite": "~4.3.3", + "vite-plugin-checker": "^0.6.4", "vitest": "^1.0.4", "vitest-dom": "^0.1.1", "web-ext": "^7.6.2" diff --git a/playwright.config.ts b/playwright.config.ts index f1bb6f6..3108699 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, + retries: process.env.CI ? 3 : 0, /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 245b9d5..e8af4ac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -118,6 +118,9 @@ devDependencies: vite: specifier: ~4.3.3 version: 4.3.3(@types/node@20.9.0)(sass@1.69.5) + vite-plugin-checker: + specifier: ^0.6.4 + version: 0.6.4(typescript@5.0.4)(vite@4.3.3) vitest: specifier: ^1.0.4 version: 1.0.4(@types/node@20.9.0)(jsdom@23.0.1)(sass@1.69.5) @@ -4593,6 +4596,13 @@ packages: engines: {node: '>=6'} dev: true + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -5322,6 +5332,11 @@ packages: engines: {node: '>= 6'} dev: true + /commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + dev: true + /commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} @@ -10640,6 +10655,11 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + /type-fest@0.6.0: resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} engines: {node: '>=8'} @@ -10960,6 +10980,56 @@ packages: - terser dev: true + /vite-plugin-checker@0.6.4(typescript@5.0.4)(vite@4.3.3): + resolution: {integrity: sha512-2zKHH5oxr+ye43nReRbC2fny1nyARwhxdm0uNYp/ERy4YvU9iZpNOsueoi/luXw5gnpqRSvjcEPxXbS153O2wA==} + engines: {node: '>=14.16'} + peerDependencies: + eslint: '>=7' + meow: ^9.0.0 + optionator: ^0.9.1 + stylelint: '>=13' + typescript: '*' + vite: '>=2.0.0' + vls: '*' + vti: '*' + vue-tsc: '>=1.3.9' + peerDependenciesMeta: + eslint: + optional: true + meow: + optional: true + optionator: + optional: true + stylelint: + optional: true + typescript: + optional: true + vls: + optional: true + vti: + optional: true + vue-tsc: + optional: true + dependencies: + '@babel/code-frame': 7.22.13 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + chokidar: 3.5.3 + commander: 8.3.0 + fast-glob: 3.3.2 + fs-extra: 11.1.1 + npm-run-path: 4.0.1 + semver: 7.5.4 + strip-ansi: 6.0.1 + tiny-invariant: 1.3.1 + typescript: 5.0.4 + vite: 4.3.3(@types/node@20.9.0)(sass@1.69.5) + vscode-languageclient: 7.0.0 + vscode-languageserver: 7.0.0 + vscode-languageserver-textdocument: 1.0.11 + vscode-uri: 3.0.8 + dev: true + /vite@4.3.3(@types/node@20.9.0)(sass@1.69.5): resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -11114,6 +11184,46 @@ packages: - terser dev: true + /vscode-jsonrpc@6.0.0: + resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} + engines: {node: '>=8.0.0 || >=10.0.0'} + dev: true + + /vscode-languageclient@7.0.0: + resolution: {integrity: sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==} + engines: {vscode: ^1.52.0} + dependencies: + minimatch: 3.1.2 + semver: 7.5.4 + vscode-languageserver-protocol: 3.16.0 + dev: true + + /vscode-languageserver-protocol@3.16.0: + resolution: {integrity: sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==} + dependencies: + vscode-jsonrpc: 6.0.0 + vscode-languageserver-types: 3.16.0 + dev: true + + /vscode-languageserver-textdocument@1.0.11: + resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==} + dev: true + + /vscode-languageserver-types@3.16.0: + resolution: {integrity: sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==} + dev: true + + /vscode-languageserver@7.0.0: + resolution: {integrity: sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==} + hasBin: true + dependencies: + vscode-languageserver-protocol: 3.16.0 + dev: true + + /vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + dev: true + /w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} diff --git a/src/entries/background/main.ts b/src/entries/background/main.ts index 8256b3a..e69de29 100644 --- a/src/entries/background/main.ts +++ b/src/entries/background/main.ts @@ -1,20 +0,0 @@ -import browser from "webextension-polyfill"; -import OptionsSyncStorage from "../../lib/services/storage"; -import TabsService from "../../lib/services/tabsService"; - -const storage = OptionsSyncStorage.getInstance(); -const tabs = new TabsService(storage); - -browser.tabs.onUpdated.addListener(async function (tabId, changeInfo, tab) { - if ( - changeInfo.status == "complete" && - (tab.title?.toLowerCase().includes("vitesicure") || - tab.title?.toLowerCase().includes("bridge insurance services")) - ) { - await tabs.addTab(tabId.toString()); - } -}); - -browser.tabs.onRemoved.addListener(async function (tabId, _removeInfo) { - await tabs.removeTab(tabId.toString()); -}); diff --git a/src/entries/contentScript/primary/main.ts b/src/entries/contentScript/primary/main.ts index e94ed40..c66ec32 100644 --- a/src/entries/contentScript/primary/main.ts +++ b/src/entries/contentScript/primary/main.ts @@ -3,10 +3,9 @@ import { waitForElement } from "../../../lib/utils/waitForElement"; import prepareComponent from "../renderContent"; import PageFactory from "../../../lib/pages/pageFactory"; import OptionsSyncStorage from "../../../lib/services/storage"; -import BrowserMessagingClient from "../../../lib/services/messenger/messagingClient"; +import MessagingService from "../../../lib/services/messagingService/messagingService"; const storage = OptionsSyncStorage.getInstance(); -const messageListener = new BrowserMessagingClient(); let lastUrl = location.href; new MutationObserver(() => { @@ -37,7 +36,7 @@ async function loadPathBox() { loadPathBox(); -messageListener.listenForMessage("auto-fill", async (content) => { +MessagingService.listen("auto-fill", async (content) => { const { goToNextPage } = content; const [_, product, isPreventivatorePage, isOtherPage] = window.location.pathname.split("/"); @@ -51,10 +50,10 @@ messageListener.listenForMessage("auto-fill", async (content) => { } }); -messageListener.listenForMessage("remove-path-box", async () => { +MessagingService.listen("remove-path-box", async () => { document.getElementById("vitesicure-path-box")?.remove(); }); -messageListener.listenForMessage("load-path-box", async () => { +MessagingService.listen("load-path-box", async () => { loadPathBox(); }); diff --git a/src/entries/popup/App.svelte b/src/entries/popup/App.svelte index c398232..9f78b26 100644 --- a/src/entries/popup/App.svelte +++ b/src/entries/popup/App.svelte @@ -2,14 +2,10 @@ import { onMount } from "svelte"; import Button from "~/lib/components/Button.svelte"; import Switch from "~/lib/components/Switch.svelte"; - import MessengerService from "~/lib/services/messenger/messengerService"; - import BrowserMessagingClient from "~/lib/services/messenger/messagingClient"; + import MessagingService from "~/lib/services/messagingService/messagingService"; import OptionsSyncStorage from "~/lib/services/storage"; - import TabsService from "~/lib/services/tabsService"; const storage = OptionsSyncStorage.getInstance(); - const tabs = new TabsService(storage); - const messenger = new MessengerService(new BrowserMessagingClient(), tabs); let showPathBox = true; let debugMode = false; @@ -27,15 +23,15 @@ storage.set("debugMode", debugMode); }; - $: messenger.send(debugMode ? "set-debug-mode" : "unset-debug-mode"); - $: messenger.send(showPathBox ? "load-path-box" : "remove-path-box"); + $: MessagingService.send(debugMode ? "set-debug-mode" : "unset-debug-mode"); + $: MessagingService.send(showPathBox ? "load-path-box" : "remove-path-box"); const autofill = async () => { - await messenger.send("auto-fill"); + await MessagingService.send("auto-fill"); }; const autofillAndGoToNextPage = async () => { - await messenger.send("auto-fill", { + await MessagingService.send("auto-fill", { goToNextPage: true, }); }; diff --git a/src/lib/pages/page.ts b/src/lib/pages/page.ts index 15fdfb4..71082ad 100644 --- a/src/lib/pages/page.ts +++ b/src/lib/pages/page.ts @@ -1,17 +1,15 @@ -import BrowserMessagingClient from "../services/messenger/messagingClient"; +import MessagingService from "../services/messagingService/messagingService"; export default abstract class Page { static path: string; protected debugMode: boolean; constructor() { - const messageListener = new BrowserMessagingClient(); - - messageListener.listenForMessage("set-debug-mode", () => { + MessagingService.listen("set-debug-mode", () => { this.debugMode = true; }); - messageListener.listenForMessage("unset-debug-mode", () => { + MessagingService.listen("unset-debug-mode", () => { this.debugMode = false; }); } diff --git a/src/lib/pages/pageFactory.test.ts b/src/lib/pages/pageFactory.test.ts index 9694c61..58cffbe 100644 --- a/src/lib/pages/pageFactory.test.ts +++ b/src/lib/pages/pageFactory.test.ts @@ -1,4 +1,3 @@ -import BrowserMessagingClient from "../services/messenger/messagingClient"; import InjuryCheckoutPage from "./injury/checkoutPage"; import ContractorPage from "./injury/contractorPage"; import SelectPage from "./injury/selectPage"; @@ -17,17 +16,6 @@ import OldPreventivatorePage from "./old-life/preventivatorePage"; import OldYourOfferPage from "./old-life/yourOfferPage"; import PageFactory from "./pageFactory"; -vi.mock("../services/messenger/messagingClient", () => { - return { - __esModule: true, - default: vi.fn().mockImplementation(() => { - return { - listenForMessage: vi.fn(), - }; - }), - }; -}); - describe("PageFactory tests", () => { it("should return correct page from product and path", () => { expect(PageFactory.getPage("vita", "preventivatore")).toBeInstanceOf( diff --git a/src/lib/services/browser.ts b/src/lib/services/browser.ts new file mode 100644 index 0000000..f9c5d04 --- /dev/null +++ b/src/lib/services/browser.ts @@ -0,0 +1,25 @@ +import browser from "webextension-polyfill"; + +export const getCurrentTab = async () => { + const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); + return tab; +}; + +export const sendMessage = async ( + message: string, + content: any, + tabId: number, +) => { + await browser.tabs.sendMessage(tabId, { message, content }); +}; + +export const listenForMessage = ( + message: string, + callback: (content: any) => void, +) => { + browser.runtime.onMessage.addListener((listenerMessage) => { + if (listenerMessage.message === message) { + callback(listenerMessage.content); + } + }); +}; diff --git a/src/lib/services/messagingService/messagingService.test.ts b/src/lib/services/messagingService/messagingService.test.ts new file mode 100644 index 0000000..525c87d --- /dev/null +++ b/src/lib/services/messagingService/messagingService.test.ts @@ -0,0 +1,22 @@ +import MessagingService from "./messagingService"; +import * as browser from "../browser"; + +describe("MessagingService", () => { + const browserSendMessage = vi.spyOn(browser, "sendMessage"); + + it("sendMessage should send message to current tab", async () => { + MessagingService.send("messageTest", { + myContent: "test", + }); + + await vi.waitFor(() => { + expect(browserSendMessage).toHaveBeenCalledWith( + "messageTest", + { + myContent: "test", + }, + 1, + ); + }); + }); +}); diff --git a/src/lib/services/messagingService/messagingService.ts b/src/lib/services/messagingService/messagingService.ts new file mode 100644 index 0000000..2adfebd --- /dev/null +++ b/src/lib/services/messagingService/messagingService.ts @@ -0,0 +1,17 @@ +import { getCurrentTab, listenForMessage, sendMessage } from "../browser"; + +class MessagingService { + public static async send(message: string, content: any = {}) { + const tab = await getCurrentTab(); + await sendMessage(message, content, tab.id); + } + + public static async listen( + message: string, + callback: (content: any) => void, + ) { + listenForMessage(message, callback); + } +} + +export default MessagingService; diff --git a/src/lib/services/messenger/messagingClient.ts b/src/lib/services/messenger/messagingClient.ts deleted file mode 100644 index 6c98b4f..0000000 --- a/src/lib/services/messenger/messagingClient.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { MessagingClient } from "./messengerService"; -import browser from "webextension-polyfill"; - -class BrowserMessagingClient implements MessagingClient { - public async sendMessage(message: string, content: any, tabId: string) { - browser.tabs.sendMessage(parseInt(tabId), { message, content }); - } - - public async listenForMessage( - message: string, - callback: (content: any) => void, - ) { - browser.runtime.onMessage.addListener((listenerMessage) => { - if (listenerMessage.message === message) { - callback(listenerMessage.content); - } - }); - } -} - -export default BrowserMessagingClient; diff --git a/src/lib/services/messenger/messengerService.test.ts b/src/lib/services/messenger/messengerService.test.ts deleted file mode 100644 index f926d2b..0000000 --- a/src/lib/services/messenger/messengerService.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import MessengerService from "./messengerService"; - -describe("messengerService", () => { - let messageService: MessengerService; - - const mockedMessagingClient = { - sendMessage: vi.fn(), - }; - - const mockedTabsService = { - getTabs: vi.fn(), - } as any; - - beforeAll(() => { - messageService = new MessengerService( - mockedMessagingClient, - mockedTabsService, - ); - }); - - it("sendMessage should send message to each saved tab", async () => { - mockedTabsService.getTabs.mockResolvedValueOnce(["tabId1", "tabId2"]); - messageService.send("messageTest", { - myContent: "test", - }); - - await vi.waitFor(() => { - expect(mockedMessagingClient.sendMessage).toHaveBeenCalledWith( - "messageTest", - { myContent: "test" }, - "tabId1", - ); - expect(mockedMessagingClient.sendMessage).toHaveBeenCalledWith( - "messageTest", - { myContent: "test" }, - "tabId2", - ); - }); - }); -}); diff --git a/src/lib/services/messenger/messengerService.ts b/src/lib/services/messenger/messengerService.ts deleted file mode 100644 index 547b05c..0000000 --- a/src/lib/services/messenger/messengerService.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type TabsService from "../tabsService"; - -class MessengerService { - constructor( - private readonly messagingClient: MessagingClient, - private readonly tabs: TabsService, - ) {} - - public async send(message: string, content: any = {}) { - const tabs = await this.tabs.getTabs(); - for (const tabId of tabs) { - this.messagingClient.sendMessage(message, content, tabId); - } - } -} - -export interface MessagingClient { - sendMessage: (message: string, content: any, tabId: string) => void; -} - -export default MessengerService; diff --git a/src/lib/services/tabsService.test.ts b/src/lib/services/tabsService.test.ts deleted file mode 100644 index b608709..0000000 --- a/src/lib/services/tabsService.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import TabsService from "./tabsService"; - -describe("tabsService", () => { - const mockedStorage = { - get: vi.fn(), - getAll: vi.fn(), - set: vi.fn(), - }; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it("getTabs should return a list of tab ids", async () => { - const tabs = ["1", "2", "3"]; - mockedStorage.get.mockResolvedValueOnce(tabs); - const tabsService = new TabsService(mockedStorage); - - const result = await tabsService.getTabs(); - - expect(result).toEqual(tabs); - }); - - describe("removeTab", () => { - it("should remove the tab id from the list", async () => { - mockedStorage.get.mockResolvedValueOnce(["1", "2", "3"]); - const tabsService = new TabsService(mockedStorage); - - await tabsService.removeTab("2"); - - expect(mockedStorage.set).toHaveBeenCalledWith("vitesicureTabIds", [ - "1", - "3", - ]); - }); - - it("should do nothing if tab id is not present", async () => { - mockedStorage.get.mockResolvedValueOnce(["1", "2"]); - const tabsService = new TabsService(mockedStorage); - - await tabsService.removeTab("3"); - - expect(mockedStorage.set).not.toHaveBeenCalled(); - }); - }); - - describe("addTab", () => { - it("should add the tab id to the list", async () => { - mockedStorage.get.mockResolvedValueOnce(["1", "2", "3"]); - const tabsService = new TabsService(mockedStorage); - - await tabsService.addTab("4"); - - expect(mockedStorage.set).toHaveBeenCalledWith("vitesicureTabIds", [ - "1", - "2", - "3", - "4", - ]); - }); - - it("should do nothing if tab id is already present in the list", async () => { - mockedStorage.get.mockResolvedValueOnce(["1", "2", "3"]); - const tabsService = new TabsService(mockedStorage); - - await tabsService.addTab("3"); - - expect(mockedStorage.set).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/src/lib/services/tabsService.ts b/src/lib/services/tabsService.ts deleted file mode 100644 index 9692142..0000000 --- a/src/lib/services/tabsService.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { IStorage } from "./storage"; - -class TabsService { - private readonly tabsKey = "vitesicureTabIds"; - - constructor(private readonly storage: IStorage) {} - - public async getTabs(): Promise { - return (await this.storage.get(this.tabsKey)) ?? []; - } - - public async addTab(tabId: string) { - const tabs = await this.getTabs(); - if (this.isTabIdPresent(tabId, tabs)) { - return; - } - - await this.storage.set(this.tabsKey, [...tabs, tabId]); - } - - public async removeTab(tabId: string) { - const tabs = await this.getTabs(); - if (!this.isTabIdPresent(tabId, tabs)) { - return; - } - - tabs.splice(tabs.indexOf(tabId), 1); - await this.storage.set(this.tabsKey, tabs); - } - - private isTabIdPresent(tabId: string, tabs: string[]) { - return tabs.includes(tabId); - } -} - -export default TabsService; diff --git a/src/manifest.ts b/src/manifest.ts index 5d9fc87..77444fa 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -95,7 +95,7 @@ export function getManifest( ...manifest, ...ManifestV3, manifest_version: manifestVersion, - }; + } as chrome.runtime.ManifestV3; } throw new Error( diff --git a/src/tests/mock/webextension-polyfill.ts b/src/tests/mock/webextension-polyfill.ts new file mode 100644 index 0000000..6a255e9 --- /dev/null +++ b/src/tests/mock/webextension-polyfill.ts @@ -0,0 +1,22 @@ +const mockBrowser = { + tabs: { + sendMessage: vi.fn(), + query: vi.fn().mockResolvedValue([ + { + id: 1, + index: 0, + highlighted: false, + active: false, + pinned: false, + incognito: false, + }, + ]), + }, + runtime: { + onMessage: { + addListener: vi.fn(), + }, + }, +}; + +export default mockBrowser; diff --git a/src/tests/setup.ts b/src/tests/setup.ts index 2a90905..97cd9be 100644 --- a/src/tests/setup.ts +++ b/src/tests/setup.ts @@ -1,23 +1 @@ import "vitest-dom/extend-expect"; - -// beforeAll(() => { -// const chromeMock = { -// tabs: { -// query: vi.fn((_queryInfo, callback) => { -// callback([{ id: 123 }]); -// }), -// // eslint-disable-next-line @typescript-eslint/no-unused-vars -// create: vi.fn(({ url }: { url: string }) => {}), -// }, -// sidePanel: { -// open: vi.fn(), -// }, -// commands: { -// getAll: vi.fn(() => { -// return []; -// }), -// }, -// }; -// -// vi.stubGlobal("chrome", chromeMock); -// }); diff --git a/tsconfig.json b/tsconfig.json index 2f90329..21ac140 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,8 @@ * of JS in `.svelte` files. */ "allowJs": true, - "checkJs": true + "checkJs": true, + "noEmit": true }, "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] } diff --git a/vite.config.ts b/vite.config.ts index 0d122e5..187bcf9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,6 +2,7 @@ import { defineConfig, loadEnv } from "vite"; import { svelte } from "@sveltejs/vite-plugin-svelte"; import webExtension from "@samrum/vite-plugin-web-extension"; +import checker from "vite-plugin-checker"; import path from "path"; import { getManifest } from "./src/manifest"; @@ -13,6 +14,9 @@ export default defineConfig(({ mode }) => { return { plugins: [ svelte(), + checker({ + typescript: true, + }), process.env.ENVIRONMENT === "storybook" || process.env.ENVIRONMENT === "test" ? null @@ -24,6 +28,12 @@ export default defineConfig(({ mode }) => { resolve: { alias: { "~": path.resolve(__dirname, "./src"), + ...(process.env.ENVIRONMENT === "test" && { + "webextension-polyfill": path.resolve( + __dirname, + "./src/tests/mock/webextension-polyfill.ts", + ), + }), }, }, test: {