I'm testing if my store selector functions are being called correctly in my ngOnInit() method, and my selectors with parameters are failing tests my selectors without parameters are passing (failing tests are commented in code sample, they are the last two). The error message Expected $[0] = Function to equal Function
isn't helpful for me. Some insight to why this might be happening or just general test debugging tips for ngrx would be appreciated.
Please let me know if any more code is needed.
Spec.ts
fdescribe('OpenOrderAddComponent', () => {
let component: OpenOrderAddComponent;
let fixture: ComponentFixture<OpenOrderAddComponent>;
const modalSpy: jasmine.Spy = jasmine.createSpyObj('ModalController', ['create']);
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [OpenOrderAddComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
provideMockStore({
initialState: INITIAL_APP_STATE()
}),
{ provide: ModalController, useValue: modalSpy },
]
}).compileComponents();
fixture = TestBed.createComponent(OpenOrderAddComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
describe('on ngOnInit', () => {
let store: any;
beforeEach(() => {
store = fixture.debugElement.injector.get(Store);
spyOn(store, 'select').and.callThrough();
component.documentId = 'fakeid';
component.ngOnInit();
fixture.detectChanges();
});
it('should call select 3 different times', () => {
expect(store.select).toHaveBeenCalledTimes(3); // succeeds
});
it('should select searched items ids', () => {
expect(store.select.calls.allArgs()[1]).toEqual([getSearchedItemsIds]) // succeeds
});
// FAILING TESTS BELOW
it('should select open order lines', () => {
expect(store.select.calls.allArgs()[2]).toEqual([getOpenOrderLines(component.documentId)])
// fails with error: Expected $[0] = Function to equal Function.
});
it('should select open order modifications', () => {
expect(store.select.calls.allArgs()[3]).toEqual([getOpenOrderModifications(component.documentId)])
// fails with error: Expected $[0] = Function to equal Function.
});
});
});
component.ts ngOnInit() code
ngOnInit(){
this.itemIds$ = this.store.select(getSearchedItemsIds);
this.store.select(getOpenOrderLines(this.documentId)).subscribe(openOrderLines => {...});
this.store.select(getOpenOrderModifications(this.documentId)).subscribe(orderModifications =>{...});
}
selectors
export const getSearchedItemsIds = createSelector(
selectSearch,
selectItems,
selectCartLines,
(searchState, items): string[] => {
return searchState.search
.map((itemId: string) => items[itemId].ItemID);
}
);
export const getOpenOrderLines = (documentId: string) => createSelector(
selectOpenOrderItems(documentId),
(orderItems?: OpenOrderItem[]) => {
return orderItems ? orderItems : undefined;
}
);
export const getOpenOrderModifications = (documentId: string) => createSelector(
selectOrderModifications(documentId),
(orderModifications: OpenOrderModification[]) => {
return orderModifications;
}
);
I would do something like this, !! is placed for stuff that requires your attention:
fdescribe('OpenOrderAddComponent', () => {
let component: OpenOrderAddComponent;
let fixture: ComponentFixture<OpenOrderAddComponent>;
const modalSpy: jasmine.Spy = jasmine.createSpyObj('ModalController', ['create']);
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [OpenOrderAddComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
provideMockStore({
initialState: INITIAL_APP_STATE()
}),
{ provide: ModalController, useValue: modalSpy },
]
}).compileComponents();
fixture = TestBed.createComponent(OpenOrderAddComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
describe('on ngOnInit', () => {
let store: any;
beforeEach(() => {
store = fixture.debugElement.injector.get(Store);
spyOn(store, 'select').and.callThrough();
component.documentId = 'fakeid';
// component.ngOnInit(); => No need to call `ngOnInit here, the `fixture.detechChanges() below does it for you. Calling it twice can make your assertions fail.
fixture.detectChanges();
});
it('should call select 3 different times', () => {
expect(store.select).toHaveBeenCalledTimes(3); // succeeds
});
it('should select searched items ids', () => {
expect(store.select.calls.allArgs()[1]).toEqual([getSearchedItemsIds]) // succeeds
});
// FAILING TESTS BELOW
it('should select open order lines', () => {
expect(store.select).toHaveBeenCalledWith(getOpenOrderLines(component.documentId));
// !! ^^
// fails with error: Expected $[0] = Function to equal Function.
});
it('should select open order modifications', () => {
expect(store.select).toHaveBeenCalledWith(getOpenOrderModifications(component.documentId));
// ^^
// fails with error: Expected $[0] = Function to equal Function.
});
});
});
But I wouldn't be asserting that store.select
was called with this or that argument. I would be testing what goes on in the subscribe
block of each select
.