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

Thunk异步Action测试时请求头未Mock报错及优化方案问询

解决Nock测试Thunk异步Action时的请求头Mock问题

首先你的报错核心原因很明确:测试环境中authService.getAccessToken()返回了undefined,导致请求头x-access-token携带了非法值,触发了TypeError [ERR_HTTP_INVALID_HEADER_VALUE]错误。下面给你一套更简洁的测试方案和请求头Mock优化方法:

原代码回顾

发起异步请求的Thunk Action

buyerAction = (data = {}, cb) => (dispatch) => { 
  console.log('x-access-token', authService.getAccessToken()); 
  axios({ 
    method: 'POST', 
    url: `http://localhost:3001/api/manageUsers`, 
    headers: { 
      'x-access-token': authService.getAccessToken() 
    }, 
    data 
  }).then((res) => { 
    if (res.status === 200 && res.data) { 
      dispatch({ type: 'buyer_created', data: res.data.message }); 
      if (data.role === 'buyer') { 
        axios({ 
          method: 'POST', 
          url: `http://localhost:3001/api/populateBuyerLookUp`, 
          headers: { 
            'x-access-token': authService.getAccessToken() 
          }, 
          data 
        }).then((response) => { 
          console.log(`${response} lookup is created`); 
        }).catch((err) => { 
          console.log(err); 
        }); 
      } 
      cb(res.data.message); 
    } 
  }) 
  .catch((err) => { 
    console.log('_+_+_+', err); 
  }); 
};

原始测试代码

const middleware = [thunk]; 
const mockStore = configureMockStore(middleware); 
describe('Async Actions', () => { 
  const host = 'http://localhost'; 
  axios.defaults.host = host; 
  axios.defaults.adapter = httpAdapter; 
  afterEach(() => { 
    nock.cleanAll(); 
  }); 
  it('should create Async and load data', (done) => { 
    nock('http://localhost:3001', { 
      reqheaders: { 
        'x-access-token': 'authtoken' 
      } 
    }) 
    .post('/api/manageUsers') 
    .reply(200, { body: { name: 'prakash' } }); 
    const store = mockStore({}, [{ type: 'buyer_created', data: 'message' }]); 
    store.dispatch(buyerAction(undefined, () => {})); 
    done(); 
  }); 
});

优化后的解决方案

1. 先Mock认证服务的Token获取

测试时我们不需要依赖真实的认证状态,直接用Jest Mock掉authService.getAccessToken(),让它返回固定的测试用token:

// 放在测试文件顶部或describe块内部
jest.mock('../path/to/authService', () => ({
  getAccessToken: jest.fn(() => 'authtoken') // 返回预设的测试token
}));

2. 简化Thunk测试逻辑(弃用done回调)

用async/await替代done,配合mockStore的getActions()做断言,同时精简nock配置:

const middleware = [thunk];
const mockStore = configureMockStore(middleware);

describe('Async Actions', () => {
  afterEach(() => {
    nock.cleanAll();
    jest.clearAllMocks(); // 清除mock的调用记录,避免测试用例互相干扰
  });

  it('should dispatch buyer_created action on successful user creation', async () => {
    // 拦截第一个POST请求,验证请求头并返回模拟响应
    const userCreateNock = nock('http://localhost:3001', {
      reqheaders: {
        'x-access-token': 'authtoken'
      }
    })
    .post('/api/manageUsers')
    .reply(200, { message: 'User created successfully' });

    // 测试buyer角色时,拦截第二个lookup请求
    const testData = { role: 'buyer' };
    if (testData.role === 'buyer') {
      nock('http://localhost:3001', {
        reqheaders: {
          'x-access-token': 'authtoken'
        }
      })
      .post('/api/populateBuyerLookUp')
      .reply(200);
    }

    const store = mockStore({});
    const mockCb = jest.fn(); // Mock回调函数,用来验证是否被调用

    // 异步dispatch action,等待所有异步操作完成
    await store.dispatch(buyerAction(testData, mockCb));

    // 断言nock是否确实拦截到了请求
    expect(userCreateNock.isDone()).toBe(true);
    // 断言正确的action被dispatch
    expect(store.getActions()).toEqual([
      { type: 'buyer_created', data: 'User created successfully' }
    ]);
    // 断言回调函数被正确触发
    expect(mockCb).toHaveBeenCalledWith('User created successfully');
  });
});

3. 额外优化:统一请求头配置

为了避免在每个请求里重复写headers,可以给axios加个全局请求拦截器,自动注入token:

// 在axios初始化的文件中添加
axios.interceptors.request.use(config => {
  const token = authService.getAccessToken();
  if (token) {
    config.headers['x-access-token'] = token;
  }
  return config;
});

这样你的Thunk Action可以简化成:

buyerAction = (data = {}, cb) => (dispatch) => { 
  axios({ 
    method: 'POST', 
    url: `http://localhost:3001/api/manageUsers`, 
    data 
  }).then((res) => { 
    // 后续逻辑保持不变
  })
  .catch((err) => { 
    console.log('_+_+_+', err); 
  }); 
};

关键说明

  • Mock认证服务:彻底解决测试环境中token为undefined的问题,确保请求头合法。
  • 用async/await替代done:让测试代码更简洁易读,同时保证所有异步操作完成后再执行断言,避免异步时序问题。
  • 验证nock调用状态:用isDone()确保请求确实被拦截,避免测试用例"假通过"。

内容的提问来源于stack exchange,提问作者bikky barnwal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:46:35