Question: Angular Material provides [component harnesses](https://material.angular.io/guide/using-component-harnesses) for testing, which lets you interact with their components by `await`ing promises, like this:

```js
  it('should click button', async () => {
    const matButton = await loader.getHarness(MatButtonHarness);
    await matButton.click();
    expect(...);
  });

```

But what if the button click triggers a delayed operation? Normally I would use `fakeAsync()`/`tick()` to handle it:

```js
  it('should click button', fakeAsync(() => {
    mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
    // click button
    tick(1000);
    fixture.detectChanges();
    expect(...);
  }));

```

But is there any way I can do both in the same test?

Wrapping the `async` function inside `fakeAsync()` gives me "Error: The code should be running in the fakeAsync zone to call this function", presumably because once it finishes an `await`, it's no longer in the same function I passed to `fakeAsync()`.

Do I need to do something like this -- starting a fakeAsync function after the await? Or is there a more elegant way?

```js
  it('should click button', async () => {
    mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
    const matButton = await loader.getHarness(MatButtonHarness);

    fakeAsync(async () => {
      // not awaiting click here, so I can tick() first
      const click = matButton.click(); 
      tick(1000);
      fixture.detectChanges();
      await click;
      expect(...);
    })();
  });

```

Answer: 
`fakeAsync(async () => {...})` is a valid construct.

Moreover, Angular Material team is [explicitly testing this scenario](https://github.com/angular/components/blob/b9f761a7283e7525cb569118e4fa0e937cf0d37f/src/cdk/testing/tests/testbed.spec.ts#L87).

```js
it('should wait for async operation to complete in fakeAsync test', fakeAsync(async () => {
        const asyncCounter = await harness.asyncCounter();
        expect(await asyncCounter.text()).toBe('5');
        await harness.increaseCounter(3);
        expect(await asyncCounter.text()).toBe('8');
      }));

```
You should not need a (real) `async` inside `fakeAsync`, at least to control the simulated flow of time. The point of `fakeAsync` is to allow you to replace `await`s with `tick` / `flush`. Now, when you actually need the value, I think you're stuck reverting to `then`, like this:

```js
  it('should click button', fakeAsync(() => {
    mockService.load.and.returnValue(of(mockResults).pipe(delay(1000)));
    const resultThing = fixture.debugElement.query(By.css("div.result"));
    loader.getHarness(MatButtonHarness).then(matButton => {
      matButton.click(); 
      expect(resultThing.textContent).toBeFalsy(); // `Service#load` observable has not emitted yet
      tick(1000); // cause observable to emit
      expect(resultThing.textContent).toBe(mockResults); // Expect element content to be updated
    });
  }));

```

Now, because your test body function is inside a call to `fakeAsync`, it should 1) not allow the test to complete until all Promises created (including the one returned by `getHarness`) are resolved, and 2) fail the test if there are any pending tasks.

(As an aside, I don't think you need a `fixture.detectChanges()` before that second `expect` if you're using the `async` pipe with the Observable returned by your Service, because the `async` pipe explicitly pokes the owner's change detector whenever its internal subscription fires. I'd be interested to know if I'm wrong, though.)