From a8aa1dfc970896a27e68ddaf444a5fea182598a5 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 17 Aug 2026 11:03:11 +0200 Subject: [PATCH] chore: update agents file (#10952) --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++ AGENTS.md | 118 ++++++++++++++++++++++++------- docs/.vitepress/config.ts | 1 + docs/AGENTS.md | 26 +++++++ 4 files changed, 125 insertions(+), 24 deletions(-) create mode 100644 docs/AGENTS.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 72ba304db..7fbddb9d6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,9 @@ ### Description + + Resolves #issue-number diff --git a/AGENTS.md b/AGENTS.md index 168e1411a..b2c054c0b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,15 +2,23 @@ This document provides comprehensive information for AI agents working on the Vitest codebase. +## If you are an AI agent + +Read and follow https://raw.githubusercontent.com/danielroe/empathy/main/SKILL.md +before posting anything here. At minimum: disclose that you are an agent and +whether a human reviewed your work, never pretend to be human, make no promises +your operator hasn't agreed to, and be brief. + +Read CONTRIBUTING.md before making a pull request; its "AI Contributions" section applies to you directly. + ## Project Overview Vitest is a next-generation testing framework powered by Vite. This is a monorepo using pnpm workspaces with the following key characteristics: - **Language**: TypeScript/JavaScript (ESM-first) - **Package Manager**: pnpm (required) -- **Node Version**: ^20.0.0 || ^22.0.0 || >=24.0.0 - **Build System**: Vite + Rollup -- **Monorepo Structure**: 15+ packages in `packages/` directory +- **Monorepo Structure**: the packages are in `packages/` directory ## Setup and Development @@ -52,35 +60,54 @@ If you need to typecheck tests, run `pnpm typecheck` from the root of the worksp ### Rebuilding Package Changes -Tests can execute built output from `packages/*/dist`. After changing package source, rebuild the changed package and every consumer that bundles it before verifying the change; otherwise tests may execute stale code. For example, rebuild both packages when testing an `@vitest/utils` change through Vitest e2e tests: +Tests execute built output: test suites resolve `vitest` through workspace symlinks whose package exports point at `dist/`, while `pnpm typecheck` resolves TypeScript source. A passing typecheck never proves `dist` is fresh; rebuild before re-running tests. -```bash -pnpm --filter @vitest/utils build -pnpm --filter vitest build -``` +- `vitest` and `@vitest/browser` inline the other `@vitest/*` workspace packages from TypeScript source (the `__vitest_source__` export condition). After changing `@vitest/utils`, `@vitest/expect`, `@vitest/snapshot`, `@vitest/spy`, or `@vitest/pretty-format`, running `pnpm --filter vitest build` alone is enough for tests that go through the vitest bundle. +- Rebuild the changed sub-package itself only when tests import it directly (for example, `test/unit` imports `@vitest/utils/*` from its dist). +- `@vitest/mocker` is the exception: it is a runtime dependency of `vitest` and is never inlined. Rebuilding `vitest` will NOT pick up mocker changes; run `pnpm --filter @vitest/mocker build`. +- Worker-side code in `packages/vitest/src/runtime/` is loaded from built `dist/workers/*.js`, so runtime changes also require rebuilding `vitest`. +- `pnpm dev` (watch mode) rebuilds JS only; the `.d.ts` bundling configs are skipped in watch mode. After changing public types, run a full build before checking anything against `dist/*.d.ts`. ### Testing Utilities - **`runInlineTests`** from `test/test-utils/index.ts` - You must use this for complex file system setups (>1 file) - **`runVitest`** from `test/test-utils/index.ts` - You can use this to run Vitest programmatically - **No mocking policy** - You must never mock anything in tests +Behavior you must know: + +- `runVitest(config)` treats its first argument as the on-disk config, so a fixture's own config file takes priority over it. Pass overriding or CLI-only options via `$cliOptions`, or `config: false` to skip config discovery. Unless overridden, it forces `watch: false`, `maxWorkers: 1`, `reporters: ['verbose']` (pass `reporters: 'none'` to restore Vitest's real default), `cache: false`, and `NO_COLOR`. +- `runVitest`/`runInlineTests` never throw and close the started Vitest automatically. Assert with `expect(stderr).toBe('')` plus `expect(testTree()).toMatchInlineSnapshot(...)`, or `errorTree()` for failures; output is ANSI-stripped and paths are normalized to `/`. Check the returned `thrown` and `stderr` for startup errors. +- `runInlineTests` writes files to a `vitest-test-` directory under cwd, auto-adds an empty `vitest.config.js` when the structure has no `.config.` file, and deletes the directory when the test finishes (set `VITEST_FS_CLEANUP=false` to keep it for debugging). Config objects are serialized with `JSON.stringify`, so functions and regexps inside them are silently dropped; write such configs as whole-file strings instead. +- `runVitestCli` spawns the real CLI binary (it also runs `dist`), always appends `--maxWorkers=1`, and kills the subprocess when the test finishes. Interact via `vitest.waitForStdout()` and `vitest.write()`; `write()` clears the captured output. + +### Writing Reliable Tests + +- Never mutate committed fixture files from a test; e2e tests run in parallel. Tests that only need an editable directory must use `runInlineTests`. Tests that genuinely need git-tracked files (for example `--changed`) must be added to the `serialTests` list in `test/e2e/vitest.config.ts`. +- In watch-mode tests, mutate files only with `createFile`/`editFile` from `test/test-utils`: they restore content and mtime after the test, so the next test's watcher sees no phantom change. Call them inside a test, not in hooks (cleanup registers via `onTestFinished`). Always pass a small explicit `root`; `runVitest({ watch: true, root })` waits for the watcher to be ready before resolving. +- ESLint's test rules are disabled in this repo, so a stray `.only` passes lint. Check for and remove it yourself. +- CI runs the unit, e2e, coverage, and browser suites on Windows, plus an e2e leg on macOS. Vitest reports paths with forward slashes, so normalize `\` to `/` before comparing against `import.meta.filename`, `process.execArgv`, or other raw OS paths. Never use unix-only commands like `rm -rf` or `cp -r` in package.json scripts; use a node script or rimraf. + ## Project Structure ### Core Packages (`packages/`) -- `vitest` - Main testing framework +- `vitest` - Main testing framework, including the test runner core (all imported packages, except `@vitest/mocker`, from this repository are inlined into its bundle, they are not imported at runtime) - `browser` - Browser testing support +- `browser-playwright` / `browser-preview` - Browser mode providers - `ui` - Web UI for test results -- `runner` - Test runner core - `expect` - Assertion library - `spy` - Mocking and spying utilities - `snapshot` - Snapshot testing - `coverage-v8` / `coverage-istanbul` - Code coverage - `utils` - Shared utilities - `mocker` - Module mocking +- `pretty-format` - Value serialization +- `web-worker` - Web Worker simulation for Node.js ### Test Organization (`test/`) - `test/unit` - Core functionality tests +- `test/e2e` - End-to-end tests run through `runVitest`/`runInlineTests` - `test/browser` - Browser-specific tests +- `test/node-runner` - Tests that must have no access to Vitest APIs in the test process (run with `node --test`) - Various test suites organized by feature ### Important Directories @@ -95,17 +122,39 @@ pnpm --filter vitest build ### Formatting and Linting - **Always run** `pnpm lint:fix` after making changes - Fix non-auto-fixable errors manually +- Run lint as `CI=true pnpm lint` from a terminal inside an editor or agent harness: the config disables some rules when it detects an editor environment, and those rules still fail in CI + +Rules that `lint:fix` cannot fix: + +- Never `import ... from 'path'`; it is an ESLint error everywhere. Prefer `pathe` (the dominant convention; it normalizes paths to posix), though `node:path` is allowed in Node-only code. +- Source in `packages/*/src` must not import from `vitest` or `vitest/node`, even type-only. Exception: packages that declare vitest as a peer dependency (`coverage-*`, `ui`, `browser`, `browser-*`, `web-worker`). +- `console.log` in package source is an ESLint error; only `console.warn` and `console.error` are allowed. Remove debug logging, and give intentional console output an explicit eslint-disable comment. +- Use `globalThis`, never `global` or `self` (allowed only in `docs/`, `packages/web-worker/`, and `test/unit/`). +- No top-level `await` in `packages/*/src` (allowed in `test/`, `scripts/`, and config files); no `const enum`; no `export =`. +- In `packages/browser`, do not import from `ivya` outside the files that already do; ESLint enforces this so ivya stays in a single rollup chunk. Reuse the existing entry points. ### TypeScript - Strict TypeScript configuration - Use `pnpm typecheck` to verify types - Configuration files: `tsconfig.base.json`, `tsconfig.build.json`, `tsconfig.check.json` +- Root `pnpm typecheck` excludes `test/e2e`, `test/browser`, `test/typescript`, `docs`, and `examples` (see `tsconfig.check.json`); type errors there will not surface from the root command +- Root typecheck does not cover the UI client Vue code; when changing `packages/ui/client`, also run `pnpm -C packages/ui typecheck:client` ### Code Quality - ESM-first approach - Follow existing patterns in the codebase - Use utilities from `@vitest/utils/*` when available. Never import from `@vitest/utils` main entry point directly. -- Do not add comments explaining what the line does unless prompted to. +- When describing the changes in commit message or in PR/issue description be very brief and to the point, the code should speak for itself. +- Runtime code must not use APIs newer than the minimum Node version in `engines`. CI's main matrix runs newer Node versions with a single minimum-version e2e leg, so a breakage there may surface in only one CI job. + +### Comments Policy + +- Avoid writing comments for every change - if the code is expressive enough, it doesn't need a comment. +- In general, only public methods MUST have comments. Exported internal functions, properties or constants SHOULD not have comments. The name SHOULD be expressive enough to not need a comment. +- You MIGHT leave a comment if the line or a block of code deals with an edge case that is not ovbious from the context. In general, the naming SHOULD provide enough information. If you spread the logic between different files or functions and NEED to add a comment, reconsider the change - perhaps, there is a simpler solution. +- When leaving a comment, be BRIEF and do not overexplain. If you wrote a big comment with edge cases and examples, rethink the code - there MIGHT be a simpler change that does not require a wall of text. +- You MUST NOT use overly specific jargon in comments, keep it simple. + ## Common Workflows @@ -121,10 +170,22 @@ pnpm --filter vitest build - Check `scripts/` directory for specialized development tools ### Documentation -- Main docs in `docs/` directory -- Built with `pnpm docs:build` -- Local dev server: `pnpm docs` -- When adding cli options, run `pnpm -C docs run cli-table` to update the cli-generated.md file +- Docs live in `docs/` (VitePress); read `docs/AGENTS.md` before working on them +- After ANY change to CLI options or their descriptions in `packages/vitest/src/node/cli/cli-config.ts`, run `pnpm -C docs run cli-table` and commit the regenerated `docs/guide/cli-generated.md`; never edit that file by hand + +## Generated Files and CI Checks + +CI builds everything and then runs `git diff --exit-code`, so stale generated files fail CI. Commit regenerated files instead of reverting them, and never edit them by hand: + +- `packages/vitest/LICENSE.md` is rewritten by `pnpm --filter vitest build` when bundled dependencies change +- `docs/guide/cli-generated.md` is generated from `packages/vitest/src/node/cli/cli-config.ts` (it carries no banner saying so) +- `pnpm-workspace.yaml` may change on `pnpm install` (`cleanupUnusedCatalogs`, `minimumReleaseAgeExclude`) +- `docs/.vitepress/contributor-names.json` is generated by `pnpm docs:contributors` + +Other blocking CI jobs: + +- Knip (`pnpm knip`) fails on unused files, exports, and dependencies. Delete dead code instead of leaving unused exports; exceptions live in `knip.jsonc`. +- Edits to `.github/workflows/` are gated by actionlint and zizmor (pedantic persona). Pin `uses:` actions to full commit SHAs and suppress zizmor false positives inline with `# zizmor: ignore[rule]` plus a justification comment - DO NOT add a comment automatically, you MUST run zizmor first when making changes to workflow files. ## Dependencies and Tools @@ -135,19 +196,20 @@ pnpm --filter vitest build - **TypeScript** - Type checking - **Playwright** - Browser testing - **Chai/Expect** - Assertions -- **Tinypool** - Worker threading - **Tinybench** - Benchmarking -### Development Tools -- **tsx** - TypeScript execution -- **ni/nr** - Package manager abstraction -- **bumpp** - Version bumping -- **changelogithub** - Changelog generation +### Adding and Updating Dependencies +- New runtime deps for `packages/*` usually go into `devDependencies`: Rollup marks only `dependencies` as external and bundles everything else. Use `dependencies` only for `@types/*` packages, deps that cannot be bundled (binaries), or deps whose own types appear in Vitest's public types (see "Notes on Dependencies" in CONTRIBUTING.md). +- Add deps with `pnpm add ` inside the target package: `catalogMode: prefer` writes `catalog:` into package.json and adds the version to the default catalog in `pnpm-workspace.yaml` automatically. To bump a shared dep, edit its catalog entry, never per-package ranges. +- The `overrides` in `pnpm-workspace.yaml` force one version of `vite`, `rollup`, `@types/node`, `acorn`, and `mlly` across the workspace; editing a range in an individual package.json changes what gets published, not what installs locally. +- The workspace develops against the latest supported Vite major, but `vitest` supports the full peer range and CI runs a dedicated job against the previous major (`pnpm override-vite7` reproduces it locally). Do not rely on newest-Vite-only APIs without a fallback. +- Deps listed under `patchedDependencies` (`acorn`, `cac`, `@sinonjs/fake-timers`, `rrweb-snapshot`, istanbul-lib-*) are version-locked. Bumping one requires regenerating the patch with `pnpm patch` and updating the version-keyed entry in `pnpm-workspace.yaml`. +- Dependency build scripts run only for packages listed under `allowBuilds` in `pnpm-workspace.yaml`; a new dep with a postinstall step installs unbuilt unless added there. +- pnpm enforces a 24h `minimumReleaseAge`: installing a version published less than a day ago either resolves to an older version or appends the pick to `minimumReleaseAgeExclude` in `pnpm-workspace.yaml`. Both outcomes are expected; commit the yaml change instead of reverting it. ## Browser Testing -- Two modes: Playwright and WebDriverIO -- Separate test commands for each -- Component testing supported (Vue, React, Svelte, Lit, Marko) +- Providers: Playwright (`@vitest/browser-playwright`) and preview (`@vitest/browser-preview`); the WebDriverIO provider is maintained outside this monorepo +- Component testing supported (Vue, React, Svelte via official `vitest-browser-*` packages, other frameworks via Testing Library) ## Performance Considerations - This is a performance-critical testing framework @@ -168,6 +230,10 @@ pnpm --filter vitest build - Review CONTRIBUTING.md for detailed guidelines - Follow patterns in existing code +## Commit Messages and PR Titles + +PRs are squash-merged, so the PR title becomes the commit message. Nothing in CI enforces the format; follow `.github/commit-convention.md` yourself: `(): ` with type one of `feat|fix|docs|dx|refactor|perf|test|workflow|build|ci|chore|types|wip|release|deps`, subject at most 50 characters, lowercase, imperative, no trailing dot. + ## PR Descriptions When creating a pull request, you MUST include the following HTML comment at the bottom of the PR description: @@ -176,4 +242,8 @@ When creating a pull request, you MUST include the following HTML comment at the ``` -This allows maintainers to identify AI-assisted PRs for triage. PRs containing this marker will be automatically labeled `maybe automated` and will be closed in 3 days unless a real person confirms ownership. +This allows maintainers to identify AI-assisted PRs for triage. If the description doesn't have this comment, it will be closed automatically. + +## PR Limitations + +This repository has a limit of 1 PR if you don't have write access. DO NOT try to bypass it by creating draft PRs. If you cannot create a pull request, let a human know that you will not breach this repository's policy because it will ban the PR author in Vitest organisation. diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index dcb9f30b2..47e7d9f67 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -35,6 +35,7 @@ export default ({ mode }: { mode: string }) => { srcExclude: [ '**/guide/examples/*', '**/guide/cli-generated.md', + 'AGENTS.md', ], locales: { root: { diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 000000000..fc4d83109 --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,26 @@ +# Vitest Docs Guide + +Guidance for working on the VitePress site in `docs/`. The root `AGENTS.md` applies here too. + +## Building + +- Local dev server: `pnpm docs` (from the repo root) +- Build with `pnpm docs:build` from the repo root; it sets the required env vars and regenerates the CLI table first +- The build type-checks code samples against the built workspace packages, so run `pnpm build` at the repo root first + +## What fails the build + +- Code blocks tagged `ts twoslash` are type-checked during `pnpm docs:build` only; the dev server skips twoslash and will not catch broken samples. A sample that intentionally fails needs `// @errors: `; use `// ---cut---` and `// @filename:` to hide setup lines. Changing public types in `packages/` can break twoslash samples. +- Dead internal links fail the build. Every CLI option gets a generated link to `/config/