You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular测试中HttpClient的POST请求在Jest中无法触发

Angular 12+/13中HttpInterceptor拦截POST请求时测试失败的问题

问题背景

实现了一个基础的HttpInterceptor,用于为POST请求添加Content-Type头信息,但在Angular 12、13版本(Node 14.17)的测试中,GET请求可正常触发,POST请求始终无法执行,第一个测试用例失败,报错Expected one matching request for criteria "Match URL: /data", found none.,且拦截器未打印请求日志。该功能在Angular 11中可正常工作。

拦截器代码

import { Injectable } from '@angular/core';
import {
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http';

@Injectable()
export class MyInterceptor implements HttpInterceptor {
  public intercept(
    request: HttpRequest<Record<string, unknown>>,
    next: HttpHandler,
  ) {
    console.log('REQUEST WAS INTERCEPTED');
    if (request.method === 'POST') {
      request = request.clone({
        setHeaders: {
          'Content-Type': 'application/json;charset=UTF-8',
        },
      });
    }

    return next.handle(request);
  }
}

测试代码

import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';

import { Data } from '@angular/router';
import { HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http';
import { MyInterceptor } from './my-interceptor.service';

const testData: Data[] = [{ name: 'bob' }, { name: 'alice' }];

describe('PROVIDE_CONTENT_TYPE_HTTP_INTERCEPTOR', () => {
  let http: HttpClient;
  let httpTestingController: HttpTestingController;

  beforeEach(async () => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [{provide: HTTP_INTERCEPTORS,
        useClass: MyInterceptor,
        multi: true,}]
    });

    http = TestBed.inject(HttpClient);
    httpTestingController = TestBed.inject(HttpTestingController);
  });

  afterEach(() => {
    httpTestingController.verify();
  });

  it('handles POST requests', (done) => {
    http.post('/data', {}).subscribe((data: any) => {
      console.log('POST REQUEST HAS FIRED - NEVER HAPPENS');
      expect(data).toEqual(testData);
      done();
    });
    const request = httpTestingController.expectOne('/data');
    request.flush(testData);
  });

  it('ignores GET requests', (done) => {
    http.get('/data').subscribe((data: any) => {
      console.log('GET REQUEST HAS FIRED - SUCCESS');
      expect(data).toEqual(testData);
      done();
    });
    const request = httpTestingController.expectOne('/data');
    request.flush(testData);
  });
});

问题原因与解决方案

原因

Angular 12+对HTTP拦截器的类型检查逻辑做了变更:当拦截器中声明的HttpRequest泛型(此处为Record<string, unknown>)与实际请求的泛型不匹配时,拦截器会被跳过,导致请求无法流转到测试控制器。而GET请求通常没有请求体,泛型不匹配的问题不会触发,因此GET请求可正常执行。

解决方案

将拦截器中的HttpRequest泛型改为unknown或any,消除类型不匹配的问题:

修改后的拦截器核心代码:

public intercept(
  request: HttpRequest<unknown>, // 替换原有的Record<string, unknown>
  next: HttpHandler,
) {
  console.log('REQUEST WAS INTERCEPTED');
  if (request.method === 'POST') {
    request = request.clone({
      setHeaders: {
        'Content-Type': 'application/json;charset=UTF-8',
      },
    });
  }

  return next.handle(request);
}

修改后,POST请求会被正常拦截,测试用例可顺利通过。

内容的提问来源于stack exchange,提问作者Maria K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 00:36:27