Nx: Async test fails with jasmine-core 2.8.0 (or 2.7+)

Created on 29 Nov 2017  路  9Comments  路  Source: nrwl/nx

I followed this guide to create an ngrx effect (app.effects.spec.ts):

https://nrwl.io/nx/guide-setting-up-ngrx

When running the unit test, I get

Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
repro needed bug

Most helpful comment

I changed the generated specs to use toBeObservable instead of readAll (see here https://github.com/nrwl/nx/pull/267).

Both hot and cold use the test scheduler. The test scheduler controls the time, so you need to manually call flush on it to advance the time.

As a result, async/await and the test scheduler don't work together that well (they happen to work in some basic scenarios but break apart when in non-trivial scenarios). So from now on, the tests should either use one or the other.

All 9 comments

I went over to ngrx platform repo and found this https://github.com/ngrx/platform/issues/553. But it was closed...

Can't reproduce. Could you give us a repo or link.

@Yonet
I just created another project with nx. Things work fine out of the box.

Once I update the libraries, I see the issue. Here is the branch that has the issue:

https://github.com/dereklin/nx-demo/tree/feature/update-libraries

The master branch is fine.

Thanks for checking.

Also, I am using windows 10. I had to run

npm i --no-optional

to install the dependencies.

To run the tests, I did

ng test --app=app1

This problem is due to jasmine-core. I downgraded from 2.8.0 to 2.6.2. The problem went away.

Here is the working repo: https://github.com/dereklin/nx-demo/tree/feature/figure-out-async-timeout

I think there is an issue with the reallAll function. It seems like the promise return from it never resolves. I was told at the jasmine repo that async was introduced at version 2.7. I tested a simple async test and it went through ok.

This is the failing repo: https://github.com/dereklin/nx-demo/tree/feature/figuring-out-jasmine-async-2

Here is my spec:

import { TestBed } from '@angular/core/testing';
import { StoreModule } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { provideMockActions } from '@ngrx/effects/testing';
import { DataPersistence } from '@nrwl/nx';
import { readAll, hot } from '@nrwl/nx/testing';
import { AppEffects } from './app.effects';
import { of } from 'rxjs/observable/of';

export const return1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 5000);
  });
};

describe('AppEffects', () => {
  let actions;
  let effects: AppEffects;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [StoreModule.forRoot({})],
      providers: [AppEffects, DataPersistence, provideMockActions(() => actions)]
    });

    effects = TestBed.get(AppEffects);
  });

  describe('someEffect', () => {
    it("should support async execution of test preparation and expectations", async () => {
      expect(await return1()).toEqual(1);
    }, 10000);

    it('should work', async () => {
      actions = hot('-a-|', { a: { type: 'LOAD_DATA' } });
      expect(await readAll(effects.loadData)).toEqual([{ type: 'DATA_LOADED', payload: {} }]);
    }, 50000);

  });

});

I'm using jest and had the same problem. I tried using rxjs-marbles and the problem was resolved:

  describe('someEffect', () => {
    it('should work', marbles(async m => {
      actions = m.hot('-a-|', { a: { type: 'LOAD_DATA' } });
      expect(await readAll(effects.loadData)).toEqual([
        { type: 'DATA_LOADED', payload: {} }
      ]);
    });
  });

@mike-packetwerk
Thanks for the tip. There is a little syntax error in the code posted. Here is my working test:

  describe("someEffect", () => {
    it("should work", marbles(async(m) => {
      actions = hot('-a-|', { a: { type: 'LOAD_DATA' } });
      expect(await readAll(effects.loadData)).toEqual([{ type: 'DATA_LOADED', payload: {} }]);
    }));
  });

I am new to marbles. And from their example at https://github.com/cartant/rxjs-marbles
The hot and cold is from the m param. I change the test to use m.hot and it still works:

  describe("someEffect", () => {
    it("should work with m.hot", marbles(async(m) => {
      actions = m.hot('-a-|', { a: { type: 'LOAD_DATA' } });
      expect(await readAll(effects.loadData)).toEqual([{ type: 'DATA_LOADED', payload: {} }]);
    }));
  });

Do we still need this?:

import { hot } from '@nrwl/nx/testing';

I changed the generated specs to use toBeObservable instead of readAll (see here https://github.com/nrwl/nx/pull/267).

Both hot and cold use the test scheduler. The test scheduler controls the time, so you need to manually call flush on it to advance the time.

As a result, async/await and the test scheduler don't work together that well (they happen to work in some basic scenarios but break apart when in non-trivial scenarios). So from now on, the tests should either use one or the other.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

elliotmendiola picture elliotmendiola  路  3Comments

kmkatsma picture kmkatsma  路  3Comments

MichaelWarneke picture MichaelWarneke  路  3Comments

Svancara picture Svancara  路  3Comments

about-code picture about-code  路  3Comments