在我们的应用程序中,我们有一个简单的商店,在根级别包含 anAuthState
和 a RouterState
。RouterState
是通过@ngrx/router-store
方法创建的。
我们有一些选择器必须使用 RouterState 来检索例如一个参数,然后将它与其他选择器结果结合起来。
我们的问题是我们无法找到正确设置测试套件以测试此类组合选择器的方法。
减速机设置
应用模块导入
StoreModule.forRoot(reducers, { metaReducers }),
StoreRouterConnectingModule.forRoot({
stateKey: 'router',
}),
StoreDevtoolsModule.instrument(),
reducers
如下:
减速机
export interface RouterStateUrl {
url: string;
queryParams: Params;
params: Params;
}
export interface State {
router: fromNgrxRouter.RouterReducerState<RouterStateUrl>;
auth: fromAuth.AuthState;
}
export const reducers: ActionReducerMap<State> = {
router: fromNgrxRouter.routerReducer,
auth: fromAuth.reducer,
};
export const getRouterState = createFeatureSelector<fromNgrxRouter.RouterReducerState<RouterStateUrl>>('router');
export const getRouterStateUrl = createSelector(
getRouterState,
(routerState: fromNgrxRouter.RouterReducerState<RouterStateUrl>) => routerState.state
);
export const isSomeIdParamValid = createSelector(
getRouterState,
(routerS) => {
return routerS.state.params && routerS.state.params.someId;
}
);
这是 AuthState 减速器:
export interface AuthState {
loggedIn: boolean;
}
export const initialState: AuthState = {
loggedIn: false,
};
export function reducer(
state = initialState,
action: Action
): AuthState {
switch (action.type) {
default: {
return state;
}
}
}
export const getAuthState = createFeatureSelector<AuthState>('auth');
export const getIsLoggedIn = createSelector(
getAuthState,
(authState: AuthState) => {
return authState.loggedIn;
}
);
export const getMixedSelection = createSelector(
isSomeIdParamValid,
getIsLoggedIn,
(paramValid, isLoggedIn) => paramValid && isLoggedIn
)
测试设置
@Component({
template: ``
})
class ListMockComponent {}
describe('Router Selectors', () => {
let store: Store<State>;
let router: Router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([{
path: 'list/:someId',
component: ListMockComponent
}]),
StoreModule.forRoot({
// How to add auth at that level
router: combineReducers(reducers)
}),
StoreRouterConnectingModule.forRoot({
stateKey: 'router',
}),
],
declarations: [ListMockComponent],
});
store = TestBed.get(Store);
router = TestBed.get(Router);
});
测试及其结果
测试 1
it('should retrieve routerState', () => {
router.navigateByUrl('/list/123');
store.select(getRouterState).subscribe(routerState => console.log(routerState));
});
{路由器:{状态:{url:'/list/123',参数:{someId:123},queryParams:{}},navigationId:1},身份验证:{loggedIn:false}}
如您所见,getRouterState
选择器不仅检索router
状态切片,而且检索包含整个routerState
+的对象authState
State
。router 和 auth 是这个对象的子对象。因此选择器无法检索正确的切片。
测试 2
it('should retrieve routerStateUrl', () => {
router.navigateByUrl('/list/123');
store.select(getRouterStateUrl).subscribe(value => console.log(value));
});
未定义 - 类型错误:无法读取未定义的属性“状态”
测试 3
it('should retrieve mixed selector results', () => {
router.navigateByUrl('/list/123');
store.select(getMixedSelection).subscribe(value => console.log(value));
});
不明确的
TypeError:无法读取未定义的属性“状态”
类型错误:无法读取 {auth: {}、路由器:{}} 的属性“loggedIn”
笔记
请注意语法
StoreModule.forRoot({
// How to add auth at that level
router: combineReducers(reducers)
}),
如果我们想使用多个 reducer 组合选择器,这似乎是强制性的。我们可以只使用forRoot(reducers)
,但我们不能只测试路由器选择器。州的其他部分将不存在。
例如,如果我们需要测试:
export const getMixedSelection = createSelector(
isSomeIdParamValid,
getIsLoggedIn,
(paramValid, isLoggedIn) => paramValid && isLoggedIn
)
我们需要路由器和身份验证。而且我们找不到合适的测试设置来允许我们使用AuthState
and来测试这样的组合选择器RouterState
。
问题
如何设置这个测试,以便我们基本上可以测试我们的选择器?
当我们运行该应用程序时,它运行良好。所以问题只出在测试设置上。
我们认为使用真实路由器设置测试床可能是一个错误的想法。但是我们很难模拟 routerSelector(仅)并给它一个模拟的路由器状态切片,仅用于测试目的。
仅模拟这些路由器选择器真的很难。监视store.select
很容易,但是监视store.select(routerSelectorMethod)
, 方法作为参数变得一团糟。