Skip to content

docs: add a multi-tab testing guide for @cypress/puppeteer - #7049

Open
jennifer-shehane wants to merge 11 commits into
mainfrom
docs/multi-tab-testing-guide
Open

jennifer-shehane wants to merge 11 commits into
mainfrom
docs/multi-tab-testing-guide

Conversation

@jennifer-shehane

@jennifer-shehane jennifer-shehane commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds a Multi-tab testing guide (/app/guides/multi-tab-testing) that shows how to test links, popups, and windows that open a new browser tab. It covers the @cypress/puppeteer plugin, and the alternatives that keep a test in the Cypress tab. The guide replaces the scattered "Cypress can't do multiple tabs" mentions on five other pages with links to it.

Why

Readers kept landing on pages that said multi-tab testing wasn't possible, or that pointed at a plugin with no worked examples. The guide does three things:

  • Helps readers decide whether a test needs a second tab at all. When the tabs never interact, asserting the link, removing target, or stubbing window.open is enough, and it runs in every browser.
  • Explains how cy.puppeteer() reaches other tabs, with a diagram.
  • Gives tested examples for the flows teams ask about most:
    • reading a tab a link opens
    • a sign-in or payment popup that reports back to the app
    • cross-tab updates and signing out across tabs
    • two users in separate browser contexts
    • closing leftover tabs
    • screenshotting other tabs when a test fails

It's written for @cypress/puppeteer 1.0 (cypress-io/cypress#35203), which bundles puppeteer-core v24 and drops the beta label. The examples use v24 APIs, such as createBrowserContext() in place of createIncognitoBrowserContext().

What changed

  • New guide: docs/app/write-tests/multi-tab-testing.mdx
  • New images in static/img/app/multi-tab-testing/:
    • a how-it-works SVG
    • two Command Log screenshots captured from real runs of the page's snippets
  • Pages updated to link to the guide:
    • trade-offs.mdx
    • faq.mdx
    • the Playwright and Selenium migration guides. The Playwright guide's multi-tab section is rewritten, and its "After" example now runs.
    • src/data/plugins.json

Notes for reviewers

Code example verification

Every example ran in the .example-check/ harness, pasted verbatim, with Cypress 16.1.0. The plugin was @cypress/puppeteer 0.1.10 with puppeteer-core overridden to 24.43.1. That's the code 1.0 ships: the PR's only source change is the wording of the minimum-version error.

Example Result
Assert the link, open it in the Cypress tab, stub window.open ✅ Electron and Chromium
readNewTab, plus the "Failed retrying after 4000ms" troubleshooting example ✅ Electron and Chromium
Popup flow (allowAccessInPopup) ✅ Chromium
clickInNewTab (theme and sign-out) ✅ Chromium
Second user in a separate browser context ✅ Chromium, including a message with an unbalanced )
closeExtraTabs and screenshotOtherTabs support-file hooks ✅ Chromium and Electron. The screenshot is a valid PNG
Playwright guide's "After" example ✅ Electron and Chromium
All config examples, and the tsconfig.json types entry ✅ Strict typecheck against Puppeteer 24
cypress run --browser chrome ⚠️ Not run: Google Chrome isn't installed in the environment
Hooks in Firefox and WebKit ⚠️ Not run: neither browser is installed. The guard is Cypress.browser.family === 'chromium'

The guide's Electron limits each failed with the exact text the guide quotes: newPage() (Target.createTarget: Not supported), browser contexts (Failed to create browser context), a popup with no window.opener, and a page.screenshot() that never finishes. The headed Chrome 137+ launch failure was reproduced by registering Chromium as Chrome 141.

Decisions worth knowing

  • The popup handler clicks with $eval, not page.click(). The app closes the popup on click, so page.click() intermittently failed with Protocol error (Input.dispatchMouseEvent): Target closed: 2 of 200 runs on Puppeteer 21 and 8 of 300 on 24. $eval ran 800 of 800 clean.
  • cy.puppeteer() doesn't retry. A chained assertion that fails doesn't run the handler again. The guide says so and waits inside handlers with retry(). This was confirmed in the plugin source (Commands.add around one cy.task()) and with a run.
  • The tab lookups use a plain URL match. They don't skip the Cypress tab, whose URL contains /__/ and the spec's file name. A spec named receipt.cy.js calling readNewTab('receipt') closes the Cypress tab and aborts the run. The guide warns about this. Whether to add a /__/ filter to the three lookups is still an open question.
  • The diagram passes WCAG 2.2 AA contrast. Text is 13.96:1 and 16.51:1; arrows and outlines are 5.31:1 and 4.23:1.
  • The trade-offs heading "Multiple browsers open at the same time" is unchanged, because five pages link to its anchor.

Generated by Claude Code


Note

Low Risk
Documentation-only: new guide, cross-links, plugin copy, and static assets; no runtime or security-sensitive code paths.

Overview

Summary

Adds /app/guides/multi-tab-testing—a full guide for testing new tabs, popups, and separate contexts with @cypress/puppeteer, plus when to stay in the Cypress tab (assert href, strip target, stub window.open). Includes setup, browser limits (Chromium, headed Chrome 137+, Electron caveats), worked examples (read tab, OAuth-style popup, cross-tab storage, second user via createBrowserContext, cleanup hooks, failure screenshots), troubleshooting, and a how-it-works diagram.

Why

