如何在Cypress(TypeScript)中测试DOM元素是否变化?
问题描述
我正在使用Cypress(搭配TypeScript)评估其是否适用于某Web应用的E2E测试。目前面临的挑战是没有数据库初始化工具,只能基于生产副本的staging环境测试,因此需要验证操作后DOM元素是否变化,比如筛选功能应用后结果是否改变。
应用筛选的代码:
visitCountryPage(); cy .get('#sharedTrips .filtersContainer button') .then((buttons: JQuery<HTMLElement>) => { buttons[0].click(); }) // 点击菜单选项 .get('#sharedTrips .filtersContainer label[for="experiencesrelax"]') .click();
我的尝试代码如下:
let initialIdeas: Chainable<JQuery<HTMLElement>> = getTripIdeas(); cy .get('#sharedTrips .filtersContainer button') .then((buttons: JQuery<HTMLElement>) => { buttons[0].click(); }) // 点击菜单选项 .get('#sharedTrips .filtersContainer label[for="experiencesrelax"]') .click() .then(() => { getTripIdeas().should('not.equal', initialIdeas); });
其中getTripIdeas()是通过DOM读取返回Chainable<JQuery<HTMLElement>>的外部函数。但即使移除最后一步click(),测试仍通过,怀疑是对象引用不同导致,想知道如何正确验证DOM元素变化。
解决方案
你的问题核心是直接比较Cypress的Chainable对象引用,而非实际的DOM元素内容或数量。Chainable每次调用都会生成新对象,所以即使DOM没变化,not.equal也会通过——因为两个对象的引用本来就不一样。
可以从以下几个方向正确验证筛选后的DOM变化:
1. 比较元素数量
如果筛选后结果数量会变化,直接断言数量不同:
// 先获取初始的结果数量 getTripIdeas().its('length').as('initialCount'); // 执行筛选操作 cy.get('#sharedTrips .filtersContainer button') .first().click() .get('#sharedTrips .filtersContainer label[for="experiencesrelax"]') .click(); // 断言筛选后的数量和初始数量不同 getTripIdeas().its('length').should('not.eq', this.initialCount);
2. 比较元素的文本内容集合
如果结果的文本内容会变化,把元素的文本提取成数组再比较:
// 存储初始结果的文本数组 getTripIdeas().then($ideas => { const initialTexts = Array.from($ideas).map(el => el.textContent?.trim()); // 执行筛选 cy.get('#sharedTrips .filtersContainer button') .first().click() .get('#sharedTrips .filtersContainer label[for="experiencesrelax"]') .click(); // 断言筛选后的文本集合和初始不同 getTripIdeas().then($filteredIdeas => { const filteredTexts = Array.from($filteredIdeas).map(el => el.textContent?.trim()); expect(filteredTexts).to.not.deep.equal(initialTexts); }); });
3. 断言特定元素出现/消失
如果筛选后有明确的预期元素(比如某个特定旅行项应该被筛选掉或出现),可以直接断言该元素的存在状态:
// 先确认某个元素在初始结果中存在 cy.get('.trip-idea[data-id="relax-trip-123"]').should('exist'); // 执行筛选 cy.get('#sharedTrips .filtersContainer button') .first().click() .get('#sharedTrips .filtersContainer label[for="experiencesrelax"]') .click(); // 断言该元素消失(如果是筛选保留则用should('exist')) cy.get('.trip-idea[data-id="relax-trip-123"]').should('not.exist');
额外优化:简化点击代码
你原来的按钮点击逻辑可以简化,不需要用then手动调用click,Cypress的get返回的元素可以直接调用click():
cy.get('#sharedTrips .filtersContainer button').first().click();
这样比手动操作JQuery数组更符合Cypress的最佳实践。
内容的提问来源于stack exchange,提问作者halfer
相关产品推荐
相关产品推荐

