I am testing an angular/NgRx application and I am facing difficulties overriding the Store with the angular TestBed.
Please note that for the purpose of this test suite, I cannot rely on the provideMockStore utility. I have to use the actual Store.
Here is the global test setup in the top-level describe:
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
SmartRecoRecommendationComponent,
...
],
imports: [
...
StoreModule.forRoot({
products: productsReducer,
...
}),
StoreModule.forFeature(smartRecoFeatureKey, {
...fromSmartReco.reducers,
recommendation: (
state: {
products: ProductRecommendation[];
} | null = smartRecoStateMock.recommendation,
type: Action
) => fromSmartReco.reducers.recommendation(state, type),
...
Here is how I try to override the Store import in a local describe:
beforeEach(async () => {
TestBed.overrideModule(StoreModule, {
remove: {
imports: [StoreModule.forRoot({}), StoreModule.forFeature(smartRecoFeatureKey, {})],
},
add: {
imports: [
StoreModule.forRoot({
products: productsReducer,
...
}),
StoreModule.forFeature(smartRecoFeatureKey, {
...fromSmartReco.reducers,
recommendationErrorType: (state: ProductRecommendationErrorTypes = ProductRecommendationErrorTypes.TECHNICAL, type: Action) =>
}),
],
},
});
await TestBed.compileComponents();
...
However, the Store is not overridden by the local setup... Only the global setup is taken into account.
The documentation about overriding providers or modules is scarce and I am not sure what I got wrong. Can someone please help?
TestBed.overrideModuleis used for overriding metadata (an object passed to@NgModuledecorator) of a certain module used for setting up a TestBed. So the callTestBed.overrideModule(StoreModule, ...)overrides StoreModule's imports but what you need instead is to override the imports of the module created withTestBed.configureTestingModule. It seems that there is no way to do it (more info at the end of the answer), but there are other ways to achieve the same result.TestBed.configureTestingModulein nested beforeEach or even as part ofit. That is it, you don't have to have only 1 configuration in the top-levelbeforeEach. The most obvious downside of this approach is that you may have a lot of duplication, but it is always possible to extractimports,providers, and other parts into arrays, or create your own wrapper aroundTestBed.configureTestingModule:TestBed.override*methods. For example,TestBed.overrideProvidercan be used for overriding a provider:This way it should be possible to override certain providers, provided by
StoreModule, but it may be quite hard to understand what exactly should be overridden, asStoreModuleuses a lot of providers.About "It seems that there is no way to do it". Among other things
TestBed.configureTestingModuledoes under the hood, it creates a module and a reference to this module is accessible via private fields:(TestBed as any).INSTANCE.testModuleRef, but as long as module metadata is passed through a decorator, at the time a reference to a module exists it is too late to override it. Because of the same reason, calls toTestBed.override*should be done before the test module is instantiated.