我有一个Angular 5项目,我正在为我的登录组件添加单元测试。
测试在我的“提交”按钮上,该按钮将调用REST API
进行身份验证,如果成功,则返回JWT
。
这是我的LoginComponent.submit
功能:
submit() {
this.loggingService.log('LoginComponent | submit | ...');
this.loginService.login(this.loginFormGroup.get('username').value, this.loginFormGroup.get('password').value)
.subscribe((jwtString: string) => {
window.alert('login successful, token: ' + jwtString);
// the response should be the JWT, so let's set it
this.authenticationService.setToken(jwtString);
}, (error: any) => { // should this be changed to the Error type on return???
const errorString: string = error && error.message ? error.message : error;
this.loggingService.error('login failed ' + errorString);
this.loginFormGroup.setErrors({ 'post': errorString });
});
}
这是我的LoginService.login
功能:
login(username: string, password: string): Observable<any> {
this.loggingService.log('LoginService | login | loginUrl: ' + this.loginUrl + '; username: ' + username + '; password: xxxxx');
return this.http.post(this.loginUrl, { username: username, password: password });
}
非常简单,现在这是LoginComponent
的单元测试:
it('submit logs the user in successfully', () => {
// spyOn(loginService, 'login').and.returnValue('asdfasdfasdf').and.callThrough();
component.loginFormGroup.setValue({ username: 'roberto', password: 'password' });
component.submit();
expect(authenticationService.getToken()).toEqual('asdfasdfasdf');
});
执行测试时,我收到此错误:
'错误:登录失败_this.handler.handle不是函数'
现在,看到这一点,它让我觉得它与middleware
有关。只有我拥有的中间件是HttpInterceptor
,这里是代码:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.loggingService.log('CustomHttpInterceptor | intercept | intercepting http(s) transaction: ' + request.urlWithParams);
const customRequest = this.authenticationService.isAuthenticated()
? request.clone({
headers: request.headers
.set('Authorization', 'Bearer ' + this.authenticationService.getToken())
.set('Content-type', 'application/json')
})
: request.clone({
headers: request.headers
.set('Content-type', 'application/json')
});
return next.handle(customRequest)
.do((event: HttpEvent<any>) => {
// need this if check here because the options calls are NOT an HttpResponse, and we don't want to do anything with them
if (event instanceof HttpResponse) {
// log a successful response from the API call
this.loggingService.logApiCall('CustomHttpInterceptor | intercept | ' + JSON.stringify(event));
}
})
.catch((error: any) => {
// log the failed response
this.loggingService.error('CustomHttpInterceptor | intercept | ' + JSON.stringify(error));
if (error instanceof HttpErrorResponse && error.status === 401) {
// if we ever want to save our failed (401) requests, and retry after attempting to refresh the JWT,
// add a function to the auth service to add this HttpEvent, then after the JWT refresh, we can re-execute
// the http call.
this.router.navigate(['login']);
}
return Observable.throw('asdf error');
});
}
为了摆脱上面的错误,我必须将这一行添加到我的单元测试的开头(部分内容已在上面注释掉):
spyOn(loginService, 'login').and.returnValue('asdfasdfasdf'); // .and.callThrough()
正如您所看到的,如果我将间谍设置为明确返回我的字符串,那么处理程序错误就会消失,但现在我收到此错误:
TypeError:this.loginService.login(...)。subscribe不是函数
这里有什么想法吗?
编辑:回复以下评论......
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
loginService = TestBed.get(LoginService);
authenticationService = TestBed.get(AuthenticationService);
fixture.detectChanges();
});
答案 0 :(得分:2)
spyOn(loginService, 'login').and.returnValue(Observable.of('asdfasdfasdf'))
应该有一个Observable作为返回值。例如:
display:inline-block
。