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

本地正常的Cypress模态框元素测试为何在GitHub Actions中失败?

问题

在Vue+Ionic应用中,自定义Cypress命令cy.el(selector)用于查找模态框内元素,本地测试正常,但在GitHub Actions中部分测试失败,报错Timed out retrying after 10000ms: Expected to find element。已确认模态框存在于DOM中,且延长超时时间至60秒仍无效。

自定义命令代码:

Cypress.Commands.add('el', (selector) => {
  return cy
    .get('ion-modal:not(.overlay-hidden)', { timeout: 50000 })
    .first({ timeout: 50000 })
    .find('.ion-page:not(.ion-page-hidden)', { timeout: 50000 })
    .first({ timeout: 50000 })
    .find(selector, { timeout: 50000 })
    .should('be.exist', { timeout: 50000 })
})

GitHub Actions相关配置:

name: cypress
on: [push]
jobs:
  cypress-run:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v1
      - name: Install dependencies
        run: npm ci
      - name: Cypress - pre-analyses test
        uses: cypress-io/github-action@v5
        with:
          start: npm run test:e2e:chrome
          browser: chrome
          screenshotOnRunFailure: true
          screenshotsFolder: 'cypress/screenshots'
          wait-on: http://localhost:8080/
          config-file: cypress.config.ts
          spec: "tests/e2e/**/*"
        env:
          CYPRESS_baseUrl: http://localhost:8080/
          VUE_APP_API_BASE_URL: ${{ secrets.VUE_APP_API_BASE_URL }}
          VUE_APP_MAP_KEY: ${{ secrets.VUE_APP_MAP_KEY }}
          VUE_APP_SEGMENT_KEY: ${{ secrets.VUE_APP_SEGMENT_KEY }}
          VUE_APP_SENTRY_DSN: ${{ secrets.VUE_APP_SENTRY_DSN }}
          CYPRESS_USER_EMAIL: ${{ secrets.CYPRESS_USER_EMAIL }}
          CYPRESS_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}

测试用例核心逻辑:

describe('Test simulation', { includeShadowDom: true }, () => {
  beforeEach(() => {
    cy.login()
  })

  it('simulation flow', () => {
    cy.location('pathname', { timeout: 50000 }).should('include', 'page/home')
    cy.wrap(scenarios).each((scenario) => {
      cy.wait(2000)
      cy.get('[data-cy="home-page"]').should('be.exist', { timeout: 10000 }).first().click({ force: true })
      cy.wait(2000)
      cy.get('[data-cy="new-simulation"]')
        .should('be.exist', { timeout: 10000 })
        .first()
        .wait(600)
        .shadow()
        .find('button')
        .first()
        .click({ force: true })

      // step 0
      cy.wait(4000)
      cy.el('[data-cy="address"] input')
      cy.el('[data-cy="address"] input').click().type(scenario.address, { delay: 100 })
      cy.get('div.pac-item').first().click({ force: true })
      cy.el('[data-cy="submit"]').shadow().find('button').should('not.be.disabled').click({ force: true })

      // ...后续多步骤提交逻辑
    })
  })
})
原因分析
  • 模态框上下文未更新:自定义命令中ion-modal:not(.overlay-hidden)的选择器,无法确保每次都匹配当前活跃的模态框。在GitHub Actions环境下,DOM更新延迟可能导致命令捕获到已隐藏的旧模态框。
  • 硬编码等待不可靠:测试中大量使用cy.wait(xxx),本地环境速度快可覆盖,但GitHub Actions资源有限,等待时间不足/过长都会导致元素查找失败,且硬等待会破坏测试的稳定性。
  • 状态判断不精准:ion-modal:not(.overlay-hidden)和.ion-page:not(.ion-page-hidden)的组合,无法精准识别Ionic模态框切换时的过渡状态,可能匹配到非目标模态框。
  • 重试机制未有效利用:自定义命令中重复设置超时,但未通过Cypress的should断言触发自动重试,无法应对DOM动态变化。
修复方案

1. 优化自定义命令cy.el()

更新命令,确保每次查找当前可见的活跃模态框,并简化超时配置(继承Cypress全局超时):

Cypress.Commands.add('el', (selector) => {
  return cy
    .get('ion-modal', { timeout: 50000 })
    .filter(':visible') // 用:visible更可靠判断模态框状态
    .first()
    .find('.ion-page')
    .filter(':visible')
    .first()
    .find(selector)
    .should('exist') // should会自动触发重试,无需重复设置超时
})

2. 替换硬等待为断言式等待

移除所有cy.wait(xxx),改用元素可见/存在的断言等待,让测试自适应环境速度:

// 替换step0中的硬等待
cy.el('[data-cy="address"] input').should('be.visible')

// 提交后等待下一个步骤的元素(替代cy.wait(800))
cy.el('[data-cy="submit"]').shadow().find('button').should('not.be.disabled').click()
cy.el('[data-cy="property_ownership_type"]').should('be.visible')

3. 确保模态框切换后的上下文重置

每次提交后,等待旧模态框隐藏或新模态框元素出现,避免上下文混乱:

cy.el('[data-cy="submit"]').shadow().find('button').click()
// 等待旧模态框隐藏
cy.get('ion-modal').filter(':visible').should('not.have.attr', 'data-cy', 'step-0')
// 或直接等待新步骤元素
cy.el('[data-cy="property_ownership_type"]').should('be.visible')

4. 优化GitHub Actions配置

  • 升级依赖版本,适配无头环境:
jobs:
  cypress-run:
    runs-on: ubuntu-latest
    env:
      NODE_OPTIONS: "--max-old-space-size=8192" # 增加Node内存限制
    steps:
      - name: Checkout
        uses: actions/checkout@v4 # 升级到最新版本
      # ...其他步骤
      - name: Cypress - pre-analyses test
        uses: cypress-io/github-action@v6 # 升级到最新版本
        with:
          start: npm run test:e2e:chrome
          browser: chrome
          headless: true # 明确启用无头模式
          # ...其他配置
  • 在cypress.config.ts中添加Chrome无头模式参数:
export default defineConfig({
  e2e: {
    browser: {
      chrome: {
        args: ['--no-sandbox', '--disable-gpu', '--headless=new']
      }
    }
  }
})

5. 测试用例细节优化

  • 移除不必要的{ force: true },强制点击会跳过元素可见性检查,增加测试不稳定风险。
  • 循环测试中重置状态,确保每次循环从干净的首页开始:
cy.wrap(scenarios).each((scenario) => {
  cy.location('pathname').should('include', 'page/home')
  // ...后续测试步骤
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:17:52