Cypress如何同时校验表格常规行与子行的文本内容
问题:Cypress(Cucumber)测试遍历子元素时出现
TypeError: $subRow.text is not a function 场景与需求
需要验证表格第一列的每个条目都等于--,表格HTML结构如下:
<table> <tbody> <tr> <td class="first-col">--</td> <td class="second-col">--</td> <td class="third-col">--</td> </tr> <tr> <td class="first-col">--</td> <td class="second-col">--</td> <td class="third-col">--</td> </tr> <tr> <td class="first-col"> <div> <span class="sub-row">--</span> </div> <div> <span class="sub-row">--</span> </div> <div> <span class="sub-row">--</span> </div> </td> <td class="second-col"> <div> <span class="sub-row">--</span> </div> <div> <span class="sub-row">--</span> </div> <div> <span class="sub-row">--</span> </div> </td> <td class="third-col"> <div> <span class="sub-row">--</span> </div> <div> <span class="sub-row">--</span> </div> <div> <span class="sub-row">--</span> </div> </td> </tr> </tbody> </table>
最初的测试代码与错误
最初编写的测试代码:
Then('The first column displays -- in every row', function () { cy.get(this.base).find('.first-col').each(($row) => { expect($row.text().trim()).to.equal('--'); }); });
运行后第三行的子行文本被拼接,出现断言错误:
AssertionError
+ expected - actual-'-- -- --' +'--'
修改后的代码与新错误
修改代码后尝试遍历子行:
Then('The first column displays -- in every row', function () { cy.get(this.base).find('.first-col').each(($row) => { const subRows = $row.find('.sub-row'); if (subRows.length) { subRows.each(($subRow) => { expect($subRow.text().trim()).to.equal('--') }); } else { expect($row.text().trim()).to.equal('--'); } }); });
此时出现新错误:
TypeError: $subRow.text is not a function
前两行的else分支逻辑正常运行,疑问:对.each()或.find()的返回值存在概念误解?还是元素类型的问题?
问题原因
错误出在jQuery的.each()和Cypress的.each()的回调参数差异:
- 外层的
cy.get(...).each(($row) => {})是Cypress的命令,回调里的$row是Cypress封装的jQuery对象,因此可以调用.text()方法。 - 内层的
subRows.each(($subRow) => {})是jQuery原生的.each()方法,它的回调参数顺序是(index, element),其中element是原生DOM元素,不是jQuery对象,所以原生DOM元素没有.text()方法,导致报错。
修正方案
方案1:将原生DOM元素转为jQuery对象
在jQuery的.each()回调中,把原生DOM元素转成jQuery对象后再调用.text():
Then('The first column displays -- in every row', function () { cy.get(this.base).find('.first-col').each(($row) => { const subRows = $row.find('.sub-row'); if (subRows.length) { // jQuery.each的回调参数是(索引, 原生元素) subRows.each((index, subRow) => { // 把原生元素转为jQuery对象 expect($(subRow).text().trim()).to.equal('--') }); } else { expect($row.text().trim()).to.equal('--'); } }); });
方案2:用Cypress的.each()遍历子元素
通过cy.wrap()把jQuery对象包装成Cypress链式对象,再用Cypress的.each()遍历,此时回调参数是jQuery对象:
Then('The first column displays -- in every row', function () { cy.get(this.base).find('.first-col').each(($row) => { const subRows = $row.find('.sub-row'); if (subRows.length) { // 用cy.wrap将jQuery对象转为Cypress对象 cy.wrap(subRows).each(($subRow) => { expect($subRow.text().trim()).to.equal('--') }); } else { expect($row.text().trim()).to.equal('--'); } }); });
更简洁的写法
可以直接定位第一列下所有需要验证的文本元素,不管是td本身还是子行span,统一断言:
Then('The first column displays -- in every row', function () { // 定位第一列下的所有文本载体元素 cy.get(`${this.base} .first-col :is(.sub-row, :not(.sub-row))`).each(($el) => { expect($el.text().trim()).to.equal('--') }) });
内容的提问来源于stack exchange,提问作者Reed M
相关产品推荐
相关产品推荐

