skip to content

How would you decide whether a Cypress suite sets injectDocumentDomain to true?

level: principalimportance: nice to knowfreq 33%

answer

  1. Cypress 14 changed the confinement rule
  2. A migration budget, not a feature
  3. Deprecated at introduction, warns at launch
  4. Some identity flows break with it on
  5. WebKit runs still require it

basics

~20 s

Treat it as a dated migration budget, not a setting. It buys time for specs that cross subdomains after Cypress 14 made every origin change need cy.origin(), but it is deprecated, breaks some identity providers, and will be removed.

solid answer

~40 s

Since Cypress 14, `cy.origin()` is required between **any** two origins, including two subdomains of one site, because Cypress stopped injecting the legacy `document.domain` relaxation. `injectDocumentDomain: true` puts that injection back, so a suite that roams across subdomains keeps passing untouched. It is deprecated at introduction, warns at launch, and is slated for removal, so the decision is about *time*, not about design. Weigh how many specs actually cross subdomains, whether the sites they touch are among the ones known to break with the injection on, and whether WebKit coverage matters — `cy.origin()` is unsupported there, so the flag is mandatory for it. If you set it, set it as an exception with an owner, an end date and a rule that new specs are written with `cy.origin()`.

go deeper

for a junior

Know that Cypress 16 needs cy.origin() even between two subdomains of one site, and that a deprecated configuration option exists to restore the older behaviour.

for a middle

Explain what injectDocumentDomain switches back on, what still needs cy.origin() with it enabled, and why the option warns at launch.

for a senior

Be ready to plan the migration off it: which specs cross subdomains, which sites break with the injection on, and how you prove progress in CI rather than assuming it.

for a principal

Own the trade-off between a green suite this week and a deprecated flag whose removal date belongs to someone else, and set the rule that stops new specs depending on it.

## What the flag actually changes Cypress 14 changed the unit of confinement. Before it, the runner injected the legacy `document.domain` relaxation — a browser mechanism, and one browsers are moving away from — which let a test roam freely within one **superdomain**: `app.example.com` and `statements.example.com` were interchangeable, and only a genuinely different site needed `cy.origin()`. From 14 onward the injection is off by default, so the boundary is the **origin**: scheme, hostname and port. `injectDocumentDomain: true` restores the old behaviour. Cross-subdomain navigation stops needing `cy.origin()`; crossing to a different site still does. The option exists explicitly to ease the transition, and it is marked deprecated in the same release that introduced it. ```js // cypress.config.js — dated exception, remove once the last spec is migrated module.exports = { e2e: { injectDocumentDomain: true } } ``` ## What you are actually deciding Not "is this good?" — it is deprecated, so it is not a destination. The real question is whether the migration happens **now, in one change**, or **later, in batches**, and what the interest rate on that delay is. Inputs worth putting numbers against: - **Blast radius.** How many specs actually cross subdomains? A statements app whose sign-in sits on `id.example.com` may have three; one with a subdomain per business line may have three hundred. - **Compatibility.** The injection is documented as breaking some real sites, including certain identity-provider workflows. A suite that signs in through one of those does not get the option at all. - **Browser coverage.** `cy.origin()` is not supported in the experimental WebKit browser, so any WebKit run requires the flag today. That is a genuine reason to keep it, and one that ends when either half of the constraint changes. - **Removal risk.** The flag warns at launch and is slated for removal. If your upgrade cadence is "whatever is current in CI", the removal lands as a red pipeline on a day nobody chose. - **Migration cost per spec.** Wrapping commands in `cy.origin()` is mechanical, but the callback is not a closure, so specs that lean on shared helpers or page objects need real restructuring rather than an indent. ## A defensible position 1. **Default to migrating.** Take the deprecation warning at face value and convert specs to `cy.origin()`, newest and most-changed first. 2. **Use the flag only as a dated exception.** If the suite is too large to convert in one change, set it with a comment naming an owner and a date, and treat that date as a commitment rather than a hope. 3. **Stop the bleeding immediately.** New specs are written with `cy.origin()` regardless of the flag, so the backlog stops growing on the day the decision is made. 4. **Prove the migration continuously.** Run a scheduled job with the flag off, over the subset already converted, and grow that subset. When it covers everything, delete the flag. 5. **Re-decide if a site breaks.** The moment the injection breaks a real flow, the delay option has expired for that flow and it migrates first. ## The trap to name out loud The flag's danger is not that it is wrong today — it is that it **hides work that is already due** and makes the suite feel healthy while the deadline approaches. A deprecated compatibility switch set project-wide with no owner is indistinguishable from a permanent setting six months later, and by then the specs that depend on it have multiplied. It is also worth separating this decision from its neighbours, because teams reach for the wrong lever under pressure: | Symptom | The lever people reach for | What it is really about | | --- | --- | --- | | Specs break when navigating between subdomains | `injectDocumentDomain` | this migration, and its end date | | A vendor's embedded frame is unreadable | `injectDocumentDomain` | the same-origin policy on iframes, which it does not fix | | A third-party sign-in errors mid-flow | turning the flag on | usually a `cy.origin()` block that is missing or misplaced | A lead is expected to hold two things at once here: the suite has to stay green this week, and a deprecated flag is a loan whose repayment date is set by someone else's release schedule.

  • What exactly stops needing cy.origin() when a Cypress suite sets injectDocumentDomain to true?
    Navigation between hosts inside one superdomain — `app.example.com` to `statements.example.com`, for instance — because the runner injects the legacy `document.domain` relaxation again. Crossing to a genuinely different site still needs the block, and so does a change of scheme or port. It is a partial reprieve, not a general opt-out of the confinement.
  • How would you retire injectDocumentDomain once a Cypress suite already depends on it?
    Inventory the specs that cross subdomains, migrate them in batches to `cy.origin()`, and run a scheduled job over the migrated subset with the flag off so the progress is proved rather than assumed. When that job covers the whole suite, delete the flag. The launch-time deprecation warning is a useful recurring reminder in the meantime.

saying these in an interview costs you the question

  • Treats injectDocumentDomain as the permanent fix for subdomain navigation
  • Sets it project-wide with no owner and no end date
  • Assumes it works with every identity provider
  • Expects it to make cross-origin iframes readable
  • Insists the whole suite must be rewritten in a single change