Marble Testing — Series 3

Preview — 3 of 10 questions

Suppose the teardown function (clearing the interval) had a bug and didn't actually stop setInterval. Would subscriber.next(...) calls made after .unsubscribe() still reach the console.log in this code?

javascript
new Observable(subscriber => {
  const id = setInterval(() => subscriber.next(Date.now()), 100);
  return () => clearInterval(id);
}).subscribe(v => console.log(v)).unsubscribe();
ANo — the Subscriber object RxJS wraps around your next: v => console.log(v) callback tracks its own closed state; once .unsubscribe() has run, that Subscriber silently ignores any further next() calls, even ones a buggy producer keeps making. This is a safety net built into RxJS's own subscriber implementation, independent of whether the producer's teardown logic is actually correct
BYes — nothing stops a misbehaving producer from continuing to deliver values to a consumer that has already unsubscribed
CIt throws an error the next time next() is called after unsubscription
DIt depends on whether the Observable was created with new Observable() versus a creation function like interval()

What does the ^ inside the subscription marble string represent, and why does hot() need it (unlike cold())?

javascript
testScheduler.run(({ hot, expectObservable }) => {
  const source$ = hot('--a--b--c--|', { }, undefined);
  const sub =        '   ^--------!';
  expectObservable(source$, sub).toBe('  --b--c--|');
});
A^ marks where the test expects an error to occur
B^ is purely decorative in marble diagrams and has no effect on the test
C^ marks the moment the test's virtual subscriber actually subscribes to the hot source — since a hot() Observable is treated as already "running" on its own timeline regardless of when anything subscribes, values emitted before that point (a here) are missed entirely, exactly as a real subscriber joining a live stream late would miss earlier broadcasts. cold() sources don't need this marker because each subscription always starts that source's timeline fresh, from frame zero
D^ indicates the point where the source should be unsubscribed

What does outputFromObservable() provide here, compared to a plain @Output() termChanged = new EventEmitter<string>()?

javascript
export class SearchBoxComponent {
  private readonly searchTerm$ = new Subject<string>();
  termChanged = outputFromObservable(this.searchTerm$);
}
ANothing different at the template usage level — (termChanged) works the same either way. The difference is internal: outputFromObservable wires the component's output directly to an existing RxJS source, subscribing to it and automatically unsubscribing when the component is destroyed, instead of requiring the component to manually call .next() on an EventEmitter inside its own subscription callback
BIt converts the output into a signal that must be read with termChanged() instead of bound with (termChanged)
CIt requires searchTerm$ to be a signal, not a plain RxJS Subject
DIt makes the output synchronous, bypassing change detection scheduling entirely

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.