--- id: biomejs/biome/testing-codegen version: "c82a542b" license: Apache-2.0 install: manual updated: 2026-07-27 --- # testing-codegen — testing-codegen guides you through snapshot testing with insta and code generation for the Biome codebase. It covers running tests for specific crates, fast iteration with quick-test workflows, and safely managing snapshots—including pruning orphaned files and reviewing changes interactively. Use this skill when testing lint rules, inspecting AST structure, or regenerating parser and analyzer code. Publisher: biomejs · Stars: 25418 · Updated: 2026-07-27 Install (manual): `git clone https://github.com/biomejs/biome` ## SKILL.md ## Purpose Use this skill for testing and code generation. Covers snapshot testing with `insta` and code generation commands. ## Prerequisites 1. Install required tools: `just install-tools` (installs `cargo-insta`) 2. Install pnpm: `curl -fsSL https://get.pnpm.io/install.sh | sh -` in repo root 3. Understand which changes require code generation ## Common Workflows ### Run Tests ```shell # Run all tests cargo test # Run tests for specific crate cd crates/biome_js_analyze cargo test # Run specific test cargo test quick_test # Show test output (for dbg! macros) cargo test quick_test -- --show-output # Run tests with just (uses CI test runner) just test # Test specific crate with just just test-crate biome_cli ``` ### Quick Test for Rules Fast iteration during development: ```rust // In crates/biome_js_analyze/tests/quick_test.rs // Modify the quick_test function: const SOURCE: &str = r#" const x = 1; var y = 2; "#; let rule_filter = RuleFilter::Rule("nursery", "noVar"); ``` Run: ```shell just qt biome_js_analyze ``` ### Quick Test for Parser Development **IMPORTANT:** Use this instead of building full Biome binary for syntax inspection - it's much faster! For inspecting AST structure when implementing parsers or working with embedded languages: ```rust // In crates/biome_html_parser/tests/quick_test.rs // Modify the quick_test function: #[test] pub fn quick_test() { let code = r#""#; let source_type = HtmlFileSource::svelte(); let options = HtmlParserOptions::from(&source_type); let root = parse_html(code, options); let syntax = root.syntax(); dbg!(&syntax, root.diagnostics(), root.has_errors()); } ``` Run: ```shell just qt biome_html_parser ``` The `dbg!` output shows the full AST tree structure, helping you understand: - How directives/attributes are parsed (e.g., `HtmlAttribute` vs `SvelteBindDirective`) - Whether values use `HtmlString` (quotes) or `HtmlTextExpression` (curly braces) - Token ranges and offsets needed for proper snippet creation - Node hierarchy and parent-child relationships ### Snapshot Testing with Insta Run tests and generate snapshots: ```shell cargo test ``` Review generated/changed snapshots: ```shell # Interactive review (recommended) cargo insta review # Accept all changes cargo insta accept # Reject all changes cargo insta reject # Review for specific test cargo insta review --test-runner nextest ``` Snapshot commands: - `a` - accept snapshot - `r` - reject snapshot - `s` - skip snapshot - `q` - quit ### Pruning Orphaned Snapshots When tests are removed or renamed, their old snapshot files become orphaned. **Never delete snapshot files manually with `rm`** — always use insta's built-in pruning: ```shell # Delete unreferenced snapshots after a successful test run cargo insta test --unreferenced delete -p # Or scoped to specific tests cargo insta test --unreferenced delete -p biome_cli --test main -- "handle_vue" ``` This runs the tests first, then deletes any `.snap` files that no test references. It is the only safe way to clean up snapshots — manual `rm` risks deleting snapshots that are still needed or creating git conflicts. ### Test Lint Rules ```shell # Test specific rule by name just test-lintrule noVar # Run from analyzer crate cd crates/biome_js_analyze cargo test ``` ### Create Test Files **Single file tests** - Place in `tests/specs/{group}/{rule}/` under the appropriate `*_analyze` crate for the language: ``` tests/specs/nursery/noVar/ ├── invalid.js # Code that should generate diagnostics ├── valid.js # Code that should not generate diagnostics └── options.json # Optional: rule configuration ``` **File and folder naming conventions (IMPORTANT):** - Use `valid` or `invalid` in file names or parent folder names to indicate expected behaviour. - Files/folders with `valid` in the name (but not `invalid`) are expected to produce **no diagnostics**. - Files/folders with `invalid` in the name are expected to produce **diagnostics**. - When testing cases inside a folder, prefix the name of folder using `valid`/`invalid` e.g. `validResolutionReact`/`invalidResolutionReact` ``` tests/specs/nursery/noShadow/ ├── invalid.js # should generate diagnostics ├── valid.js # should not generate diagnostics ├── validResolutionReact/ └───── file.js # should generate diagnostics └── file2.js # should not generate diagnostics ``` **Multiple test cases** - Use `.jsonc` files with arrays: ```jsonc // tests/specs/nursery/noVar/invalid.jsonc [ "var x = 1;", "var y = 2; var z = 3;", "for (var i = 0; i < 10; i++) {}" ] ``` **Test-specific options** - Create `options.json`: ```json { "linter": { "rules": { "nursery": { "noVar": { "level": "error", "options": { "someOption": "value" } } } } } } ``` ### Top-Level Comment Convention (REQUIRED) Every test spec file **must** begin with a top-level comment declaring whether it expects diagnostics. The test runner (`assert_diagnostics_expectation_comment` in `biome_test_utils`) enforces this and panics if the rules are violated. Write the marker text using whatever comment syntax the language under test supports. For languages that do not support comments at all, rely on the file/folder naming convention (`valid`/`invalid`) instead. **For files whose name contains "valid" (but not "invalid"):** The comment is **mandatory** — the test panics if it is absent. **For files whose name contains "invalid" (or other names):** The comment is strongly recommended and is also enforced when present: if the comment says `should generate diagnostics` but no diagnostics appear, the test panics. **Rules enforced by the test runner:** | File name contains | Comment present? | Behaviour | |---------------------------|-----------------------------------|------------------------------------| | "valid" (not "invalid") | `should not generate diagnostics` | Passes if no diagnostics | | "valid" (not "invalid") | `should generate diagnostics` | Passes if diagnostics present | | "valid" (not "invalid") | absent | **PANIC** — comment is mandatory | | "invalid" or neutral name | `should not generate diagnostics` | Passes if no diagnostics | | "invalid" or neutral name | `should generate diagnostics` | Passes if diagnostics present | | "invalid" or neutral name | absent | No enforcement (but add it anyway) | **Important details:** - The comment is found by scanning the entire file's leading trivia — it does not have to be literally the first token, but putting it at the very top (line 1) is the established convention. - Fixture/support files (e.g. `foo.js`, `bar.ts`) that don't contain "valid" or "invalid" in their name do **not** require a comment, since they are not considered "valid test files" by the runner. - Files excluded from comment enforcement regardless of name: `.snap`, `.json`, `.jsonc`. **HTML-ish files (`.vue`, `.svelte`, `.astro`, `.html`):** These files are analyzed via the workspace-based test path (`analyze_with_workspace` in `biome_test_utils`), which checks the expectation comment by scanning the **raw file content** (not the parsed AST trivia). Use an HTML comment at the very top of the file: ```vue ``` ```vue ``` The same rules apply: valid files **must** have the comment, invalid files **should** have it. Do not place the comment inside `