Declarative Tests
Define inputs, expected outputs, and assertions in a clear, readable format. No boilerplate.
Declarative Tests
Define inputs, expected outputs, and assertions in a clear, readable format. No boilerplate.
Database Native
Built for database testing. Write queries in your dialect (Cypher, SQL) with full syntax highlighting.
Hierarchical Organization
Group tests by query, feature, or scenario. Inherit setup blocks. Keep things DRY.
Editor Support
Tree-sitter grammar, Neovim plugin with neotest integration, and LSP for diagnostics.
// Define your queryfn GetUser() `MATCH (u:User {id: $userId})RETURN u.name, u.email, u.age`
// Global setupsetup `CREATE (alice:User {id: 1, name: "Alice", email: "alice@example.com", age: 30})CREATE (bob:User {id: 2, name: "Bob", email: "bob@example.com", age: 25})`
// Test the queryGetUser { group "existing users" { test "finds Alice by id" { $userId: 1
u.name: "Alice" u.email: "alice@example.com" u.age: 30 }
test "finds Bob by id" { $userId: 2
u.name: "Bob" u.age: 25
// Assertion expressions assert (u.age >= 18) } }
test "non-existent user returns null" { $userId: 999
u.name: null }}The pattern: Define queries, set up test data, specify inputs with $param, and declare expected outputs. Add assertion expressions for complex validations.
Simple I/O Testing
Specify $inputs and expected outputs. scaf runs the query and compares results.
Expression Assertions
Use expr-lang for powerful assertions: comparisons, string matching, function calls.
Setup Inheritance
Define setup at suite, scope, group, or test level. Child tests inherit from parents.
Multiple Databases
Support for Neo4j (Cypher) with PostgreSQL, MySQL, SQLite coming soon.
go install github.com/rlch/scaf/cmd/scaf@latestThen create a .scaf.yaml config:
neo4j: uri: bolt://localhost:7687 username: neo4j password: password# Run all testsscaf test
# Run specific filescaf test queries/users.scaf
# With verbose outputscaf test --format=verbose