Skip to content

Cypress - 选项卡

一个常见的网页模式是链接或按钮会打开新的浏览器标签页或窗口,这通常通过在 <a> 标签上使用 target="_blank" 属性实现。Cypress 的设计理念是在单个浏览器标签页内运行。它不提供直接切换到或与新的标签页或窗口交互的原生支持。

这种设计选择有助于 Cypress 的速度和可靠性,因为管理多个标签页可能会引入不稳定性(flakiness)。然而,Cypress 为涉及通常会在新标签页中打开的链接的测试场景提供了一个直接的解决方法。

最常见的策略是在点击链接元素之前,以编程方式移除它的 target 属性。这将导致链接在同一标签页中打开,从而允许 Cypress 继续与新加载的页面进行交互。

Cypress 使用 jQuery 方法 removeAttr() 来实现这一点,通过 cy.invoke() 命令调用。通过移除 target="_blank",浏览器的默认行为是在当前标签页中打开链接。

在与新页面(现在在同一标签页中)的内容交互后,如果需要,你可以使用 cy.go('back') 导航回上一页。

考虑以下 HTML 代码片段,其中一个链接被设计为在新标签页中打开:

/links.html
<!-- 在页面: /links.html -->
<a id="new-tab-link" href="/new-page.html" target="_blank">Open New Page</a>

以下是如何在 Cypress 中测试此场景:

describe('New Tab Handling', () => {
it('Should open link in the same tab by removing target attribute', () => {
// Visit the page containing the link
// 访问包含链接的页面
cy.visit('https://the-internet.herokuapp.com/windows'); // A great site for practice
// 一个很好的练习网站
// Find the link that opens a new window/tab
// 找到打开新窗口/标签页的链接
// The selector '.example > a' targets the link on this specific page
// 选择器 '.example > a' 定位到此特定页面上的链接
cy.get('.example > a')
.invoke('removeAttr', 'target') // Remove the target attribute
// 移除 target 属性
.click(); // Click the link
// 点击链接
// Verify that the new URL is loaded in the same tab
// 验证新 URL 已在同一标签页加载
cy.url().should('include', '/windows/new');
cy.contains('h3', 'New Window').should('be.visible');
// Optionally, navigate back to the original page
// (可选)导航回原始页面
cy.go('back');
// Verify we are back on the original page
// 验证我们已回到原始页面
cy.url().should('not.include', '/windows/new');
cy.url().should('include', '/windows');
});
});

在此脚本中:

  • cy.get('.example > a') 选择链接元素。
  • .invoke('removeAttr', 'target') 移除 target 属性。此命令在 .click() 之前链式调用。
  • .click() 然后点击修改后的链接,使其在当前标签页中加载。
  • cy.url().should('include', '/windows/new') 验证导航是否按预期发生。
  • cy.go('back') 导航回浏览器历史记录中的上一页。

有时,新窗口是通过 JavaScript 使用 window.open() 打开的。虽然 removeAttr 技术适用于 target 属性,但 window.open() 需要不同的方法。你通常可以通过存根(stubbing)window.open() 来测试打开新窗口的意图:

it('Should verify a new window is requested via window.open', () => {
cy.visit('/page-with-js-popup.html'); // A page that uses window.open()
// 使用 window.open() 的页面
cy.window().then((win) => {
cy.stub(win, 'open').as('windowOpen'); // Stub window.open and alias it
// 存根 window.open 并设置别名
});
cy.get('#button-that-opens-window').click();
cy.get('@windowOpen').should('be.calledOnce');
// Optionally, check the URL it was called with:
// (可选)检查调用时使用的 URL:
// cy.get('@windowOpen').should('be.calledWith', '/expected-popup-url.html');
});

这种方法不与新窗口的内容交互,但会验证应用程序是否尝试打开它,这对于测试目的通常是足够的。

虽然 Cypress 将测试限制在单个标签页中,但 invoke('removeAttr', 'target') 方法为测试那些否则会打开新标签页的链接提供了一个有效且广泛采用的解决方案。这种方法符合 Cypress 推崇快速、可靠且无不稳定性的测试的理念。