I want to test an Angular service which contains my logic. I will simplify my case in order to make it straightforward :
I have logic$ which is what I want to test, it is bound to data$, another observable
@Injectable({
providedIn: 'root',
})
export class MyService {
readonly data = new BehaviorSubject<string>('');
readonly data$ = this.data.asObservable();
readonly logic$ = this.data$.pipe(
map((logic: string) => `Mighty ${logic}`)
)
constructor() {}
}
I want to be able to mock the data in my test and see if my logic is behaving as intended
describe('MyService', () => {
let myService: MyService;
const testScheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
beforeEach(() => {
myService = new MyService();
myService.data$ = of("foo", "bar");
TestBed.configureTestingModule({
providers: [{ provide: MyService, useValue: myService }]
});
});
it('should be created', inject([MyService], (service: MyService) => {
expect(service).toBeTruthy();
}));
it('should be toto lala', inject([MyService], (service: MyService) => {
testScheduler.run(helpers => {
const { expectObservable, cold } = helpers;
const expect$ = "ab";
expectObservable(service.logic$).toBe(expect$, {
a: "Mighty foo",
b: "Mighty bar",
})
});
}));
});
I'm getting the following error :
Chrome Headless 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
Error: Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
at <Jasmine>
at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
at node_modules/rxjs/_esm2015/internal/testing/TestScheduler.js:110:1
at <Jasmine>
Chrome Headless 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (0 secs / 0.028 secs)
Chrome Headless 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
Error: Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
at <Jasmine>
at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
at node_modules/rxjs/_esm2015/internal/testing/TestScheduler.js:110:1
Chrome 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
Error: Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
at <Jasmine>
at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
at node_modules/rxjs/_esm2015/internal/testing/TestScheduler.js:110:1
at <Jasmine>
Chrome Headless 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (skipped 1) (0.097 secs / 0.028 secs)
Chrome 97.0.4692.99 (Windows 10): Executed 1 of 3 (1 FAILED) (0 secs / 0.019 secs)
Chrome 97.0.4692.99 (Windows 10) MyService should be toto lala FAILED
Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
Error: Expected $.length = 1 to equal 2.
Expected $[0].notification.value = 'Mighty ' to equal 'Mighty foo'.
Expected $[1] = undefined to equal Object({ frame: 1, notification: Notification({ kind: 'N', value: 'Mighty bar', error: undefined, hasValue: true }) }).
at <Jasmine>
at TestScheduler.assertDeepEqual (projects/ui-affaire-client/src/lib/components/my-component/my-component.service.spec.ts:11:20)
Chrome Headless 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (skipped 1) (0.097 secs / 0.028 secs)
Chrome 97.0.4692.99 (Windows 10): Executed 2 of 3 (1 FAILED) (skipped 1) (0.099 secs / 0.026 secs)
TOTAL: 2 FAILED, 2 SUCCESS
TOTAL: 2 FAILED, 2 SUCCESS
For what I can understand, visibly my mock is not working. logic$ has a length of 1 and the data emits only '' (which is emitted by the behaviorSubject) My guess is that my mock is done after the creation of the service and therefore, the "old" observables are still used and not replaced.
Is there a way to properly replace observables to test logic in a service ?