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

使用Cypress测试Material-UI Select组件时无法选择选项(超时)

Cypress测试Material-UI多选Select组件失败问题

问题现象

登录并打开对话框后,无法从Material-UI Select组件中选择选项,断言报错:

Assert: expected '' to equal Rxx.

应用是Corda网络的前端,部署在Kubernetes集群,使用Skaffold管理开发环境。

对话框组件简化代码

<Grid container spacing={2}>
  <Grid item xs={12}>
    <FormikFormControlSelect
      formik={formik}
      label="Insurers"
      id="insurers"
      variant="outlined"
      dataCy="insurers"
      fullWidth
      multiple
      disabled={promiseInProgress}
    >
      {memberships.insurers?.map((membership, index) => (
        <MenuItem key={index} value={membership.identity}>
          {membership.identity}
        </MenuItem>
      ))}
    </FormikFormControlSelect>
  </Grid>
</Grid>

当前测试代码

describe('MachineDialog', () => {
  it('should add a new machine successfully', () => {
    // 登录流程
    cy.visit('https://xx.xx.xxx.xxxxxx.com/machines');
    cy.get('input#username').type('xxx');
    cy.get('input#password').type('xxxxxxxx');
    cy.get('input#kc-login').click();

    // 打开新建机器对话框
    cy.get('[data-cy="new-machine-btn"]').click({ force: true });

    cy.get('#insurers-select', {timeout:5000)   // 语法错误:缺少闭合括号
      .parent()
      .should('be.visible')
      .click()                              // 无需点击父元素

    cy.get('[aria-labelledby="insurers-label"]')
      .as('options')
      .find('li')
      .should('have.length.gt', 0)       // 确保选项加载完成

    cy.get('@options')     
      .contains('li', 'Rxx)')   // 多余右括号,应为'Rxx'
      .should('be.visible')
      .click()

    cy.get('#insurers')
      .find('input')
      .invoke('val')
      .should('eq', 'Rxx')  // 多选模式下input的val不会直接显示选中值
  })
})

运行时错误信息

index-b28d6e1f.js:133631 Error:     AssertionError: Timed out retrying after 4000ms: Expected '' to equal Rxx

              > cy.get(@insurers-select, [object Object])
    at Context.eval (webpack://xxxxxx.com/./cypress/e2e/machineDialogInt.cy.ts:49:62)
    at runnable.fn (https://xxxxxx.com/__cypress/runner/cypress_runner.js:138678:19)
    at callFn (https://xxxxxx.com/__cypress/runner/cypress_runner.js:157289:21)
    at Runnable.run (https://xxxxxx.com/__cypress/runner/cypress_runner.js:157276:7)
    at <unknown> (https://xxxxxx.com/__cypress/runner/cypress_runner.js:163200:30)
    at PassThroughHandlerContext.finallyHandler (https://xxxxxx.com/__cypress/runner/cypress_runner.js:4072:23)
    at PassThroughHandlerContext.tryCatcher (https://xxxxxx.com/__cypress/runner/cypress_runner.js:1807:23)
    at Promise._settlePromiseFromHandler (https://xxxxxx.com/__cypress/runner/cypress_runner.js:1519:31)
index-b28d6e1f.js:133631 Actual:    0
index-b28d6e1f.js:133631 Expected:  0

(webpack://xxxxxx/./cypress/e2e/machineDialogInt.cy.ts:49:62)
    at runnable.fn (cypress_runner.js:138678:19)
    at callFn (cypress_runner.js:157289:21)
    at Runnable.run (cypress_runner.js:157276:7)
    at <unknown> (cypress_runner.js:163200:30)
    at PassThroughHandlerContext.finallyHandler (cypress_runner.js:4072:23)
    at PassThroughHandlerContext.tryCatcher (cypress_runner.js:1807:23)
    at Promise._settlePromiseFromHandler (cypress_runner.js:1519:31)
logError @ index-b28d6e1f.js:133634
(anonymous) @ index-b28d6e1f.js:145969
emit2 @ index-b28d6e1f.js:139329
(anonymous) @ cypress_runner.js:182180
emit @ cypress_runner.js:146549
emit @ cypress_runner.js:182243
onPrint @ cypress_runner.js:200038
_onPrintClick @ cypress_runner.js:200042
(anonymous) @ cypress_runner.js:199743
executeAction @ cypress_runner.js:180885
n @ cypress_runner.js:180885
ca @ cypress_runner.js:245
ja @ cypress_runner.js:246
ka @ cypress_runner.js:246
wa @ cypress_runner.js:248
Aa @ cypress_runner.js:249
ya @ cypress_runner.js:249
Da @ cypress_runner.js:252
Ad @ cypress_runner.js:315
Gi @ cypress_runner.js:481
Kb @ cypress_runner.js:270
Dd @ cypress_runner.js:317
(anonymous) @ cypress_runner.js:482
exports.unstable_runWithPriority @ cypress_runner.js:537
Ii @ cypress_runner.js:482
Cd @ cypress_runner.js:316

DOM元素对比

未选择选项时

<div class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12">
  <div class="MuiFormControl-root MuiFormControl-fullWidth" id="insurers">
    <label class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-outlined" data-shrink="false" id="insurers-label">Insurers</label>
    <div class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-formControl" data-cy="insurers">
      <div class="MuiSelect-root MuiSelect-select MuiSelect-selectMenu MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input" role="button" aria-haspopup="listbox" aria-labelledby="insurers-label insurers-select" id="insurers-select" tabindex="0">
        <span>​</span>
      </div>
      <input aria-hidden="true" tabindex="-1" class="MuiSelect-nativeInput" value="">
      <svg class="MuiSvgIcon-root MuiSelect-icon MuiSelect-iconOutlined" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
        <path d="M7 10l5 5 5-5z"></path>
      </svg>
      <fieldset aria-hidden="true" class="jss54 MuiOutlinedInput-notchedOutline">
        <legend class="jss56"><span>Insurers</span></legend>
      </fieldset>
    </div>
  </div>
</div>

手动选择选项后

<ul class="MuiList-root MuiMenu-list MuiList-padding" role="listbox" tabindex="-1" aria-labelledby="insurers-label">
  <li class="MuiButtonBase-root MuiListItem-root MuiMenuItem-root Mui-selected MuiMenuItem-gutters MuiListItem-gutters MuiListItem-button Mui-selected" tabindex="0" role="option" aria-disabled="false" data-cy="select-option-Rxx" data-value="Rxx" aria-selected="true">
    Rxx
    <span class="MuiTouchRipple-root"></span>
  </li>
</ul>

修正方案

1. 修复语法错误

测试代码中cy.get('#insurers-select', {timeout:5000)缺少闭合括号,应改为:

cy.get('#insurers-select', {timeout:5000})

2. 修正选项选择器

contains('li', 'Rxx)')多了一个右括号,改为contains('li', 'Rxx')

3. 调整Select打开方式

直接点击#insurers-select元素,无需点击父元素:

cy.get('#insurers-select', {timeout:5000})
  .should('be.visible')
  .click()

4. 正确断言选中状态

由于组件是multiple多选模式,MuiSelect-nativeInput的value不会直接显示选中值,可通过以下方式断言:

  • 断言选项的aria-selected状态为true
  • 断言Formik表单中的对应字段值
  • 断言组件显示的选中文本

示例断言代码:

// 断言选项已被选中
cy.get('[data-cy="select-option-Rxx"]')
  .should('have.attr', 'aria-selected', 'true')

// 或者断言Formik表单中的值(如果能访问formik实例)
cy.window().its('formik.values.insurers').should('include', 'Rxx')

修正后的完整测试代码

describe('MachineDialog', () => {
  it('should add a new machine successfully', () => {
    // 登录流程
    cy.visit('https://xx.xx.xxx.xxxxxx.com/machines');
    cy.get('input#username').type('xxx');
    cy.get('input#password').type('xxxxxxxx');
    cy.get('input#kc-login').click();

    // 打开新建机器对话框
    cy.get('[data-cy="new-machine-btn"]').click({ force: true });

    // 打开Select下拉框
    cy.get('#insurers-select', {timeout:5000})
      .should('be.visible')
      .click()

    // 等待选项加载并选择目标选项
    cy.get('[aria-labelledby="insurers-label"]')
      .find('li')
      .should('have.length.gt', 0)
      .contains('li', 'Rxx')
      .should('be.visible')
      .click()

    // 断言选项已被选中
    cy.get('[data-cy="select-option-Rxx"]')
      .should('have.attr', 'aria-selected', 'true')
  })
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:44:53