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() }); }) });
错误原因分析
- 键名大小写不匹配:响应体中的OTP字段是小写的
otp,但代码里用了大写的OTP去取值,直接导致pinNumber变成undefined,这是报错的核心原因。 - 拦截与操作的顺序问题:
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
相关产品推荐
相关产品推荐

