1

I thought that by using a fakeAsync wrapper, my tests wouldn't automatically run subscriptions and that I'd be controlling that part by calling tick manually, but that doesn't seem to be the case. For example, using this method:

foo(): void {
    of([1, 2, 3]).subscribe({
        next: () => {
            console.info('Subscription completed.')
            this.value = true
        },
        error: (err: unknown) => console.error('error called')
    })
}

and testing with this spec:

it('should foo', fakeAsync(() => {
    component.foo()
    expect(component.value).toBeFalse()
}))

I'm seeing the subscription completed message print and thus the expectation fails. I thought that the foo method would be called, but that the subscription wouldn't complete until I put a tick() call into the spec.

What am I doing wrong?

Gargoyle
  • 9,590
  • 16
  • 80
  • 145

2 Answers2

0

tick is just the way to control the passage of time. from Angular documentation. If you omit the tickOptions parameter (tick(100))), then tickOptions defaults to {processNewMacroTasksSynchronously: true}.

https://angular.io/api/core/testing/tick

  • But I haven't called `tick` at all when I do the first expectation check. Why was the subscription already called? – Gargoyle May 27 '21 at 18:10
0

Your assumption that all observables are asynchronous is wrong.

Observables can either be asynchronous or synchronous depending on the underlying implementation. In other words, reactive streams are synchronous if the source is synchronous unless you explicitly make them asynchronous.

Some examples:

//Synchronous
of(1,2)
  .subscribe(console.log);

//asynchronous because of async source
interval(1000)
  .subscribe(console.log);

//aynchronous because one stream is async (interval)
of(1,2)
  .pipe(
    mergeMap(x => interval(1000).pipe(take(2)))
  )
  .subscribe(console.log);

//async because we make it async
of(1,2, asyncScheduler)
  .subscribe(console.log);

TLDR: Because of([1, 2, 3]) is a synchronous source, you won't be able to control when it completes with fakeAsync.

g0rb
  • 2,234
  • 1
  • 9
  • 13
  • 1
    but first you said `//Synchronous of(1,2).subscribe(console.log);` and then `Because of([1, 2, 3]) is an asynchronous source`. I'm confused... – bokkie Oct 27 '22 at 12:21
  • 1
    @bokkie good catch. It should say Because of([1, 2, 3]) is an synchronous source, you wont be able to control. Fixing now. – g0rb Oct 27 '22 at 16:53