Replaces scattered “no multi-tab” messaging with one source of truth and links from Trade-offs, FAQ (new-tab anchors), Playwright and Selenium migration guides (rewritten multi-tab sections and cheat-sheet row pointing at the guide), and a clearer plugins.json blurb for Puppeteer.

Notes for reviewers

Examples are written for @cypress/puppeteer 1.0 / Puppeteer v24 APIs (createBrowserContext, etc.). Confirm sidebar/nav picks up the new MDX from existing patterns. Large guide and image assets (~863 lines + SVG); spot-check internal links and Command Log image paths.

Reviewed by Cursor Bugbot for commit 50cffbe. Bugbot is set up for automated code reviews on this repo. Configure here.

Multi-tab coverage was scattered across five pages, each a sentence or
two that linked out to the plugin README. This adds one guide that covers
when a second tab is needed, how the plugin works, browser support, setup,
four verified multi-tab flows, CI, and troubleshooting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016sNZ3z2W8wCcBH61TTgwXn
…t example

Trade-offs, the FAQ, both migration guides, and the plugins list each
described @cypress/puppeteer in a sentence and linked out to three
different places. They now lead readers to the multi-tab testing guide.

The Playwright migration example is also corrected: it no longer says
Puppeteer must be installed separately (the plugin bundles it), its
"After" now clicks Confirm like the "Before" does and closes the tab, and
it uses the cypress-config-plugin-example directive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016sNZ3z2W8wCcBH61TTgwXn
Adds a diagram of how one cy.puppeteer() call moves between the browser
and Node.js, a sequence diagram of the popup flow, and Command Log
screenshots of a passing and a failing handler, captured from real runs
on Cypress 16.1.1.

Adds three verified workflows: signing out across tabs, testing two
users at once with a separate browser context, and screenshotting other
tabs when a test fails, since Cypress screenshots only capture its own
tab.

Also fixes the tab lookups in readNewTab, allowAccessInPopup, and the
Playwright guide's confirmInNewTab to skip the Cypress tab. Its URL
contains the spec's file name, so a spec named after the tab it looks
for matched the Cypress tab and closed it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016sNZ3z2W8wCcBH61TTgwXn
Puts the new tab or popup to the right of Node.js, so the diagram reads
left to right from the spec to the handler to the tab it controls. Drops
the numbered steps and legend from the image and explains the call in
the page text instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016sNZ3z2W8wCcBH61TTgwXn
Drops the gray notes under each box so the diagram shows only the tabs,
the handler, and the calls between them. The page text already explains
the fresh Puppeteer connection and where the new tab comes from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016sNZ3z2W8wCcBH61TTgwXn
Drops the sequence diagram from the popup section of the multi-tab
guide. The section's markup, handler, and spec already walk through the
flow step by step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016sNZ3z2W8wCcBH61TTgwXn
Returns readNewTab, allowAccessInPopup, and the Playwright guide's
confirmInNewTab to a plain URL match. The guide still warns that the
Cypress tab's URL contains the spec's file name, so a handler can match
it by mistake. Recaptures both Command Log screenshots with the simpler
handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016sNZ3z2W8wCcBH61TTgwXn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LaBf5JWCwkJkA3hA1Qz3n2
- Move the diagram's column labels into the page text so the SVG shows
  only the three boxes and arrows.
- Rework the intro for flow and drop the public beta caution.
- Rename "Choose how to test links that open a new tab" to say these
  options fit when the tabs don't interact, and update the FAQ link.
- Lead the how-it-works section with the scenarios that need the plugin,
  and move the explanation under an H3.
- Reduce browser support to the Chromium-based requirement and its two
  limits, without the Cypress version or the browser table.
- Click "Allow access" from inside the popup with $eval. popup.click()
  failed intermittently with "Target closed" because the app closes the
  popup on click (2 of 200 runs; the fix ran 500 of 500 clean).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LaBf5JWCwkJkA3hA1Qz3n2
…w fixes

- Use browser.createBrowserContext(), since puppeteer-core 24 removed
  createIncognitoBrowserContext(), and update the related notes.
- Say that cy.puppeteer() runs its handler once and doesn't retry.
- Guard the afterEach hooks so suites still run outside Chromium.
- Say that headed Chrome 137+ fails to launch once setup() is
  registered.
- Show the connect.html markup the window.open stub runs against.
- Quote the ::-p-text() selector so unbalanced parentheses match.
- Drop bold from list lead-ins, trim the description, and remove unused
  SVG styles.
- Make five headings stand on their own, and tighten wording for tense,
  voice, and tone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LaBf5JWCwkJkA3hA1Qz3n2
@cypress

cypress Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

cypress-documentation    Run #2794

Run Properties:  status check passed Passed #2794  •  git commit ca8a03e928 ℹ️: Merge 50cffbefcdd51acb7217bb0cd0ab36c6f382bb80 into fc274e3d59db489fef1d37cc8028...
Project cypress-documentation
Branch Review docs/multi-tab-testing-guide
Run status status check passed Passed #2794
Run duration 02m 21s
Commit git commit ca8a03e928 ℹ️: Merge 50cffbefcdd51acb7217bb0cd0ab36c6f382bb80 into fc274e3d59db489fef1d37cc8028...
Committer Jennifer Shehane
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 2
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 428
View all changes introduced in this branch ↗︎
UI Coverage  32.73%
  Untested elements 745  
  Tested elements 26  
Accessibility  98.89%
  Failed rules  2 critical   6 serious   4 moderate   1 minor
  Failed elements 150  

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants