Skip to content

Testing

Run the two suites, and point them at in-development Lit when you need to. Read Development first if you have not installed the workspace yet.

Terminal window
pnpm test # unit + e2e
pnpm run test:unit # node-only unit tests
pnpm run test:e2e # spawns vite dev servers + system Chrome

test:unit is the fast loop: plain Node, no browser. test:e2e builds the plugin first, then drives a real dev server with playwright-core and the system Chrome through channel: 'chrome'. It runs one dev server and one browser per test file, sequentially, to avoid port and file contention.

  • HMR_E2E_HEADED=1 watches the browser while the tests run.
  • HMR_E2E_EXECUTABLE=/path/to/chrome uses a specific browser binary. Reach for it after npx playwright install chromium when you have no system Chrome.

By default the tests run against the published npm versions of lit, @lit/context, @lit/task, @lit-labs/signals, and @lit-labs/virtualizer.

Start from startFixture() in src/test/e2e/utils.ts. It copies the playground into a fresh directory and serves that, so a test can edit files to trigger HMR without touching the real playground or another test’s copy.

  • Fixtures live under .e2e-tmp/, inside the package, not the OS temp directory. Bare imports in a fixture resolve by walking up to the repo’s node_modules, and they would not find it from /tmp. Use tmpRoot(prefix) for any other throwaway directory a test needs. .e2e-tmp/ is gitignored.
  • HOME points at a throwaway directory while a fixture runs, because devframe keeps its global settings store under the home directory. Panel settings a test writes never reach your own. Seed them with the seedSettings option instead of writing to ~/.vite.
  • Importing a bare package a fixture has never loaded can make Vite’s dep optimizer reload the page mid-test. Load the module once and wait for the network to settle before the part of the test that matters.

The plugin’s internal virtual modules use ids that start with \0lit-plugin: (VIRTUAL_PREFIX in src/lib/transform.ts). The \0 is Rollup’s marker for “not a file”: other plugins skip these ids, and this plugin’s own transforms skip them too. The one public virtual module, virtual:lit-plugin/timeline, resolves to \0virtual:lit-plugin/timeline. When a test looks for a module in Vite’s module graph or a build chunk, match on these ids, not on a file path.

The lit monorepo is checked out as a submodule. It is a read-only reference to the real lit source, not the compiled npm output, and an opt-in way to test this plugin against in-development lit changes.

Terminal window
git submodule update --init # once
pnpm build:lit-canary # installs + builds lit inside ./lit
LIT_CANARY=1 pnpm test # resolves lit imports from ./lit

With LIT_CANARY=1, every bare lit, @lit/*, and @lit-labs/* import in the test fixtures and the unit tests is aliased into the built submodule output. The whole suite then runs against lit main.

The Lit canary workflow does the same every Monday and on demand from the Actions tab. It moves the submodule to the tip of lit’s default branch first, so a red run means something changed upstream, or in the plugin’s reading of it.