Skip to content

Commit bf590eb

Browse files
mike-plummerZachJW34astone123lmiller1990
authored
feat: CT stack traces (#23916)
Co-authored-by: Zachary Williams <[email protected]> Co-authored-by: astone123 <[email protected]> Co-authored-by: Lachlan Miller <[email protected]>
1 parent 3aad5a0 commit bf590eb

File tree

152 files changed

+5950
-137
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+5950
-137
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ windowsWorkflowFilters: &windows-workflow-filters
6363
or:
6464
- equal: [ develop, << pipeline.git.branch >> ]
6565
- equal: [ linux-arm64, << pipeline.git.branch >> ]
66-
- equal: [ 'lmiller/fixing-windows-ci', << pipeline.git.branch >> ]
66+
- equal: [ 'mikep/21720-ct-stack-traces', << pipeline.git.branch >> ]
6767
- matches:
6868
pattern: "-release$"
6969
value: << pipeline.git.branch >>

npm/vite-dev-server/client/initCypressTests.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,22 @@ if (supportFile) {
2424

2525
// We need a slash before /cypress/supportFile.js, this happens by default
2626
// with the current string replacement logic.
27-
importsToLoad.push(() => import(`${devServerPublicPathRoute}${supportRelativeToProjectRoot}`))
27+
importsToLoad.push({
28+
load: () => import(`${devServerPublicPathRoute}${supportRelativeToProjectRoot}`),
29+
absolute: supportFile,
30+
relative: supportRelativeToProjectRoot,
31+
relativeUrl: `${devServerPublicPathRoute}${supportRelativeToProjectRoot}`,
32+
})
2833
}
2934

3035
/* Spec file import logic */
3136
// We need a slash before /src/my-spec.js, this does not happen by default.
32-
importsToLoad.push(() => import(`${devServerPublicPathRoute}/${CypressInstance.spec.relative}`))
37+
importsToLoad.push({
38+
load: () => import(`${devServerPublicPathRoute}/${CypressInstance.spec.relative}`),
39+
absolute: CypressInstance.spec.absolute,
40+
relative: CypressInstance.spec.relative,
41+
relativeUrl: `${devServerPublicPathRoute}/${CypressInstance.spec.relative}`,
42+
})
3343

3444
if (!CypressInstance) {
3545
throw new Error('Tests cannot run without a reference to Cypress!')

npm/vite-dev-server/cypress/e2e/react.cy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ for (const project of VITE_REACT) {
5757
cy.contains('MissingReactInSpec.cy.jsx').click()
5858
cy.waitForSpecToFinish()
5959
cy.get('.failed > .num').should('contain', 1)
60+
cy.get('.test-err-code-frame').should('be.visible')
6061
cy.withCtx(async (ctx) => {
6162
await ctx.actions.file.writeFileInProject(`src/MissingReactInSpec.cy.jsx`,
6263
await ctx.file.readFileInProject('src/App.cy.jsx'))

npm/vite-dev-server/src/plugins/cypress.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,27 @@ export const Cypress = (
105105
return res.end(transformedIndexHtml)
106106
})
107107
},
108+
transform (code, id, options?) {
109+
try {
110+
if (/\.js$/i.test(id) && !/\/\/# sourceMappingURL=/i.test(code)) {
111+
// The Vite dev server and plugins automatically transpile TS and JSX files, which results in sourcemaps being generated
112+
// and included in output. However, Vite serves up `esnext`-compliant Javascript which means many JS files won't be
113+
// transpiled and won't supply a sourcemap - this prevents Cypress from providing codeFrames in the event of an error.
114+
//
115+
// A sourcemap is generated by Vite for JS files (just not included) which is in effect an "identity" sourcemap mapping
116+
// 1-to-1 to the output file. We can grab this and pass it along as a sourcemap we want Vite to embed into the output,
117+
// giving Cypress a sourcemap to use for codeFrame lookups.
118+
// @see https://rollupjs.org/guide/en/#thisgetcombinedsourcemap
119+
120+
return {
121+
code,
122+
map: this.getCombinedSourcemap(),
123+
}
124+
}
125+
} catch (_err) {
126+
debug('Failed to propagate sourcemap for %s: %o', id, _err)
127+
}
128+
},
108129
handleHotUpdate: ({ server, file }) => {
109130
debug('handleHotUpdate - file', file)
110131

npm/webpack-dev-server/__snapshots__/makeWebpackConfig.spec.ts.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,18 @@ exports['makeWebpackConfig ignores userland webpack `output.publicPath` and `dev
1010
"overlay": false
1111
}
1212
},
13-
"mode": "development",
1413
"optimization": {
1514
"emitOnErrors": true,
1615
"splitChunks": {
1716
"chunks": "all"
1817
}
1918
},
19+
"mode": "development",
2020
"plugins": [
2121
"HtmlWebpackPlugin",
2222
"CypressCTWebpackPlugin"
23-
]
23+
],
24+
"devtool": "inline-source-map"
2425
}
2526

2627
exports['makeWebpackConfig ignores userland webpack `output.publicPath` and `devServer.overlay` with webpack-dev-server v3 1'] = {
@@ -32,15 +33,16 @@ exports['makeWebpackConfig ignores userland webpack `output.publicPath` and `dev
3233
"progress": true,
3334
"overlay": false
3435
},
35-
"mode": "development",
3636
"optimization": {
3737
"noEmitOnErrors": false,
3838
"splitChunks": {
3939
"chunks": "all"
4040
}
4141
},
42+
"mode": "development",
4243
"plugins": [
4344
"HtmlWebpackPlugin",
4445
"CypressCTWebpackPlugin"
45-
]
46+
],
47+
"devtool": "inline-source-map"
4648
}

