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

Cypress中cy.type()失败因目标为禁用元素的解决方法

Cypress 验证码输入流程报错修复

问题场景

在commands.js中通过自定义loginByGoogleApi命令调用Google API登录Gmail账号,获取验证邮件正文后提取验证码存入常量code,计划在testFile.cy.js测试用例中填入提取到的验证码完成登录。目前登录流程可正常触发,但Cypress运行时抛出错误:
cy.type() failed because it targeted a disabled element.

原始代码

commands.js

/// <reference types="cypress" 
import { parseString } from "xml2js";
Cypress.Commands.add('loginByGoogleApi', () => {  
  cy.request({
    method: 'POST',
    url: 'https://www.googleapis.com/oauth2/v4/token',
    body: {
      grant_type: 'refresh_token',
      client_id:  Cypress.env('googleClientId'),
      client_secret:  Cypress.env('googleClientSecret'),
      refresh_token:  Cypress.env('googleRefreshToken'),
    },   
  }).then(({ body }) => {
    const { access_token, id_token } = body
    cy.log('Opening emails including code to verify')
    cy.request({
      method: 'GET',
      url: 'https://mail.google.com/mail/feed/atom/verifyCode',
      headers: { Authorization: Bearer ${access_token} },
    }).then(({ body }) => {
      parseString(body, function (err, results) {
        let data = JSON.stringify(results)
        let codeTitle = JSON.parse(data).feed.entry[0].title[0];
        let code = codeTitle.replace('Chaine confirmation code: ','');
        cy.log(code)
      });
    });   
  })
})

testFile.cy.js

const { Code } = require("@chaine/keychaine");


describe('Open login page', () => {   
  it('Enter your email to login', () => {
    cy.visit('https://chaineapp.com/staging/login%27)
    cy.get('#field-1').click().type('paras@loadtap.com');
    cy.get('[class*="chakra-button css-yg51i0"]').click();
    cy.get('#pin-input-2-0').type(<need to put code here>);
    })   
  it('get code', () => {
    cy.loginByGoogleApi()

  }) 
})

报错详情

cy.type() failed because it targeted a disabled element.
本次type操作的目标元素为:

<input aria-label="Please enter your pin code" inputmode="numeric" type="tel" id="pin-input-2-5" autocomplete="one-time-code" placeholder="" class="chakra-pin-input css-jyb0wy" value="1" data-index="5" disabled="">

请在执行type操作前确认目标元素不存在disabled属性。


根因分析

  1. 执行顺序错误:把输入验证码、拉取验证码拆成了两个独立的it用例,默认先执行输验证码的逻辑,此时不仅没拿到验证码,PIN输入框还没完成加载解锁。
  2. PIN输入框交互逻辑问题:报错指向的#pin-input-2-5是第6位验证码的输入框,Chakra的PIN输入组件初始状态下除第一位外,其余输入框默认带disabled属性,只有前一位输入完成才会解锁下一位,直接操作未解锁的输入框就会触发disabled报错。
  3. 自定义命令存在缺陷:
    • 提取到的code是parseString回调内的局部变量,没有对外返回,测试用例无法获取到验证码值
    • parseString是回调风格的异步方法,没有做Promise包装,Cypress不会等待XML解析完成就继续执行后续逻辑
    • 存在语法错误:请求头Authorization的Bearer token拼接没用模板字符串反引号,cy.visit的URL末尾多了冗余单引号
  4. 缺少状态等待:点击登录按钮后没有等待第一个PIN输入框解锁就直接执行输入操作,容易命中元素未就绪的状态。

修复方案

  1. 改造自定义loginByGoogleApi命令,包装异步解析逻辑,将提取到的验证码作为返回值返回,修复原有语法错误
  2. 合并测试流程,不要把拉取验证码、填写验证码拆成独立it块,保证验证码时效性,避免流程断裂
  3. 增加元素状态断言,每次输入验证码前确认当前位的输入框已移除disabled属性,逐位输入验证码自动解锁下一位输入框

修正后代码

commands.js

/// <reference types="cypress" />
import { parseString } from "xml2js";
Cypress.Commands.add('loginByGoogleApi', () => {  
  return cy.request({
    method: 'POST',
    url: 'https://www.googleapis.com/oauth2/v4/token',
    body: {
      grant_type: 'refresh_token',
      client_id:  Cypress.env('googleClientId'),
      client_secret:  Cypress.env('googleClientSecret'),
      refresh_token:  Cypress.env('googleRefreshToken'),
    },   
  }).then(({ body }) => {
    const { access_token } = body
    cy.log('拉取验证邮件中')
    return cy.request({
      method: 'GET',
      url: 'https://mail.google.com/mail/feed/atom/verifyCode',
      headers: { Authorization: `Bearer ${access_token}` },
    }).then(({ body }) => {
      return new Promise((resolve, reject) => {
        parseString(body, (err, results) => {
          if (err) return reject(err)
          const codeTitle = results.feed.entry[0].title[0];
          const verifyCode = codeTitle.replace('Chaine confirmation code: ','');
          cy.log(`提取到验证码:${verifyCode}`)
          resolve(verifyCode)
        });
      })
    });   
  })
})

testFile.cy.js

const { Code } = require("@chaine/keychaine");

describe('登录流程测试', () => {   
  it('输入邮箱-拉取验证码-完成登录', () => {
    cy.visit('https://chaineapp.com/staging/login')
    cy.get('#field-1').click().type('paras@loadtap.com');
    cy.get('[class*="chakra-button css-yg51i0"]').click();

    // 等待第一位验证码输入框解锁
    cy.get('#pin-input-2-0').should('not.be.disabled')
    // 调用自定义命令获取验证码
    cy.loginByGoogleApi().then(verifyCode => {
      // 逐位输入验证码,每输入一位前确认当前输入框已解锁
      verifyCode.split('').forEach((num, index) => {
        cy.get(`#pin-input-2-${index}`)
          .should('not.be.disabled')
          .type(num)
      })

      // 后续登录成功断言、业务操作写在这里
    })
  }) 
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:39:36