I want to unit test this file, can you please tell how to write jasmine test for this
import { Effect, Actions } from '#ngrx/effects';
import { NavigationActionType } from 'app/core/store/actions/navigation/navigation.action';
import { NavigationService } from 'app/core/services/navigation.service';
import 'rxjs/add/operator/switchMap';
#Injectable()
export class NavigationServiceEffect {
#Effect()
navigations$ = this.actions$
.ofType(NavigationActionType.TRIGGER_LOAD_NAVIGATION_ITEMS)
.switchMap( () => this.navigationService.load())
.map(data => ({ type: NavigationActionType.LOAD_NAVIGATIONS_LINKS, payload: data}));
constructor(private actions$: Actions, private navigationService: NavigationService) {}
}
it('should dispatch LOAD_NAVIGATIONS_LINKS', () => {
runner.queue({
type: NavigationActionType.TRIGGER_LOAD_NAVIGATION_ITEMS,
payload: 1
});
navigationServiceEffect.navigations$.subscribe(result => {
expect(result.type).toEqual(NavigationActionType.LOAD_NAVIGATIONS_LINKS)
expect(result.payload).toEqual(1);
});
}
Note you'll have to mock out the navigationService
You can use jasmine-marbles that provide hot and cold observables to test the effects like this:
it('should dispatch LOAD_NAVIGATIONS_LINKS action', () => {
// arrange
const action = new TriggerLoadNavigationItems();
const expected = cold('-a', {a: new LoadNavigationLinks({data: 'some test data'})});
spyOn(navigationService, 'load').and.returnValue({data: 'some test data'});
// act
actions$ = hot('-a', {a: action});
// assert
expect(effects.navigations$).toBeObservable(expected);
});
Related
I have a custom react hook, just to make a GET request with axios, and
the file named as: useAxiosGet.ts,
and the code is:
import {useMemo, useState} from "react";
import axios, {AxiosResponse} from "axios";
interface ErrorBody {
code: string,
message: string
}
export interface ErrorResponse {
status: number,
errorBody?: ErrorBody
}
export const useAxiosGet = <TResponse>(
requestUrl: string,
) => {
const [data, setData] = useState<TResponse>();
const [error, setError] = useState<ErrorResponse>();
const [loading, setLoading] = useState(false);
const getData = useMemo(() => {
return () => {
setLoading(true);
setError(undefined);
return axios.get(requestUrl)
.then((response: AxiosResponse<TResponse>) => {
const responseData = response.data;
setData(responseData);//update the date
return responseData
})
.catch(err => {
const errorResponse = {status: err.response.status, errorBody: err.response.data}
setError(errorResponse); //update the error
return Promise.reject(errorResponse) //return a Promise.reject
}).finally(() => {
setLoading(false)
});
};
}, []);
return {data, getData, setData, loading, error}
};
I made the resolved case test passed, but the reject case does not, and you can see that
I am returning the Promise.reject(errorResponse) in the.catch(), and I think this is the key point for the failed test. And my test code looks like below:
import {act, renderHook} from '#testing-library/react-hooks'
import axios from 'axios';
import MockAdapter from "axios-mock-adapter";
import {useAxiosGet} from "./useAxiosGet";
interface TProfile {
name: string
}
describe('useAxiosGet', () => {
let mockAxios: MockAdapter;
beforeAll(() => {
mockAxios = new MockAdapter(axios);
})
afterEach(() => {
mockAxios.reset()
})
afterAll(() => {
mockAxios.restore()
})
//This test passed
test('should get data for success request', async () => {
mockAxios.onGet("/id/1").reply(200, {name: 'nana'})
const {result, waitForNextUpdate} = renderHook(() => useAxiosGet<TProfile>('/id/1',))
act(() => {
result.current.getData()
})
await waitForNextUpdate()
expect(result.current.data).toStrictEqual({name: 'nana'})
expect(result.current.loading).toBeFalsy()
expect(result.current.error).toBe(undefined)
});
//This test not passed
test('should get error for failed request', async () => {
const errorBody = {
'code': 'NOT_FOUND',
'message': 'id 1 not found',
};
//Mock the request with a failed HTTP response
mockAxios.onGet("/id/1").reply(404, errorBody)
const {result, waitForValueToChange} = renderHook(() => useAxiosGet<TProfile>('/id/1',))
await waitForValueToChange(() => result.current.getData());
let errorResponse = {
status: 404,
errorBody: errorBody
};
expect(result.current.data).toStrictEqual(undefined);
expect(result.current.error).toStrictEqual(errorResponse);
})
})
I would like to test after the API called, the result.current.error should be the errorResponse expected, but I always get undefined :
test failed screenshot
I know there are something wrong with the test code, but I do not know the correct way to test the reject case, any one know how to do it?
I try to follow the example in the documentation to test epic:
Epic
import { ofType } from 'redux-observable';
import { combineEpics } from 'redux-observable';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { switchMap } from 'rxjs/add/operator/switchMap';
import { from } from 'rxjs/observable/from';
import { of } from 'rxjs/observable/of';
import { fromPromise } from 'rxjs/observable/fromPromise';
import {
getTopStories
} from '../../../utils/service-helper';
import { type, actions } from './action';
export const getHackernewsStoryEpic = (action$, store) =>
action$.ofType(type.GET_HACKERNEWS_STORIES_REQUEST)
.switchMap(
action => {
return from(getTopStories())
.takeUntil(action$.ofType(type.GET_HACKERNEWS_STORIES_REQUEST_CANCEL))
.map(result => actions.getHackernewsStoriesRequestSuccess(result))
.catch((error) => actions.getHackernewsStoriesRequestFailure(error))
}
);
export default combineEpics(
getHackernewsStoryEpic
);
Get getTopStories is service call which talks to hackernews API:
export const getTopStories = async () => await getRequest('/topstories.json');
My test looks like this:
describe('Hackernews stories epic', () => {
describe('getHackernewsStoryEpic', () => {
let store;
beforeEach(() => {
store = mockStore();
});
afterEach(() => {
nock.cleanAll();
epicMiddleware.replaceEpic(storiesEpic);
});
it('should return success on request success', async () => {
store.dispatch({ type: type.GET_HACKERNEWS_STORIES_REQUEST });
expect(store.getActions()).toEqual([
{ type: type.GET_HACKERNEWS_STORIES_REQUEST },
{ type: type.GET_HACKERNEWS_STORIES_SUCCESS }
]);
});
});
});
Looking at the test it fails as one action is trigger and getTopStories() is never trigger (nock is not complaining that there is no mock) and not getting next action. I think I missing something as from should run async call?
it('should return success on request success', async () => {
const mock = require('../../../../data/hackernews/topstories.json');
nock(__ROOT_API__)
.defaultReplyHeaders({ 'access-control-allow-origin': '*' })
.get('/topstories.json')
.reply(200, mock);
const action$ = ActionsObservable.of(
{type: type.GET_HACKERNEWS_STORIES_REQUEST}
);
const expectedAction = [actions.getHackernewsStoriesRequestSuccess(mock)]
await getHackernewsStoryEpic(action$)
.toArray()
.toPromise()
.then(actualOutputActions => {
expect(actualOutputActions).toEqual(expectedAction)
});
});
I'm trying to test a promise in a separate library I injected to my app.
function myFunc(input) {
return new Promise(function(resolve, reject) {
···
resolve(value); // success
···
reject(error); // failure
});
};
This is my function that returns a Promise.
I would seriously love to run the test in jasmine like this
describe('Service: myService', function () {
var $log;
beforeEach(inject(function (_$log_) {
$log = _$log_;
}));
it('should get results', function () {
$log.log("start test");
var self = this;
myFunc(input).then(function(response) {
$log.log("success");
expect(response).toBe("response");
done();
}).catch(function(error) {
$log.log("fail");
self.fail(error);
done();
});
$log.log("end test");
});
});
My test passes(not expected.) and the only thing in my log is [start test] and [end test] as if the promise is totally ignored.
Since I'm not using $q for the promise, most jasmine tips angular doesn't seem to be helpful.
Any ideas on how to get into that 'then'?
Thanks
I could be wrong here, but this is most likely because you are attempting to test an asynchronous process here. So essentially what is happening, is that you call the function, but the test continues running and finishes before the promise ever returns, which is why the test succeeds.
One way to work around this (this is more like a hack, I'm sure there is a better way to do this, and if I find it, I will edit this post) is to add this bit of code at the end of your test:
describe("baseline test",function(){
it("baseline",function(done){
setTimeout(function(){
expect(1).toEqual(1);
done();
},1000);
});
});
Essentially what this snippet does is just set a timeout that waits for 1 second for any asynchronous calls to call back. If 1 second isn't enough, you can always increase that 1000 (which is in milliseconds). If this doesn't work, maybe look into adding another test suite that won't complete until the promises return.
TypeScipt code (Angular 8) to be tested
import { Injectable } from '#angular/core';
import { KeycloakService } from 'keycloak-angular';
import { environment } from 'environments/environment';
import { LoggedInUserHelperService } from 'shared/helper/logged-in-user-helper.service';
#Injectable({
providedIn: 'root'
})
export class AppInitializationService {
constructor(public keycloakService: KeycloakService) {
}
initApplication(): Promise<any> {
return new Promise<any>(
async (resolve: any, reject: any): Promise<any> => {
await this.initKeycloak()
.then(() => keyCloakInitialized = true)
.catch((error: Error) => {
console.error(`Couldn\'t initialize Keycloak Service. (Error: ${error})`);
reject(error);
return;
});
resolve();
}
);
}
private async initKeycloak(): Promise<any> {
return this.keycloakService.init({
config: environment.keycloak,
initOptions: {
onLoad: 'login-required',
checkLoginIframe: false,
promiseType: 'legacy'
},
enableBearerInterceptor: true,
bearerExcludedUrls: ['/assets']
});
}
}
Tests
import { TestBed } from '#angular/core/testing';
import { AppInitializationService } from 'app/app-initialization.service';
import { KeycloakService } from 'keycloak-angular';
describe('AppInitializationService', () => {
let testObj: AppInitializationService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
KeycloakService
]
});
testObj = TestBed.get(AppInitializationService);
});
it('should call keycloak service init', async () => {
const spy = spyOn(testObj.keycloakService, 'init').and.returnValue(Promise.resolve(true));
await testObj.initApplication();
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith({
config: environment.keycloak,
initOptions: {
onLoad: 'login-required',
checkLoginIframe: false,
promiseType: 'legacy'
},
enableBearerInterceptor: true,
bearerExcludedUrls: ['/assets']
});
});
it('should log error on failed keycloak initialization', async () => {
const errorMsg = 'error-msg';
const spy1 = spyOn(testObj.keycloakService, 'init').and.callFake(
() => Promise.reject(errorMsg));
const spy2 = spyOn(console, 'error');
await testObj.initApplication().catch(() => { return; });
expect(spy1).toHaveBeenCalledTimes(1);
expect(spy2).toHaveBeenCalledTimes(1);
expect(spy2).toHaveBeenCalledWith(`Couldn\'t initialize Keycloak Service. (Error: ${errorMsg})`);
});
});
How does one write a Jasmine test to test an observable with the debounce operator? I've followed this blog post and understand the principles of how it should be tested, but it just doesn't seem to work.
Below is the factory that I am using to create the observable:
import Rx from "rx/dist/rx.all";
import DOMFactory from "../utils/dom-factory";
import usernameService from "./username.service";
function createUsernameComponent(config) {
const element = DOMFactory(config);
const username = Rx.Observable
.fromEvent(element.find('input'), 'input')
.pluck('target', 'value')
.startWith(config.value);
const isAvailable = username
.debounce(500)
.tap(() => console.info('I am never called!'))
.flatMapLatest(usernameService.isAvailable)
.startWith(false);
const usernameStream = Rx.Observable.combineLatest(username, isAvailable)
.map((results) => {
const [username, isAvailable] = results;
return isAvailable ? username : ''
})
.distinctUntilChanged();
return Object.freeze({
stream: usernameStream,
view: element
});
}
export default createUsernameComponent;
Note that tap operator is never called by the test. However, it will be executed properly if I run this code on the browser.
Below is my attempt at the test:
import Rx from "rx/dist/rx.all";
import Username from "./username.component";
import DataItemBuilder from "../../../test/js/utils/c+j-builders";
import usernameService from "./username.service"
describe('Username Component', () => {
let input, username;
beforeEach(() => {
const usernameConfig = DataItemBuilder.withName('foo')
.withPrompt('label').withType('text').build();
const usernameComponent = Username(usernameConfig);
usernameComponent.stream.subscribe(value => username = value);
input = usernameComponent.view.find('input');
});
it('should set to a valid username after debounce', () => {
const scheduler = injectTestSchedulerIntoDebounce();
scheduler.scheduleRelative(null, 1000, () => {
doKeyUpTest('abcddd', 'abcdd');
scheduler.stop();
});
scheduler.start();
scheduler.advanceTo(1000);
});
function injectTestSchedulerIntoDebounce() {
const originalOperator = Rx.Observable.prototype.debounce;
const scheduler = new Rx.TestScheduler();
spyOn(Rx.Observable.prototype, 'debounce').and.callFake((dueTime) => {
console.info('The mocked debounce is never called!');
if (typeof dueTime === 'number') {
return originalOperator.call(this, dueTime, scheduler);
}
return originalOperator.call(this, dueTime);
});
return scheduler;
}
function doKeyUpTest(inputValue, expectation) {
input.val(inputValue);
input.trigger('input');
expect(username).toBe(expectation);
}
});
When I run the test, the fake debounce never gets called. I plan to mock the username service once I can get past the debounce.
In your test code you are triggering the input event inside the scheduleRelative function. This doesn't work because you are advancing 1000ms before doing the change. The debouncer then waits 500ms to debounce the isAvailable call but you already stopped the scheduler so time is not advancing afterwards.
What you should do is: trigger the input event before advancing the scheduler time or even better in a scheduleRelative function for a time <= 500ms in a and then inside the scheduleRelative function for 1000ms you have to call the expect function with the expected output and then stop the scheduler.
It should look like this:
it('should set to a valid username after debounce', () => {
const scheduler = injectTestSchedulerIntoDebounce();
scheduler.scheduleRelative(null, 500, () => {
input.val(inputValue);
input.trigger('input');
});
scheduler.scheduleRelative(null, 1000, () => {
expect(username).toBe(expectation);
scheduler.stop();
});
scheduler.start();
scheduler.advanceTo(1000);
});
In addition to that I have better experience with scheduleAbsolute instead of scheduleRelative because it is less confusing.
As per Simon Jentsch's answer, below is the answer using scheduleAbsolute instead of scheduleRelative:
import Rx from "rx/dist/rx.all";
import Username from "./username.component";
import DataItemBuilder from "../../../test/js/utils/c+j-builders";
import usernameService from "./username.service"
describe('Username Component', () => {
let input, username, promiseHelper;
const scheduler = new Rx.TestScheduler(0);
beforeEach(() => {
spyOn(usernameService, 'isAvailable').and.callFake(() => {
return Rx.Observable.just(true);
});
});
beforeEach(() => {
const usernameConfig = DataItemBuilder.withName('foo')
.withPrompt('label').withType('text').build();
const usernameComponent = Username(usernameConfig, scheduler);
usernameComponent.stream.subscribe(value => username = value);
input = usernameComponent.view.find('input');
});
it('should set the username for valid input after debounce', (done) => {
doKeyUpTest('abcddd', '');
scheduler.scheduleAbsolute(null, 100, () => {
expect(usernameService.isAvailable).not.toHaveBeenCalled();
expect(username).toBe('');
});
scheduler.scheduleAbsolute(null, 1000, () => {
expect(usernameService.isAvailable).toHaveBeenCalled();
expect(username).toBe('abcddd');
scheduler.stop();
done();
});
scheduler.start();
});
function doKeyUpTest(inputValue, expectation) {
input.val(inputValue);
input.trigger('input');
expect(username).toBe(expectation);
}
});
I have an Angular 2 component I am trying to put under test, but I am having trouble because the data is set in the ngOnInit function, so is not immediately available in the unit test.
user-view.component.ts:
import {Component, OnInit} from 'angular2/core';
import {RouteParams} from 'angular2/router';
import {User} from './user';
import {UserService} from './user.service';
#Component({
selector: 'user-view',
templateUrl: './components/users/view.html'
})
export class UserViewComponent implements OnInit {
public user: User;
constructor(
private _routeParams: RouteParams,
private _userService: UserService
) {}
ngOnInit() {
const id: number = parseInt(this._routeParams.get('id'));
this._userService
.getUser(id)
.then(user => {
console.info(user);
this.user = user;
});
}
}
user.service.ts:
import {Injectable} from 'angular2/core';
// mock-users is a static JS array
import {users} from './mock-users';
import {User} from './user';
#Injectable()
export class UserService {
getUsers() : Promise<User[]> {
return Promise.resolve(users);
}
getUser(id: number) : Promise<User> {
return Promise.resolve(users[id]);
}
}
user-view.component.spec.ts:
import {
beforeEachProviders,
describe,
expect,
it,
injectAsync,
TestComponentBuilder
} from 'angular2/testing';
import {provide} from 'angular2/core';
import {RouteParams} from 'angular2/router';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {UserViewComponent} from './user-view.component';
import {UserService} from './user.service';
export function main() {
describe('User view component', () => {
beforeEachProviders(() => [
provide(RouteParams, { useValue: new RouteParams({ id: '0' }) }),
UserService
]);
it('should have a name', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb.createAsync(UserViewComponent)
.then((rootTC) => {
spyOn(console, 'info');
let uvDOMEl = rootTC.nativeElement;
rootTC.detectChanges();
expect(console.info).toHaveBeenCalledWith(0);
expect(DOM.querySelectorAll(uvDOMEl, 'h2').length).toBe(0);
});
}));
});
}
The route param is getting passed correctly, but the view hasn't changed before the tests are run. How do I set up a test that happens after the promise in ngOnInit is resolved?
IMO the best solution for this use case is to just make a synchronous mock service . You can't use fakeAsync for this particular case because of the XHR call for templateUrl. And personally I don't think the "hack" to make ngOnInit return a promise is very elegant. And you should not have to call ngOnInit directly, as it should be called by the framework.
You should already be using mocks anyway, as you are only unit testing the component, and don't want to be dependent on the real service working correctly.
To make a service that is synchronous, simple return the service itself from whatever methods are being called. You can then add your then and catch (subscribe if you are using Observable) methods to the mock, so it acts like a Promise. For example
class MockService {
data;
error;
getData() {
return this;
}
then(callback) {
if (!this.error) {
callback(this.data);
}
return this;
}
catch(callback) {
if (this.error) {
callback(this.error);
}
}
setData(data) {
this.data = data;
}
setError(error) {
this.error = error;
}
}
This has a few benefits. For one it gives you a lot of control over the service during execution, so you can easily customize it's behavior. And of course it's all synchronous.
Here's another example.
A common thing you will see with components is the use of ActivatedRoute and subscribing to its params. This is asynchronous, and done inside the ngOnInit. What I tend to do with this is create a mock for both the ActivatedRoute and the params property. The params property will be a mock object and have some functionality that appears to the outside world like an observable.
export class MockParams {
subscription: Subscription;
error;
constructor(private _parameters?: {[key: string]: any}) {
this.subscription = new Subscription();
spyOn(this.subscription, 'unsubscribe');
}
get params(): MockParams {
return this;
}
subscribe(next: Function, error: Function): Subscription {
if (this._parameters && !this.error) {
next(this._parameters);
}
if (this.error) {
error(this.error);
}
return this.subscription;
}
}
export class MockActivatedRoute {
constructor(public params: MockParams) {}
}
You can see we have a subscribe method that behaves like an Observable#subscribe. Another thing we do is spy on the Subscription so that we can test that it is destroyed. In most cases you will have unsubscribed inside your ngOnDestroy. To set up these mocks in your test you can just do something like
let mockParams: MockParams;
beforeEach(() => {
mockParams = new MockParams({ id: 'one' });
TestBed.configureTestingModule({
imports: [ CommonModule ],
declarations: [ TestComponent ],
providers: [
{ provide: ActivatedRoute, useValue: new MockActivatedRoute(mockParams) }
]
});
});
Now all the params are set for the route, and we have access to the mock params so we can set the error, and also check the subscription spy to make sure its been unsubscribed from.
If you look at the tests below, you will see that they are all synchronous tests. No need for async or fakeAsync, and it passes with flying colors.
Here is the complete test (using RC6)
import { Component, OnInit, OnDestroy, DebugElement } from '#angular/core';
import { CommonModule } from '#angular/common';
import { ActivatedRoute } from '#angular/router';
import { Subscription } from 'rxjs/Subscription';
import { TestBed, async } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
#Component({
template: `
<span *ngIf="id">{{ id }}</span>
<span *ngIf="error">{{ error }}</span>
`
})
export class TestComponent implements OnInit, OnDestroy {
id: string;
error: string;
subscription: Subscription;
constructor(private _route: ActivatedRoute) {}
ngOnInit() {
this.subscription = this._route.params.subscribe(
(params) => {
this.id = params['id'];
},
(error) => {
this.error = error;
}
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
export class MockParams {
subscription: Subscription;
error;
constructor(private _parameters?: {[key: string]: any}) {
this.subscription = new Subscription();
spyOn(this.subscription, 'unsubscribe');
}
get params(): MockParams {
return this;
}
subscribe(next: Function, error: Function): Subscription {
if (this._parameters && !this.error) {
next(this._parameters);
}
if (this.error) {
error(this.error);
}
return this.subscription;
}
}
export class MockActivatedRoute {
constructor(public params: MockParams) {}
}
describe('component: TestComponent', () => {
let mockParams: MockParams;
beforeEach(() => {
mockParams = new MockParams({ id: 'one' });
TestBed.configureTestingModule({
imports: [ CommonModule ],
declarations: [ TestComponent ],
providers: [
{ provide: ActivatedRoute, useValue: new MockActivatedRoute(mockParams) }
]
});
});
it('should set the id on success', () => {
let fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
let debugEl = fixture.debugElement;
let spanEls: DebugElement[] = debugEl.queryAll(By.css('span'));
expect(spanEls.length).toBe(1);
expect(spanEls[0].nativeElement.innerHTML).toBe('one');
});
it('should set the error on failure', () => {
mockParams.error = 'Something went wrong';
let fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
let debugEl = fixture.debugElement;
let spanEls: DebugElement[] = debugEl.queryAll(By.css('span'));
expect(spanEls.length).toBe(1);
expect(spanEls[0].nativeElement.innerHTML).toBe('Something went wrong');
});
it('should unsubscribe when component is destroyed', () => {
let fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
fixture.destroy();
expect(mockParams.subscription.unsubscribe).toHaveBeenCalled();
});
});
Return a Promise from #ngOnInit:
ngOnInit(): Promise<any> {
const id: number = parseInt(this._routeParams.get('id'));
return this._userService
.getUser(id)
.then(user => {
console.info(user);
this.user = user;
});
}
I ran into the same issue a few days back, and found this to be the most workable solution. As far as I can tell, it doesn't impact anywhere else in the application; since #ngOnInit has no specified return type in the source's TypeScript, I doubt anything in the source code is expecting a return value from that.
Link to OnInit: https://github.com/angular/angular/blob/2.0.0-beta.6/modules/angular2/src/core/linker/interfaces.ts#L79-L122
Edit
In your test, you'd return a new Promise:
it('should have a name', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
// Create a new Promise to allow greater control over when the test finishes
//
return new Promise((resolve, reject) => {
tcb.createAsync(UserViewComponent)
.then((rootTC) => {
// Call ngOnInit manually and put your test inside the callback
//
rootTC.debugElement.componentInstance.ngOnInit().then(() => {
spyOn(console, 'info');
let uvDOMEl = rootTC.nativeElement;
rootTC.detectChanges();
expect(console.info).toHaveBeenCalledWith(0);
expect(DOM.querySelectorAll(uvDOMEl, 'h2').length).toBe(0);
// Test is done
//
resolve();
});
});
}));
}
I had the same issue, here is how I managed to fix it. I had to use fakeAsync and tick.
fakeAsync(
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
tcb
.overrideProviders(UsersComponent, [
{ provide: UserService, useClass: MockUserService }
])
.createAsync(UsersComponent)
.then(fixture => {
fixture.autoDetectChanges(true);
let component = <UsersComponent>fixture.componentInstance;
component.ngOnInit();
flushMicrotasks();
let element = <HTMLElement>fixture.nativeElement;
let items = element.querySelectorAll('li');
console.log(items);
});
})
)