Issue
I'm trying to understand how I can test if observation$
is updated as well as _observations
.
//This is the function I want to test
public createNewOdour(odour: OdourCreateForm): Observable<ObservationRes> {
return this.http
.post<ObservationRes>(
`${environment.BACKEND_BASE_URL}api/observations`,
{ ...odour },
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
withCredentials: true,
},
)
.pipe(
tap(({ data }) => {
this.observation$.next(data[0]);
const currObservations = this._observations.getValue();
this.updateObservations([...currObservations, data[0]]);
}),
);
}
describe('OdourService', () => {
let service: OdourService;
let httpMock: jest.Mocked<HttpClient>;
const observation$ = new Subject<Observation>();
beforeEach(() => {
httpMock = {
get: jest.fn(),
post: jest.fn(),
} as unknown as jest.Mocked<HttpClient>;
service = new OdourService(httpMock);
});
[......]
//This is the test:
it('createNewOdour() updates the observation$ Subject and _observations BehaviorSubject', (done) => {
httpMock.post.mockReturnValueOnce(
of({ status: 'success', data: [observationsMock[0]] }),
);
// Mock the observation$ and _observations Observables
service.observation$ = observation$;
service.createNewOdour(odourCreateFormMock).subscribe((res) => {
// Check if observation$ and _observations have the expected value
service.observation$.subscribe((observationValue) => {
expect(observationValue).toEqual(null)//The tests pass and it shouldn't
done()
});
done()
});
});
I want to check if observation$
subject is updated with HTTP response. I'm expecting to res.data[0]
to be the same as observationValue
but nothing happens. Now it's equal to null and the test still passes when it shouldn't.
UPDATE:
Now I'm subscribing to the service Subject and not mocking it. What It works it's been that I'm subscribing it before call the function that updates it. Any better solution?
` it('createNewOdour() updates the observation$ Subject', () => {
httpMock.post.mockReturnValueOnce(
of({ status: 'success', data: [observationsMock[0]] }),
);
// Check if observation$ have the expected value
service.observation$.subscribe((observationValue) => {
expect(observationValue.id).toEqual(observationsMock[0].id);
});
service.createNewOdour(odourCreateFormMock).subscribe();
});`
Solution
The test is just a few lines of code, but with subscriptions it's a bit all over the place. In test setups like this, it's often not obvious if the subscription is asynchronous or not, or if the assertions run at all. That's why I don't like to subscribe in tests and use a promise instead. And in most cases it's a one-shot anyways, or you can use toArray()
if you expect multiple values.
So I would write the test like that:
it('should update the observation$ subject', async () => {
// [Mock setup here]
const obs = service.createNewOdour(odourCreateFormMock)
.pipe(switchMap(() => service.observation$));
const result = await firstValueFrom(obs);
expect(result.id).toEqual(observationsMock[0].id);
});
observation$
should be a BehaviorSubject, so that the time of subscription doesn't matter.
Answered By - Bastian Bräu
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.