Har*_*lue 7 jasmine rxjs ngrx angular
我使用的是Angular 6,NgRx 6,RxJS 6.
我有一个看起来像这样的护卫员 -
import { CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { IAppState } from '../../../app.state';
import { Store } from '@ngrx/store';
import { SetTenant } from './../../../store/config/config.actions';
@Injectable()
export default class TenantGuard implements CanActivate {
constructor(private store: Store<IAppState>) {}
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
const tenant = route.params['tenant'];
if (!tenant) {
return of(false);
}
this.store.dispatch(new SetTenant(tenant));
return of(true);
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我正在通过tenant商店将我添加到商店this.store.dispatch(new SetTenant(tenant));
然而,这导致每次用户访问基本路线时都会触发该动作.
为了解决这个问题,我添加了一个检查,看看是否tenant已填充,如果没有,则仅触发操作 -
import { CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable, of, combineLatest } from 'rxjs';
import { IAppState } from '../../../app.state';
import { Store, select } from '@ngrx/store';
import { SetTenant } from './../../../store/config/config.actions';
import { getTenant } from '../../../store/config/config.selectors';
import { map } from 'rxjs/operators';
@Injectable()
export default class TenantGuard implements CanActivate {
constructor(private store: Store<IAppState>) {}
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
const tenantFromRoute: string = route.params['tenant'];
return this.store.pipe(select(getTenant)).pipe(
map(tenantFromStore => {
if (!tenantFromRoute) {
return false;
}
if (!tenantFromStore) {
this.store.dispatch(new SetTenant(tenantFromRoute));
}
return true;
})
);
}
}
Run Code Online (Sandbox Code Playgroud)
然而,这已经破坏了我的单元测试,因为我已经引入了额外的逻辑,现在我收到了错误 TypeError: Cannot read property 'pipe' of undefined
我的spec文件看起来像这样 -
import { TestBed, async } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { Store } from '@ngrx/store';
import { StoreModule } from '@ngrx/store';
import { SetTenant } from './../../../store/config/config.actions';
import TenantGuard from './tenant.guard';
describe('TenantGuard', () => {
it('should return false if a tenant is not present on the route', async(() => {
const { tenantGuard, props } = setup({});
let result: boolean;
tenantGuard.canActivate(props).subscribe(canActivate => (result = canActivate));
expect(result).toBeFalsy();
}));
it('should return true if a tenant is present on the route', async(() => {
const { tenantGuard, props } = setup({ tenant: 'main' });
let result: boolean;
tenantGuard.canActivate(props).subscribe(canActivate => (result = canActivate));
expect(result).toBeTruthy();
}));
it('should dispatch an action to set the tenant in the store', () => {
const { store, tenantGuard, props } = setup({ tenant: 'foo' });
const action = new SetTenant('foo');
tenantGuard.canActivate(props);
expect(store.dispatch).toHaveBeenCalledWith(action);
});
it('should not dispatch an action to set the tenant in the store if the tenant is missing', () => {
const { store, tenantGuard, props } = setup({});
tenantGuard.canActivate(props);
expect(store.dispatch).not.toHaveBeenCalled();
});
const setup = propOverrides => {
TestBed.configureTestingModule({
imports: [StoreModule.forRoot({})],
providers: [
TenantGuard,
{
provide: Store,
useValue: jasmine.createSpyObj('Store', ['dispatch', 'pipe']),
},
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
const props = Object.assign({ params: { tenant: null } }, { params: { ...propOverrides } });
const tenantGuard = TestBed.get(TenantGuard);
const store = TestBed.get(Store);
return { tenantGuard, props, store };
};
});
Run Code Online (Sandbox Code Playgroud)
我已经加入pipe了我,jasmine.createSpyObj但我不确定如何进步.
我想围绕这个编写额外的测试,但是在模拟出pipe在这种情况下应该/将如何使用时遇到了麻烦.
编辑 - 如果我没有传入pipe我的jasmine.createSpyObjI而是得到错误??TypeError: this.store.pipe is not a function??
我和你有同样的错误信息。我将路由器注入到组件中并使用了 this.router.events.pipe(...)... 我在测试中使用了路由器的存根。在 routerStub 之前看起来像这样:
routerStub = {
navigate: (commands: any[]) => { Promise.resolve(true); },
};
Run Code Online (Sandbox Code Playgroud)
所以你可以看到,在我的组件中需要路由器的导航方法之前,我在存根中定义了它。现在我还需要 events 属性,它返回一个使用 .pipe 的可观察值。我在 routerStub 中添加了以下内容,它为我解决了这个问题:
routerStub = {
navigate: (commands: any[]) => { Promise.resolve(true); },
events: of(new Scroll(new NavigationEnd(0, 'dummyUrl', 'dummyUrl'), [0, 0], 'dummyString'))
};
Run Code Online (Sandbox Code Playgroud)
就我而言,我需要一个滚动事件才能使我的代码正常工作,但现在事件在我的存根中被定义为可观察的,并且现在管道是已知的。
也许这对你有帮助...
| 归档时间: |
|
| 查看次数: |
11106 次 |
| 最近记录: |