CodeVetter · Repo Unpack · Testing signals
tailwindlabs/tailwindcss
Testing is unusually thorough and layered: Vitest for ~80 co-located unit/snapshot suites, `cargo test` for the Rust scanner and the vendored `ignore` crate, a bespoke Vitest-based integration harness that materializes real temp projects and installs packed tarballs, and Playwright for browser-truth assertions about computed styles. CI runs unit and integration suites as two separate workflows, each with a three-OS matrix that is trimmed to Linux-only on feature branches unless the PR body contains `[ci-all]`. The gaps are mostly in the thin adapter layers — the CLI watch/poll machinery, the webpack/Turbopack loaders, and the release scripts have no direct unit tests.
- Vitest is configured at the root with `projects: ['./packages/*']` and excludes `*.spec.*` files and `integrations/**` — the `.spec.ts` extension is reserved for Playwright so the two runners never collide.
- Roughly 80 `*.test.ts` files live beside their sources under `packages/`, dominated by `utilities.test.ts` at ~31,600 lines and `index.test.ts` at ~7,300 lines — the utility matrix is tested exhaustively by snapshot.
- `packages/tailwindcss/vitest.config.mts` registers a custom snapshot serializer at `src/test-utils/custom-serializer.ts`, which is why CSS snapshots read as formatted stylesheets rather than escaped strings.
- Rust coverage centers on `crates/oxide/tests/scanner.rs` (~4,080 lines, 80+ `#[test]` cases inside a `mod scanner` block) covering source resolution, gitignore interaction, and symlink handling; the vendored `ignore` crate carries its own upstream tests.
- The integration harness in `integrations/utils.ts` exports a custom `test(name, config, cb)` that mkdtemps a real project directory, writes a `fs` map of files, and hands the callback `exec`, `spawn`, `fs.expectFileToContain`, and `parseSourceMap` helpers.
- Integration tests run against real packed tarballs: `PUBLIC_PACKAGES` is derived by reading `dist/` and mapping `tailwindcss-*.tgz` back to `@tailwindcss/*` names, which is why `pnpm build` must precede `pnpm test:integrations`.
- There are 42 integration test files across six suites — `cli`, `oxide`, `postcss`, `turbopack`, `upgrade`, `vite`, `webpack` — with the Vite suite alone covering Astro, Nuxt, SvelteKit, SolidStart, Qwik, React Router, Preact, Vue, CSS Modules, SSR, and source maps.
- The integration harness compensates for known CI flakiness: timeouts are 120s on Windows vs 60s elsewhere, `retry` defaults to 2 under CI, and on Windows CI the temp root is derived from `GITHUB_WORKSPACE` because `tmpdir()` returns a `RUNNER~1` short path that breaks Vite builds.
- Playwright covers browser-truth behavior that unit tests cannot: `packages/tailwindcss/tests/ui.spec.ts` (~2,480 lines) asserts *computed* values such as `touch-action` after `page.hover()` and resolved `linear-gradient(... in oklab ...)` strings.
- The Playwright config sets Firefox `ui.primaryPointerCapabilities`/`ui.allPointerCapabilities` to `0x02 | 0x04` because headless Firefox otherwise reports no pointer, which would silently break every `hover:` variant assertion relying on `(hover: hover)`.
- WebKit is skipped on Windows in both Playwright configs (a hanging-worker workaround) and the CI matrix pins macOS to `macos-15` for the unit job because Playwright 1.62+ dropped WebKit on macOS 14 and hangs rather than failing.
- CI has two independent workflows: `ci.yml` (build → lint → `pnpm test` → Playwright) and `integration-tests.yml` (a 6-way `integration` matrix crossed with the OS matrix), both notifying Discord via `secrets.DISCORD_WEBHOOK_URL` on `main` failures.
- Windows and macOS runners are excluded on feature branches unless the PR body contains `[ci-all]` (or the author is `depfu[bot]`), so most PRs only get Linux coverage by default — a documented, deliberate trade-off.
- CI lint is effectively Linux-only *and* currently dead: the step is gated on `matrix.runner.os == 'ubuntu-latest'`, but the Linux matrix entry sets `os: namespace-profile-default`, so the condition never matches.
- Benchmarks are a first-class suite run via `pnpm bench` (`vitest bench`), with `*.bench.ts` files for the CSS parser, candidate parser, AST, sorting, brace expansion, and `infer-data-type`; the Rust side has its own throughput harness in `crates/oxide/src/main.rs`.