Cross-field Validation with dependsOn
Use test(...).dependsOn(...) to declare field dependencies for focused runs.
import { create, test, enforce } from 'vest';
const suite = create((data: { password: string; confirmPassword: string }) => {
test('password', 'Password is required', () => {
enforce(data.password).isNotEmpty();
});
test('confirmPassword', 'Passwords must match', () => {
enforce(data.confirmPassword).equals(data.password);
}).dependsOn('password');
});
What it does​
dependsOn is syntactic sugar over include(field).when(depField).
// Equivalent wiring:
include('confirmPassword').when('password');
The 3 Pillars​
- Focus Sync: when a dependency is focused with
suite.only(...), the dependent test is included too. - Dirty-Field Guard: the dependent test is included only after it has been tested at least once, so untouched fields do not light up too early.
- Validity Link: if any dependency is invalid, the dependent field is considered invalid.
Multiple dependencies​
test('total', 'Total must be 100', () => {
enforce(Number(data.a) + Number(data.b) + Number(data.c)).equals(100);
}).dependsOn('a', 'b', 'c');
Rules and edge cases​
- Self-dependency is not allowed (
test('x', ...).dependsOn('x')) and throws. dependsOncan be combined with manualinclude(...).when(...)rules.- It works in grouped tests and async tests as well.
Typed suites​
When using typed methods from a typed suite, dependsOn is typed to your suite fields.
const suite = create<'USERNAME' | 'PASSWORD'>(() => {
const { test } = suite;
test('PASSWORD', 'Required', () => false).dependsOn('USERNAME');
// test('PASSWORD', 'Required', () => false).dependsOn('EMAIL'); // TS error
});