Description
Use StackBlitz to reproduce your issue: ADDED (thanks @annieyw!), example here
Steps to reproduce:
- Follow the instructions for using Harnesses
- In the component under test, use
setInterval
, or the rxjsinterval(n)
ortimer(0, n)
observables - Your test will stall indefinitely at e.g.
await loader.getAllHarnesses(MatButtonHarness);
(from the docs linked in step 1)
Expected Behavior
getAllHarnesses
completes once the component has finished initializing and had a chance to create instances of child components.
Actual Behavior
The call to getAllHarnesses
never resolves, and the test times out.
Environment
- Angular: 10.1.2
- CDK/Material: 10.2.1
- Browser(s): N/A
- Operating System (e.g. Windows, macOS, Ubuntu): N/A (Win10)
As I understand it, this is because under the hood, TestbedHarnessEnvironment
is using ComponentFixture#whenStable
. From what I can tell, the official stance from Angular / Zone is that you should use fakeAsync
plus tick
, and call discardPeriodicTasks
to ignore the (expected) pending intervals, instead of using waitForAsync
/ whenStable
.
This very old StackOverflow question suggests that one should never have setInterval
in a component or service, instead using an injected service to provide periodic actions, so it can be mocked out during testing, but I've never seen anything "official" from Angular to say that intervals are unsupported.
If it's not permissible to use intervals in a component, this should be documented somewhere, with suggestions of alternative design patterns to use that are compatible with Material's test utilities. If it is permissible, TestbedHarnessEnvironment
should be updated to include another way of determining when the owning ComponentFixture
is "ready", or I guess kick this upstream to the Zone folks so they can make whenStable
work with intervals.