Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

breaking: no longer inject document.domain by default #30770

Open
wants to merge 88 commits into
base: release/14.0.0
Choose a base branch
from

Conversation

cacieprins
Copy link
Contributor

@cacieprins cacieprins commented Dec 16, 2024

Docs PR: cypress-io/cypress-documentation#5974

Additional details

Chrome is in the process of deprecating the setter for document.domain. As well, our usage of document.domain caused issues with certain sites that used origin agent clusters for security.

Cypress used document.domain to allow for navigation between subdomains in a single test without requiring the use of cy.origin().With the deprecation of document.domain, Cypress can no longer rely on the availability of a setter on document.domain.

Because this is a fairly disruptive change for users who rely on cy.origin() to navigate between subdomains, a new configuration option is being introduced. injectDocumentDomain can be set to true in order to re-enable the injection of document.domain setters in Cypress. This configuration option is marked as deprecated, and you will receive a warning when Cypress is launched with this option set to true. It will be removed in Cypress 15.

Steps to test

How has the user experience changed?

The cy.origin() command must now be used when navigating between subdomains, unless the injectDocumentDomain e2e configuration option is enabled. When this option is enabled, there will be a warning when Cypress starts.

PR Tasks


if << parameters.inject-document-domain >> ; then
YARN_CMD="cypress:run:inject-document-domain"
PARALLEL=""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't be parallel because it ends up with the same build id but a different set of specs from the run without injectDocumentDomain

@@ -3000,6 +3046,8 @@ linux-x64-workflow: &linux-x64-workflow
- driver-integration-tests-firefox
- driver-integration-tests-chrome
- driver-integration-tests-chrome-beta
- driver-integration-tests-chrome-inject-document-domain
- driver-integration-tests-chrome-beta-inject-document-domain
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding firefox and electron to this mix was going to be pretty cumbersome - I'd like to refactor workflows.yml to use matrix parameters, which would make all of this so much easier.

