'How to test RxJs observable callback with NgRx setState
I would like to know how to test the code inside a .subscribe callback, with the subscription being on a NgRx store selector.
Environment: Angular 13, RxJs 7+, NgRx 13, Jest 27
Consider
my-component.ts
...
ngOnInit {
this.myValue = true;
this.store.select(mySelector).pipe(filter(data => data.attribute === true)).subscribe(data => {
this.myValue = false; // I want to test this
}
}
...
my-component.spec.ts
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let store: MockStore;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [MyComponent],
imports: [...],
providers: [
provideMockStore({
initialState: { myFeature: { } },
}),
],
}).compileComponents();
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
store = TestBed.inject(MockStore);
});
it('should perform animation & redirect to /dashboard if login successful', () => {
store.setState({
myFeature: {
...
attribute: true,
},
});
expect(component.myValue).toBe(false);
});
This works, but it's random. Since this is asynchronous I could test myValue before the subscribe callback has been called and the test would fail, for example if my subscribe callback takes time to do stuff, like so (I'm adding a delay of 500ms) :
...
ngOnInit {
this.myValue = true;
this.store.select(mySelector).pipe(filter(data => data.attribute === true), delay(500)).subscribe(data => {
this.myValue = false; // I want to test this
}
}
...
This fails.
How can I wait the callback to perform before testing my value ? I could wait an arbitrary time like 1 sec before testing, but it could break at any time in the future it's not robust enough. Like :
it('should perform animation & redirect to /dashboard if login successful',
async () => {
store.setState({
myFeature: {
...
attribute: true,
},
});
await lastValueFrom(timer(600)); //rxjs 7
expect(component.myValue).toBe(false);
});
Thanks for your help
Solution 1:[1]
Use waitForAsync and fixture.whenStable to ensure completion of async tasks before evaluating the expect.
it('should perform animation & redirect to /dashboard if login successful', waitForAsync(() => {
store.setState({
myFeature: {
...
attribute: true,
},
});
fixture.whenStable()
.then(() => expect(component.myValue).toBe(false));
}));
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
