Skip to content

Conversation

@astone123
Copy link
Contributor

@astone123 astone123 commented Oct 10, 2025

This PR closes https://github.com/cypress-io/cypress-services/issues/11991

Additional details

There are a few cases where we don't correctly derive the test body invocation details from the stack trace. This PR fixes those scenarios by looking for at eval or at Suite.eval in Chrome stack traces, and lines with anonymous functions in Firefox stack traces. This will allow Cypress Studio and "Open in IDE" features to work in more cases than they did before.

One of these situations is when it has been re-written as itGrep which happens in the @cypress/grep and @bahmutov/cy-grep plugins. This allows us to determine the correct invocation details for the test.

Steps to test

I tested this with the @bahmutov/cy-grep package. Install the package and register it in your support file in accordance with the documentation. Open Cypress Studio by clicking the "edit in studio" button next to a test. Verify that the test content is loaded correctly and you can edit and save the test as expected.

How has the user experience changed?

Users of @bahmutov/cy-grep package can now use Cypress studio as intended

PR Tasks


Note

Normalizes test body invocation details from stack traces (Chrome/Firefox), updates Mocha to request test-specific details, and adds targeted tests plus changelog entry.

  • Driver:
    • stack_utils: add browser-aware trimming via stackTrimmedToTestInvocation() and extend getInvocationDetails(specWindow, root, 'test') to normalize test invocation frames.
    • mocha.ts: pass 'test' to getInvocationDetails when adding tests so IDE/Studio get accurate file/line/column.
  • Tests:
    • E2E: expand reporter.hooks.cy.ts with assertions for correct "Open in IDE" invocation details (before hook, basic body, .only, wrapped it).
    • Unit: add cases validating stack trimming and fallback behavior in stack_utils.spec.ts.
    • Fixtures: add hooks/wrapped-it.cy.js.
  • Docs/Meta:
    • Update cli/CHANGELOG.md with a bugfix note about correcting invocation details from stack traces.

Written by Cursor Bugbot for commit 4a53ed1. This will update automatically on new commits. Configure here.

@astone123 astone123 self-assigned this Oct 10, 2025
@astone123 astone123 closed this Oct 10, 2025
@cypress
Copy link

cypress bot commented Oct 10, 2025

cypress    Run #67291

Run Properties:  status check failed Failed #67291  •  git commit 4a53ed1626: changelog entry
Project cypress
Branch Review astone123/fix-itgrep-trace
Run status status check failed Failed #67291
Run duration 18m 53s
Commit git commit 4a53ed1626: changelog entry
Committer astone123
View all properties for this run ↗︎

Test results
Tests that failed  Failures 1
Tests that were flaky  Flaky 12
Tests that did not run due to a developer annotating a test with .skip  Pending 1098
Tests that did not run due to a failure in a mocha hook  Skipped 4
Tests that passed  Passing 26596
View all changes introduced in this branch ↗︎

Warning

Partial Report: The results for the Application Quality reports may be incomplete.

UI Coverage  45.48%
  Untested elements 188  
  Tested elements 161  
Accessibility  97.99%
  Failed rules  4 critical   8 serious   2 moderate   2 minor
  Failed elements 101  

Tests for review

Failed  cypress/e2e/commands/files.cy.js • 1 failed test • 5x-driver-firefox

View Output

Test Artifacts
src/cy/commands/files > #readFile > retries to read when ENOENT
    </td>
  </tr></table>
Flakiness  commands/net_stubbing.cy.ts • 1 flaky test • 5x-driver-electron

View Output

Test Artifacts
... > stops waiting when an fetch request is canceled Test Replay
Flakiness  issues/28527.cy.ts • 1 flaky test • 5x-driver-electron

View Output

Test Artifacts
issue 28527 > fails and then retries and verifies about:blank is not displayed Test Replay Screenshots
Flakiness  e2e/origin/config_env.cy.ts • 1 flaky test • 5x-driver-inject-document-domain-chrome:beta

View Output

Test Artifacts
cy.origin- Cypress.config() > serializable > overwrites different values in secondary if one exists in the primary Test Replay
Flakiness  e2e/origin/config_env.cy.ts • 1 flaky test • 5x-driver-chrome:beta

View Output

Test Artifacts
cy.origin- Cypress.config() > serializable > overwrites different values in secondary if one exists in the primary Test Replay
Flakiness  issues/28527.cy.ts • 1 flaky test • 5x-driver-chrome:beta

View Output

Test Artifacts
issue 28527 > fails and then retries and verifies about:blank is not displayed Test Replay Screenshots

The first 5 flaky specs are shown, see all 11 specs in Cypress Cloud.

@astone123
Copy link
Contributor Author

