Reputation: 13367
I am trying to understand rxjs Subscriptions, Observables, etc, but it is foreign to me. I have a service with a method I subscribe to. The method looks like this:
create(product: any): Observable<any> {
return this.http.post<any>(`${environment.apiUrl}/products`, product).pipe(
map((response: any) => {
this.toastr.success(response.message);
return response.model;
}),
);
}
Then I have a save method in my component and for the tests I want to get the returned model. So I did this:
onSubmit(): Observable<any> {
this.submitted = true;
if (this.saveForm.invalid) return;
let valid = true;
let categoryId = this.fields[0].categoryId;
let product = {
categoryId: categoryId,
};
this.fields.forEach(field => {
let value = this.f[field.name].value;
if (valid) {
valid = value !== undefined;
}
product[field.name] = value;
});
product['state'] = valid ? 'verified' : 'raw';
var response = new Subject<any>();
this.productService.create(product).subscribe(data => {
response.next(data);
});
return response.asObservable();
}
In my test, I wrote this:
it('should save a product and remove from range', () => {
let component = spectator.component;
component.onSubmit().subscribe(product => {
expect(product.gtin).toBe(0);
expect(product.state).toBe('verified');
console.log(product);
});
expect(component.range.length).toBe(1);
expect(component.saveForm.controls['gtin'].value).toBe(1);
});
I am guessing I have done it wrong. The test passes, but I think that's because subscribe is never reached. Can someone tell me what I need to do?
Upvotes: 1
Views: 1234
Reputation: 9124
Instead of
var response = new Subject<any>();
this.productService.create(product).subscribe(data => {
response.next(data);
});
return response.asObservable();
Just do
return this.productService.create(product);
Upvotes: 1
Reputation: 6250
Your assumption is correct, the subscribe body is never called in your test... as the observable would not yield.
You need to change the test like this:
let httpTestingController: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule, // <== very important to mock the request
],
});
(...)
httpTestingController = TestBed.get(HttpTestingController);
});
it('should save a product and remove from range', async done => {
let component = spectator.component;
component.onSubmit().subscribe(product => {
expect(product.gtin).toBe(0);
expect(product.state).toBe('verified');
console.log(product);
done();
});
expect(component.range.length).toBe(1);
expect(component.saveForm.controls['gtin'].value).toBe(1);
//This part simulates the backend responding your .onSubmit() call:
const testProductData = {your_atributes} // <== this should be what you expect to receive from the backend;
const mockRequest = httpTestingController.expectOne(`${environment.apiUrl}/products`);
mockRequest.flush(testProductData); // <== this call will make your observable respond.
});
This done
callback in the test is what will make your test work for asynchronous tests requirements like yours. The test fails when the subscription body is not called.
Upvotes: 0