Skip to content

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

  1. Understand: fake, stub, mock, and controlled dependency.
  2. Apply: test one behavior at each boundary.
  3. Analyze: debug a suite-only failure.
  4. Evaluate: decide where an integration or E2E test earns its cost.
  5. 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.