Node中用Jest模拟NDJSON流式端点时遇超时问题求助
问题分析
测试超时的核心原因是:你用ndjson.stringify(EventsResponseBody)生成的Transform流,在测试环境中没有被正确写入数据并结束,导致getEvents里监听的end事件永远不触发,Promise一直处于pending状态,最终触发Jest的超时。
解决方案
1. 提前生成NDJSON格式字符串,构造可自动结束的可读流
不要直接用ndjson.stringify的流作为Response的body,而是先把数据转成NDJSON字符串,再用Node.js的Readable.from创建可读流,这样流会自动结束,触发end事件。
2. 修改测试代码
import * as fetch from 'node-fetch'; const { Readable } = require('stream'); import getEvents from './getEvents'; import { EventResponseBody } from '../mocks/mockData'; describe('Events resolver', () => { let fetchMock: jest.SpyInstance; beforeAll(() => { fetchMock = jest.spyOn(fetch, 'default').mockImplementation(() => undefined); }); afterEach(() => { fetchMock.mockReset(); }); afterAll(() => { fetchMock.mockRestore(); }); it('returns events for an id', async () => { // 把数组转成NDJSON格式字符串,每个JSON元素单独一行 const ndjsonStr = EventResponseBody.map(JSON.stringify).join('\n') + '\n'; // 基于NDJSON字符串创建可读流 const responseBody = Readable.from(Buffer.from(ndjsonStr)); const response = new fetch.Response(responseBody, { status: 200 }); fetchMock.mockReturnValue(Promise.resolve(response)); const result = await getEvents(url, token, { id: '1' }); expect(fetchMock).toHaveBeenCalledTimes(1); // 可选:验证返回结果是否与原数据一致 expect(result).toEqual(EventResponseBody); }); });
3. 优化getEvents代码(可选,修复Promise反模式)
你的getEvents使用了async修饰的Promise构造器,属于反模式,同时补充流错误监听避免遗漏异常:
const getEvents = <T>(url: string, token: string, params: { id: string }) => { return new Promise<T[]>((resolve, reject) => { fetch(`${url}${params.id}`, { headers: { Accept: 'application/x-ndjson', Authorization: `Bearer ${token}`, }, }) .then(response => { const events: T[] = []; response.body .pipe(ndjson.parse()) .on('data', (data: T) => events.push(data)) .on('end', () => resolve(events)) .on('error', reject); // 监听流错误,避免未捕获异常导致Promise挂起 }) .catch(reject); }); };
关键说明
ndjson.stringify是Transform流,需要手动写入数据并调用end()才会结束流。测试中直接用它作为Response body,流会一直处于等待写入的状态,永远不会触发end事件。- 用
Readable.from创建的流,当所有数据被读取完毕后会自动触发end事件,这样getEvents中的Promise就能正常resolve,测试不会超时。
内容的提问来源于stack exchange,提问作者boing
相关产品推荐
相关产品推荐

