I have the following test
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let loader: HarnessLoader;
const items: MyItem[] = [
{
id: '66249535-31bf-41f3-8f55-8a14877c6d7e',
status: 'New'
}
];
const myServiceSpy = jasmine.createSpyObj<MyService>(
'MyService',
{
getItems: of(items),
changeItemStatus: of()
}
);
const alertsServiceSpy = jasmine.createSpyObj<AlertsService>('AlertsService', [
'error',
'warning',
'success',
'info'
]);
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyComponent, TableComponent],
providers: [{ provide: MyService, useValue: myServiceSpy }, { provide: AlertsService, useValue: alertsServiceSpy}],
imports: [MatTableModule, SharedModule]
}).compileComponents();
}));
beforeEach(() => {
myServiceSpy.getItems.calls.reset();
fixture = TestBed.createComponent(MyComponent);
loader = TestbedHarnessEnvironment.loader(fixture);
component = fixture.componentInstance;
component.myId = 123;
fixture.detectChanges();
});
afterAll(() => {
myServiceSpy.getItems.and.returnValue(of(items));
});
it('should call to change the item status if the slider is toggled', async(() => {
component.onItemChange(items[0], { checked: true, event: { source: { checked: true }}});
component.onItemChange(items[0], { checked: false, event: { source: { checked: false }}});
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(myServiceSpy.changeItemStatus).toHaveBeenCalled();
});
}));
And the following component
ngOnInit() {
const updatedItems$ = this.itemChangeSubject.asObservable().pipe(
switchMap(itemChange => {
this.itemBeingChanged = itemChange.item;
this.toggleEvent = itemChange.event;
return this.myService.changeItemStatus(
this.myId,
itemChange.item.id
)
.pipe(catchError(() => {
this.clicked = false;
this.toggleEvent.source.checked = ! this.toggleEvent.source.checked;
return empty();
}));
}),
tap({
next: () => {
const itemStatus = this.itemBeingChanged.isItemChanged ? 'active' : new';
this.clicked = false;
this.alerts.success({
message: `Item is now ${itemStatus}.`
});
}
}),
switchMap(() => this.myService.getItems(
this.myId
)
.pipe(catchError(() => {
return empty();
}))
)
);
this.items$ = this.myService
.getItems(this.myId)
.pipe(catchError(() => {
return empty();
}))
.pipe(concat(updatedItems$))
}
onItemChange(item: MyItem, event) {
this.itemChangeSubject.next({ item, event });
}
My test executes the first switchMap
within the ngOnInit
as expected, however neither the tap side effect or the following switchMap is executed. How can I modify my test so I can test this entire chain, rather than just the first switchMap
? Additionally, is it necessary to even test the tap or error blocks? I'm mostly concerned about the final switchMap since it does make a call to a service.
I think it's due to changeItemStatus: of()
.
of
is defined as follows:
return fromArray(args as T[]);
which will eventually reach subscribeToArray
:
export const subscribeToArray = <T>(array: ArrayLike<T>) => (subscriber: Subscriber<T>) => {
for (let i = 0, len = array.length; i < len && !subscriber.closed; i++) {
subscriber.next(array[i]);
}
subscriber.complete();
};
So, when using of()
the array
from above will be empty, which means that the Observable won't emit anything. As a result, the next operators in the chain won't be reached.
It should work if you replace of()
with of(null)
.