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

Node.js+Jest单元测试unzip方法超时问题求助

问题:unzipper解压函数Jest单元测试超时

我实现了一个基于unzipper的小型文件解压函数,功能运行正常,但用Jest做单元测试时出现超时问题。程序基于Node.js 16开发,修改函数会导致功能失效,后续流程依赖解压后的文件,必须解决测试超时问题。

解压函数代码

exports.unzipFile = async (folderPath) => {
  return new Promise((resolve, reject) => {
    fs.createReadStream(folderPath)
      .pipe(unzipper.Extract({ path: tmpPath + path.parse(folderPath).name }))
      .on('close', () => resolve())
      .on('error', (error) => reject(error))
  })
}

当前单元测试代码

const { PassThrough } = require('stream')
const os = require('os');
const unzipper = require("unzipper")
const fs = require("fs")

let tmpdir, mockReadStream
    
beforeEach(() => {
  tmpdir = os.tmpdir() + "/uploadFolder/";
  if (!fs.existsSync(tmpdir)){
      fs.mkdirSync(tmpdir);
  }
  fs.writeFileSync(tmpdir+"tempfile.zip", "file to be used")
  mockReadStream = new PassThrough()
})
afterEach(() => {
  // Restore mocks
  jest.clearAllMocks()
})

describe('Test helper.js unzip method', () => {
  test('should be able to unzip file  ', async () => {
    jest.isolateModules(() => {
        helper = require('helper')
    })
    const result = await helper.unzipFile(tmpdir+"tempfile.zip")
    console.log(result)
  })
})

问题原因分析

  • 无效Zip文件:测试中写入的tempfile.zip是普通文本,不是合法Zip包。unzipper处理无效文件时,不会触发close或error事件,导致Promise一直pending,Jest超时。
  • 未清理测试资源:afterEach仅清除Mock,未删除临时文件和目录,可能干扰后续测试。
  • 不必要的模块隔离:jest.isolateModules无配合Mock重置,可能导致模块状态异常。

解决方案

1. 生成合法测试Zip文件

使用archiver生成真实Zip包用于测试:

const archiver = require('archiver'); // 先安装:npm install archiver --save-dev

beforeEach(async () => {
  tmpdir = os.tmpdir() + "/uploadFolder/";
  if (!fs.existsSync(tmpdir)){
      fs.mkdirSync(tmpdir);
  }
  // 生成包含测试文件的Zip包
  const output = fs.createWriteStream(tmpdir+"tempfile.zip");
  const archive = archiver('zip', { zlib: { level: 9 } });
  archive.pipe(output);
  archive.append('test content', { name: 'test.txt' });
  await archive.finalize();
})

2. 完善Promise事件监听

确保所有异常和结束事件都被捕获:

exports.unzipFile = async (folderPath) => {
  return new Promise((resolve, reject) => {
    const extractStream = unzipper.Extract({ path: tmpPath + path.parse(folderPath).name });
    fs.createReadStream(folderPath)
      .pipe(extractStream)
      .on('close', resolve)
      .on('end', resolve) // 补充end事件监听
      .on('error', reject);
    // 监听extractStream自身的error事件,避免遗漏
    extractStream.on('error', reject);
  })
}

3. 清理测试临时资源

用rimraf递归删除测试目录:

const rimraf = require('rimraf'); // 先安装:npm install rimraf --save-dev

afterEach(async () => {
  jest.clearAllMocks();
  // 异步删除临时目录
  await new Promise((resolve) => rimraf(tmpdir, resolve));
})

4. 优化测试代码结构

移除不必要的模块隔离,添加断言验证结果:

const helper = require('helper'); // 移到测试文件顶部

describe('Test helper.js unzip method', () => {
  test('should be able to unzip file', async () => {
    await helper.unzipFile(tmpdir+"tempfile.zip");
    // 断言解压后的文件存在
    expect(fs.existsSync(tmpPath + 'tempfile/test.txt')).toBe(true);
  }, 10000); // 必要时可延长超时时间至10秒
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:10:31