Compare commits

..

4 Commits

Author SHA1 Message Date
GitHub Actions aea137a3a1 chore(release): v0.12.3 2023-12-23 04:26:47 +00:00
Aaron ad0e8e4144 fix: Correctly mock webextension-polyfill for Vitest (#294) 2023-12-22 22:21:09 -06:00
GitHub Actions 7fd5752ef1 chore(release): v0.12.2 2023-12-19 17:48:24 +00:00
Aaron 1a8b7ff635 feat: Support PNPM without hoisting dependencies (#291) 2023-12-19 11:42:20 -06:00
15 changed files with 170 additions and 506 deletions
+16
View File
@@ -1,5 +1,21 @@
# Changelog
## v0.12.3
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.12.2...v0.12.3)
### 🩹 Fixes
- Correctly mock `webextension-polyfill` for Vitest ([#294](https://github.com/wxt-dev/wxt/pull/294))
## v0.12.2
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.12.1...v0.12.2)
### 🚀 Enhancements
- Support PNPM without hoisting dependencies ([#291](https://github.com/wxt-dev/wxt/pull/291))
## v0.12.1
[compare changes](https://github.com/wxt-dev/wxt/compare/v0.12.0...v0.12.1)
+1 -3
View File
@@ -19,13 +19,11 @@
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vitest": "^0.34.6",
"webextension-polyfill": "^0.10.0"
"vitest": "^1.1.0"
},
"devDependencies": {
"@types/react": "^18.2.34",
"@types/react-dom": "^18.2.14",
"@types/webextension-polyfill": "^0.10.5",
"sass": "^1.69.5",
"wxt": "workspace:*"
}
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import background from '../background';
browser.i18n.getMessage = () => 'fake-message';
@@ -7,6 +7,10 @@ const logMock = vi.fn();
console.log = logMock;
describe('Background Entrypoint', () => {
beforeEach(() => {
fakeBrowser.reset();
});
it("should log the extenion's runtime ID", () => {
const id = 'some-id';
fakeBrowser.runtime.id = id;
@@ -15,4 +19,11 @@ describe('Background Entrypoint', () => {
expect(logMock).toBeCalledWith(id);
});
it('should set the start time in storage', async () => {
background.main();
await new Promise((res) => setTimeout(res));
expect(await storage.getItem('session:startTime')).toBeDefined();
});
});
+16 -151
View File
@@ -1,162 +1,27 @@
# Testing
WXT provides several utils for writing tests.
## Official Frameworks
## Unit tests
WXT officially supports [Vitest](https://vitest.dev/) for unit tests and either [Playwright](https://playwright.dev/) or [Puppeteer](https://pptr.dev/) for E2E tests against Chromium browsers.
If you're using auto-imports (enabled by default), [Vitest](https://vitest.dev/) is the only testing framework that supports them.
For details setting up each testing framework, see the official examples:
If you want to use a different testing library/framework (like Jest, mocha, node:test, etc), you can keep using it, but you have two options:
- [Vitest example](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-vitest#readme)
- [Playwright example](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-playwright#readme)
- [Puppeteer example](https://github.com/wxt-dev/wxt-examples/tree/main/examples/vanilla-puppeteer#readme)
1. Switch to Vitest (recommended)
2. Configure the testing library manually
- Disable auto-imports by setting `imports: false` in your `wxt.config.ts` file
- Manually add globals normally provided by WXT (like `__BROWSER__`) that you consume to the global scope before accessing them (`globalThis.__BROWSER__ = "chrome"`)
### Unofficial Frameworks
### Vitest Setup
Puppeteer and Playwright are the only E2E test runners that support Chrome Extensions. There are no other options at the time of writing.
Install vitest and add the `WxtVitest` plugin to your `vitest.config.ts` file.
There are other options for unit tests however, like [Jest](https://jestjs.io/), [Mocha](https://mochajs.org/), or [`node:test`](https://nodejs.org/api/test.html). **_WXT does not claim to support any of them_** because none of them support all of WXT's features, like TypeScript or auto-imports.
```sh
pnpm i -D vitest
```
If you want to try to use a different framework for unit tests, you will need to configure the environment manually:
```ts
// <root>/vitest.config.ts
import { defineConfig } from 'vitest/config';
import { WxtVitest } from 'wxt/testing';
- **Auto-imports**: Add `unimport` to your test environment or disable them by setting `imports: false` in your `wxt.config.ts` file
- **`browser` mock**: Mock the `webextension-polyfill` module globally with `wxt/dist/virtual/mock-browser.js`
- **[Remote Code Bundling](/guide/remote-code)**: If you use it, configure your environment to handle the `url:` module prefix
- **Global Variables**: If you consume them, manually define globals provided by WXT (like `__BROWSER__`) by adding them to the global scope before accessing them (`globalThis.__BROWSER__ = "chrome"`)
- **Import paths**: If you use the `@/` or `~/` path aliases, add them to your test environment
export default defineConfig({
plugins: [WxtVitest()],
test: {
server: {
deps: {
// Add any dependencies that import webextension-polyfill here, otherwise tests will attempt to import the real polyfill, breaking the
// TODO: Auto-detect these dependencies inside `WxtVitest` so maintaining this list manually isn't necessary
inline: [...],
},
},
},
});
```
And that's it. You're ready to start writing tests.
### Writing Tests
Here's a very basic test, written with a few different testing libraries, with a few different approaches for mocking the `browser` global.
:::code-group
```ts [Vitest]
import { describe, it, expect, vi } from 'vitest';
function logRuntimeId() {
// Vitest automatically mocks "browser" with "fakeBrowser"
console.log(browser.runtime.id);
}
describe('logRuntimeId', () => {
it("should log the extension's runtime ID", () => {
// Set a known ID on fakeBrowser for the test
const id = 'some-runtime-id';
fakeBrowser.runtime.id = id;
const logSpy = vi.spyOn(console, 'log');
logRuntimeId();
expect(logSpy).toBeCalledWith(id);
});
});
```
```ts [Jest - Manual Mock]
import { fakeBrowser } from 'wxt/testing';
import { browser } from 'wxt/browser';
function logRuntimeId() {
console.log(browser.runtime.id);
}
// Manually mock
jest.mock('wxt/browser', () => {
const { fakeBrowser } = require('wxt/testing');
return { browser: fakeBrowser };
});
describe('logRuntimeId', () => {
it("should log the extension's runtime ID", () => {
// Set a known ID on fakeBrowser for the test
const id = 'some-runtime-id';
fakeBrowser.runtime.id = id;
const logSpy = jest.spyOn(console, 'log');
logRuntimeId();
expect(logSpy).toBeCalledWith(id);
});
});
```
```ts [node:test - Parameterized]
import { describe, it, mock } from 'node:test';
import { assert } from 'node:assert';
import { fakeBrowser } from 'wxt/testing';
import { browser } from 'wxt/browser';
// Add browser as a parameter so fakeBrowser can be passed instead of browser
function logRuntimeId(browser = browser) {
console.log(browser.runtime.id);
}
describe('logRuntimeId', () => {
it("should log the extension's runtime ID", () => {
// Set a known ID on fakeBrowser for the test
const id = 'some-runtime-id';
fakeBrowser.runtime.id = id;
console.log = mock.fn();
// pass in fakeBrowser during tests
logRuntimeId(fakeBrowser);
assert.deepStrictEqual(console.log.mock.calls[0].arguments, [id]);
});
});
```
:::
:::warning
Without mocking the `browser` variable, you'll see errors like this:
```
This script should only be loaded in a browser extension.
```
:::
WXT provides an in-memory, partial implementation of `browser`, [`fakeBrowser`](/api/wxt/testing/variables/fakeBrowser), from the [`@webext-core/fake-browser`](https://webext-core.aklinker1.io/guide/fake-browser/) package. `fakeBrowser` works with all testing frameworks/libraries. See their docs for a list of [implemented APIs](https://webext-core.aklinker1.io/guide/fake-browser/implemented-apis.html) and more example tests.
## E2E Tests
WXT does not provide any utils for running E2E tests. There are two libraries you can use to run E2E tests for any chrome extension.
- [`playwright`](https://playwright.dev/docs/chrome-extensions) (recommended) - "A high-level API to automate web browsers"
- [`puppeteer`](https://pptr.dev/guides/chrome-extensions) - "A high-level API to control headless Chrome over the DevTools Protocol"
:::info
Note that both only support running tests on Chrome.
:::
Before running tests with either of these tools, you must build the extension with `wxt build` and then load the extension from the output directory in a new tab.
To test an extension's UI, like the popup or options page, you'll need to know the extension's ID to open the URL directly.
> _chrome-extension://`browser.runtime.id`/popup.html_
- Playwright provides an API to get your extension ID after it has been installed. [See their docs](https://playwright.dev/docs/chrome-extensions#testing).
- Puppeteer requires you know the ID before installing the extension, so you can hard code it into the URLs you open. Follow [Chrome's guide](https://developer.chrome.com/docs/extensions/mv3/manifest/key/) to setup a consistent runtime id.
:::info
You cannot test popups in their normal popup window, you have to open them in a tab.
:::
[Here's how Vitest is configured](https://github.com/wxt-dev/wxt/blob/main/src/testing/wxt-vitest-plugin.ts) for reference.
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "wxt",
"type": "module",
"version": "0.12.2-alpha2",
"version": "0.12.3",
"description": "Next gen framework for developing web extensions",
"engines": {
"node": ">=18",
@@ -88,7 +88,7 @@
"lint:package": "publint",
"compile": "run-s -c compile:*",
"compile:wxt": "tsc --noEmit",
"compile:virtual": "tsc --noEmit",
"compile:virtual": "tsc --noEmit -p src/virtual",
"test": "vitest",
"test:coverage": "vitest run --coverage",
"prepare": "simple-git-hooks",
@@ -158,7 +158,7 @@
"typedoc-vitepress-theme": "1.0.0-next.3",
"typescript": "^5.3.2",
"vitepress": "1.0.0-rc.31",
"vitest": "^1.0.0",
"vitest": "^1.1.0",
"vitest-mock-extended": "^1.3.1",
"vue": "^3.3.10"
},
+42 -273
View File
@@ -97,7 +97,7 @@ importers:
version: 1.9.0
vite:
specifier: ^5.0.0
version: 5.0.5(@types/node@20.10.3)
version: 5.0.5(@types/node@20.10.3)(sass@1.69.5)
web-ext-run:
specifier: ^0.1.0
version: 0.1.0
@@ -128,7 +128,7 @@ importers:
version: 2.4.9
'@vitest/coverage-v8':
specifier: ^1.0.1
version: 1.0.1(vitest@1.0.0)
version: 1.0.1(vitest@1.1.0)
execa:
specifier: ^8.0.1
version: 8.0.1
@@ -178,11 +178,11 @@ importers:
specifier: 1.0.0-rc.31
version: 1.0.0-rc.31(@types/node@20.10.3)(typescript@5.3.2)
vitest:
specifier: ^1.0.0
version: 1.0.0(@types/node@20.10.3)(happy-dom@12.10.3)
specifier: ^1.1.0
version: 1.1.0(@types/node@20.10.3)(happy-dom@12.10.3)(sass@1.69.5)
vitest-mock-extended:
specifier: ^1.3.1
version: 1.3.1(typescript@5.3.2)(vitest@1.0.0)
version: 1.3.1(typescript@5.3.2)(vitest@1.1.0)
vue:
specifier: ^3.3.10
version: 3.3.10(typescript@5.3.2)
@@ -196,11 +196,8 @@ importers:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
vitest:
specifier: ^0.34.6
version: 0.34.6(happy-dom@12.10.3)(sass@1.69.5)
webextension-polyfill:
specifier: ^0.10.0
version: 0.10.0
specifier: ^1.1.0
version: 1.1.0(@types/node@20.10.3)(happy-dom@12.10.3)(sass@1.69.5)
devDependencies:
'@types/react':
specifier: ^18.2.34
@@ -208,9 +205,6 @@ importers:
'@types/react-dom':
specifier: ^18.2.14
version: 18.2.14
'@types/webextension-polyfill':
specifier: ^0.10.5
version: 0.10.5
sass:
specifier: ^1.69.5
version: 1.69.5
@@ -1210,16 +1204,6 @@ packages:
defer-to-connect: 2.0.1
dev: false
/@types/chai-subset@1.3.3:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
dependencies:
'@types/chai': 4.3.5
dev: false
/@types/chai@4.3.5:
resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==}
dev: false
/@types/estree@1.0.4:
resolution: {integrity: sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==}
dev: false
@@ -1291,12 +1275,6 @@ packages:
dependencies:
undici-types: 5.26.5
/@types/node@20.8.10:
resolution: {integrity: sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==}
dependencies:
undici-types: 5.26.5
dev: false
/@types/normalize-path@3.0.2:
resolution: {integrity: sha512-DO++toKYPaFn0Z8hQ7Tx+3iT9t77IJo/nDiqTXilgEP+kPNIYdpS9kh3fXuc53ugqwp9pxC1PVjCpV1tQDyqMA==}
dev: true
@@ -1340,6 +1318,7 @@ packages:
/@types/webextension-polyfill@0.10.5:
resolution: {integrity: sha512-LlmbFLUB7+BDrb9nMuM0wlqtx9LZbBV2x3W98o02cD7Y8i10+sBenTlhG56vr47dzC7WIVXbURii+5jMJsyjLw==}
dev: false
/@ungap/structured-clone@1.2.0:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
@@ -1352,11 +1331,11 @@ packages:
vite: ^4.0.0 || ^5.0.0
vue: ^3.2.25
dependencies:
vite: 5.0.5(@types/node@20.10.3)
vite: 5.0.5(@types/node@20.10.3)(sass@1.69.5)
vue: 3.3.10(typescript@5.3.2)
dev: true
/@vitest/coverage-v8@1.0.1(vitest@1.0.0):
/@vitest/coverage-v8@1.0.1(vitest@1.1.0):
resolution: {integrity: sha512-Z4a7ig4VjUCT/P+LRB3IZrBRXb9xWRUM8rSBH9cKgfrU1Oe01/K2WJKtGshOnQwXZoSfQtwCGpbnHmB/qJwjcw==}
peerDependencies:
vitest: ^1.0.0
@@ -1374,86 +1353,43 @@ packages:
std-env: 3.6.0
test-exclude: 6.0.0
v8-to-istanbul: 9.2.0
vitest: 1.0.0(@types/node@20.10.3)(happy-dom@12.10.3)
vitest: 1.1.0(@types/node@20.10.3)(happy-dom@12.10.3)(sass@1.69.5)
transitivePeerDependencies:
- supports-color
dev: true
/@vitest/expect@0.34.6:
resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==}
/@vitest/expect@1.1.0:
resolution: {integrity: sha512-9IE2WWkcJo2BR9eqtY5MIo3TPmS50Pnwpm66A6neb2hvk/QSLfPXBz2qdiwUOQkwyFuuXEUj5380CbwfzW4+/w==}
dependencies:
'@vitest/spy': 0.34.6
'@vitest/utils': 0.34.6
'@vitest/spy': 1.1.0
'@vitest/utils': 1.1.0
chai: 4.3.10
dev: false
/@vitest/expect@1.0.0:
resolution: {integrity: sha512-EbqHCSzQhAY8Su/uLsMCDXkC26LyqQO54kAqJy/DubBqwpRre1iMzvDMPWx+YPfNIN3w7/ydKaJWjH6qRoz0fA==}
/@vitest/runner@1.1.0:
resolution: {integrity: sha512-zdNLJ00pm5z/uhbWF6aeIJCGMSyTyWImy3Fcp9piRGvueERFlQFbUwCpzVce79OLm2UHk9iwaMSOaU9jVHgNVw==}
dependencies:
'@vitest/spy': 1.0.0
'@vitest/utils': 1.0.0
chai: 4.3.10
dev: true
/@vitest/runner@0.34.6:
resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==}
dependencies:
'@vitest/utils': 0.34.6
p-limit: 4.0.0
pathe: 1.1.1
dev: false
/@vitest/runner@1.0.0:
resolution: {integrity: sha512-1CaYs4knCexozpGxNiT89foiIxidOdU220QpU6CKMN0qU05e3K5XNH8f4pW9KyXH37o1Zin1cLHkoLr/k7NyrQ==}
dependencies:
'@vitest/utils': 1.0.0
'@vitest/utils': 1.1.0
p-limit: 5.0.0
pathe: 1.1.1
dev: true
/@vitest/snapshot@0.34.6:
resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==}
/@vitest/snapshot@1.1.0:
resolution: {integrity: sha512-5O/wyZg09V5qmNmAlUgCBqflvn2ylgsWJRRuPrnHEfDNT6tQpQ8O1isNGgo+VxofISHqz961SG3iVvt3SPK/QQ==}
dependencies:
magic-string: 0.30.5
pathe: 1.1.1
pretty-format: 29.7.0
dev: false
/@vitest/snapshot@1.0.0:
resolution: {integrity: sha512-kAcQJGsaHMBLrY0QC6kMe7S+JgiMielX2qHqgWFxlUir5IVekJGokJcYTzoOp+MRN1Gue3Q6H5fZD4aC0XHloA==}
dependencies:
magic-string: 0.30.5
pathe: 1.1.1
pretty-format: 29.7.0
dev: true
/@vitest/spy@0.34.6:
resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==}
/@vitest/spy@1.1.0:
resolution: {integrity: sha512-sNOVSU/GE+7+P76qYo+VXdXhXffzWZcYIPQfmkiRxaNCSPiLANvQx5Mx6ZURJ/ndtEkUJEpvKLXqAYTKEY+lTg==}
dependencies:
tinyspy: 2.2.0
dev: false
/@vitest/spy@1.0.0:
resolution: {integrity: sha512-k2gZwSi7nkwcYMj1RNgb45jNUDV/opAGlsVvcmYrRXu2QljMSlyAa0Yut+n3S39XoEKp0I4ggVLABj0xVInynw==}
dependencies:
tinyspy: 2.2.0
dev: true
/@vitest/utils@0.34.6:
resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==}
/@vitest/utils@1.1.0:
resolution: {integrity: sha512-z+s510fKmYz4Y41XhNs3vcuFTFhcij2YF7F8VQfMEYAAUfqQh0Zfg7+w9xdgFGhPf3tX3TicAe+8BDITk6ampQ==}
dependencies:
diff-sequences: 29.6.3
loupe: 2.3.7
pretty-format: 29.7.0
dev: false
/@vitest/utils@1.0.0:
resolution: {integrity: sha512-r9JhgaP2bUYSnKE9w0aNblCIK8SKpDhXfJgE4TzjDNq3G40Abo5WXJBEKYAteq5p+OWedSFUg6GirNOlH7pN7Q==}
dependencies:
diff-sequences: 29.6.3
loupe: 2.3.7
pretty-format: 29.7.0
dev: true
/@vue/compiler-core@3.3.10:
resolution: {integrity: sha512-doe0hODR1+i1menPkRzJ5MNR6G+9uiZHIknK3Zn5OcIztu6GGw7u0XUzf3AgB8h/dfsZC9eouzoLo3c3+N/cVA==}
@@ -1631,15 +1567,9 @@ packages:
resolution: {integrity: sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==}
dev: false
/acorn-walk@8.2.0:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
engines: {node: '>=0.4.0'}
dev: false
/acorn-walk@8.3.0:
resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==}
engines: {node: '>=0.4.0'}
dev: true
/acorn@8.11.2:
resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==}
@@ -2565,7 +2495,6 @@ packages:
onetime: 6.0.0
signal-exit: 4.1.0
strip-final-newline: 3.0.0
dev: true
/fast-glob@3.3.1:
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
@@ -2730,7 +2659,6 @@ packages:
/get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
dev: true
/get-symbol-description@1.0.0:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
@@ -3080,7 +3008,6 @@ packages:
/human-signals@5.0.0:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
dev: true
/iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
@@ -3353,7 +3280,6 @@ packages:
/is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
@@ -3652,7 +3578,6 @@ packages:
dependencies:
mlly: 1.4.2
pkg-types: 1.0.3
dev: true
/lodash.defaults@4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
@@ -3833,7 +3758,6 @@ packages:
/mimic-fn@4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
engines: {node: '>=12'}
dev: true
/mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
@@ -4082,7 +4006,6 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
path-key: 4.0.0
dev: true
/nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
@@ -4141,7 +4064,6 @@ packages:
engines: {node: '>=12'}
dependencies:
mimic-fn: 4.0.0
dev: true
/open@8.4.2:
resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
@@ -4177,19 +4099,11 @@ packages:
engines: {node: '>=12.20'}
dev: false
/p-limit@4.0.0:
resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
yocto-queue: 1.0.0
dev: false
/p-limit@5.0.0:
resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==}
engines: {node: '>=18'}
dependencies:
yocto-queue: 1.0.0
dev: true
/p-map@7.0.0:
resolution: {integrity: sha512-EZl03dLKv3RypkrjlevZoNwQMSy4bAblWcR18zhonktnN4fUs3asFQKSe0awn982omGxamvbejqQKQYDJYHCEg==}
@@ -4251,7 +4165,6 @@ packages:
/path-key@4.0.0:
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
engines: {node: '>=12'}
dev: true
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@@ -4782,7 +4695,6 @@ packages:
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
dev: true
/simple-git-hooks@2.9.0:
resolution: {integrity: sha512-waSQ5paUQtyGC0ZxlHmcMmD9I1rRXauikBwX31bX58l5vTOhCEcBC5Bi+ZDkPXTjDnZAF8TbCqKBY+9+sVPScw==}
@@ -4889,17 +4801,12 @@ packages:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
dev: false
/std-env@3.3.3:
resolution: {integrity: sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==}
dev: false
/std-env@3.4.3:
resolution: {integrity: sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==}
dev: false
/std-env@3.6.0:
resolution: {integrity: sha512-aFZ19IgVmhdB2uX599ve2kE6BIE3YMnQ6Gp6BURhW/oIzpXGKr878TQfAQZn1+i0Flcc/UKUy1gOlcfaUBCryg==}
dev: true
/stdin-discarder@0.1.0:
resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==}
@@ -5026,7 +4933,6 @@ packages:
/strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
dev: true
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
@@ -5115,23 +5021,12 @@ packages:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: false
/tinybench@2.5.0:
resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==}
dev: false
/tinybench@2.5.1:
resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==}
dev: true
/tinypool@0.7.0:
resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==}
engines: {node: '>=14.0.0'}
dev: false
/tinypool@0.8.1:
resolution: {integrity: sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg==}
engines: {node: '>=14.0.0'}
dev: true
/tinyspy@2.2.0:
resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==}
@@ -5551,30 +5446,8 @@ packages:
vfile-message: 4.0.2
dev: true
/vite-node@0.34.6(@types/node@20.8.10)(sass@1.69.5):
resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
engines: {node: '>=v14.18.0'}
hasBin: true
dependencies:
cac: 6.7.14
debug: 4.3.4
mlly: 1.4.2
pathe: 1.1.1
picocolors: 1.0.0
vite: 5.0.5(@types/node@20.8.10)(sass@1.69.5)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- stylus
- sugarss
- supports-color
- terser
dev: false
/vite-node@1.0.0(@types/node@20.10.3):
resolution: {integrity: sha512-9pGEPYsHy+7Ok7d6FkvniCmMI58IJ4KfFSK0Xq2FHWPQoBRpJKubaNBvMcXm0+uAwS6K2Rh9qJOKijdgqrjN+Q==}
/vite-node@1.1.0(@types/node@20.10.3)(sass@1.69.5):
resolution: {integrity: sha512-jV48DDUxGLEBdHCQvxL1mEh7+naVy+nhUUUaPAZLd3FJgXuxQiewHcfeZebbJ6onDqNGkP4r3MhQ342PRlG81Q==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
dependencies:
@@ -5582,7 +5455,7 @@ packages:
debug: 4.3.4
pathe: 1.1.1
picocolors: 1.0.0
vite: 5.0.5(@types/node@20.10.3)
vite: 5.0.5(@types/node@20.10.3)(sass@1.69.5)
transitivePeerDependencies:
- '@types/node'
- less
@@ -5592,9 +5465,8 @@ packages:
- sugarss
- supports-color
- terser
dev: true
/vite@5.0.5(@types/node@20.10.3):
/vite@5.0.5(@types/node@20.10.3)(sass@1.69.5):
resolution: {integrity: sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@@ -5626,45 +5498,9 @@ packages:
esbuild: 0.19.8
postcss: 8.4.32
rollup: 4.6.1
optionalDependencies:
fsevents: 2.3.3
/vite@5.0.5(@types/node@20.8.10)(sass@1.69.5):
resolution: {integrity: sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
dependencies:
'@types/node': 20.8.10
esbuild: 0.19.8
postcss: 8.4.32
rollup: 4.6.1
sass: 1.69.5
optionalDependencies:
fsevents: 2.3.3
dev: false
/vitepress@1.0.0-rc.31(@types/node@20.10.3)(typescript@5.3.2):
resolution: {integrity: sha512-ikH9pIjOOAbyoYAGBVfTz8TzuXp+UoWaIRMU4bw/oiTg8R65SbAaGKY84xx6TuL+f4VqUJ8lhzW82YyxSLvstA==}
@@ -5691,7 +5527,7 @@ packages:
mrmime: 1.0.1
shikiji: 0.7.6
shikiji-transformers: 0.7.6
vite: 5.0.5(@types/node@20.10.3)
vite: 5.0.5(@types/node@20.10.3)(sass@1.69.5)
vue: 3.3.10(typescript@5.3.2)
transitivePeerDependencies:
- '@algolia/client-search'
@@ -5721,7 +5557,7 @@ packages:
- universal-cookie
dev: true
/vitest-mock-extended@1.3.1(typescript@5.3.2)(vitest@1.0.0):
/vitest-mock-extended@1.3.1(typescript@5.3.2)(vitest@1.1.0):
resolution: {integrity: sha512-OpghYjh4BDuQ/Mzs3lFMQ1QRk9D8/2O9T47MLUA5eLn7K4RWIy+MfIivYOWEyxjTENjsBnzgMihDjyNalN/K0Q==}
peerDependencies:
typescript: 3.x || 4.x || 5.x
@@ -5729,84 +5565,18 @@ packages:
dependencies:
ts-essentials: 9.3.2(typescript@5.3.2)
typescript: 5.3.2
vitest: 1.0.0(@types/node@20.10.3)(happy-dom@12.10.3)
vitest: 1.1.0(@types/node@20.10.3)(happy-dom@12.10.3)(sass@1.69.5)
dev: true
/vitest@0.34.6(happy-dom@12.10.3)(sass@1.69.5):
resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==}
engines: {node: '>=v14.18.0'}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@vitest/browser': '*'
'@vitest/ui': '*'
happy-dom: '*'
jsdom: '*'
playwright: '*'
safaridriver: '*'
webdriverio: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@vitest/browser':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
playwright:
optional: true
safaridriver:
optional: true
webdriverio:
optional: true
dependencies:
'@types/chai': 4.3.5
'@types/chai-subset': 1.3.3
'@types/node': 20.8.10
'@vitest/expect': 0.34.6
'@vitest/runner': 0.34.6
'@vitest/snapshot': 0.34.6
'@vitest/spy': 0.34.6
'@vitest/utils': 0.34.6
acorn: 8.11.2
acorn-walk: 8.2.0
cac: 6.7.14
chai: 4.3.10
debug: 4.3.4
happy-dom: 12.10.3
local-pkg: 0.4.3
magic-string: 0.30.5
pathe: 1.1.1
picocolors: 1.0.0
std-env: 3.3.3
strip-literal: 1.3.0
tinybench: 2.5.0
tinypool: 0.7.0
vite: 5.0.5(@types/node@20.8.10)(sass@1.69.5)
vite-node: 0.34.6(@types/node@20.8.10)(sass@1.69.5)
why-is-node-running: 2.2.2
transitivePeerDependencies:
- less
- lightningcss
- sass
- stylus
- sugarss
- supports-color
- terser
dev: false
/vitest@1.0.0(@types/node@20.10.3)(happy-dom@12.10.3):
resolution: {integrity: sha512-jpablj5+ifiFHV3QGOxPews3uxBuu6rQUzTaQYtEd6ocBpdQBil6AvmmGRQ3Rn0WPgyzb+Ni+JekfMyng+qYng==}
/vitest@1.1.0(@types/node@20.10.3)(happy-dom@12.10.3)(sass@1.69.5):
resolution: {integrity: sha512-oDFiCrw7dd3Jf06HoMtSRARivvyjHJaTxikFxuqJjO76U436PqlVw1uLn7a8OSPrhSfMGVaRakKpA2lePdw79A==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0
'@vitest/browser': '*'
'@vitest/ui': '*'
'@vitest/browser': ^1.0.0
'@vitest/ui': ^1.0.0
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
@@ -5824,11 +5594,11 @@ packages:
optional: true
dependencies:
'@types/node': 20.10.3
'@vitest/expect': 1.0.0
'@vitest/runner': 1.0.0
'@vitest/snapshot': 1.0.0
'@vitest/spy': 1.0.0
'@vitest/utils': 1.0.0
'@vitest/expect': 1.1.0
'@vitest/runner': 1.1.0
'@vitest/snapshot': 1.1.0
'@vitest/spy': 1.1.0
'@vitest/utils': 1.1.0
acorn-walk: 8.3.0
cac: 6.7.14
chai: 4.3.10
@@ -5843,8 +5613,8 @@ packages:
strip-literal: 1.3.0
tinybench: 2.5.1
tinypool: 0.8.1
vite: 5.0.5(@types/node@20.10.3)
vite-node: 1.0.0(@types/node@20.10.3)
vite: 5.0.5(@types/node@20.10.3)(sass@1.69.5)
vite-node: 1.1.0(@types/node@20.10.3)(sass@1.69.5)
why-is-node-running: 2.2.2
transitivePeerDependencies:
- less
@@ -5854,7 +5624,6 @@ packages:
- sugarss
- supports-color
- terser
dev: true
/vscode-oniguruma@1.7.0:
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
+1 -2
View File
@@ -9,7 +9,6 @@ export * from './noopBackground';
export * from './cssEntrypoints';
export * from './bundleAnalysis';
export * from './globals';
export * from './webextensionPolyfillAlias';
export * from './webextensionPolyfillInlineDeps';
export * from './webextensionPolyfillMock';
export * from './excludeBrowserPolyfill';
export * from './entrypointGroupGlobals';
@@ -1,28 +0,0 @@
import path from 'node:path';
import type * as vite from 'vite';
import { InternalConfig } from '~/types';
/**
* Creates an alias to redirect "webextension-polyfill" imports to WXT's `fakeBrowser`.
*
* This should only be used during tests.
*/
export function webextensionPolyfillAlias(
config: Omit<InternalConfig, 'builder'>,
): vite.PluginOption {
return {
name: 'wxt:webextension-polyfill-test-alias',
config() {
return {
resolve: {
alias: {
'webextension-polyfill': path.resolve(
config.root,
'node_modules/wxt/dist/virtual/mock-browser',
),
},
},
};
},
};
}
@@ -1,24 +0,0 @@
import type * as vite from 'vite';
/**
* Add all deps that import `webextension-polyfill` to `test.server.deps.inline`.
*
* TODO: Auto-detect non-wxt dependencies via `npm list`.
*/
export function webextensionPolyfillInlineDeps(): vite.PluginOption {
return {
name: 'wxt:testing-inline-deps',
config() {
const wxtModules = ['wxt/browser'];
return {
test: {
server: {
deps: {
inline: [...wxtModules],
},
},
},
};
},
};
}
@@ -0,0 +1,41 @@
import path from 'node:path';
import type * as vite from 'vite';
import { InternalConfig } from '~/types';
/**
* Mock `webextension-polyfill` by inlining all dependencies that import it and adding a custom
* alias so that Vite resolves to a mocked version of the module.
*
* There are two ways to mark a module as inline:
* 1. Use partial file paths ("wxt/dist/browser.js") in the `test.server.deps.inline` option.
* 2. Use module names ("wxt" or "@webext-core/messaging") in the `ssr.noExternalize` option.
*
* This plugin uses the second approach since it's a little more intuative to understand.
*
* TODO: Detect non-wxt dependencies (like `@webext-core/*`) that import `webextension-polyfill` via
* `npm list` and inline them automatically.
*/
export function webextensionPolyfillMock(
config: Omit<InternalConfig, 'builder'>,
): vite.PluginOption {
return {
name: 'wxt:testing-inline-deps',
config() {
return {
resolve: {
alias: {
// Alias to use a mocked version of the polyfill
'webextension-polyfill': path.resolve(
config.root,
'node_modules/wxt/dist/virtual/mock-browser',
),
},
},
ssr: {
// Inline all WXT modules
noExternal: ['wxt'],
},
};
},
};
}
+2 -4
View File
@@ -4,8 +4,7 @@ import {
download,
tsconfigPaths,
globals,
webextensionPolyfillAlias,
webextensionPolyfillInlineDeps,
webextensionPolyfillMock,
} from '../core/builders/vite/plugins';
import { getInternalConfig } from '~/core/utils/building';
import { InlineConfig } from '../types';
@@ -27,8 +26,7 @@ import { InlineConfig } from '../types';
*/
export function WxtVitest(inlineConfig?: InlineConfig): vite.PluginOption {
return getInternalConfig(inlineConfig ?? {}, 'serve').then((config) => [
webextensionPolyfillAlias(config),
webextensionPolyfillInlineDeps(),
webextensionPolyfillMock(config),
unimport(config),
globals(config),
download(config),
+3 -5
View File
@@ -1,9 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["vite/client", "../types/globals.d.ts"],
"paths": {
"wxt/*": ["../*"]
}
}
"types": ["vite/client", "../types/globals.d.ts"]
},
"include": ["./*"]
}
+10 -8
View File
@@ -1,8 +1,14 @@
import { browser, Manifest } from 'wxt/browser';
import { browser } from 'wxt/browser';
import { logger } from '../../sandbox/utils/logger';
import { MatchPattern } from 'wxt/sandbox';
export function reloadContentScript(contentScript: Manifest.ContentScript) {
interface ContentScript {
matches: string[];
js?: string[];
css?: string[];
}
export function reloadContentScript(contentScript: ContentScript) {
const manifest = browser.runtime.getManifest();
if (manifest.manifest_version == 2) {
void reloadContentScriptMv2(contentScript);
@@ -11,9 +17,7 @@ export function reloadContentScript(contentScript: Manifest.ContentScript) {
}
}
export async function reloadContentScriptMv3(
contentScript: Manifest.ContentScript,
) {
export async function reloadContentScriptMv3(contentScript: ContentScript) {
const id = `wxt:${contentScript.js![0]}`;
logger.log('Reloading content script:', contentScript);
const registered = await browser.scripting.getRegisteredContentScripts();
@@ -41,8 +45,6 @@ export async function reloadContentScriptMv3(
await Promise.all(matchingTabs.map((tab) => browser.tabs.reload(tab.id)));
}
export async function reloadContentScriptMv2(
contentScript: Manifest.ContentScript,
) {
export async function reloadContentScriptMv2(contentScript: ContentScript) {
throw Error('TODO: reloadContentScriptMv2');
}
+22 -4
View File
@@ -1,21 +1,39 @@
// Types required to make the virtual modules happy.
declare module 'virtual:user-background' {
const definition: import('wxt/types').BackgroundDefinition;
const definition: { main: () => void };
export default definition;
}
declare module 'virtual:user-content-script-isolated-world' {
const definition: import('wxt/types').ContentScriptIsolatedWorldDefinition;
const definition: {
main: (
ctx: import('wxt/client').ContentScriptContext,
) => void | Promise<void>;
};
export default definition;
}
declare module 'virtual:user-content-script-main-world' {
const definition: import('wxt/types').ContentScriptMainWorldDefinition;
const definition: { main: () => void | Promise<void> };
export default definition;
}
declare module 'virtual:user-unlisted-script' {
const definition: import('wxt/types').UnlistedScriptDefinition;
const definition: { main: () => void | Promise<void> };
export default definition;
}
declare module 'wxt/browser' {
export const browser: import('webextension-polyfill').Browser;
}
declare module 'wxt/client' {
export class ContentScriptContext {
constructor(name: string, options: any);
}
}
declare module 'wxt/testing' {
export const fakeBrowser: import('webextension-polyfill').Browser;
}
+1
View File
@@ -20,6 +20,7 @@ const resolve = {
alias: {
'~': path.resolve('src'),
'webextension-polyfill': path.resolve('src/virtual/mock-browser'),
'wxt/testing': path.resolve('src/testing'),
},
};