Skip to content

Testing Architecture

Logseq Copilot is tested at three levels. Each level covers what the one below cannot.

Unit tests

Vitest with happy-dom and the WXT test plugin. Fast, no browser, no Logseq. They run on every commit.

Integration tests

The extension’s Logseq client and service code against a real Logseq desktop app, for file graphs and DB graphs.

End-to-end tests

The built extension in Playwright’s Chromium and Firefox, against a real Logseq.

Command What it runs
pnpm test The unit tests (vitest run)
pnpm test:coverage The unit tests with V8 coverage
pnpm typecheck tsc --noEmit
pnpm test:integration The integration tests, against a real Logseq
pnpm test:e2e Builds both browsers, then runs the E2E tests in Chromium and Firefox
pnpm test:e2e:chromium, pnpm test:e2e:firefox Build and run the E2E tests of one browser
pnpm test:e2e:run Run the E2E tests without building first

The Git pre-commit hook (husky) runs pnpm test, so a commit with a failing unit test is rejected.

Unit tests sit next to the code they cover, as src/**/*.test.ts and src/**/*.test.tsx. They are configured in vitest.config.ts:

  • Vitest is the test runner.
  • happy-dom is the DOM, set as the test environment.
  • WxtVitest(), from wxt/testing, is a Vite plugin that sets up what WXT code needs: the auto-imports and an in-memory fakeBrowser in place of the real browser APIs, such as storage, tabs and messaging.
  • React Testing Library (@testing-library/react) renders and drives the React components, in the options pages, the side panel and the content script UI.
  • Coverage uses V8 and covers src/**/*.{ts,tsx}, except the test files and the generated UI primitives in src/components/ui. It writes a JSON summary, a text report and lcov.

A typical test runs real code and fakes only the edge. For example src/entrypoints/background/background.test.ts runs the real background entrypoint against fakeBrowser and talks to it with the real @webext-core/messaging client, so message names and payloads are checked at both ends. Only the Logseq service is replaced.

The integration tests (tests/integration) run the extension’s Logseq client and service code against a real Logseq desktop app. They use their own Vitest config, vitest.integration.config.ts, which includes only tests/integration/**/*.test.ts and starts Logseq in a global setup. The unit test run skips them.

The same tests run for both graph types:

Variant Logseq Graph
file 0.10.x The fixture graph in tests/integration/fixtures/file-graph, opened from disk
db 2.x The default “Demo” DB graph, seeded through the API

The global setup starts Logseq through a launcher shared with the E2E tests (tests/support/logseq-app.ts). It drives the Electron app with Playwright, in a throwaway home and user data directory, with the HTTP API server switched on and a known token. Your own Logseq is untouched, and can run next to it as long as the API port differs.

The tests check the HTTP API itself (a wrong token is rejected, the graph type is reported correctly) and the extension services on top of it: the matching service is picked for the graph type, search and URL search find the seeded blocks, the clip path appends a block to a page, and the task status of a block can be changed. One Logseq is shared, so the test files run one after another.

Set these variables to run them:

Terminal window
BIN=$(scripts/download-logseq.sh db 2.0.2 .logseq-bin | tail -n 1)
LOGSEQ_VARIANT=db LOGSEQ_BIN=$BIN pnpm test:integration
BIN=$(scripts/download-logseq.sh file 0.10.15 .logseq-bin | tail -n 1)
LOGSEQ_VARIANT=file LOGSEQ_BIN=$BIN pnpm test:integration

On Linux, run them under xvfb-run -a, because Logseq needs a display. On macOS, give Logseq a free LOGSEQ_API_PORT, because the launcher refuses a port that is taken. Set LOGSEQ_DEBUG=1 to see the logs of Logseq. See tests/integration/README.md for the details.

The E2E tests (tests/e2e) use Playwright to load the built extension in a real browser, with a real Logseq behind it. The config is tests/e2e/playwright.config.ts. It defines two projects, chromium and firefox, and both run the same specs. The tests run one at a time and share a single Logseq.

The specs cover the user flows: clipping, the floating button, highlights and the comment popup, the connection and recall rule pages in the options, the browser sidebar and which sidebar the toolbar button opens, the search engine panel, and changing a task status from the results.

pnpm test:e2e makes two builds for each browser:

  • the packaged build (wxt build), where the in-page UI sits in closed shadow roots, as shipped. Only closed-shadow.spec.ts uses it, to check that every in-page UI is mounted in a closed shadow root.
  • the E2E build (WXT_E2E=true), which has open shadow roots so that Playwright locators can see inside the in-page UI. It goes to its own -e2e output folders so that it cannot be published by mistake.
  • Chromium: each test gets a fresh profile from a persistent context with --load-extension. Playwright’s full Chromium runs extensions in headless mode.
  • Firefox: Playwright’s Firefox cannot load an extension, so each test starts Firefox with the remote debugging server on and installs the build as a temporary add-on over the remote debugging protocol, as web-ext run does. The same specs then run in both browsers, with a small abstraction for the extension pages.

Websites are fixtures: the tests route a minimal Google results page and a few articles, and abort every other request, so nothing reaches the internet.

A failing test keeps a screenshot of every open page and a Playwright trace in test-results/e2e.

See tests/e2e/README.md for the details of both browsers and how to run the tests locally.

  • Build runs pnpm typecheck, pnpm test:coverage and pnpm run build.
  • Integration runs two jobs. logseq runs the integration tests for Logseq 0.10.15 (file graph) and 2.0.2 (DB graph). e2e runs the E2E tests for each browser and each graph type, so four combinations.
  • Website Deploy builds this website for every change under docs/, and publishes it from main and for published releases.