2

I have the following angular (4) test which should be testing a service, however, it seems to be passing before the Observable returns and expect get's hit.

   it('should enter the assertion', inject(
        [ MockBackend, CellService ],
        ( backend: MockBackend, s: CellService ) => {
            const urls = [];

            backend.connections.subscribe((connection: MockConnection) => {
                const req = connection.request;
                urls.push(req.url);
                if (req.method === RequestMethod.Get && req.url === '/api/getTest') {
                    connection.mockRespond(new Response(new ResponseOptions('enter mocked content')));
                }
            });
            s.getCell('powders').subscribe(val => expect(true).toBeFalsy())
        })
    );

I tried adding async/await, but that didn't make a difference. How can I do this?

Update:

This code passes too ...

it('should enter the assertion', async(inject(
    [ MockBackend, CellService ],
    ( backend: MockBackend, s: CellService ) => {
        const urls = [];

        backend.connections.subscribe((connection: MockConnection) => {
            const req = connection.request;
            urls.push(req.url);
            if (req.method === RequestMethod.Get && req.url === '/api/getTest') {
                connection.mockRespond(new Response(new ResponseOptions('enter mocked content')));
            }
        });
        s.getCell('powders').subscribe(val => expect(true).toBeFalsy())
    })
));
George Edwards
  • 8,979
  • 20
  • 78
  • 161

3 Answers3

2

Wrap the test in Angular's async

import { async } from '@angular/core/testing';

                         ---==== vvvv ===----
it('should enter the assertion', async(inject(
    [ MockBackend, CellService ],
    ( backend: MockBackend, s: CellService ) => {
        ...
    })
));

This will wrap the test in a test zone, which will allow Angular to actually wait for all the asynchronous tasks to complete before finishing the test.

See also:

UPDATE

Try it with fakeAsycn/tick

import { fakeAsync } from '@angular/core/testing';

it('should enter the assertion', fakeAsync(inject(
    [ MockBackend, CellService ],
    ( backend: MockBackend, s: CellService ) => {
        ...

        let value;
        s.getCell('powders').subscribe(val => {
          value = val;
        })
        tick();
        expect(val).toBeTruthy();
    })
));

It should work with async, but using fakeAsync makes it a little easier to debug, since every thing is synchronous.

If it still doesn't work, then you may need to check the logic somewhere else. One of the checks I would make is here

req.method === RequestMethod.Get && req.url === '/api/getTest'

Are you sure both of these pass? If not, there will be no response.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
0

I would prefer to use Jasmine done() callback here.

First, get rid off injectors in the spec and use TestBed.get(serviceToken) in beforeEach section.

Second, pass done as parameter of spec function

it('should use asynchronous', done => {
  s.method().subscribe(result => {
    expect(result).toBe(...);
    done();
  }
})
s-f
  • 2,091
  • 22
  • 28
0

You can use waitForAsync which is intended exactly for this and works both with observables and promises.

Wraps a test function in an asynchronous test zone. The test will automatically complete when all asynchronous calls within this zone are done. Can be used to wrap an inject call. (doc)

it('...', waitForAsync(inject([AClass], (object) => {
  object.doSomething.subscribe(() => {
    expect(...);
  })
})));
Addis
  • 2,480
  • 2
  • 13
  • 21