dd-trace 5.103.0 → 5.105.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 +90 -102
- package/index.d.ts +107 -6
- package/package.json +18 -17
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +15 -2
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
- package/packages/datadog-instrumentations/src/cucumber.js +181 -35
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -67
- package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +31 -229
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/ioredis.js +3 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +390 -183
- package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/memcached.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
- package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
- package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
- package/packages/datadog-instrumentations/src/mongoose.js +10 -12
- package/packages/datadog-instrumentations/src/mysql.js +2 -2
- package/packages/datadog-instrumentations/src/mysql2.js +1 -1
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pg.js +1 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +537 -297
- package/packages/datadog-instrumentations/src/router.js +80 -34
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +246 -149
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +223 -45
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-graphql/src/utils.js +4 -1
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +35 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +311 -35
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-redis/src/index.js +37 -2
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +19 -0
- package/packages/datadog-plugin-vitest/src/index.js +24 -20
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +49 -21
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/blocking.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +11 -4
- package/packages/dd-trace/src/appsec/reporter.js +24 -11
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
- package/packages/dd-trace/src/config/supported-configurations.json +36 -8
- package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
- package/packages/dd-trace/src/datastreams/context.js +4 -2
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +57 -42
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/exporters/common/agents.js +3 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -1
- package/packages/dd-trace/src/id.js +17 -4
- package/packages/dd-trace/src/lambda/handler.js +2 -4
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +10 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/log/writer.js +3 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/noop/span.js +3 -1
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/apollo.js +3 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -46
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +48 -8
- package/packages/dd-trace/src/plugins/util/git.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +318 -13
- package/packages/dd-trace/src/plugins/util/web.js +89 -64
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/scope.js +7 -5
- package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- 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/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
- package/vendor/dist/opentracing/LICENSE +0 -201
- package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
- package/vendor/dist/opentracing/constants.d.ts +0 -61
- package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
- package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
- package/vendor/dist/opentracing/functions.d.ts +0 -20
- package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
- package/vendor/dist/opentracing/index.d.ts +0 -12
- package/vendor/dist/opentracing/index.js +0 -1
- package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
- package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
- package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
- package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
- package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
- package/vendor/dist/opentracing/noop.d.ts +0 -8
- package/vendor/dist/opentracing/reference.d.ts +0 -33
- package/vendor/dist/opentracing/span.d.ts +0 -147
- package/vendor/dist/opentracing/span_context.d.ts +0 -26
- package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
- package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
- package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
- package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
- package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
- package/vendor/dist/opentracing/tracer.d.ts +0 -127
|
@@ -6,18 +6,24 @@ const { DD_MAJOR } = require('../../../../version')
|
|
|
6
6
|
const { addHook, channel } = require('../helpers/instrument')
|
|
7
7
|
const shimmer = require('../../../datadog-shimmer')
|
|
8
8
|
const { isMarkedAsUnskippable } = require('../../../datadog-plugin-jest/src/util')
|
|
9
|
+
const { writeCoverageBackfillToCache } = require('../../../dd-trace/src/ci-visibility/test-optimization-cache')
|
|
9
10
|
const log = require('../../../dd-trace/src/log')
|
|
10
11
|
const { getEnvironmentVariable } = require('../../../dd-trace/src/config/helper')
|
|
11
12
|
const {
|
|
12
13
|
getTestSuitePath,
|
|
13
14
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
14
15
|
fromCoverageMapToCoverage,
|
|
15
|
-
|
|
16
|
+
getCoveredFilesFromCoverage,
|
|
17
|
+
getExecutableFilesFromCoverage,
|
|
18
|
+
applySkippedCoverageToCoverage,
|
|
16
19
|
mergeCoverage,
|
|
17
20
|
resetCoverage,
|
|
18
21
|
getIsFaultyEarlyFlakeDetection,
|
|
22
|
+
getRelativeCoverageFiles,
|
|
23
|
+
getTestCoverageLinesPercentage,
|
|
19
24
|
collectTestOptimizationSummariesFromTraces,
|
|
20
25
|
logTestOptimizationSummary,
|
|
26
|
+
getTestOptimizationRequestResults,
|
|
21
27
|
} = require('../../../dd-trace/src/plugins/util/test')
|
|
22
28
|
|
|
23
29
|
const {
|
|
@@ -52,6 +58,8 @@ const unskippableSuites = []
|
|
|
52
58
|
let suitesToSkip = []
|
|
53
59
|
let isSuitesSkipped = false
|
|
54
60
|
let skippedSuites = []
|
|
61
|
+
let skippableSuitesCoverage = {}
|
|
62
|
+
let skippedSuitesCoverage = {}
|
|
55
63
|
let itrCorrelationId = ''
|
|
56
64
|
let isForcedToRun = false
|
|
57
65
|
const config = {}
|
|
@@ -109,10 +117,56 @@ function isTestFailed (test) {
|
|
|
109
117
|
return false
|
|
110
118
|
}
|
|
111
119
|
|
|
120
|
+
function getRootSuiteStatus (rootTests) {
|
|
121
|
+
let status = 'pass'
|
|
122
|
+
if (rootTests.every(t => t.isPending())) {
|
|
123
|
+
status = 'skip'
|
|
124
|
+
} else {
|
|
125
|
+
for (const test of rootTests) {
|
|
126
|
+
if (test.state === 'failed' || test.timedOut || test._ddHookFailed) {
|
|
127
|
+
status = 'fail'
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return status
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function haveRootTestsFinished (rootTests) {
|
|
135
|
+
for (const test of rootTests) {
|
|
136
|
+
if (!test.isPending() && !test.state && !test.timedOut && !test._ddHookFailed) {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return true
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getSuitePath (suite) {
|
|
144
|
+
return getTestSuitePath(suite.file, process.cwd())
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function getSuitesToSkip (originalSuites) {
|
|
148
|
+
return getSuitesToSkipFromPaths(originalSuites.map(getSuitePath))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getSuitesToSkipFromPaths (localSuites) {
|
|
152
|
+
const localSuitesSet = new Set(localSuites)
|
|
153
|
+
const suitesToSkipForRun = []
|
|
154
|
+
|
|
155
|
+
for (const suite of suitesToSkip) {
|
|
156
|
+
if (localSuitesSet.has(suite)) {
|
|
157
|
+
suitesToSkipForRun.push(suite)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return suitesToSkipForRun
|
|
162
|
+
}
|
|
163
|
+
|
|
112
164
|
function getFilteredSuites (originalSuites) {
|
|
165
|
+
const suitesToSkipForRun = getSuitesToSkip(originalSuites)
|
|
166
|
+
|
|
113
167
|
return originalSuites.reduce((acc, suite) => {
|
|
114
|
-
const testPath =
|
|
115
|
-
const shouldSkip =
|
|
168
|
+
const testPath = getSuitePath(suite)
|
|
169
|
+
const shouldSkip = suitesToSkipForRun.includes(testPath)
|
|
116
170
|
const isUnskippable = unskippableSuites.includes(suite.file)
|
|
117
171
|
if (shouldSkip && !isUnskippable) {
|
|
118
172
|
acc.skippedSuites.add(testPath)
|
|
@@ -120,7 +174,50 @@ function getFilteredSuites (originalSuites) {
|
|
|
120
174
|
acc.suitesToRun.push(suite)
|
|
121
175
|
}
|
|
122
176
|
return acc
|
|
123
|
-
}, { suitesToRun: [], skippedSuites: new Set() })
|
|
177
|
+
}, { suitesToRun: [], skippedSuites: new Set(), suitesToSkipForRun })
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function hasSkippableSuitesCoverage () {
|
|
181
|
+
return skippableSuitesCoverage &&
|
|
182
|
+
typeof skippableSuitesCoverage === 'object' &&
|
|
183
|
+
Object.keys(skippableSuitesCoverage).length > 0
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function isTiaCoverageBackfillEnabled () {
|
|
187
|
+
return config.isItrEnabled && config.isCoverageReportUploadEnabled
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getCoverageRootDir () {
|
|
191
|
+
return config.repositoryRoot || process.cwd()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function shouldReportCodeCoverageLinesPct (hasBackfilledCoverage) {
|
|
195
|
+
return !isSuitesSkipped || hasBackfilledCoverage
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function getSkippedSuitesCoverageForRun () {
|
|
199
|
+
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
|
|
200
|
+
? skippableSuitesCoverage
|
|
201
|
+
: {}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function applySkippedCoverageToMochaCoverageMap () {
|
|
205
|
+
if (!isTiaCoverageBackfillEnabled()) return false
|
|
206
|
+
return applySkippedCoverageToCoverage(originalCoverageMap, skippedSuitesCoverage, getCoverageRootDir())
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function getMochaTestSessionCoverageFiles () {
|
|
210
|
+
return getRelativeCoverageFiles(getExecutableFilesFromCoverage(originalCoverageMap), getCoverageRootDir())
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function resetSuiteSkippingRunState () {
|
|
214
|
+
isSuitesSkipped = false
|
|
215
|
+
skippedSuites = []
|
|
216
|
+
skippableSuitesCoverage = {}
|
|
217
|
+
skippedSuitesCoverage = {}
|
|
218
|
+
untestedCoverage = undefined
|
|
219
|
+
config.repositoryRoot = undefined
|
|
220
|
+
writeCoverageBackfillToCache({})
|
|
124
221
|
}
|
|
125
222
|
|
|
126
223
|
function getOnStartHandler (frameworkVersion) {
|
|
@@ -194,12 +291,24 @@ function getOnEndHandler (isParallel) {
|
|
|
194
291
|
testFileToSuiteCtx.clear()
|
|
195
292
|
|
|
196
293
|
let testCodeCoverageLinesTotal
|
|
197
|
-
|
|
294
|
+
let testSessionCoverageFiles
|
|
295
|
+
if (global.__coverage__ || untestedCoverage) {
|
|
198
296
|
try {
|
|
297
|
+
let hasBackfilledCoverage = false
|
|
199
298
|
if (untestedCoverage) {
|
|
200
299
|
originalCoverageMap.merge(fromCoverageMapToCoverage(untestedCoverage))
|
|
201
300
|
}
|
|
202
|
-
|
|
301
|
+
hasBackfilledCoverage = applySkippedCoverageToMochaCoverageMap()
|
|
302
|
+
if (shouldReportCodeCoverageLinesPct(hasBackfilledCoverage)) {
|
|
303
|
+
testCodeCoverageLinesTotal = getTestCoverageLinesPercentage(
|
|
304
|
+
originalCoverageMap,
|
|
305
|
+
undefined,
|
|
306
|
+
getCoverageRootDir()
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
if (isTiaCoverageBackfillEnabled()) {
|
|
310
|
+
testSessionCoverageFiles = getMochaTestSessionCoverageFiles()
|
|
311
|
+
}
|
|
203
312
|
} catch {
|
|
204
313
|
// ignore errors
|
|
205
314
|
}
|
|
@@ -211,6 +320,7 @@ function getOnEndHandler (isParallel) {
|
|
|
211
320
|
status,
|
|
212
321
|
isSuitesSkipped,
|
|
213
322
|
testCodeCoverageLinesTotal,
|
|
323
|
+
testSessionCoverageFiles,
|
|
214
324
|
numSkippedSuites: skippedSuites.length,
|
|
215
325
|
hasForcedToRunSuites: isForcedToRun,
|
|
216
326
|
hasUnskippableSuites: !!unskippableSuites.length,
|
|
@@ -226,22 +336,65 @@ function getOnEndHandler (isParallel) {
|
|
|
226
336
|
}
|
|
227
337
|
}
|
|
228
338
|
|
|
229
|
-
function
|
|
339
|
+
function getRunStoresPromise (channelToPublishTo, ctx) {
|
|
340
|
+
return new Promise(resolve => {
|
|
341
|
+
channelToPublishTo.runStores({ ...ctx, onDone: resolve }, () => {})
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function applyKnownTestsResponse ({ err, knownTests }) {
|
|
346
|
+
if (err) {
|
|
347
|
+
config.knownTests = []
|
|
348
|
+
config.isEarlyFlakeDetectionEnabled = false
|
|
349
|
+
config.isKnownTestsEnabled = false
|
|
350
|
+
} else {
|
|
351
|
+
config.knownTests = knownTests
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function applyTestManagementTestsResponse ({ err, testManagementTests: receivedTestManagementTests }) {
|
|
356
|
+
if (err) {
|
|
357
|
+
config.testManagementTests = {}
|
|
358
|
+
config.isTestManagementTestsEnabled = false
|
|
359
|
+
config.testManagementAttemptToFixRetries = 0
|
|
360
|
+
} else {
|
|
361
|
+
config.testManagementTests = receivedTestManagementTests
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFinishRequest, localSuites) {
|
|
230
366
|
const ctx = {
|
|
231
367
|
isParallel,
|
|
232
368
|
frameworkVersion,
|
|
233
369
|
}
|
|
234
|
-
|
|
235
|
-
|
|
370
|
+
let skippableSuitesResponse
|
|
371
|
+
resetSuiteSkippingRunState()
|
|
372
|
+
|
|
373
|
+
const onReceivedSkippableSuites = ({
|
|
374
|
+
err,
|
|
375
|
+
skippableSuites,
|
|
376
|
+
itrCorrelationId: responseItrCorrelationId,
|
|
377
|
+
skippableSuitesCoverage: responseSkippableSuitesCoverage,
|
|
378
|
+
}) => {
|
|
236
379
|
if (err) {
|
|
237
380
|
suitesToSkip = []
|
|
381
|
+
skippableSuitesCoverage = {}
|
|
238
382
|
} else {
|
|
239
383
|
suitesToSkip = skippableSuites
|
|
240
384
|
itrCorrelationId = responseItrCorrelationId
|
|
385
|
+
skippableSuitesCoverage = responseSkippableSuitesCoverage || {}
|
|
386
|
+
}
|
|
387
|
+
if (localSuites) {
|
|
388
|
+
suitesToSkip = getSuitesToSkipFromPaths(localSuites)
|
|
389
|
+
mochaGlobalRunCh.runStores(ctx, () => {
|
|
390
|
+
onFinishRequest()
|
|
391
|
+
})
|
|
392
|
+
return
|
|
241
393
|
}
|
|
394
|
+
|
|
242
395
|
// We remove the suites that we skip through ITR
|
|
243
396
|
const filteredSuites = getFilteredSuites(runner.suite.suites)
|
|
244
|
-
const { suitesToRun } = filteredSuites
|
|
397
|
+
const { suitesToRun, suitesToSkipForRun } = filteredSuites
|
|
245
398
|
|
|
246
399
|
isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
|
|
247
400
|
|
|
@@ -250,12 +403,25 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
250
403
|
runner.suite.suites = suitesToRun
|
|
251
404
|
|
|
252
405
|
skippedSuites = [...filteredSuites.skippedSuites]
|
|
406
|
+
suitesToSkip = suitesToSkipForRun
|
|
407
|
+
skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
|
|
408
|
+
writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
|
|
253
409
|
|
|
254
410
|
mochaGlobalRunCh.runStores(ctx, () => {
|
|
255
411
|
onFinishRequest()
|
|
256
412
|
})
|
|
257
413
|
}
|
|
258
414
|
|
|
415
|
+
const requestSkippableSuites = () => {
|
|
416
|
+
if (skippableSuitesResponse) {
|
|
417
|
+
onReceivedSkippableSuites(skippableSuitesResponse)
|
|
418
|
+
return
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
ctx.onDone = onReceivedSkippableSuites
|
|
422
|
+
skippableSuitesCh.runStores(ctx, () => {})
|
|
423
|
+
}
|
|
424
|
+
|
|
259
425
|
const onReceivedImpactedTests = ({ err, modifiedFiles: receivedModifiedFiles }) => {
|
|
260
426
|
if (err) {
|
|
261
427
|
config.modifiedFiles = []
|
|
@@ -264,8 +430,7 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
264
430
|
config.modifiedFiles = receivedModifiedFiles
|
|
265
431
|
}
|
|
266
432
|
if (config.isSuitesSkippingEnabled) {
|
|
267
|
-
|
|
268
|
-
skippableSuitesCh.runStores(ctx, () => {})
|
|
433
|
+
requestSkippableSuites()
|
|
269
434
|
} else {
|
|
270
435
|
mochaGlobalRunCh.runStores(ctx, () => {
|
|
271
436
|
onFinishRequest()
|
|
@@ -273,44 +438,12 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
273
438
|
}
|
|
274
439
|
}
|
|
275
440
|
|
|
276
|
-
const
|
|
277
|
-
if (err) {
|
|
278
|
-
config.testManagementTests = {}
|
|
279
|
-
config.isTestManagementTestsEnabled = false
|
|
280
|
-
config.testManagementAttemptToFixRetries = 0
|
|
281
|
-
} else {
|
|
282
|
-
config.testManagementTests = receivedTestManagementTests
|
|
283
|
-
}
|
|
441
|
+
const continueAfterTestRequests = () => {
|
|
284
442
|
if (config.isImpactedTestsEnabled) {
|
|
285
443
|
ctx.onDone = onReceivedImpactedTests
|
|
286
444
|
modifiedFilesCh.runStores(ctx, () => {})
|
|
287
445
|
} else if (config.isSuitesSkippingEnabled) {
|
|
288
|
-
|
|
289
|
-
skippableSuitesCh.runStores(ctx, () => {})
|
|
290
|
-
} else {
|
|
291
|
-
mochaGlobalRunCh.runStores(ctx, () => {
|
|
292
|
-
onFinishRequest()
|
|
293
|
-
})
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const onReceivedKnownTests = ({ err, knownTests }) => {
|
|
298
|
-
if (err) {
|
|
299
|
-
config.knownTests = []
|
|
300
|
-
config.isEarlyFlakeDetectionEnabled = false
|
|
301
|
-
config.isKnownTestsEnabled = false
|
|
302
|
-
} else {
|
|
303
|
-
config.knownTests = knownTests
|
|
304
|
-
}
|
|
305
|
-
if (config.isTestManagementTestsEnabled) {
|
|
306
|
-
ctx.onDone = onReceivedTestManagementTests
|
|
307
|
-
testManagementTestsCh.runStores(ctx, () => {})
|
|
308
|
-
} else if (config.isImpactedTestsEnabled) {
|
|
309
|
-
ctx.onDone = onReceivedImpactedTests
|
|
310
|
-
modifiedFilesCh.runStores(ctx, () => {})
|
|
311
|
-
} else if (config.isSuitesSkippingEnabled) {
|
|
312
|
-
ctx.onDone = onReceivedSkippableSuites
|
|
313
|
-
skippableSuitesCh.runStores(ctx, () => {})
|
|
446
|
+
requestSkippableSuites()
|
|
314
447
|
} else {
|
|
315
448
|
mochaGlobalRunCh.runStores(ctx, () => {
|
|
316
449
|
onFinishRequest()
|
|
@@ -318,12 +451,13 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
318
451
|
}
|
|
319
452
|
}
|
|
320
453
|
|
|
321
|
-
const onReceivedConfiguration = ({ err, libraryConfig }) => {
|
|
454
|
+
const onReceivedConfiguration = ({ err, libraryConfig, repositoryRoot }) => {
|
|
322
455
|
if (err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
|
|
323
456
|
return mochaGlobalRunCh.runStores(ctx, () => {
|
|
324
457
|
onFinishRequest()
|
|
325
458
|
})
|
|
326
459
|
}
|
|
460
|
+
config.repositoryRoot = repositoryRoot
|
|
327
461
|
config.isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
328
462
|
config.earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
329
463
|
config.earlyFlakeDetectionSlowTestRetries = libraryConfig.earlyFlakeDetectionSlowTestRetries ?? {}
|
|
@@ -332,27 +466,37 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
332
466
|
config.isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
|
|
333
467
|
config.testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
|
|
334
468
|
config.isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
|
|
335
|
-
config.
|
|
469
|
+
config.isItrEnabled = libraryConfig.isItrEnabled
|
|
470
|
+
config.isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
|
|
471
|
+
config.isCoverageReportUploadEnabled = libraryConfig.isCoverageReportUploadEnabled
|
|
472
|
+
config.isSuitesSkippingEnabled = config.isItrEnabled && libraryConfig.isSuitesSkippingEnabled
|
|
336
473
|
config.isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
|
|
337
474
|
config.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
|
|
338
475
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
476
|
+
getTestOptimizationRequestResults({
|
|
477
|
+
isKnownTestsEnabled: config.isKnownTestsEnabled,
|
|
478
|
+
isTestManagementTestsEnabled: config.isTestManagementTestsEnabled,
|
|
479
|
+
isSuitesSkippingEnabled: config.isSuitesSkippingEnabled,
|
|
480
|
+
getKnownTests: () => getRunStoresPromise(knownTestsCh, ctx),
|
|
481
|
+
getTestManagementTests: () => getRunStoresPromise(testManagementTestsCh, ctx),
|
|
482
|
+
getSkippableSuites: () => getRunStoresPromise(skippableSuitesCh, ctx),
|
|
483
|
+
}).then(requestResults => {
|
|
484
|
+
const {
|
|
485
|
+
knownTestsResponse,
|
|
486
|
+
testManagementTestsResponse,
|
|
487
|
+
skippableSuitesResponse: requestSkippableSuitesResponse,
|
|
488
|
+
} = requestResults
|
|
489
|
+
|
|
490
|
+
if (knownTestsResponse) {
|
|
491
|
+
applyKnownTestsResponse(knownTestsResponse)
|
|
492
|
+
}
|
|
493
|
+
if (testManagementTestsResponse) {
|
|
494
|
+
applyTestManagementTestsResponse(testManagementTestsResponse)
|
|
495
|
+
}
|
|
496
|
+
skippableSuitesResponse = requestSkippableSuitesResponse
|
|
497
|
+
|
|
498
|
+
continueAfterTestRequests()
|
|
499
|
+
})
|
|
356
500
|
}
|
|
357
501
|
|
|
358
502
|
ctx.onDone = onReceivedConfiguration
|
|
@@ -473,22 +617,166 @@ addHook({
|
|
|
473
617
|
// Populated during the root 'suite' event so the normal finish path can include them
|
|
474
618
|
// in mixed-file status calculation.
|
|
475
619
|
const rootTestsByFile = new Map()
|
|
620
|
+
// Counts how many original tests per pure-root file still need their final attempt.
|
|
621
|
+
// Hits zero when the last test's lifecycle completes, triggering the suite finish.
|
|
622
|
+
const rootPendingCountByFile = new Map()
|
|
623
|
+
const rootFinalizationPendingCountByFile = new Map()
|
|
624
|
+
const rootFallbackPendingFiles = new Set()
|
|
625
|
+
const rootFinalizationPendingTests = new WeakSet()
|
|
626
|
+
let pendingRootFinalizations = 0
|
|
627
|
+
let hasEnded = false
|
|
628
|
+
let hasFinishedRun = false
|
|
629
|
+
let endRunner
|
|
630
|
+
|
|
631
|
+
function updateRootTestForFinalAttempt (test) {
|
|
632
|
+
if (!test._retriedTest) return
|
|
633
|
+
|
|
634
|
+
const rootTests = rootTestsByFile.get(test.file)
|
|
635
|
+
if (!rootTests) return
|
|
636
|
+
|
|
637
|
+
const retriedTestIndex = rootTests.indexOf(test._retriedTest)
|
|
638
|
+
if (retriedTestIndex !== -1) {
|
|
639
|
+
rootTests[retriedTestIndex] = test
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function finishRunIfReady () {
|
|
644
|
+
if (hasFinishedRun) return
|
|
645
|
+
if (hasEnded && pendingRootFinalizations === 0) {
|
|
646
|
+
hasFinishedRun = true
|
|
647
|
+
onEnd.call(endRunner)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function incrementPendingRootFinalization (test) {
|
|
652
|
+
if (!rootPendingCountByFile.has(test.file) || rootFinalizationPendingTests.has(test)) return
|
|
653
|
+
|
|
654
|
+
rootFinalizationPendingTests.add(test)
|
|
655
|
+
pendingRootFinalizations++
|
|
656
|
+
rootFinalizationPendingCountByFile.set(
|
|
657
|
+
test.file,
|
|
658
|
+
(rootFinalizationPendingCountByFile.get(test.file) || 0) + 1
|
|
659
|
+
)
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function decrementPendingRootFinalization (test) {
|
|
663
|
+
if (!rootFinalizationPendingTests.has(test)) return
|
|
664
|
+
|
|
665
|
+
rootFinalizationPendingTests.delete(test)
|
|
666
|
+
pendingRootFinalizations--
|
|
667
|
+
|
|
668
|
+
const remaining = rootFinalizationPendingCountByFile.get(test.file) - 1
|
|
669
|
+
if (remaining > 0) {
|
|
670
|
+
rootFinalizationPendingCountByFile.set(test.file, remaining)
|
|
671
|
+
} else {
|
|
672
|
+
rootFinalizationPendingCountByFile.delete(test.file)
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
if (!rootFinalizationPendingCountByFile.has(test.file) && rootFallbackPendingFiles.delete(test.file)) {
|
|
676
|
+
finishRootSuiteFallbackForFile(test.file)
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
finishRunIfReady()
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function finishRootSuiteForFile (file) {
|
|
683
|
+
const remaining = rootPendingCountByFile.get(file) - 1
|
|
684
|
+
if (remaining > 0) {
|
|
685
|
+
rootPendingCountByFile.set(file, remaining)
|
|
686
|
+
return
|
|
687
|
+
}
|
|
688
|
+
rootPendingCountByFile.delete(file)
|
|
689
|
+
|
|
690
|
+
const ctx = testFileToSuiteCtx.get(file)
|
|
691
|
+
if (!ctx) {
|
|
692
|
+
log.warn('No ctx found for suite', file)
|
|
693
|
+
return
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const rootTests = rootTestsByFile.get(file) || []
|
|
697
|
+
const status = getRootSuiteStatus(rootTests)
|
|
698
|
+
|
|
699
|
+
if (global.__coverage__) {
|
|
700
|
+
const coverageFiles = getCoveredFilesFromCoverage(global.__coverage__)
|
|
701
|
+
testSuiteCodeCoverageCh.publish({ coverageFiles, suiteFile: file })
|
|
702
|
+
mergeCoverage(global.__coverage__, originalCoverageMap)
|
|
703
|
+
resetCoverage(global.__coverage__)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
testSuiteFinishCh.publish({ status, ...ctx.currentStore }, () => {})
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function finishRootSuiteFallbackForFile (file) {
|
|
710
|
+
const ctx = testFileToSuiteCtx.get(file)
|
|
711
|
+
if (!ctx || !rootPendingCountByFile.has(file)) return
|
|
712
|
+
|
|
713
|
+
const rootTests = rootTestsByFile.get(file) || []
|
|
714
|
+
const status = haveRootTestsFinished(rootTests) ? getRootSuiteStatus(rootTests) : 'fail'
|
|
715
|
+
rootPendingCountByFile.delete(file)
|
|
716
|
+
testSuiteFinishCh.publish({ status, ...ctx.currentStore }, () => {})
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
function finishRootSuiteAfterFinalAttempt (test) {
|
|
720
|
+
if (!test._ddIsFinalAttempt || !rootPendingCountByFile.has(test.file)) return
|
|
721
|
+
|
|
722
|
+
updateRootTestForFinalAttempt(test)
|
|
723
|
+
finishRootSuiteForFile(test.file)
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const onEnd = getOnEndHandler(false)
|
|
476
727
|
|
|
477
728
|
this.once('start', getOnStartHandler(frameworkVersion))
|
|
478
729
|
|
|
479
|
-
this.once('end',
|
|
730
|
+
this.once('end', function () {
|
|
731
|
+
hasEnded = true
|
|
732
|
+
endRunner = this
|
|
733
|
+
finishRunIfReady()
|
|
734
|
+
})
|
|
735
|
+
|
|
736
|
+
// The job of this listener is to
|
|
737
|
+
// initialize the suite span tag in correct order
|
|
738
|
+
// (that is suiteA -> testA ... -> suiteB -> testB
|
|
739
|
+
// instead of suiteA -> suiteB -> testA -> ... -> testB)
|
|
740
|
+
// when the suite has tests that are in the top level
|
|
741
|
+
// (no describe(...))
|
|
742
|
+
this.on('test', function (test) {
|
|
743
|
+
const ctx = testFileToSuiteCtx.get(test.file)
|
|
744
|
+
if (ctx?._pendingRootStart) {
|
|
745
|
+
ctx._pendingRootStart = false
|
|
746
|
+
testSuiteStartCh.runStores(ctx, () => {})
|
|
747
|
+
}
|
|
748
|
+
})
|
|
480
749
|
|
|
481
750
|
this.on('test', getOnTestHandler(true))
|
|
482
751
|
|
|
483
|
-
this.on('test end', getOnTestEndHandler(config
|
|
752
|
+
this.on('test end', getOnTestEndHandler(config, {
|
|
753
|
+
onStart: incrementPendingRootFinalization,
|
|
754
|
+
onFinish: function (test) {
|
|
755
|
+
finishRootSuiteAfterFinalAttempt(test)
|
|
756
|
+
decrementPendingRootFinalization(test)
|
|
757
|
+
},
|
|
758
|
+
}))
|
|
484
759
|
|
|
485
760
|
this.on('retry', getOnTestRetryHandler(config))
|
|
486
761
|
|
|
487
762
|
// If the hook passes, 'hook end' will be emitted. Otherwise, 'fail' will be emitted
|
|
488
763
|
this.on('hook end', getOnHookEndHandler(config))
|
|
489
764
|
|
|
765
|
+
this.on('hook end', function (hook) {
|
|
766
|
+
const test = hook.ctx?.currentTest
|
|
767
|
+
if (!test) return
|
|
768
|
+
finishRootSuiteAfterFinalAttempt(test)
|
|
769
|
+
})
|
|
770
|
+
|
|
490
771
|
this.on('fail', getOnFailHandler(true, config))
|
|
491
772
|
|
|
773
|
+
this.on('fail', function (testOrHook) {
|
|
774
|
+
if (testOrHook.type !== 'hook') return
|
|
775
|
+
const test = testOrHook.ctx?.currentTest
|
|
776
|
+
if (!test) return
|
|
777
|
+
finishRootSuiteAfterFinalAttempt(test)
|
|
778
|
+
})
|
|
779
|
+
|
|
492
780
|
this.on('pending', getOnPendingHandler())
|
|
493
781
|
|
|
494
782
|
this.on('suite', function (suite) {
|
|
@@ -503,7 +791,13 @@ addHook({
|
|
|
503
791
|
if (suite.root && suite.tests.length > 0) {
|
|
504
792
|
const files = new Set(suite.tests.map(test => test.file).filter(Boolean))
|
|
505
793
|
for (const file of files) {
|
|
506
|
-
|
|
794
|
+
const testsForFile = suite.tests.filter(t => t.file === file)
|
|
795
|
+
rootTestsByFile.set(file, testsForFile)
|
|
796
|
+
// Only track the countdown for pure root-level files.
|
|
797
|
+
// Mixed files are finished by the normal 'suite end' path.
|
|
798
|
+
if (!suitesByTestFile[file]) {
|
|
799
|
+
rootPendingCountByFile.set(file, testsForFile.length)
|
|
800
|
+
}
|
|
507
801
|
if (testFileToSuiteCtx.get(file)) continue
|
|
508
802
|
const isUnskippable = unskippableSuites.includes(file)
|
|
509
803
|
isForcedToRun = isUnskippable && suitesToSkip.includes(getTestSuitePath(file, process.cwd()))
|
|
@@ -512,9 +806,9 @@ addHook({
|
|
|
512
806
|
isUnskippable,
|
|
513
807
|
isForcedToRun,
|
|
514
808
|
itrCorrelationId,
|
|
809
|
+
_pendingRootStart: true, // Now the suite start fires lazily on the first test event for this file
|
|
515
810
|
}
|
|
516
811
|
testFileToSuiteCtx.set(file, ctx)
|
|
517
|
-
testSuiteStartCh.runStores(ctx, () => {})
|
|
518
812
|
}
|
|
519
813
|
}
|
|
520
814
|
return
|
|
@@ -536,42 +830,38 @@ addHook({
|
|
|
536
830
|
|
|
537
831
|
this.on('suite end', function (suite) {
|
|
538
832
|
if (suite.root) {
|
|
539
|
-
//
|
|
540
|
-
|
|
833
|
+
// Normal case: pure root-level files are finished by the 'test end' / 'hook end'
|
|
834
|
+
// listeners via finishRootSuiteForFile. Two edge cases remain here:
|
|
835
|
+
//
|
|
836
|
+
// 1. All-pending: no 'test' event fired, _pendingRootStart is still true.
|
|
837
|
+
// Start and immediately finish with 'skip'.
|
|
838
|
+
//
|
|
839
|
+
// 2. Aborted mid-run (e.g. a beforeEach hook failure): Mocha skips remaining
|
|
840
|
+
// tests and jumps straight to 'suite end'. rootPendingCountByFile still has
|
|
841
|
+
// a nonzero count for the file because the last tests never ran. Finish it
|
|
842
|
+
// as failed now.
|
|
843
|
+
//
|
|
844
|
+
// 3. Async finalization lagged behind Mocha's synchronous events (e.g. DI retry
|
|
845
|
+
// wait): all tests have Mocha terminal state, but the final-attempt callback
|
|
846
|
+
// did not run before root 'suite end'. Finish from the observed test states.
|
|
847
|
+
const processedFiles = new Set()
|
|
541
848
|
for (const test of suite.tests) {
|
|
542
|
-
if (!test.file) continue
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
status = 'skip'
|
|
556
|
-
} else {
|
|
557
|
-
for (const test of tests) {
|
|
558
|
-
if (test.state === 'failed' || test.timedOut) {
|
|
559
|
-
status = 'fail'
|
|
560
|
-
break
|
|
561
|
-
}
|
|
849
|
+
if (!test.file || processedFiles.has(test.file)) continue
|
|
850
|
+
processedFiles.add(test.file)
|
|
851
|
+
if (suitesByTestFile[test.file]) continue // mixed: handled by normal path
|
|
852
|
+
const ctx = testFileToSuiteCtx.get(test.file)
|
|
853
|
+
if (!ctx) continue
|
|
854
|
+
if (ctx._pendingRootStart) {
|
|
855
|
+
ctx._pendingRootStart = false
|
|
856
|
+
testSuiteStartCh.runStores(ctx, () => {})
|
|
857
|
+
testSuiteFinishCh.publish({ status: 'skip', ...ctx.currentStore }, () => {})
|
|
858
|
+
} else if (rootPendingCountByFile.has(test.file)) {
|
|
859
|
+
if (rootFinalizationPendingCountByFile.has(test.file)) {
|
|
860
|
+
rootFallbackPendingFiles.add(test.file)
|
|
861
|
+
continue
|
|
562
862
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const coverageFiles = getCoveredFilenamesFromCoverage(global.__coverage__)
|
|
566
|
-
testSuiteCodeCoverageCh.publish({ coverageFiles, suiteFile: file })
|
|
567
|
-
mergeCoverage(global.__coverage__, originalCoverageMap)
|
|
568
|
-
resetCoverage(global.__coverage__)
|
|
569
|
-
}
|
|
570
|
-
const ctx = testFileToSuiteCtx.get(file)
|
|
571
|
-
if (ctx) {
|
|
572
|
-
testSuiteFinishCh.publish({ status, ...ctx.currentStore }, () => {})
|
|
573
|
-
} else {
|
|
574
|
-
log.warn('No ctx found for suite', file)
|
|
863
|
+
|
|
864
|
+
finishRootSuiteFallbackForFile(test.file)
|
|
575
865
|
}
|
|
576
866
|
}
|
|
577
867
|
return
|
|
@@ -605,7 +895,7 @@ addHook({
|
|
|
605
895
|
}
|
|
606
896
|
|
|
607
897
|
if (global.__coverage__) {
|
|
608
|
-
const coverageFiles =
|
|
898
|
+
const coverageFiles = getCoveredFilesFromCoverage(global.__coverage__)
|
|
609
899
|
|
|
610
900
|
testSuiteCodeCoverageCh.publish({
|
|
611
901
|
coverageFiles,
|
|
@@ -727,11 +1017,11 @@ addHook({
|
|
|
727
1017
|
}
|
|
728
1018
|
}
|
|
729
1019
|
|
|
1020
|
+
const localSuites = files.map(file => getTestSuitePath(file, process.cwd()))
|
|
730
1021
|
getExecutionConfiguration(this, true, frameworkVersion, () => {
|
|
731
1022
|
if (config.isKnownTestsEnabled) {
|
|
732
|
-
const testSuites = files.map(file => getTestSuitePath(file, process.cwd()))
|
|
733
1023
|
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
734
|
-
|
|
1024
|
+
localSuites,
|
|
735
1025
|
config.knownTests?.mocha || {},
|
|
736
1026
|
config.earlyFlakeDetectionFaultyThreshold
|
|
737
1027
|
)
|
|
@@ -756,11 +1046,13 @@ addHook({
|
|
|
756
1046
|
}
|
|
757
1047
|
isSuitesSkipped = skippedFiles.length > 0
|
|
758
1048
|
skippedSuites = skippedFiles
|
|
1049
|
+
skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
|
|
1050
|
+
writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
|
|
759
1051
|
run.apply(this, [cb, { files: filteredFiles }])
|
|
760
1052
|
} else {
|
|
761
1053
|
run.apply(this, arguments)
|
|
762
1054
|
}
|
|
763
|
-
})
|
|
1055
|
+
}, localSuites)
|
|
764
1056
|
|
|
765
1057
|
return this
|
|
766
1058
|
})
|