Skip to content

Commit 75a9f96

Browse files
emilyrohrboughBlue FAtofStryker
authored
chore: destroy source maps consumers when spec finishes (#23708)
Co-authored-by: Blue F <[email protected]> Co-authored-by: Bill Glesias <[email protected]>
1 parent 25a47aa commit 75a9f96

File tree

6 files changed

+41
-27
lines changed

6 files changed

+41
-27
lines changed

packages/driver/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ TODO: this data is accurate but also somewhat out of date.
8282
| mocha:fail | Mocha | Cypress | when mocha runner fires its 'fail' event |
8383
| test:end | Mocha | Cypress | when mocha runner fires its 'test end' event |
8484
| test:results:ready | Runner | Anyone | when we receive the 'test:end' event |
85-
| test:after:hooks | Cypress | Cypress | after all hooks have run for a test |
8685
| test:after:run | Cypress | Anyone | after any code has run for a test |
8786
| mocha:end | Mocha | Cypress | when mocha runner fires its 'end' event |
8887
| after:run | Runner | Anyone | after run has finished |

packages/driver/cypress/e2e/cypress/script_utils.cy.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ describe('src/cypress/script_utils', () => {
3535
return $scriptUtils.runScripts(scriptWindow, scripts)
3636
.then(() => {
3737
expect($sourceMapUtils.extractSourceMap).to.be.calledTwice
38-
expect($sourceMapUtils.extractSourceMap).to.be.calledWith(scripts[0], 'the script contents')
39-
expect($sourceMapUtils.extractSourceMap).to.be.calledWith(scripts[1], 'the script contents')
38+
expect($sourceMapUtils.extractSourceMap).to.be.calledWith('the script contents')
39+
expect($sourceMapUtils.extractSourceMap).to.be.calledWith('the script contents')
4040
})
4141
})
4242

packages/driver/cypress/e2e/cypress/source_map_utils.cy.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,19 @@ const file2 = createFile('file2')
4646
describe('driver/src/cypress/source_map_utils', () => {
4747
context('.extractSourceMap', () => {
4848
it('returns null if there is no source map embedded', () => {
49-
const sourceMap = $sourceMapUtils.extractSourceMap(file2, testContent)
49+
const sourceMap = $sourceMapUtils.extractSourceMap(testContent)
5050

5151
expect(sourceMap).to.be.null
5252
})
5353

5454
it('returns null if it is not an inline map', () => {
55-
const sourceMap = $sourceMapUtils.extractSourceMap(file2, `${testContent}\n\/\/# sourceMappingURL=foo.map`)
55+
const sourceMap = $sourceMapUtils.extractSourceMap(`${testContent}\n\/\/# sourceMappingURL=foo.map`)
5656

5757
expect(sourceMap).to.be.null
5858
})
5959

6060
it('returns source map when content has an inline map', () => {
61-
const sourceMap = $sourceMapUtils.extractSourceMap(file1, fileContents)
61+
const sourceMap = $sourceMapUtils.extractSourceMap(fileContents)
6262

6363
expect(sourceMap).to.be.eql(sourceMap)
6464
})
@@ -71,7 +71,7 @@ describe('driver/src/cypress/source_map_utils', () => {
7171
const timeLimit = 10
7272
const startTime = Date.now()
7373

74-
$sourceMapUtils.extractSourceMap(file1, fileContents)
74+
$sourceMapUtils.extractSourceMap(fileContents)
7575

7676
const endTime = Date.now()
7777

@@ -81,7 +81,7 @@ describe('driver/src/cypress/source_map_utils', () => {
8181

8282
// https://github.com/cypress-io/cypress/issues/7481
8383
it('does not garble utf-8 characters', () => {
84-
const sourceMap = $sourceMapUtils.extractSourceMap(file1, fileContents)
84+
const sourceMap = $sourceMapUtils.extractSourceMap(fileContents)
8585

8686
expect(sourceMap.sourcesContent[1]).to.include('サイプリスは一番')
8787
})

packages/driver/src/cypress.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import debugFn from 'debug'
99

1010
import browserInfo from './cypress/browser'
1111
import $scriptUtils from './cypress/script_utils'
12+
import $sourceMapUtils from './cypress/source_map_utils'
1213

1314
import $Commands from './cypress/commands'
1415
import { $Cy } from './cypress/cy'
@@ -403,15 +404,9 @@ class $Cypress {
403404
break
404405

405406
case 'runner:end':
406-
// mocha runner has finished running the tests
407+
$sourceMapUtils.destroySourceMapConsumers()
407408

408-
// end may have been caused by an uncaught error
409-
// that happened inside of a hook.
410-
//
411-
// when this happens mocha aborts the entire run
412-
// and does not do the usual cleanup so that means
413-
// we have to fire the test:after:hooks and
414-
// test:after:run events ourselves
409+
// mocha runner has finished running the tests
415410
this.emit('run:end')
416411

417412
this.maybeEmitCypressInCypress('mocha', 'end', args[0])

packages/driver/src/cypress/script_utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const fetchScript = (scriptWindow, script) => {
1414
const extractSourceMap = ([script, contents]) => {
1515
script.fullyQualifiedUrl = `${window.top!.location.origin}${script.relativeUrl}`.replace(/ /g, '%20')
1616

17-
const sourceMap = $sourceMapUtils.extractSourceMap(script, contents)
17+
const sourceMap = $sourceMapUtils.extractSourceMap(contents)
1818

1919
return $sourceMapUtils.initializeSourceMapConsumer(script, sourceMap)
2020
.catch((_err) => {

packages/driver/src/cypress/source_map_utils.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import _ from 'lodash'
22
import { SourceMapConsumer } from 'source-map'
33

4+
import type { BasicSourceMapConsumer } from 'source-map'
45
// @ts-ignore
56
import mappingsWasm from 'source-map/lib/mappings.wasm'
67

@@ -9,9 +10,9 @@ import $utils from './utils'
910
const sourceMapExtractionRegex = /\/\/\s*[@#]\s*sourceMappingURL\s*=\s*(data:[^\s]*)/g
1011
const regexDataUrl = /data:[^;\n]+(?:;charset=[^;\n]+)?;base64,([a-zA-Z0-9+/]+={0,2})/ // matches data urls
1112

12-
let sourceMapConsumers = {}
13+
let sourceMapConsumers: Record<string, BasicSourceMapConsumer> = {}
1314

14-
const initializeSourceMapConsumer = async (file, sourceMap) => {
15+
const initializeSourceMapConsumer = async (script, sourceMap): Promise<BasicSourceMapConsumer | null> => {
1516
if (!sourceMap) return null
1617

1718
// @ts-ignore
@@ -21,18 +22,29 @@ const initializeSourceMapConsumer = async (file, sourceMap) => {
2122

2223
const consumer = await new SourceMapConsumer(sourceMap)
2324

24-
sourceMapConsumers[file.fullyQualifiedUrl] = consumer
25+
sourceMapConsumers[script.fullyQualifiedUrl] = consumer
2526

2627
return consumer
2728
}
2829

29-
const extractSourceMap = (file, fileContents) => {
30-
let sourceMapMatch = fileContents.match(sourceMapExtractionRegex)
30+
const extractSourceMap = (fileContents) => {
31+
let dataUrlMatch
3132

32-
if (!sourceMapMatch) return null
33+
try {
34+
let sourceMapMatch = fileContents.match(sourceMapExtractionRegex)
35+
36+
if (!sourceMapMatch) return null
37+
38+
const url = _.last(sourceMapMatch) as any
3339

34-
const url = _.last(sourceMapMatch) as any
35-
const dataUrlMatch = url.match(regexDataUrl)
40+
dataUrlMatch = url.match(regexDataUrl)
41+
} catch (err) {
42+
// ignore unable to match regex. there's nothing we
43+
// can do about it and we don't want to thrown an exception
44+
if (err.message === 'Maximum call stack size exceeded') return null
45+
46+
throw err
47+
}
3648

3749
if (!dataUrlMatch) return null
3850

@@ -61,15 +73,16 @@ const getSourcePosition = (filePath, position) => {
6173

6274
if (!sourceMapConsumer) return null
6375

64-
const sourcePosition = sourceMapConsumer.originalPositionFor(position)
65-
const { source, line, column } = sourcePosition
76+
const { source, line, column } = sourceMapConsumer.originalPositionFor(position)
6677

6778
if (!source || line == null || column == null) return
6879

6980
// if the file is outside of the projectRoot
7081
// originalPositionFor will not provide the correct relative path
7182
// https://github.com/cypress-io/cypress/issues/16255
83+
// @ts-expect-error
7284
const sourceIndex = sourceMapConsumer._absoluteSources.indexOf(source)
85+
// @ts-expect-error
7386
const file = sourceMapConsumer._sources.at(sourceIndex)
7487

7588
return {
@@ -89,9 +102,16 @@ const base64toJs = (base64) => {
89102
}
90103
}
91104

105+
const destroySourceMapConsumers = () => {
106+
Object.values(sourceMapConsumers).forEach((consumer) => {
107+
consumer.destroy()
108+
})
109+
}
110+
92111
export default {
93112
getSourcePosition,
94113
getSourceContents,
95114
extractSourceMap,
96115
initializeSourceMapConsumer,
116+
destroySourceMapConsumers,
97117
}

0 commit comments

Comments
 (0)