使用Cypress测试Material UI下拉框时偶发失效问题排查
问题描述
尝试了多种方法,但测试并不总是生效。测试代码能够找到元素并点击,但下拉输入框并非总能成功赋值。由于该下拉框为必填项,导致测试无法继续进行。下拉输入框不能为空。
自定义Cypress命令代码如下:
Cypress.Commands.add("selectTooltipDropdownOption", (optionText, inputSelector) => { cy.getCyInput(inputSelector,{timeout:10000}).click(); cy.getCyRole("menu").children('li').contains(optionText).trigger("click", { timeout: 10000 }); cy.getCyInput(inputSelector) .invoke("prop", "defaultValue") .should("contain", optionText); });
请问如何确保cy.getCyInput("dropdowninputField")始终有值,而非空状态?
该下拉框并非原生select类型,是基于Material UI样式封装的经典下拉组件,其HTML结构如下:
<div role="tooltip" class="jss390" style=" position: absolute; top: 0px; left: 0px; transform: translate3d(317px, 412px, 0px); will-change: transform; " x-placement="bottom" > <div class="MuiPaper-root MuiPaper-elevation8 MuiPaper-rounded"> <ul class="MuiList-root jss389 MuiList-padding" role="menu" tabindex="-1" data-cy-action="select-action-root/insured/seller/0/data/address/country" style="min-width: 271px" > <li class="MuiButtonBase-root MuiListItem-root MuiMenuItem-root MuiMenuItem-gutters MuiListItem-gutters MuiListItem-button" tabindex="0" role="menuitem" aria-disabled="false" > Austria<span class="MuiTouchRipple-root"></span> </li> <li class="MuiButtonBase-root MuiListItem-root MuiMenuItem-root MuiMenuItem-gutters MuiListItem-gutters MuiListItem-button" tabindex="-1" role="menuitem" aria-disabled="false" > Belgium<span class="MuiTouchRipple-root"></span> </li> <!-- 其他选项省略 --> </ul> </div> </div>
解决方案
针对Material UI的自定义下拉组件,调整Cypress命令的几个关键逻辑,就能确保选择操作稳定触发组件状态更新:
1. 用真实点击替代trigger("click")
trigger("click")仅触发DOM基础事件,但Material UI的MenuItem组件依赖React合成事件处理内部状态更新,直接使用.click()能更可靠地触发选择逻辑:
cy.getCyRole("menu").children('li').contains(optionText).click({ timeout: 10000 });
2. 验证正确的属性或文本内容
defaultValue是输入框的初始值,选择选项后组件通常更新的是value属性或输入框的显示文本,而非defaultValue。根据组件结构,选择以下一种方式验证:
// 验证输入框显示的文本 cy.getCyInput(inputSelector).should("have.text", optionText); // 或者验证value属性(如果组件绑定了value) cy.getCyInput(inputSelector).invoke("prop", "value").should("eq", optionText);
3. 等待下拉菜单完全渲染
点击输入框后,先确保下拉菜单(role="menu"的元素)完全显示再操作选项,避免因菜单未渲染完成导致的元素查找失败:
cy.getCyInput(inputSelector, {timeout:10000}).click(); // 等待菜单可见 cy.getCyRole("menu", {timeout:10000}).should("be.visible"); // 再查找并点击选项 cy.getCyRole("menu").children('li').contains(optionText).click({ timeout: 10000 });
4. 添加重试机制确保赋值成功
利用Cypress的自动重试特性,通过断言强制等待输入框状态更新完成:
cy.getCyInput(inputSelector) .should(($input) => { const value = $input.val() || $input.text(); expect(value).to.contain(optionText); });
优化后的完整命令
Cypress.Commands.add("selectTooltipDropdownOption", (optionText, inputSelector) => { // 点击输入框打开下拉菜单,确保获得焦点 cy.getCyInput(inputSelector, { timeout: 10000 }) .click() .should("be.focused"); // 等待菜单完全可见 cy.getCyRole("menu", { timeout: 10000 }).should("be.visible"); // 点击目标选项 cy.getCyRole("menu") .find(`li:contains("${optionText}")`) .click({ timeout: 10000 }); // 验证输入框已正确赋值 cy.getCyInput(inputSelector) .should(($input) => { const displayValue = $input.text().trim() || $input.val(); expect(displayValue).to.eq(optionText); }); });
额外建议
- 如果选项是异步加载的,需先等待加载状态结束,比如添加
.should("not.have.class", "loading")断言。 - 用
find('li')替代children('li'),能更灵活地查找嵌套的选项元素。
内容的提问来源于stack exchange,提问作者Fah
相关产品推荐
相关产品推荐

