I'm currently utilizing NGXS in my Angular application for state management. As part of my development process, I am now focusing on implementing Unit Tests for NGXS async actions. Here is a snippet of the code that I have been working on:
schedule.service.ts
public getSchedulesByOrgIdAndJobRefId(orgId: string, jobRefId: string): Observable<Schedule[]> {
const url = 'http://localhost:5000/api/v1/schedules';
return this.httpClient.get<Schedule[]>(url);
}
and within the action section of schedule.state.ts
@Action(LoadSchedulesAction)
loadSchedules({patchState, getState}: StateContext<ScheduleStateModel>,
{orgId, jobRefId}: LoadSchedulesAction) {
return this.scheduleService.getSchedulesByOrgIdAndJobRefId(orgId, jobRefId)
.pipe(
map((schedules: Schedule[]) => { // convert to a map
return schedules.reduce((prev: EntityMap<string, Schedule>, curr: Schedule) => {
prev[curr.id] = curr;
return prev;
}, {});
}),
tap((schedulesMap: EntityMap<string, Schedule>) => {
const existingSchedules = getState().schedules;
patchState({schedules: {...existingSchedules, ...schedulesMap}});
})
);
}
While the action functions as expected, I have encountered challenges when it comes to Unit Testing such HTTP async actions. There seems to be a lack of documentation or resources addressing this specific scenario. Below is an excerpt from one of my test cases that aims to test the aforementioned action:
schedule.state.spec.tstestSchedules = [...Array(5).keys()].map((cd, i: number) => {
return {
orgId,
containerId: `CCD-${i}`,
jobRefId,
jobTitle: `Test Job ${i}`,
};
});
describe('Actions', () => {
it('should load and schedules for specific job File', async () => {
spyOn(scheduleService, 'getSchedulesByOrgIdAndJobRefId')
.and.returnValue(of(testSchedules));
await store.dispatch(new LoadSchedulesAction(orgId, jobRefId)).toPromise();
expect(scheduleService.getSchedulesByOrgIdAndJobRefId).toHaveBeenCalled();
const scheduleState = store.selectSnapshot((state) => state.schedulesState);
// using a util method testSchedules converted to a Map type schedulesMap
expect(scheduleState.schedules).toEqual(schedulesMap);
});
});
The issue at hand is that scheduleState.schedules consistently returns an empty object during testing. Interestingly enough, if we were to subscribe directly to the service call within the loadSchedules() function, the expected value would be returned. However, it is generally discouraged to subscribe to service calls within an Action implementation.
If anyone has insights on how to effectively Unit Test this particular type of action in NGXS, or if there are any details I might have overlooked, I welcome your expertise and advice.