Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ce8016d
fix: ensure that absolute paths can be found via source maps
ryanthemanuel Oct 24, 2025
9ea3aeb
add tests
ryanthemanuel Oct 24, 2025
636a961
refactor
ryanthemanuel Oct 25, 2025
fdca4d8
fix test
ryanthemanuel Oct 25, 2025
4cb74e8
debugging
ryanthemanuel Oct 25, 2025
4e3c0f4
debugging
ryanthemanuel Oct 25, 2025
0096ace
debugging
ryanthemanuel Oct 25, 2025
a010c9b
debugging
ryanthemanuel Oct 25, 2025
fd71292
Add wait before interacting with error file path
ryanthemanuel Oct 25, 2025
694cac5
Update click action to scroll into view first
ryanthemanuel Oct 25, 2025
4355d7e
real events
ryanthemanuel Oct 25, 2025
72d3367
let's try this
ryanthemanuel Oct 25, 2025
8c6af86
let's try this
ryanthemanuel Oct 25, 2025
4db8a66
rework
ryanthemanuel Oct 26, 2025
af88bbd
rework
ryanthemanuel Oct 26, 2025
48b2738
run all
ryanthemanuel Oct 26, 2025
dd75bbc
fixes
ryanthemanuel Oct 27, 2025
859e6e7
fix
ryanthemanuel Oct 27, 2025
c7539c5
Merge branch 'develop' into ryanm/fix/issue-with-sourcemaps
ryanthemanuel Oct 27, 2025
250dc88
PR comments
ryanthemanuel Oct 28, 2025
48980a6
cursor comment
ryanthemanuel Oct 28, 2025
d877458
Merge branch 'develop' into ryanm/fix/issue-with-sourcemaps
ryanthemanuel Oct 28, 2025
b8e6568
changelog
ryanthemanuel Oct 28, 2025
5e72fc8
Merge branch 'develop' into ryanm/fix/issue-with-sourcemaps
ryanthemanuel Oct 29, 2025
46e22c7
cursor comment
ryanthemanuel Oct 29, 2025
02d00f5
PR comments
ryanthemanuel Oct 29, 2025
7f5e87d
Update CHANGELOG.md
ryanthemanuel Oct 29, 2025
f9051b8
Update CHANGELOG.md
ryanthemanuel Oct 29, 2025
69f79b0
fix build
ryanthemanuel Oct 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/src/pipeline/workflows/@main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ linux-x64:
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'chore/fix_builds', << pipeline.git.branch >> ]
- equal: [ 'ryanm/fix/issue-with-sourcemaps', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand Down
1 change: 1 addition & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ _Released 10/20/2025 (PENDING)_
- Fixed an issue where grouped command text jumps up and down when expanding and collapsing in the command log. Addressed in [#32757](https://github.com/cypress-io/cypress/pull/32757).
- Fixed an issue with grouped console prop items having a hard to read blue color in the console log and duplicate `:` characters being displayed. Addressed in [#32776](https://github.com/cypress-io/cypress/pull/32776).
- Added more context to the error message shown when `cy.prompt()` fails to download. Addressed in [#32822](https://github.com/cypress-io/cypress/pull/32822).
- Fixed an issue where absolute file paths were not correctly determined from the source map when the source map root was updated. Fixes [#32809](https://github.com/cypress-io/cypress/issues/32809).

**Misc:**

Expand Down
28 changes: 22 additions & 6 deletions npm/vite-dev-server/cypress/e2e/vite-dev-server.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,27 +126,27 @@ describe('sourcemaps', () => {

cy.withCtx(async (ctx, o) => {
await ctx.actions.file.writeFileInProject(
'JsErrorSpec.cy.js',
'src/JsErrorSpec.cy.js',
o.testContent,
)

await ctx.actions.file.writeFileInProject(
'JsWithImportErrorSpec.cy.js',
'src/JsWithImportErrorSpec.cy.js',
`import React from 'react';\n\n${o.testContent}`,
)

await ctx.actions.file.writeFileInProject(
'JsxErrorSpec.cy.jsx',
'src/JsxErrorSpec.cy.jsx',
o.testContent,
)

await ctx.actions.file.writeFileInProject(
'TsErrorSpec.cy.ts',
'src/TsErrorSpec.cy.ts',
`type MyType = { value: string }\n\n${o.testContent}`,
)

await ctx.actions.file.writeFileInProject(
'TsxErrorSpec.cy.tsx',
'src/TsxErrorSpec.cy.tsx',
`type MyType = { value: string }\n\n${o.testContent}`,
)
}, { testContent })
Expand All @@ -157,7 +157,23 @@ describe('sourcemaps', () => {
cy.contains(specName).click()
cy.waitForSpecToFinish()
cy.get('.failed > .num').should('contain', 2)
cy.get('.runnable-err-file-path', { timeout: 250 }).should('contain', `${specName}:${line}:${column}`)
cy.get('.runnable-err-file-path').eq(1).should('contain', `${specName}:${line}:${column}`)
cy.window().then((win) => {
// @ts-expect-error
cy.stub(win.getEventManager(), 'emit').as('emit')
})

cy.get('.runnable-err-file-path', { timeout: 250 }).eq(1).as('filePath')
cy.get('@filePath').should('contain', `${specName}:${line}:${column}`)
cy.get('@filePath').then(($el) => {
$el.find('span').trigger('click')
})

cy.get('@emit').should('have.been.calledWithMatch', 'open:file', {
absoluteFile: Cypress.sinon.match(new RegExp(`cy-projects/vite7.0.0-react/src/${specName}$`)),
line,
column,
})
}

verifySourcemap('JsErrorSpec.cy.js', 7, 8)
Expand Down
69 changes: 69 additions & 0 deletions npm/webpack-dev-server/cypress/e2e/webpack-dev-server.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/// <reference path="../support/e2e.ts" />

import dedent from 'dedent'

describe('Config options', () => {
it('supports supportFile = false', () => {
cy.scaffoldProject('webpack5_wds5-react')
Expand Down Expand Up @@ -86,3 +88,70 @@ describe('Config options', () => {
cy.get('.passed > .num').should('contain', 1)
})
})

describe('sourcemaps', () => {
it('should be provided for JS and transpiled files', () => {
const testContent = dedent`
describe('spec file with import', () => {
it('should generate uncaught error', () => {
throw new Error('uncaught')
})

it('should generate failed command', () => {
cy.get('#does-not-exist', { timeout: 100 })
})
})
`

cy.scaffoldProject('webpack5_wds5-react')
cy.openProject('webpack5_wds5-react', ['--config-file', 'cypress-webpack-no-support.config.ts', '--component'])
cy.startAppServer('component')

cy.withCtx(async (ctx, o) => {
await ctx.actions.file.writeFileInProject(
'src/JsErrorSpec.cy.js',
o.testContent,
)

await ctx.actions.file.writeFileInProject(
'src/JsWithImportErrorSpec.cy.js',
`import React from 'react';\n\n${o.testContent}`,
)

await ctx.actions.file.writeFileInProject(
'src/JsxErrorSpec.cy.jsx',
o.testContent,
)
}, { testContent })

const verifySourcemap = (specName: string, line: number, column: number) => {
cy.visitApp()
cy.specsPageIsVisible()
cy.contains(specName).click()
cy.waitForSpecToFinish()
cy.get('.failed > .num').should('contain', 2)
cy.window().then((win) => {
// @ts-expect-error
cy.stub(win.getEventManager(), 'emit').as('emit')
})

cy.get('.runnable-err-file-path', { timeout: 250 }).eq(1).as('filePath')
cy.get('@filePath').should('contain', `${specName}:${line}:${column}`)
cy.get('@filePath').then(($el) => {
$el.find('span').trigger('click')
})

cy.get('@emit').should('have.been.calledWithMatch', 'open:file', {
absoluteFile: Cypress.sinon.match(new RegExp(`cy-projects/webpack5_wds5-react/src/${specName}$`)),
line,
column,
})
}

verifySourcemap('JsErrorSpec.cy.js', 7, 8)

verifySourcemap('JsWithImportErrorSpec.cy.js', 9, 8)

verifySourcemap('JsxErrorSpec.cy.jsx', 7, 8)
})
})
2 changes: 1 addition & 1 deletion packages/app/cypress/e2e/runner/ct-framework-errors.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function loadErrorSpec (options: Options): VerifyFunc {
})

// Return scoped verify function with spec options baked in
return createVerify({ fileName: Cypress._.last(filePath.split('/')), hasPreferredIde: false, mode: 'component' })
return createVerify({ fileName: Cypress._.last(filePath.split('/')), filePath, hasPreferredIde: false, mode: 'component' })
}

const reactVersions = [18, 19] as const
Expand Down
2 changes: 1 addition & 1 deletion packages/app/cypress/e2e/runner/reporter-ct-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function loadErrorSpec (options: specLoader.LoadSpecOptions, configFile: string)
specLoader.loadSpec(effectiveOptions)

// Return scoped verify function with spec options baked in
return createVerify({ fileName: Cypress._.last(filePath.split('/')), hasPreferredIde, mode })
return createVerify({ fileName: Cypress._.last(filePath.split('/')), filePath, hasPreferredIde, mode })
}

/**
Expand Down
33 changes: 32 additions & 1 deletion packages/app/cypress/e2e/runner/reporter.command_errors.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function loadErrorSpec (options: specLoader.LoadSpecOptions): VerifyFunc {
specLoader.loadSpec(options)

// Return scoped verify function with spec options baked in
return createVerify({ fileName: Cypress._.last(filePath.split('/')), hasPreferredIde, mode })
return createVerify({ filePath, fileName: Cypress._.last(filePath.split('/')), hasPreferredIde, mode })
}

describe('errors ui', {
Expand Down Expand Up @@ -56,6 +56,37 @@ describe('errors ui', {
})
})

it('assertion failures with new sourcemap root', () => {
const verifyWithNewSourcemapRoot = loadErrorSpec({
filePath: 'errors/assertions.cy.js',
hasPreferredIde: true,
failCount: 3,
projectName: 'runner-e2e-specs-new-sourcemap-root',
configFile: 'cypress.config.mjs',
})

verifyWithNewSourcemapRoot('with expect().<foo>', {
line: 3,
column: 25,
message: `expected 'actual' to equal 'expected'`,
verifyOpenInIde: true,
})

verifyWithNewSourcemapRoot('with assert()', {
line: 7,
column: [5, 12], // [chrome, firefox]
message: `should be true`,
verifyOpenInIde: true,
})

verifyWithNewSourcemapRoot('with assert.<foo>()', {
line: 11,
column: 12,
message: `expected 'actual' to equal 'expected'`,
verifyOpenInIde: true,
})
})

it('assertion failures - no preferred IDE', () => {
const verify = loadErrorSpec({
filePath: 'errors/assertions.cy.js',
Expand Down
2 changes: 1 addition & 1 deletion packages/app/cypress/e2e/runner/reporter.errors.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function loadErrorSpec (options: specLoader.LoadSpecOptions): VerifyFunc {
specLoader.loadSpec(options)

// Return scoped verify function with spec options baked in
return createVerify({ fileName: Cypress._.last(filePath.split('/')), hasPreferredIde, mode })
return createVerify({ fileName: Cypress._.last(filePath.split('/')), filePath, hasPreferredIde, mode })
}

describe('errors ui', {
Expand Down
2 changes: 1 addition & 1 deletion packages/app/cypress/e2e/runner/support/spec-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export type LoadSpecOptions = {
failCount?: number | string
pendingCount?: number | string
hasPreferredIde?: boolean
projectName?: 'runner-e2e-specs' | 'runner-ct-specs' | 'session-and-origin-e2e-specs' | ExperimentalRetriesProjects
projectName?: 'runner-e2e-specs' | 'runner-e2e-specs-new-sourcemap-root' | 'runner-ct-specs' | 'session-and-origin-e2e-specs' | ExperimentalRetriesProjects
mode?: 'e2e' | 'component'
configFile?: string
scaffold?: boolean
Expand Down
12 changes: 8 additions & 4 deletions packages/app/cypress/e2e/runner/support/verify-failures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import defaultMessages from '@packages/frontend-shared/src/locales/en-US.json'

// Assert that either the the dialog is presented or the mutation is emitted, depending on
// whether the test has a preferred IDE defined.
const verifyIdeOpen = ({ fileName, action, hasPreferredIde, line, column }) => {
const verifyIdeOpen = ({ fileName, filePath, action, hasPreferredIde, line, column }) => {
if (hasPreferredIde) {
cy.withCtx((ctx, o) => {
// @ts-expect-error - check if we've stubbed it already, only need to stub it once
Expand All @@ -15,8 +15,8 @@ const verifyIdeOpen = ({ fileName, action, hasPreferredIde, line, column }) => {
action()

cy.withCtx((ctx, o) => {
expect(ctx.actions.file.openFile).to.have.been.calledWith(o.sinon.match(new RegExp(`${o.fileName}$`)), o.line, o.column)
}, { fileName, line, column })
expect(ctx.actions.file.openFile).to.have.been.calledWith(o.sinon.match(new RegExp(`cypress/e2e/${o.filePath}$`)), o.line, o.column)
}, { fileName, filePath, line, column })
} else {
action()

Expand All @@ -38,6 +38,7 @@ const verifyFailure = (options) => {
command,
stack,
fileName,
filePath,
uncaught = false,
uncaughtMessage,
line,
Expand Down Expand Up @@ -138,6 +139,7 @@ const verifyFailure = (options) => {
if (verifyOpenInIde) {
verifyIdeOpen({
fileName,
filePath,
hasPreferredIde,
action: () => {
cy.get('@Root').contains('.runnable-err-stack-trace .runnable-err-file-path a', fileName)
Expand Down Expand Up @@ -185,6 +187,7 @@ const verifyFailure = (options) => {
if (verifyOpenInIde) {
verifyIdeOpen({
fileName,
filePath,
hasPreferredIde,
action: () => {
cy.get('@Root').contains('.test-err-code-frame .runnable-err-file-path a', fileName)
Expand All @@ -198,12 +201,13 @@ const verifyFailure = (options) => {

type ChainableVerify = (specTitle: string, props: any) => Cypress.Chainable

export const createVerify = ({ fileName, hasPreferredIde, mode }): ChainableVerify => {
export const createVerify = ({ fileName, filePath, hasPreferredIde, mode }): ChainableVerify => {
return (specTitle: string, props: any) => {
props.specTitle ||= specTitle
props.fileName ||= fileName
props.hasPreferredIde = hasPreferredIde
props.mode = mode
props.filePath ||= filePath

return cy.wrap(
(props.verifyFn || verifyFailure).call(null, props),
Expand Down
5 changes: 3 additions & 2 deletions packages/driver/src/cy/commands/origin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { LogUtils } from '../../../cypress/log'
import logGroup from '../../logGroup'
import type { StateFunc } from '../../../cypress/state'
import { runPrivilegedCommand } from '../../../util/privileged_channel'
import $sourceMapUtils from '../../../cypress/source_map_utils'

const reHttp = /^https?:\/\//

Expand All @@ -28,7 +29,7 @@ const normalizeOrigin = (urlOrDomain) => {
type OptionsOrFn<T> = { args: T } | (() => {})
type Fn<T> = (args?: T) => {}

export default (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: StateFunc, config: Cypress.InternalConfig) => {
export default (Commands, Cypress: InternalCypress.Cypress, cy: Cypress.cy, state: StateFunc, config: Cypress.InternalConfig) => {
const communicator = Cypress.primaryOriginCommunicator

Commands.addAll({
Expand Down Expand Up @@ -190,7 +191,7 @@ export default (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: State
// Attach the spec bridge to the window to be tested.
communicator.toSpecBridge(origin, 'attach:to:window')
const fn = isFunction(callbackFn) ? callbackFn.toString() : callbackFn
const file = $stackUtils.getSourceDetailsForFirstLine(userInvocationStack, config('projectRoot'))?.absoluteFile
const file = $stackUtils.getSourceDetailsForFirstLine(userInvocationStack, $sourceMapUtils.getSourceMapProjectRoot())?.absoluteFile

try {
// origin is a privileged command, meaning it has to be invoked
Expand Down
3 changes: 2 additions & 1 deletion packages/driver/src/cy/commands/sessions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
SESSION_STEPS,
statusMap,
} from './utils'
import $sourceMapUtils from '../../../cypress/source_map_utils'

/**
* Session data should be cleared with spec browser launch.
Expand Down Expand Up @@ -263,7 +264,7 @@ export default function (Commands, Cypress, cy) {
err = $errUtils.enhanceStack({
err,
userInvocationStack,
projectRoot: Cypress.config('projectRoot'),
projectRoot: $sourceMapUtils.getSourceMapProjectRoot(),
})

// show validation error and allow sessions workflow to recreate the session
Expand Down
5 changes: 5 additions & 0 deletions packages/driver/src/cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ class $Cypress {
lolex = fakeTimers
handlePrimaryOriginSocketEvent = handlePrimaryOriginSocketEvent
areSourceMapsAvailable: boolean = false
sourceMapProjectRoot: string = ''

static $: any
static utils: any
Expand Down Expand Up @@ -406,9 +407,13 @@ class $Cypress {
scripts,
specWindow,
testingType: this.testingType,
projectRoot: this.config('projectRoot'),
specRelativePath: this.spec.relative,
specAbsolutePath: this.spec.absolute,
})
.then(() => {
this.areSourceMapsAvailable = $sourceMapUtils.areSourceMapsAvailable()
this.sourceMapProjectRoot = $sourceMapUtils.getSourceMapProjectRoot()
if (this.testingType === 'e2e') {
return setSpecContentSecurityPolicy(specWindow)
}
Expand Down
3 changes: 2 additions & 1 deletion packages/driver/src/cypress/cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { historyNavigationTriggeredHashChange } from '../cy/navigation'
import { EventEmitter2 } from 'eventemitter2'
import { handleCrossOriginCookies } from '../cross-origin/events/cookies'
import { trackTopUrl } from '../util/trackTopUrl'
import $sourceMapUtils from './source_map_utils'

import type { ICypress } from '../cypress'
import type { ICookies } from './cookies'
Expand Down Expand Up @@ -399,7 +400,7 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert
err = $errUtils.enhanceStack({
err,
userInvocationStack,
projectRoot: this.config('projectRoot'),
projectRoot: $sourceMapUtils.getSourceMapProjectRoot(),
})

err = $errUtils.processErr(err, this.config)
Expand Down
Loading
Loading