I want to unit test a component. I am using @ngrx/store and rxjs in order to update my store from my component. To do that, I subscribe and unsubscribe to a store. My unit test is failing with
TypeError: undefined is not an object (evaluating 'this.store.unsubscribe') in config/spec-bundle.js
I am not able to find how to correctly mock my store and its event emitters.
Here are the following lines:
app.component.ts :
ngOnDestroy() {
// unsubscribe the observable
this.userStore.unsubscribe();
}
app.component.spec.ts :
how I mock the store :
export class MockStore extends Subject<fromRoot.State> implements Store <fromRoot.State> {}
how I configure :
TestBed.configureTestingModule({
imports: [
FormsModule,
ReactiveFormsModule,
StoreModule.provideStore(reducer)
],
declarations: [LoginComponent],
providers: [
BaseRequestOptions,
MockBackend,
{ provide: AuthService, useValue: authServiceStub },
{ provide: LoginService, useValue: loginServiceStub },
{ provide: LoggerService, useValue: loggerServiceStub },
{
provide: Http, useFactory: (backend: ConnectionBackend,
defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}, deps: [MockBackend, BaseRequestOptions]
},
{ provide: Router, useClass: MockRouter }
]
})
Tell me if you want more informations. Thanks in advance.
There's more than one way that you can mock the store and what you do is going to depend upon how you want to test.
When I mock the store in my tests, I'm only interested in two things:
I'm not interested in wiring up reducers, as they are tested elsewhere, so this is what I do.
I use a function like this to create a Store
from two Subject
instances:
import { Action, Store } from "@ngrx/store";
import { Subject } from "rxjs/Subject";
export function mockStore<T>({
actions = new Subject<Action>(),
states = new Subject<T>()
}: {
actions?: Subject<Action>,
states?: Subject<T>
}): Store<T> {
let result = states as any;
result.dispatch = (action: Action) => actions.next(action);
return result;
}
And in a beforeEach
I create the Store
and add it to the TestBed
's providers
:
actions = new Subject<Action>();
states = new Subject<AppState>();
store = mockStore<AppState>({ actions, states });
TestBed.configureTestingModule({
imports: [EffectsTestingModule],
providers: [
{
provide: Store,
useValue: store
},
...
]
});
With the mocked Store
injected in the components - or effects, or whatever you are testing - it's then simple to emit a particular state within a test - using the states
subject - and it's easy to check to see that any expected actions have been dispatched - by subscribing to the actions
subject.
Regarding your error, you should not be calling unsubscribe
on the Store
; you should call it on the Subscription
object that's returned when you subscribe to the store - as mentioned in the other answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With