dd-trace 6.4.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/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 +10 -7
- package/packages/datadog-instrumentations/src/ai.js +8 -2
- 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 +20 -7
- package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
- package/packages/datadog-instrumentations/src/fastify.js +7 -11
- 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/jest.js +26 -0
- 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 +18 -8
- 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/util.js +2 -2
- package/packages/datadog-plugin-cucumber/src/index.js +1 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -57
- 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 +87 -45
- package/packages/datadog-plugin-graphql/src/validate.js +2 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- 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-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/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/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 +41 -3
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +7 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +1 -1
- 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 +168 -8
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +16 -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 +66 -0
- 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 +10 -3
- 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/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 +68 -0
- 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/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 +16 -27
- 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/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 +56 -4
- package/packages/dd-trace/src/proxy.js +84 -7
- package/packages/dd-trace/src/span_processor.js +5 -0
- package/packages/dd-trace/src/standalone/index.js +0 -14
- 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
|
@@ -4,19 +4,19 @@ const path = require('node:path')
|
|
|
4
4
|
|
|
5
5
|
// Build-time half of the optional-peer mechanism shared by the webpack and esbuild plugins.
|
|
6
6
|
//
|
|
7
|
-
// Runtime files load an optional peer through `requireOptionalPeer('name')`
|
|
8
|
-
//
|
|
9
|
-
// the feature never pulls in the peer's
|
|
10
|
-
// peer is installed at build time the user has opted in, so the plugins
|
|
11
|
-
// literal `require('name')` and let the bundler inline the peer, which
|
|
12
|
-
// the bundle is relocated
|
|
13
|
-
// build time stay opaque, so the rewrite is a no-op and the #8635 guarantee holds.
|
|
7
|
+
// Runtime files load an optional peer through a local `requireOptionalPeer('name')` wrapper.
|
|
8
|
+
// File tracers recognize its bound-require shape, while bundlers cannot follow the dynamic
|
|
9
|
+
// argument, so a build that does not opt into the feature never pulls in the peer's dependency
|
|
10
|
+
// chain (#8635). When the peer is installed at build time the user has opted in, so the plugins
|
|
11
|
+
// rewrite the call into a literal `require('name')` and let the bundler inline the peer, which
|
|
12
|
+
// keeps it working after the bundle is relocated without the peer on disk (#8980). Peers that
|
|
13
|
+
// are absent at build time stay opaque, so the rewrite is a no-op and the #8635 guarantee holds.
|
|
14
14
|
|
|
15
15
|
// Files that load an optional peer this way, as suffixes of the resolved module path. The same
|
|
16
16
|
// suffix matches the repo layout and `node_modules/dd-trace`. Add a file here to extend the
|
|
17
17
|
// mechanism to a new optional peer; no plugin change is needed.
|
|
18
18
|
const OPTIONAL_PEER_FILES = [
|
|
19
|
-
'packages/dd-trace/src/openfeature/
|
|
19
|
+
'packages/dd-trace/src/openfeature/require-provider.js',
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
// Captures the peer name from `requireOptionalPeer('name')` / `requireOptionalPeer("name")`.
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
// Playwright
|
|
4
|
-
// Keep these rewrites limited to
|
|
3
|
+
// Playwright keeps several hook targets in private local classes/functions.
|
|
4
|
+
// Keep these rewrites limited to bundled internals that addHook cannot wrap.
|
|
5
5
|
module.exports = [
|
|
6
|
+
{
|
|
7
|
+
module: {
|
|
8
|
+
name: 'playwright',
|
|
9
|
+
versionRange: '>=1.38.0 <1.51.0',
|
|
10
|
+
filePath: 'lib/index.js',
|
|
11
|
+
},
|
|
12
|
+
functionQuery: {
|
|
13
|
+
className: 'ArtifactsRecorder',
|
|
14
|
+
methodName: '_createScreenshotAttachmentPath',
|
|
15
|
+
kind: 'Sync',
|
|
16
|
+
},
|
|
17
|
+
channelName: 'ArtifactsRecorder_createScreenshotAttachmentPath',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
module: {
|
|
21
|
+
name: 'playwright',
|
|
22
|
+
versionRange: '>=1.51.0',
|
|
23
|
+
filePath: 'lib/index.js',
|
|
24
|
+
},
|
|
25
|
+
functionQuery: {
|
|
26
|
+
className: 'SnapshotRecorder',
|
|
27
|
+
methodName: '_createAttachmentPath',
|
|
28
|
+
kind: 'Sync',
|
|
29
|
+
},
|
|
30
|
+
channelName: 'SnapshotRecorder_createAttachmentPath',
|
|
31
|
+
},
|
|
6
32
|
{
|
|
7
33
|
module: {
|
|
8
34
|
name: 'playwright',
|
|
@@ -1858,6 +1858,26 @@ function resetSuiteSkippingRunState () {
|
|
|
1858
1858
|
coverageBackfillFiles = undefined
|
|
1859
1859
|
}
|
|
1860
1860
|
|
|
1861
|
+
function resetLibraryConfiguration () {
|
|
1862
|
+
knownTests = {}
|
|
1863
|
+
isCodeCoverageEnabled = false
|
|
1864
|
+
isCoverageReportUploadEnabled = false
|
|
1865
|
+
isItrEnabled = false
|
|
1866
|
+
isSuitesSkippingEnabled = false
|
|
1867
|
+
isEarlyFlakeDetectionEnabled = false
|
|
1868
|
+
earlyFlakeDetectionNumRetries = 0
|
|
1869
|
+
earlyFlakeDetectionSlowTestRetries = {}
|
|
1870
|
+
earlyFlakeDetectionFaultyThreshold = 30
|
|
1871
|
+
isEarlyFlakeDetectionFaulty = false
|
|
1872
|
+
isKnownTestsEnabled = false
|
|
1873
|
+
isTestManagementTestsEnabled = false
|
|
1874
|
+
testManagementTests = {}
|
|
1875
|
+
testManagementAttemptToFixRetries = 0
|
|
1876
|
+
isImpactedTestsEnabled = false
|
|
1877
|
+
modifiedFiles = {}
|
|
1878
|
+
repositoryRoot = undefined
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1861
1881
|
function applySuiteSkipping (originalTests, rootDir, frameworkVersion) {
|
|
1862
1882
|
if (!isItrEnabled || !isSuitesSkippingEnabled) return originalTests
|
|
1863
1883
|
|
|
@@ -2211,11 +2231,13 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
2211
2231
|
resetSuiteSkippingRunState()
|
|
2212
2232
|
hasFinishedTestSession = false
|
|
2213
2233
|
|
|
2234
|
+
let shouldResetLibraryConfiguration = true
|
|
2214
2235
|
try {
|
|
2215
2236
|
const { err, libraryConfig } = await getChannelPromise(libraryConfigurationCh, {
|
|
2216
2237
|
frameworkVersion: jestVersion,
|
|
2217
2238
|
})
|
|
2218
2239
|
if (!err) {
|
|
2240
|
+
shouldResetLibraryConfiguration = false
|
|
2219
2241
|
isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
|
|
2220
2242
|
isCoverageReportUploadEnabled = libraryConfig.isCoverageReportUploadEnabled
|
|
2221
2243
|
isItrEnabled = libraryConfig.isItrEnabled
|
|
@@ -2231,6 +2253,10 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
2231
2253
|
}
|
|
2232
2254
|
} catch (err) {
|
|
2233
2255
|
log.error('Jest library configuration error', err)
|
|
2256
|
+
} finally {
|
|
2257
|
+
if (shouldResetLibraryConfiguration) {
|
|
2258
|
+
resetLibraryConfiguration()
|
|
2259
|
+
}
|
|
2234
2260
|
}
|
|
2235
2261
|
|
|
2236
2262
|
const {
|
|
@@ -135,7 +135,7 @@ function wrapPoolMethod (createConnection) {
|
|
|
135
135
|
|
|
136
136
|
function wrapPoolGetConnectionMethod (getConnection) {
|
|
137
137
|
return function wrappedGetConnection (...args) {
|
|
138
|
-
const cb = args
|
|
138
|
+
const cb = args.at(-1)
|
|
139
139
|
if (typeof cb !== 'function') return getConnection.apply(this, args)
|
|
140
140
|
|
|
141
141
|
const ctx = {}
|
|
@@ -553,7 +553,6 @@ addHook({
|
|
|
553
553
|
|
|
554
554
|
const runner = run.apply(this, args)
|
|
555
555
|
|
|
556
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
557
556
|
this.files.forEach((path) => {
|
|
558
557
|
const isUnskippable = isMarkedAsUnskippable({ path })
|
|
559
558
|
if (isUnskippable) {
|
|
@@ -915,7 +914,6 @@ addHook({
|
|
|
915
914
|
status = 'skip'
|
|
916
915
|
} else {
|
|
917
916
|
// has to check every test in the test file
|
|
918
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
919
917
|
suitesInTestFile.forEach(suite => {
|
|
920
918
|
suite.eachTest(test => {
|
|
921
919
|
if (test.state === 'failed' || test.timedOut) {
|
|
@@ -229,7 +229,6 @@ function getSuitesByTestFile (root) {
|
|
|
229
229
|
suitesByTestFile[suite.file] = [suite]
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
233
232
|
suite.suites.forEach(suite => {
|
|
234
233
|
getSuites(suite)
|
|
235
234
|
})
|
|
@@ -920,7 +919,6 @@ function getOnPendingHandler () {
|
|
|
920
919
|
function getRunTestsWrapper (runTests, config) {
|
|
921
920
|
return function (suite) {
|
|
922
921
|
if (config.isTestManagementTestsEnabled) {
|
|
923
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
924
922
|
suite.tests.forEach((test) => {
|
|
925
923
|
const { isAttemptToFix, isDisabled, isQuarantined } = getTestProperties(test, config.testManagementTests)
|
|
926
924
|
if (isAttemptToFix && !test.isPending()) {
|
|
@@ -944,7 +942,6 @@ function getRunTestsWrapper (runTests, config) {
|
|
|
944
942
|
}
|
|
945
943
|
|
|
946
944
|
if (config.isImpactedTestsEnabled) {
|
|
947
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
948
945
|
suite.tests.forEach((test) => {
|
|
949
946
|
isModifiedCh.publish({
|
|
950
947
|
modifiedFiles: config.modifiedFiles,
|
|
@@ -968,7 +965,6 @@ function getRunTestsWrapper (runTests, config) {
|
|
|
968
965
|
|
|
969
966
|
if (config.isKnownTestsEnabled) {
|
|
970
967
|
// by the time we reach `this.on('test')`, it is too late. We need to add retries here
|
|
971
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
972
968
|
suite.tests.forEach((test) => {
|
|
973
969
|
if (!test.isPending() && isNewTest(test, config.knownTests)) {
|
|
974
970
|
test._ddIsNew = true
|
|
@@ -20,11 +20,11 @@ const collectionMethodsWithFilter = [
|
|
|
20
20
|
'replaceOne',
|
|
21
21
|
] // findOne is ignored because it calls to find
|
|
22
22
|
|
|
23
|
-
const collectionMethodsWithTwoFilters = [
|
|
23
|
+
const collectionMethodsWithTwoFilters = new Set([
|
|
24
24
|
'findOneAndUpdate',
|
|
25
25
|
'updateMany',
|
|
26
26
|
'updateOne',
|
|
27
|
-
]
|
|
27
|
+
])
|
|
28
28
|
|
|
29
29
|
const startCh = channel('datadog:mongodb:collection:filter:start')
|
|
30
30
|
|
|
@@ -36,7 +36,7 @@ addHook({ name: 'mongodb', versions: ['>=3.3 <5', '5', '>=6'] }, mongodb => {
|
|
|
36
36
|
for (const methodName of [...collectionMethodsWithFilter, ...collectionMethodsWithTwoFilters]) {
|
|
37
37
|
if (!(methodName in mongodb.Collection.prototype)) continue
|
|
38
38
|
|
|
39
|
-
const useTwoArguments = collectionMethodsWithTwoFilters.
|
|
39
|
+
const useTwoArguments = collectionMethodsWithTwoFilters.has(methodName)
|
|
40
40
|
|
|
41
41
|
shimmer.wrap(mongodb.Collection.prototype, methodName, method => {
|
|
42
42
|
return function (...args) {
|
|
@@ -55,11 +55,11 @@ const collectionMethodsWithFilter = [
|
|
|
55
55
|
'remove',
|
|
56
56
|
]
|
|
57
57
|
|
|
58
|
-
const collectionMethodsWithTwoFilters = [
|
|
58
|
+
const collectionMethodsWithTwoFilters = new Set([
|
|
59
59
|
'findOneAndUpdate',
|
|
60
60
|
'updateMany',
|
|
61
61
|
'updateOne',
|
|
62
|
-
]
|
|
62
|
+
])
|
|
63
63
|
|
|
64
64
|
addHook({
|
|
65
65
|
name: 'mongoose',
|
|
@@ -67,7 +67,7 @@ addHook({
|
|
|
67
67
|
file: 'lib/model.js',
|
|
68
68
|
}, Model => {
|
|
69
69
|
for (const methodName of [...collectionMethodsWithFilter, ...collectionMethodsWithTwoFilters]) {
|
|
70
|
-
const useTwoArguments = collectionMethodsWithTwoFilters.
|
|
70
|
+
const useTwoArguments = collectionMethodsWithTwoFilters.has(methodName)
|
|
71
71
|
if (!(methodName in Model)) continue
|
|
72
72
|
|
|
73
73
|
shimmer.wrap(Model, methodName, method => {
|
|
@@ -20,14 +20,14 @@ const methods = [
|
|
|
20
20
|
'where',
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
-
const methodsOptionalArgs = ['findOneAndUpdate']
|
|
23
|
+
const methodsOptionalArgs = new Set(['findOneAndUpdate'])
|
|
24
24
|
|
|
25
25
|
function getFilters (args, methodName) {
|
|
26
26
|
const [arg0, arg1] = args
|
|
27
27
|
|
|
28
28
|
const filters = arg0 !== null && typeof arg0 === 'object' ? [arg0] : []
|
|
29
29
|
|
|
30
|
-
if (arg1 !== null && typeof arg1 === 'object' && methodsOptionalArgs.
|
|
30
|
+
if (arg1 !== null && typeof arg1 === 'object' && methodsOptionalArgs.has(methodName)) {
|
|
31
31
|
filters.push(arg1)
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -84,7 +84,7 @@ addHook({ name: 'mysql', file: 'lib/Pool.js', versions: ['>=2'] }, Pool => {
|
|
|
84
84
|
const finish = () => finishPoolQueryCh.publish(ctx)
|
|
85
85
|
|
|
86
86
|
return startPoolQueryCh.runStores(ctx, () => {
|
|
87
|
-
const cb = args
|
|
87
|
+
const cb = args.at(-1)
|
|
88
88
|
if (typeof cb === 'function') {
|
|
89
89
|
args[args.length - 1] = shimmer.wrapCallback(cb, cb => function (...args) {
|
|
90
90
|
return finishPoolQueryCh.runStores(ctx, cb, this, ...args)
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
+
const nomenclature = require('../../dd-trace/src/service-naming')
|
|
5
|
+
const spanEndingHook = require('../../dd-trace/src/opentelemetry/span-ending-hook')
|
|
6
|
+
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
4
7
|
const { channel, addHook } = require('./helpers/instrument')
|
|
5
8
|
|
|
6
9
|
const startChannel = channel('apm:next:request:start')
|
|
@@ -21,6 +24,27 @@ const NEXT_REQUEST_META = Symbol.for('NextInternalRequestMeta')
|
|
|
21
24
|
const META_IS_MIDDLEWARE = 'middlewareInvoke'
|
|
22
25
|
const encounteredMiddleware = new WeakSet()
|
|
23
26
|
|
|
27
|
+
// `next.span_type` value Next.js sets on its own OTel root request span; the whole detection surface.
|
|
28
|
+
const NEXT_BASE_SERVER_HANDLE_REQUEST = 'BaseServer.handleRequest'
|
|
29
|
+
|
|
30
|
+
// In OTel-bridge mode (`plugins: false` + `new tracer.TracerProvider().register()`) Next emits its
|
|
31
|
+
// own OTel spans and renames the root request span to `${method} ${route}` at finish, which the
|
|
32
|
+
// bridge routes into the DD operation name and leaves the resource as the bare method — the reverse
|
|
33
|
+
// of Datadog's contract. Correct it via the bridge's pre-finish hook. See span-ending-hook.js.
|
|
34
|
+
spanEndingHook.hook = (ddSpan) => {
|
|
35
|
+
const tags = ddSpan.context().getTags()
|
|
36
|
+
if (tags['next.span_type'] !== NEXT_BASE_SERVER_HANDLE_REQUEST) return
|
|
37
|
+
|
|
38
|
+
const method = tags['http.method']
|
|
39
|
+
const route = tags['next.route'] ?? tags['http.route']
|
|
40
|
+
// Next already wrote the RSC-aware `${method} ${route}` into `next.span_name`; prefer it so we
|
|
41
|
+
// mirror Next's own naming, and only construct the resource when it is absent.
|
|
42
|
+
const resource = tags['next.span_name'] ?? (route ? `${method} ${route}` : method)
|
|
43
|
+
|
|
44
|
+
ddSpan.setOperationName(nomenclature.opName('web', 'server', 'next'))
|
|
45
|
+
ddSpan.setTag(RESOURCE_NAME, resource)
|
|
46
|
+
}
|
|
47
|
+
|
|
24
48
|
function wrapHandleRequest (handleRequest) {
|
|
25
49
|
return function (req, res, pathname, query) {
|
|
26
50
|
return instrument(req, res, () => handleRequest.apply(this, arguments))
|
|
@@ -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
|
}
|