Reputation: 203
Here is the testbed setup. Mocking and providing everything needed:
let component: PageUploadContainer;
let store;
let route;
let fixture: ComponentFixture<PageUploadContainer>;
const sanitizer = jasmine.createSpyObj('sanitizer', ['bypassSecurityTrustResourceUrl']);
sanitizer.bypassSecurityTrustResourceUrl.and.callFake(url => url);
const mockTranslate = {
instant: label => label,
};
beforeEach(() => {
store = createMockStore<AppState>(reducers);
route = new MockActivatedRoute();
});
beforeEach(() => {
TestBed.configureTestingModule({
imports: [translationModule],
declarations: [
PageUploadContainer,
MockTranslatePipe,
MockTranslateCutPipe,
],
schemas: [NO_ERRORS_SCHEMA],
providers: [
FormBuilder,
{ provide: DomSanitizer, useValue: sanitizer },
{ provide: Store, useValue: store },
{ provide: ActivatedRoute, useValue: route },
{ provide: TranslateService, useFactory: () => mockTranslate },
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PageUploadContainer);
component = fixture.componentInstance;
component.mappingTriggered$ = Observable.of(false);
});
I have the following code, I set up me tests with testBed:
onGoTo(uploadStep: string) {
if (uploadStep === NAVIGATION.DEFAULT) {
this.store.dispatch(new ReplaceSelectedCompanies([]));
this.companyIds$.filter(isEmpty)
.take(1)
.subscribe(() => {
this.store.dispatch(new Navigate({ direction: uploadStep}));
});
} else {
this.store.dispatch(new Navigate({ direction: uploadStep}));
}
}
And my test. This test fails due to new Navigate({ direction: uploadStep})
was not called due to it's asynchronous nature
it('if navigation default and companyIds empty should call navigate', () => {
component.companyIds$ = Observable.of(['123', '234']);
component.onGoTo(NAVIGATION.DEFAULT);
expect(store.dispatch).toHaveBeenCalledWith(new ReplaceSelectedCompanies([]));
expect(store.dispatch).toHaveBeenCalledWith(new Navigate({ direction: NAVIGATION.DEFAULT }));
});
Can you help me how to test such methods?
Upvotes: 2
Views: 9362
Reputation: 6826
Although I am not certain, you might need to just import the async
method provided by angular.
General Example
it("description", async( /* function */ ));
Your Code
import { async } from "@angular/core/testing";
it('if navigation default and companyIds empty should call navigate', async(() => {
component.companyIds$ = Observable.of(['123', '234']);
component.onGoTo(NAVIGATION.DEFAULT);
expect(store.dispatch)
.toHaveBeenCalledWith(new ReplaceSelectedCompanies([]));
expect(store.dispatch)
.toHaveBeenCalledWith(new Navigate({ direction: NAVIGATION.DEFAULT }));
}));
Recommendations
First, I would watch this video about angular 6 asynchronous unit tests. The whole unit test series is good too.
You have a lot of custom-ly mocked classes so I can't comment much on that. I do recommend using RouterTestingModule.withRoutes({ /* test routes */ })
. Here's another video in that series that talks about the RouterTestingModule.
Then, you could always get the mocked router like router = TestBed.get(Router)
or other objects created by the RouterTestingModule
.
Upvotes: 2
Reputation: 14149
You can create asynchronous Jasmine tests by calling done()
after your tested code has executed completely. You get the done
function passed as an argument from the test spec, like that:
it('if navigation default and companyIds empty should call navigate', (done) => {
...
});
However, you wouldn't know in your test code when the code has executed completely. I'd suggest returning a Promise from `onGoTo. It could look like that:
onGoTo(uploadStep: string): Promise<void> {
if (uploadStep === NAVIGATION.DEFAULT) {
this.store.dispatch(new ReplaceSelectedCompanies([]));
return new Promise(resolve => this.companyIds$.filter(isEmpty)
.take(1)
.subscribe(() => {
this.store.dispatch(new Navigate({ direction: uploadStep}));
resolve();
}));
} else {
this.store.dispatch(new Navigate({ direction: uploadStep}));
return Promise.resolve();
}
}
Then, modify your test code like that:
it('if navigation default and companyIds empty should call navigate', (done) => {
component.companyIds$ = Observable.of(['123', '234']);
component.onGoTo(NAVIGATION.DEFAULT).then(() => {
expect(store.dispatch).toHaveBeenCalledWith(new ReplaceSelectedCompanies([]));
expect(store.dispatch).toHaveBeenCalledWith(new Navigate({ direction: NAVIGATION.DEFAULT }));
done()});
});
Upvotes: 0