I’m trying to test an angular service.
Another service provides an observable on which this service needs to react, start some parallel HTTP requests and do something with them.
I’m struggling to test them.
Here is a working dummy test of exactly what I’m trying to achieve:
import { HttpClient, provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { Injectable } from '@angular/core';
import { fakeAsync, flush, TestBed } from '@angular/core/testing';
import { createSpyFromClass, Spy } from 'jest-auto-spies';
import { firstValueFrom, Subject, Subscription, tap } from 'rxjs';
describe('Testings tests', () => {
let httpTestingController!: HttpTestingController;
let someSourceOfDataMock: Spy<SomeSourceOfData>;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{
provide: SomeSourceOfData,
useValue: createSpyFromClass(SomeSourceOfData, { observablePropsToSpyOn: ['latestInfo'] }),
},
provideHttpClient(),
provideHttpClientTesting(),
DummyTest,
],
}).compileComponents();
someSourceOfDataMock = TestBed.inject<any>(SomeSourceOfData);
});
fit('Should request data', fakeAsync(() => {
//Arrange
httpTestingController = TestBed.inject(HttpTestingController);
let dummyTest = TestBed.inject(DummyTest);
//Act
someSourceOfDataMock.latestInfo.nextWith('go go go');
flush();
//Assert
const request = httpTestingController.expectOne('https://google.com');
expect(request.request.method).toBe('GET');
request.flush({});
const requestTwo = httpTestingController.expectOne('https://yahoo.com');
expect(requestTwo.request.method).toBe('GET');
requestTwo.flush({});
httpTestingController.verify();
dummyTest.Dispose();
}));
});
@Injectable({
providedIn: 'root',
})
export class DummyTest {
subscription: Subscription;
constructor(
private httpClient: HttpClient,
someSourceOfData: SomeSourceOfData
) {
this.subscription = someSourceOfData.latestInfo
.pipe(tap(info => console.log('pipe: data received', info)))
.subscribe(info => async () => {
console.log('subscription: info received', info);
await this.TestRequest();
});
}
public Dispose() {
this.subscription.unsubscribe();
}
private async TestRequest() {
console.log('Refreshing request');
const [googleResponse, yahooResponse] = await Promise.all([
firstValueFrom(this.httpClient.get('https://google.com')),
firstValueFrom(this.httpClient.get('https://yahoo.com')),
]);
//.... Do something with the result which will get asserted.
}
}
export class SomeSourceOfData {
private _dataSource = new Subject<string>();
public latestInfo = this._dataSource.asObservable();
}
My current issue is that the Pipe: data received
is reached, but not the subscription: info received
(and obviously, the TestRequest
method is not called, and therefor, the test fails).
I tried to use fakeasync
+flush
to ensure the micro-tasks were executed, but I get the same result. I also tried to use tick
.
It goes without saying, but the actual code that uses this do work.