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

实现Cypress测试报告、截图及视频自动上传至MongoDB

可行性说明

完全可行。Cypress提供了测试生命周期钩子来捕获测试完成事件,结合MongoDB的Node.js驱动(支持GridFS存储大文件),可以实现测试报告、截图、视频的自动上传。

具体实现步骤

1. 安装依赖

  • 安装MongoDB Node.js驱动:
    npm install mongodb
    
  • 若使用Mochawesome等第三方报告工具,按需安装对应包(如mochawesome、mochawesome-merge)。

2. 编写Cypress生命周期钩子

在cypress.config.js(或.ts)中使用after:run钩子,这个钩子会在整个测试套件运行结束后触发,适合处理上传逻辑:

const { defineConfig } = require('cypress');
const { MongoClient, GridFSBucket } = require('mongodb');
const fs = require('fs');
const path = require('path');

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on('after:run', async (results) => {
        let client;
        try {
          // 1. 连接MongoDB
          client = new MongoClient('mongodb://localhost:27017');
          await client.connect();
          const db = client.db('cypress_dashboard');

          // 2. 上传测试报告(以Mochawesome JSON报告为例)
          const reportPath = path.join(config.projectRoot, 'mochawesome-report', 'mochawesome.json');
          if (fs.existsSync(reportPath)) {
            const reportContent = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));
            await db.collection('test_reports').insertOne({
              testRunId: results.runId,
              timestamp: new Date(),
              report: reportContent,
              status: results.status,
              totalTests: results.totalTests,
              passedTests: results.passedTests,
              failedTests: results.failedTests
            });
          }

          // 3. 上传截图(Cypress默认路径:cypress/screenshots)
          const screenshotsDir = path.join(config.projectRoot, 'cypress', 'screenshots');
          if (fs.existsSync(screenshotsDir)) {
            const screenshotFiles = fs.readdirSync(screenshotsDir).filter(f => f.endsWith('.png'));
            const bucket = new GridFSBucket(db, { bucketName: 'screenshots' });
            
            for (const file of screenshotFiles) {
              const filePath = path.join(screenshotsDir, file);
              const uploadStream = bucket.openUploadStream(file, {
                metadata: { testRunId: results.runId, timestamp: new Date() }
              });
              await new Promise((resolve) => {
                fs.createReadStream(filePath).pipe(uploadStream).on('finish', resolve);
              });
            }
          }

          // 4. 上传视频(Cypress默认路径:cypress/videos)
          const videosDir = path.join(config.projectRoot, 'cypress', 'videos');
          if (fs.existsSync(videosDir)) {
            const videoFiles = fs.readdirSync(videosDir).filter(f => f.endsWith('.mp4'));
            const bucket = new GridFSBucket(db, { bucketName: 'videos' });
            
            for (const file of videoFiles) {
              const filePath = path.join(videosDir, file);
              const uploadStream = bucket.openUploadStream(file, {
                metadata: { testRunId: results.runId, timestamp: new Date() }
              });
              await new Promise((resolve) => {
                fs.createReadStream(filePath).pipe(uploadStream).on('finish', resolve);
              });
            }
          }
        } catch (err) {
          console.error('上传测试资源失败:', err);
        } finally {
          if (client) await client.close();
        }
      });
    },
  },
});

3. 配置MongoDB存储策略

  • 小文件(截图、小型报告):若文件小于16MB,可转成Base64字符串存入普通集合;但更推荐用GridFS统一管理。
  • 大文件(测试视频):必须用GridFS,它会自动将大文件拆分为256KB的块存储,避免MongoDB单文档大小限制。

4. 验证与调试

  • 运行测试:npx cypress run,观察控制台输出的上传日志。
  • 检查MongoDB:查看test_reports集合、screenshots.files/screenshots.chunks、videos.files/videos.chunks是否生成对应数据。
  • 排查问题:若上传失败,检查MongoDB连接字符串、本地文件路径权限、磁盘空间是否充足。
额外建议
  • 本地文件清理:上传完成后,可通过fs.unlinkSync(filePath)删除本地截图/视频,节省磁盘空间。
  • 关联ID绑定:用Cypress的results.runId作为所有资源的关联标识,方便在Dashboard中按测试运行查询对应资源。
  • 并发控制:若测试生成大量文件,可限制同时上传的流数量,避免占用过多系统资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 17:50:36