@mschile @mabela416
After looking at fixing this on the cloud side for a bit, I think the best way to handle the grep stack issue is with a solution like this on the app side. We use the invocation details in various places across the app to decide which test to focus in studio mode and other things, so normalizing the stack on the cloud side doesn't fix the issue entirely. Let me know what you think

@astone123 astone123 reopened this Oct 28, 2025
@astone123 astone123 requested a review from mabela416 October 28, 2025 13:07
Copy link
Contributor

@mabela416 mabela416 left a comment

Choose a reason for hiding this comment

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

I tested it locally and it works

}
}

// if the stack includes the 'itGrep' function, remove any lines that include it
Copy link
Contributor

Choose a reason for hiding this comment

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

Likely good to reference what itGrep is and where it is coming from (same with above) https://github.com/cypress-io/cypress/blob/develop/npm/grep/src/register.ts#L77. people who aren't familiar with @cypress/grep will struggle to understand what this means.

The other concern I have is that there could be something legitimate in the stack that has itGrep in it that we want to capture but are omitting it here. Or is this only considered when trying to calculate the row/column in the spec file where the error occurred?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a comment there. I'm pretty sure this function is specifically used to identify where the test was executed from, so this shouldn't affect anything else. If it does, it'll be limited to use of the grep plugin

@astone123
Copy link
Contributor Author

@mschile I updated this so that it works for tests with .only as well as tests that are nested in suite definitions

@astone123 astone123 changed the title fix: (studio) remove itGrep lines from stack trace when determining invocationDetails fix: normalize test body invocationDetails from stack traces Nov 6, 2025
@astone123 astone123 requested a review from AtofStryker November 7, 2025 15:57
) {
lines.shift()
}
} else if (specWindow.Cypress.isBrowser('firefox')) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is firefox tested?

Copy link
Contributor

Choose a reason for hiding this comment

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

We need to make sure we have sufficient testing where if the stack implementation changed, our tests would fail for both chromium and firefox.

if (specWindow.Cypress.isBrowser('chrome')) {
// There are cases where there are other lines in the stack trace before the invocation (eg. `context.it.only`, `createRunnable`, etc)
// Remove lines from the start until the top line starts with 'at eval' or 'at Suite.eval' so that we only keep the actual invocation line.
while (
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest using _.dropWhile (also used elsewhere in the file).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

return splitAtAt.length > 1 && splitAtAt[0].trim().length === 0
}

while (
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

})

// if we removed all the lines then something went wrong. return the original stack instead
if (modifiedStack.length === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this works since the error will still be on the stack as shown with the return value in stackWithLinesRemoved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated this logic to return the original stack if the modified stack is Error

})

it('returns the correct invocation details for a grep stack trace for a test body', () => {
const stack = `Error at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)
Copy link
Contributor

Choose a reason for hiding this comment

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

The Error should be on it's own line:

Suggested change
const stack = `Error at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)
const stack = `Error
at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

})

it('returns the original stack if it cannot be normalized for a test body', () => {
const stack = `Error at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)
Copy link
Contributor

Choose a reason for hiding this comment

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

The Error should be on it's own line:

Suggested change
const stack = `Error at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)
const stack = `Error
at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

}))
})

it('returns the original stack if it cannot be normalized for a test body', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
it('returns the original stack if it cannot be normalized for a test body', () => {
it('returns the original stack if it cannot be normalized for a test', () => {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

})
}

it('returns the correct invocation details for a grep stack trace', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
it('returns the correct invocation details for a grep stack trace', () => {
it('returns the correct invocation details for a test with a stack that needs to be trimmed', () => {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

Comment on lines +70 to +73
const stack = `Error\n at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)\n
at eval (http://localhost:3000/__cypress/tests?p=cypress/e2e/spec.cy.js:14:1)\n
at eval (http://localhost:3000/__cypress/tests?p=cypress/e2e/spec.cy.js:18:12)\n
at eval (<anonymous>)\n
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const stack = `Error\n at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)\n
at eval (http://localhost:3000/__cypress/tests?p=cypress/e2e/spec.cy.js:14:1)\n
at eval (http://localhost:3000/__cypress/tests?p=cypress/e2e/spec.cy.js:18:12)\n
at eval (<anonymous>)\n
const stack = `Error
at itGrep (http://localhost:3000/__cypress/tests?p=cypress/support/e2e.js:444:14)
at eval (http://localhost:3000/__cypress/tests?p=cypress/e2e/spec.cy.js:14:1)
at eval (http://localhost:3000/__cypress/tests?p=cypress/e2e/spec.cy.js:18:12)
at eval (<anonymous>)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

})

cy.get('.hook-open-in-ide').first().invoke('show').click()
it('sends the correct invocation details for .only test body', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this supposed to test the new logic because I don't think it is.

Copy link
Contributor

@mschile mschile left a comment

Choose a reason for hiding this comment

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

Added some comments.

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.

5 participants