使用 Svelte 进行 Flaky cypress 测试:按钮有时会被点击,有时不会

Flaky cypress test with Svelte: Button is sometimes clicked, sometimes not

我正在使用 Cypress 测试我的 SvelteKit 网站。我有时会遇到不稳定的测试,类似于此处描述的情况:https://www.cypress.io/blog/2019/01/22/when-can-the-test-click/。简而言之,赛普拉斯有时会在附加事件侦听器之前找到并单击按钮——结果,单击无处可去。建议的解决方案是简单地重新尝试单击,直到附加了适当的侦听器。这也适用于我的情况。然而,尽管我确实理解为什么这在博客 post 中给出的示例中可能是一个问题(这是一个大日历模式),但我发现很难证明使用简单的 Svelte 按钮时会出现此问题。

下面是一个简单的按钮示例,在单击时会显示一些内容:

<script>
  let hide = true;
</script>

<button
  on:click={() => {
    console.log('clicked');
    hide = false;
  }}>
  Show
</button>

<span class:hide>Content</span>

<style>
  .hide {
    visibility: hidden;
  }
</style>

相应的测试有时通过,有时失败:

it('reveals content on click', () => {
  cy.contains('Show').click();
  cy.contains('Content').should('be.visible');
});

同样,我知道可以通过重新尝试单击按钮来解决此问题。如果这就是让 Cypress 与 Svelte/SvelteKit 一起工作所需要的,那么我觉得没问题。但我想知道:为什么这会成为一个问题?

最小复制回购:https://github.com/sophiamersmann/test-svelte-kit-cypress

SvelteKit 默认会进行服务器端渲染 (SSR),这意味着完整的 HTML 会发送到浏览器,包括按钮。然后 HTML 之后需要补充水分才能变得互动。这意味着一些代码运行,以便 Svelte 连接到已经存在的 HTML。 Cypress 在这里可能“太快”了,在水化步骤完成之前点击了按钮,因此没有任何反应。

纯 Svelte 不会发生这种情况,因为不涉及 SSR。最初有一个空白的 index.html 页面,它完全由浏览器中的 Svelte JavaScript 填充,所以当按钮可见时,事件侦听器和其他所有内容都已由 Svelte 初始化。

步进比较:

带 SSR 的 SvelteKit:

  1. 转到第 X 页
  2. 页面 X 在服务器上呈现
  3. 页面 X 被发送到浏览器,带有完整的 HTML
  4. Svelte 补充了 HTML(赛普拉斯点击测试的竞争条件)
  5. 完成

没有 SSR 的纯 Svelte 或 SvelteKit:

  1. 转到第 X 页
  2. 空白页面被发送到浏览器
  3. Svelte 在浏览器中构建并初始化 HTML(Cypress 的点击测试没有竞争条件)
  4. 完成

我认为问题出在Vite,它使用ES模块加载页面及其组件。

在 cy.visit() 之前添加截距似乎给出了一致的结果。 (注意拦截的 URL 可能会有所不同,您可以从 devtools Network 的最后一个条目中获取)。

beforeEach(() => {
  cy.intercept('index.svelte?svelte&type=style&lang.css').as('svelte')
  cy.visit('/');
  cy.wait('@svelte')
});

使用 cypress-grep 到 burn-test

npx cypress run --env burn=100

有拦截

没有拦截


为什么不补水?

如果您创建一个等效的 Svelte 应用并将 hydratable 设置为 true,它将通过刻录测试 - IMO,因为它使用 rollup 而不是 vite将应用交付给浏览器。