React+Redux项目RxJS Ajax错误处理及Jest 404测试问题
解决React+Redux+RxJS场景下的404响应处理与Jest测试问题
看起来你在React+Redux+RxJS的项目里遇到了两个头疼的问题:RxJS Ajax没法正确处理404响应,同时写不出对应的Jest测试用例。我来帮你一步步拆解解决!
一、先搞定RxJS Ajax的404错误处理问题
首先得明确:RxJS的ajax操作符默认会把所有4xx/5xx状态码的响应都当成错误抛出,这就是你没法正常处理404的核心原因。我们需要修改请求配置,让RxJS把404视为“正常响应”,而不是错误流。
调整RxJS Ajax请求配置
你可以通过statusCode选项指定哪些状态码算成功,再配合responseType确保正确获取text/html内容:
import { ajax } from 'rxjs/ajax'; import { map, catchError } from 'rxjs/operators'; import { of } from 'rxjs'; export const fetchResource = () => { return ajax({ url: '/your-target-resource', responseType: 'text', // 明确指定接收text类型响应(适配text/html) // 关键配置:告诉RxJS 200和404都属于成功响应,不会触发catchError statusCode: { 200: true, 404: true } }).pipe( map(response => { // 根据状态码分支处理业务逻辑 if (response.status === 200) { return { type: 'GET_RESOURCE_SUCCESS', payload: response.response // 直接返回text/html内容 }; } else if (response.status === 404) { // 这里编写404对应的业务逻辑,比如返回特定action return { type: 'GET_RESOURCE_NOT_FOUND', payload: '请求的资源不存在' }; } }), catchError(error => { // 这里处理真正的网络错误(比如断网、跨域、500等) return of({ type: 'GET_RESOURCE_FAILURE', payload: error.message }); }) ); };
二、编写覆盖404场景的Jest测试用例
接下来我们用Jest+RxJS测试调度器+Nock(模拟HTTP请求)来写测试,确保每个分支都被覆盖。
第一步:安装必要依赖(如果还没装)
npm install --save-dev jest rxjs/testing nock
第二步:编写测试用例
import { TestScheduler } from 'rxjs/testing'; import { fetchResource } from './path-to-your-action-file'; import nock from 'nock'; describe('fetchResource Action', () => { let testScheduler; // 每次测试前初始化RxJS测试调度器,同步处理异步流 beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); }); // 测试后清理Nock的所有模拟 afterEach(() => { nock.cleanAll(); }); // 测试200成功场景 it('dispatches GET_RESOURCE_SUCCESS when resource returns 200', () => { // 模拟后端返回200和text/html内容 nock('http://your-app-domain.com') .get('/your-target-resource') .reply(200, '<div>Hello from resource</div>', { 'Content-Type': 'text/html' }); testScheduler.run(({ expectObservable }) => { const expectedAction = { type: 'GET_RESOURCE_SUCCESS', payload: '<div>Hello from resource</div>' }; const action$ = fetchResource(); // 断言流会发出一个action然后完成 expectObservable(action$).toBe('(a|)', { a: expectedAction }); }); }); // 测试404场景 it('dispatches GET_RESOURCE_NOT_FOUND when resource returns 404', () => { // 模拟后端返回404 nock('http://your-app-domain.com') .get('/your-target-resource') .reply(404, '', { 'Content-Type': 'text/html' }); testScheduler.run(({ expectObservable }) => { const expectedAction = { type: 'GET_RESOURCE_NOT_FOUND', payload: '请求的资源不存在' }; const action$ = fetchResource(); expectObservable(action$).toBe('(a|)', { a: expectedAction }); }); }); // 测试网络错误场景 it('dispatches GET_RESOURCE_FAILURE on network error', () => { // 模拟网络错误 nock('http://your-app-domain.com') .get('/your-target-resource') .replyWithError('Failed to connect'); testScheduler.run(({ expectObservable }) => { const expectedAction = { type: 'GET_RESOURCE_FAILURE', payload: 'Failed to connect' }; const action$ = fetchResource(); expectObservable(action$).toBe('(a|)', { a: expectedAction }); }); }); });
测试注意点:
- 使用
TestScheduler可以把异步的RxJS流变成同步测试,避免时序问题 nock用来精准模拟HTTP响应,不用依赖真实后端就能测试各种状态码- 一定要覆盖200、404、网络错误三个核心场景,确保逻辑无死角
三、Redux Reducer中补充404逻辑
最后别忘了在Reducer里处理新增的GET_RESOURCE_NOT_FOUND action,更新状态:
const initialState = { content: '初始默认内容', error: null, isResourceNotFound: false }; export const resourceReducer = (state = initialState, action) => { switch (action.type) { case 'GET_RESOURCE_SUCCESS': return { ...state, content: action.payload, error: null, isResourceNotFound: false }; case 'GET_RESOURCE_NOT_FOUND': return { ...state, content: '资源不存在的提示文案', // 或者保留初始内容,根据业务需求调整 error: action.payload, isResourceNotFound: true }; case 'GET_RESOURCE_FAILURE': return { ...state, error: action.payload, isResourceNotFound: false }; default: return state; } };
这样一套操作下来,你就能正确处理404响应,同时拥有覆盖全面的Jest测试用例了!
内容的提问来源于stack exchange,提问作者user
相关产品推荐
相关产品推荐

