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.
Files changed (213) hide show
  1. package/LICENSE-3rdparty.csv +90 -102
  2. package/index.d.ts +107 -6
  3. package/package.json +18 -17
  4. package/packages/datadog-core/src/storage.js +1 -1
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/ai.js +8 -7
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +15 -2
  8. package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
  10. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
  11. package/packages/datadog-instrumentations/src/cucumber.js +181 -35
  12. package/packages/datadog-instrumentations/src/dns.js +54 -18
  13. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  14. package/packages/datadog-instrumentations/src/fastify.js +142 -82
  15. package/packages/datadog-instrumentations/src/graphql.js +188 -67
  16. package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
  17. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
  18. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
  21. package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
  22. package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
  23. package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
  24. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +31 -229
  32. package/packages/datadog-instrumentations/src/hono.js +54 -3
  33. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  34. package/packages/datadog-instrumentations/src/http/server.js +9 -4
  35. package/packages/datadog-instrumentations/src/ioredis.js +3 -3
  36. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
  37. package/packages/datadog-instrumentations/src/jest.js +390 -183
  38. package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
  39. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  40. package/packages/datadog-instrumentations/src/memcached.js +2 -1
  41. package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
  42. package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
  43. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  44. package/packages/datadog-instrumentations/src/mongoose.js +10 -12
  45. package/packages/datadog-instrumentations/src/mysql.js +2 -2
  46. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  47. package/packages/datadog-instrumentations/src/nats.js +182 -0
  48. package/packages/datadog-instrumentations/src/nyc.js +38 -1
  49. package/packages/datadog-instrumentations/src/openai.js +33 -18
  50. package/packages/datadog-instrumentations/src/oracledb.js +6 -1
  51. package/packages/datadog-instrumentations/src/pg.js +1 -1
  52. package/packages/datadog-instrumentations/src/pino.js +17 -5
  53. package/packages/datadog-instrumentations/src/playwright.js +537 -297
  54. package/packages/datadog-instrumentations/src/router.js +80 -34
  55. package/packages/datadog-instrumentations/src/stripe.js +1 -1
  56. package/packages/datadog-instrumentations/src/vitest.js +246 -149
  57. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  58. package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
  59. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
  60. package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
  61. package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
  62. package/packages/datadog-plugin-bunyan/src/index.js +28 -0
  63. package/packages/datadog-plugin-cucumber/src/index.js +17 -3
  64. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +223 -45
  65. package/packages/datadog-plugin-cypress/src/support.js +69 -1
  66. package/packages/datadog-plugin-dns/src/lookup.js +8 -6
  67. package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
  68. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
  69. package/packages/datadog-plugin-graphql/src/execute.js +2 -0
  70. package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
  71. package/packages/datadog-plugin-graphql/src/utils.js +4 -1
  72. package/packages/datadog-plugin-http/src/server.js +40 -15
  73. package/packages/datadog-plugin-jest/src/index.js +11 -3
  74. package/packages/datadog-plugin-jest/src/util.js +15 -8
  75. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  76. package/packages/datadog-plugin-kafkajs/src/producer.js +35 -0
  77. package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
  78. package/packages/datadog-plugin-mocha/src/index.js +19 -4
  79. package/packages/datadog-plugin-mongodb-core/src/index.js +311 -35
  80. package/packages/datadog-plugin-nats/src/consumer.js +43 -0
  81. package/packages/datadog-plugin-nats/src/index.js +20 -0
  82. package/packages/datadog-plugin-nats/src/producer.js +62 -0
  83. package/packages/datadog-plugin-nats/src/util.js +33 -0
  84. package/packages/datadog-plugin-next/src/index.js +5 -3
  85. package/packages/datadog-plugin-openai/src/tracing.js +15 -2
  86. package/packages/datadog-plugin-oracledb/src/index.js +13 -2
  87. package/packages/datadog-plugin-pino/src/index.js +42 -0
  88. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  89. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  90. package/packages/datadog-plugin-redis/src/index.js +37 -2
  91. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  92. package/packages/datadog-plugin-router/src/index.js +33 -44
  93. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  94. package/packages/datadog-plugin-undici/src/index.js +19 -0
  95. package/packages/datadog-plugin-vitest/src/index.js +24 -20
  96. package/packages/datadog-plugin-winston/src/index.js +30 -0
  97. package/packages/datadog-shimmer/src/shimmer.js +49 -21
  98. package/packages/dd-trace/src/aiguard/index.js +1 -1
  99. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  100. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  101. package/packages/dd-trace/src/appsec/blocking.js +2 -2
  102. package/packages/dd-trace/src/appsec/index.js +11 -4
  103. package/packages/dd-trace/src/appsec/reporter.js +24 -11
  104. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  105. package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
  106. package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
  107. package/packages/dd-trace/src/baggage.js +7 -1
  108. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
  109. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
  110. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
  111. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
  112. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
  113. package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
  114. package/packages/dd-trace/src/config/supported-configurations.json +36 -8
  115. package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
  116. package/packages/dd-trace/src/datastreams/context.js +4 -2
  117. package/packages/dd-trace/src/datastreams/writer.js +2 -4
  118. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
  119. package/packages/dd-trace/src/encode/0.4.js +124 -108
  120. package/packages/dd-trace/src/encode/0.5.js +114 -26
  121. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +57 -42
  122. package/packages/dd-trace/src/encode/agentless-json.js +4 -2
  123. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
  124. package/packages/dd-trace/src/encode/span-stats.js +16 -16
  125. package/packages/dd-trace/src/encode/tags-processors.js +16 -0
  126. package/packages/dd-trace/src/exporters/common/agents.js +3 -1
  127. package/packages/dd-trace/src/exporters/common/request.js +3 -1
  128. package/packages/dd-trace/src/id.js +17 -4
  129. package/packages/dd-trace/src/lambda/handler.js +2 -4
  130. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  131. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  132. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  133. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
  134. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  135. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
  136. package/packages/dd-trace/src/llmobs/sdk.js +10 -16
  137. package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
  138. package/packages/dd-trace/src/llmobs/tagger.js +9 -1
  139. package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
  140. package/packages/dd-trace/src/llmobs/util.js +66 -3
  141. package/packages/dd-trace/src/log/index.js +1 -1
  142. package/packages/dd-trace/src/log/writer.js +3 -1
  143. package/packages/dd-trace/src/msgpack/chunk.js +394 -10
  144. package/packages/dd-trace/src/msgpack/index.js +96 -2
  145. package/packages/dd-trace/src/noop/span.js +3 -1
  146. package/packages/dd-trace/src/openfeature/encoding.js +70 -0
  147. package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
  148. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
  149. package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
  150. package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
  151. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
  152. package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
  153. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  154. package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
  155. package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
  156. package/packages/dd-trace/src/opentracing/span.js +59 -19
  157. package/packages/dd-trace/src/opentracing/span_context.js +49 -0
  158. package/packages/dd-trace/src/plugins/apollo.js +3 -1
  159. package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
  160. package/packages/dd-trace/src/plugins/database.js +7 -6
  161. package/packages/dd-trace/src/plugins/index.js +4 -0
  162. package/packages/dd-trace/src/plugins/log_injection.js +56 -0
  163. package/packages/dd-trace/src/plugins/log_plugin.js +3 -46
  164. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  165. package/packages/dd-trace/src/plugins/plugin.js +15 -17
  166. package/packages/dd-trace/src/plugins/tracing.js +48 -8
  167. package/packages/dd-trace/src/plugins/util/git.js +3 -1
  168. package/packages/dd-trace/src/plugins/util/test.js +318 -13
  169. package/packages/dd-trace/src/plugins/util/web.js +89 -64
  170. package/packages/dd-trace/src/priority_sampler.js +2 -2
  171. package/packages/dd-trace/src/profiling/profiler.js +2 -2
  172. package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
  173. package/packages/dd-trace/src/sampling_rule.js +7 -7
  174. package/packages/dd-trace/src/scope.js +7 -5
  175. package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
  176. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
  177. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  178. package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
  179. package/packages/dd-trace/src/span_format.js +190 -58
  180. package/packages/dd-trace/src/spanleak.js +1 -1
  181. package/packages/dd-trace/src/standalone/index.js +3 -3
  182. package/packages/dd-trace/src/tagger.js +0 -2
  183. package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
  184. package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
  185. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  186. package/vendor/dist/protobufjs/index.js +1 -1
  187. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  188. package/packages/dd-trace/src/msgpack/encoder.js +0 -308
  189. package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
  190. package/vendor/dist/opentracing/LICENSE +0 -201
  191. package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
  192. package/vendor/dist/opentracing/constants.d.ts +0 -61
  193. package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
  194. package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
  195. package/vendor/dist/opentracing/functions.d.ts +0 -20
  196. package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
  197. package/vendor/dist/opentracing/index.d.ts +0 -12
  198. package/vendor/dist/opentracing/index.js +0 -1
  199. package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
  200. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
  201. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
  202. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
  203. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
  204. package/vendor/dist/opentracing/noop.d.ts +0 -8
  205. package/vendor/dist/opentracing/reference.d.ts +0 -33
  206. package/vendor/dist/opentracing/span.d.ts +0 -147
  207. package/vendor/dist/opentracing/span_context.d.ts +0 -26
  208. package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
  209. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
  210. package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
  211. package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
  212. package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
  213. 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
