Open-Source Wikis

/

Zed

/

How to contribute

/

Testing

zed-industries/zed

Testing

How tests are organised

Tests live next to the code they exercise:

  • Unit tests as #[cfg(test)] mod tests { … } blocks at the bottom of source files.
  • Integration tests in each crate's tests/ directory.
  • Benchmarks under */benches/ (e.g. crates/editor/benches, crates/language/benches, crates/project_benchmarks, crates/fs_benchmarks, crates/worktree_benchmarks).
  • Visual regression tests via crates/zed/src/visual_test_runner.rs plus the visual-tests Cargo feature on the zed crate.

Many crates ship a test-support Cargo feature — when set, it pulls in fakes and helpers used by other crates' tests. For example, gpui/test-support provides TestAppContext, VisualTestContext, fake clocks, deterministic runtimes; project/test-support provides a FakeFs, a fake LSP, and so on.

Running tests

cargo test                            # everything
cargo test -p editor                  # one crate
cargo test -p editor -- --nocapture   # see println! output
cargo test -p editor display_map      # filter by name
cargo nextest run -p editor           # via nextest if installed

CI runs the full suite via .github/workflows/run_tests.yml.

GPUI tests

GPUI provides its own deterministic test harness. See gpui::TestAppContext and gpui::VisualTestContext. Two patterns to know:

#[gpui::test]
async fn test_something(cx: &mut TestAppContext) {
    let entity = cx.new(|_cx| MyEntity::default());
    entity.update(cx, |this, cx| { /* ... */ });
    cx.run_until_parked();
}
#[gpui::test]
async fn test_visual(cx: &mut TestAppContext) {
    let cx = cx.add_empty_window();
    // build UI, take a screenshot, compare to a snapshot
}

Timers in tests

From .rules:

Prefer GPUI executor timers over smol::Timer::after(...) when you need timeouts, delays, or to drive run_until_parked():

  • Use cx.background_executor().timer(duration).await.
  • smol::Timer::after(...) is not tracked by GPUI's scheduler and can deadlock run_until_parked().

This is the kind of trap that will silently waste an afternoon.

Visual regression tests

Visual tests render UI to an image and diff against a checked-in snapshot. They run under the visual-tests feature:

cargo test -p zed --features visual-tests

When you intentionally change UI, regenerate the snapshot. The macOS dev guide (docs/src/development/macos.md#visual-regression-tests) covers the workflow.

Test patterns by crate

Areas of the codebase with particularly heavy test coverage:

  • editor, multi_buffer, text, rope — many tests, often randomized fuzzing for invariants.
  • project — uses FakeFs to simulate a filesystem.
  • language — Tree-sitter parsing and language-detection coverage.
  • collab — full-stack integration tests against a real Postgres in crates/collab/tests.
  • lsp, dap — protocol-level tests with mocked transports.

Mocking and fakes

  • FakeFs (fs::FakeFs) — in-memory filesystem used by the project tests.
  • FakeHttpClient (http_client) — programmable HTTP responses.
  • Test-support features in many crates expose deterministic versions of otherwise non-deterministic state.

Coverage expectations

The project does not enforce a numeric coverage threshold. The cultural expectation is:

  • Bugs come with a regression test that fails before the fix and passes after.
  • New features come with tests for the happy path and at least the obvious failure modes.
  • UI work comes with visual regression coverage where reasonable.

Performance regression checks

script/compare-perf and .github/workflows/compare_perf.yml track performance-sensitive paths. The benchmark crates (*/benches/*, project_benchmarks, worktree_benchmarks, fs_benchmarks) feed into these.

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

Testing – Zed wiki | Factory