Write Tests
Guide for writing tests in Syncpack using the TestBuilder pattern.
TDD Workflow (Mandatory)
- Study existing tests — Read 2-3 tests in same file, identify the pattern, match it exactly
- Write failing test — Never invent APIs; read source to see what exists
- Verify it fails — Run
just testto confirm - Ask user to confirm — Get approval before implementing
- Implement minimal code — Only what's needed to pass
- Clean up — Run
just format, fix warnings, refactor if needed
Golden Rule
Always use TestBuilder — Never manually construct Context in tests.
Quick Start
use {
crate::{
instance_state::{FixableInstance::*, InstanceState, ValidInstance::*},
test::{
builder::TestBuilder,
expect::{expect, ExpectedInstance},
},
},
serde_json::json,
};
#[test]
fn test_descriptive_name() {
let ctx = TestBuilder::new()
.with_packages(vec![
json!({"name": "pkg-a", "dependencies": {"react": "17.0.0"}}),
])
.with_version_group(json!({
"dependencies": ["react"],
"pinVersion": "18.0.0"
}))
.build_and_visit_packages();
expect(&ctx).to_have_instances(vec![
ExpectedInstance {
state: InstanceState::fixable(DiffersToPin),
dependency_name: "react",
id: "react in /dependencies of pkg-a",
actual: "17.0.0",
expected: Some("18.0.0"),
overridden: None,
},
]);
}
TestBuilder Methods
Packages
.with_package(json!({...})) // Single package
.with_packages(vec![json!({...})]) // Multiple packages
Version Groups
.with_version_group(json!({...})) // Single group
.with_version_groups(vec![...]) // Multiple groups
Configuration
.with_config(json!({...})) // Custom config
.with_semver_group(json!({...})) // Semver rules
.with_strict(true) // Strict mode
Registry (for update command)
.with_registry_updates(json!({"react": ["17.0.0", "18.0.0"]}))
.with_update_target(UpdateTarget::Latest)
Build
.build() // Without visiting (rare)
.build_and_visit_packages() // With visiting (most common)
Location String Format
{dependency} in {location} of {package}
Examples:
"react in /dependencies of pkg-a""lodash in /devDependencies of pkg-b""pnpm in /packageManager of pkg-c"
Running Tests
just test # All tests
cargo test test_name -- --nocapture # Specific test with output
cargo test banned_test # Tests matching pattern
Test Organisation
- Integration tests:
src/visit_packages/*_test.rs(preferred) - Unit tests: Co-located as
*_test.rs(e.g.,src/foo.rs→src/foo_test.rs) - Test utilities:
src/test/builder.rs,src/test/expect.rs
Common Patterns
→ Full patterns and examples: patterns.md
Good Test Examples
Study these files:
src/visit_packages/banned_test.rs— Comprehensive examplessrc/visit_packages/pinned_test.rs— Version group testingsrc/visit_packages/preferred_semver_test.rs— Local package and highest/lowest semver handling
Common Mistakes
| Wrong | Right |
|---|---|
Context { ... } | TestBuilder::new()... |
.build() then check states | .build_and_visit_packages() |
ctx.instances[0] | .find(|i| i.dependency.name == "react") |