Skip to content

Cypress - Tabs

A common web pattern is for links or buttons to open new browser tabs or windows, often achieved using the target="_blank" attribute on an <a> tag. Cypress, by design, operates within a single browser tab. It does not provide native support for switching to or interacting with new tabs or windows directly.

This design choice contributes to Cypress’s speed and reliability, as managing multiple tabs can introduce flakiness. However, Cypress offers a straightforward workaround for testing scenarios involving links that would normally open in new tabs.

The Workaround: Removing the target Attribute

Section titled “The Workaround: Removing the target Attribute”

The most common strategy is to programmatically remove the target attribute from the link element before clicking it. This causes the link to open in the same tab, allowing Cypress to continue interacting with the newly loaded page.

Cypress uses the jQuery method removeAttr() for this, invoked via the cy.invoke() command. By removing target="_blank", the browser’s default behavior is to open the link in the current tab.

After interacting with the content on the new page (now in the same tab), you can navigate back to the previous page using cy.go('back') if needed.

Consider the following HTML snippet where a link is designed to open in a new tab:

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

Here’s how you can test this scenario in 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
cy.get('.example > a')
.invoke('removeAttr', 'target') // Remove the target attribute
.click(); // Click the link
// Verify that the new URL is loaded in the same tab
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');
});
});

In this script:

  • cy.get('.example > a') selects the link element.
  • .invoke('removeAttr', 'target') removes the target attribute. This command is chained before .click().
  • .click() then clicks the modified link, causing it to load in the current tab.
  • cy.url().should('include', '/windows/new') verifies that navigation occurred as expected.
  • cy.go('back') navigates back to the previous page in the browser’s history.

Sometimes, new windows are opened via JavaScript using window.open(). While the removeAttr technique works for target attributes, window.open() requires a different approach. You can often test the intent to open a new window by 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()
cy.window().then((win) => {
cy.stub(win, 'open').as('windowOpen'); // Stub window.open and alias it
});
cy.get('#button-that-opens-window').click();
cy.get('@windowOpen').should('be.calledOnce');
// Optionally, check the URL it was called with:
// cy.get('@windowOpen').should('be.calledWith', '/expected-popup-url.html');
});

This method doesn’t interact with the content of the new window but verifies that the application attempted to open it, which is often sufficient for testing purposes.

While Cypress restricts tests to a single tab, the invoke('removeAttr', 'target') method provides an effective and widely adopted solution for testing links that would otherwise open new tabs. This approach aligns with Cypress’s philosophy of promoting fast, reliable, and non-flaky tests.