dd-trace 3.2.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +2 -1
- package/README.md +4 -0
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +14 -12
- package/packages/datadog-instrumentations/src/grpc/server.js +15 -7
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/jest.js +136 -14
- package/packages/datadog-instrumentations/src/mocha.js +77 -31
- package/packages/datadog-instrumentations/src/next.js +7 -3
- package/packages/datadog-plugin-jest/src/index.js +106 -6
- package/packages/datadog-plugin-mocha/src/index.js +15 -7
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +27 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +13 -5
- package/packages/dd-trace/src/appsec/recommended.json +1144 -275
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +3 -3
- package/packages/dd-trace/src/config.js +16 -2
- package/packages/dd-trace/src/encode/0.4.js +7 -1
- package/packages/dd-trace/src/encode/0.5.js +7 -1
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +2 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -20
- package/packages/dd-trace/src/exporters/common/request.js +3 -3
- package/packages/dd-trace/src/opentracing/span.js +6 -0
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/util/ip_blocklist.js +30 -4
- package/packages/dd-trace/src/plugins/util/redis.js +0 -74
- package/packages/dd-trace/src/plugins/util/tx.js +0 -75
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -3,11 +3,11 @@ require,@datadog/native-appsec,Apache license 2.0,Copyright 2018 Datadog Inc.
|
|
|
3
3
|
require,@datadog/native-metrics,Apache license 2.0,Copyright 2018 Datadog Inc.
|
|
4
4
|
require,@datadog/pprof,Apache license 2.0,Copyright 2019 Google Inc.
|
|
5
5
|
require,@datadog/sketches-js,Apache license 2.0,Copyright 2020 Datadog Inc.
|
|
6
|
-
require,cidr-matcher,MIT,Copyright 2015 Marco Pracucci
|
|
7
6
|
require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
|
|
8
7
|
require,diagnostics_channel,MIT,Copyright 2021 Simon D.
|
|
9
8
|
require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
|
|
10
9
|
require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
|
|
10
|
+
require,ipaddr.js,MIT,Copyright 2011-2017 whitequark
|
|
11
11
|
require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.
|
|
12
12
|
require,koalas,MIT,Copyright 2013-2017 Brian Woodward
|
|
13
13
|
require,limiter,MIT,Copyright 2011 John Hurliman
|
|
@@ -15,6 +15,7 @@ require,lodash.kebabcase,MIT,Copyright JS Foundation and other contributors
|
|
|
15
15
|
require,lodash.pick,MIT,Copyright JS Foundation and other contributors
|
|
16
16
|
require,lodash.sortby,MIT,Copyright JS Foundation and other contributors
|
|
17
17
|
require,lodash.uniq,MIT,Copyright JS Foundation and other contributors
|
|
18
|
+
require,lru-cache,ISC,Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors
|
|
18
19
|
require,methods,MIT,Copyright 2013-2014 TJ Holowaychuk
|
|
19
20
|
require,module-details-from-path,MIT,Copyright 2016 Thomas Watson Steen
|
|
20
21
|
require,opentracing,MIT,Copyright 2016 Resonance Labs Inc
|
package/README.md
CHANGED
|
@@ -21,6 +21,10 @@ For descriptions of terminology used in APM, take a look at the [official docume
|
|
|
21
21
|
|
|
22
22
|
Before contributing to this open source project, read our [CONTRIBUTING.md](https://github.com/DataDog/dd-trace-js/blob/master/CONTRIBUTING.md).
|
|
23
23
|
|
|
24
|
+
## Security Vulnerabilities
|
|
25
|
+
|
|
26
|
+
If you have found a security issue, please contact the security team directly at [security@datadoghq.com](mailto:security@datadoghq.com).
|
|
27
|
+
|
|
24
28
|
### Requirements
|
|
25
29
|
|
|
26
30
|
Since this project supports multiple Node versions, using a version
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -59,14 +59,14 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@datadog/native-appsec": "^1.2.1",
|
|
62
|
-
"@datadog/native-metrics": "^1.4.
|
|
62
|
+
"@datadog/native-metrics": "^1.4.3",
|
|
63
63
|
"@datadog/pprof": "^1.0.2",
|
|
64
64
|
"@datadog/sketches-js": "^2.1.0",
|
|
65
|
-
"cidr-matcher": "^2.1.1",
|
|
66
65
|
"crypto-randomuuid": "^1.0.0",
|
|
67
66
|
"diagnostics_channel": "^1.1.0",
|
|
68
67
|
"ignore": "^5.2.0",
|
|
69
|
-
"import-in-the-middle": "^1.3.
|
|
68
|
+
"import-in-the-middle": "^1.3.4",
|
|
69
|
+
"ipaddr.js": "^2.0.1",
|
|
70
70
|
"istanbul-lib-coverage": "3.2.0",
|
|
71
71
|
"koalas": "^1.0.2",
|
|
72
72
|
"limiter": "^1.1.4",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"lodash.pick": "^4.4.0",
|
|
75
75
|
"lodash.sortby": "^4.7.0",
|
|
76
76
|
"lodash.uniq": "^4.5.0",
|
|
77
|
+
"lru-cache": "^7.14.0",
|
|
77
78
|
"methods": "^1.1.2",
|
|
78
79
|
"module-details-from-path": "^1.0.3",
|
|
79
80
|
"opentracing": ">=0.12.1",
|
|
@@ -6,25 +6,27 @@ const {
|
|
|
6
6
|
} = require('./helpers/instrument')
|
|
7
7
|
const shimmer = require('../../datadog-shimmer')
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const cryptoHashCh = channel('datadog:crypto:hashing:start')
|
|
10
|
+
const cryptoCipherCh = channel('datadog:crypto:cipher:start')
|
|
11
|
+
|
|
12
|
+
const hashMethods = ['createHash', 'createHmac', 'createSign', 'createVerify', 'sign', 'verify']
|
|
13
|
+
const cipherMethods = ['createCipheriv', 'createDecipheriv']
|
|
10
14
|
|
|
11
15
|
addHook({ name: 'crypto' }, crypto => {
|
|
12
|
-
shimmer.massWrap(
|
|
13
|
-
|
|
14
|
-
['createHash', 'createHmac', 'createSign', 'createVerify', 'sign', 'verify'],
|
|
15
|
-
wrapMethod
|
|
16
|
-
)
|
|
16
|
+
shimmer.massWrap(crypto, hashMethods, wrapCryptoMethod(cryptoHashCh))
|
|
17
|
+
shimmer.massWrap(crypto, cipherMethods, wrapCryptoMethod(cryptoCipherCh))
|
|
17
18
|
return crypto
|
|
18
19
|
})
|
|
19
20
|
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (arguments.length > 0) {
|
|
21
|
+
function wrapCryptoMethod (channel) {
|
|
22
|
+
function wrapMethod (cryptoMethod) {
|
|
23
|
+
return function () {
|
|
24
|
+
if (channel.hasSubscribers && arguments.length > 0) {
|
|
24
25
|
const algorithm = arguments[0]
|
|
25
|
-
|
|
26
|
+
channel.publish({ algorithm })
|
|
26
27
|
}
|
|
28
|
+
return cryptoMethod.apply(this, arguments)
|
|
27
29
|
}
|
|
28
|
-
return cryptoMethod.apply(this, arguments)
|
|
29
30
|
}
|
|
31
|
+
return wrapMethod
|
|
30
32
|
}
|
|
@@ -37,15 +37,17 @@ function wrapHandler (func, name) {
|
|
|
37
37
|
return requestResource.runInAsyncScope(() => {
|
|
38
38
|
startChannel.publish({ name, metadata, type })
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
call.once('cancelled', requestResource.bind(() => {
|
|
40
|
+
const onCancel = requestResource.bind(() => {
|
|
42
41
|
finishChannel.publish({ code: CANCELLED })
|
|
43
|
-
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// Finish the span if the call was cancelled.
|
|
45
|
+
call.once('cancelled', onCancel)
|
|
44
46
|
|
|
45
47
|
if (isStream) {
|
|
46
|
-
wrapStream(call, requestResource,
|
|
48
|
+
wrapStream(call, requestResource, onCancel)
|
|
47
49
|
} else {
|
|
48
|
-
arguments[1] = wrapCallback(callback, requestResource, parentResource)
|
|
50
|
+
arguments[1] = wrapCallback(callback, call, requestResource, parentResource, onCancel)
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
shimmer.wrap(call, 'emit', emit => requestResource.bind(emit))
|
|
@@ -65,7 +67,7 @@ function wrapRegister (register) {
|
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
function wrapStream (call, requestResource) {
|
|
70
|
+
function wrapStream (call, requestResource, onCancel) {
|
|
69
71
|
if (call.call && call.call.sendStatus) {
|
|
70
72
|
call.call.sendStatus = wrapSendStatus(call.call.sendStatus, requestResource)
|
|
71
73
|
}
|
|
@@ -77,6 +79,8 @@ function wrapStream (call, requestResource) {
|
|
|
77
79
|
errorChannel.publish(args[0])
|
|
78
80
|
finishChannel.publish({ code: args[0].code })
|
|
79
81
|
|
|
82
|
+
call.removeListener('cancelled', onCancel)
|
|
83
|
+
|
|
80
84
|
break
|
|
81
85
|
|
|
82
86
|
// Finish the span of the response only if it was successful.
|
|
@@ -90,6 +94,8 @@ function wrapStream (call, requestResource) {
|
|
|
90
94
|
finishChannel.publish()
|
|
91
95
|
}
|
|
92
96
|
|
|
97
|
+
call.removeListener('cancelled', onCancel)
|
|
98
|
+
|
|
93
99
|
break
|
|
94
100
|
}
|
|
95
101
|
|
|
@@ -98,7 +104,7 @@ function wrapStream (call, requestResource) {
|
|
|
98
104
|
})
|
|
99
105
|
}
|
|
100
106
|
|
|
101
|
-
function wrapCallback (callback, requestResource, parentResource) {
|
|
107
|
+
function wrapCallback (callback, call, requestResource, parentResource, onCancel) {
|
|
102
108
|
return function (err, value, trailer, flags) {
|
|
103
109
|
requestResource.runInAsyncScope(() => {
|
|
104
110
|
if (err instanceof Error) {
|
|
@@ -107,6 +113,8 @@ function wrapCallback (callback, requestResource, parentResource) {
|
|
|
107
113
|
} else {
|
|
108
114
|
finishChannel.publish({ code: OK, trailer })
|
|
109
115
|
}
|
|
116
|
+
|
|
117
|
+
call.removeListener('cancelled', onCancel)
|
|
110
118
|
})
|
|
111
119
|
|
|
112
120
|
if (callback) {
|
|
@@ -7,6 +7,7 @@ module.exports = {
|
|
|
7
7
|
'@google-cloud/pubsub': () => require('../google-cloud-pubsub'),
|
|
8
8
|
'@grpc/grpc-js': () => require('../grpc'),
|
|
9
9
|
'@hapi/hapi': () => require('../hapi'),
|
|
10
|
+
'@jest/core': () => require('../jest'),
|
|
10
11
|
'@koa/router': () => require('../koa'),
|
|
11
12
|
'@node-redis/client': () => require('../redis'),
|
|
12
13
|
'amqp10': () => require('../amqp10'),
|
|
@@ -31,6 +32,8 @@ module.exports = {
|
|
|
31
32
|
'http2': () => require('../http2'),
|
|
32
33
|
'https': () => require('../http'),
|
|
33
34
|
'ioredis': () => require('../ioredis'),
|
|
35
|
+
'jest-circus': () => require('../jest'),
|
|
36
|
+
'jest-config': () => require('../jest'),
|
|
34
37
|
'jest-environment-node': () => require('../jest'),
|
|
35
38
|
'jest-environment-jsdom': () => require('../jest'),
|
|
36
39
|
'jest-jasmine2': () => require('../jest'),
|
|
@@ -3,13 +3,20 @@ const istanbul = require('istanbul-lib-coverage')
|
|
|
3
3
|
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
5
|
|
|
6
|
+
const testSessionStartCh = channel('ci:jest:session:start')
|
|
7
|
+
const testSessionFinishCh = channel('ci:jest:session:finish')
|
|
8
|
+
|
|
9
|
+
const testSessionConfigurationCh = channel('ci:jest:session:configuration')
|
|
10
|
+
|
|
11
|
+
const testSuiteStartCh = channel('ci:jest:test-suite:start')
|
|
12
|
+
const testSuiteFinishCh = channel('ci:jest:test-suite:finish')
|
|
13
|
+
const testSuiteCodeCoverageCh = channel('ci:jest:test-suite:code-coverage')
|
|
14
|
+
|
|
6
15
|
const testStartCh = channel('ci:jest:test:start')
|
|
7
16
|
const testSkippedCh = channel('ci:jest:test:skip')
|
|
8
17
|
const testRunFinishCh = channel('ci:jest:test:finish')
|
|
9
18
|
const testErrCh = channel('ci:jest:test:err')
|
|
10
19
|
|
|
11
|
-
const testCodeCoverageCh = channel('ci:jest:test:code-coverage')
|
|
12
|
-
|
|
13
20
|
const {
|
|
14
21
|
getTestSuitePath,
|
|
15
22
|
getTestParametersString
|
|
@@ -17,7 +24,8 @@ const {
|
|
|
17
24
|
|
|
18
25
|
const { getFormattedJestTestParameters, getJestTestName } = require('../../datadog-plugin-jest/src/util')
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
28
|
+
|
|
21
29
|
function extractCoverageInformation (coverage, rootDir) {
|
|
22
30
|
const coverageMap = istanbul.createCoverageMap(coverage)
|
|
23
31
|
|
|
@@ -28,8 +36,6 @@ function extractCoverageInformation (coverage, rootDir) {
|
|
|
28
36
|
const lineCoverage = fileCoverage.getLineCoverage()
|
|
29
37
|
const isAnyLineExecuted = Object.entries(lineCoverage).some(([, numExecutions]) => !!numExecutions)
|
|
30
38
|
|
|
31
|
-
fileCoverage.resetHits()
|
|
32
|
-
|
|
33
39
|
return isAnyLineExecuted
|
|
34
40
|
})
|
|
35
41
|
.map(filename => filename.replace(`${rootDir}/`, ''))
|
|
@@ -63,6 +69,16 @@ function formatJestError (errors) {
|
|
|
63
69
|
return error
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
function getTestEnvironmentOptions (config) {
|
|
73
|
+
if (config.projectConfig && config.projectConfig.testEnvironmentOptions) { // newer versions
|
|
74
|
+
return config.projectConfig.testEnvironmentOptions
|
|
75
|
+
}
|
|
76
|
+
if (config.testEnvironmentOptions) {
|
|
77
|
+
return config.testEnvironmentOptions
|
|
78
|
+
}
|
|
79
|
+
return {}
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
function getWrappedEnvironment (BaseEnvironment) {
|
|
67
83
|
return class DatadogEnvironment extends BaseEnvironment {
|
|
68
84
|
constructor (config, context) {
|
|
@@ -72,6 +88,8 @@ function getWrappedEnvironment (BaseEnvironment) {
|
|
|
72
88
|
this.testSuite = getTestSuitePath(context.testPath, rootDir)
|
|
73
89
|
this.nameToParams = {}
|
|
74
90
|
this.global._ddtrace = global._ddtrace
|
|
91
|
+
|
|
92
|
+
this.testEnvironmentOptions = getTestEnvironmentOptions(config)
|
|
75
93
|
}
|
|
76
94
|
|
|
77
95
|
async handleTestEvent (event, state) {
|
|
@@ -114,10 +132,6 @@ function getWrappedEnvironment (BaseEnvironment) {
|
|
|
114
132
|
if (event.name === 'test_done') {
|
|
115
133
|
const asyncResource = asyncResources.get(event.test)
|
|
116
134
|
asyncResource.runInAsyncScope(() => {
|
|
117
|
-
if (this.global.__coverage__) {
|
|
118
|
-
const coverageFiles = extractCoverageInformation(this.global.__coverage__, this.rootDir)
|
|
119
|
-
testCodeCoverageCh.publish(coverageFiles)
|
|
120
|
-
}
|
|
121
135
|
let status = 'pass'
|
|
122
136
|
if (event.test.errors && event.test.errors.length) {
|
|
123
137
|
status = 'fail'
|
|
@@ -163,11 +177,113 @@ addHook({
|
|
|
163
177
|
versions: ['>=24.8.0']
|
|
164
178
|
}, getTestEnvironment)
|
|
165
179
|
|
|
180
|
+
function cliWrapper (cli) {
|
|
181
|
+
const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
|
|
182
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
183
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
184
|
+
testSessionStartCh.publish(`jest ${processArgv}`)
|
|
185
|
+
})
|
|
186
|
+
return runCLI.apply(this, arguments).then(result => {
|
|
187
|
+
const { results: { success } } = result
|
|
188
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
189
|
+
testSessionFinishCh.publish(success ? 'pass' : 'fail')
|
|
190
|
+
})
|
|
191
|
+
return result
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
cli.runCLI = wrapped.runCLI
|
|
196
|
+
|
|
197
|
+
return cli
|
|
198
|
+
}
|
|
199
|
+
|
|
166
200
|
addHook({
|
|
167
|
-
name: 'jest
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
},
|
|
201
|
+
name: '@jest/core',
|
|
202
|
+
file: 'build/cli/index.js',
|
|
203
|
+
versions: ['>=24.8.0']
|
|
204
|
+
}, cliWrapper)
|
|
205
|
+
|
|
206
|
+
function jestAdapterWrapper (jestAdapter) {
|
|
207
|
+
const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
|
|
208
|
+
const newAdapter = shimmer.wrap(adapter, function () {
|
|
209
|
+
const environment = arguments[2]
|
|
210
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
211
|
+
return asyncResource.runInAsyncScope(() => {
|
|
212
|
+
testSuiteStartCh.publish({
|
|
213
|
+
testSuite: environment.testSuite,
|
|
214
|
+
testEnvironmentOptions: environment.testEnvironmentOptions
|
|
215
|
+
})
|
|
216
|
+
return adapter.apply(this, arguments).then(suiteResults => {
|
|
217
|
+
const { numFailingTests, skipped, failureMessage: errorMessage } = suiteResults
|
|
218
|
+
let status = 'pass'
|
|
219
|
+
if (skipped) {
|
|
220
|
+
status = 'skipped'
|
|
221
|
+
} else if (numFailingTests !== 0) {
|
|
222
|
+
status = 'fail'
|
|
223
|
+
}
|
|
224
|
+
testSuiteFinishCh.publish({ status, errorMessage })
|
|
225
|
+
if (environment.global.__coverage__) {
|
|
226
|
+
const coverageFiles = extractCoverageInformation(environment.global.__coverage__, environment.rootDir)
|
|
227
|
+
if (coverageFiles.length) {
|
|
228
|
+
testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return suiteResults
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
if (jestAdapter.default) {
|
|
236
|
+
jestAdapter.default = newAdapter
|
|
237
|
+
} else {
|
|
238
|
+
jestAdapter = newAdapter
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return jestAdapter
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
addHook({
|
|
245
|
+
name: 'jest-circus',
|
|
246
|
+
file: 'build/legacy-code-todo-rewrite/jestAdapter.js',
|
|
247
|
+
versions: ['>=24.8.0']
|
|
248
|
+
}, jestAdapterWrapper)
|
|
249
|
+
|
|
250
|
+
function configureTestEnvironment (readConfigsResult) {
|
|
251
|
+
const { configs } = readConfigsResult
|
|
252
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
253
|
+
testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function jestConfigAsyncWrapper (jestConfig) {
|
|
258
|
+
shimmer.wrap(jestConfig, 'readConfigs', readConfigs => async function () {
|
|
259
|
+
const readConfigsResult = await readConfigs.apply(this, arguments)
|
|
260
|
+
configureTestEnvironment(readConfigsResult)
|
|
261
|
+
return readConfigsResult
|
|
262
|
+
})
|
|
263
|
+
return jestConfig
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function jestConfigSyncWrapper (jestConfig) {
|
|
267
|
+
shimmer.wrap(jestConfig, 'readConfigs', readConfigs => function () {
|
|
268
|
+
const readConfigsResult = readConfigs.apply(this, arguments)
|
|
269
|
+
configureTestEnvironment(readConfigsResult)
|
|
270
|
+
return readConfigsResult
|
|
271
|
+
})
|
|
272
|
+
return jestConfig
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// from 25.1.0 on, readConfigs becomes async
|
|
276
|
+
addHook({
|
|
277
|
+
name: 'jest-config',
|
|
278
|
+
versions: ['>=25.1.0']
|
|
279
|
+
}, jestConfigAsyncWrapper)
|
|
280
|
+
|
|
281
|
+
addHook({
|
|
282
|
+
name: 'jest-config',
|
|
283
|
+
versions: ['24.8.0 - 24.9.0']
|
|
284
|
+
}, jestConfigSyncWrapper)
|
|
285
|
+
|
|
286
|
+
function jasmineAsyncInstallWraper (jasmineAsyncInstallExport) {
|
|
171
287
|
return function (globalConfig, globalInput) {
|
|
172
288
|
globalInput._ddtrace = global._ddtrace
|
|
173
289
|
shimmer.wrap(globalInput.jasmine.Spec.prototype, 'execute', execute => function (onComplete) {
|
|
@@ -194,4 +310,10 @@ addHook({
|
|
|
194
310
|
})
|
|
195
311
|
return jasmineAsyncInstallExport.default(globalConfig, globalInput)
|
|
196
312
|
}
|
|
197
|
-
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
addHook({
|
|
316
|
+
name: 'jest-jasmine2',
|
|
317
|
+
versions: ['>=24.8.0'],
|
|
318
|
+
file: 'build/jasmineAsyncInstall.js'
|
|
319
|
+
}, jasmineAsyncInstallWraper)
|
|
@@ -19,7 +19,31 @@ const patched = new WeakSet()
|
|
|
19
19
|
|
|
20
20
|
const testToAr = new WeakMap()
|
|
21
21
|
const originalFns = new WeakMap()
|
|
22
|
-
const
|
|
22
|
+
const testFileToSuiteAr = new Map()
|
|
23
|
+
|
|
24
|
+
function getSuitesByTestFile (root) {
|
|
25
|
+
const suitesByTestFile = {}
|
|
26
|
+
function getSuites (suite) {
|
|
27
|
+
if (suite.file) {
|
|
28
|
+
if (suitesByTestFile[suite.file]) {
|
|
29
|
+
suitesByTestFile[suite.file].push(suite)
|
|
30
|
+
} else {
|
|
31
|
+
suitesByTestFile[suite.file] = [suite]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
suite.suites.forEach(suite => {
|
|
35
|
+
getSuites(suite)
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
getSuites(root)
|
|
39
|
+
|
|
40
|
+
const numSuitesByTestFile = Object.keys(suitesByTestFile).reduce((acc, testFile) => {
|
|
41
|
+
acc[testFile] = suitesByTestFile[testFile].length
|
|
42
|
+
return acc
|
|
43
|
+
}, {})
|
|
44
|
+
|
|
45
|
+
return { suitesByTestFile, numSuitesByTestFile }
|
|
46
|
+
}
|
|
23
47
|
|
|
24
48
|
function getTestStatus (test) {
|
|
25
49
|
if (test.pending) {
|
|
@@ -56,6 +80,8 @@ function mochaHook (Runner) {
|
|
|
56
80
|
return run.apply(this, arguments)
|
|
57
81
|
}
|
|
58
82
|
|
|
83
|
+
const { suitesByTestFile, numSuitesByTestFile } = getSuitesByTestFile(this.suite)
|
|
84
|
+
|
|
59
85
|
const testRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
60
86
|
|
|
61
87
|
this.once('end', testRunAsyncResource.bind(function () {
|
|
@@ -65,6 +91,7 @@ function mochaHook (Runner) {
|
|
|
65
91
|
} else if (this.failures !== 0) {
|
|
66
92
|
status = 'fail'
|
|
67
93
|
}
|
|
94
|
+
testFileToSuiteAr.clear()
|
|
68
95
|
testRunFinishCh.publish(status)
|
|
69
96
|
}))
|
|
70
97
|
|
|
@@ -75,34 +102,45 @@ function mochaHook (Runner) {
|
|
|
75
102
|
}))
|
|
76
103
|
|
|
77
104
|
this.on('suite', function (suite) {
|
|
78
|
-
if (suite.root) {
|
|
105
|
+
if (suite.root || !suite.tests.length) {
|
|
79
106
|
return
|
|
80
107
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
108
|
+
let asyncResource = testFileToSuiteAr.get(suite.file)
|
|
109
|
+
if (!asyncResource) {
|
|
110
|
+
asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
111
|
+
testFileToSuiteAr.set(suite.file, asyncResource)
|
|
112
|
+
asyncResource.runInAsyncScope(() => {
|
|
113
|
+
testSuiteStartCh.publish(suite)
|
|
114
|
+
})
|
|
115
|
+
}
|
|
88
116
|
})
|
|
89
117
|
|
|
90
118
|
this.on('suite end', function (suite) {
|
|
91
119
|
if (suite.root) {
|
|
92
120
|
return
|
|
93
121
|
}
|
|
122
|
+
const suitesInTestFile = suitesByTestFile[suite.file]
|
|
123
|
+
|
|
124
|
+
const isLastSuite = --numSuitesByTestFile[suite.file] === 0
|
|
125
|
+
if (!isLastSuite) {
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
94
129
|
let status = 'pass'
|
|
95
|
-
if (suite.pending) {
|
|
130
|
+
if (suitesInTestFile.every(suite => suite.pending)) {
|
|
96
131
|
status = 'skip'
|
|
97
132
|
} else {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
133
|
+
// has to check every test in the test file
|
|
134
|
+
suitesInTestFile.forEach(suite => {
|
|
135
|
+
suite.eachTest(test => {
|
|
136
|
+
if (test.state === 'failed' || test.timedOut) {
|
|
137
|
+
status = 'fail'
|
|
138
|
+
}
|
|
139
|
+
})
|
|
102
140
|
})
|
|
103
141
|
}
|
|
104
142
|
|
|
105
|
-
const asyncResource =
|
|
143
|
+
const asyncResource = testFileToSuiteAr.get(suite.file)
|
|
106
144
|
asyncResource.runInAsyncScope(() => {
|
|
107
145
|
// get suite status
|
|
108
146
|
testSuiteFinishCh.publish(status)
|
|
@@ -125,7 +163,7 @@ function mochaHook (Runner) {
|
|
|
125
163
|
const status = getTestStatus(test)
|
|
126
164
|
|
|
127
165
|
// if there are afterEach to be run, we don't finish the test yet
|
|
128
|
-
if (!test.parent._afterEach.length) {
|
|
166
|
+
if (asyncResource && !test.parent._afterEach.length) {
|
|
129
167
|
asyncResource.runInAsyncScope(() => {
|
|
130
168
|
testFinishCh.publish(status)
|
|
131
169
|
})
|
|
@@ -148,34 +186,38 @@ function mochaHook (Runner) {
|
|
|
148
186
|
})
|
|
149
187
|
|
|
150
188
|
this.on('fail', (testOrHook, err) => {
|
|
189
|
+
const testFile = testOrHook.file
|
|
151
190
|
let test = testOrHook
|
|
152
191
|
const isHook = testOrHook.type === 'hook'
|
|
153
192
|
if (isHook && testOrHook.ctx) {
|
|
154
193
|
test = testOrHook.ctx.currentTest
|
|
155
194
|
}
|
|
156
|
-
let
|
|
195
|
+
let testAsyncResource
|
|
157
196
|
if (test) {
|
|
158
|
-
|
|
197
|
+
testAsyncResource = getTestAsyncResource(test)
|
|
159
198
|
}
|
|
160
|
-
if (
|
|
161
|
-
|
|
199
|
+
if (testAsyncResource) {
|
|
200
|
+
testAsyncResource.runInAsyncScope(() => {
|
|
162
201
|
if (isHook) {
|
|
163
|
-
err.message = `${testOrHook.
|
|
202
|
+
err.message = `${testOrHook.fullTitle()}: ${err.message}`
|
|
164
203
|
errorCh.publish(err)
|
|
165
204
|
// if it's a hook and it has failed, 'test end' will not be called
|
|
166
205
|
testFinishCh.publish('fail')
|
|
167
206
|
} else {
|
|
168
207
|
errorCh.publish(err)
|
|
169
208
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
const testSuiteAsyncResource = testFileToSuiteAr.get(testFile)
|
|
212
|
+
|
|
213
|
+
if (testSuiteAsyncResource) {
|
|
214
|
+
// we propagate the error to the suite
|
|
215
|
+
const testSuiteError = new Error(
|
|
216
|
+
`"${testOrHook.parent.fullTitle()}" failed with message "${err.message}"`
|
|
217
|
+
)
|
|
218
|
+
testSuiteError.stack = err.stack
|
|
219
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
220
|
+
testSuiteErrorCh.publish(testSuiteError)
|
|
179
221
|
})
|
|
180
222
|
}
|
|
181
223
|
})
|
|
@@ -189,7 +231,11 @@ function mochaHook (Runner) {
|
|
|
189
231
|
} else {
|
|
190
232
|
// if there is no async resource, the test has been skipped through `test.skip``
|
|
191
233
|
const skippedTestAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
192
|
-
|
|
234
|
+
if (test.fn) {
|
|
235
|
+
testToAr.set(test.fn, skippedTestAsyncResource)
|
|
236
|
+
} else {
|
|
237
|
+
testToAr.set(test, skippedTestAsyncResource)
|
|
238
|
+
}
|
|
193
239
|
skippedTestAsyncResource.runInAsyncScope(() => {
|
|
194
240
|
skipCh.publish(test)
|
|
195
241
|
})
|
|
@@ -65,21 +65,25 @@ function wrapFindPageComponents (findPageComponents) {
|
|
|
65
65
|
const result = findPageComponents.apply(this, arguments)
|
|
66
66
|
|
|
67
67
|
if (result) {
|
|
68
|
-
pageLoadChannel.publish({ page: pathname })
|
|
68
|
+
pageLoadChannel.publish({ page: getPagePath(pathname) })
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
return result
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
function getPagePath (page) {
|
|
76
|
+
return typeof page === 'object' ? page.pathname : page
|
|
77
|
+
}
|
|
78
|
+
|
|
75
79
|
function getPageFromPath (page, dynamicRoutes = []) {
|
|
76
80
|
for (const dynamicRoute of dynamicRoutes) {
|
|
77
81
|
if (dynamicRoute.page.startsWith('/api') && dynamicRoute.match(page)) {
|
|
78
|
-
return dynamicRoute.page
|
|
82
|
+
return getPagePath(dynamicRoute.page)
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
return page
|
|
86
|
+
return getPagePath(page)
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
function instrument (req, res, handler) {
|