Marble test typeahead — verifying debounce/switchMap
Pattern
Typeahead depends on TIME (debounce) and on CANCELLATION (switchMap). Testing it with setTimeout and real timers is slow and flaky on CI. Marble tests give virtual time: 100ms passes instantly, but the stream "thinks" 100ms went by.
The problem it solves
If a test waits 300 real ms, on a busy CI it can hang or produce a flaky result. And you want to test the ALGORITHM's idea (cancelled the old request, handled the last one), not real time.
Operators and why they matter
TestScheduler — gives virtual time. debounce, timer, interval run instantly on that scale.
Input marble string ('-a-ab--abc') — describes events on a timeline.
Expected marble — describes the expected result, including exactly when it should arrive.
Gotchas
Real timers in debounce tests are a recipe for flaky tests. Passes locally, fails on CI.
The mock HTTP must be a cold observable, so switchMap cancellation is actually tested.
Marbles check not just the values but the TIMING of emissions. A test "received abc" doesn't cover "cancelled a and ab".
What you get
Typeahead timing becomes a deterministic test contract. Tests are fast and stable.