dd-trace 5.55.0 → 5.57.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/LICENSE-3rdparty.csv +1 -0
- package/index.d.ts +44 -2
- package/init.js +4 -1
- package/package.json +24 -23
- package/packages/datadog-core/src/utils/src/set.js +8 -10
- package/packages/datadog-esbuild/index.js +22 -0
- package/packages/datadog-instrumentations/src/cassandra-driver.js +43 -60
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +12 -12
- package/packages/datadog-instrumentations/src/cucumber.js +4 -6
- package/packages/datadog-instrumentations/src/elasticsearch.js +16 -19
- package/packages/datadog-instrumentations/src/fastify.js +91 -9
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +20 -5
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +17 -5
- package/packages/datadog-instrumentations/src/ioredis.js +8 -13
- package/packages/datadog-instrumentations/src/iovalkey.js +10 -14
- package/packages/datadog-instrumentations/src/jest.js +423 -325
- package/packages/datadog-instrumentations/src/memcached.js +17 -24
- package/packages/datadog-instrumentations/src/mocha/main.js +7 -6
- package/packages/datadog-instrumentations/src/moleculer/client.js +9 -10
- package/packages/datadog-instrumentations/src/moleculer/server.js +12 -13
- package/packages/datadog-instrumentations/src/openai.js +30 -2
- package/packages/datadog-instrumentations/src/playwright.js +4 -1
- package/packages/datadog-instrumentations/src/prisma.js +116 -0
- package/packages/datadog-instrumentations/src/redis.js +32 -43
- package/packages/datadog-instrumentations/src/router.js +1 -1
- package/packages/datadog-instrumentations/src/sharedb.js +10 -16
- package/packages/datadog-instrumentations/src/vitest.js +4 -4
- package/packages/datadog-plugin-aws-sdk/src/base.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -4
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +3 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -4
- package/packages/datadog-plugin-bunyan/src/index.js +2 -2
- package/packages/datadog-plugin-cassandra-driver/src/index.js +6 -2
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/consumer.js +1 -1
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/producer.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +4 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -5
- package/packages/datadog-plugin-elasticsearch/src/index.js +12 -4
- package/packages/datadog-plugin-http/src/client.js +1 -0
- package/packages/datadog-plugin-http/src/server.js +2 -1
- package/packages/datadog-plugin-http2/src/client.js +1 -0
- package/packages/datadog-plugin-http2/src/server.js +1 -0
- package/packages/datadog-plugin-jest/src/index.js +4 -3
- package/packages/datadog-plugin-memcached/src/index.js +6 -2
- package/packages/datadog-plugin-mocha/src/index.js +3 -2
- package/packages/datadog-plugin-moleculer/src/client.js +15 -9
- package/packages/datadog-plugin-moleculer/src/server.js +9 -5
- package/packages/datadog-plugin-next/src/index.js +2 -1
- package/packages/datadog-plugin-openai/src/tracing.js +127 -80
- package/packages/datadog-plugin-oracledb/src/index.js +2 -1
- package/packages/datadog-plugin-pino/src/index.js +2 -2
- package/packages/datadog-plugin-prisma/src/client.js +62 -0
- package/packages/datadog-plugin-prisma/src/engine.js +81 -0
- package/packages/datadog-plugin-prisma/src/index.js +22 -0
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-redis/src/index.js +9 -3
- package/packages/datadog-plugin-router/src/index.js +1 -0
- package/packages/datadog-plugin-sharedb/src/index.js +13 -5
- package/packages/datadog-plugin-winston/src/index.js +2 -2
- package/packages/dd-trace/src/appsec/channels.js +26 -21
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +13 -20
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +44 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +7 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +0 -1
- package/packages/dd-trace/src/appsec/index.js +28 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +0 -5
- package/packages/dd-trace/src/appsec/reporter.js +6 -4
- package/packages/dd-trace/src/baggage.js +2 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -3
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -6
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -3
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +3 -3
- package/packages/dd-trace/src/config.js +334 -312
- package/packages/dd-trace/src/constants.js +2 -1
- package/packages/dd-trace/src/crashtracking/crashtracker.js +12 -14
- package/packages/dd-trace/src/datastreams/context.js +1 -1
- package/packages/dd-trace/src/datastreams/processor.js +1 -1
- package/packages/dd-trace/src/datastreams/writer.js +3 -3
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -3
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -3
- package/packages/dd-trace/src/debugger/devtools_client/send.js +5 -1
- package/packages/dd-trace/src/debugger/devtools_client/state.js +7 -4
- package/packages/dd-trace/src/debugger/devtools_client/status.js +5 -1
- package/packages/dd-trace/src/dogstatsd.js +3 -3
- package/packages/dd-trace/src/exporters/agent/index.js +10 -5
- package/packages/dd-trace/src/exporters/agent/writer.js +4 -2
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +2 -2
- package/packages/dd-trace/src/exporters/log/index.js +1 -1
- package/packages/dd-trace/src/exporters/span-stats/writer.js +2 -2
- package/packages/dd-trace/src/guardrails/index.js +3 -1
- package/packages/dd-trace/src/guardrails/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/index.js +11 -5
- package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +13 -13
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
- package/packages/dd-trace/src/llmobs/writers/spans.js +2 -2
- package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +22 -28
- package/packages/dd-trace/src/opentracing/span.js +1 -0
- package/packages/dd-trace/src/plugin_manager.js +3 -3
- package/packages/dd-trace/src/plugins/cache.js +2 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +11 -7
- package/packages/dd-trace/src/plugins/database.js +3 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +5 -1
- package/packages/dd-trace/src/plugins/outbound.js +8 -6
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +9 -0
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +83 -30
- package/packages/dd-trace/src/plugins/util/git.js +1 -0
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +3 -2
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -0
- package/packages/dd-trace/src/plugins/util/tags.js +4 -1
- package/packages/dd-trace/src/plugins/util/test.js +80 -10
- package/packages/dd-trace/src/plugins/util/web.js +1 -0
- package/packages/dd-trace/src/profiler.js +0 -2
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/events.js +10 -2
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +18 -126
- package/packages/dd-trace/src/proxy.js +12 -27
- package/packages/dd-trace/src/runtime_metrics/index.js +1 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +14 -45
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +2 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +2 -2
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
- package/packages/dd-trace/src/supported-configurations.json +13 -3
- package/packages/dd-trace/src/telemetry/telemetry.js +11 -4
- package/packages/dd-trace/src/tracer.js +11 -0
- package/packages/dd-trace/src/tracer_metadata.js +25 -0
- package/packages/dd-trace/src/util.js +11 -4
- package/version.js +3 -1
- package/packages/datadog-core/src/utils/src/get.js +0 -11
- package/packages/datadog-core/src/utils/src/has.js +0 -14
- package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +0 -30
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { addHook, channel } = require('./helpers/instrument')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
5
|
const log = require('../../dd-trace/src/log')
|
|
6
|
+
const path = require('path')
|
|
6
7
|
const {
|
|
7
8
|
getCoveredFilenamesFromCoverage,
|
|
8
9
|
JEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
@@ -89,6 +90,8 @@ const originalHookFns = new WeakMap()
|
|
|
89
90
|
const retriedTestsToNumAttempts = new Map()
|
|
90
91
|
const newTestsTestStatuses = new Map()
|
|
91
92
|
const attemptToFixRetriedTestsStatuses = new Map()
|
|
93
|
+
const wrappedWorkers = new WeakSet()
|
|
94
|
+
const testSuiteMockedFiles = new Map()
|
|
92
95
|
|
|
93
96
|
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
94
97
|
|
|
@@ -136,6 +139,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
136
139
|
this.nameToParams = {}
|
|
137
140
|
this.global._ddtrace = global._ddtrace
|
|
138
141
|
this.hasSnapshotTests = undefined
|
|
142
|
+
this.testSuiteAbsolutePath = context.testPath
|
|
139
143
|
|
|
140
144
|
this.displayName = config.projectConfig?.displayName?.name
|
|
141
145
|
this.testEnvironmentOptions = getTestEnvironmentOptions(config)
|
|
@@ -290,7 +294,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
290
294
|
// We'll still detect new tests, but we won't retry them.
|
|
291
295
|
// TODO: do not bail out of retrying tests for the whole test suite
|
|
292
296
|
if (this.getHasSnapshotTests()) {
|
|
293
|
-
log.warn(
|
|
297
|
+
log.warn('%s is disabled for suites with snapshots', retryType)
|
|
294
298
|
return
|
|
295
299
|
}
|
|
296
300
|
|
|
@@ -298,7 +302,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
298
302
|
if (this.global.test) {
|
|
299
303
|
this.global.test(addRetryStringToTestName(testName, retryIndex), event.fn, event.timeout)
|
|
300
304
|
} else {
|
|
301
|
-
log.error(
|
|
305
|
+
log.error('%s could not retry test because global.test is undefined', retryType)
|
|
302
306
|
}
|
|
303
307
|
}
|
|
304
308
|
}
|
|
@@ -425,6 +429,10 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
425
429
|
if (event.name === 'add_test') {
|
|
426
430
|
const originalTestName = this.getTestNameFromAddTestEvent(event, state)
|
|
427
431
|
|
|
432
|
+
if (event.failing) {
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
|
|
428
436
|
const isSkipped = event.mode === 'todo' || event.mode === 'skip'
|
|
429
437
|
if (this.isTestManagementTestsEnabled) {
|
|
430
438
|
const isAttemptToFix = this.testManagementTestsForThisSuite?.attemptToFix?.includes(originalTestName)
|
|
@@ -592,6 +600,17 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
592
600
|
})
|
|
593
601
|
}
|
|
594
602
|
}
|
|
603
|
+
|
|
604
|
+
teardown () {
|
|
605
|
+
if (this._globalProxy?.propertyToValue) {
|
|
606
|
+
for (const [key] of this._globalProxy.propertyToValue) {
|
|
607
|
+
if (typeof key === 'string' && key.startsWith('_dd')) {
|
|
608
|
+
this._globalProxy.propertyToValue.delete(key)
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return super.teardown()
|
|
613
|
+
}
|
|
595
614
|
}
|
|
596
615
|
}
|
|
597
616
|
|
|
@@ -647,299 +666,305 @@ function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
|
|
|
647
666
|
}
|
|
648
667
|
}
|
|
649
668
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
file: 'build/TestScheduler.js',
|
|
653
|
-
versions: ['>=27.0.0']
|
|
654
|
-
}, (testSchedulerPackage, frameworkVersion) => {
|
|
655
|
-
const oldCreateTestScheduler = testSchedulerPackage.createTestScheduler
|
|
656
|
-
const newCreateTestScheduler = async function () {
|
|
657
|
-
if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
|
|
658
|
-
return oldCreateTestScheduler.apply(this, arguments)
|
|
659
|
-
}
|
|
660
|
-
// If suite skipping is enabled and has not filtered skippable suites yet, we'll attempt to do it
|
|
661
|
-
const scheduler = await oldCreateTestScheduler.apply(this, arguments)
|
|
662
|
-
shimmer.wrap(scheduler, 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion))
|
|
663
|
-
return scheduler
|
|
664
|
-
}
|
|
665
|
-
testSchedulerPackage.createTestScheduler = newCreateTestScheduler
|
|
666
|
-
return testSchedulerPackage
|
|
667
|
-
})
|
|
669
|
+
function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
|
|
670
|
+
const SearchSource = searchSourcePackage.default ?? searchSourcePackage
|
|
668
671
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
versions: ['>=24.8.0 <27.0.0']
|
|
673
|
-
}, (testSchedulerPackage, frameworkVersion) => {
|
|
674
|
-
shimmer.wrap(
|
|
675
|
-
testSchedulerPackage.default.prototype,
|
|
676
|
-
'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion)
|
|
677
|
-
)
|
|
678
|
-
return testSchedulerPackage
|
|
679
|
-
})
|
|
672
|
+
shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
|
|
673
|
+
const testPaths = await getTestPaths.apply(this, arguments)
|
|
674
|
+
const [{ rootDir, shard }] = arguments
|
|
680
675
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
676
|
+
if (isKnownTestsEnabled) {
|
|
677
|
+
const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
|
|
678
|
+
const isFaulty =
|
|
679
|
+
getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
|
|
680
|
+
if (isFaulty) {
|
|
681
|
+
log.error('Early flake detection is disabled because the number of new suites is too high.')
|
|
682
|
+
isEarlyFlakeDetectionEnabled = false
|
|
683
|
+
isKnownTestsEnabled = false
|
|
684
|
+
const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions
|
|
685
|
+
// Project config is shared among all tests, so we can modify it here
|
|
686
|
+
if (testEnvironmentOptions) {
|
|
687
|
+
testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false
|
|
688
|
+
testEnvironmentOptions._ddIsKnownTestsEnabled = false
|
|
689
|
+
}
|
|
690
|
+
isEarlyFlakeDetectionFaulty = true
|
|
691
|
+
}
|
|
692
|
+
}
|
|
687
693
|
|
|
688
|
-
if (
|
|
689
|
-
|
|
694
|
+
if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) {
|
|
695
|
+
// If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
|
|
696
|
+
// The reason for this is the following:
|
|
697
|
+
// The tests for different shards are likely being run in different CI jobs so
|
|
698
|
+
// the requests to the skippable endpoint might be done at different times and their responses might be different.
|
|
699
|
+
// If the skippable endpoint is returning different suites and we filter the list of tests here,
|
|
700
|
+
// the base list of tests that is used for sharding might be different,
|
|
701
|
+
// causing the shards to potentially run the same suite.
|
|
702
|
+
return testPaths
|
|
690
703
|
}
|
|
691
|
-
const
|
|
692
|
-
const rootDir = test?.context?.config?.rootDir
|
|
704
|
+
const { tests } = testPaths
|
|
693
705
|
|
|
694
|
-
|
|
706
|
+
const suitesToRun = applySuiteSkipping(tests, rootDir, frameworkVersion)
|
|
707
|
+
return { ...testPaths, tests: suitesToRun }
|
|
695
708
|
})
|
|
696
|
-
return sequencerPackage
|
|
697
|
-
})
|
|
698
709
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
let onDone
|
|
702
|
-
const configurationPromise = new Promise((resolve) => {
|
|
703
|
-
onDone = resolve
|
|
704
|
-
})
|
|
705
|
-
if (!libraryConfigurationCh.hasSubscribers) {
|
|
706
|
-
return runCLI.apply(this, arguments)
|
|
707
|
-
}
|
|
710
|
+
return searchSourcePackage
|
|
711
|
+
}
|
|
708
712
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
|
|
719
|
-
isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
720
|
-
isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
|
|
721
|
-
testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
|
|
722
|
-
isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
|
|
723
|
-
}
|
|
724
|
-
} catch (err) {
|
|
725
|
-
log.error('Jest library configuration error', err)
|
|
713
|
+
function getCliWrapper (isNewJestVersion) {
|
|
714
|
+
return function cliWrapper (cli, jestVersion) {
|
|
715
|
+
if (isNewJestVersion) {
|
|
716
|
+
cli = shimmer.wrap(
|
|
717
|
+
cli,
|
|
718
|
+
'SearchSource',
|
|
719
|
+
searchSource => searchSourceWrapper(searchSource, jestVersion),
|
|
720
|
+
{ replaceGetter: true }
|
|
721
|
+
)
|
|
726
722
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
const
|
|
723
|
+
return shimmer.wrap(cli, 'runCLI', runCLI => async function () {
|
|
724
|
+
let onDone
|
|
725
|
+
const configurationPromise = new Promise((resolve) => {
|
|
730
726
|
onDone = resolve
|
|
731
727
|
})
|
|
728
|
+
if (!libraryConfigurationCh.hasSubscribers) {
|
|
729
|
+
return runCLI.apply(this, arguments)
|
|
730
|
+
}
|
|
732
731
|
|
|
733
|
-
|
|
732
|
+
libraryConfigurationCh.publish({ onDone, frameworkVersion: jestVersion })
|
|
734
733
|
|
|
735
734
|
try {
|
|
736
|
-
const { err,
|
|
737
|
-
if (err) {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
735
|
+
const { err, libraryConfig } = await configurationPromise
|
|
736
|
+
if (!err) {
|
|
737
|
+
isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
|
|
738
|
+
isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
|
|
739
|
+
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
740
|
+
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
741
|
+
earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
|
|
742
|
+
isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
743
|
+
isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
|
|
744
|
+
testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
|
|
745
|
+
isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
|
|
743
746
|
}
|
|
744
747
|
} catch (err) {
|
|
745
|
-
log.error('Jest
|
|
748
|
+
log.error('Jest library configuration error', err)
|
|
746
749
|
}
|
|
747
|
-
}
|
|
748
750
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
751
|
+
if (isKnownTestsEnabled) {
|
|
752
|
+
const knownTestsPromise = new Promise((resolve) => {
|
|
753
|
+
onDone = resolve
|
|
754
|
+
})
|
|
753
755
|
|
|
754
|
-
|
|
756
|
+
knownTestsCh.publish({ onDone })
|
|
755
757
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
758
|
+
try {
|
|
759
|
+
const { err, knownTests: receivedKnownTests } = await knownTestsPromise
|
|
760
|
+
if (err) {
|
|
761
|
+
// We disable EFD if there has been an error in the known tests request
|
|
762
|
+
isEarlyFlakeDetectionEnabled = false
|
|
763
|
+
isKnownTestsEnabled = false
|
|
764
|
+
} else {
|
|
765
|
+
knownTests = receivedKnownTests
|
|
766
|
+
}
|
|
767
|
+
} catch (err) {
|
|
768
|
+
log.error('Jest known tests error', err)
|
|
760
769
|
}
|
|
761
|
-
} catch (err) {
|
|
762
|
-
log.error('Jest test-suite skippable error', err)
|
|
763
770
|
}
|
|
764
|
-
}
|
|
765
771
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
772
|
+
if (isSuitesSkippingEnabled) {
|
|
773
|
+
const skippableSuitesPromise = new Promise((resolve) => {
|
|
774
|
+
onDone = resolve
|
|
775
|
+
})
|
|
770
776
|
|
|
771
|
-
|
|
777
|
+
skippableSuitesCh.publish({ onDone })
|
|
772
778
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
779
|
+
try {
|
|
780
|
+
const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
|
|
781
|
+
if (!err) {
|
|
782
|
+
skippableSuites = receivedSkippableSuites
|
|
783
|
+
}
|
|
784
|
+
} catch (err) {
|
|
785
|
+
log.error('Jest test-suite skippable error', err)
|
|
777
786
|
}
|
|
778
|
-
} catch (err) {
|
|
779
|
-
log.error('Jest test management tests error', err)
|
|
780
787
|
}
|
|
781
|
-
}
|
|
782
788
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
789
|
+
if (isTestManagementTestsEnabled) {
|
|
790
|
+
const testManagementTestsPromise = new Promise((resolve) => {
|
|
791
|
+
onDone = resolve
|
|
792
|
+
})
|
|
787
793
|
|
|
788
|
-
|
|
794
|
+
testManagementTestsCh.publish({ onDone })
|
|
789
795
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
796
|
+
try {
|
|
797
|
+
const { err, testManagementTests: receivedTestManagementTests } = await testManagementTestsPromise
|
|
798
|
+
if (!err) {
|
|
799
|
+
testManagementTests = receivedTestManagementTests
|
|
800
|
+
}
|
|
801
|
+
} catch (err) {
|
|
802
|
+
log.error('Jest test management tests error', err)
|
|
794
803
|
}
|
|
795
|
-
} catch (err) {
|
|
796
|
-
log.error('Jest impacted tests error', err)
|
|
797
804
|
}
|
|
798
|
-
}
|
|
799
805
|
|
|
800
|
-
|
|
801
|
-
|
|
806
|
+
if (isImpactedTestsEnabled) {
|
|
807
|
+
const impactedTestsPromise = new Promise((resolve) => {
|
|
808
|
+
onDone = resolve
|
|
809
|
+
})
|
|
802
810
|
|
|
803
|
-
|
|
811
|
+
impactedTestsCh.publish({ onDone })
|
|
804
812
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
+
try {
|
|
814
|
+
const { err, modifiedTests: receivedModifiedTests } = await impactedTestsPromise
|
|
815
|
+
if (!err) {
|
|
816
|
+
modifiedTests = receivedModifiedTests
|
|
817
|
+
}
|
|
818
|
+
} catch (err) {
|
|
819
|
+
log.error('Jest impacted tests error', err)
|
|
820
|
+
}
|
|
813
821
|
}
|
|
814
|
-
} = result
|
|
815
822
|
|
|
816
|
-
|
|
823
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
824
|
+
testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
|
|
817
825
|
|
|
818
|
-
|
|
819
|
-
try {
|
|
820
|
-
const { pct, total } = coverageMap.getCoverageSummary().lines
|
|
821
|
-
testCodeCoverageLinesTotal = total === 0 ? 0 : pct
|
|
822
|
-
} catch {
|
|
823
|
-
// ignore errors
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
let status, error
|
|
826
|
+
const result = await runCLI.apply(this, arguments)
|
|
827
827
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
828
|
+
const {
|
|
829
|
+
results: {
|
|
830
|
+
success,
|
|
831
|
+
coverageMap,
|
|
832
|
+
numFailedTestSuites,
|
|
833
|
+
numFailedTests,
|
|
834
|
+
numTotalTests,
|
|
835
|
+
numTotalTestSuites
|
|
836
|
+
}
|
|
837
|
+
} = result
|
|
835
838
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
839
|
+
let testCodeCoverageLinesTotal
|
|
840
|
+
|
|
841
|
+
if (isUserCodeCoverageEnabled) {
|
|
842
|
+
try {
|
|
843
|
+
const { pct, total } = coverageMap.getCoverageSummary().lines
|
|
844
|
+
testCodeCoverageLinesTotal = total === 0 ? 0 : pct
|
|
845
|
+
} catch {
|
|
846
|
+
// ignore errors
|
|
847
|
+
}
|
|
841
848
|
}
|
|
842
|
-
|
|
849
|
+
let status, error
|
|
843
850
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
851
|
+
if (success) {
|
|
852
|
+
status = numTotalTests === 0 && numTotalTestSuites === 0 ? 'skip' : 'pass'
|
|
853
|
+
} else {
|
|
854
|
+
status = 'fail'
|
|
855
|
+
error = new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
|
|
856
|
+
}
|
|
857
|
+
let timeoutId
|
|
849
858
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
hasUnskippableSuites,
|
|
858
|
-
hasForcedToRunSuites,
|
|
859
|
-
error,
|
|
860
|
-
isEarlyFlakeDetectionEnabled,
|
|
861
|
-
isEarlyFlakeDetectionFaulty,
|
|
862
|
-
isTestManagementTestsEnabled,
|
|
863
|
-
onDone
|
|
864
|
-
})
|
|
859
|
+
// Pass the resolve callback to defer it to DC listener
|
|
860
|
+
const flushPromise = new Promise((resolve) => {
|
|
861
|
+
onDone = () => {
|
|
862
|
+
clearTimeout(timeoutId)
|
|
863
|
+
resolve()
|
|
864
|
+
}
|
|
865
|
+
})
|
|
865
866
|
|
|
866
|
-
|
|
867
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
868
|
+
timeoutId = setTimeout(() => {
|
|
869
|
+
resolve('timeout')
|
|
870
|
+
}, FLUSH_TIMEOUT).unref()
|
|
871
|
+
})
|
|
867
872
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
873
|
+
testSessionFinishCh.publish({
|
|
874
|
+
status,
|
|
875
|
+
isSuitesSkipped,
|
|
876
|
+
isSuitesSkippingEnabled,
|
|
877
|
+
isCodeCoverageEnabled,
|
|
878
|
+
testCodeCoverageLinesTotal,
|
|
879
|
+
numSkippedSuites,
|
|
880
|
+
hasUnskippableSuites,
|
|
881
|
+
hasForcedToRunSuites,
|
|
882
|
+
error,
|
|
883
|
+
isEarlyFlakeDetectionEnabled,
|
|
884
|
+
isEarlyFlakeDetectionFaulty,
|
|
885
|
+
isTestManagementTestsEnabled,
|
|
886
|
+
onDone
|
|
887
|
+
})
|
|
871
888
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
* - If all attempts for a test are failing, the test has failed and we will let the test process fail.
|
|
877
|
-
* - If just a single attempt passes, we will prevent the test process from failing.
|
|
878
|
-
* The rationale behind is the following: you may still be able to block your CI pipeline by gating
|
|
879
|
-
* on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
|
|
880
|
-
*/
|
|
881
|
-
|
|
882
|
-
if (isEarlyFlakeDetectionEnabled) {
|
|
883
|
-
let numFailedTestsToIgnore = 0
|
|
884
|
-
for (const testStatuses of newTestsTestStatuses.values()) {
|
|
885
|
-
const { pass, fail } = getTestStats(testStatuses)
|
|
886
|
-
if (pass > 0) { // as long as one passes, we'll consider the test passed
|
|
887
|
-
numFailedTestsToIgnore += fail
|
|
888
|
-
}
|
|
889
|
+
const waitingResult = await Promise.race([flushPromise, timeoutPromise])
|
|
890
|
+
|
|
891
|
+
if (waitingResult === 'timeout') {
|
|
892
|
+
log.error('Timeout waiting for the tracer to flush')
|
|
889
893
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
894
|
+
|
|
895
|
+
numSkippedSuites = 0
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* If Early Flake Detection (EFD) is enabled the logic is as follows:
|
|
899
|
+
* - If all attempts for a test are failing, the test has failed and we will let the test process fail.
|
|
900
|
+
* - If just a single attempt passes, we will prevent the test process from failing.
|
|
901
|
+
* The rationale behind is the following: you may still be able to block your CI pipeline by gating
|
|
902
|
+
* on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
|
|
903
|
+
*/
|
|
904
|
+
|
|
905
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
906
|
+
let numFailedTestsToIgnore = 0
|
|
907
|
+
for (const testStatuses of newTestsTestStatuses.values()) {
|
|
908
|
+
const { pass, fail } = getTestStats(testStatuses)
|
|
909
|
+
if (pass > 0) { // as long as one passes, we'll consider the test passed
|
|
910
|
+
numFailedTestsToIgnore += fail
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
// If every test that failed was an EFD retry, we'll consider the suite passed
|
|
914
|
+
if (numFailedTestsToIgnore !== 0 && result.results.numFailedTests === numFailedTestsToIgnore) {
|
|
915
|
+
result.results.success = true
|
|
916
|
+
}
|
|
893
917
|
}
|
|
894
|
-
}
|
|
895
918
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
919
|
+
if (isTestManagementTestsEnabled) {
|
|
920
|
+
const failedTests = result
|
|
921
|
+
.results
|
|
922
|
+
.testResults.flatMap(({ testResults, testFilePath: testSuiteAbsolutePath }) => (
|
|
923
|
+
testResults.map(({ fullName: testName, status }) => (
|
|
924
|
+
{ testName, testSuiteAbsolutePath, status }
|
|
925
|
+
))
|
|
902
926
|
))
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
927
|
+
.filter(({ status }) => status === 'failed')
|
|
928
|
+
|
|
929
|
+
let numFailedQuarantinedTests = 0
|
|
930
|
+
let numFailedQuarantinedOrDisabledAttemptedToFixTests = 0
|
|
931
|
+
|
|
932
|
+
for (const { testName, testSuiteAbsolutePath } of failedTests) {
|
|
933
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, result.globalConfig.rootDir)
|
|
934
|
+
const originalName = removeAttemptToFixStringFromTestName(testName)
|
|
935
|
+
const testManagementTest = testManagementTests
|
|
936
|
+
?.jest
|
|
937
|
+
?.suites
|
|
938
|
+
?.[testSuite]
|
|
939
|
+
?.tests
|
|
940
|
+
?.[originalName]
|
|
941
|
+
?.properties
|
|
942
|
+
// This uses `attempt_to_fix` because this is always the main process and it's not formatted in camelCase
|
|
943
|
+
if (testManagementTest?.attempt_to_fix && (testManagementTest?.quarantined || testManagementTest?.disabled)) {
|
|
944
|
+
numFailedQuarantinedOrDisabledAttemptedToFixTests++
|
|
945
|
+
} else if (testManagementTest?.quarantined) {
|
|
946
|
+
numFailedQuarantinedTests++
|
|
947
|
+
}
|
|
924
948
|
}
|
|
925
|
-
}
|
|
926
949
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
(
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
950
|
+
// If every test that failed was quarantined, we'll consider the suite passed
|
|
951
|
+
// Note that if a test is attempted to fix,
|
|
952
|
+
// it's considered quarantined both if it's disabled and if it's quarantined
|
|
953
|
+
// (it'll run but its status is ignored)
|
|
954
|
+
if (
|
|
955
|
+
(numFailedQuarantinedOrDisabledAttemptedToFixTests !== 0 || numFailedQuarantinedTests !== 0) &&
|
|
956
|
+
result.results.numFailedTests ===
|
|
957
|
+
numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
|
|
958
|
+
) {
|
|
959
|
+
result.results.success = true
|
|
960
|
+
}
|
|
936
961
|
}
|
|
937
|
-
}
|
|
938
962
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
963
|
+
return result
|
|
964
|
+
}, {
|
|
965
|
+
replaceGetter: true
|
|
966
|
+
})
|
|
967
|
+
}
|
|
943
968
|
}
|
|
944
969
|
|
|
945
970
|
function coverageReporterWrapper (coverageReporter) {
|
|
@@ -963,6 +988,55 @@ function coverageReporterWrapper (coverageReporter) {
|
|
|
963
988
|
return coverageReporter
|
|
964
989
|
}
|
|
965
990
|
|
|
991
|
+
addHook({
|
|
992
|
+
name: '@jest/core',
|
|
993
|
+
file: 'build/TestScheduler.js',
|
|
994
|
+
versions: ['>=27.0.0']
|
|
995
|
+
}, (testSchedulerPackage, frameworkVersion) => {
|
|
996
|
+
const oldCreateTestScheduler = testSchedulerPackage.createTestScheduler
|
|
997
|
+
const newCreateTestScheduler = async function () {
|
|
998
|
+
if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
|
|
999
|
+
return oldCreateTestScheduler.apply(this, arguments)
|
|
1000
|
+
}
|
|
1001
|
+
// If suite skipping is enabled and has not filtered skippable suites yet, we'll attempt to do it
|
|
1002
|
+
const scheduler = await oldCreateTestScheduler.apply(this, arguments)
|
|
1003
|
+
shimmer.wrap(scheduler, 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion))
|
|
1004
|
+
return scheduler
|
|
1005
|
+
}
|
|
1006
|
+
testSchedulerPackage.createTestScheduler = newCreateTestScheduler
|
|
1007
|
+
return testSchedulerPackage
|
|
1008
|
+
})
|
|
1009
|
+
|
|
1010
|
+
addHook({
|
|
1011
|
+
name: '@jest/core',
|
|
1012
|
+
file: 'build/TestScheduler.js',
|
|
1013
|
+
versions: ['>=24.8.0 <27.0.0']
|
|
1014
|
+
}, (testSchedulerPackage, frameworkVersion) => {
|
|
1015
|
+
shimmer.wrap(
|
|
1016
|
+
testSchedulerPackage.default.prototype,
|
|
1017
|
+
'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion)
|
|
1018
|
+
)
|
|
1019
|
+
return testSchedulerPackage
|
|
1020
|
+
})
|
|
1021
|
+
|
|
1022
|
+
addHook({
|
|
1023
|
+
name: '@jest/test-sequencer',
|
|
1024
|
+
versions: ['>=28']
|
|
1025
|
+
}, (sequencerPackage, frameworkVersion) => {
|
|
1026
|
+
shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
|
|
1027
|
+
const shardedTests = shard.apply(this, arguments)
|
|
1028
|
+
|
|
1029
|
+
if (!shardedTests.length || !isSuitesSkippingEnabled || !skippableSuites.length) {
|
|
1030
|
+
return shardedTests
|
|
1031
|
+
}
|
|
1032
|
+
const [test] = shardedTests
|
|
1033
|
+
const rootDir = test?.context?.config?.rootDir
|
|
1034
|
+
|
|
1035
|
+
return applySuiteSkipping(shardedTests, rootDir, frameworkVersion)
|
|
1036
|
+
})
|
|
1037
|
+
return sequencerPackage
|
|
1038
|
+
})
|
|
1039
|
+
|
|
966
1040
|
addHook({
|
|
967
1041
|
name: '@jest/reporters',
|
|
968
1042
|
file: 'build/coverage_reporter.js',
|
|
@@ -975,11 +1049,23 @@ addHook({
|
|
|
975
1049
|
versions: ['>=26.6.2']
|
|
976
1050
|
}, coverageReporterWrapper)
|
|
977
1051
|
|
|
1052
|
+
addHook({
|
|
1053
|
+
name: '@jest/reporters',
|
|
1054
|
+
versions: ['>=30.0.0']
|
|
1055
|
+
}, (reporters) => {
|
|
1056
|
+
return shimmer.wrap(reporters, 'CoverageReporter', coverageReporterWrapper, { replaceGetter: true })
|
|
1057
|
+
})
|
|
1058
|
+
|
|
978
1059
|
addHook({
|
|
979
1060
|
name: '@jest/core',
|
|
980
1061
|
file: 'build/cli/index.js',
|
|
981
|
-
versions: ['>=24.8.0']
|
|
982
|
-
},
|
|
1062
|
+
versions: ['>=24.8.0 <30.0.0']
|
|
1063
|
+
}, getCliWrapper(false))
|
|
1064
|
+
|
|
1065
|
+
addHook({
|
|
1066
|
+
name: '@jest/core',
|
|
1067
|
+
versions: ['>=30.0.0']
|
|
1068
|
+
}, getCliWrapper(true))
|
|
983
1069
|
|
|
984
1070
|
function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
985
1071
|
const adapter = jestAdapter.default ?? jestAdapter
|
|
@@ -1012,10 +1098,12 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
|
1012
1098
|
if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
|
|
1013
1099
|
const root = environment.repositoryRoot || environment.rootDir
|
|
1014
1100
|
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1101
|
+
const getFilesWithPath = (files) => files.map(file => getTestSuitePath(file, root))
|
|
1102
|
+
|
|
1103
|
+
const coverageFiles = getFilesWithPath(getCoveredFilenamesFromCoverage(environment.global.__coverage__))
|
|
1104
|
+
const mockedFiles = getFilesWithPath(testSuiteMockedFiles.get(environment.testSuiteAbsolutePath) || [])
|
|
1017
1105
|
|
|
1018
|
-
testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile })
|
|
1106
|
+
testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile, mockedFiles })
|
|
1019
1107
|
}
|
|
1020
1108
|
testSuiteFinishCh.publish({ status, errorMessage })
|
|
1021
1109
|
return suiteResults
|
|
@@ -1033,6 +1121,12 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
|
1033
1121
|
return jestAdapter
|
|
1034
1122
|
}
|
|
1035
1123
|
|
|
1124
|
+
addHook({
|
|
1125
|
+
name: 'jest-circus',
|
|
1126
|
+
file: 'build/runner.js',
|
|
1127
|
+
versions: ['>=30.0.0']
|
|
1128
|
+
}, jestAdapterWrapper)
|
|
1129
|
+
|
|
1036
1130
|
addHook({
|
|
1037
1131
|
name: 'jest-circus',
|
|
1038
1132
|
file: 'build/legacy-code-todo-rewrite/jestAdapter.js',
|
|
@@ -1077,21 +1171,19 @@ function configureTestEnvironment (readConfigsResult) {
|
|
|
1077
1171
|
}
|
|
1078
1172
|
|
|
1079
1173
|
function jestConfigAsyncWrapper (jestConfig) {
|
|
1080
|
-
shimmer.wrap(jestConfig, 'readConfigs', readConfigs => async function () {
|
|
1174
|
+
return shimmer.wrap(jestConfig, 'readConfigs', readConfigs => async function () {
|
|
1081
1175
|
const readConfigsResult = await readConfigs.apply(this, arguments)
|
|
1082
1176
|
configureTestEnvironment(readConfigsResult)
|
|
1083
1177
|
return readConfigsResult
|
|
1084
1178
|
})
|
|
1085
|
-
return jestConfig
|
|
1086
1179
|
}
|
|
1087
1180
|
|
|
1088
1181
|
function jestConfigSyncWrapper (jestConfig) {
|
|
1089
|
-
shimmer.wrap(jestConfig, 'readConfigs', readConfigs => function () {
|
|
1182
|
+
return shimmer.wrap(jestConfig, 'readConfigs', readConfigs => function () {
|
|
1090
1183
|
const readConfigsResult = readConfigs.apply(this, arguments)
|
|
1091
1184
|
configureTestEnvironment(readConfigsResult)
|
|
1092
1185
|
return readConfigsResult
|
|
1093
1186
|
})
|
|
1094
|
-
return jestConfig
|
|
1095
1187
|
}
|
|
1096
1188
|
|
|
1097
1189
|
addHook({
|
|
@@ -1142,51 +1234,9 @@ addHook({
|
|
|
1142
1234
|
*/
|
|
1143
1235
|
addHook({
|
|
1144
1236
|
name: '@jest/core',
|
|
1145
|
-
versions: ['>=24.8.0'],
|
|
1237
|
+
versions: ['>=24.8.0 <30.0.0'],
|
|
1146
1238
|
file: 'build/SearchSource.js'
|
|
1147
|
-
},
|
|
1148
|
-
const SearchSource = searchSourcePackage.default ?? searchSourcePackage
|
|
1149
|
-
|
|
1150
|
-
shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
|
|
1151
|
-
const testPaths = await getTestPaths.apply(this, arguments)
|
|
1152
|
-
const [{ rootDir, shard }] = arguments
|
|
1153
|
-
|
|
1154
|
-
if (isKnownTestsEnabled) {
|
|
1155
|
-
const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
|
|
1156
|
-
const isFaulty =
|
|
1157
|
-
getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
|
|
1158
|
-
if (isFaulty) {
|
|
1159
|
-
log.error('Early flake detection is disabled because the number of new suites is too high.')
|
|
1160
|
-
isEarlyFlakeDetectionEnabled = false
|
|
1161
|
-
isKnownTestsEnabled = false
|
|
1162
|
-
const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions
|
|
1163
|
-
// Project config is shared among all tests, so we can modify it here
|
|
1164
|
-
if (testEnvironmentOptions) {
|
|
1165
|
-
testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false
|
|
1166
|
-
testEnvironmentOptions._ddIsKnownTestsEnabled = false
|
|
1167
|
-
}
|
|
1168
|
-
isEarlyFlakeDetectionFaulty = true
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) {
|
|
1173
|
-
// If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
|
|
1174
|
-
// The reason for this is the following:
|
|
1175
|
-
// The tests for different shards are likely being run in different CI jobs so
|
|
1176
|
-
// the requests to the skippable endpoint might be done at different times and their responses might be different.
|
|
1177
|
-
// If the skippable endpoint is returning different suites and we filter the list of tests here,
|
|
1178
|
-
// the base list of tests that is used for sharding might be different,
|
|
1179
|
-
// causing the shards to potentially run the same suite.
|
|
1180
|
-
return testPaths
|
|
1181
|
-
}
|
|
1182
|
-
const { tests } = testPaths
|
|
1183
|
-
|
|
1184
|
-
const suitesToRun = applySuiteSkipping(tests, rootDir, frameworkVersion)
|
|
1185
|
-
return { ...testPaths, tests: suitesToRun }
|
|
1186
|
-
})
|
|
1187
|
-
|
|
1188
|
-
return searchSourcePackage
|
|
1189
|
-
})
|
|
1239
|
+
}, searchSourceWrapper)
|
|
1190
1240
|
|
|
1191
1241
|
// from 25.1.0 on, readConfigs becomes async
|
|
1192
1242
|
addHook({
|
|
@@ -1222,6 +1272,23 @@ addHook({
|
|
|
1222
1272
|
}, (runtimePackage) => {
|
|
1223
1273
|
const Runtime = runtimePackage.default ?? runtimePackage
|
|
1224
1274
|
|
|
1275
|
+
shimmer.wrap(Runtime.prototype, '_createJestObjectFor', _createJestObjectFor => function (from) {
|
|
1276
|
+
const result = _createJestObjectFor.apply(this, arguments)
|
|
1277
|
+
const suiteFilePath = this._testPath
|
|
1278
|
+
|
|
1279
|
+
shimmer.wrap(result, 'mock', mock => function (moduleName) {
|
|
1280
|
+
if (suiteFilePath) {
|
|
1281
|
+
const existingMockedFiles = testSuiteMockedFiles.get(suiteFilePath) || []
|
|
1282
|
+
const suiteDir = path.dirname(suiteFilePath)
|
|
1283
|
+
const mockPath = path.resolve(suiteDir, moduleName)
|
|
1284
|
+
existingMockedFiles.push(mockPath)
|
|
1285
|
+
testSuiteMockedFiles.set(suiteFilePath, existingMockedFiles)
|
|
1286
|
+
}
|
|
1287
|
+
return mock.apply(this, arguments)
|
|
1288
|
+
})
|
|
1289
|
+
return result
|
|
1290
|
+
})
|
|
1291
|
+
|
|
1225
1292
|
shimmer.wrap(Runtime.prototype, 'requireModuleOrMock', requireModuleOrMock => function (from, moduleName) {
|
|
1226
1293
|
// TODO: do this for every library that we instrument
|
|
1227
1294
|
if (shouldBypassJestRequireEngine(moduleName)) {
|
|
@@ -1234,19 +1301,27 @@ addHook({
|
|
|
1234
1301
|
return runtimePackage
|
|
1235
1302
|
})
|
|
1236
1303
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1304
|
+
function onMessageWrapper (onMessage) {
|
|
1305
|
+
return function () {
|
|
1306
|
+
const [code, data] = arguments[0]
|
|
1307
|
+
if (code === JEST_WORKER_TRACE_PAYLOAD_CODE) { // datadog trace payload
|
|
1308
|
+
workerReportTraceCh.publish(data)
|
|
1309
|
+
return
|
|
1310
|
+
}
|
|
1311
|
+
if (code === JEST_WORKER_COVERAGE_PAYLOAD_CODE) { // datadog coverage payload
|
|
1312
|
+
workerReportCoverageCh.publish(data)
|
|
1313
|
+
return
|
|
1314
|
+
}
|
|
1315
|
+
if (code === JEST_WORKER_LOGS_PAYLOAD_CODE) { // datadog logs payload
|
|
1316
|
+
workerReportLogsCh.publish(data)
|
|
1317
|
+
return
|
|
1318
|
+
}
|
|
1319
|
+
return onMessage.apply(this, arguments)
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
function sendWrapper (send) {
|
|
1324
|
+
return function (request) {
|
|
1250
1325
|
if (!isKnownTestsEnabled && !isTestManagementTestsEnabled && !isImpactedTestsEnabled) {
|
|
1251
1326
|
return send.apply(this, arguments)
|
|
1252
1327
|
}
|
|
@@ -1284,24 +1359,47 @@ addHook({
|
|
|
1284
1359
|
}
|
|
1285
1360
|
}
|
|
1286
1361
|
}
|
|
1287
|
-
|
|
1288
1362
|
return send.apply(this, arguments)
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
function enqueueWrapper (enqueue) {
|
|
1367
|
+
return function () {
|
|
1368
|
+
shimmer.wrap(arguments[0], 'onStart', onStart => function (worker) {
|
|
1369
|
+
if (worker && !wrappedWorkers.has(worker)) {
|
|
1370
|
+
shimmer.wrap(worker._child, 'send', sendWrapper)
|
|
1371
|
+
shimmer.wrap(worker, '_onMessage', onMessageWrapper)
|
|
1372
|
+
worker._child.on('message', worker._onMessage.bind(worker))
|
|
1373
|
+
wrappedWorkers.add(worker)
|
|
1374
|
+
}
|
|
1375
|
+
return onStart.apply(this, arguments)
|
|
1376
|
+
})
|
|
1377
|
+
return enqueue.apply(this, arguments)
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
/*
|
|
1382
|
+
* This hook does three things:
|
|
1383
|
+
* - Pass known tests to the workers.
|
|
1384
|
+
* - Pass test management tests to the workers.
|
|
1385
|
+
* - Receive trace, coverage and logs payloads from the workers.
|
|
1386
|
+
*/
|
|
1387
|
+
addHook({
|
|
1388
|
+
name: 'jest-worker',
|
|
1389
|
+
versions: ['>=24.9.0 <30.0.0'],
|
|
1390
|
+
file: 'build/workers/ChildProcessWorker.js'
|
|
1391
|
+
}, (childProcessWorker) => {
|
|
1392
|
+
const ChildProcessWorker = childProcessWorker.default
|
|
1393
|
+
shimmer.wrap(ChildProcessWorker.prototype, 'send', sendWrapper)
|
|
1394
|
+
shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', onMessageWrapper)
|
|
1306
1395
|
return childProcessWorker
|
|
1307
1396
|
})
|
|
1397
|
+
|
|
1398
|
+
addHook({
|
|
1399
|
+
name: 'jest-worker',
|
|
1400
|
+
versions: ['>=30.0.0']
|
|
1401
|
+
}, (jestWorkerPackage) => {
|
|
1402
|
+
shimmer.wrap(jestWorkerPackage.FifoQueue.prototype, 'enqueue', enqueueWrapper)
|
|
1403
|
+
shimmer.wrap(jestWorkerPackage.PriorityQueue.prototype, 'enqueue', enqueueWrapper)
|
|
1404
|
+
return jestWorkerPackage
|
|
1405
|
+
})
|