Cypress提取Zip归档并验证文件内容报错:fs$readFile is not a function
问题根源分析
这个错误的核心原因是**decompress是Node.js环境下的库,依赖Node核心模块fs,但Cypress的测试代码默认运行在浏览器上下文,浏览器环境中不存在fs模块**。同时未处理的Promise拒绝,是因为你在浏览器环境中调用了依赖Node模块的异步方法,导致Promise无法正常resolve/reject,进而抛出未捕获异常。
解决方案:将解压逻辑移至Node环境执行
Cypress提供了cy.task机制,允许测试代码调用运行在Node环境中的自定义任务。我们可以把文件解压、读取的逻辑放到task中,避开浏览器环境的限制,同时正确处理Promise生命周期。
步骤1:配置Cypress任务(cypress.config.js)
在Cypress配置文件中注册处理解压和文件读取的任务,所有依赖fs、decompress的逻辑都在这里执行:
const { defineConfig } = require("cypress"); const decompress = require('decompress'); const fs = require('fs'); const path = require('path'); const { rmSync } = require('fs'); module.exports = defineConfig({ e2e: { setupNodeEvents(on, config) { on('task', { async extractAndValidateZip(zipPath) { try { // 清理旧的解压目录,避免残留文件干扰测试 const outputDir = path.join(__dirname, 'cypress', 'downloads', 'extracted'); rmSync(outputDir, { recursive: true, force: true }); // 解压Zip文件到临时目录 await decompress(zipPath, outputDir); // 读取需要验证的4个文件内容 const targetFiles = ['file1.txt', 'file2.csv', 'file3.json', 'file4.md']; const fileContents = {}; for (const fileName of targetFiles) { const fullPath = path.join(outputDir, fileName); fileContents[fileName] = fs.readFileSync(fullPath, 'utf8'); } return fileContents; } catch (err) { // 主动抛出错误,让Cypress捕获并标记测试失败,避免未处理Promise拒绝 throw new Error(`解压/读取文件失败: ${err.message}`); } } }); }, }, });
步骤2:编写测试用例
在测试代码中调用上述任务,完成登录、下载、验证流程:
describe('Zip文件下载与内容验证', () => { it('完成登录、下载Zip并验证文件内容', () => { // 1. 登录操作 cy.visit('/login'); cy.get('#username').type('你的用户名'); cy.get('#password').type('你的密码'); cy.get('[data-test="login-btn"]').click(); cy.url().should('include', '/dashboard'); // 2. 触发Zip下载并等待完成 cy.get('[data-test="download-zip-btn"]').click(); const zipFilePath = 'cypress/downloads/archive.zip'; cy.readFile(zipFilePath, { timeout: 10000 }).should('exist'); // 3. 调用Node环境的任务解压并读取文件 cy.task('extractAndValidateZip', zipFilePath).then((fileContents) => { // 4. 逐个验证文件内容 expect(fileContents['file1.txt']).to.include('预期的文本片段'); expect(fileContents['file2.csv']).to.match(/^ID,Name,Email$/); expect(JSON.parse(fileContents['file3.json'])).to.deep.equal({ status: 'success', data: [] }); expect(fileContents['file4.md']).to.contain('# 归档文件说明'); }); }); });
关键注意事项
- 确保
decompress已安装在项目依赖中(执行npm install decompress --save-dev) - 测试前确认Cypress的
downloads目录存在,或在任务中添加目录创建逻辑 - 任务中必须处理所有异常并抛出,避免出现未捕获的Promise拒绝
- 可根据实际需求调整目标文件名、解压路径和内容验证规则
内容的提问来源于stack exchange,提问作者springpendulum
相关产品推荐
相关产品推荐

