mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-12 18:29:53 -05:00
feat: Add codeFrame to record data attempt errors (#8595)
This commit is contained in:
Vendored
+4
-3
@@ -8,6 +8,7 @@
|
||||
|
||||
declare namespace CypressCommandLine {
|
||||
type HookName = 'before' | 'beforeEach' | 'afterEach' | 'after'
|
||||
|
||||
interface TestError {
|
||||
name: string
|
||||
message: string
|
||||
@@ -225,7 +226,7 @@ declare namespace CypressCommandLine {
|
||||
startedAt: dateTimeISO
|
||||
endedAt: dateTimeISO
|
||||
duration: ms
|
||||
},
|
||||
}
|
||||
/**
|
||||
* Reporter name like "spec"
|
||||
*/
|
||||
@@ -255,7 +256,7 @@ declare namespace CypressCommandLine {
|
||||
* resolved filename of the spec
|
||||
*/
|
||||
absolute: string
|
||||
},
|
||||
}
|
||||
shouldUploadVideo: boolean
|
||||
}
|
||||
|
||||
@@ -358,7 +359,7 @@ declare module 'cypress' {
|
||||
})
|
||||
```
|
||||
*/
|
||||
run(options?: Partial<CypressCommandLine.CypressRunOptions>): Promise<CypressCommandLine.CypressRunResult | CypressCommandLine.CypressFailedRunResult>,
|
||||
run(options?: Partial<CypressCommandLine.CypressRunOptions>): Promise<CypressCommandLine.CypressRunResult | CypressCommandLine.CypressFailedRunResult>
|
||||
/**
|
||||
* Opens Cypress GUI. Resolves with void when the
|
||||
* GUI is closed.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2191,7 +2191,16 @@ exports['e2e record passing passes 2'] = [
|
||||
"error": {
|
||||
"name": "Error",
|
||||
"message": "foo\n\nBecause this error occurred during a `before each` hook we are skipping the remaining tests in the current suite: `record fails`",
|
||||
"stack": "[stack trace lines]"
|
||||
"stack": "[stack trace lines]",
|
||||
"codeFrame": {
|
||||
"line": 3,
|
||||
"column": 11,
|
||||
"originalFile": "cypress/integration/record_fail_spec.coffee",
|
||||
"relativeFile": "cypress/integration/record_fail_spec.coffee",
|
||||
"absoluteFile": "/foo/bar/.projects/e2e/cypress/integration/record_fail_spec.coffee",
|
||||
"frame": " 1 | describe \"record fails\", ->\n 2 | beforeEach ->\n> 3 | throw new Error(\"foo\")\n | ^\n 4 | \n 5 | it \"fails 1\", ->\n 6 | ",
|
||||
"language": "coffee"
|
||||
}
|
||||
},
|
||||
"timings": {
|
||||
"lifecycle": 100,
|
||||
@@ -2382,7 +2391,16 @@ exports['e2e record passing passes 2'] = [
|
||||
"error": {
|
||||
"name": "Error",
|
||||
"message": "The following error originated from your test code, not from Cypress.\n\n > instantly fails\n\nWhen Cypress detects uncaught errors originating from your test code it will automatically fail the current test.\n\nCypress could not associate this error to any specific test.\n\nWe dynamically generated a new test to display this failure.",
|
||||
"stack": "[stack trace lines]"
|
||||
"stack": "[stack trace lines]",
|
||||
"codeFrame": {
|
||||
"line": 1,
|
||||
"column": 7,
|
||||
"originalFile": "cypress/integration/record_uncaught_spec.coffee",
|
||||
"relativeFile": "cypress/integration/record_uncaught_spec.coffee",
|
||||
"absoluteFile": "/foo/bar/.projects/e2e/cypress/integration/record_uncaught_spec.coffee",
|
||||
"frame": "> 1 | throw new Error('instantly fails')\n | ^\n 2 | ",
|
||||
"language": "coffee"
|
||||
}
|
||||
},
|
||||
"timings": {
|
||||
"lifecycle": 100,
|
||||
|
||||
@@ -33,7 +33,16 @@ exports['lib/reporter #stats has reporterName stats, reporterStats, etc 1'] = {
|
||||
"state": "failed",
|
||||
"error": {
|
||||
"message": "foo",
|
||||
"stack": "at foo:1:1\nat bar:1:1\nat baz:1:1"
|
||||
"stack": "at foo:1:1\nat bar:1:1\nat baz:1:1",
|
||||
"codeFrame": {
|
||||
"line": 7,
|
||||
"column": 8,
|
||||
"originalFile": "cypress/integration/spec.js",
|
||||
"relativeFile": "cypress/integration/spec.js",
|
||||
"absoluteFile": "/path/to/cypress/integration/spec.js",
|
||||
"frame": " 5 | \n 6 | it('fails', () => {\n> 7 | cy.get('nope', { timeout: 1 })\n | ^\n 8 | })\n 9 | })\n 10 | ",
|
||||
"language": "js"
|
||||
}
|
||||
},
|
||||
"timings": null,
|
||||
"failedFromHookId": null,
|
||||
|
||||
@@ -362,6 +362,7 @@ class Reporter {
|
||||
name: attempt.err.name,
|
||||
message: attempt.err.message,
|
||||
stack: stackUtils.stackWithoutMessage(attempt.err.stack),
|
||||
codeFrame: attempt.err.codeFrame,
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -27,6 +27,9 @@ describe('e2e spec_isolation', () => {
|
||||
outputPath,
|
||||
snapshot: false,
|
||||
expectedExitCode: 5,
|
||||
config: {
|
||||
video: false,
|
||||
},
|
||||
async onRun (execFn) {
|
||||
const { stdout } = await execFn()
|
||||
|
||||
@@ -36,14 +39,16 @@ describe('e2e spec_isolation', () => {
|
||||
|
||||
// now what we want to do is read in the outputPath
|
||||
// and snapshot it so its what we expect after normalizing it
|
||||
const json = await fs.readJsonAsync(outputPath)
|
||||
let json = await fs.readJsonAsync(outputPath)
|
||||
|
||||
json.runs = e2e.normalizeRuns(json.runs)
|
||||
|
||||
// also mutates into normalized obj ready for snapshot
|
||||
expectCorrectModuleApiResult(json, {
|
||||
e2ePath, runs: 4,
|
||||
e2ePath, runs: 4, video: false,
|
||||
})
|
||||
|
||||
snapshot('e2e spec isolation fails', json, { allowSharedSnapshot: true })
|
||||
snapshot(json, { allowSharedSnapshot: true })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -54,15 +59,20 @@ describe('e2e spec_isolation', () => {
|
||||
expectedExitCode: 4,
|
||||
config: {
|
||||
retries: 1,
|
||||
video: false,
|
||||
},
|
||||
async onRun (execFn) {
|
||||
await execFn()
|
||||
const json = await fs.readJsonAsync(outputPath)
|
||||
let json = await fs.readJsonAsync(outputPath)
|
||||
|
||||
json.runs = e2e.normalizeRuns(json.runs)
|
||||
|
||||
// also mutates into normalized obj ready for snapshot
|
||||
expectCorrectModuleApiResult(json, { e2ePath, runs: 2 })
|
||||
expectCorrectModuleApiResult(json, {
|
||||
e2ePath, runs: 2, video: false,
|
||||
})
|
||||
|
||||
snapshot('failing with retries enabled', json)
|
||||
snapshot(json)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@@ -402,10 +402,12 @@ describe('e2e record', () => {
|
||||
expect(forthInstanceStdout.body.stdout).not.to.include('record_fail_spec.coffee')
|
||||
expect(forthInstanceStdout.body.stdout).not.to.include('record_pass_spec.coffee')
|
||||
|
||||
const runs = requests.filter((v) => v.body.tests).map((v) => v.body)
|
||||
let runs = requests.filter((v) => v.body.tests).map((v) => v.body)
|
||||
|
||||
expectRunsToHaveCorrectTimings(runs)
|
||||
|
||||
runs = e2e.normalizeRuns(runs)
|
||||
|
||||
snapshot(runs)
|
||||
|
||||
const results = await fs.readJsonAsync(outputPath)
|
||||
|
||||
@@ -781,6 +781,22 @@ const e2e = {
|
||||
.replace(/using description file: .* \(relative/g, 'using description file: [..] (relative')
|
||||
.replace(/Module build failed \(from .*\)/g, 'Module build failed (from [..])')
|
||||
},
|
||||
|
||||
normalizeRuns (runs) {
|
||||
runs.forEach((run) => {
|
||||
run.tests.forEach((test) => {
|
||||
test.attempts.forEach((attempt) => {
|
||||
const codeFrame = attempt.error && attempt.error.codeFrame
|
||||
|
||||
if (codeFrame) {
|
||||
codeFrame.absoluteFile = codeFrame.absoluteFile.split(pathUpToProjectName).join('/foo/bar/.projects')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return runs
|
||||
},
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -185,7 +185,12 @@ export const expectRunsToHaveCorrectTimings = (runs = []) => {
|
||||
export const expectCorrectModuleApiResult = (json, opts: {
|
||||
e2ePath: string
|
||||
runs: number
|
||||
video: boolean
|
||||
}) => {
|
||||
if (opts.video == null) {
|
||||
opts.video = true
|
||||
}
|
||||
|
||||
// should be n runs
|
||||
expect(json.runs).to.have.length(opts.runs)
|
||||
|
||||
@@ -281,8 +286,10 @@ export const expectCorrectModuleApiResult = (json, opts: {
|
||||
expect(d.toJSON()).to.eq(attempt.startedAt)
|
||||
attempt.startedAt = STATIC_DATE
|
||||
|
||||
expect(attempt.videoTimestamp).to.be.a('number')
|
||||
attempt.videoTimestamp = 9999
|
||||
if (opts.video) {
|
||||
expect(attempt.videoTimestamp).to.be.a('number')
|
||||
attempt.videoTimestamp = 9999
|
||||
}
|
||||
}
|
||||
|
||||
attempt.screenshots.forEach((screenshot) => {
|
||||
@@ -303,7 +310,9 @@ export const expectCorrectModuleApiResult = (json, opts: {
|
||||
}
|
||||
})
|
||||
|
||||
// normalize video path
|
||||
run.video = e2e.normalizeStdout(run.video)
|
||||
if (opts.video) {
|
||||
// normalize video path
|
||||
run.video = e2e.normalizeStdout(run.video)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,6 +33,15 @@ describe('lib/reporter', () => {
|
||||
err: {
|
||||
message: 'foo',
|
||||
stack: 'at foo:1:1\nat bar:1:1\nat baz:1:1',
|
||||
codeFrame: {
|
||||
line: 7,
|
||||
column: 8,
|
||||
originalFile: 'cypress/integration/spec.js',
|
||||
relativeFile: 'cypress/integration/spec.js',
|
||||
absoluteFile: '/path/to/cypress/integration/spec.js',
|
||||
frame: ' 5 | \n 6 | it(\'fails\', () => {\n> 7 | cy.get(\'nope\', { timeout: 1 })\n | ^\n 8 | })\n 9 | })\n 10 | ',
|
||||
language: 'js',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user