dd-trace 6.20.1 → 6.22.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/diagnose.js +9 -14
- package/ci/init.js +1 -2
- package/ci/test-optimization-validation/ci-discovery.js +9 -4
- package/ci/test-optimization-validation/executable.js +1 -5
- package/ci/test-optimization-validation/framework-adapters/cypress.js +1 -4
- package/ci/test-optimization-validation/framework-adapters/vitest.js +1 -1
- package/ci/test-optimization-validation/generated-files.js +6 -4
- package/ci/test-optimization-validation/generated-test-contract.js +7 -3
- package/ci/test-optimization-validation/manifest-scaffold.js +7 -2
- package/ci/test-optimization-validation/manifest-schema.js +6 -7
- package/ci/test-optimization-validation/report-writer.js +6 -2
- package/ci/test-optimization-validation/runner-command.js +2 -4
- package/ci/test-optimization-validation/runner-contract.js +1 -2
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +1 -15
- package/ci/vitest-no-worker-init-setup.mjs +10 -7
- package/index.d.ts +116 -17
- package/initialize.mjs +1 -3
- package/openfeature/rules-based.d.ts +11 -0
- package/openfeature/rules-based.js +7 -0
- package/package.json +13 -11
- package/packages/datadog-core/src/storage.js +16 -0
- package/packages/datadog-esbuild/index.js +18 -12
- package/packages/datadog-instrumentations/src/aerospike.js +3 -3
- package/packages/datadog-instrumentations/src/ai.js +3 -3
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -6
- package/packages/datadog-instrumentations/src/aws-sdk.js +21 -13
- package/packages/datadog-instrumentations/src/cassandra-driver.js +25 -20
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +9 -23
- package/packages/datadog-instrumentations/src/cucumber.js +48 -33
- package/packages/datadog-instrumentations/src/elasticsearch.js +1 -5
- package/packages/datadog-instrumentations/src/electron.js +6 -6
- package/packages/datadog-instrumentations/src/fastify.js +13 -4
- package/packages/datadog-instrumentations/src/fs.js +2 -2
- package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +9 -5
- package/packages/datadog-instrumentations/src/grpc/client.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +36 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +87 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +5 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +48 -31
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +64 -11
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +42 -4
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +7 -10
- package/packages/datadog-instrumentations/src/ioredis.js +7 -5
- package/packages/datadog-instrumentations/src/iovalkey.js +7 -5
- package/packages/datadog-instrumentations/src/jest.js +122 -11
- package/packages/datadog-instrumentations/src/knex.js +9 -5
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +3 -3
- package/packages/datadog-instrumentations/src/mocha/common.js +20 -8
- package/packages/datadog-instrumentations/src/mocha/main.js +140 -43
- package/packages/datadog-instrumentations/src/mocha/utils.js +127 -38
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +61 -34
- package/packages/datadog-instrumentations/src/mocha/worker.js +7 -5
- package/packages/datadog-instrumentations/src/mongodb-core.js +3 -3
- package/packages/datadog-instrumentations/src/mongoose.js +3 -3
- package/packages/datadog-instrumentations/src/nova-sonic/audio.js +173 -0
- package/packages/datadog-instrumentations/src/nova-sonic/index.js +209 -0
- package/packages/datadog-instrumentations/src/nova-sonic/session.js +483 -0
- package/packages/datadog-instrumentations/src/openai-realtime/index.js +18 -6
- package/packages/datadog-instrumentations/src/openai-realtime/session.js +1 -1
- package/packages/datadog-instrumentations/src/openai.js +7 -0
- package/packages/datadog-instrumentations/src/pino.js +5 -6
- package/packages/datadog-instrumentations/src/playwright.js +3 -0
- package/packages/datadog-instrumentations/src/redis.js +27 -13
- package/packages/datadog-instrumentations/src/router.js +30 -0
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +2 -6
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +7 -5
- package/packages/datadog-instrumentations/src/vitest-main.js +9 -17
- package/packages/datadog-instrumentations/src/vitest-util.js +2 -2
- package/packages/datadog-instrumentations/src/vitest-worker.js +1 -2
- package/packages/datadog-instrumentations/src/vitest.js +2 -2
- package/packages/datadog-instrumentations/src/webdriverio.js +118 -21
- package/packages/datadog-instrumentations/src/ws.js +1 -4
- package/packages/datadog-plugin-amqplib/src/client.js +1 -2
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -5
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +5 -8
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +18 -0
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/sonic.js +45 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -5
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +5 -4
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -3
- package/packages/datadog-plugin-claude-agent-sdk/src/index.js +0 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +18 -5
- package/packages/datadog-plugin-cypress/src/index.js +6 -6
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -2
- package/packages/datadog-plugin-cypress/src/support.js +1 -4
- package/packages/datadog-plugin-express/src/code_origin.js +1 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
- package/packages/datadog-plugin-graphql/src/execute.js +5 -5
- package/packages/datadog-plugin-grpc/src/util.js +1 -2
- package/packages/datadog-plugin-kafkajs/src/producer.js +1 -2
- package/packages/datadog-plugin-mocha/src/index.js +223 -39
- package/packages/datadog-plugin-mocha/src/webdriverio-video.js +453 -0
- package/packages/datadog-plugin-mongodb-core/src/query.js +8 -5
- package/packages/datadog-plugin-next/src/index.js +1 -2
- package/packages/datadog-plugin-openai/src/tracing.js +5 -2
- package/packages/datadog-plugin-openai-agents/src/integration.js +6 -2
- package/packages/datadog-plugin-openai-agents/src/processor.js +2 -4
- package/packages/datadog-plugin-postgres/src/index.js +24 -0
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -5
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -4
- package/packages/datadog-plugin-vitest/src/index.js +5 -2
- package/packages/datadog-shimmer/src/shimmer.js +5 -4
- package/packages/datadog-webpack/index.js +55 -43
- package/packages/datadog-webpack/src/loader.js +56 -8
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -4
- package/packages/dd-trace/src/aiguard/messages/utils.js +1 -2
- package/packages/dd-trace/src/aiguard/redaction.js +8 -2
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +3 -2
- package/packages/dd-trace/src/appsec/api_security/sampler.js +2 -6
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -9
- package/packages/dd-trace/src/appsec/handlers/http-request.js +3 -9
- package/packages/dd-trace/src/appsec/handlers/http-response.js +7 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +4 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +1 -4
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +7 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -3
- package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +1 -6
- package/packages/dd-trace/src/appsec/lambda.js +1 -3
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +37 -27
- package/packages/dd-trace/src/appsec/rasp/lfi.js +9 -5
- package/packages/dd-trace/src/appsec/reporter.js +21 -1
- package/packages/dd-trace/src/appsec/stack_trace.js +1 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +3 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +13 -7
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +1 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +2 -8
- package/packages/dd-trace/src/ci-visibility/resolve-runfile-path.js +54 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +5 -8
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +2 -53
- package/packages/dd-trace/src/config/config-types.d.ts +2 -2
- package/packages/dd-trace/src/config/defaults.js +5 -5
- package/packages/dd-trace/src/config/generated-config-types.d.ts +8 -0
- package/packages/dd-trace/src/config/helper.js +34 -3
- package/packages/dd-trace/src/config/index.js +10 -9
- package/packages/dd-trace/src/config/normalize-service.js +1 -1
- package/packages/dd-trace/src/config/parsers.js +2 -2
- package/packages/dd-trace/src/config/supported-configurations.json +35 -0
- package/packages/dd-trace/src/datastreams/processor.js +3 -2
- package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -4
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +5 -3
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +17 -12
- package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/worker-error.js +21 -0
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +2 -2
- package/packages/dd-trace/src/debugger/index.js +24 -2
- package/packages/dd-trace/src/debugger/probe_sampler.js +108 -11
- package/packages/dd-trace/src/dogstatsd.js +1 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/request.js +2 -5
- package/packages/dd-trace/src/exporters/common/url.js +1 -1
- package/packages/dd-trace/src/id.js +15 -5
- package/packages/dd-trace/src/lambda/handler.js +179 -19
- package/packages/dd-trace/src/lambda/index.js +15 -1
- package/packages/dd-trace/src/lambda/runtime/patch.js +34 -7
- package/packages/dd-trace/src/llmobs/agent-manifest.js +296 -0
- package/packages/dd-trace/src/llmobs/audio-utils.js +3 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +13 -0
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +15 -0
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +1 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +1 -3
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/nova-sonic.js +92 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +56 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +38 -0
- package/packages/dd-trace/src/llmobs/prompts/manager.js +5 -7
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +23 -6
- package/packages/dd-trace/src/llmobs/span_processor.js +18 -8
- package/packages/dd-trace/src/llmobs/tagger.js +56 -3
- package/packages/dd-trace/src/llmobs/util.js +1 -2
- package/packages/dd-trace/src/llmobs/writers/base.js +7 -6
- package/packages/dd-trace/src/llmobs/writers/util.js +3 -1
- package/packages/dd-trace/src/log/log.js +1 -5
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +30 -1
- package/packages/dd-trace/src/openfeature/configuration_source.js +17 -2
- package/packages/dd-trace/src/openfeature/debug-logging-hook.js +25 -0
- package/packages/dd-trace/src/openfeature/evaluation-telemetry-opt-out-hook.js +51 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +59 -3
- package/packages/dd-trace/src/openfeature/remote_config.js +9 -0
- package/packages/dd-trace/src/openfeature/writers/util.js +43 -4
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -2
- package/packages/dd-trace/src/opentelemetry/otlp/common.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/resource-attributes.js +1 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +6 -23
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +53 -13
- package/packages/dd-trace/src/otel-sampling.js +4 -5
- package/packages/dd-trace/src/otel-thread-ctx.js +81 -15
- package/packages/dd-trace/src/plugins/database.js +7 -16
- package/packages/dd-trace/src/plugins/util/git.js +9 -25
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -5
- package/packages/dd-trace/src/plugins/util/test.js +48 -4
- package/packages/dd-trace/src/priority_sampler.js +1 -2
- package/packages/dd-trace/src/profiling/profiler.js +4 -6
- package/packages/dd-trace/src/profiling/profilers/wall.js +4 -10
- package/packages/dd-trace/src/proxy.js +3 -2
- package/packages/dd-trace/src/ritm.js +4 -2
- package/packages/dd-trace/src/serverless.js +10 -0
- package/packages/dd-trace/src/span_processor.js +13 -17
- package/packages/dd-trace/src/storage-channels.js +112 -46
- package/packages/dd-trace/src/telemetry/endpoints.js +1 -3
- package/packages/dd-trace/src/util.js +29 -0
- package/packages/dd-trace/src/web-tags-cache.js +6 -2
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/vendor/dist/@datadog/openfeature-node-server/rules-based/LICENSE +201 -0
- package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.d.ts +925 -0
- package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.js +1 -0
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
|
@@ -25,7 +25,7 @@ function wrapAddCommand (addCommand) {
|
|
|
25
25
|
return startCh.runStores(ctx, () => {
|
|
26
26
|
const res = addCommand.apply(this, arguments)
|
|
27
27
|
|
|
28
|
-
res.then(() => finish(
|
|
28
|
+
res.then(() => finish(ctx), err => finish(ctx, err))
|
|
29
29
|
|
|
30
30
|
return res
|
|
31
31
|
})
|
|
@@ -85,13 +85,11 @@ addHook({ name: '@redis/client', file: 'dist/lib/client/commands-queue.js', vers
|
|
|
85
85
|
|
|
86
86
|
addHook({ name: 'redis', versions: ['>=2.6 <4'] }, redis => {
|
|
87
87
|
shimmer.wrap(redis.RedisClient.prototype, 'internal_send_command', internalSendCommand => function (options) {
|
|
88
|
-
if (!startCh.hasSubscribers) return internalSendCommand.apply(this, arguments)
|
|
89
|
-
|
|
90
|
-
if (!options.callback) return internalSendCommand.apply(this, arguments)
|
|
88
|
+
if (!startCh.hasSubscribers || !options.callback) return internalSendCommand.apply(this, arguments)
|
|
91
89
|
|
|
92
90
|
const ctx = getStartCtx(this, options.command, options.args)
|
|
93
91
|
return startCh.runStores(ctx, () => {
|
|
94
|
-
options.callback = wrapCallback(
|
|
92
|
+
options.callback = wrapCallback(ctx, options.callback)
|
|
95
93
|
|
|
96
94
|
try {
|
|
97
95
|
return internalSendCommand.apply(this, arguments)
|
|
@@ -114,11 +112,11 @@ addHook({ name: 'redis', versions: ['>=0.12 <2.6'] }, redis => {
|
|
|
114
112
|
const ctx = getStartCtx(this, command, args)
|
|
115
113
|
return startCh.runStores(ctx, () => {
|
|
116
114
|
if (typeof callback === 'function') {
|
|
117
|
-
arguments[2] = wrapCallback(
|
|
115
|
+
arguments[2] = wrapCallback(ctx, callback)
|
|
118
116
|
} else if (Array.isArray(args) && typeof args.at(-1) === 'function') {
|
|
119
|
-
args[args.length - 1] = wrapCallback(
|
|
117
|
+
args[args.length - 1] = wrapCallback(ctx, args.at(-1))
|
|
120
118
|
} else {
|
|
121
|
-
arguments[2] = wrapCallback(
|
|
119
|
+
arguments[2] = wrapCallback(ctx)
|
|
122
120
|
}
|
|
123
121
|
|
|
124
122
|
try {
|
|
@@ -155,20 +153,36 @@ function getStartCtx (client, command, args, argsStartIndex) {
|
|
|
155
153
|
}
|
|
156
154
|
}
|
|
157
155
|
|
|
158
|
-
|
|
156
|
+
/**
|
|
157
|
+
* @param {Record<string, unknown> & { error?: Error }} ctx
|
|
158
|
+
* @param {Function} [callback]
|
|
159
|
+
*/
|
|
160
|
+
function wrapCallback (ctx, callback) {
|
|
159
161
|
if (typeof callback !== 'function') return callback
|
|
160
162
|
return function (err) {
|
|
161
|
-
return finish(
|
|
163
|
+
return finish(ctx, err, callback, this, arguments)
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
|
|
167
|
+
/**
|
|
168
|
+
* @param {Record<string, unknown> & { error?: Error }} ctx
|
|
169
|
+
* @param {Error} [error]
|
|
170
|
+
* @param {Function} [callback]
|
|
171
|
+
* @param {object} [thisArg]
|
|
172
|
+
* @param {Iterable<unknown>} [args]
|
|
173
|
+
*/
|
|
174
|
+
function finish (ctx, error, callback, thisArg, args) {
|
|
166
175
|
if (error) {
|
|
167
176
|
ctx.error = error
|
|
168
177
|
errorCh.publish(ctx)
|
|
169
178
|
}
|
|
170
179
|
if (callback) {
|
|
171
|
-
return finishCh.runStores(
|
|
180
|
+
return finishCh.runStores(
|
|
181
|
+
ctx,
|
|
182
|
+
/** @type {Parameters<typeof finishCh.runStores>[1]} */ (callback),
|
|
183
|
+
thisArg,
|
|
184
|
+
...(/** @type {Iterable<unknown>} */ (args))
|
|
185
|
+
)
|
|
172
186
|
}
|
|
173
|
-
finishCh.publish(ctx)
|
|
187
|
+
return finishCh.publish(ctx)
|
|
174
188
|
}
|
|
@@ -91,6 +91,28 @@ function resolveLayerRouteOrForwardError (meta, layer, next) {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
// Wrapped `next` -> the host continuation it calls.
|
|
95
|
+
const hostNexts = new WeakMap()
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Routers store their continuation on `req.next` once per `handle()`, and host
|
|
99
|
+
* APIs call it directly (express `res.format`, `res.sendFile` and `res.render`
|
|
100
|
+
* errors). Point it at the wrapper the current handler receives when that
|
|
101
|
+
* wrapper wraps the same continuation: `req.next` is the host continuation
|
|
102
|
+
* itself, or an earlier layer's wrapper of it. Route handlers receive a
|
|
103
|
+
* route-local continuation from `Route.dispatch`, so `req.next` keeps the
|
|
104
|
+
* router-level one there. A nested router restores its parent's `req.next`
|
|
105
|
+
* when it finishes.
|
|
106
|
+
*
|
|
107
|
+
* @param {import('node:http').IncomingMessage | undefined} req
|
|
108
|
+
* @param {Function} hostNext
|
|
109
|
+
* @param {Function} wrappedNext
|
|
110
|
+
*/
|
|
111
|
+
function adoptRequestNext (req, hostNext, wrappedNext) {
|
|
112
|
+
hostNexts.set(wrappedNext, hostNext)
|
|
113
|
+
if (req && (req.next === hostNext || hostNexts.get(req.next) === hostNext)) req.next = wrappedNext
|
|
114
|
+
}
|
|
115
|
+
|
|
94
116
|
/**
|
|
95
117
|
* Build the request/error dispatch wrappers for one host (`express` / `router`).
|
|
96
118
|
* They wrap the layer's prototype dispatch and read the side-table metadata, so
|
|
@@ -171,6 +193,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
const wrappedNext = typeof next === 'function' ? wrapNext(req, meta.name, next) : next
|
|
196
|
+
if (wrappedNext !== next) adoptRequestNext(req, next, wrappedNext)
|
|
174
197
|
enterChannel.publish({ name: meta.name, req, route, layer: this })
|
|
175
198
|
|
|
176
199
|
try {
|
|
@@ -199,6 +222,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
199
222
|
}
|
|
200
223
|
|
|
201
224
|
const wrappedNext = typeof next === 'function' ? wrapNext(req, meta.name, next) : next
|
|
225
|
+
if (wrappedNext !== next) adoptRequestNext(req, next, wrappedNext)
|
|
202
226
|
enterChannel.publish({ name: meta.name, req, route, layer: this })
|
|
203
227
|
|
|
204
228
|
try {
|
|
@@ -223,6 +247,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
223
247
|
|
|
224
248
|
let calls = 0
|
|
225
249
|
if (typeof next === 'function') {
|
|
250
|
+
const hostNext = next
|
|
226
251
|
next = shimmer.wrapCallback(next, originalNext => function next (error) {
|
|
227
252
|
calls++
|
|
228
253
|
if (calls === 1) {
|
|
@@ -238,6 +263,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
238
263
|
|
|
239
264
|
originalNext.apply(this, arguments)
|
|
240
265
|
})
|
|
266
|
+
adoptRequestNext(req, hostNext, next)
|
|
241
267
|
}
|
|
242
268
|
|
|
243
269
|
const route = needMultiMatch ? resolveLayerRoute(meta, layer) : captureRoute
|
|
@@ -273,6 +299,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
273
299
|
|
|
274
300
|
let calls = 0
|
|
275
301
|
if (typeof next === 'function') {
|
|
302
|
+
const hostNext = next
|
|
276
303
|
next = shimmer.wrapCallback(next, originalNext => function next (nextError) {
|
|
277
304
|
calls++
|
|
278
305
|
if (calls === 1) {
|
|
@@ -288,6 +315,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
288
315
|
|
|
289
316
|
originalNext.apply(this, arguments)
|
|
290
317
|
})
|
|
318
|
+
adoptRequestNext(req, hostNext, next)
|
|
291
319
|
}
|
|
292
320
|
|
|
293
321
|
const route = needMultiMatch ? resolveLayerRoute(meta, layer) : captureRoute
|
|
@@ -336,6 +364,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
336
364
|
const nextIndex = isErrorHandler ? 3 : 2
|
|
337
365
|
let calls = 0
|
|
338
366
|
if (typeof args[nextIndex] === 'function') {
|
|
367
|
+
const hostNext = args[nextIndex]
|
|
339
368
|
args[nextIndex] = shimmer.wrapCallback(args[nextIndex], originalNext => function next (error) {
|
|
340
369
|
calls++
|
|
341
370
|
if (calls === 1) {
|
|
@@ -351,6 +380,7 @@ function createLayerDispatchWrappers (name) {
|
|
|
351
380
|
|
|
352
381
|
originalNext.apply(this, arguments)
|
|
353
382
|
})
|
|
383
|
+
adoptRequestNext(req, hostNext, args[nextIndex])
|
|
354
384
|
}
|
|
355
385
|
|
|
356
386
|
const route = needMultiMatch ? resolveLayerRoute(meta, layer) : captureRoute
|
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
/** @returns {{ isRumInstrumented: boolean, isRumActive: boolean, rumSamplingRate: number | null }} */
|
|
6
6
|
function detectRum () {
|
|
7
7
|
const isRumInstrumented = !!window.DD_RUM
|
|
8
|
-
const isRumActive = window.DD_RUM && window.DD_RUM.getInternalContext
|
|
9
|
-
? !!window.DD_RUM.getInternalContext()
|
|
10
|
-
: false
|
|
8
|
+
const isRumActive = !!(window.DD_RUM && window.DD_RUM.getInternalContext && window.DD_RUM.getInternalContext())
|
|
11
9
|
const rumInitConfiguration = window.DD_RUM && window.DD_RUM.getInitConfiguration
|
|
12
10
|
? window.DD_RUM.getInitConfiguration()
|
|
13
11
|
: undefined
|
|
@@ -26,9 +24,7 @@ function stopRumSession () {
|
|
|
26
24
|
|
|
27
25
|
function stopRumSessionAndReportActivity () {
|
|
28
26
|
if (window.DD_RUM && window.DD_RUM.stopSession) {
|
|
29
|
-
const isRumActive = window.DD_RUM.getInternalContext
|
|
30
|
-
? !!window.DD_RUM.getInternalContext()
|
|
31
|
-
: false
|
|
27
|
+
const isRumActive = !!(window.DD_RUM.getInternalContext && window.DD_RUM.getInternalContext())
|
|
32
28
|
window.DD_RUM.stopSession()
|
|
33
29
|
return isRumActive
|
|
34
30
|
}
|
|
@@ -659,8 +659,7 @@ function createMainProcessReporter (reporterState) {
|
|
|
659
659
|
},
|
|
660
660
|
|
|
661
661
|
onTaskUpdate (packs, events) {
|
|
662
|
-
if (!isReporterActive()) return
|
|
663
|
-
if (!events) return
|
|
662
|
+
if (!isReporterActive() || !events) return
|
|
664
663
|
|
|
665
664
|
for (const event of events) {
|
|
666
665
|
if (event[1] === 'test-retried') {
|
|
@@ -685,8 +684,7 @@ function createMainProcessReporter (reporterState) {
|
|
|
685
684
|
},
|
|
686
685
|
|
|
687
686
|
onFinished (files) {
|
|
688
|
-
if (!isReporterActive()) return
|
|
689
|
-
if (!files) return
|
|
687
|
+
if (!isReporterActive() || !files) return
|
|
690
688
|
|
|
691
689
|
for (const file of files) {
|
|
692
690
|
const testModule = createTestModuleFromFile(file)
|
|
@@ -1276,10 +1274,12 @@ function reportFinalTestAttempt (testReport) {
|
|
|
1276
1274
|
isQuarantined: testProperties.isQuarantined,
|
|
1277
1275
|
})
|
|
1278
1276
|
}
|
|
1277
|
+
const attemptIndex = task.meta?.__ddTestOptCurrentAttemptIndex ?? 0
|
|
1278
|
+
const attemptStartTime = task.meta?.__ddTestOptAttemptStartTimes?.[attemptIndex]
|
|
1279
1279
|
const {
|
|
1280
1280
|
isRumActive,
|
|
1281
1281
|
testExecutionId,
|
|
1282
|
-
} = getRumCorrelation(task)
|
|
1282
|
+
} = getRumCorrelation(task, attemptIndex)
|
|
1283
1283
|
testSkipCh.publish({
|
|
1284
1284
|
...browserEnvironment,
|
|
1285
1285
|
testName,
|
|
@@ -1291,6 +1291,8 @@ function reportFinalTestAttempt (testReport) {
|
|
|
1291
1291
|
isRumActive,
|
|
1292
1292
|
isTestFrameworkWorker: true,
|
|
1293
1293
|
requestErrorTags: state.requestErrorTags,
|
|
1294
|
+
startTime: Number.isFinite(attemptStartTime) ? attemptStartTime : undefined,
|
|
1295
|
+
duration: task.meta?.__ddTestOptAttemptDurations?.[attemptIndex],
|
|
1294
1296
|
testStartLine: task.location?.line,
|
|
1295
1297
|
testExecutionId,
|
|
1296
1298
|
...testSuiteStore,
|
|
@@ -300,8 +300,7 @@ function configureEfdSuiteTracker (testFilepaths, repositoryRoot) {
|
|
|
300
300
|
* @param {boolean} hasNewTest
|
|
301
301
|
*/
|
|
302
302
|
function reserveEarlyFlakeDetectionSuite (testSuite, hasNewTest) {
|
|
303
|
-
if (!isEfdSuiteAdmissionEnabled || typeof testSuite !== 'string') return false
|
|
304
|
-
if (isEarlyFlakeDetectionFaulty) return false
|
|
303
|
+
if (!isEfdSuiteAdmissionEnabled || typeof testSuite !== 'string' || isEarlyFlakeDetectionFaulty) return false
|
|
305
304
|
|
|
306
305
|
if (hasNewTest) {
|
|
307
306
|
suitesWithNewTests.add(testSuite)
|
|
@@ -1201,11 +1200,7 @@ function getSortWrapper (sort, frameworkVersion) {
|
|
|
1201
1200
|
|
|
1202
1201
|
function getFinishWrapper (exitOrClose) {
|
|
1203
1202
|
return async function () {
|
|
1204
|
-
if (finishedSessionContexts.has(this)) {
|
|
1205
|
-
return exitOrClose.apply(this, arguments)
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
if (!testSessionFinishCh.hasSubscribers) {
|
|
1203
|
+
if (finishedSessionContexts.has(this) || !testSessionFinishCh.hasSubscribers) {
|
|
1209
1204
|
return exitOrClose.apply(this, arguments)
|
|
1210
1205
|
}
|
|
1211
1206
|
finishedSessionContexts.add(this)
|
|
@@ -1230,15 +1225,15 @@ function getFinishWrapper (exitOrClose) {
|
|
|
1230
1225
|
const tests = getTypeTasks(this.state.getFiles())
|
|
1231
1226
|
const hasExecutedTests = tests.some(test =>
|
|
1232
1227
|
test.mode !== 'skip' && test.mode !== 'todo' &&
|
|
1233
|
-
test.result?.state
|
|
1228
|
+
(test.result?.state === 'pass' || test.result?.state === 'fail')
|
|
1234
1229
|
)
|
|
1235
1230
|
const hasErrors = hasRunError || error ||
|
|
1236
1231
|
this.state.getCountOfFailedTests() > 0 || this.state.getUnhandledErrors().length > 0
|
|
1237
|
-
const testSessionEmptyReason =
|
|
1238
|
-
?
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1232
|
+
const testSessionEmptyReason = hasErrors || hasExecutedTests
|
|
1233
|
+
? undefined
|
|
1234
|
+
: isEmptyShard
|
|
1235
|
+
? 'zero_test_shard'
|
|
1236
|
+
: tests.length > 0 || skippedSuites.length > 0 ? 'all_tests_skipped' : 'zero_tests'
|
|
1242
1237
|
const status = hasErrors ? 'fail' : (testSessionEmptyReason ? 'skip' : 'pass')
|
|
1243
1238
|
const flushPromise = getChannelPromise(testSessionFinishCh, {
|
|
1244
1239
|
status,
|
|
@@ -1758,8 +1753,7 @@ async function reportTypecheckFile (file, sessionConfiguration, frameworkVersion
|
|
|
1758
1753
|
}
|
|
1759
1754
|
|
|
1760
1755
|
async function reportTypecheckResults (result, frameworkVersion, ctx, typechecker, files = result?.files) {
|
|
1761
|
-
if (!testSuiteFinishCh.hasSubscribers) return
|
|
1762
|
-
if (!Array.isArray(result?.files) || !Array.isArray(files)) return
|
|
1756
|
+
if (!testSuiteFinishCh.hasSubscribers || !Array.isArray(result?.files) || !Array.isArray(files)) return
|
|
1763
1757
|
|
|
1764
1758
|
const setupState = ctx && mainProcessSetupStates.get(ctx)
|
|
1765
1759
|
if (
|
|
@@ -2239,8 +2233,6 @@ addHook({
|
|
|
2239
2233
|
versions: ['>=5.0.0'],
|
|
2240
2234
|
filePattern: 'dist/chunks/index.*',
|
|
2241
2235
|
}, (vitestPackage, frameworkVersion) => {
|
|
2242
|
-
if (!getVitestExport(vitestPackage)) return vitestPackage
|
|
2243
|
-
|
|
2244
2236
|
wrapVitestInternals(vitestPackage, frameworkVersion)
|
|
2245
2237
|
|
|
2246
2238
|
const typecheckPoolWorker = getTypecheckPoolWorkerExport(vitestPackage)
|
|
@@ -33,7 +33,7 @@ const testManagementTestsCh = channel('ci:vitest:test-management-tests')
|
|
|
33
33
|
const modifiedFilesCh = channel('ci:vitest:modified-files')
|
|
34
34
|
|
|
35
35
|
const CLOSING_SCRIPT_TAG_RE = /<\/script/i
|
|
36
|
-
const SERIALIZED_CONTEXT_PREFIX = '\
|
|
36
|
+
const SERIALIZED_CONTEXT_PREFIX = '\0dd-vitest-context:'
|
|
37
37
|
|
|
38
38
|
const workerReportTraceCh = channel('ci:vitest:worker-report:trace')
|
|
39
39
|
const workerReportCoverageCh = channel('ci:vitest:worker-report:coverage')
|
|
@@ -299,7 +299,7 @@ function getVitestTestProperties (providedContext, testSuiteAbsolutePath, testNa
|
|
|
299
299
|
|
|
300
300
|
return {
|
|
301
301
|
testSuite: testProperties?.testSuite,
|
|
302
|
-
isNew: Array.isArray(knownTests)
|
|
302
|
+
isNew: Array.isArray(knownTests) && !knownTests.includes(testName),
|
|
303
303
|
isModified: testProperties?.isModified === true,
|
|
304
304
|
isAttemptToFix: testManagementProperties.isAttemptToFix,
|
|
305
305
|
isDisabled: testManagementProperties.isDisabled,
|
|
@@ -354,8 +354,7 @@ function hasConcurrentTask (tasks) {
|
|
|
354
354
|
if (!tasks) return false
|
|
355
355
|
|
|
356
356
|
for (const task of tasks) {
|
|
357
|
-
if (task.concurrent === true) return true
|
|
358
|
-
if (hasConcurrentTask(task.tasks)) return true
|
|
357
|
+
if (task.concurrent === true || hasConcurrentTask(task.tasks)) return true
|
|
359
358
|
}
|
|
360
359
|
|
|
361
360
|
return false
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
4
4
|
const { isTrue } = require('../../dd-trace/src/util')
|
|
5
5
|
|
|
6
|
-
const VITEST_NO_WORKER_INIT_ACTIVE_ENV = 'DD_TEST_OPT_VITEST_NO_WORKER_INIT_ACTIVE'
|
|
7
|
-
|
|
8
6
|
if (getEnvironmentVariable('DD_VITEST_WORKER') === '1') {
|
|
7
|
+
const VITEST_NO_WORKER_INIT_ACTIVE_ENV = 'DD_TEST_OPT_VITEST_NO_WORKER_INIT_ACTIVE'
|
|
8
|
+
|
|
9
9
|
// In no-worker-init mode the main process reports Vitest events from reporter hooks.
|
|
10
10
|
// Loading worker instrumentation here would reintroduce the worker tracer path.
|
|
11
11
|
// eslint-disable-next-line eslint-rules/eslint-process-env
|
|
@@ -6,6 +6,7 @@ const realSetTimeout = setTimeout
|
|
|
6
6
|
const { AsyncResource } = require('node:async_hooks')
|
|
7
7
|
const { fileURLToPath } = require('node:url')
|
|
8
8
|
|
|
9
|
+
const { createFinalFlushTimeoutError, FINAL_FLUSH_TIMEOUT } = require('../../dd-trace/src/ci-visibility/final-flush')
|
|
9
10
|
const { EMPTY_EFD_RETRY_POLICY } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
|
|
10
11
|
const { RUM_TEST_EXECUTION_ID_COOKIE_NAME } = require('../../dd-trace/src/ci-visibility/rum')
|
|
11
12
|
const { getEnvironmentVariable, getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
@@ -30,6 +31,9 @@ const {
|
|
|
30
31
|
SCREENSHOT_UPLOAD_RESPONSE,
|
|
31
32
|
sendWebdriverioWorkerMessage,
|
|
32
33
|
SUITE_FINISH,
|
|
34
|
+
VIDEO_UPLOAD,
|
|
35
|
+
VIDEO_UPLOAD_FLUSH,
|
|
36
|
+
VIDEO_UPLOAD_RESPONSE,
|
|
33
37
|
WEBDRIVERIO_WORKER_ENV,
|
|
34
38
|
WEBDRIVERIO_WORKER_EVENT,
|
|
35
39
|
WEBDRIVERIO_WORKER_ORIGIN,
|
|
@@ -52,6 +56,8 @@ const logSubmissionFlushCh = channel('ci:log-submission:flush')
|
|
|
52
56
|
const modifiedFilesCh = channel('ci:mocha:modified-files')
|
|
53
57
|
const screenshotCapabilitiesCh = channel('ci:webdriverio:screenshot:capabilities')
|
|
54
58
|
const screenshotUploadCh = channel('ci:webdriverio:screenshot:upload')
|
|
59
|
+
const videoCapabilitiesCh = channel('ci:webdriverio:video:capabilities')
|
|
60
|
+
const videoUploadCh = channel('ci:webdriverio:video:upload')
|
|
55
61
|
const testManagementTestsCh = channel('ci:mocha:test-management-tests')
|
|
56
62
|
const workerConfigurationCh = channel('ci:mocha:worker:configuration')
|
|
57
63
|
const workerReportLogsCh = channel('ci:mocha:worker-report:logs')
|
|
@@ -59,8 +65,10 @@ const workerReportTelemetryCh = channel('ci:mocha:worker-report:telemetry')
|
|
|
59
65
|
const workerReportTraceCh = channel('ci:mocha:worker-report:trace')
|
|
60
66
|
|
|
61
67
|
const jasmineAdapterInitCh = tracingChannel('orchestrion:@wdio/jasmine-framework:JasmineAdapter_init')
|
|
68
|
+
const mochaAdapterInitCh = tracingChannel('orchestrion:@wdio/mocha-framework:MochaAdapter_init')
|
|
62
69
|
const baseReporterWaitForSyncCh = tracingChannel('orchestrion:@wdio/runner:BaseReporter_waitForSync')
|
|
63
70
|
const runnerRunCh = tracingChannel('orchestrion:@wdio/runner:Runner_run')
|
|
71
|
+
const runnerStartSessionCh = tracingChannel('orchestrion:@wdio/runner:Runner_startSession')
|
|
64
72
|
const executeAsyncCh = tracingChannel('orchestrion:@wdio/utils:executeAsync')
|
|
65
73
|
const launcherStartInstanceCh = tracingChannel('orchestrion:@wdio/cli:Launcher_startInstance')
|
|
66
74
|
const configParserShardCh = tracingChannel('orchestrion:@wdio/config:ConfigParser_shard')
|
|
@@ -80,7 +88,7 @@ const TEST_FRAMEWORK = 'webdriverio'
|
|
|
80
88
|
const SET_RUM_COOKIE_SCRIPT = 'cookie => { globalThis.document.cookie = cookie }'
|
|
81
89
|
const RUM_FLUSH_WAIT_TIME = getValueFromEnvSources('DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS')
|
|
82
90
|
const isWebdriverioWorker = !!getEnvironmentVariable(WEBDRIVERIO_WORKER_ENV)
|
|
83
|
-
let
|
|
91
|
+
let workerRequestId = 0
|
|
84
92
|
|
|
85
93
|
const loadCh = channel('dd-trace:instrumentation:load')
|
|
86
94
|
if (loadCh.hasSubscribers) {
|
|
@@ -289,8 +297,7 @@ async function preloadRumNavigation () {
|
|
|
289
297
|
try {
|
|
290
298
|
const browser = this
|
|
291
299
|
const testExecutionId = getRumTestExecutionId(browser)
|
|
292
|
-
if (!canCorrelateRumBrowser(browser)) return
|
|
293
|
-
if (!rumRunnerBrowsers.has(browser)) return
|
|
300
|
+
if (!canCorrelateRumBrowser(browser) || !rumRunnerBrowsers.has(browser)) return
|
|
294
301
|
|
|
295
302
|
retainRumBrowser(browser)
|
|
296
303
|
if (!testExecutionId) return
|
|
@@ -363,9 +370,7 @@ async function handleRumNavigation (context) {
|
|
|
363
370
|
log.debug("RUM was detected on the page, but it isn't active because the sampling rate is below 100%")
|
|
364
371
|
}
|
|
365
372
|
const testExecutionId = getRumTestExecutionId(browser, isRumActive)
|
|
366
|
-
if (sampledOut)
|
|
367
|
-
|
|
368
|
-
if (!testExecutionId) {
|
|
373
|
+
if (sampledOut || !testExecutionId) {
|
|
369
374
|
return
|
|
370
375
|
}
|
|
371
376
|
if (!isRumActive && browser.isBidi) return
|
|
@@ -957,6 +962,8 @@ function waitForRumTestStart (context) {
|
|
|
957
962
|
* @property {boolean|undefined} hasTests
|
|
958
963
|
* @property {number|undefined} exitCode
|
|
959
964
|
* @property {number|undefined} retries
|
|
965
|
+
* @property {AbortController|undefined} videoController
|
|
966
|
+
* @property {ReturnType<typeof setTimeout>|undefined} videoFlushTimer
|
|
960
967
|
*/
|
|
961
968
|
|
|
962
969
|
/**
|
|
@@ -1019,6 +1026,7 @@ function createWorkerConfiguration () {
|
|
|
1019
1026
|
isItrEnabled: false,
|
|
1020
1027
|
isKnownTestsEnabled: false,
|
|
1021
1028
|
isTestFailureScreenshotsEnabled: false,
|
|
1029
|
+
isTestFailureVideosEnabled: false,
|
|
1022
1030
|
isSuitesSkippingEnabled: false,
|
|
1023
1031
|
isTestDynamicInstrumentationEnabled: false,
|
|
1024
1032
|
isTestManagementTestsEnabled: false,
|
|
@@ -1032,22 +1040,23 @@ function createWorkerConfiguration () {
|
|
|
1032
1040
|
}
|
|
1033
1041
|
|
|
1034
1042
|
/**
|
|
1035
|
-
* Configures a
|
|
1043
|
+
* Configures a framework worker before browser session creation using its coordinator-owned settings.
|
|
1036
1044
|
*
|
|
1037
1045
|
* @param {{_jrunner?: {env?: {addReporter?: (reporter: object) => void}}, _specs?: string[]}} adapter
|
|
1038
1046
|
* @param {{
|
|
1039
1047
|
* resolveCallback?: (onDone: () => void) => void,
|
|
1040
1048
|
* rejectCallback?: (onDone: () => void) => void
|
|
1041
1049
|
* }} context
|
|
1050
|
+
* @param {'mocha'|'jasmine'} testFrameworkAdapter
|
|
1042
1051
|
*/
|
|
1043
|
-
function
|
|
1052
|
+
function initializeFrameworkWorker (adapter, context, testFrameworkAdapter) {
|
|
1044
1053
|
if (!isWebdriverioWorker) {
|
|
1045
1054
|
return
|
|
1046
1055
|
}
|
|
1047
1056
|
|
|
1048
1057
|
const specs = adapter?._specs || []
|
|
1049
1058
|
|
|
1050
|
-
if (jasmineDoneCh.hasSubscribers) {
|
|
1059
|
+
if (testFrameworkAdapter === JASMINE_FRAMEWORK_ADAPTER && jasmineDoneCh.hasSubscribers) {
|
|
1051
1060
|
adapter?._jrunner?.env?.addReporter?.({
|
|
1052
1061
|
/**
|
|
1053
1062
|
* Publishes run-level failures that are absent from suiteDone.
|
|
@@ -1066,11 +1075,11 @@ function initializeJasmineWorker (adapter, context) {
|
|
|
1066
1075
|
* @param {() => void} onDone
|
|
1067
1076
|
*/
|
|
1068
1077
|
const waitForCoordinator = onDone => {
|
|
1069
|
-
const requestId = `${process.pid}-${++
|
|
1078
|
+
const requestId = `${process.pid}-${++workerRequestId}`
|
|
1070
1079
|
let finished = false
|
|
1071
1080
|
|
|
1072
1081
|
/**
|
|
1073
|
-
* Releases
|
|
1082
|
+
* Releases framework initialization exactly once.
|
|
1074
1083
|
*
|
|
1075
1084
|
* @param {object} [configuration]
|
|
1076
1085
|
*/
|
|
@@ -1087,7 +1096,7 @@ function initializeJasmineWorker (adapter, context) {
|
|
|
1087
1096
|
repositoryRoot: configuration.repositoryRoot,
|
|
1088
1097
|
specs,
|
|
1089
1098
|
testFramework: TEST_FRAMEWORK,
|
|
1090
|
-
testFrameworkAdapter
|
|
1099
|
+
testFrameworkAdapter,
|
|
1091
1100
|
})
|
|
1092
1101
|
onDone()
|
|
1093
1102
|
}
|
|
@@ -1111,7 +1120,7 @@ function initializeJasmineWorker (adapter, context) {
|
|
|
1111
1120
|
name: WORKER_READY,
|
|
1112
1121
|
content: {
|
|
1113
1122
|
requestId,
|
|
1114
|
-
testFrameworkAdapter
|
|
1123
|
+
testFrameworkAdapter,
|
|
1115
1124
|
},
|
|
1116
1125
|
}, error => {
|
|
1117
1126
|
if (error) {
|
|
@@ -1327,6 +1336,9 @@ function configureCoordinator (state, response) {
|
|
|
1327
1336
|
const screenshotCapabilities = {}
|
|
1328
1337
|
screenshotCapabilitiesCh.publish(screenshotCapabilities)
|
|
1329
1338
|
configuration.isTestFailureScreenshotsEnabled = screenshotCapabilities.enabled === true
|
|
1339
|
+
const videoCapabilities = {}
|
|
1340
|
+
videoCapabilitiesCh.publish(videoCapabilities)
|
|
1341
|
+
configuration.isTestFailureVideosEnabled = videoCapabilities.enabled === true
|
|
1330
1342
|
|
|
1331
1343
|
configuration.repositoryRoot = repositoryRoot
|
|
1332
1344
|
if (err || !libraryConfig) {
|
|
@@ -1667,6 +1679,13 @@ function handleWorkerMessage (state, workerRecord, message) {
|
|
|
1667
1679
|
return
|
|
1668
1680
|
}
|
|
1669
1681
|
|
|
1682
|
+
if (message.name === WORKER_READY || message.name === CONFIGURATION_REQUEST) {
|
|
1683
|
+
// Watch mode reuses the worker. Keep old requests cancelled while the new run gets a fresh signal.
|
|
1684
|
+
clearTimeout(workerRecord.videoFlushTimer)
|
|
1685
|
+
workerRecord.videoFlushTimer = undefined
|
|
1686
|
+
workerRecord.videoController?.abort(new Error('WebdriverIO video run completed'))
|
|
1687
|
+
workerRecord.videoController = undefined
|
|
1688
|
+
}
|
|
1670
1689
|
if (message.name === WORKER_READY) {
|
|
1671
1690
|
initializeCoordinator(state, configuration => {
|
|
1672
1691
|
if (state.testFrameworkAdapter === JASMINE_FRAMEWORK_ADAPTER) {
|
|
@@ -1687,25 +1706,51 @@ function handleWorkerMessage (state, workerRecord, message) {
|
|
|
1687
1706
|
handleConfigurationRequest(state, workerRecord, message)
|
|
1688
1707
|
return
|
|
1689
1708
|
}
|
|
1690
|
-
if (message.name ===
|
|
1709
|
+
if (message.name === VIDEO_UPLOAD_FLUSH) {
|
|
1710
|
+
if (message.content?.complete) {
|
|
1711
|
+
clearTimeout(workerRecord.videoFlushTimer)
|
|
1712
|
+
workerRecord.videoFlushTimer = undefined
|
|
1713
|
+
// The worker may have reached its own deadline before the coordinator's timer fires.
|
|
1714
|
+
workerRecord.videoController?.abort(new Error('WebdriverIO video flush completed'))
|
|
1715
|
+
return
|
|
1716
|
+
}
|
|
1717
|
+
const controller = workerRecord.videoController ??= new AbortController()
|
|
1718
|
+
workerRecord.videoFlushTimer ??= setTimeout(() => {
|
|
1719
|
+
controller.abort(createFinalFlushTimeoutError())
|
|
1720
|
+
}, FINAL_FLUSH_TIMEOUT)
|
|
1721
|
+
workerRecord.videoFlushTimer.unref?.()
|
|
1722
|
+
return
|
|
1723
|
+
}
|
|
1724
|
+
if (message.name === SCREENSHOT_UPLOAD || message.name === VIDEO_UPLOAD) {
|
|
1725
|
+
const isVideo = message.name === VIDEO_UPLOAD
|
|
1726
|
+
const uploadCh = isVideo ? videoUploadCh : screenshotUploadCh
|
|
1691
1727
|
const { requestId, ...content } = message.content || {}
|
|
1692
1728
|
const respond = (error) => sendWorkerMessage(workerRecord, {
|
|
1693
1729
|
origin: 'datadog',
|
|
1694
|
-
name: SCREENSHOT_UPLOAD_RESPONSE,
|
|
1730
|
+
name: isVideo ? VIDEO_UPLOAD_RESPONSE : SCREENSHOT_UPLOAD_RESPONSE,
|
|
1695
1731
|
content: {
|
|
1696
1732
|
error: error?.message,
|
|
1697
1733
|
requestId,
|
|
1698
1734
|
},
|
|
1699
1735
|
})
|
|
1700
|
-
if (
|
|
1701
|
-
respond(new Error('WebdriverIO screenshot upload is not available'))
|
|
1702
|
-
} else {
|
|
1736
|
+
if (requestId && uploadCh.hasSubscribers) {
|
|
1703
1737
|
try {
|
|
1704
|
-
|
|
1738
|
+
let signal
|
|
1739
|
+
if (isVideo) {
|
|
1740
|
+
workerRecord.videoController ??= new AbortController()
|
|
1741
|
+
signal = workerRecord.videoController.signal
|
|
1742
|
+
}
|
|
1743
|
+
uploadCh.publish({
|
|
1744
|
+
...content,
|
|
1745
|
+
signal,
|
|
1746
|
+
onDone: respond,
|
|
1747
|
+
})
|
|
1705
1748
|
} catch (error) {
|
|
1706
|
-
log.error('WebdriverIO
|
|
1749
|
+
log.error('WebdriverIO media upload error: %s', error?.message || String(error))
|
|
1707
1750
|
respond(error)
|
|
1708
1751
|
}
|
|
1752
|
+
} else {
|
|
1753
|
+
respond(new Error('WebdriverIO media upload is not available'))
|
|
1709
1754
|
}
|
|
1710
1755
|
return
|
|
1711
1756
|
}
|
|
@@ -1732,6 +1777,8 @@ function handleWorkerMessage (state, workerRecord, message) {
|
|
|
1732
1777
|
* @param {object} exit
|
|
1733
1778
|
*/
|
|
1734
1779
|
function handleWorkerExit (state, workerRecord, exit) {
|
|
1780
|
+
clearTimeout(workerRecord.videoFlushTimer)
|
|
1781
|
+
workerRecord.videoController?.abort(new Error('WebdriverIO worker exited during video upload'))
|
|
1735
1782
|
state.activeWorkers--
|
|
1736
1783
|
workerRecord.exitCode = exit.exitCode
|
|
1737
1784
|
workerRecord.retries = exit.retries
|
|
@@ -1768,6 +1815,8 @@ function registerWorker (state, worker, specs) {
|
|
|
1768
1815
|
hasTests: undefined,
|
|
1769
1816
|
exitCode: undefined,
|
|
1770
1817
|
retries: undefined,
|
|
1818
|
+
videoController: undefined,
|
|
1819
|
+
videoFlushTimer: undefined,
|
|
1771
1820
|
}
|
|
1772
1821
|
state.activeWorkers++
|
|
1773
1822
|
if (state.activeWorkers > state.maxActiveWorkers) {
|
|
@@ -1917,6 +1966,44 @@ function waitForRumCleanupBeforeSessionEnd (context) {
|
|
|
1917
1966
|
context.rumCleanupCallback = cleanupAllRumBrowsers
|
|
1918
1967
|
}
|
|
1919
1968
|
|
|
1969
|
+
/**
|
|
1970
|
+
* Opted-in background screenshots must not dismiss dialogs. Preserve explicit customer policies.
|
|
1971
|
+
*
|
|
1972
|
+
* @param {{
|
|
1973
|
+
* arguments: [{framework?: string, sessionId?: string, automationProtocol?: string}, object],
|
|
1974
|
+
* self: {_isMultiremote?: boolean, _isMultiRemote?: boolean}
|
|
1975
|
+
* }} context
|
|
1976
|
+
*/
|
|
1977
|
+
function configureVideoPromptBehavior (context) {
|
|
1978
|
+
if (!testFinishCh.hasSubscribers || getValueFromEnvSources('DD_TEST_FAILURE_VIDEOS_ENABLED', true) !== true) return
|
|
1979
|
+
const [config, capabilities] = context.arguments
|
|
1980
|
+
if (!SUPPORTED_FRAMEWORK_ADAPTERS.has(config?.framework) || 'sessionId' in config ||
|
|
1981
|
+
config.automationProtocol === './protocol-stub.js') return
|
|
1982
|
+
try {
|
|
1983
|
+
const videoCapabilities = {}
|
|
1984
|
+
videoCapabilitiesCh.publish(videoCapabilities)
|
|
1985
|
+
if (!videoCapabilities.enabled) return
|
|
1986
|
+
/** @param {{unhandledPromptBehavior?: unknown}} caps - Capabilities for one browser session. */
|
|
1987
|
+
const withDefault = caps => caps && caps.unhandledPromptBehavior === undefined
|
|
1988
|
+
? { ...caps, unhandledPromptBehavior: 'ignore' }
|
|
1989
|
+
: caps
|
|
1990
|
+
// Prepare every session before replacing the argument, so a read failure cannot leave partial defaults.
|
|
1991
|
+
context.arguments[1] = (context.self._isMultiremote || context.self._isMultiRemote)
|
|
1992
|
+
? Object.fromEntries(Object.entries(capabilities).map(([name, options]) => {
|
|
1993
|
+
const session = { ...options }
|
|
1994
|
+
session.capabilities = withDefault(session.capabilities)
|
|
1995
|
+
return [name, session]
|
|
1996
|
+
}))
|
|
1997
|
+
: withDefault(capabilities)
|
|
1998
|
+
} catch (error) {
|
|
1999
|
+
log.error('Error configuring WebdriverIO video prompt handling: %s', error?.message || String(error))
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
runnerStartSessionCh.start.subscribe(
|
|
2004
|
+
/** @type {import('node:diagnostics_channel').ChannelListener} */ (configureVideoPromptBehavior)
|
|
2005
|
+
)
|
|
2006
|
+
|
|
1920
2007
|
baseReporterWaitForSyncCh.asyncEnd.subscribe(
|
|
1921
2008
|
/** @type {import('node:diagnostics_channel').ChannelListener} */ (waitForLogSubmissionAtWorkerExit)
|
|
1922
2009
|
)
|
|
@@ -1974,7 +2061,17 @@ executeAsyncCh.subscribe({
|
|
|
1974
2061
|
// @ts-expect-error See the partial tracing-channel subscriber above.
|
|
1975
2062
|
jasmineAdapterInitCh.subscribe({
|
|
1976
2063
|
asyncEnd (context) {
|
|
1977
|
-
|
|
2064
|
+
initializeFrameworkWorker(context.result || context.self, context, JASMINE_FRAMEWORK_ADAPTER)
|
|
2065
|
+
},
|
|
2066
|
+
})
|
|
2067
|
+
|
|
2068
|
+
// @ts-expect-error See the partial tracing-channel subscriber above.
|
|
2069
|
+
mochaAdapterInitCh.subscribe({
|
|
2070
|
+
asyncEnd (context) {
|
|
2071
|
+
// Mocha normally receives worker settings in run(), after WebdriverIO creates its browser session.
|
|
2072
|
+
if (getValueFromEnvSources('DD_TEST_FAILURE_VIDEOS_ENABLED', true) === true) {
|
|
2073
|
+
initializeFrameworkWorker(context.result || context.self, context, MOCHA_FRAMEWORK_ADAPTER)
|
|
2074
|
+
}
|
|
1978
2075
|
},
|
|
1979
2076
|
})
|
|
1980
2077
|
|
|
@@ -291,10 +291,7 @@ function dataLength (data) {
|
|
|
291
291
|
if (data instanceof Blob) {
|
|
292
292
|
return data.size
|
|
293
293
|
}
|
|
294
|
-
if (ArrayBuffer.isView(data)) {
|
|
295
|
-
return data.byteLength
|
|
296
|
-
}
|
|
297
|
-
if (data instanceof ArrayBuffer) {
|
|
294
|
+
if (ArrayBuffer.isView(data) || data instanceof ArrayBuffer) {
|
|
298
295
|
return data.byteLength
|
|
299
296
|
}
|
|
300
297
|
let total = 0
|
|
@@ -13,8 +13,7 @@ class AmqplibClientPlugin extends ClientPlugin {
|
|
|
13
13
|
bindStart (ctx) {
|
|
14
14
|
const { channel = {}, method, fields } = ctx
|
|
15
15
|
|
|
16
|
-
if (method === 'basic.deliver' || method === 'basic.get') return
|
|
17
|
-
if (method === 'basic.publish') return
|
|
16
|
+
if (method === 'basic.deliver' || method === 'basic.get' || method === 'basic.publish') return
|
|
18
17
|
|
|
19
18
|
const stream = (channel.connection && channel.connection.stream) || {}
|
|
20
19
|
const span = this.startSpan(this.operationName(), {
|