dd-trace 6.3.0 → 6.5.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/README.electron.md +7 -0
- package/README.md +17 -0
- package/ci/diagnose.js +2100 -0
- package/ci/init.js +23 -2
- package/ci/runbook.md +198 -0
- package/ci/test-optimization-validation/approval-artifacts.js +143 -0
- package/ci/test-optimization-validation/approval.js +299 -0
- package/ci/test-optimization-validation/artifact-id.js +20 -0
- package/ci/test-optimization-validation/bounded-json.js +121 -0
- package/ci/test-optimization-validation/ci-command-candidate.js +83 -0
- package/ci/test-optimization-validation/ci-discovery.js +181 -0
- package/ci/test-optimization-validation/ci-remediation.js +210 -0
- package/ci/test-optimization-validation/cli.js +903 -0
- package/ci/test-optimization-validation/command-blocker.js +81 -0
- package/ci/test-optimization-validation/command-output-policy.js +206 -0
- package/ci/test-optimization-validation/command-runner.js +707 -0
- package/ci/test-optimization-validation/command-suitability.js +471 -0
- package/ci/test-optimization-validation/executable-approval.js +48 -0
- package/ci/test-optimization-validation/executable.js +480 -0
- package/ci/test-optimization-validation/generated-file-policy.js +63 -0
- package/ci/test-optimization-validation/generated-files.js +351 -0
- package/ci/test-optimization-validation/generated-verifier.js +196 -0
- package/ci/test-optimization-validation/init-probe-preload.js +163 -0
- package/ci/test-optimization-validation/init-probe.js +246 -0
- package/ci/test-optimization-validation/late-initialization.js +63 -0
- package/ci/test-optimization-validation/local-command.js +163 -0
- package/ci/test-optimization-validation/manifest-loader.js +133 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +738 -0
- package/ci/test-optimization-validation/manifest-schema.js +862 -0
- package/ci/test-optimization-validation/offline-fixtures.js +327 -0
- package/ci/test-optimization-validation/offline-output.js +406 -0
- package/ci/test-optimization-validation/payload-normalizer.js +72 -0
- package/ci/test-optimization-validation/plan-writer.js +1120 -0
- package/ci/test-optimization-validation/preflight-runner.js +114 -0
- package/ci/test-optimization-validation/redaction.js +331 -0
- package/ci/test-optimization-validation/report-writer.js +1508 -0
- package/ci/test-optimization-validation/safe-files.js +203 -0
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +159 -0
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +657 -0
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +780 -0
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +141 -0
- package/ci/test-optimization-validation/scenarios/helpers.js +539 -0
- package/ci/test-optimization-validation/scenarios/test-management.js +218 -0
- package/ci/test-optimization-validation/setup-runner.js +97 -0
- package/ci/test-optimization-validation/static-diagnosis.js +159 -0
- package/ci/test-optimization-validation/test-output.js +129 -0
- package/ci/test-optimization-validation-manifest.schema.json +1 -0
- package/ci/validate-test-optimization.js +3 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +121 -8
- package/index.electron.js +3 -0
- package/init.js +18 -0
- package/initialize.mjs +1 -1
- package/loader-hook.mjs +28 -18
- package/openfeature.d.ts +1 -0
- package/openfeature.js +4 -0
- package/package.json +15 -8
- package/packages/datadog-instrumentations/src/ai.js +37 -26
- package/packages/datadog-instrumentations/src/child_process.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +9 -3
- package/packages/datadog-instrumentations/src/cucumber.js +24 -10
- package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
- package/packages/datadog-instrumentations/src/express.js +20 -2
- package/packages/datadog-instrumentations/src/fastify.js +7 -11
- package/packages/datadog-instrumentations/src/grpc/server.js +18 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +27 -6
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +8 -8
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +28 -2
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +8 -8
- package/packages/datadog-instrumentations/src/http2/server.js +143 -17
- package/packages/datadog-instrumentations/src/jest.js +36 -4
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +0 -2
- package/packages/datadog-instrumentations/src/mocha/utils.js +0 -4
- package/packages/datadog-instrumentations/src/mongodb.js +3 -3
- package/packages/datadog-instrumentations/src/mongoose.js +3 -3
- package/packages/datadog-instrumentations/src/mquery.js +2 -2
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +24 -0
- package/packages/datadog-instrumentations/src/nyc.js +0 -2
- package/packages/datadog-instrumentations/src/oracledb.js +2 -2
- package/packages/datadog-instrumentations/src/pg.js +2 -2
- package/packages/datadog-instrumentations/src/playwright.js +159 -22
- package/packages/datadog-instrumentations/src/process.js +3 -0
- package/packages/datadog-instrumentations/src/router.js +191 -106
- package/packages/datadog-instrumentations/src/selenium.js +52 -26
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +2 -2
- package/packages/datadog-instrumentations/src/vitest-main.js +0 -2
- package/packages/datadog-instrumentations/src/ws.js +2 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +41 -16
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +21 -21
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +14 -8
- package/packages/datadog-plugin-aws-sdk/src/util.js +2 -24
- package/packages/datadog-plugin-cucumber/src/index.js +1 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +24 -62
- package/packages/datadog-plugin-cypress/src/index.js +6 -1
- package/packages/datadog-plugin-cypress/src/support.js +92 -26
- package/packages/datadog-plugin-electron/src/ipc.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +177 -59
- package/packages/datadog-plugin-graphql/src/parse.js +22 -1
- package/packages/datadog-plugin-graphql/src/request.js +32 -1
- package/packages/datadog-plugin-graphql/src/utils.js +42 -0
- package/packages/datadog-plugin-graphql/src/validate.js +15 -3
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +38 -6
- package/packages/datadog-plugin-jest/src/util.js +21 -6
- package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -1
- package/packages/datadog-plugin-langchain/src/handlers/language_models.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +177 -64
- package/packages/datadog-plugin-router/src/index.js +11 -2
- package/packages/datadog-plugin-selenium/src/index.js +5 -36
- package/packages/datadog-plugin-vitest/src/index.js +4 -2
- package/packages/datadog-plugin-ws/src/close.js +2 -1
- package/packages/datadog-plugin-ws/src/producer.js +2 -1
- package/packages/datadog-plugin-ws/src/receiver.js +2 -1
- package/packages/datadog-plugin-ws/src/server.js +2 -1
- package/packages/dd-trace/index.electron.js +3 -0
- package/packages/dd-trace/index.js +2 -37
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +3 -1
- package/packages/dd-trace/src/azure_metadata.js +2 -1
- package/packages/dd-trace/src/bootstrap.js +39 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +93 -28
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +160 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +288 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/payload-projection.js +84 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +369 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +60 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +55 -5
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +5 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +62 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -2
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +6 -2
- package/packages/dd-trace/src/ci-visibility/rum.js +7 -0
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +137 -9
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +173 -9
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +20 -0
- package/packages/dd-trace/src/config/helper.js +1 -0
- package/packages/dd-trace/src/config/index.js +10 -0
- package/packages/dd-trace/src/config/supported-configurations.json +83 -0
- package/packages/dd-trace/src/constants.js +7 -0
- package/packages/dd-trace/src/datastreams/pathway.js +6 -4
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/common/client-library-headers.js +21 -0
- package/packages/dd-trace/src/exporters/common/request.js +59 -30
- package/packages/dd-trace/src/exporters/common/url.js +15 -1
- package/packages/dd-trace/src/feature-registry.js +29 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +113 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +154 -0
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +283 -0
- package/packages/dd-trace/src/llmobs/experiments/index.js +152 -0
- package/packages/dd-trace/src/llmobs/experiments/noop.js +30 -0
- package/packages/dd-trace/src/llmobs/experiments/result.js +34 -0
- package/packages/dd-trace/src/llmobs/index.js +10 -2
- package/packages/dd-trace/src/llmobs/noop.js +6 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +20 -3
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +8 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +48 -14
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +43 -0
- package/packages/dd-trace/src/llmobs/sdk.js +17 -0
- package/packages/dd-trace/src/llmobs/tagger.js +79 -7
- package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
- package/packages/dd-trace/src/llmobs/util.js +32 -0
- package/packages/dd-trace/src/noop/proxy.js +5 -4
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +322 -0
- package/packages/dd-trace/src/openfeature/configuration_source.js +90 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -23
- package/packages/dd-trace/src/openfeature/index.js +0 -2
- package/packages/dd-trace/src/openfeature/noop.js +1 -28
- package/packages/dd-trace/src/openfeature/register.js +35 -0
- package/packages/dd-trace/src/openfeature/remote_config.js +15 -18
- package/packages/dd-trace/src/openfeature/require-provider.js +18 -0
- package/packages/dd-trace/src/opentelemetry/span-ending-hook.js +10 -0
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/opentracing/propagation/log.js +11 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +80 -14
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +10 -1
- package/packages/dd-trace/src/opentracing/tracer.js +7 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -6
- package/packages/dd-trace/src/plugins/util/git.js +3 -2
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +29 -5
- package/packages/dd-trace/src/plugins/util/test.js +65 -8
- package/packages/dd-trace/src/plugins/util/web.js +12 -0
- package/packages/dd-trace/src/proxy.js +99 -10
- package/packages/dd-trace/src/span_processor.js +5 -0
- package/packages/dd-trace/src/standalone/index.js +0 -36
- package/packages/dd-trace/src/telemetry/send-data.js +2 -2
- package/packages/dd-trace/src/util.js +26 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- 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
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +0 -17
|
@@ -144,8 +144,8 @@ addHook({ name: 'oracledb', versions: ['>=5'], file: 'lib/oracledb.js' }, oracle
|
|
|
144
144
|
shimmer.wrap(oracledb.Pool.prototype, 'getConnection', getConnection => {
|
|
145
145
|
return function wrappedGetConnection (...args) {
|
|
146
146
|
let callback
|
|
147
|
-
if (typeof args
|
|
148
|
-
callback = args
|
|
147
|
+
if (typeof args.at(-1) === 'function') {
|
|
148
|
+
callback = args.at(-1)
|
|
149
149
|
}
|
|
150
150
|
if (callback) {
|
|
151
151
|
args[args.length - 1] = shimmer.wrapFunction(callback, callback => (err, connection) => {
|
|
@@ -97,7 +97,7 @@ function wrapQuery (query) {
|
|
|
97
97
|
|
|
98
98
|
// Based on: https://github.com/brianc/node-postgres/blob/54eb0fa216aaccd727765641e7d1cf5da2bc483d/packages/pg/lib/client.js#L510
|
|
99
99
|
const reusingQuery = typeof pgQuery.submit === 'function'
|
|
100
|
-
const callback = args
|
|
100
|
+
const callback = args.at(-1)
|
|
101
101
|
|
|
102
102
|
finish(error)
|
|
103
103
|
|
|
@@ -197,7 +197,7 @@ function wrapPoolQuery (query) {
|
|
|
197
197
|
const ctx = { query: pgQuery, abortController }
|
|
198
198
|
|
|
199
199
|
return startPoolQueryCh.runStores(ctx, () => {
|
|
200
|
-
const cb = args
|
|
200
|
+
const cb = args.at(-1)
|
|
201
201
|
|
|
202
202
|
if (abortController.signal.aborted) {
|
|
203
203
|
const error = abortController.signal.reason || new Error('Aborted')
|
|
@@ -25,6 +25,9 @@ const log = require('../../dd-trace/src/log')
|
|
|
25
25
|
const {
|
|
26
26
|
getValueFromEnvSources,
|
|
27
27
|
} = require('../../dd-trace/src/config/helper')
|
|
28
|
+
const {
|
|
29
|
+
RUM_TEST_EXECUTION_ID_COOKIE_NAME: RUM_COOKIE_NAME,
|
|
30
|
+
} = require('../../dd-trace/src/ci-visibility/rum')
|
|
28
31
|
const { DD_MAJOR } = require('../../../version')
|
|
29
32
|
const { addHook, channel, tracingChannel } = require('./helpers/instrument')
|
|
30
33
|
|
|
@@ -33,6 +36,7 @@ const testFinishCh = channel('ci:playwright:test:finish')
|
|
|
33
36
|
const testSkipCh = channel('ci:playwright:test:skip')
|
|
34
37
|
|
|
35
38
|
const testSessionStartCh = channel('ci:playwright:session:start')
|
|
39
|
+
const testSessionConfigurationCh = channel('ci:playwright:session:configuration')
|
|
36
40
|
const testSessionFinishCh = channel('ci:playwright:session:finish')
|
|
37
41
|
|
|
38
42
|
const libraryConfigurationCh = channel('ci:playwright:library-configuration')
|
|
@@ -51,6 +55,9 @@ const dispatcherRunCh = tracingChannel('orchestrion:playwright:Dispatcher_run')
|
|
|
51
55
|
const dispatcherCreateWorkerCh = tracingChannel('orchestrion:playwright:Dispatcher_createWorker')
|
|
52
56
|
const processHostStartRunnerCh = tracingChannel('orchestrion:playwright:ProcessHost_startRunner')
|
|
53
57
|
const createRootSuiteCh = tracingChannel('orchestrion:playwright:createRootSuite')
|
|
58
|
+
const artifactsRecorderScreenshotPathCh =
|
|
59
|
+
tracingChannel('orchestrion:playwright:ArtifactsRecorder_createScreenshotAttachmentPath')
|
|
60
|
+
const snapshotRecorderScreenshotPathCh = tracingChannel('orchestrion:playwright:SnapshotRecorder_createAttachmentPath')
|
|
54
61
|
const pageGotoCh = tracingChannel('orchestrion:playwright-core:Page_goto')
|
|
55
62
|
|
|
56
63
|
const testToCtx = new WeakMap()
|
|
@@ -61,6 +68,8 @@ const testsToTestStatuses = new Map()
|
|
|
61
68
|
|
|
62
69
|
const RUM_FLUSH_WAIT_TIME = getValueFromEnvSources('DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS')
|
|
63
70
|
const DD_PROPERTIES_TIMEOUT = 5000
|
|
71
|
+
const isFailureScreenshotUploadEnabled =
|
|
72
|
+
getValueFromEnvSources('DD_TEST_FAILURE_SCREENSHOTS_ENABLED') === true
|
|
64
73
|
|
|
65
74
|
let applyRepeatEachIndex = null
|
|
66
75
|
|
|
@@ -115,8 +124,21 @@ const EFD_RETRY_COUNT_RESPONSE = 'ddEfdRetryCountResponse'
|
|
|
115
124
|
const DD_PROPERTIES_REQUEST = 'ddPropertiesRequest'
|
|
116
125
|
const DD_PROPERTIES_RESPONSE = 'ddProperties'
|
|
117
126
|
const kDdPlaywrightDisabledTestIds = Symbol('ddPlaywrightDisabledTestIds')
|
|
127
|
+
const kDdPlaywrightFailureScreenshots = Symbol('ddPlaywrightFailureScreenshots')
|
|
118
128
|
const kDdPlaywrightWorkerHostInstrumented = Symbol('ddPlaywrightWorkerHostInstrumented')
|
|
119
129
|
const kDdPlaywrightWorkerInstrumented = Symbol('ddPlaywrightWorkerInstrumented')
|
|
130
|
+
const PLAYWRIGHT_FAILURE_SCREENSHOT_PATH_RE = /(?:^|[\\/])test-failed-\d+\.png$/
|
|
131
|
+
const automaticFailureScreenshotPaths = new Set()
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Returns whether Playwright's internal screenshot recorder created an attachment.
|
|
135
|
+
*
|
|
136
|
+
* @param {object} attachment - Playwright attachment payload
|
|
137
|
+
* @returns {boolean}
|
|
138
|
+
*/
|
|
139
|
+
function isAutomaticFailureScreenshotAttachment (attachment) {
|
|
140
|
+
return typeof attachment?.path === 'string' && automaticFailureScreenshotPaths.delete(attachment.path)
|
|
141
|
+
}
|
|
120
142
|
|
|
121
143
|
function isValidKnownTests (receivedKnownTests) {
|
|
122
144
|
return !!receivedKnownTests.playwright
|
|
@@ -501,6 +523,23 @@ function getProjectsFromRunner (runner, configArg) {
|
|
|
501
523
|
})
|
|
502
524
|
}
|
|
503
525
|
|
|
526
|
+
/**
|
|
527
|
+
* Returns whether at least one Playwright project captures automatic screenshots for failed tests.
|
|
528
|
+
*
|
|
529
|
+
* @param {Array<object>} projects - Playwright projects with resolved use options
|
|
530
|
+
* @returns {boolean} Whether failure screenshot capture is enabled
|
|
531
|
+
*/
|
|
532
|
+
function isFailureScreenshotCaptureEnabled (projects) {
|
|
533
|
+
for (const project of projects) {
|
|
534
|
+
const screenshot = project.use?.screenshot
|
|
535
|
+
const mode = typeof screenshot === 'object' && screenshot !== null ? screenshot.mode : screenshot
|
|
536
|
+
if (mode === 'on' || mode === 'only-on-failure' || mode === 'on-first-failure') {
|
|
537
|
+
return true
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return false
|
|
541
|
+
}
|
|
542
|
+
|
|
504
543
|
function getProjectsFromDispatcher (dispatcher) {
|
|
505
544
|
const bundledConfig = dispatcher._testRun?.config?.config?.projects
|
|
506
545
|
if (bundledConfig) {
|
|
@@ -993,6 +1032,7 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
993
1032
|
|
|
994
1033
|
const projects = getProjectsFromDispatcher(dispatcher)
|
|
995
1034
|
sessionProjects = projects
|
|
1035
|
+
const automaticFailureScreenshotPathsByTestId = new Map()
|
|
996
1036
|
|
|
997
1037
|
if (disabledTestIds.size && !worker[kDdPlaywrightWorkerHostInstrumented] &&
|
|
998
1038
|
typeof worker.runTestGroup === 'function') {
|
|
@@ -1021,6 +1061,16 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
1021
1061
|
const shouldCreateTestSpan = test.expectedStatus === 'skipped'
|
|
1022
1062
|
testBeginHandler(test, browser, shouldCreateTestSpan)
|
|
1023
1063
|
})
|
|
1064
|
+
worker.on('attach', ({ testId, path, _ddIsAutomaticFailureScreenshot }) => {
|
|
1065
|
+
if (!_ddIsAutomaticFailureScreenshot) return
|
|
1066
|
+
|
|
1067
|
+
let screenshotPaths = automaticFailureScreenshotPathsByTestId.get(testId)
|
|
1068
|
+
if (!screenshotPaths) {
|
|
1069
|
+
screenshotPaths = new Set()
|
|
1070
|
+
automaticFailureScreenshotPathsByTestId.set(testId, screenshotPaths)
|
|
1071
|
+
}
|
|
1072
|
+
screenshotPaths.add(path)
|
|
1073
|
+
})
|
|
1024
1074
|
worker.on('testEnd', ({ testId, status, errors, annotations }) => {
|
|
1025
1075
|
const test = getTestByTestId(dispatcher, testId)
|
|
1026
1076
|
if (!test) return
|
|
@@ -1043,6 +1093,20 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
1043
1093
|
}
|
|
1044
1094
|
)
|
|
1045
1095
|
const testResult = test.results.at(-1)
|
|
1096
|
+
const automaticFailureScreenshotPaths = automaticFailureScreenshotPathsByTestId.get(testId)
|
|
1097
|
+
automaticFailureScreenshotPathsByTestId.delete(testId)
|
|
1098
|
+
if (testStatus === 'fail' && automaticFailureScreenshotPaths?.size && testResult?.attachments?.length) {
|
|
1099
|
+
const screenshots = []
|
|
1100
|
+
for (const attachment of testResult.attachments) {
|
|
1101
|
+
if (automaticFailureScreenshotPaths.has(attachment.path)) {
|
|
1102
|
+
screenshots.push(attachment)
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
if (screenshots.length) {
|
|
1106
|
+
worker[kDdPlaywrightFailureScreenshots] ??= []
|
|
1107
|
+
worker[kDdPlaywrightFailureScreenshots].push(screenshots)
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1046
1110
|
const isAtrRetry = testResult?.retry > 0 &&
|
|
1047
1111
|
isFlakyTestRetriesEnabled &&
|
|
1048
1112
|
!test._ddIsAttemptToFix &&
|
|
@@ -1145,9 +1209,16 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1145
1209
|
let onDone
|
|
1146
1210
|
|
|
1147
1211
|
rootDir = getRootDir(this, config)
|
|
1212
|
+
const projects = getProjectsFromRunner(this, config)
|
|
1213
|
+
const isFailureScreenshotEnabled = isFailureScreenshotCaptureEnabled(projects)
|
|
1148
1214
|
const processArgv = process.argv.slice(2).join(' ')
|
|
1149
1215
|
const command = `playwright ${processArgv}`
|
|
1150
|
-
testSessionStartCh.publish({
|
|
1216
|
+
testSessionStartCh.publish({
|
|
1217
|
+
command,
|
|
1218
|
+
frameworkVersion: playwrightVersion,
|
|
1219
|
+
rootDir,
|
|
1220
|
+
isFailureScreenshotEnabled,
|
|
1221
|
+
})
|
|
1151
1222
|
|
|
1152
1223
|
try {
|
|
1153
1224
|
const { err, libraryConfig } = await getChannelPromise(
|
|
@@ -1174,6 +1245,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1174
1245
|
log.error('Playwright session start error', e)
|
|
1175
1246
|
}
|
|
1176
1247
|
|
|
1248
|
+
testSessionConfigurationCh.publish({ isFailureScreenshotEnabled })
|
|
1249
|
+
|
|
1177
1250
|
const isTestOptimizationSupported = satisfies(playwrightVersion, MINIMUM_SUPPORTED_VERSION_RANGE_EFD)
|
|
1178
1251
|
const shouldGetKnownTests = isKnownTestsEnabled && isTestOptimizationSupported
|
|
1179
1252
|
const shouldGetTestManagementTests = isTestManagementTestsEnabled && isTestOptimizationSupported
|
|
@@ -1239,8 +1312,6 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1239
1312
|
}
|
|
1240
1313
|
}
|
|
1241
1314
|
|
|
1242
|
-
const projects = getProjectsFromRunner(this, config)
|
|
1243
|
-
|
|
1244
1315
|
// ATR and `--retries` are now compatible with Test Management.
|
|
1245
1316
|
// Test Management tests have their retries set to 0 at the test level,
|
|
1246
1317
|
// preventing them from being retried by ATR or `--retries`.
|
|
@@ -1288,7 +1359,7 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1288
1359
|
|
|
1289
1360
|
for (const [fqn, testStatuses] of testsToTestStatuses.entries()) {
|
|
1290
1361
|
// Only count as failed if the final status (after retries) is 'fail'
|
|
1291
|
-
const lastStatus = testStatuses
|
|
1362
|
+
const lastStatus = testStatuses.at(-1)
|
|
1292
1363
|
if (lastStatus === 'fail') {
|
|
1293
1364
|
totalFailedTestCount += 1
|
|
1294
1365
|
if (quarantinedButNotAttemptToFixFqns.has(fqn)) {
|
|
@@ -1439,6 +1510,23 @@ pageGotoCh.subscribe({
|
|
|
1439
1510
|
},
|
|
1440
1511
|
})
|
|
1441
1512
|
|
|
1513
|
+
/**
|
|
1514
|
+
* Records a path created by Playwright's automatic screenshot recorder.
|
|
1515
|
+
*
|
|
1516
|
+
* @param {object} ctx - Orchestrion context
|
|
1517
|
+
* @returns {void}
|
|
1518
|
+
*/
|
|
1519
|
+
function recordAutomaticFailureScreenshotPath (ctx) {
|
|
1520
|
+
if (isFailureScreenshotUploadEnabled &&
|
|
1521
|
+
typeof ctx.result === 'string' &&
|
|
1522
|
+
PLAYWRIGHT_FAILURE_SCREENSHOT_PATH_RE.test(ctx.result)) {
|
|
1523
|
+
automaticFailureScreenshotPaths.add(ctx.result)
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
artifactsRecorderScreenshotPathCh.subscribe({ end: recordAutomaticFailureScreenshotPath })
|
|
1528
|
+
snapshotRecorderScreenshotPathCh.subscribe({ end: recordAutomaticFailureScreenshotPath })
|
|
1529
|
+
|
|
1442
1530
|
if (DD_MAJOR < 6) { // <1.38.0 is only supported up to version 5
|
|
1443
1531
|
addHook({
|
|
1444
1532
|
name: '@playwright/test',
|
|
@@ -1750,7 +1838,10 @@ function finishProcessHostStartRunner (processHost) {
|
|
|
1750
1838
|
}
|
|
1751
1839
|
// These messages are [code, payload]. The payload is test data
|
|
1752
1840
|
if (Array.isArray(message) && message[0] === PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE) {
|
|
1753
|
-
workerReportCh.publish(
|
|
1841
|
+
workerReportCh.publish({
|
|
1842
|
+
serializedTraces: message[1],
|
|
1843
|
+
screenshots: processHost[kDdPlaywrightFailureScreenshots]?.shift(),
|
|
1844
|
+
})
|
|
1754
1845
|
}
|
|
1755
1846
|
})
|
|
1756
1847
|
}
|
|
@@ -1774,23 +1865,64 @@ addHook({
|
|
|
1774
1865
|
})
|
|
1775
1866
|
|
|
1776
1867
|
async function handlePageGoto (page) {
|
|
1868
|
+
if (!testPageGotoCh.hasSubscribers || !page || typeof page.evaluate !== 'function') {
|
|
1869
|
+
return
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
let rumState
|
|
1777
1873
|
try {
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1874
|
+
rumState = await page.evaluate(detectRum)
|
|
1875
|
+
} catch (error) {
|
|
1876
|
+
// Redirects and closed contexts can make page evaluation fail after a successful navigation.
|
|
1877
|
+
log.error('Playwright RUM detection error', error)
|
|
1878
|
+
return
|
|
1879
|
+
}
|
|
1783
1880
|
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
|
|
1881
|
+
if (!rumState) {
|
|
1882
|
+
return
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
const { isRumInstrumented, isRumActive, rumSamplingRate } = rumState
|
|
1886
|
+
if (isRumInstrumented && rumSamplingRate < 100 && !isRumActive) {
|
|
1887
|
+
log.debug("RUM was detected on the page, but it isn't active because the sampling rate is below 100%")
|
|
1888
|
+
}
|
|
1889
|
+
if (!isRumActive) {
|
|
1890
|
+
return
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
let browserVersion
|
|
1894
|
+
try {
|
|
1895
|
+
browserVersion = page.context().browser()?.version()
|
|
1896
|
+
} catch (error) {
|
|
1897
|
+
log.error('Playwright browser metadata error', error)
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
const context = {
|
|
1901
|
+
isRumActive,
|
|
1902
|
+
browserVersion,
|
|
1903
|
+
testExecutionId: undefined,
|
|
1904
|
+
}
|
|
1905
|
+
try {
|
|
1906
|
+
testPageGotoCh.publish(context)
|
|
1907
|
+
} catch (error) {
|
|
1908
|
+
log.error('Playwright RUM correlation channel error', error)
|
|
1909
|
+
return
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
if (!context.testExecutionId) {
|
|
1913
|
+
return
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
try {
|
|
1917
|
+
const domain = new URL(page.url()).hostname
|
|
1918
|
+
await page.context().addCookies([{
|
|
1919
|
+
name: RUM_COOKIE_NAME,
|
|
1920
|
+
value: context.testExecutionId,
|
|
1921
|
+
domain,
|
|
1922
|
+
path: '/',
|
|
1923
|
+
}])
|
|
1924
|
+
} catch (error) {
|
|
1925
|
+
log.error('Playwright RUM correlation cookie error', error)
|
|
1794
1926
|
}
|
|
1795
1927
|
}
|
|
1796
1928
|
|
|
@@ -1918,10 +2050,11 @@ function instrumentWorkerMainMethods (workerMain) {
|
|
|
1918
2050
|
if (url) {
|
|
1919
2051
|
const domain = new URL(url).hostname
|
|
1920
2052
|
await page.context().addCookies([{
|
|
1921
|
-
name:
|
|
2053
|
+
name: RUM_COOKIE_NAME,
|
|
1922
2054
|
value: '',
|
|
1923
2055
|
domain,
|
|
1924
2056
|
path: '/',
|
|
2057
|
+
expires: 0,
|
|
1925
2058
|
}])
|
|
1926
2059
|
} else {
|
|
1927
2060
|
log.error('RUM is active but page.url() is not available')
|
|
@@ -2042,7 +2175,9 @@ function instrumentWorkerMainMethods (workerMain) {
|
|
|
2042
2175
|
// We reproduce what happens in `Dispatcher#_onStepBegin` and `Dispatcher#_onStepEnd`,
|
|
2043
2176
|
// since `startTime` and `duration` are not available directly in the worker process
|
|
2044
2177
|
shimmer.wrap(workerMain, 'dispatchEvent', dispatchEvent => function (event, payload) {
|
|
2045
|
-
if (event === '
|
|
2178
|
+
if (event === 'testBegin' || event === 'testEnd') {
|
|
2179
|
+
automaticFailureScreenshotPaths.clear()
|
|
2180
|
+
} else if (event === 'stepBegin') {
|
|
2046
2181
|
stepInfoByStepId[payload.stepId] = {
|
|
2047
2182
|
startTime: payload.wallTime,
|
|
2048
2183
|
title: payload.title,
|
|
@@ -2058,6 +2193,8 @@ function instrumentWorkerMainMethods (workerMain) {
|
|
|
2058
2193
|
duration: payload.wallTime - stepInfo.startTime,
|
|
2059
2194
|
error: payload.error,
|
|
2060
2195
|
})
|
|
2196
|
+
} else if (event === 'attach' && isAutomaticFailureScreenshotAttachment(payload)) {
|
|
2197
|
+
payload._ddIsAutomaticFailureScreenshot = true
|
|
2061
2198
|
}
|
|
2062
2199
|
return dispatchEvent.apply(this, arguments)
|
|
2063
2200
|
})
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { syncBuiltinESMExports } = require('node:module')
|
|
4
|
+
|
|
3
5
|
const { channel } = require('dc-polyfill')
|
|
4
6
|
const shimmer = require('../../datadog-shimmer')
|
|
5
7
|
|
|
@@ -26,4 +28,5 @@ if (process.setUncaughtExceptionCaptureCallback) {
|
|
|
26
28
|
return result
|
|
27
29
|
}
|
|
28
30
|
})
|
|
31
|
+
syncBuiltinESMExports()
|
|
29
32
|
}
|