Lesson 10 — Testing behavior and boundaries¶
Objective¶
Create a fast, risk-based Vitest suite that protects behavior at the narrowest useful boundaries.
Prerequisites¶
The tracker state, component, route, form, HTTP, and RxJS boundaries from Lessons 4–9.
Mental model¶
A test controls relevant inputs and dependencies, exercises a public behavior, and observes a meaningful outcome. Test depth follows risk, not implementation line count.
Why it exists¶
Focused tests provide change confidence and diagnostic location. Broader tests validate integration but cost more and fail less precisely.
Working model: unit tests are fast; integration tests prove pieces work together.
Engineering reality: boundary and controllability matter more than labels. A giant mocked TestBed can be both slow and unrealistic; a direct store test can still protect valuable domain behavior.
Minimal example¶
| Boundary | Tool | Assert |
|---|---|---|
| pure/domain store | Vitest | transitions and derived facts |
| component | TestBed | accessible rendered behavior/events |
| route | RouterTestingHarness | navigation outcome/page |
| HTTP repository | HTTP testing providers | request contract/mapping |
| critical journey | optional browser runner | a few integrated flows |
Real-world usage¶
Regression suites should isolate network, storage, time, and randomness while preserving meaningful framework behavior.
Common mistakes¶
- asserting private methods or signal names;
- selecting by fragile CSS implementation detail;
- snapshots without behavioral assertions;
- shared state leaking between tests;
- real sleeps, network, clocks, or storage;
- mocking the subject until no real behavior remains.
Mini lab¶
Task: Test store transitions, progress accessibility, invalid/valid form submission, topic route, storage/HTTP overrides, and one regression before fixing a deliberate bug.
Constraints: use public inputs/DOM/outcomes; control external state; keep setups local to scenarios.
Expected result: failures identify a behavior boundary and the suite remains deterministic.
Hint 1
Ask which observation would prove the user/domain outcome with the least infrastructure.
Hint 2
Trigger behavior as a user or public consumer would, then run change detection or stabilization required by that action.
Solution direction — last resort
Arrange only required providers, dispatch public interactions, wait for actual async work, and assert accessible output or domain state.
Verification¶
Change a signal and query stale DOM; choose detectChanges, whenStable, or event dispatch based on actual scheduling. Invert one domain condition and identify which meaningful test catches it.
Mastery evidence: propose a risk-based portfolio, write a regression first, and diagnose test scheduling without arbitrary waits.
Bloom challenge¶
- Understand: fake, stub, mock, and controlled dependency.
- Apply: test one behavior at each boundary.
- Analyze: debug a suite-only failure.
- Evaluate: decide where an integration or E2E test earns its cost.
- Create: design verification for a routed persisted form feature.
Summary¶
Test observable behavior at intentional boundaries; control nondeterminism and spend integration cost where risk justifies it.
Spaced review¶
Retrieve Lessons 3, 6, 7, 8, and 9 by testing their contracts without rereading them.
What comes next¶
Continue to performance.