dd-trace 5.102.0 → 5.103.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/ext/exporters.js +1 -0
- package/package.json +12 -11
- package/packages/datadog-esbuild/src/utils.js +2 -2
- package/packages/datadog-instrumentations/src/ai.js +1 -1
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +32 -15
- package/packages/datadog-instrumentations/src/couchbase.js +69 -220
- package/packages/datadog-instrumentations/src/cucumber.js +1 -1
- package/packages/datadog-instrumentations/src/electron/preload.js +42 -0
- package/packages/datadog-instrumentations/src/electron.js +240 -0
- package/packages/datadog-instrumentations/src/fetch.js +5 -5
- package/packages/datadog-instrumentations/src/graphql.js +13 -12
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/kafka.js +41 -0
- package/packages/datadog-instrumentations/src/ioredis.js +16 -12
- package/packages/datadog-instrumentations/src/jest.js +351 -50
- package/packages/datadog-instrumentations/src/kafkajs.js +164 -173
- package/packages/datadog-instrumentations/src/mocha/main.js +73 -1
- package/packages/datadog-instrumentations/src/mongodb-core.js +33 -8
- package/packages/datadog-instrumentations/src/pg.js +24 -10
- package/packages/datadog-instrumentations/src/playwright.js +427 -55
- package/packages/datadog-instrumentations/src/redis.js +19 -10
- package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
- package/packages/datadog-plugin-aws-sdk/src/base.js +18 -24
- package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
- package/packages/datadog-plugin-couchbase/src/index.js +58 -52
- package/packages/datadog-plugin-cucumber/src/index.js +1 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +214 -22
- package/packages/datadog-plugin-cypress/src/support.js +13 -1
- package/packages/datadog-plugin-electron/src/index.js +17 -0
- package/packages/datadog-plugin-electron/src/ipc.js +143 -0
- package/packages/datadog-plugin-electron/src/net.js +82 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
- package/packages/datadog-plugin-graphql/src/execute.js +6 -28
- package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
- package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
- package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
- package/packages/datadog-plugin-graphql/src/utils.js +29 -0
- package/packages/datadog-plugin-grpc/src/client.js +6 -7
- package/packages/datadog-plugin-grpc/src/util.js +57 -22
- package/packages/datadog-plugin-http/src/client.js +2 -2
- package/packages/datadog-plugin-jest/src/index.js +92 -50
- package/packages/datadog-plugin-mocha/src/index.js +1 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +36 -70
- package/packages/datadog-plugin-mysql/src/index.js +1 -1
- package/packages/datadog-plugin-openai/src/services.js +2 -1
- package/packages/datadog-plugin-pg/src/index.js +3 -3
- package/packages/datadog-plugin-playwright/src/index.js +4 -0
- package/packages/datadog-plugin-redis/src/index.js +18 -23
- package/packages/dd-trace/src/aiguard/index.js +3 -1
- package/packages/dd-trace/src/aiguard/sdk.js +36 -30
- package/packages/dd-trace/src/aiguard/tags.js +20 -11
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
- package/packages/dd-trace/src/azure_metadata.js +17 -6
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +3 -14
- package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -1
- package/packages/dd-trace/src/config/helper.js +4 -0
- package/packages/dd-trace/src/config/index.js +2 -2
- package/packages/dd-trace/src/config/major-overrides.js +98 -0
- package/packages/dd-trace/src/config/parsers.js +7 -1
- package/packages/dd-trace/src/config/supported-configurations.json +51 -38
- package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
- package/packages/dd-trace/src/datastreams/manager.js +1 -1
- package/packages/dd-trace/src/datastreams/processor.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
- package/packages/dd-trace/src/debugger/index.js +7 -7
- package/packages/dd-trace/src/dogstatsd.js +2 -2
- package/packages/dd-trace/src/encode/0.4.js +45 -54
- package/packages/dd-trace/src/encode/0.5.js +34 -3
- package/packages/dd-trace/src/encode/agentless-json.js +1 -1
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/agent/index.js +2 -1
- package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
- package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
- package/packages/dd-trace/src/exporters/common/request.js +1 -1
- package/packages/dd-trace/src/exporters/electron/index.js +49 -0
- package/packages/dd-trace/src/external-logger/src/index.js +2 -1
- package/packages/dd-trace/src/git_metadata.js +10 -8
- package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
- package/packages/dd-trace/src/lambda/index.js +62 -14
- package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
- package/packages/dd-trace/src/llmobs/index.js +13 -2
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
- package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
- package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +49 -4
- package/packages/dd-trace/src/plugins/database.js +54 -12
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/plugin.js +2 -4
- package/packages/dd-trace/src/plugins/util/ci.js +8 -8
- package/packages/dd-trace/src/plugins/util/git-cache.js +20 -18
- package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
- package/packages/dd-trace/src/plugins/util/test.js +37 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -15
- package/packages/dd-trace/src/priority_sampler.js +1 -1
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
- package/packages/dd-trace/src/rate_limiter.js +1 -1
- package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
- package/packages/dd-trace/src/ritm.js +2 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
- package/packages/dd-trace/src/serverless.js +5 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +20 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +20 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
- package/packages/dd-trace/src/span_stats.js +1 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
- package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
// Capture real timers at module load time, before any test can install fake timers.
|
|
4
4
|
const realSetTimeout = setTimeout
|
|
5
5
|
|
|
6
|
+
const { readFileSync } = require('node:fs')
|
|
7
|
+
const { builtinModules } = require('node:module')
|
|
6
8
|
const path = require('path')
|
|
7
9
|
const satisfies = require('../../../vendor/dist/semifies')
|
|
8
10
|
const { DD_MAJOR } = require('../../../version')
|
|
9
11
|
const shimmer = require('../../datadog-shimmer')
|
|
12
|
+
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
10
13
|
const log = require('../../dd-trace/src/log')
|
|
11
14
|
const {
|
|
12
15
|
getCoveredFilenamesFromCoverage,
|
|
@@ -74,6 +77,7 @@ const CHILD_MESSAGE_CALL = 1
|
|
|
74
77
|
|
|
75
78
|
// Maximum time we'll wait for the tracer to flush
|
|
76
79
|
const FLUSH_TIMEOUT = 10_000
|
|
80
|
+
const isJestWorker = !!getEnvironmentVariable('JEST_WORKER_ID')
|
|
77
81
|
|
|
78
82
|
// https://github.com/jestjs/jest/blob/41f842a46bb2691f828c3a5f27fc1d6290495b82/packages/jest-circus/src/types.ts#L9C8-L9C54
|
|
79
83
|
const RETRY_TIMES = Symbol.for('RETRY_TIMES')
|
|
@@ -101,6 +105,8 @@ let testManagementTests = {}
|
|
|
101
105
|
let testManagementAttemptToFixRetries = 0
|
|
102
106
|
let isImpactedTestsEnabled = false
|
|
103
107
|
let modifiedFiles = {}
|
|
108
|
+
let activeTestSuiteAbsolutePath
|
|
109
|
+
let isConsoleErrorWrapped = false
|
|
104
110
|
|
|
105
111
|
const testContexts = new WeakMap()
|
|
106
112
|
const originalTestFns = new WeakMap()
|
|
@@ -124,7 +130,12 @@ const efdNewTestCandidates = new Set()
|
|
|
124
130
|
// Tests that are genuinely new (not in known tests list).
|
|
125
131
|
const newTests = new Set()
|
|
126
132
|
const testSuiteAbsolutePathsWithFastCheck = new Set()
|
|
133
|
+
const testSuiteFastCheckUsage = new Map()
|
|
127
134
|
const testSuiteJestObjects = new Map()
|
|
135
|
+
const wrappedJestGlobals = new WeakSet()
|
|
136
|
+
const wrappedJestObjects = new WeakSet()
|
|
137
|
+
const wrappedWorkerInitializers = new WeakSet()
|
|
138
|
+
const publishedRuntimeReferenceErrors = new WeakMap()
|
|
128
139
|
|
|
129
140
|
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
130
141
|
const ATR_RETRY_SUPPRESSION_FLAG = '_ddDisableAtrRetry'
|
|
@@ -303,6 +314,26 @@ function getAttemptToFixExecutionsFromJestResults (result) {
|
|
|
303
314
|
return executions
|
|
304
315
|
}
|
|
305
316
|
|
|
317
|
+
function wrapConsoleErrorForJestReferenceErrors () {
|
|
318
|
+
if (isConsoleErrorWrapped) return
|
|
319
|
+
|
|
320
|
+
isConsoleErrorWrapped = true
|
|
321
|
+
// eslint-disable-next-line no-console
|
|
322
|
+
const originalConsoleError = console.error
|
|
323
|
+
// eslint-disable-next-line no-console
|
|
324
|
+
console.error = function () {
|
|
325
|
+
const [message] = arguments
|
|
326
|
+
if (
|
|
327
|
+
typeof message === 'string' &&
|
|
328
|
+
message.includes('Jest environment has been torn down') &&
|
|
329
|
+
activeTestSuiteAbsolutePath
|
|
330
|
+
) {
|
|
331
|
+
publishRuntimeReferenceError({ _testPath: activeTestSuiteAbsolutePath }, message)
|
|
332
|
+
}
|
|
333
|
+
return originalConsoleError.apply(this, arguments)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
306
337
|
function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
307
338
|
return class DatadogEnvironment extends BaseEnvironment {
|
|
308
339
|
constructor (config, context) {
|
|
@@ -314,6 +345,9 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
314
345
|
this.global._ddtrace = global._ddtrace
|
|
315
346
|
this.hasSnapshotTests = undefined
|
|
316
347
|
this.testSuiteAbsolutePath = context.testPath
|
|
348
|
+
activeTestSuiteAbsolutePath = this.testSuiteAbsolutePath
|
|
349
|
+
wrapConsoleErrorForJestReferenceErrors()
|
|
350
|
+
this.globalConfig = config.globalConfig
|
|
317
351
|
|
|
318
352
|
this.displayName = config.projectConfig?.displayName?.name || config.displayName
|
|
319
353
|
this.testEnvironmentOptions = getTestEnvironmentOptions(config)
|
|
@@ -423,6 +457,10 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
423
457
|
*/
|
|
424
458
|
resetMockState () {
|
|
425
459
|
try {
|
|
460
|
+
if (this.moduleMocker?.clearAllMocks) {
|
|
461
|
+
this.moduleMocker.clearAllMocks()
|
|
462
|
+
return
|
|
463
|
+
}
|
|
426
464
|
const jestObject = testSuiteJestObjects.get(this.testSuiteAbsolutePath)
|
|
427
465
|
if (jestObject?.clearAllMocks) {
|
|
428
466
|
jestObject.clearAllMocks()
|
|
@@ -504,7 +542,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
504
542
|
}
|
|
505
543
|
|
|
506
544
|
getShouldStripSeedFromTestName () {
|
|
507
|
-
return
|
|
545
|
+
return doesTestSuiteUseFastCheck(this.testSuiteAbsolutePath)
|
|
508
546
|
}
|
|
509
547
|
|
|
510
548
|
// At the `add_test` event we don't have the test object yet, so we can't use it
|
|
@@ -843,8 +881,8 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
843
881
|
const willBeRetriedByFailedTestReplay = numRetries > 0 && numTestExecutions - 1 < numRetries
|
|
844
882
|
const mightHitBreakpoint = this.isDiEnabled && numTestExecutions >= 2
|
|
845
883
|
|
|
846
|
-
// For quarantined tests,
|
|
847
|
-
//
|
|
884
|
+
// For quarantined tests, track failures so the session can be marked as passing later,
|
|
885
|
+
// and suppress errors so Jest does not mark the test suite as failing.
|
|
848
886
|
// The actual status ('fail') is already captured above for dd-trace reporting.
|
|
849
887
|
// Only suppress on the final execution — not when ATR/EFD/ATF will retry the test.
|
|
850
888
|
if (!event.test?.[ATR_RETRY_SUPPRESSION_FLAG] && !willBeRetriedByFailedTestReplay) {
|
|
@@ -1055,7 +1093,19 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
1055
1093
|
}
|
|
1056
1094
|
}
|
|
1057
1095
|
}
|
|
1058
|
-
|
|
1096
|
+
const clearActiveTestSuite = () => {
|
|
1097
|
+
realSetTimeout(() => {
|
|
1098
|
+
if (activeTestSuiteAbsolutePath === this.testSuiteAbsolutePath) {
|
|
1099
|
+
activeTestSuiteAbsolutePath = undefined
|
|
1100
|
+
}
|
|
1101
|
+
}, 0)
|
|
1102
|
+
}
|
|
1103
|
+
const result = super.teardown()
|
|
1104
|
+
if (result?.then) {
|
|
1105
|
+
return result.finally(clearActiveTestSuite)
|
|
1106
|
+
}
|
|
1107
|
+
clearActiveTestSuite()
|
|
1108
|
+
return result
|
|
1059
1109
|
}
|
|
1060
1110
|
}
|
|
1061
1111
|
}
|
|
@@ -1492,7 +1542,8 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
1492
1542
|
const timeoutPromise = new Promise((resolve) => {
|
|
1493
1543
|
timeoutId = realSetTimeout(() => {
|
|
1494
1544
|
resolve('timeout')
|
|
1495
|
-
}, FLUSH_TIMEOUT)
|
|
1545
|
+
}, FLUSH_TIMEOUT)
|
|
1546
|
+
timeoutId.unref?.()
|
|
1496
1547
|
})
|
|
1497
1548
|
|
|
1498
1549
|
testSessionFinishCh.publish({
|
|
@@ -1557,6 +1608,33 @@ function coverageReporterWrapper (coverageReporter) {
|
|
|
1557
1608
|
return coverageReporter
|
|
1558
1609
|
}
|
|
1559
1610
|
|
|
1611
|
+
function shouldWaitForTestSuiteFinish (environment) {
|
|
1612
|
+
return isJestWorker && environment.globalConfig?.workerIdleMemoryLimit !== undefined
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
function publishTestSuiteFinish (payload, waitForFinish) {
|
|
1616
|
+
if (!testSuiteFinishCh.hasSubscribers) return
|
|
1617
|
+
|
|
1618
|
+
if (!waitForFinish) {
|
|
1619
|
+
testSuiteFinishCh.publish(payload)
|
|
1620
|
+
return
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
return new Promise(resolve => {
|
|
1624
|
+
testSuiteFinishCh.publish({
|
|
1625
|
+
...payload,
|
|
1626
|
+
waitForFinish,
|
|
1627
|
+
onDone: resolve,
|
|
1628
|
+
})
|
|
1629
|
+
})
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
function cleanupTestSuiteState (testSuiteAbsolutePath) {
|
|
1633
|
+
testSuiteMockedFiles.delete(testSuiteAbsolutePath)
|
|
1634
|
+
testSuiteFastCheckUsage.delete(testSuiteAbsolutePath)
|
|
1635
|
+
testSuiteJestObjects.delete(testSuiteAbsolutePath)
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1560
1638
|
addHook({
|
|
1561
1639
|
name: '@jest/core',
|
|
1562
1640
|
file: 'build/TestScheduler.js',
|
|
@@ -1675,7 +1753,7 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
|
1675
1753
|
const getFilesWithPath = (files) => files.map(file => getTestSuitePath(file, root))
|
|
1676
1754
|
|
|
1677
1755
|
const coverageFiles = getFilesWithPath(getCoveredFilenamesFromCoverage(environment.global.__coverage__))
|
|
1678
|
-
const mockedFiles = getFilesWithPath(
|
|
1756
|
+
const mockedFiles = getFilesWithPath(getMockedFiles(environment.testSuiteAbsolutePath))
|
|
1679
1757
|
|
|
1680
1758
|
testSuiteCodeCoverageCh.publish({
|
|
1681
1759
|
coverageFiles,
|
|
@@ -1684,19 +1762,51 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
|
1684
1762
|
testSuiteAbsolutePath: environment.testSuiteAbsolutePath,
|
|
1685
1763
|
})
|
|
1686
1764
|
}
|
|
1687
|
-
|
|
1765
|
+
const waitForFinish = shouldWaitForTestSuiteFinish(environment)
|
|
1766
|
+
const finishPayload = {
|
|
1767
|
+
status,
|
|
1768
|
+
errorMessage,
|
|
1769
|
+
testSuiteAbsolutePath: environment.testSuiteAbsolutePath,
|
|
1770
|
+
}
|
|
1771
|
+
if (waitForFinish) {
|
|
1772
|
+
const finishPromise = publishTestSuiteFinish(finishPayload, waitForFinish)
|
|
1773
|
+
if (finishPromise) {
|
|
1774
|
+
return finishPromise.then(() => {
|
|
1775
|
+
// Cleanup per-suite state to avoid memory leaks
|
|
1776
|
+
cleanupTestSuiteState(environment.testSuiteAbsolutePath)
|
|
1777
|
+
|
|
1778
|
+
return suiteResults
|
|
1779
|
+
})
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
publishTestSuiteFinish(finishPayload, waitForFinish)
|
|
1688
1783
|
|
|
1689
1784
|
// Cleanup per-suite state to avoid memory leaks
|
|
1690
|
-
|
|
1691
|
-
testSuiteJestObjects.delete(environment.testSuiteAbsolutePath)
|
|
1785
|
+
cleanupTestSuiteState(environment.testSuiteAbsolutePath)
|
|
1692
1786
|
|
|
1693
1787
|
return suiteResults
|
|
1694
1788
|
}).catch(error => {
|
|
1695
|
-
|
|
1789
|
+
const waitForFinish = shouldWaitForTestSuiteFinish(environment)
|
|
1790
|
+
const finishPayload = {
|
|
1791
|
+
status: 'fail',
|
|
1792
|
+
error,
|
|
1793
|
+
testSuiteAbsolutePath: environment.testSuiteAbsolutePath,
|
|
1794
|
+
}
|
|
1795
|
+
if (waitForFinish) {
|
|
1796
|
+
const finishPromise = publishTestSuiteFinish(finishPayload, waitForFinish)
|
|
1797
|
+
if (finishPromise) {
|
|
1798
|
+
return finishPromise.then(() => {
|
|
1799
|
+
// Cleanup per-suite state to avoid memory leaks
|
|
1800
|
+
cleanupTestSuiteState(environment.testSuiteAbsolutePath)
|
|
1801
|
+
|
|
1802
|
+
throw error
|
|
1803
|
+
})
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
publishTestSuiteFinish(finishPayload, waitForFinish)
|
|
1696
1807
|
|
|
1697
1808
|
// Cleanup per-suite state to avoid memory leaks
|
|
1698
|
-
|
|
1699
|
-
testSuiteJestObjects.delete(environment.testSuiteAbsolutePath)
|
|
1809
|
+
cleanupTestSuiteState(environment.testSuiteAbsolutePath)
|
|
1700
1810
|
|
|
1701
1811
|
throw error
|
|
1702
1812
|
})
|
|
@@ -1794,6 +1904,7 @@ const DD_TEST_ENVIRONMENT_OPTION_KEYS = [
|
|
|
1794
1904
|
'_ddRepositoryRoot',
|
|
1795
1905
|
'_ddIsFlakyTestRetriesEnabled',
|
|
1796
1906
|
'_ddFlakyTestRetriesCount',
|
|
1907
|
+
'_ddItrSkippingEnabledTags',
|
|
1797
1908
|
'_ddIsDiEnabled',
|
|
1798
1909
|
'_ddIsKnownTestsEnabled',
|
|
1799
1910
|
'_ddIsTestManagementTestsEnabled',
|
|
@@ -1904,39 +2015,195 @@ const LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = new Set([
|
|
|
1904
2015
|
'winston',
|
|
1905
2016
|
])
|
|
1906
2017
|
|
|
2018
|
+
function recordMockedFile (suiteFilePath, moduleName) {
|
|
2019
|
+
if (!suiteFilePath || typeof moduleName !== 'string') return
|
|
2020
|
+
|
|
2021
|
+
const existingMockedFiles = testSuiteMockedFiles.get(suiteFilePath) || []
|
|
2022
|
+
const suiteDir = path.dirname(suiteFilePath)
|
|
2023
|
+
const mockPath = path.resolve(suiteDir, moduleName)
|
|
2024
|
+
existingMockedFiles.push(mockPath)
|
|
2025
|
+
testSuiteMockedFiles.set(suiteFilePath, existingMockedFiles)
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
const JEST_STATIC_MOCK_CALL_RE = /\bjest\.(?:mock|doMock|unstable_mockModule)\(\s*(['"`])([^'"`]+)\1/g
|
|
2029
|
+
|
|
2030
|
+
function getStaticMockedFiles (suiteFilePath) {
|
|
2031
|
+
if (!suiteFilePath) return []
|
|
2032
|
+
|
|
2033
|
+
const mockedFiles = []
|
|
2034
|
+
try {
|
|
2035
|
+
const source = readFileSync(suiteFilePath, 'utf8')
|
|
2036
|
+
let match
|
|
2037
|
+
JEST_STATIC_MOCK_CALL_RE.lastIndex = 0
|
|
2038
|
+
while ((match = JEST_STATIC_MOCK_CALL_RE.exec(source)) !== null) {
|
|
2039
|
+
mockedFiles.push(path.resolve(path.dirname(suiteFilePath), match[2]))
|
|
2040
|
+
}
|
|
2041
|
+
} catch {
|
|
2042
|
+
// ignore errors
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
return mockedFiles
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
function getMockedFiles (suiteFilePath) {
|
|
2049
|
+
const mockedFiles = testSuiteMockedFiles.get(suiteFilePath)
|
|
2050
|
+
if (mockedFiles?.length) {
|
|
2051
|
+
return mockedFiles
|
|
2052
|
+
}
|
|
2053
|
+
return getStaticMockedFiles(suiteFilePath)
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
function wrapJestObject (jestObject, suiteFilePath) {
|
|
2057
|
+
if (!jestObject || !suiteFilePath || wrappedJestObjects.has(jestObject)) return
|
|
2058
|
+
|
|
2059
|
+
testSuiteJestObjects.set(suiteFilePath, jestObject)
|
|
2060
|
+
wrappedJestObjects.add(jestObject)
|
|
2061
|
+
|
|
2062
|
+
shimmer.wrap(jestObject, 'mock', mock => function (moduleName) {
|
|
2063
|
+
// If the library is mocked with `jest.mock`, we don't want to bypass jest's own require engine
|
|
2064
|
+
if (LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
|
|
2065
|
+
LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.delete(moduleName)
|
|
2066
|
+
}
|
|
2067
|
+
recordMockedFile(suiteFilePath, moduleName)
|
|
2068
|
+
return mock.apply(this, arguments)
|
|
2069
|
+
})
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
function wrapJestGlobalsForRuntime (runtime) {
|
|
2073
|
+
const jestGlobals = runtime?.jestGlobals
|
|
2074
|
+
if (!jestGlobals || wrappedJestGlobals.has(jestGlobals) || typeof jestGlobals.jestObjectFor !== 'function') {
|
|
2075
|
+
return
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
wrappedJestGlobals.add(jestGlobals)
|
|
2079
|
+
shimmer.wrap(jestGlobals, 'jestObjectFor', jestObjectFor => function (from) {
|
|
2080
|
+
const jestObject = jestObjectFor.apply(this, arguments)
|
|
2081
|
+
wrapJestObject(jestObject, from)
|
|
2082
|
+
return jestObject
|
|
2083
|
+
})
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
function recordFastCheckUsage (runtime, from, moduleName) {
|
|
2087
|
+
if (moduleName !== '@fast-check/jest') return
|
|
2088
|
+
|
|
2089
|
+
if (from) {
|
|
2090
|
+
testSuiteAbsolutePathsWithFastCheck.add(from)
|
|
2091
|
+
testSuiteFastCheckUsage.set(from, true)
|
|
2092
|
+
}
|
|
2093
|
+
if (runtime?._testPath) {
|
|
2094
|
+
testSuiteAbsolutePathsWithFastCheck.add(runtime._testPath)
|
|
2095
|
+
testSuiteFastCheckUsage.set(runtime._testPath, true)
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
function doesTestSuiteUseFastCheck (testSuiteAbsolutePath) {
|
|
2100
|
+
if (!testSuiteAbsolutePath) return false
|
|
2101
|
+
if (testSuiteFastCheckUsage.has(testSuiteAbsolutePath)) {
|
|
2102
|
+
return testSuiteFastCheckUsage.get(testSuiteAbsolutePath)
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
try {
|
|
2106
|
+
const usesFastCheck = readFileSync(testSuiteAbsolutePath, 'utf8').includes('@fast-check/jest')
|
|
2107
|
+
testSuiteFastCheckUsage.set(testSuiteAbsolutePath, usesFastCheck)
|
|
2108
|
+
if (usesFastCheck) {
|
|
2109
|
+
testSuiteAbsolutePathsWithFastCheck.add(testSuiteAbsolutePath)
|
|
2110
|
+
}
|
|
2111
|
+
return usesFastCheck
|
|
2112
|
+
} catch {
|
|
2113
|
+
testSuiteFastCheckUsage.set(testSuiteAbsolutePath, false)
|
|
2114
|
+
return false
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
function getLastLoggedReferenceError (runtime) {
|
|
2119
|
+
const loggedReferenceErrors = runtime?.loggedReferenceErrors
|
|
2120
|
+
if (!loggedReferenceErrors?.size) return
|
|
2121
|
+
return [...loggedReferenceErrors].pop()
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
function publishRuntimeReferenceError (runtime, errorMessage) {
|
|
2125
|
+
if (!errorMessage || !runtime?._testPath) return
|
|
2126
|
+
|
|
2127
|
+
let publishedErrors = publishedRuntimeReferenceErrors.get(runtime)
|
|
2128
|
+
if (!publishedErrors) {
|
|
2129
|
+
publishedErrors = new Set()
|
|
2130
|
+
publishedRuntimeReferenceErrors.set(runtime, publishedErrors)
|
|
2131
|
+
}
|
|
2132
|
+
if (publishedErrors.has(errorMessage)) return
|
|
2133
|
+
|
|
2134
|
+
publishedErrors.add(errorMessage)
|
|
2135
|
+
testSuiteErrorCh.publish({
|
|
2136
|
+
errorMessage,
|
|
2137
|
+
testSuiteAbsolutePath: runtime._testPath,
|
|
2138
|
+
})
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
function isBetweenTestsReferenceError (error) {
|
|
2142
|
+
return error?.name === 'ReferenceError' &&
|
|
2143
|
+
typeof error.message === 'string' &&
|
|
2144
|
+
error.message.includes('outside of the scope of the test code')
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
function reportBetweenTestsReferenceError (runtime, moduleName, originalErrorMessage) {
|
|
2148
|
+
if (typeof moduleName !== 'string') return false
|
|
2149
|
+
|
|
2150
|
+
const fallbackErrorMessage = moduleName.startsWith('node:') || builtinModules.includes(moduleName)
|
|
2151
|
+
? 'You are trying to access a Node.js module outside of the scope of the test code.'
|
|
2152
|
+
: 'You are trying to `require` a file after the Jest environment has been torn down.'
|
|
2153
|
+
const errorMessage = originalErrorMessage || fallbackErrorMessage
|
|
2154
|
+
|
|
2155
|
+
if (typeof runtime._logFormattedReferenceError === 'function') {
|
|
2156
|
+
runtime._logFormattedReferenceError(errorMessage)
|
|
2157
|
+
}
|
|
2158
|
+
publishRuntimeReferenceError(runtime, getLastLoggedReferenceError(runtime) || errorMessage)
|
|
2159
|
+
process.exitCode = 1
|
|
2160
|
+
return true
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
function requireOutsideJestRequireEngine (runtime, moduleName) {
|
|
2164
|
+
if (typeof runtime._requireCoreModule === 'function') {
|
|
2165
|
+
return runtime._requireCoreModule(moduleName)
|
|
2166
|
+
}
|
|
2167
|
+
return require(moduleName)
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
function formatDefaultStackTrace (error, structuredStackTrace) {
|
|
2171
|
+
const errorString = Error.prototype.toString.call(error)
|
|
2172
|
+
if (structuredStackTrace.length === 0) return errorString
|
|
2173
|
+
|
|
2174
|
+
return `${errorString}\n at ${structuredStackTrace.join('\n at ')}`
|
|
2175
|
+
}
|
|
2176
|
+
|
|
1907
2177
|
addHook({
|
|
1908
2178
|
name: 'jest-runtime',
|
|
1909
2179
|
versions: [MINIMUM_JEST_VERSION],
|
|
1910
2180
|
}, (runtimePackage) => {
|
|
1911
2181
|
const Runtime = runtimePackage.default ?? runtimePackage
|
|
1912
2182
|
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
2183
|
+
if (typeof Runtime.prototype._createJestObjectFor === 'function') {
|
|
2184
|
+
shimmer.wrap(Runtime.prototype, '_createJestObjectFor', _createJestObjectFor => function (from) {
|
|
2185
|
+
const result = _createJestObjectFor.apply(this, arguments)
|
|
2186
|
+
const suiteFilePath = this._testPath || from
|
|
1916
2187
|
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2188
|
+
wrapJestObject(result, suiteFilePath)
|
|
2189
|
+
return result
|
|
2190
|
+
})
|
|
2191
|
+
}
|
|
1921
2192
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
if (
|
|
1928
|
-
|
|
1929
|
-
const suiteDir = path.dirname(suiteFilePath)
|
|
1930
|
-
const mockPath = path.resolve(suiteDir, moduleName)
|
|
1931
|
-
existingMockedFiles.push(mockPath)
|
|
1932
|
-
testSuiteMockedFiles.set(suiteFilePath, existingMockedFiles)
|
|
2193
|
+
shimmer.wrap(Runtime.prototype, 'requireModule', requireModule => function (from, moduleName) {
|
|
2194
|
+
wrapJestGlobalsForRuntime(this)
|
|
2195
|
+
try {
|
|
2196
|
+
return requireModule.apply(this, arguments)
|
|
2197
|
+
} catch (error) {
|
|
2198
|
+
if (isBetweenTestsReferenceError(error)) {
|
|
2199
|
+
reportBetweenTestsReferenceError(this, moduleName, error.message)
|
|
1933
2200
|
}
|
|
1934
|
-
|
|
1935
|
-
}
|
|
1936
|
-
return result
|
|
2201
|
+
throw error
|
|
2202
|
+
}
|
|
1937
2203
|
})
|
|
1938
2204
|
|
|
1939
2205
|
shimmer.wrap(Runtime.prototype, 'requireModuleOrMock', requireModuleOrMock => function (from, moduleName) {
|
|
2206
|
+
wrapJestGlobalsForRuntime(this)
|
|
1940
2207
|
// `requireModuleOrMock` may log errors to the console. If we don't remove ourselves
|
|
1941
2208
|
// from the stack trace, the user might see a useless stack trace rather than the error
|
|
1942
2209
|
// that `jest` tries to show.
|
|
@@ -1945,32 +2212,33 @@ addHook({
|
|
|
1945
2212
|
const filteredStackTrace = structuredStackTrace
|
|
1946
2213
|
.filter(callSite => !callSite.getFileName()?.includes('datadog-instrumentations/src/jest.js'))
|
|
1947
2214
|
|
|
1948
|
-
|
|
2215
|
+
if (typeof originalPrepareStackTrace === 'function') {
|
|
2216
|
+
return originalPrepareStackTrace(error, filteredStackTrace)
|
|
2217
|
+
}
|
|
2218
|
+
return formatDefaultStackTrace(error, filteredStackTrace)
|
|
1949
2219
|
}
|
|
1950
2220
|
try {
|
|
1951
2221
|
// TODO: do this for every library that we instrument
|
|
1952
2222
|
if (LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
|
|
1953
2223
|
// To bypass jest's own require engine
|
|
1954
|
-
return this
|
|
2224
|
+
return requireOutsideJestRequireEngine(this, moduleName)
|
|
1955
2225
|
}
|
|
1956
2226
|
// This means that `@fast-check/jest` is used in the test file.
|
|
1957
|
-
|
|
1958
|
-
|
|
2227
|
+
recordFastCheckUsage(this, from, moduleName)
|
|
2228
|
+
let returnedValue
|
|
2229
|
+
try {
|
|
2230
|
+
returnedValue = requireModuleOrMock.apply(this, arguments)
|
|
2231
|
+
} catch (error) {
|
|
2232
|
+
if (isBetweenTestsReferenceError(error)) {
|
|
2233
|
+
reportBetweenTestsReferenceError(this, moduleName, error.message)
|
|
2234
|
+
}
|
|
2235
|
+
throw error
|
|
1959
2236
|
}
|
|
1960
|
-
const returnedValue = requireModuleOrMock.apply(this, arguments)
|
|
1961
2237
|
if (process.exitCode === 1) {
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
testSuiteAbsolutePath: this._testPath,
|
|
1967
|
-
})
|
|
1968
|
-
} else {
|
|
1969
|
-
testSuiteErrorCh.publish({
|
|
1970
|
-
errorMessage: 'An error occurred while importing a module',
|
|
1971
|
-
testSuiteAbsolutePath: this._testPath,
|
|
1972
|
-
})
|
|
1973
|
-
}
|
|
2238
|
+
publishRuntimeReferenceError(
|
|
2239
|
+
this,
|
|
2240
|
+
getLastLoggedReferenceError(this) || 'An error occurred while importing a module'
|
|
2241
|
+
)
|
|
1974
2242
|
}
|
|
1975
2243
|
return returnedValue
|
|
1976
2244
|
} finally {
|
|
@@ -1979,6 +2247,27 @@ addHook({
|
|
|
1979
2247
|
}
|
|
1980
2248
|
})
|
|
1981
2249
|
|
|
2250
|
+
if (Runtime.prototype._logFormattedReferenceError) {
|
|
2251
|
+
shimmer.wrap(Runtime.prototype, '_logFormattedReferenceError', logFormattedReferenceError => function () {
|
|
2252
|
+
// eslint-disable-next-line no-console
|
|
2253
|
+
const originalConsoleError = console.error
|
|
2254
|
+
let loggedReferenceError
|
|
2255
|
+
// eslint-disable-next-line no-console
|
|
2256
|
+
console.error = function () {
|
|
2257
|
+
loggedReferenceError = arguments[0]
|
|
2258
|
+
return originalConsoleError.apply(this, arguments)
|
|
2259
|
+
}
|
|
2260
|
+
try {
|
|
2261
|
+
const result = logFormattedReferenceError.apply(this, arguments)
|
|
2262
|
+
publishRuntimeReferenceError(this, getLastLoggedReferenceError(this) || loggedReferenceError)
|
|
2263
|
+
return result
|
|
2264
|
+
} finally {
|
|
2265
|
+
// eslint-disable-next-line no-console
|
|
2266
|
+
console.error = originalConsoleError
|
|
2267
|
+
}
|
|
2268
|
+
})
|
|
2269
|
+
}
|
|
2270
|
+
|
|
1982
2271
|
return runtimePackage
|
|
1983
2272
|
})
|
|
1984
2273
|
|
|
@@ -2065,11 +2354,23 @@ function wrapWorkerChannel (worker) {
|
|
|
2065
2354
|
shimmer.wrap(workerChannel, worker._child ? 'send' : 'postMessage', sendWrapper)
|
|
2066
2355
|
}
|
|
2067
2356
|
|
|
2357
|
+
function wrapWorkerInitializer (worker) {
|
|
2358
|
+
if (wrappedWorkerInitializers.has(worker) || typeof worker.initialize !== 'function') return
|
|
2359
|
+
|
|
2360
|
+
wrappedWorkerInitializers.add(worker)
|
|
2361
|
+
shimmer.wrap(worker, 'initialize', initialize => function () {
|
|
2362
|
+
const result = initialize.apply(this, arguments)
|
|
2363
|
+
wrapWorkerChannel(this)
|
|
2364
|
+
return result
|
|
2365
|
+
})
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2068
2368
|
function wrapWorker (worker) {
|
|
2069
2369
|
// ChildProcessWorker uses _child (child_process), ExperimentalWorker uses _worker (worker_threads)
|
|
2070
2370
|
const workerChannel = worker._child || worker._worker
|
|
2071
2371
|
if (!workerChannel) return
|
|
2072
2372
|
|
|
2373
|
+
wrapWorkerInitializer(worker)
|
|
2073
2374
|
wrapWorkerChannel(worker)
|
|
2074
2375
|
shimmer.wrap(worker, '_onMessage', onMessageWrapper)
|
|
2075
2376
|
workerChannel.removeAllListeners('message')
|