BiomeJS Testing: Unit, Snapshot, and End-to-End Testing in the Biome Toolchain
BiomeJS employs a three-layer testing strategy combining Rust unit tests, snapshot tests using the insta crate, and shell-based end-to-end tests to ensure formatting, linting, and parsing reliability across its entire toolchain.
The biomejs/biome repository is a Rust-based toolchain for web languages that provides formatting, linting, and language services. Understanding the BiomeJS testing infrastructure is essential for contributors who want to ensure their changes maintain the project's 97% Prettier compatibility guarantee and CLI stability.
Unit Test Architecture in BiomeJS
Biome organizes its codebase into crates under the crates/ directory, with each language-specific crate (e.g., biome_js_parser, biome_css_formatter) containing its own test suite. The unit tests validate individual components such as parsers, formatters, and analyzers.
Parser and Lexer Testing
The JavaScript parser (biome_js_parser) includes rigorous tests for its lexer and concrete-syntax-tree (CST) generator. These tests reside in src/ adjacent to the code they validate, following Rust's standard testing conventions.
For example, the lexer tests in crates/biome_js_parser/src/lexer/tests.rs verify tokenization:
#[test]
fn simple_identifier() {
let mut lexer = Lexer::new("foo");
assert_eq!(lexer.next(), Some(Token::Identifier("foo")));
}
Formatter Testing with Snapshots
The formatter crate (biome_js_formatter) utilizes the insta crate to create snapshot tests that ensure formatted output remains stable across changes. These tests run the formatter on code snippets and compare results against stored golden snapshots.
#[test]
fn format_simple_function() {
let source = "function foo(){return 1;}";
let formatted = format_js(source);
insta::assert_snapshot!(formatted);
}
Snapshots are stored under crates/biome_js_formatter/tests/specs/prettier/, mirroring Prettier's test layout to maintain the project's 97% compatibility claim.
End-to-End CLI Testing
The end-to-end (e2e) test layer validates the Biome CLI as a real user would. Located in the e2e-tests/ directory, these tests are self-contained projects that invoke the Biome binary through shell scripts.
Each e2e test folder contains a test.sh script and optional biome.json configuration. The script executes Biome commands and relies on process exit codes to signal success or failure. For example, e2e-tests/relative-path/test.sh runs:
set -eu
cargo run --bin biome -- lint src
When linting reports diagnostics, the non-zero exit code causes the test harness to mark the test as failed. All e2e tests are executed by the CI workflow defined in .github/workflows/main.yml, ensuring breaking changes are caught before merge.
Fuzzing and Property-Based Testing
Beyond standard tests, Biome includes a lightweight fuzzing harness in the fuzz/ directory. Running via cargo fuzz run, this harness feeds randomly generated inputs to the parsers to detect panics or crashes. The fuzzing suite is integrated into the CI pipeline, providing additional reliability guarantees against malformed input edge cases.
Running BiomeJS Tests Locally
Developers can execute the complete BiomeJS testing suite using standard Cargo commands:
# Run all Rust unit and snapshot tests
cargo test
# Run only the JavaScript parser lexer tests
cargo test -p biome_js_parser --test lexer
For end-to-end validation, use the Just task runner:
just e2e
This command iterates over every e2e-tests/*/test.sh script and reports a summary, as defined in the repository's justfile.
Adding New Tests to BiomeJS
When contributing to Biome, you can add tests at any layer of the architecture:
- Unit tests: Create
src/<module>/tests.rsinside the appropriate crate and add#[test]functions. These compile as standard Rust tests. - Snapshot tests: Add a new directory under
tests/specs/prettier/with an input file and expected.snapfile containing the formatted output. - E2E tests: Copy an existing folder under
e2e-tests/, adjustbiome.jsonor source files, and modifytest.shto run the desired Biome command.
All new tests are automatically picked up by cargo test and the CI workflow.
Programmatic Usage Examples
Biome can be used programmatically via its Rust API. The following snippet mirrors the core logic found in crates/biome_cli/src/main.rs:
use biome_cli::BiomeCommand;
use biome_service::workspace;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let command = BiomeCommand::parse();
let fs = biome_fs::OsFileSystem::default();
let workspace = workspace::server(std::sync::Arc::new(fs), command.get_threads())?;
let session = biome_cli::CliSession::new(&*workspace, &mut biome_console::EnvConsole::default())?;
session.run(command)?;
Ok(())
}
For CLI usage, format files with:
npx @biomejs/biome format src/index.js --write
Or lint with safe fixes applied automatically:
npx @biomejs/biome lint src --apply-safe-fixes
Summary
- BiomeJS testing operates on three layers: Rust unit tests for internals, snapshot tests for output stability, and shell-based e2e tests for CLI validation.
- Unit tests reside in
src/directories next to code, while snapshot tests use theinstacrate incrates/*/tests/specs/. - End-to-end tests in
e2e-tests/validate the actual binary through exit codes. - Run the full suite with
cargo testandjust e2e, or fuzz withcargo fuzz run. - The snapshot structure in
crates/biome_js_formatter/tests/specs/prettier/maintains 97% Prettier compatibility.
Frequently Asked Questions
How does BiomeJS snapshot testing work?
BiomeJS snapshot testing uses the insta crate to compare current output against stored golden snapshots. When tests run in crates/biome_js_formatter/tests/specs/, the formatter processes input files and insta::assert_snapshot! verifies the output matches the .snap files. If output changes, the test fails until you review and accept the new snapshot with cargo insta review.
What is the difference between unit tests and e2e tests in BiomeJS?
Unit tests in crates/*/src/ validate individual Rust functions like lexer tokenization or parser AST generation. End-to-end tests in e2e-tests/ execute the compiled Biome binary through shell scripts, testing the complete integration of configuration parsing, file handling, and CLI exit codes. Unit tests provide fast feedback during development, while e2e tests catch integration regressions.
How do I run only specific tests in BiomeJS?
Use Cargo's package filtering to target specific crates: cargo test -p biome_js_parser --test lexer runs only the JavaScript parser lexer tests. For formatter-specific tests, navigate to crates/biome_js_formatter and run cargo test within that directory. End-to-end tests can be run individually by executing their specific test.sh script, or collectively via just e2e.
How does BiomeJS ensure Prettier compatibility?
Biome maintains a snapshot test suite in crates/biome_js_formatter/tests/specs/prettier/ that mirrors Prettier's official test layout. By running these snapshots against the formatter and verifying output matches Prettier's expected results, Biome claims 97% compatibility. Any divergence in formatting output causes snapshot test failures, ensuring the formatter remains consistent with Prettier behavior.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →