使用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
相关产品推荐
相关产品推荐