- getCoveredFilenamesFromCoverage,
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 = getTestSuitePath(suite.file, process.cwd())
115
- const shouldSkip = suitesToSkip.includes(testPath)
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
- if (global.__coverage__) {
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
- testCodeCoverageLinesTotal = originalCoverageMap.getCoverageSummary().lines.pct
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 getExecutionConfiguration (runner, isParallel, frameworkVersion, onFinishRequest) {
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
- const onReceivedSkippableSuites = ({ err, skippableSuites, itrCorrelationId: responseItrCorrelationId }) => {
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
- ctx.onDone = onReceivedSkippableSuites
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 onReceivedTestManagementTests = ({ err, testManagementTests: receivedTestManagementTests }) => {
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
- ctx.onDone = onReceivedSkippableSuites
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.isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
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
- if (config.isKnownTestsEnabled) {
340
- ctx.onDone = onReceivedKnownTests
341
- knownTestsCh.runStores(ctx, () => {})
342
- } else if (config.isTestManagementTestsEnabled) {
343
- ctx.onDone = onReceivedTestManagementTests
344
- testManagementTestsCh.runStores(ctx, () => {})
345
- } else if (config.isImpactedTestsEnabled) {
346
- ctx.onDone = onReceivedImpactedTests
347
- modifiedFilesCh.runStores(ctx, () => {})
348
- } else if (config.isSuitesSkippingEnabled) {
349
- ctx.onDone = onReceivedSkippableSuites
350
- skippableSuitesCh.runStores(ctx, () => {})
351
- } else {
352
- mochaGlobalRunCh.runStores(ctx, () => {
353
- onFinishRequest()
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', getOnEndHandler(false))
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
- rootTestsByFile.set(file, suite.tests.filter(t => t.file === file))
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
- // Symmetric to the suite start fix
540
- const fileToTests = new Map()
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
- if (!fileToTests.has(test.file)) fileToTests.set(test.file, [])
544
- fileToTests.get(test.file).push(test)
545
- }
546
- for (const [file, tests] of fileToTests) {
547
- // Mixed case: if a file appears in suitesByTestFile (pre-populated before the run),
548
- // its numSuitesByTestFile counter hits zero when its last describe-based suite ends
549
- // and the normal path below fires testSuiteFinishCh. Since root is last when
550
- // 'suite end' fires, any such file has already been handled — skipping it here
551
- // avoids duplication.
552
- if (suitesByTestFile[file]) continue
553
- let status = 'pass'
554
- if (tests.every(test => test.isPending())) {
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
- if (global.__coverage__) {
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 = getCoveredFilenamesFromCoverage(global.__coverage__)
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
- testSuites,
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
  })