tailwindlabs/tailwindcss
Testing
The project has four test surfaces.
1. Vitest unit tests
Most testing happens here. The root vitest.config.ts defines a workspace of two projects: a node project and a jsdom project (browser-like environment for the browser build).
Common entry points:
| File | Coverage |
|---|---|
packages/tailwindcss/src/index.test.ts |
End-to-end compiler behavior (~3,000 lines) |
packages/tailwindcss/src/utilities.test.ts |
Built-in utilities (largest test file in the repo) |
packages/tailwindcss/src/variants.test.ts |
All variants |
packages/tailwindcss/src/candidate.test.ts |
parseCandidate |
packages/tailwindcss/src/css-parser.test.ts |
The CSS parser |
packages/tailwindcss/src/canonicalize-candidates.test.ts |
Class-list normalization |
packages/tailwindcss/src/source-maps/source-map.test.ts |
Source map generation |
packages/tailwindcss/src/compat/config.test.ts |
v3 config bridging |
packages/tailwindcss/src/compat/plugin-api.test.ts |
v3 plugin API |
packages/@tailwindcss-postcss/src/index.test.ts |
PostCSS plugin behavior |
packages/@tailwindcss-upgrade/src/index.test.ts |
Upgrade tool top-level |
packages/@tailwindcss-upgrade/src/codemods/**/*.test.ts |
Per-codemod tests |
Run all of them:
pnpm test # cargo test + vitest run --hideSkippedTests
pnpm tdd # vitest in watch modeRun one file:
pnpm vitest run packages/tailwindcss/src/utilities.test.ts
pnpm vitest packages/tailwindcss/src/utilities.test.ts -- -t 'background-color'Inline snapshots
The compiler's tests use expect(css).toMatchInlineSnapshot('...') heavily. To regenerate after a change:
pnpm vitest run -- --update2. Cargo tests
The Rust crates ship in-line #[cfg(test)] mod tests { ... } blocks plus dedicated test files in crates/<crate>/tests/.
cargo test # all crates in the workspace
cargo test -p tailwindcss-oxide # just the scanner
cargo test --release # opt-level 3, slower compile, faster runtimeNotable Rust test files:
crates/oxide/tests/scanner.rs— ~1,800 lines exercising auto source detection, ignore behavior, and re-scan logic.crates/oxide/src/extractor/mod.rs— large#[cfg(test)]block at the bottom that drives the extractor against fixture strings.
3. Integration tests (integrations/)
These are real builds, not mocks. Each subdirectory exercises one bundler against the freshly-packed dist tarballs from pnpm build:
integrations/
├── cli/
├── postcss/
├── vite/
├── webpack/
├── upgrade/
└── oxide/The shared harness is integrations/utils.ts (~720 lines). It:
- Spawns the right package manager (npm/yarn/pnpm/bun depending on the test).
- Installs the locally packed
*.tgzfiles. - Runs build/dev commands.
- Asserts on output CSS, file content, and process behavior.
Run them all:
pnpm build
pnpm test:integrationsRun a subset:
pnpm test:integrations -- vite
pnpm test:integrations -- --grep "watch"Integration tests are slow because each one starts a fresh package install. Reserve them for changes that cross package boundaries (e.g. a fix for @tailwindcss/postcss consuming a new compiler API).
4. Playwright UI tests (pnpm test:ui)
Two Playwright suites:
packages/tailwindcss/playwright.config.ts— runstests/ui.spec.ts(~2,000 lines) against built CSS in real browsers. Tests browser-specific resolution:color-mix,@property, custom properties under@supports.packages/@tailwindcss-browser/playwright.config.ts— drives the in-browser bundle and verifies it builds CSS from real DOM mutations.
pnpm build
pnpm test:uiBenchmarks
Files matching *.bench.ts use Vitest's bench runner. Useful for verifying performance work:
pnpm benchThe compiler ships several benches: ast.bench.ts, candidate.bench.ts, css-parser.bench.ts, intellisense.bench.ts, index.bench.ts, plus per-utility benchmarks under packages/tailwindcss/src/utils/.
CI
Tests are wired up in .github/workflows/ci.yml (unit + lint) and .github/workflows/integration-tests.yml (integrations). Adding [ci-all] to a PR description fans the CI matrix out across all platforms (otherwise it runs on Linux only).
What "good test coverage" looks like here
Patterns to follow when adding tests:
- Pin the bug. Reproduce the failing case first; commit only when it passes.
- Use snapshot tests for output CSS. They are the project's preferred way to assert on compiler output. They also catch incidental output changes.
- Use small
dedent-style fixture inputs. Most compiler tests construct a minimal CSS input string inline and assert against snapshotted output. - Test the public API. For new compiler features, add an
index.test.tscase that goes throughcompile(...). - Test extractor changes against pre-existing fixtures. Don't invent a one-off test string; the extractor tests already cover dozens of language quirks.
Local QA screenshots
These screenshots came from local QA runs and are kept here as supporting test evidence rather than overview material.


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