Search code examples
angularunit-testingkarma-jasmine

How to mock interceptor with post and get requests?


I'm trying to test interceptor with both post/get requests. If i'm testing only the GET requests - it's working fine - but when i've added the switch , to check for both POST & GET request - i'm getting an error - TypeError: req.headers.get is not a function. If i only use GET and remove the POST code - it's working

const mockRequest = new HttpRequest('GET', mockUrl) // working

// not working

switch (e.req_type) { case 'GET': mockRequest = new HttpRequest('GET', mockUrl); break; case 'POST': mockRequest = new HttpRequest('POST', mockUrl, {}, {headers: e.input}); break; }

  const auditTestCases: AuditTestCase[] = [
    {
      test_name: 'check user_navigation',
      test_url: '/backend-gateway/user_navigation',
      req_type: 'POST',
      input: {
        audit: 'true',
        'tag-code': 'NEWS',
        'tag-text': '',
        'tag-view': 'TOP_BAR_NAVIGATION',
      },
      output: {
        audit: 'true',
        'tag-code': 'GALLERY',
        'tag-text': '',
        'tag-view': 'TOP_BAR_NAVIGATION',
      },
    },
    {
      test_name: 'add user',
      test_url: '/backend-gateway/add_user',
      req_type: 'POST',
      input: {
        audit: 'true',
        'tag-code': 'NEW_USER_ADDED',
        'tag-text': '',
        'tag-view': 'TOP_BAR_NAVIGATION',
      },
      output: {
        audit: 'true',
        'tag-code': 'NEW_USER_ADDED',
        'tag-text': '',
        'tag-view': 'TOP_BAR_NAVIGATION',
      },
    },
  ];

  describe('LoaderInterceptor', () => {
    let client: HttpClient;
    let httpMock: HttpTestingController;
    let interceptor: LoaderInterceptor;
    let apiServiceSpy = jasmine.createSpyObj('ApiService', ['']);
    let commonServiceSpy = jasmine.createSpyObj('CommonService', ['']);

    beforeEach(() => {
      TestBed.configureTestingModule({
        imports: [HttpClientTestingModule],
        providers: [
          LoaderInterceptor,
          {
            provide: HTTP_INTERCEPTORS,
            useClass: LoaderInterceptor,
            multi: true,
          },
          { provide: ApiService, useValue: apiServiceSpy },
          { provide: CommonService, useValue: commonServiceSpy },
        ],
      });
      apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
      commonServiceSpy = TestBed.inject(
        CommonService
      ) as jasmine.SpyObj<CommonService>;
      client = TestBed.get(HttpClient);
      httpMock = TestBed.get(HttpTestingController);
      interceptor = TestBed.get(LoaderInterceptor);
    });

    auditTestCases.forEach((e) => {
      it(e.test_name, (done) => {
        const mockUrl = e.test_url;
        spyOn(interceptor, 'handleNext').and.callFake((req, next, isPolling) => {
          // Return an HttpResponse for the mocked response
          console.log('req.method', req.method);
          let response;
          // Not sure if this is the right way ...
          if (req.method === 'GET') {
            response = new HttpResponse({ status: 200, body: {}, url: req.url });
          }
          if (req.method === 'POST') {
            response = new HttpResponse({
              status: 200,
              body: {},
              url: req.url,
              headers: e.output,
            });
          }
          return of(response);
        });

        commonServiceSpy.isAuditClick$ = new BehaviorSubject<any>({
          tag_code: e.input['tag-code'],
          tag_view: e.input['tag-view'],
          tag_text: e.input['tag-text'],
        });
        let mockRequest;
        switch (e.req_type) {
          case 'GET':
            mockRequest = new HttpRequest('GET', mockUrl);
            break;
          case 'POST':
            mockRequest = new HttpRequest(
              'POST',
              mockUrl,
              {},
              { headers: e.input }
            );
            break;
        }

        interceptor
          .intercept(mockRequest, {
            // Use a mock HttpHandler
            handle: (_req: HttpRequest<any>): Observable<HttpEvent<any>> => {
              if (_req.method === 'GET') {
                return of(
                  new HttpResponse({ status: 500, body: {}, url: _req.url })
                );
              }
              if (_req.method === 'POST') {
                return of(
                  new HttpResponse({
                    status: 500,
                    body: {},
                    url: _req.url,
                    headers: e.output,
                  })
                );
              }
            },
          })
          .subscribe((res) => {
            // Check the request passed to the handleNext spy
            const actualRequest = (
              interceptor.handleNext as jasmine.Spy
            ).calls.mostRecent().args[0] as HttpRequest<any>;
            expect(actualRequest.url).toBe(mockUrl);
            expect(actualRequest.headers.has('audit')).toBeTruthy();
            expect(actualRequest.headers.get('audit')).toBe('true');
            expect(actualRequest.headers.get('tag-code')).toBe(
              e.output['tag-code']
            );
            expect(actualRequest.headers.get('tag-view')).toBe(
              e.output['tag-view']
            );
            expect(actualRequest.headers.get('tag-text')).toBe(
              e.output['tag-text']
            );
            done();
          });
      });
    });
  });

Solution

  • I bet the issue is the headers mock.

    Try the following:

    mockRequest = new HttpRequest('POST', mockUrl, {}, {headers: new HttpHeaders().set('key', 'value')}); break; 
    

    I am not sure what e.input is but you should be using HttpHeaders for .get to work and not a plain object.