Files
wxt/docs/guide/testing.md
T
2023-10-30 09:48:52 -05:00

5.2 KiB

Testing

WXT provides several utils for writing tests.

Unit tests

If you're using auto-imports (enabled by default), Vitest is the only testing framework that supports them.

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:

  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")

Vitest Setup

Install vitest and add the WxtVitest plugin to your vitest.config.ts file.

pnpm i -D vitest
// <root>/vitest.config.ts
import { defineConfig } from 'vitest/config';
import { WxtVitest } from 'wxt/testing';

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

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);
  });
});
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);
  });
});
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, from the @webext-core/fake-browser package. fakeBrowser works with all testing frameworks/libraries. See their docs for a list of implemented APIs 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 (recommended) - "A high-level API to automate web browsers"
  • puppeteer - "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.
  • 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 to setup a consistent runtime id.

:::info You cannot test popups in their normal popup window, you have to open them in a tab. :::