dd-trace 6.7.0 → 6.8.0
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/ci/test-optimization-validation/command-output-policy.js +5 -5
- package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
- package/ci/test-optimization-validation/generated-files.js +9 -9
- package/ci/test-optimization-validation/generated-test-contract.js +1 -3
- package/ci/test-optimization-validation/manifest-scaffold.js +1 -2
- package/ci/test-optimization-validation/offline-output.js +6 -6
- package/ci/test-optimization-validation/runner-command.js +1 -1
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +1 -1
- package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
- package/ci/vitest-no-worker-init-setup.mjs +348 -51
- package/index.d.ts +77 -13
- package/package.json +9 -3
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +4 -4
- package/packages/datadog-instrumentations/src/cucumber.js +9 -6
- package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest.js +8 -14
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +2 -42
- package/packages/datadog-instrumentations/src/mocha/utils.js +68 -2
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +19 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +446 -42
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +3 -2
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +525 -56
- package/packages/datadog-instrumentations/src/vitest-main.js +90 -10
- package/packages/datadog-instrumentations/src/webdriverio.js +914 -0
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +5 -8
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +2 -1
- package/packages/datadog-plugin-jest/src/index.js +2 -3
- package/packages/datadog-plugin-jest/src/util.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +25 -6
- package/packages/datadog-plugin-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +84 -11
- package/packages/datadog-webpack/index.js +2 -2
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/sdk/track_event.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -2
- package/packages/dd-trace/src/config/index.js +15 -0
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/supported-configurations.json +5 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +51 -12
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +218 -0
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +4 -11
- package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
- package/packages/dd-trace/src/llmobs/tagger.js +1 -2
- package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +105 -20
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +7 -6
- package/packages/dd-trace/src/plugins/util/git.js +1 -1
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +38 -12
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/ritm.js +5 -20
- package/packages/dd-trace/src/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { addHook, channel } = require('../helpers/instrument')
|
|
4
4
|
const shimmer = require('../../../datadog-shimmer')
|
|
5
|
+
const { getEnvironmentVariable } = require('../../../dd-trace/src/config/helper')
|
|
6
|
+
const log = require('../../../dd-trace/src/log')
|
|
5
7
|
const { DD_MAJOR } = require('../../../../version')
|
|
6
8
|
|
|
7
9
|
const {
|
|
@@ -14,14 +16,351 @@ const {
|
|
|
14
16
|
getOnTestRetryHandler,
|
|
15
17
|
getRunTestsWrapper,
|
|
16
18
|
patchFailedTestReplayHookUp,
|
|
19
|
+
adjustRunnerFailuresForTestOptimization,
|
|
20
|
+
efdTests,
|
|
21
|
+
getTestFullName,
|
|
17
22
|
} = require('./utils')
|
|
23
|
+
const {
|
|
24
|
+
CONFIGURATION_REQUEST,
|
|
25
|
+
CONFIGURATION_RESPONSE,
|
|
26
|
+
createWebdriverioWorkerMessage,
|
|
27
|
+
SUITE_FINISH,
|
|
28
|
+
WEBDRIVERIO_WORKER_ENV,
|
|
29
|
+
WORKER_READY,
|
|
30
|
+
} = require('./webdriverio-protocol')
|
|
18
31
|
require('./common')
|
|
19
32
|
|
|
20
33
|
const MINIMUM_MOCHA_VERSION = DD_MAJOR >= 6 ? '>=8.0.0' : '>=5.2.0'
|
|
21
34
|
|
|
22
35
|
const workerFinishCh = channel('ci:mocha:worker:finish')
|
|
36
|
+
const workerConfigurationCh = channel('ci:mocha:worker:configuration')
|
|
23
37
|
|
|
24
38
|
const config = {}
|
|
39
|
+
const runnerToFiles = new WeakMap()
|
|
40
|
+
const runnerToFailedHooks = new WeakMap()
|
|
41
|
+
const isWebdriverioWorker = !!getEnvironmentVariable(WEBDRIVERIO_WORKER_ENV)
|
|
42
|
+
let configurationRequestId = 0
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Sends a message to the WebdriverIO launcher without surfacing closed IPC channels.
|
|
46
|
+
*
|
|
47
|
+
* @param {object} message
|
|
48
|
+
* @param {() => void} [onError]
|
|
49
|
+
* @param {() => void} [onDone]
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
function sendWebdriverioMessage (message, onError, onDone) {
|
|
53
|
+
if (!process.send || !process.connected) {
|
|
54
|
+
onError?.()
|
|
55
|
+
onDone?.()
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
process.send(createWebdriverioWorkerMessage(message), (error) => {
|
|
60
|
+
if (error) {
|
|
61
|
+
log.error('WebdriverIO Test Optimization IPC error', error)
|
|
62
|
+
onError?.()
|
|
63
|
+
}
|
|
64
|
+
onDone?.()
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Applies configuration encoded as private Mocha options by its parallel runner.
|
|
70
|
+
*
|
|
71
|
+
* @param {object} options
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
function applyMochaOptions (options) {
|
|
75
|
+
if (options._ddIsKnownTestsEnabled) {
|
|
76
|
+
config.isKnownTestsEnabled = true
|
|
77
|
+
config.isEarlyFlakeDetectionEnabled = options._ddIsEfdEnabled
|
|
78
|
+
config.knownTests = options._ddKnownTests
|
|
79
|
+
config.earlyFlakeDetectionNumRetries = options._ddEfdNumRetries
|
|
80
|
+
config.earlyFlakeDetectionSlowTestRetries = options._ddEfdSlowTestRetries ?? {}
|
|
81
|
+
delete options._ddIsEfdEnabled
|
|
82
|
+
delete options._ddKnownTests
|
|
83
|
+
delete options._ddEfdNumRetries
|
|
84
|
+
delete options._ddEfdSlowTestRetries
|
|
85
|
+
delete options._ddIsKnownTestsEnabled
|
|
86
|
+
}
|
|
87
|
+
if (options._ddIsImpactedTestsEnabled) {
|
|
88
|
+
config.isImpactedTestsEnabled = true
|
|
89
|
+
config.modifiedFiles = options._ddModifiedFiles
|
|
90
|
+
delete options._ddIsImpactedTestsEnabled
|
|
91
|
+
delete options._ddModifiedFiles
|
|
92
|
+
}
|
|
93
|
+
if (options._ddIsTestManagementTestsEnabled) {
|
|
94
|
+
config.isTestManagementTestsEnabled = true
|
|
95
|
+
config.testManagementAttemptToFixRetries = options._ddTestManagementAttemptToFixRetries
|
|
96
|
+
config.testManagementTests = options._ddTestManagementTests
|
|
97
|
+
delete options._ddIsTestManagementTestsEnabled
|
|
98
|
+
delete options._ddTestManagementAttemptToFixRetries
|
|
99
|
+
delete options._ddTestManagementTests
|
|
100
|
+
}
|
|
101
|
+
if (options._ddIsFlakyTestRetriesEnabled) {
|
|
102
|
+
config.isFlakyTestRetriesEnabled = true
|
|
103
|
+
config.flakyTestRetriesCount = options._ddFlakyTestRetriesCount
|
|
104
|
+
delete options._ddIsFlakyTestRetriesEnabled
|
|
105
|
+
delete options._ddFlakyTestRetriesCount
|
|
106
|
+
}
|
|
107
|
+
if (options._ddIsFailedTestReplayEnabled) {
|
|
108
|
+
config.isTestDynamicInstrumentationEnabled = true
|
|
109
|
+
config.isDiEnabled = true
|
|
110
|
+
delete options._ddIsFailedTestReplayEnabled
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Removes files selected for suite-level skipping from an already loaded Mocha root suite.
|
|
116
|
+
*
|
|
117
|
+
* @param {object} runner
|
|
118
|
+
* @param {string[]} skippedFiles
|
|
119
|
+
* @returns {void}
|
|
120
|
+
*/
|
|
121
|
+
function filterSkippedFiles (runner, skippedFiles) {
|
|
122
|
+
if (!skippedFiles.length) {
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const skippedFilesSet = new Set(skippedFiles)
|
|
127
|
+
runner.suite.suites = runner.suite.suites.filter(suite => !skippedFilesSet.has(suite.file))
|
|
128
|
+
runner.suite.tests = runner.suite.tests.filter(test => !skippedFilesSet.has(test.file))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Requests configuration from the WebdriverIO launcher before releasing Mocha's delayed root suite.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} frameworkVersion
|
|
135
|
+
* @param {string[]} files
|
|
136
|
+
* @param {(response: object) => void} onDone
|
|
137
|
+
* @returns {void}
|
|
138
|
+
*/
|
|
139
|
+
function requestWebdriverioConfiguration (frameworkVersion, files, onDone) {
|
|
140
|
+
const requestId = `${process.pid}-${++configurationRequestId}`
|
|
141
|
+
let finished = false
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Finishes the configuration request exactly once.
|
|
145
|
+
*
|
|
146
|
+
* @param {object} response
|
|
147
|
+
* @returns {void}
|
|
148
|
+
*/
|
|
149
|
+
function finish (response) {
|
|
150
|
+
if (finished) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
finished = true
|
|
154
|
+
clearTimeout(timeout)
|
|
155
|
+
process.off('message', onMessage)
|
|
156
|
+
process.off('disconnect', onDisconnect)
|
|
157
|
+
onDone(response)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Receives the matching coordinator response.
|
|
162
|
+
*
|
|
163
|
+
* @param {object} message
|
|
164
|
+
* @returns {void}
|
|
165
|
+
*/
|
|
166
|
+
function onMessage (message) {
|
|
167
|
+
if (message?.name === CONFIGURATION_RESPONSE && message.content?.requestId === requestId) {
|
|
168
|
+
finish(message.content)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Releases the runner if its parent disconnects.
|
|
174
|
+
*
|
|
175
|
+
* @returns {void}
|
|
176
|
+
*/
|
|
177
|
+
function onDisconnect () {
|
|
178
|
+
finish({})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const timeout = setTimeout(() => finish({}), 30_000)
|
|
182
|
+
process.on('message', onMessage)
|
|
183
|
+
process.once('disconnect', onDisconnect)
|
|
184
|
+
sendWebdriverioMessage({
|
|
185
|
+
origin: 'datadog',
|
|
186
|
+
name: CONFIGURATION_REQUEST,
|
|
187
|
+
content: {
|
|
188
|
+
files,
|
|
189
|
+
frameworkVersion,
|
|
190
|
+
requestId,
|
|
191
|
+
},
|
|
192
|
+
}, () => finish({}))
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Reports the Mocha version as soon as WebdriverIO loads its framework adapter.
|
|
197
|
+
*
|
|
198
|
+
* @param {string} frameworkVersion
|
|
199
|
+
* @returns {void}
|
|
200
|
+
*/
|
|
201
|
+
function reportWebdriverioWorkerReady (frameworkVersion) {
|
|
202
|
+
if (!isWebdriverioWorker) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
sendWebdriverioMessage({
|
|
207
|
+
origin: 'datadog',
|
|
208
|
+
name: WORKER_READY,
|
|
209
|
+
content: { frameworkVersion },
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Checks whether Test Optimization converts a failed WebdriverIO test attempt to a passing result.
|
|
215
|
+
*
|
|
216
|
+
* @param {object|undefined} test
|
|
217
|
+
* @returns {boolean}
|
|
218
|
+
*/
|
|
219
|
+
function isWebdriverioFailureSuppressed (test) {
|
|
220
|
+
if (!test) {
|
|
221
|
+
return false
|
|
222
|
+
}
|
|
223
|
+
const hasPassingEfdAttempt = config.isEarlyFlakeDetectionEnabled &&
|
|
224
|
+
efdTests[getTestFullName(test)]?.some(attempt => attempt.state === 'passed' && !attempt._ddHookFailed)
|
|
225
|
+
return (test._ddIsQuarantined && !test._ddIsAttemptToFix) || hasPassingEfdAttempt
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Gets the test owned by a per-test hook without associating suite hooks with boundary tests.
|
|
230
|
+
*
|
|
231
|
+
* @param {object} hook
|
|
232
|
+
* @returns {object|undefined}
|
|
233
|
+
*/
|
|
234
|
+
function getWebdriverioHookTest (hook) {
|
|
235
|
+
const { parent } = hook
|
|
236
|
+
const isTestHook = parent?._beforeEach?.includes(hook) || parent?._afterEach?.includes(hook)
|
|
237
|
+
return isTestHook ? hook.ctx?.currentTest : undefined
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Removes managed hook failures from WebdriverIO's Mocha runner totals.
|
|
242
|
+
*
|
|
243
|
+
* @param {object} runner
|
|
244
|
+
* @returns {void}
|
|
245
|
+
*/
|
|
246
|
+
function adjustWebdriverioHookFailures (runner) {
|
|
247
|
+
let suppressedFailures = 0
|
|
248
|
+
for (const { test } of runnerToFailedHooks.get(runner) || []) {
|
|
249
|
+
if (isWebdriverioFailureSuppressed(test)) {
|
|
250
|
+
suppressedFailures++
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (runner.stats) {
|
|
254
|
+
runner.stats.failures -= suppressedFailures
|
|
255
|
+
}
|
|
256
|
+
runner.failures -= suppressedFailures
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Computes a final result for every file loaded into one Mocha worker.
|
|
261
|
+
*
|
|
262
|
+
* @param {object} runner
|
|
263
|
+
* @returns {object[]}
|
|
264
|
+
*/
|
|
265
|
+
function getWebdriverioSuiteResults (runner) {
|
|
266
|
+
const resultsByFile = new Map()
|
|
267
|
+
const files = runnerToFiles.get(runner) || []
|
|
268
|
+
|
|
269
|
+
for (const file of files) {
|
|
270
|
+
resultsByFile.set(file, {
|
|
271
|
+
file,
|
|
272
|
+
hasPassingTest: false,
|
|
273
|
+
status: 'skip',
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
runner.suite.eachTest(test => {
|
|
278
|
+
const result = resultsByFile.get(test.file)
|
|
279
|
+
if (!result) {
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
const isSuppressedFailure = isWebdriverioFailureSuppressed(test)
|
|
283
|
+
if ((test.state === 'failed' || test.timedOut || test._ddHookFailed) && !isSuppressedFailure) {
|
|
284
|
+
result.status = 'fail'
|
|
285
|
+
} else if (test.state === 'passed' || isSuppressedFailure) {
|
|
286
|
+
result.hasPassingTest = true
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
for (const { file, test } of runnerToFailedHooks.get(runner) || []) {
|
|
291
|
+
const result = resultsByFile.get(file)
|
|
292
|
+
if (result && !isWebdriverioFailureSuppressed(test)) {
|
|
293
|
+
result.status = 'fail'
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const results = []
|
|
298
|
+
let hasFailedSuite = false
|
|
299
|
+
for (const result of resultsByFile.values()) {
|
|
300
|
+
if (result.status === 'fail') {
|
|
301
|
+
hasFailedSuite = true
|
|
302
|
+
} else if (result.hasPassingTest) {
|
|
303
|
+
result.status = 'pass'
|
|
304
|
+
}
|
|
305
|
+
delete result.hasPassingTest
|
|
306
|
+
results.push(result)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (runner.failures > 0 && !hasFailedSuite) {
|
|
310
|
+
for (const result of results) {
|
|
311
|
+
result.status = 'fail'
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return results
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Sends suite results to the WebdriverIO launcher.
|
|
320
|
+
*
|
|
321
|
+
* @param {object} runner
|
|
322
|
+
* @param {() => void} [onDone]
|
|
323
|
+
* @returns {void}
|
|
324
|
+
*/
|
|
325
|
+
function reportWebdriverioSuiteResults (runner, onDone) {
|
|
326
|
+
if (!isWebdriverioWorker) {
|
|
327
|
+
onDone?.()
|
|
328
|
+
return
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
sendWebdriverioMessage({
|
|
332
|
+
origin: 'datadog',
|
|
333
|
+
name: SUITE_FINISH,
|
|
334
|
+
content: {
|
|
335
|
+
results: getWebdriverioSuiteResults(runner),
|
|
336
|
+
},
|
|
337
|
+
}, undefined, onDone)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Flushes worker payloads before reporting suite results and completing Mocha.
|
|
342
|
+
*
|
|
343
|
+
* @param {object} runner
|
|
344
|
+
* @param {() => void} onDone
|
|
345
|
+
* @returns {void}
|
|
346
|
+
*/
|
|
347
|
+
function finishWebdriverioWorker (runner, onDone) {
|
|
348
|
+
try {
|
|
349
|
+
workerFinishCh.publish({
|
|
350
|
+
onDone: () => {
|
|
351
|
+
try {
|
|
352
|
+
reportWebdriverioSuiteResults(runner, onDone)
|
|
353
|
+
} catch (error) {
|
|
354
|
+
log.error('WebdriverIO Test Optimization worker completion error', error)
|
|
355
|
+
onDone()
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
})
|
|
359
|
+
} catch (error) {
|
|
360
|
+
log.error('WebdriverIO Test Optimization worker completion error', error)
|
|
361
|
+
onDone()
|
|
362
|
+
}
|
|
363
|
+
}
|
|
25
364
|
|
|
26
365
|
function isFailedTestReplayEnabled () {
|
|
27
366
|
return config.isTestDynamicInstrumentationEnabled && config.isDiEnabled
|
|
@@ -31,46 +370,77 @@ addHook({
|
|
|
31
370
|
name: 'mocha',
|
|
32
371
|
versions: ['>=8.0.0'],
|
|
33
372
|
file: 'lib/mocha.js',
|
|
34
|
-
}, (Mocha) => {
|
|
373
|
+
}, (Mocha, frameworkVersion) => {
|
|
374
|
+
reportWebdriverioWorkerReady(frameworkVersion)
|
|
375
|
+
|
|
35
376
|
shimmer.wrap(Mocha.prototype, 'run', run => function (...args) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
config.knownTests = this.options._ddKnownTests
|
|
40
|
-
config.earlyFlakeDetectionNumRetries = this.options._ddEfdNumRetries
|
|
41
|
-
config.earlyFlakeDetectionSlowTestRetries = this.options._ddEfdSlowTestRetries ?? {}
|
|
42
|
-
delete this.options._ddIsEfdEnabled
|
|
43
|
-
delete this.options._ddKnownTests
|
|
44
|
-
delete this.options._ddEfdNumRetries
|
|
45
|
-
delete this.options._ddEfdSlowTestRetries
|
|
46
|
-
delete this.options._ddIsKnownTestsEnabled
|
|
47
|
-
}
|
|
48
|
-
if (this.options._ddIsImpactedTestsEnabled) {
|
|
49
|
-
config.isImpactedTestsEnabled = true
|
|
50
|
-
config.modifiedFiles = this.options._ddModifiedFiles
|
|
51
|
-
delete this.options._ddIsImpactedTestsEnabled
|
|
52
|
-
delete this.options._ddModifiedFiles
|
|
53
|
-
}
|
|
54
|
-
if (this.options._ddIsTestManagementTestsEnabled) {
|
|
55
|
-
config.isTestManagementTestsEnabled = true
|
|
56
|
-
config.testManagementAttemptToFixRetries = this.options._ddTestManagementAttemptToFixRetries
|
|
57
|
-
config.testManagementTests = this.options._ddTestManagementTests
|
|
58
|
-
delete this.options._ddIsTestManagementTestsEnabled
|
|
59
|
-
delete this.options._ddTestManagementAttemptToFixRetries
|
|
60
|
-
delete this.options._ddTestManagementTests
|
|
61
|
-
}
|
|
62
|
-
if (this.options._ddIsFlakyTestRetriesEnabled) {
|
|
63
|
-
config.isFlakyTestRetriesEnabled = true
|
|
64
|
-
config.flakyTestRetriesCount = this.options._ddFlakyTestRetriesCount
|
|
65
|
-
delete this.options._ddIsFlakyTestRetriesEnabled
|
|
66
|
-
delete this.options._ddFlakyTestRetriesCount
|
|
67
|
-
}
|
|
68
|
-
if (this.options._ddIsFailedTestReplayEnabled) {
|
|
69
|
-
config.isTestDynamicInstrumentationEnabled = true
|
|
70
|
-
config.isDiEnabled = true
|
|
71
|
-
delete this.options._ddIsFailedTestReplayEnabled
|
|
377
|
+
applyMochaOptions(this.options)
|
|
378
|
+
if (!isWebdriverioWorker || !workerFinishCh.hasSubscribers) {
|
|
379
|
+
return run.apply(this, args)
|
|
72
380
|
}
|
|
73
|
-
|
|
381
|
+
|
|
382
|
+
const isUserDelayed = this.options.delay
|
|
383
|
+
const rootSuite = this.suite
|
|
384
|
+
const rootSuiteRun = rootSuite.run
|
|
385
|
+
const hasOwnRootSuiteRun = Object.hasOwn(rootSuite, 'run')
|
|
386
|
+
let configurationReady = false
|
|
387
|
+
let userReady = !isUserDelayed
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Restores the root suite method after both delayed-mode gates are open.
|
|
391
|
+
*
|
|
392
|
+
* @returns {void}
|
|
393
|
+
*/
|
|
394
|
+
function restoreRootSuiteRun () {
|
|
395
|
+
if (hasOwnRootSuiteRun) {
|
|
396
|
+
rootSuite.run = rootSuiteRun
|
|
397
|
+
} else {
|
|
398
|
+
delete rootSuite.run
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (isUserDelayed) {
|
|
403
|
+
rootSuite.run = function (...args) {
|
|
404
|
+
userReady = true
|
|
405
|
+
if (!configurationReady) {
|
|
406
|
+
return
|
|
407
|
+
}
|
|
408
|
+
restoreRootSuiteRun()
|
|
409
|
+
return rootSuiteRun.apply(this, args)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
this.options.delay = true
|
|
414
|
+
const files = [...this.files]
|
|
415
|
+
const runner = run.apply(this, args)
|
|
416
|
+
runnerToFiles.set(runner, files)
|
|
417
|
+
|
|
418
|
+
requestWebdriverioConfiguration(frameworkVersion, files, ({
|
|
419
|
+
configuration,
|
|
420
|
+
skippedFiles = [],
|
|
421
|
+
}) => {
|
|
422
|
+
if (configuration) {
|
|
423
|
+
Object.assign(config, configuration)
|
|
424
|
+
workerConfigurationCh.publish({
|
|
425
|
+
libraryConfig: config,
|
|
426
|
+
repositoryRoot: config.repositoryRoot,
|
|
427
|
+
testFramework: config.testFramework,
|
|
428
|
+
})
|
|
429
|
+
}
|
|
430
|
+
filterSkippedFiles(runner, skippedFiles)
|
|
431
|
+
if (isFailedTestReplayEnabled()) {
|
|
432
|
+
patchFailedTestReplayHookUp(runner.constructor)
|
|
433
|
+
}
|
|
434
|
+
configurationReady = true
|
|
435
|
+
if (userReady) {
|
|
436
|
+
if (isUserDelayed) {
|
|
437
|
+
restoreRootSuiteRun()
|
|
438
|
+
}
|
|
439
|
+
rootSuite.run()
|
|
440
|
+
}
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
return runner
|
|
74
444
|
})
|
|
75
445
|
|
|
76
446
|
return Mocha
|
|
@@ -91,10 +461,32 @@ addHook({
|
|
|
91
461
|
if (isFailedTestReplayEnabled()) {
|
|
92
462
|
patchFailedTestReplayHookUp(Runner)
|
|
93
463
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
464
|
+
if (isWebdriverioWorker) {
|
|
465
|
+
this.prependOnceListener('end', () => {
|
|
466
|
+
try {
|
|
467
|
+
adjustRunnerFailuresForTestOptimization(this, config)
|
|
468
|
+
adjustWebdriverioHookFailures(this)
|
|
469
|
+
} catch (error) {
|
|
470
|
+
log.error('WebdriverIO Test Optimization failure adjustment error', error)
|
|
471
|
+
}
|
|
472
|
+
})
|
|
473
|
+
}
|
|
474
|
+
const onRunDone = args[0]
|
|
475
|
+
if (isWebdriverioWorker && typeof onRunDone === 'function') {
|
|
476
|
+
args[0] = (...onRunDoneArgs) => {
|
|
477
|
+
finishWebdriverioWorker(this, () => onRunDone(...onRunDoneArgs))
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
// Flush after the worker finishes its Mocha run, including grouped spec files.
|
|
481
|
+
this.once('end', () => {
|
|
482
|
+
try {
|
|
483
|
+
workerFinishCh.publish()
|
|
484
|
+
reportWebdriverioSuiteResults(this)
|
|
485
|
+
} catch (error) {
|
|
486
|
+
log.error('WebdriverIO Test Optimization worker completion error', error)
|
|
487
|
+
}
|
|
488
|
+
})
|
|
489
|
+
}
|
|
98
490
|
this.on('test', getOnTestHandler(false))
|
|
99
491
|
|
|
100
492
|
this.on('test end', getOnTestEndHandler(config))
|
|
@@ -104,6 +496,18 @@ addHook({
|
|
|
104
496
|
// If the hook passes, 'hook end' will be emitted. Otherwise, 'fail' will be emitted
|
|
105
497
|
this.on('hook end', getOnHookEndHandler(config))
|
|
106
498
|
|
|
499
|
+
if (isWebdriverioWorker) {
|
|
500
|
+
const failedHooks = []
|
|
501
|
+
runnerToFailedHooks.set(this, failedHooks)
|
|
502
|
+
this.on('fail', runnable => {
|
|
503
|
+
if (runnable.type === 'hook' && runnable.file) {
|
|
504
|
+
failedHooks.push({
|
|
505
|
+
file: runnable.file,
|
|
506
|
+
test: getWebdriverioHookTest(runnable),
|
|
507
|
+
})
|
|
508
|
+
}
|
|
509
|
+
})
|
|
510
|
+
}
|
|
107
511
|
this.on('fail', getOnFailHandler(false, config))
|
|
108
512
|
|
|
109
513
|
this.on('pending', getOnPendingHandler())
|
|
@@ -10,7 +10,7 @@ const errorChannel = channel('apm:moleculer:call:error')
|
|
|
10
10
|
function wrapCall (call) {
|
|
11
11
|
return function (actionName, params, opts) {
|
|
12
12
|
opts = arguments[2] = opts || {}
|
|
13
|
-
opts.meta
|
|
13
|
+
opts.meta ||= {}
|
|
14
14
|
|
|
15
15
|
arguments.length = Math.max(3, arguments.length)
|
|
16
16
|
|
|
@@ -1350,7 +1350,7 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1350
1350
|
let totalFailedTestCount = 0
|
|
1351
1351
|
let totalPureQuarantinedFailedTestCount = 0
|
|
1352
1352
|
|
|
1353
|
-
for (const [fqn, testStatuses] of testsToTestStatuses
|
|
1353
|
+
for (const [fqn, testStatuses] of testsToTestStatuses) {
|
|
1354
1354
|
// Only count as failed if the final status (after retries) is 'fail'
|
|
1355
1355
|
const lastStatus = testStatuses.at(-1)
|
|
1356
1356
|
if (lastStatus === 'fail') {
|
|
@@ -1494,7 +1494,8 @@ createRootSuiteCh.subscribe({
|
|
|
1494
1494
|
pageGotoCh.subscribe({
|
|
1495
1495
|
asyncEnd (ctx) {
|
|
1496
1496
|
// The Page.goto rewriter waits for this so tests closing immediately after navigation still get RUM tags.
|
|
1497
|
-
|
|
1497
|
+
const rumDetectionPromise = handlePageGoto(ctx.self)
|
|
1498
|
+
ctx.resolveCallback = onDone => rumDetectionPromise.then(onDone, onDone)
|
|
1498
1499
|
},
|
|
1499
1500
|
})
|
|
1500
1501
|
|
|
@@ -222,7 +222,7 @@ function beforeFinish (delivery, state) {
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
function getStateFromData (stateData) {
|
|
225
|
-
if (stateData
|
|
225
|
+
if (stateData?.descriptor) {
|
|
226
226
|
switch (stateData.descriptor.value) {
|
|
227
227
|
case 0x24: return 'accepted'
|
|
228
228
|
case 0x25: return 'rejected'
|