Angular 调用服务的组件的 5 个单元测试

Angular 5 unit test for component that calls a service

我有一个 Angular 5 项目,我在其中为登录组件添加单元测试。

测试是在我的 'submit' 按钮上进行的,它将调用 REST API 来进行我的身份验证,如果成功,return 将调用 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');
});

执行测试时,我收到此错误:

'ERROR: login failed _this.handler.handle is not a function'

现在,看到它,我觉得它与 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()

如您所见,如果我将间谍设置为显式 return 我的字符串,那么处理程序错误就会消失,但现在我收到此错误:

TypeError: this.loginService.login(...).subscribe is not a function

有什么想法吗?

编辑:对下方评论的回复...

beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;

    loginService = TestBed.get(LoginService);
    authenticationService = TestBed.get(AuthenticationService);

    fixture.detectChanges();
});

spyOn 应该有一个 Observable 作为 return 值。例如:

spyOn(loginService, 'login').and.returnValue(Observable.of('asdfasdfasdf')).