npm/webpack-dev-server/cypress/e2e/angular.cy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ for (const project of WEBPACK_REACT) {
7373
// The test should fail and the stack trace should appear in the command log
7474
cy.waitForSpecToFinish({ failCount: 1 })
7575
cy.contains('The following error originated from your test code, not from Cypress.').should('exist')
76+
cy.get('.test-err-code-frame').should('be.visible')
7677
})
7778

7879
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23455

npm/webpack-dev-server/cypress/e2e/create-react-app.cy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ for (const project of WEBPACK_REACT) {
3838
})
3939

4040
cy.waitForSpecToFinish({ failCount: 1 })
41+
cy.get('.test-err-code-frame').should('be.visible')
4142

4243
cy.withCtx(async (ctx) => {
4344
await ctx.actions.file.writeFileInProject(

npm/webpack-dev-server/cypress/e2e/next.cy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ for (const project of WEBPACK_REACT) {
4040
})
4141

4242
cy.waitForSpecToFinish({ failCount: 1 })
43+
cy.get('.test-err-code-frame').should('be.visible')
4344

4445
cy.withCtx(async (ctx) => {
4546
const indexTestPath = ctx.path.join('pages', 'index.cy.js')

npm/webpack-dev-server/cypress/e2e/nuxt.cy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ for (const project of PROJECTS) {
3535
})
3636

3737
cy.waitForSpecToFinish({ failCount: 1 })
38+
cy.get('.test-err-code-frame').should('be.visible')
3839

3940
cy.withCtx(async (ctx) => {
4041
const tutorialCyPath = ctx.path.join('components', 'Tutorial.cy.js')

npm/webpack-dev-server/cypress/e2e/react.cy.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ for (const project of WEBPACK_REACT) {
2424
it('should mount a passing test', () => {
2525
cy.visitApp()
2626
cy.contains('App.cy.jsx').click()
27-
cy.waitForSpecToFinish()
28-
cy.get('.passed > .num').should('contain', 1)
27+
cy.waitForSpecToFinish({ passCount: 1 })
2928
})
3029

3130
it('MissingReact: should fail, rerun, succeed', () => {
@@ -36,15 +35,15 @@ for (const project of WEBPACK_REACT) {
3635

3736
cy.visitApp()
3837
cy.contains('MissingReact.cy.jsx').click()
39-
cy.waitForSpecToFinish()
40-
cy.get('.failed > .num').should('contain', 1)
38+
cy.waitForSpecToFinish({ failCount: 1 })
39+
cy.get('.test-err-code-frame').should('be.visible')
4140
cy.withCtx(async (ctx) => {
4241
await ctx.actions.file.writeFileInProject(`src/MissingReact.jsx`,
4342
`import React from 'react';
4443
${await ctx.file.readFileInProject('src/MissingReact.jsx')}`)
4544
})
4645

47-
cy.get('.passed > .num').should('contain', 1)
46+
cy.waitForSpecToFinish({ passCount: 1 })
4847
})
4948

5049
it('MissingReactInSpec: should fail, rerun, succeed', () => {
@@ -55,14 +54,14 @@ for (const project of WEBPACK_REACT) {
5554

5655
cy.visitApp()
5756
cy.contains('MissingReactInSpec.cy.jsx').click()
58-
cy.waitForSpecToFinish()
59-
cy.get('.failed > .num').should('contain', 1)
57+
cy.waitForSpecToFinish({ failCount: 1 })
58+
cy.get('.test-err-code-frame').should('be.visible')
6059
cy.withCtx(async (ctx) => {
6160
await ctx.actions.file.writeFileInProject(`src/MissingReactInSpec.cy.jsx`,
6261
await ctx.file.readFileInProject('src/App.cy.jsx'))
6362
})
6463

65-
cy.get('.passed > .num').should('contain', 1)
64+
cy.waitForSpecToFinish({ passCount: 1 })
6665
})
6766

6867
it('AppCompilationError: should fail with uncaught exception error', () => {
@@ -73,8 +72,7 @@ for (const project of WEBPACK_REACT) {
7372

7473
cy.visitApp()
7574
cy.contains('AppCompilationError.cy.jsx').click()
76-
cy.waitForSpecToFinish()
77-
cy.get('.failed > .num').should('contain', 1)
75+
cy.waitForSpecToFinish({ failCount: 1 })
7876
cy.contains('An uncaught error was detected outside of a test')
7977
cy.contains('The following error originated from your test code, not from Cypress.')
8078

@@ -86,8 +84,7 @@ for (const project of WEBPACK_REACT) {
8684
)
8785
})
8886

89-
cy.waitForSpecToFinish()
90-
cy.get('.passed > .num').should('contain', 1)
87+
cy.waitForSpecToFinish({ passCount: 1 })
9188

9289
const appCompilationErrorSpec = dedent`
9390
import React from 'react'
@@ -109,8 +106,7 @@ for (const project of WEBPACK_REACT) {
109106
)
110107
}, { appCompilationErrorSpec })
111108

112-
cy.waitForSpecToFinish()
113-
cy.get('.failed > .num').should('contain', 1)
109+
cy.waitForSpecToFinish({ failCount: 1 })
114110
cy.contains('An uncaught error was detected outside of a test')
115111
cy.contains('The following error originated from your test code, not from Cypress.')
116112
})
@@ -121,7 +117,7 @@ for (const project of WEBPACK_REACT) {
121117

122118
// 1. assert spec executes successfully
123119
cy.contains('App.cy.jsx').click()
124-
cy.get('.passed > .num').should('contain', 1)
120+
cy.waitForSpecToFinish({ passCount: 1 })
125121

126122
// 2. remove file from file system
127123
cy.withCtx(async (ctx) => {
@@ -143,7 +139,7 @@ for (const project of WEBPACK_REACT) {
143139
})
144140

145141
// 5. assert recreated spec executes successfully
146-
cy.get('.passed > .num').should('contain', 1)
142+
cy.waitForSpecToFinish({ passCount: 1 })
147143
})
148144
})
149145
}

0 commit comments

Comments
 (0)