I am trying to mock an Observable in orrder to test the insides of the subscribe function (I am using BehaviourSubject)
I have a dataService:
private dataSource = new BehaviorSubject(this.data);
currentData = this.dataSource.asObservable();
nextData(data){
this.dataSource.next(data);
}
and in a component there is a function i want to test
changeSelectedData() {
this.dataService.currentData.pipe(takeUntil(this.subscription))
.subscribe(sidebar => {
if (sidebar.length > 0) {
(...)
}
})
}
and this is my test configuration:
it('should go inside the if', () => {
const selectedData = {
key: 'host:1',
ip: '1',
group: {name: 'group1'}
};
const service = TestBed.inject(DataService)
const sidebar = [
{ children: [
{key: 'host:', ip: '1', group: {name: 'group1'}},
{key: 'host:', ip: '2', group: {name: 'group1'}},
{key: 'host:', ip: '3', group: {name: 'group1'}}
]
}
];
service.nextSidebarData(sidebar); <-- this line fails
component.selectedData = selectedData;
component.changeSelectedData();
expect(component.selectedData).toEqual(something);
})
when calling the function from a service, which is next() the nested object is lost, and in a result the sidebar looks like this:
sidebar = [
{children: []}
]
can anyone please help me with this one?
CodePudding user response:
Maybe you need fakeAsync/tick
to make the subscription run before your expectation.
Try this:
// !! wrap in fakeAsync
it('should go inside the if', fakeAsync(() => {
const selectedData = {
key: 'host:1',
ip: '1',
group: {name: 'group1'}
};
const service = TestBed.inject(DataService)
const sidebar = [
{ children: [
{key: 'host:', ip: '1', group: {name: 'group1'}},
{key: 'host:', ip: '2', group: {name: 'group1'}},
{key: 'host:', ip: '3', group: {name: 'group1'}}
]
}
];
service.nextSidebarData(sidebar); <-- this line fails
component.selectedData = selectedData;
component.changeSelectedData();
// !! Run tick so subscribe happens
tick();
expect(component.selectedData).toEqual(something);
}));
Also, in here, have a log and see what it logs out:
changeSelectedData() {
this.dataService.currentData.pipe(takeUntil(this.subscription))
.subscribe(sidebar => {
console.log(sidebar);
if (sidebar.length > 0) {
(...)
}
})
}
This is a good resource in how to debug unit tests: https://testing-angular.com/debugging-tests/
CodePudding user response:
thanks to the response from @AliF50 I managed to get my result.
The key was that I did't mock the BehaviourSubject, and so I added this lines inside my test, alongside the tip about fakeAsync()
and tick()
and it works now.
So here is how the test should look like at the end:
// !! wrap in fakeAsync
it('should go inside the if', fakeAsync(() => {
const selectedData = {
key: 'host:1',
ip: '1',
group: {name: 'group1'}
};
const sidebar = [
{ children: [
{key: 'host:', ip: '1', group: {name: 'group1'}},
{key: 'host:', ip: '2', group: {name: 'group1'}},
{key: 'host:', ip: '3', group: {name: 'group1'}}
]
}
];
const service = TestBed.inject(DataService);
const sidebarSourceMock = service.sidebarDataSource = new BehaviorSubject(sidebar);
const currentSidebarMock = service.currentSidebarData = sidebarSourceMock.asObservable();
service.nextSidebarData(sidebar);
component.selectedData = selectedData;
component.changeSelectedData();
// !! Run tick so subscribe happens
tick();
expect(component.selectedData).toEqual(something);
}));