简体   繁体   English

如何对这个Angular打字机Http错误拦截器进行单元测试,该拦截器从一个管道的observable中捕获错误?

[英]How to unit test this Angular typescript Http Error Interceptor that catches errors from a piped observable?

I am running an experiment where I am learning angular and typescript via testing someone else code (eg automated unit and end to end tests). 我正在运行一个实验,我通过测试其他代码(例如自动化单元和端到端测试)来学习角度和打字稿。 After I get it under test, I plan to repurposes it for a pet project I am working on for a university classroom. 在我接受测试之后,我计划将其重新用于我正在为大学教室工作的宠物项目。

I am at least half way through unit testing the code from here: http://jasonwatmore.com/post/2018/05/16/angular-6-user-registration-and-login-example-tutorial 我至少在这里通过单元测试代码的一半: http//jasonwatmore.com/post/2018/05/16/angular-6-user-registration-and-login-example-tutorial

I have been trying for some time to get the following code under unit test but everything I have tried from my own ideas or ideas from the internet have been unsuccessful thus far: 我已经尝试了一段时间在单元测试下获得以下代码,但是我从我自己的想法或来自互联网的想法尝试的所有内容到目前为止都没有成功:

import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { AuthenticationService } from "src/app/authenticationService/AuthenticationService";
import { Observable, throwError } from "rxjs";
import { catchError } from "rxjs/operators";
import { Injectable } from "@angular/core";

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
    constructor(private authenticationService: AuthenticationService) {}

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        console.log('before error handle')
        return next.handle(request).pipe(catchError(err => {

            console.log('in error handle')

            if (err.status === 401) { 
                // auto logout if 401 response returned from api
                this.authenticationService.logout();
                location.reload(true);
            }

            const error = err.error.message || err.statusText;
            return throwError(error);
        }))
    }

}

The following test code and several variations have been unsuccessful to get the 'in error handle' message to show up in the console log: 以下测试代码和几个变体未能成功地在控制台日志中显示“错误处理”消息:

import { ErrorInterceptor } from "./ErrorInterceptor";
import { of, throwError, defer } from "rxjs";

describe('ErrorInterceptor', () => {
    let errorInterceptor;
    let authenticationServiceSpy;

    beforeEach(() => {
        authenticationServiceSpy = jasmine.createSpyObj('AuthenticationService', ['logout']);
        errorInterceptor = new ErrorInterceptor(authenticationServiceSpy);
    })

    it('should create', () => {
        expect(errorInterceptor).toBeTruthy();
    })

    describe('intercept', () => {
        let httpRequestSpy;
        let httpHandlerSpy;
        const error = {status: 401, statusText: 'error'};

        it('should auto logout if 401 response returned from api', () => {
            //arrange
            httpRequestSpy = jasmine.createSpyObj('HttpRequest', ['doesNotMatter']);
            httpHandlerSpy = jasmine.createSpyObj('HttpHandler', ['handle']);
            httpHandlerSpy.handle.and.returnValue({
                pipe: () => {
                return fakeAsyncResponseWithError({});
                }
            });

            //act
            errorInterceptor.intercept(httpRequestSpy, httpHandlerSpy);

            //assert
            //TBD

            function fakeAsyncResponseWithError<T>(data: T) {
                return defer(() => throwError(error));
            }
        })
    })
})

A couple of issues here. 这里有几个问题。

  • First, your return value from httpHandlerSpy.handle() needs to be an Observable, since that will already have the pipe operator on it and then the HttpInterceptor code can pipe it to catchError as required. 首先,来自httpHandlerSpy.handle()返回值需要是一个Observable,因为它已经有了管道操作符,然后HttpInterceptor代码可以根据需要将它传递给catchError。
  • Second, HttpInterceptor returns an Observable and for this to be "executed", it needs to be subscribed to. 其次,HttpInterceptor返回一个Observable并为此“执行”,需要订阅它。

I put together a Stackblitz to demonstrate how I'd approach this. 我把Stackblitz放在一起来演示我如何处理这个问题。

From the Stackblitz, here is the spec ( it function): 从Stackblitz,这是规范( it功能):

it('should auto logout if 401 response returned from api', () => {
    //arrange
    httpRequestSpy = jasmine.createSpyObj('HttpRequest', ['doesNotMatter']);
    httpHandlerSpy = jasmine.createSpyObj('HttpHandler', ['handle']);
    httpHandlerSpy.handle.and.returnValue(throwError(
        {error: 
            {message: 'test-error'}
        }
    ));
    //act
    errorInterceptor.intercept(httpRequestSpy, httpHandlerSpy)
        .subscribe(
            result => console.log('good', result), 
            err => { 
                console.log('error', err);
                expect(err).toEqual('test-error');
            }
        );

    //assert

})

I hope this helps. 我希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM