我正在尝试对一个角度2组件进行单元测试,并从http后端模拟错误(400 /错误请求)。
这是我的代码:
describe('Component: UserAccountActivationComponent', () => {
let fixture: ComponentFixture<UserAccountActivationComponent>;
let userAccountActivationComponent: UserAccountActivationComponent;
const observableMock = Observable.of('Some Observable');
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend, options) => new Http(backend, options),
deps: [MockBackend, BaseRequestOptions]
},
{
provide: ActivatedRoute, useClass: RouteMock
},
],
imports: [AppModule, HttpModule]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(UserAccountActivationComponent);
userAccountActivationComponent = fixture.componentInstance;
});
it('should not signin user nor navigate to dashboard if account is not activated', fakeAsync(inject(
[UserAccountService, SessionSigninService, Router, MockBackend],
(userAccountService: UserAccountService, signinService: SessionSigninService, router: Router, mockBackend: MockBackend) => {
const opts = {
type: ResponseType.Error,
status: 400
};
const responseOpts = new ResponseOptions(opts);
mockBackend.connections.subscribe(
(connection: MockConnection) => {
connection.mockError(new MockError(responseOpts));
});
const activateSpy = spyOn(userAccountService, 'activateAccount').and.callThrough();
const signinSpy = spyOn(signinService, 'signinByUserAccountToken').and.returnValue(observableMock);
const navigateSpy = spyOn(router, 'navigate').and.returnValue(observableMock);
fixture.detectChanges();
tick();
expect(activateSpy).toHaveBeenCalled();
expect(signinSpy).not.toHaveBeenCalled();
expect(navigateSpy).not.toHaveBeenCalled();
})));
});
class MockError extends Response implements Error {
name: any;
message: any;
}
class RouteMock {
readonly params = Observable.of({userAccountToken: 'a-token'});
}
我正在模拟userAccountService.activateAccount
方法中发生的错误。我只是想检查一下signinService.signinByUserAccountToken
和router.navigate
都没有被调用。这就是我正在尝试用茉莉花的期望:
expect(activateSpy).toHaveBeenCalled();
expect(signinSpy).not.toHaveBeenCalled();
expect(navigateSpy).not.toHaveBeenCalled();
但是,我通过模拟错误停止了测试:
Chrome 56.0.2924 (Mac OS X 10.12.3) Component: UserAccountActivationComponent should not signin user nor navigate to dashboard if account is not activated FAILED
Error: Error in :0:0 caused by: Response with status: 400 null for URL: null
at ViewWrappedError.ZoneAwareError (webpack:///~/zone.js/dist/zone.js:811:0 <- src/test.ts:142448:33)
at ViewWrappedError.BaseError [as constructor] (webpack:///~/@angular/core/src/facade/errors.js:22:0 <- src/test.ts:36304:16)
at ViewWrappedError.WrappedError [as constructor] (webpack:///~/@angular/core/src/facade/errors.js:87:0 <- src/test.ts:36369:16)
at new ViewWrappedError (webpack:///~/@angular/core/src/linker/errors.js:77:0 <- src/test.ts:70405:16)
at proxyClass.DebugAppView._rethrowWithContext (webpack:///~/@angular/core/src/linker/view.js:653:0 <- src/test.ts:111685:23)
at proxyClass.DebugAppView.detectChanges (webpack:///~/@angular/core/src/linker/view.js:626:0 <- src/test.ts:111658:18)
at ViewRef_.detectChanges (webpack:///~/@angular/core/src/linker/view_ref.js:170:0 <- src/test.ts:71336:20)
at ComponentFixture._tick (webpack:///~/@angular/core/bundles/core-testing.umd.js:196:0 <- src/test.ts:15653:36)
at webpack:///~/@angular/core/bundles/core-testing.umd.js:210:45 <- src/test.ts:15667:53
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:242:0 <- src/test.ts:141879:26)
at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:79:0 <- src/test.ts:98996:39)
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:241:0 <- src/test.ts:141878:32)
at Object.onInvoke (webpack:///~/@angular/core/src/zone/ng_zone.js:271:0 <- src/test.ts:38049:37)
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:241:0 <- src/test.ts:141878:32)
at Zone.run (webpack:///~/zone.js/dist/zone.js:113:0 <- src/test.ts:141750:43)
仅供参考,这是待测组件:
@Component({
templateUrl: './useraccount-activation.component.html'
})
export class UserAccountActivationComponent implements OnInit {
constructor(private userAccountService: UserAccountService,
private signinService: SessionSigninService,
private router: Router,
private route: ActivatedRoute) {
}
ngOnInit() {
this.route.params
.take(1)
.pluck('userAccountToken')
.switchMap((userAccountToken: string) =>
this.userAccountService.activateAccount(userAccountToken)
.switchMapTo(this.signinService.signinByUserAccountToken(userAccountToken))
)
.subscribe(() => this.router.navigate(['/dashboard']));
}
}
编辑1 :不幸的是,更改为:
mockBackend.connections.subscribe(
(connection: MockConnection) => {
responseOpts.url = connection.request.url;
connection.mockError(new MockError(responseOpts));
});
仍然会导致以下错误:
'HttpClient error: ', MockError{_body: null, status: 400, ok: false, statusText: null, headers: null, type: 3, url: '/api/useraccount/activate/a-valid-token'}
Error: Error in :0:0 caused by: Response with status: 400 null for URL: /api/useraccount/activate/a-valid-token
at Error.ZoneAwareError (webpack:///~/zone.js/dist/zone.js:958:0 <- src/test.ts:143513:33)
at ZoneAwareError (webpack:///~/zone.js/dist/zone.js:955:0 <- src/test.ts:143510:35)
at wrappedError (webpack:///~/@angular/core/src/error_handler.js:144:21 <- src/test.ts:36697:34)
at viewWrappedError (webpack:///~/@angular/core/src/linker/errors.js:65:21 <- src/test.ts:70785:125)
at proxyClass.DebugAppView._rethrowWithContext (webpack:///~/@angular/core/src/linker/view.js:656:0 <- src/test.ts:112336:111)
at proxyClass.DebugAppView.detectChanges (webpack:///~/@angular/core/src/linker/view.js:629:0 <- src/test.ts:112309:18)
at ViewRef_.detectChanges (webpack:///~/@angular/core/src/linker/view_ref.js:172:0 <- src/test.ts:71715:20)
at ComponentFixture._tick (webpack:///~/@angular/core/bundles/core-testing.umd.js:196:0 <- src/test.ts:15805:36)
at webpack:///~/@angular/core/bundles/core-testing.umd.js:210:45 <- src/test.ts:15819:53
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:330:0 <- src/test.ts:142885:26)
at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:79:0 <- src/test.ts:99788:39)
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:329:0 <- src/test.ts:142884:32)
at Object.onInvoke (webpack:///~/@angular/core/src/zone/ng_zone.js:273:0 <- src/test.ts:38516:37)
at ZoneDelegate.invoke (webpack:///~/zone.js/dist/zone.js:329:0 <- src/test.ts:142884:32)
at Zone.run (webpack:///~/zone.js/dist/zone.js:126:0 <- src/test.ts:142681:43)
答案 0 :(得分:1)
我认为你得到了例外,因为没有指定Url
。尝试在选项上设置网址,如下所示:
let responseOpts = new ResponseOptions(opts);
mockBackend.connections.subscribe(
(connection: MockConnection) => {
responseOpts.url = connection.request.url;
connection.mockError(new MockError(responseOpts));
});
您看到的问题可能是因为错误未被捕获到任何地方,因此它正在冒泡到区域。尝试向订阅添加错误捕获以处理异常或压制错误(error) => {}
。
this.route.params
.take(1)
.pluck('userAccountToken')
.switchMap((userAccountToken: string) =>
this.userAccountService.activateAccount(userAccountToken)
.switchMapTo(this.signinService.signinByUserAccountToken(userAccountToken))
)
.subscribe(() => this.router.navigate(['/dashboard']), (error) => {});