Using Angular 16 and Jasmine/Karma.
I have this subscription to a behavior subject called tableList$
ngOnInit() {
const { pageNumber } = this.subscribersService.getMiscValues();
this.subscribersService.initPage(pageNumber);
>> this.subscribersService.tableList$.subscribe((tableList) => {
// this.tableList = this.deleteSubscribersService.setDeleteCheckboxStates(tableList);
});
}
I am trying to mock the behavior subject, but I am getting this.subscribersService.tableList$.subscribe is not a function
.
Any ideas what I am doing wrong, please?
Note, I also have tried subscribersServiceMock.tableList$.and.returnValue({ subscribe: () => tableListMock$.subscribe });
to no success
fdescribe('ManageSubscribersComponent', () => {
let component: ManageSubscribersComponent;
let fixture: ComponentFixture<ManageSubscribersComponent>;
let miscMockValues;
let tableMockData;
let tableListMock$;
let dialogServiceMock
let dialogSubjectMock;
let subscribersServiceMock;
let deleteSubscribersServiceMock;
const displayedColumns = [
'id',
'name',
'description',
'createdBy',
'createdOn',
'updatedBy',
'updatedOn',
];
beforeEach(() => {
tableListMock$ = new Subject();
dialogSubjectMock = new Subject();
dialogServiceMock = jasmine.createSpyObj([
'open',
'afterClosed',
]);
deleteSubscribersServiceMock = jasmine.createSpyObj([
'deleteSubscribers',
]);
subscribersServiceMock = jasmine.createSpyObj([
'resetMiscValues',
'getMiscValues',
'initPage',
'tableList$',
]);
miscMockValues = {
pageNumber: 1,
pageSize: 25,
sort: '',
active: true,
testMode: false,
searchTerms: '',
};
subscribersServiceMock.getMiscValues.and.returnValue(miscMockValues);
subscribersServiceMock.tableList$.and.returnValue(tableListMock$);
dialogServiceMock.afterClosed.and.returnValue(dialogSubjectMock);
TestBed.configureTestingModule({
declarations: [ManageSubscribersComponent],
imports: [
HttpClientTestingModule,
MatFormFieldModule,
MatIconModule,
MatSliderModule,
MatTableModule,
MatFormFieldModule,
MatInputModule,
BrowserAnimationsModule,
MatPaginatorModule,
MatDialogModule,
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
NO_ERRORS_SCHEMA,
],
providers: [
{
provide: SubscribersService,
useValue: subscribersServiceMock,
},
{
provide: DeleteSubscribersService,
useValue: deleteSubscribersServiceMock,
},
],
});
fixture = TestBed.createComponent(ManageSubscribersComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
fit('should init', fakeAsync(() => {
fixture.whenStable().then(() => {
expect(component.displayedColumns).toEqual(displayedColumns);
expect(subscribersServiceMock.getMiscValues).toHaveBeenCalled();
})
}));
As stated in comments the issue lies on the test setup
When setting up the SubscribersService
mock by doing
subscribersServiceMock = jasmine.createSpyObj([
'resetMiscValues',
'getMiscValues',
'initPage',
'tableList$',
]);
Those names in the array will be methods to create spies for as per createSpyObj
docs
However, SubscribersService
uses tableList$
as a property. Because it does this.tableList$
as it's some kind of observable object and doesn't call it like you would do with a method: this.tableList$()
.
If you want to create an object with your tableListMock
subject for the tableList$
property, you can use the next optional argument for createSpyObj
:
subscribersServiceMock = jasmine.createSpyObj([
'resetMiscValues',
'getMiscValues',
'initPage',
], { tableList$: tableListMock$ });
As createSpyObj
docs state, the last argument can define properties to creates spies for. Or an object to actually define properties with their values in the object.
You can also pass an array of method names:
subscribersServiceMock = jasmine.createSpyObj([
'resetMiscValues',
'getMiscValues',
'initPage',
'tableList$',
], ['tableList$']);
Then, spies will be created for the property accessor. This way you'll be able to spy when tableList$
is get
or set
.
Here's how you'd configure the get
spy so that subscribersServiceMock.tableList$
returns the mock subject:
subscribersServiceMock = jasmine.createSpyObj(
[
// method names as ususal
],
['tableList$']
);
const tableList$GetterSpy = Object.getOwnPropertyDescriptor(
subscribersServiceMock,
'tableList$',
)!.get as jasmine.Spy
tableList$GetterSpy.and.returnValue(mockTableList$)
A bit cumbersome if you just want to set the value, previous way of passing an object is shorter. Though this way you can verify if tableList$
was accessed by using the spy:
expect(tableList$Getter).toHaveBeenCalled()