Open-Source Wikis

/

Solid

/

How to contribute

/

Testing

solidjs/solid

Testing

Active contributors: Ryan Carniato, Damian Tarnawski, Joe Pea

Solid has four kinds of tests:

  1. Behavioural tests with Vitest, exercising the reactive runtime in jsdom (packages/solid/test/*.spec.ts(x), packages/solid/web/test/*.spec.tsx, packages/solid/store/test/*.spec.ts).
  2. Type tests that compile against tsc --project tsconfig.test.json (packages/solid/test/*.type-tests.ts).
  3. Integration tests that spawn Node and probe every published entry point (packages/test-integration/test-imports.mjs).
  4. Benchmarks for the runtime (packages/solid/test/component.bench.ts, packages/solid/bench/).

Behavioural tests with Vitest

Configuration lives in packages/solid/vite.config.mjs:

test: {
  environment: "jsdom",
  transformMode: { web: [/\.[jt]sx?$/] },
  deps: { registerNodeLoader: true },
  threads: false,
  isolate: false,
  globals: true
}

threads: false and isolate: false keep all tests in a single worker so the reactive global state can be reset between tests cleanly. Coverage is via @vitest/coverage-v8 with v8's coverage instrumentation.

The Vite config aliases:

Alias Resolved to
solid-js packages/solid/src
solid-js/web packages/solid/web/src
solid-js/jsx-runtime packages/solid/src/jsx
rxcore packages/solid/web/src/core

This is the magic that lets tests run against the source tree without a build step.

Writing a new test

packages/solid/test/signals.spec.ts is the model. Tests use Solid's own createRoot to scope reactive state:

test('createSignal', () => {
  createRoot(() => {
    const [value, setValue] = createSignal(1);
    expect(value()).toBe(1);
    setValue(2);
    expect(value()).toBe(2);
  });
});

Always wrap test bodies in createRoot (or render for component tests) — otherwise reactive primitives created during the test will leak owners across the suite.

For DOM-rendering tests, packages/solid/web/test/suspense.spec.tsx shows the pattern: import render from solid-js/web, render into a fresh document.createElement('div'), and assert against the DOM.

Running a single suite

cd packages/solid
pnpm vitest run signals.spec.ts          # one file
pnpm vitest run -t "createSignal"        # by test name
pnpm vitest                              # watch mode (not the default in CI)

Type tests

The test-types script (packages/solid/package.json) runs tsc --project tsconfig.test.json against the *.type-tests.ts files. These are the surface-area regression tests:

File Covers
packages/solid/test/signals.type-tests.ts (1,129 lines) The full type contract of createSignal, Setter<T>, createMemo, createEffect, Signal<T>, etc.
packages/solid/test/component.type-tests.ts Component<P>, ParentComponent<P>, FlowComponent<P, C>, mergeProps, splitProps.
packages/solid/test/resource.type-tests.ts createResource, Resource<T>, ResourceFetcher, ResourceSource.

Type tests run as part of pnpm test. They do not assert at runtime — instead they rely on // @ts-expect-error annotations and shape-equality checks via helper types. If you change a public type in packages/solid/src/reactive/signal.ts, update the corresponding type tests in the same PR.

Integration / import tests

packages/test-integration/test-imports.mjs is a Node script that imports every published entry of solid-js (root, /web, /store, /web/storage, /h, /html, /universal, plus the dev variants), checks that the expected named exports exist, and exits non-zero if any are missing. This catches regressions in packages/solid/package.json's exports map and in the Rollup build.

Run it with:

pnpm --filter test-integration test

It depends on a successful pnpm build because it imports from dist/.

Benchmarks

  • packages/solid/test/component.bench.ts — Vitest bench blocks for component creation cost, mergeProps, etc. Run with pnpm vitest bench.
  • packages/solid/bench/ — older standalone benchmarks (kairo, rval-mod, etc.) that compare Solid's reactive runtime against other libraries. Run with pnpm --filter solid-js bench.

These are not part of CI. Maintainers use them locally to validate performance-sensitive changes.

Coverage

pnpm coverage

Runs vitest run --coverage per package. Output goes to packages/solid/coverage/. The .github/workflows/main-ci.yml job uploads the lcov.info to Coveralls (badge in README.md).

Common pitfalls

  • Forgetting createRoot. Tests that allocate signals/effects without a root will leak owners and break later tests because of isolate: false.
  • Asserting after a microtask. Some primitives (e.g. createEffect, resources) defer execution. Use await Promise.resolve() or, for transitions, await transition.done.
  • Touching the DOM in a non-DOM test. packages/solid/test/ runs in jsdom but does not import solid-js/web for most signal tests. Add the .tsx extension and import render only when you need a renderer.
  • Type-test drift. Changing a generic in signal.ts without updating signals.type-tests.ts leaves a hole. The CI test-types step catches most cases but a few // @ts-expect-error lines may need re-balancing.

For the wider tooling story (Rollup, Babel, Turborepo, Prettier), see Tooling.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Testing – Solid wiki | Factory