4
votes

I am trying to mock a service for a component unit test. Here my service:

@Injectable()
export class LoginService {

    constructor(public http: Http) { }

    getLanguages() {
        return this.http.get('the-url')
                        .map((res: Response) => res.json());
    }

...

NOTE: My component invokes this method in constructor (load the languages when construct the comp).

Then my attempt to mock it :

class MockLoginService {
    getLanguages() {
        return Observable.of(
            [
                {
                    'name': 'English (USA)',
                    'locale': 'en-US'
                },
                {
                    'name': 'Español',
                    'locale': 'es-US'
                }
            ]
        );
    }

And my component unit test:

  it('should load languages', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
        tcb
            .overrideProviders(LoginComponent, [ provide(LoginService, { useClass: MockLoginService })])
            .createAsync(LoginComponent).then((fixture) => {
                let element = fixture.nativeElement;
                let loginInstance = fixture.componentInstance;
                fixture.detectChanges();
                expect(loginInstance._loginService.getLanguages).toHaveBeenCalled();
                expect(element.querySelectorAll('option').length).toBe(5);
            });
    }));

Issue:

I see my mock service is called and data received is correct but my 2 tests are skipped! Here is the log :

angular2-polyfills.js:528 Unhandled Promise rejection: 'expect' was used when there was no current spec, this could be because an asynchronous test timed out ; Zone: ; Task: Promise.then ; Value: Error: 'expect' was used when there was no current spec, this could be because an asynchronous test timed out(…)

I undertand the service is executed async and the tests get lost somewhere. angular2-polyfills.js:530 Error: Uncaught (in promise): Error: 'expect' was used when there was no current spec, this could be because an asynchronous test timed out(…)

I tried fakeAsync with tick - no success . Thanks in advance !

1
Try injectAsync([TestComponentBuilder], instead of inject([TestComponentBuilder], ..Günter Zöchbauer

1 Answers

1
votes

You could try to instantiate your mocked service manually and set it within the beforeEachProviders method callback

var service = new MockLoginService();

beforeEachProviders(() => [ provide(TestService, { useValue: service })]);

it('should load languages', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    tcb
        .createAsync(LoginComponent).then((fixture) => {
            let element = fixture.nativeElement;
            let loginInstance = fixture.componentInstance;
            fixture.detectChanges();

            expect(element.querySelectorAll('option').length).toBe(2);
        });
}));

It works for me. See this plunkr: https://plnkr.co/edit/zTy3Ou?p=preview.