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

Cypress登录测试:如何从关联邮箱提取OTP完成登录

登录测试中邮箱OTP提取实现方案

项目文件夹结构

login-test-otp/
├── config/
│   └── Config.js       # 全局配置文件
├── utils/
│   └── emailHandler.js # 邮件操作核心逻辑
├── tests/
│   └── login.test.js   # 登录测试用例
├── package.json
└── package-lock.json

Config.js 配置

集中管理邮箱服务、账号和OTP匹配规则,方便后续调整:

module.exports = {
  email: {
    user: 'your-test-email@example.com', // 接收OTP的测试邮箱账号
    password: 'your-email-app-password', // 邮箱应用专用密码(优先用这个,别用主密码)
    host: 'imap.example.com', // IMAP服务器地址,比如Gmail是imap.gmail.com
    port: 993, // IMAP加密端口,常规是993
    tls: true,
    markSeen: false // 是否标记邮件为已读,测试阶段建议设为false
  },
  otp: {
    regex: /Your OTP code is: (\d{6})/, // 匹配6位数字OTP的正则,根据实际邮件内容修改
    timeout: 30000 // 等待邮件的超时时间(毫秒)
  }
};

邮件操作核心代码(utils/emailHandler.js)

用imap库连接邮箱,mailparser解析邮件内容,实现最新OTP提取逻辑:

const Imap = require('imap');
const { simpleParser } = require('mailparser');
const config = require('../config/Config');

// 初始化IMAP客户端
const imap = new Imap(config.email);

// 连接邮箱并提取最新OTP
async function getLatestOtp() {
  return new Promise((resolve, reject) => {
    let otp = null;

    imap.once('ready', () => {
      imap.openBox('INBOX', false, (err, box) => {
        if (err) return reject(err);
        // 按主题+未读筛选邮件,精准定位OTP邮件
        const searchCriteria = ['UNSEEN', ['SUBJECT', 'Login Verification OTP']];
        const fetchOptions = { bodies: ['TEXT'], markSeen: config.email.markSeen };

        imap.search(searchCriteria, (err, results) => {
          if (err) return reject(err);
          if (results.length === 0) {
            return reject(new Error('未找到OTP邮件'));
          }

          // 获取最新的一封匹配邮件
          const fetch = imap.fetch(results[results.length - 1], fetchOptions);
          fetch.on('message', (msg) => {
            msg.on('body', (stream) => {
              simpleParser(stream, async (err, parsed) => {
                if (err) return reject(err);
                // 从邮件正文匹配OTP
                const match = parsed.text.match(config.otp.regex);
                if (match) {
                  otp = match[1];
                  imap.end();
                  resolve(otp);
                } else {
                  reject(new Error('邮件中未找到OTP'));
                }
              });
            });
          });

          fetch.once('error', (err) => reject(err));
          fetch.once('end', () => {
            if (!otp) reject(new Error('OTP提取失败'));
            imap.end();
          });
        });
      });
    });

    imap.once('error', (err) => reject(err));
    imap.once('end', () => console.log('IMAP连接已关闭'));

    imap.connect();
  });
}

// 带超时限制的OTP获取函数
async function getOtpWithTimeout() {
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('OTP获取超时')), config.otp.timeout);
  });
  return Promise.race([getLatestOtp(), timeoutPromise]);
}

module.exports = { getOtpWithTimeout };

登录测试用例示例(tests/login.test.js)

在测试流程中调用邮件工具获取OTP,完成登录验证:

const { getOtpWithTimeout } = require('../utils/emailHandler');

// 这里以Jest测试框架为例,替换成你实际使用的测试工具
test('使用OTP完成登录', async () => {
  // 1. 触发登录请求,触发OTP发送
  await triggerLoginRequest('test-user@example.com'); // 你的登录触发逻辑

  // 2. 从邮箱获取OTP
  const otp = await getOtpWithTimeout();
  expect(otp).toHaveLength(6); // 验证OTP格式

  // 3. 提交OTP完成登录
  const loginResult = await submitLoginWithOtp('test-user@example.com', otp);
  expect(loginResult.success).toBe(true);
});

依赖安装

需要安装两个核心依赖:

npm install imap mailparser --save-dev

注意事项

  • 如果用Gmail,需要开启IMAP访问权限并生成应用专用密码(开启两步验证后才能生成)
  • 正则表达式要根据实际邮件里的OTP展示格式调整,比如OTP是4位就改成\d{4}
  • 测试用邮箱建议用专门的测试账号,避免干扰个人邮件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:05:31