@@ -70,8 +70,7 @@ declare namespace Cypress {
strategy: 'file' | 'http'
origin: string
fileServer: string | null
props: Record<string, any>
visiting: string
props: Record<string, any> | null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visiting was never used or set internally that I could find, and props not being nullable was inconsistent with the implementation. Potential improvement: import this type directly from packages/server/lib/remote_states so it stays consistent with the implementation

const projectPath: string = Fixtures.projectPath(project)

beforeEach(async () => {
await Fixtures.scaffoldProject(project)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving the scaffoldAngularProject function inline into a beforeEach here keeps the DRY while improving the readability of the spec

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we consider moving these changes into its own PR for a quick review and to reduce changeset here?

Copy link
Contributor Author

@cacieprins cacieprins Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so - This refactor was done to help understand why the tests were failing, and don't actually change the nature of the tests other than clarification of stdout.

}, timeout)

afterEach(() => {
Fixtures.removeProject(project)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving the cleanup to an afterEach ensures that the project is removed after the last it(), rather than left in place

@@ -316,10 +324,6 @@ export class CypressError extends Error {
}
}

const getUserInvocationStackFromError = (err) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function removed for clarity sake

if (specWindow.Cypress && specWindow.Cypress.isBrowser('firefox')) {
stack = stackWithLinesDroppedFromMarker(stack, '__cypress/tests', true)
// firefox and chrome throw stacks that include lines from cypress
// So we drop the lines until we get to the spec stackframe (includes __cypress)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expanding this from __cypress/tests ensures that cy in cy component tests retain the correct stack

@@ -164,6 +163,7 @@ export class SocketBase {
const cdpIo = this._cdpIo = this.createCDPIo(socketIoRoute)

automation.use({
// @ts-ignore - this error is new, but not introduced in the most recent edit. TODO: fix
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was causing issues with linting; VScode was showing an error here with the file open, but lint only started failing against it when I changed it. For ref,

onPush is defined as a NullableMiddlewareHook = (() => void) | null, which means either this function never receives the expected props, or onPush actually being NullableMiddlewareHook instead of something else is in question.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all CDP/BiDi signature related so I would be surprised if the change was introduced here

it('logs error and exits when project folder has read permissions only and cannot write cypress.config.js', function () {
// this test is skipped because its failure causes websocket integration tests to fail.
// this test should be revisited, as the error it's asserting on probably can never be
// actually thrown by Cypress.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is never run in CI (where tests are run as root), and it always fails locally.

The ERROR_WRITING_FILE error is thrown by _logWriteErr in packages/server/lib/util/settings.ts, which is referenced by _write() in the same file. _write() is only referenced by writeForTesting() in the same file, which is only referenced in tests, and not runtime code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe not all of these extra files are necessary - I'm spending some time going through and pruning unnecessary ones. (maybe these should be snapshots instead of fixtures, since they're expected data instead of test input data)

@cacieprins cacieprins changed the title Cacie/29590/document domain subdomains - draft breaking: no longer inject document.domain by default Dec 20, 2024
@cacieprins cacieprins marked this pull request as ready for review December 20, 2024 15:38
Copy link
Member

@jennifer-shehane jennifer-shehane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cacieprins Please feel free to bypass Brian and I as codeowner approvals and merge once you get 2 review approvals. The exposure of the injectDocumentDomain config and removal of experimental is acceptable as an exposed portion of our public API.

@@ -3113,6 +3112,12 @@ declare namespace Cypress {
* @default null
*/
experimentalSkipDomainInjection: string[] | null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cacieprins This experimentalSkipDomainInjection type should be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks to need some adjustments in @packages.config where we need to remove the option experimentalSkipDomainInjection as well as adding an option that it was removed here and updating EXPERIMENTAL_USE_DEFAULT_DOCUMENT_DOMAIN_E2E_ONLY to the new option

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think full removal of experimentalSkipDomainInjection should be in a follow-up PR, to keep the scope of this as manageable as possible

@@ -1350,19 +1350,29 @@ export const AllCypressErrors = {
return errTemplate`\
The ${fmt.highlight(`justInTimeCompile`)} configuration is only supported for Component Testing.`
},
// TODO: link to docs on the new injectDocumentDomain config option
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cacieprins Is this wanted to be done before 14 releases? If so, I would add an on link and we can route it to the https://docs.cypress.io/app/references/error-messages where the specific error explanation would be in the 14 docs branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that work is in progress

@@ -3113,6 +3112,12 @@ declare namespace Cypress {
* @default null
*/
experimentalSkipDomainInjection: string[] | null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks to need some adjustments in @packages.config where we need to remove the option experimentalSkipDomainInjection as well as adding an option that it was removed here and updating EXPERIMENTAL_USE_DEFAULT_DOCUMENT_DOMAIN_E2E_ONLY to the new option

const projectPath: string = Fixtures.projectPath(project)

beforeEach(async () => {
await Fixtures.scaffoldProject(project)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we consider moving these changes into its own PR for a quick review and to reduce changeset here?

@@ -278,5 +278,6 @@
"devtools-protocol": "0.0.1346313",
"sharp": "0.29.3",
"vue-template-compiler": "2.6.12"
}
},
"packageManager": "[email protected]+sha512.ff4579ab459bb25aa7c0ff75b62acebe576f6084b36aa842971cf250a5d8c6cd3bc9420b22ce63c7f93a0857bc6ef29291db39c3e7a23aab5adfd5a4dd6c5d71"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think develop is on 1.22.22 which gets set via yarn set version. We might need to merge develop into 14 which I can look into shortly

@@ -218,6 +220,7 @@ exports['config/src/index .getPublicConfigKeys returns list of public config key
'experimentalRunAllSpecs',
'experimentalMemoryManagement',
'experimentalModifyObstructiveThirdPartyCode',
'injectDocumentDomain',
'experimentalSkipDomainInjection',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be removed from the snapshots

Suggested change
'experimentalSkipDomainInjection',
'',

validation: validate.isBoolean,
requireRestartOnChange: 'server',
},
{
name: 'experimentalSkipDomainInjection',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't need this anymore as well

@@ -164,6 +163,7 @@ export class SocketBase {
const cdpIo = this._cdpIo = this.createCDPIo(socketIoRoute)

automation.use({
// @ts-ignore - this error is new, but not introduced in the most recent edit. TODO: fix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all CDP/BiDi signature related so I would be surprised if the change was introduced here


cookieJar.setCookie(automationCookieToToughCookie(cookie, domain), url, sameSiteContext)
cookieJar.setCookie(automationCookieToToughCookie(cookie, origin), url, sameSiteContext)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it set the origin or the domain on the cookie? I see this is just a port of the existing logic, but I wonder if it's correct. For example:

for URL https://www.foobar.com/baz the

  • origin: https://www.foobar.com
  • domain: www.foobar.com

my guess is tough-cookie parses this out for us but I want to double check here. Are you able to verify that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like they are handling things correctly on there end and it shouldn't matter. I don't think there are existing bugs with this I just wanted to be sure that origin ultimately translates to domain on the tough-cookie side of things

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good catch - I'll change this to hostname to more accurately match the RFC that tough-cookie implements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in fb1219c

system-tests/__snapshots__/protocol_spec.js Show resolved Hide resolved
@@ -27,7 +24,7 @@ const normalizeResults = (resultsJson) => {
.replace(majorVersionRegex, '"$1": "X"')
.replace(osNameRegex, '"$1": "linux"')
.replace(archRegex, '"arch": "x64"')
.replace(stackLineRegex, '"displayError": "$1 <stack lines>"')
.replace(/(\Wn {4}at.+)"/g, ' <stack lines>"')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment to what is this regex doing? I'm not great at reading it on first glance 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we not want the definition of this regex to be outside of these function calls?

@AtofStryker
Copy link
Contributor

also wonder if we can remove the MaybeSetOriginAgentClusterHeader middleware now

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.

3 participants