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

Cypress:如何从登录接口响应体提取OTP并转为变量

解决Cypress登录测试中动态提取OTP的问题

问题背景

我是Cypress、JavaScript及编程新手,正在学习基础概念,恳请讲解尽量清晰,非常感谢!

测试场景:登录流程需要输入OTP(一次性密码),输入用户名/密码点击继续后,OTP会返回在接口响应体中,响应示例:

{"status":"VALID_USER","otp":"123456","maskedEmailAddress":"email@email.com","maskedPhoneNumber":"--****","otacDeliveryPreference":"SMS","pinRequired":true}

UI流程:输入用户名/密码 → 点击继续(触发请求) → 跳转至OTP输入页面。

我尝试用cy.intercept拦截请求提取OTP,但运行报错:

"cy.type() can only accept a string or number. You passed in: undefined"

测试代码如下:

context('QA login', () => {
  beforeEach(() => {
    cy.visit("https://QAlogin.com/login")  
  })

  it('should login to QA', () => {
    
    cy.get(usernameField)
      .type(username)
      .should('have.value', username); //enters username

    cy.get(passwordField)
      .type(password)
      .should('have.value', password); //enters password

    cy.intercept("POST", "/login").as("getLogin")  
      .get(loginButton)
      .click()

    cy.wait('@getLogin').then(xhr => {
      cy.log(xhr.response.body)
      const jsonResponseData = xhr.response.body
      const pinNumber = jsonResponseData['OTP'] 

      cy.get(accessCodeField).type(pinNumber)
      cy.get(submitButton).click()
    }); 
  })
});

错误原因分析

  1. 键名大小写不匹配:响应体中的OTP字段是小写的otp,但代码里用了大写的OTP去取值,直接导致pinNumber变成undefined,这是报错的核心原因。
  2. 拦截与操作的顺序问题:cy.intercept和cy.get(loginButton).click()链式调用时,可能出现拦截规则还未完全生效,请求就已经发送的情况,导致cy.wait('@getLogin')无法正确捕获目标请求。

修正方案

1. 修正字段名大小写

将jsonResponseData['OTP']改为jsonResponseData['otp']或者jsonResponseData.otp,保持和响应体的键名完全一致。

2. 调整拦截与点击的执行顺序

先单独设置好拦截规则,确保拦截生效后再触发登录请求,避免请求漏截。

修正后的完整代码

context('QA login', () => {
  beforeEach(() => {
    cy.visit("https://QAlogin.com/login")  
  })

  it('should login to QA', () => {
    // 输入用户名并验证输入内容
    cy.get(usernameField)
      .type(username)
      .should('have.value', username);

    // 输入密码并验证输入内容
    cy.get(passwordField)
      .type(password)
      .should('have.value', password);

    // 先设置拦截规则,给请求命名为getLogin
    cy.intercept("POST", "/login").as("getLogin");

    // 点击登录按钮触发请求
    cy.get(loginButton).click();

    // 等待拦截的请求完成,解构获取响应对象
    cy.wait('@getLogin').then(({ response }) => {
      // 打印响应体方便调试
      cy.log('登录接口响应:', response.body);
      
      // 提取响应体中的小写otp字段
      const pinNumber = response.body.otp;

      // 提前验证OTP的有效性,避免后续输入undefined
      expect(pinNumber).to.be.a('string').and.have.length(6);

      // 输入OTP并提交
      cy.get(accessCodeField).type(pinNumber);
      cy.get(submitButton).click();
    }); 
  })
});

额外调试建议

  • 如果还是取不到OTP,可以在cy.wait('@getLogin')的回调里添加console.log(response.body),在浏览器控制台查看完整响应数据,确认字段名和结构是否正确。
  • 检查cy.intercept的URL是否和实际请求的URL完全匹配,比如是否有前缀(如/api/login),可以用通配符**/login来匹配任意前缀的请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 04:15:48