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

如何让Cypress执行检查等待循环直至DOM元素发生变化?

如何在Cypress中替代固定等待,实现DOM变化的智能检测?

我之前在Stack Overflow提问过如何检测页面操作引发的DOM变化,收到了基于as()方法捕获状态的优质解答,以下是基于该解答的可运行测试代码:

visitCountryPage();

// 捕获trip ideas的初始状态(静态变量)
getTripIdeas().as('initialValues', { type: 'static' });

// 打开筛选菜单
cy
  .get('#sharedTrips .filtersContainer button')
  .first()
  .click();

// 选择筛选选项,触发内容变化
cy
  .get('#sharedTrips .filtersContainer label[for="experiencesrelax"]')
  .click()
  // @todo 能不能不用这种固定等待?
  .wait(3000);

// 捕获变化后的trip ideas状态
getTripIdeas().as('finalValues', { type: 'static' });

// 断言初始状态与最终状态不同
cy.get('@initialValues').then(initial => {
  cy.get('@finalValues')
    .invoke('toArray') // 将JQuery<HTMLElement>转为HTMLElement数组
    .should('not.deep.eq', initial.toArray())
});

测试步骤

  • 访问目标页面
  • 对"trip ideas"结果网格进行快照
  • 打开筛选弹出菜单
  • 选择菜单中的筛选选项
  • 等待固定时长直至页面变化 🙈
  • 再次对结果网格进行快照
  • 验证两次快照内容不同

获取Trip Ideas元素的方法

下面是我封装的获取目标元素的代码:

/**
 * 根据CSS选择器获取网格元素(比如卡片集合)
 */
export function getTripIdeas(): Cypress.Chainable<JQuery<HTMLElement>> {
  return getGridElements(
    '#sharedTrips section .container div:last-child .card-layout div.column'
  );
}

/**
 * 通用的网格元素获取方法
 */
function getGridElements(cssSelector: string): Cypress.Chainable<JQuery<HTMLElement>> {
  return cy
    .get('body')
    .find(cssSelector);
}

优化需求:替代固定等待的智能检测

当前测试中使用了wait(3000)来等待AJAX请求完成,但更符合Cypress设计理念的做法是:告诉Cypress"我期望这个变化发生,请等待最长X秒直到条件满足"。这种方式可以设置较长超时(比如15秒),一旦条件满足会立即通过,无需等待满时长。

在PHP/Selenium中,我会用这样的循环检查方法:

protected function waitUntil(callable $callback, string $reason, $timeout = 10): void
{
    $now = microtime(true);
    do {
        usleep(500 * 1000); // 每隔0.5秒检查一次
        $withinTimeout = (microtime(true) - $now) < $timeout;
        $passedTest = $callback($this->getDriver());
    } while ($withinTimeout && !$passedTest);

    if (!$passedTest) {
        throw new RuntimeException(
            sprintf('Failed to wait for %s', $reason)
        );
    }
}

调用示例:

// 等待推荐内容加载完成
$this->waitUntil(
    function(RemoteWebDriver $driver) {
        try {
            $ideas = $driver->findElements(WebDriverBy::cssSelector(
                '#sharedTrips section .container div:last-child .card-layout div.column'
            ));
            // 初始加载时通常有8个元素,这里判断数量是否大于4
            return count($ideas) > 4;
        } catch (NoSuchElementException $e) {
            return false;
        }
    },
    'trip ideas to populate'
);

注:以上仅展示同步语言中循环检查DOM的方式,并非检测DOM内容变化的示例

这种每隔一段时间检查一次DOM,直到条件满足或超时的方式,更符合我的测试习惯。能不能在Cypress中实现类似功能,去掉固定等待以提升测试的健壮性?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:11:03