dd-trace 6.8.0 → 6.10.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/ci/diagnose.js +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +9 -3
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +38 -28
- package/ci/test-optimization-validation/generated-test-contract.js +8 -4
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +300 -50
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +40 -20
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +59 -5
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +140 -42
- package/index.d.ts +140 -1
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +8 -5
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/src/utils.js +16 -1
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +81 -5
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
- package/packages/datadog-instrumentations/src/cucumber.js +124 -47
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +629 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +199 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +62 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +37 -6
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +980 -234
- package/packages/datadog-instrumentations/src/mocha/main.js +108 -10
- package/packages/datadog-instrumentations/src/mocha/utils.js +66 -50
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +25 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -18
- package/packages/datadog-instrumentations/src/mysql.js +46 -16
- package/packages/datadog-instrumentations/src/mysql2.js +119 -18
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
- package/packages/datadog-instrumentations/src/pg.js +209 -11
- package/packages/datadog-instrumentations/src/playwright.js +173 -79
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +85 -13
- package/packages/datadog-instrumentations/src/vitest-main.js +528 -72
- package/packages/datadog-instrumentations/src/vitest-util.js +106 -12
- package/packages/datadog-instrumentations/src/vitest-worker.js +382 -40
- package/packages/datadog-instrumentations/src/webdriverio.js +212 -22
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -3
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +51 -47
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +6 -22
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/producer.js +5 -3
- package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
- package/packages/datadog-plugin-mocha/src/index.js +832 -4
- package/packages/datadog-plugin-mysql/src/index.js +37 -0
- package/packages/datadog-plugin-next/src/index.js +51 -21
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
- package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
- package/packages/datadog-plugin-pg/src/index.js +66 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +103 -27
- package/packages/datadog-plugin-ws/src/util.js +2 -1
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +228 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +9 -0
- package/packages/dd-trace/src/carrier.js +356 -0
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +27 -13
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +17 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +21 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +1 -1
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/generated-config-types.d.ts +5 -0
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +16 -5
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +18 -0
- package/packages/dd-trace/src/datastreams/context.js +6 -1
- package/packages/dd-trace/src/datastreams/manager.js +5 -1
- package/packages/dd-trace/src/datastreams/pathway.js +23 -22
- package/packages/dd-trace/src/datastreams/processor.js +3 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/index.js +33 -25
- package/packages/dd-trace/src/llmobs/experiments/util.js +4 -2
- package/packages/dd-trace/src/llmobs/index.js +34 -2
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +149 -68
- package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
- package/packages/dd-trace/src/llmobs/tagger.js +96 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/util.js +78 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +21 -5
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +6 -0
- package/packages/dd-trace/src/plugins/util/git.js +6 -4
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +2 -2
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +3 -62
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/test.js +397 -74
- package/packages/dd-trace/src/plugins/util/url.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +76 -3
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const path = require('node:path')
|
|
3
4
|
const { performance } = require('node:perf_hooks')
|
|
5
|
+
const { fileURLToPath } = require('node:url')
|
|
6
|
+
const { isMainThread, parentPort } = require('node:worker_threads')
|
|
4
7
|
|
|
5
8
|
const shimmer = require('../../datadog-shimmer')
|
|
9
|
+
const log = require('../../dd-trace/src/log')
|
|
10
|
+
const { getEfdRetryCountForDuration } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
|
|
6
11
|
const {
|
|
7
12
|
DYNAMIC_NAME_RE,
|
|
8
|
-
|
|
13
|
+
getTestSuitePath,
|
|
9
14
|
recordAttemptToFixExecution,
|
|
10
15
|
logAttemptToFixTestExecution,
|
|
16
|
+
VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE,
|
|
17
|
+
VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE,
|
|
11
18
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
12
19
|
const { getChannelPromise } = require('./helpers/channel')
|
|
13
20
|
const { addHook } = require('./helpers/instrument')
|
|
@@ -27,16 +34,20 @@ const {
|
|
|
27
34
|
getTypeTasks,
|
|
28
35
|
getTestName,
|
|
29
36
|
getProvidedContext,
|
|
37
|
+
realpath,
|
|
30
38
|
isFlakyTestRetriesEnabledForTask,
|
|
31
39
|
getVitestTestProperties,
|
|
32
40
|
} = require('./vitest-util')
|
|
33
41
|
|
|
42
|
+
const EFD_SUITE_ADMISSION_TIMEOUT_MS = 5000
|
|
34
43
|
const taskToCtx = new WeakMap()
|
|
35
44
|
const taskToTestProperties = new WeakMap()
|
|
36
45
|
const taskToStatuses = new WeakMap()
|
|
37
46
|
const taskToReportedErrorCount = new WeakMap()
|
|
38
47
|
const attemptToFixTaskToStatuses = new WeakMap()
|
|
39
48
|
const fileToHasConcurrentTests = new WeakMap()
|
|
49
|
+
const fileToEfdSuiteAdmission = new WeakMap()
|
|
50
|
+
const pendingEfdSuiteAdmissionRequests = new Map()
|
|
40
51
|
const originalHookFns = new WeakMap()
|
|
41
52
|
const newTasks = new WeakSet()
|
|
42
53
|
const dynamicNameTasks = new WeakSet()
|
|
@@ -52,10 +63,190 @@ const efdExecutionStartByTask = new WeakMap()
|
|
|
52
63
|
const efdSkippedRetryResults = new WeakMap()
|
|
53
64
|
const attemptToFixExecutions = new Map()
|
|
54
65
|
const loggedAttemptToFixTests = new Set()
|
|
55
|
-
const switchedStatuses = new
|
|
66
|
+
const switchedStatuses = new WeakMap()
|
|
56
67
|
let vitestGetFn = null
|
|
57
68
|
let vitestSetFn = null
|
|
58
69
|
let vitestGetHooks = null
|
|
70
|
+
let preciseCoverageSession
|
|
71
|
+
let didInitializeEfdSuiteAdmissionTransport = false
|
|
72
|
+
let nextEfdSuiteAdmissionRequestId = 0
|
|
73
|
+
let sendEfdSuiteAdmissionMessage
|
|
74
|
+
let isPreciseCoverageUnavailable = false
|
|
75
|
+
let vitestCoverageSnapshot
|
|
76
|
+
const wrappedCoverageWorkerStates = new WeakSet()
|
|
77
|
+
const nonIsolatedCoverageFiles = new Set()
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Sends a command to a Node.js inspector session.
|
|
81
|
+
*
|
|
82
|
+
* @param {import('node:inspector').Session} session
|
|
83
|
+
* @param {string} method
|
|
84
|
+
* @param {object} [params]
|
|
85
|
+
* @returns {Promise<object>}
|
|
86
|
+
*/
|
|
87
|
+
function postInspectorCommand (session, method, params) {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
session.post(method, params, (error, result) => {
|
|
90
|
+
if (error) {
|
|
91
|
+
reject(error)
|
|
92
|
+
} else {
|
|
93
|
+
resolve(result || {})
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function startPreciseCoverage () {
|
|
100
|
+
if (preciseCoverageSession) return true
|
|
101
|
+
if (isPreciseCoverageUnavailable) return false
|
|
102
|
+
|
|
103
|
+
let session
|
|
104
|
+
try {
|
|
105
|
+
const inspector = require('node:inspector')
|
|
106
|
+
session = new inspector.Session()
|
|
107
|
+
session.connect()
|
|
108
|
+
await postInspectorCommand(session, 'Profiler.enable')
|
|
109
|
+
await postInspectorCommand(session, 'Profiler.startPreciseCoverage', {
|
|
110
|
+
callCount: false,
|
|
111
|
+
detailed: false,
|
|
112
|
+
})
|
|
113
|
+
preciseCoverageSession = session
|
|
114
|
+
return true
|
|
115
|
+
} catch (error) {
|
|
116
|
+
isPreciseCoverageUnavailable = true
|
|
117
|
+
try {
|
|
118
|
+
session?.disconnect()
|
|
119
|
+
} catch {}
|
|
120
|
+
log.warn('Could not start Vitest TIA code coverage: %s', error?.message)
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getCoverageFilename (url) {
|
|
126
|
+
if (!url) return
|
|
127
|
+
|
|
128
|
+
if (url.startsWith('file://')) {
|
|
129
|
+
try {
|
|
130
|
+
return fileURLToPath(url)
|
|
131
|
+
} catch {
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (path.isAbsolute(url)) return url
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isFileInRepository (filename, repositoryRoot) {
|
|
140
|
+
const relativeFilename = path.relative(repositoryRoot, filename)
|
|
141
|
+
return relativeFilename !== '..' &&
|
|
142
|
+
!relativeFilename.startsWith(`..${path.sep}`) &&
|
|
143
|
+
!path.isAbsolute(relativeFilename) &&
|
|
144
|
+
!relativeFilename.startsWith(`node_modules${path.sep}`) &&
|
|
145
|
+
!relativeFilename.includes(`${path.sep}node_modules${path.sep}`)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function isV8ScriptCovered (scriptCoverage) {
|
|
149
|
+
for (const functionCoverage of scriptCoverage.functions) {
|
|
150
|
+
for (const range of functionCoverage.ranges) {
|
|
151
|
+
if (range.count > 0) return true
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function getCoveredFilesFromV8Result (coverage, repositoryRoot) {
|
|
158
|
+
const coveredFiles = []
|
|
159
|
+
const scriptCoverageResults = coverage?.result
|
|
160
|
+
if (scriptCoverageResults) {
|
|
161
|
+
for (const scriptCoverage of scriptCoverageResults) {
|
|
162
|
+
if (!isV8ScriptCovered(scriptCoverage)) continue
|
|
163
|
+
|
|
164
|
+
const coverageFilename = getCoverageFilename(scriptCoverage.url)
|
|
165
|
+
if (!coverageFilename) continue
|
|
166
|
+
|
|
167
|
+
const filename = realpath(coverageFilename)
|
|
168
|
+
if (isFileInRepository(filename, repositoryRoot)) {
|
|
169
|
+
coveredFiles.push(filename)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return coveredFiles
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getVitestCoverageOptions () {
|
|
177
|
+
return globalThis.__vitest_worker__?.config?.coverage
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check whether the current Vitest worker reuses its module cache across test suites.
|
|
182
|
+
*
|
|
183
|
+
* @returns {boolean}
|
|
184
|
+
*/
|
|
185
|
+
function isNonIsolatedRun () {
|
|
186
|
+
const config = globalThis.__vitest_worker__?.config
|
|
187
|
+
if (config?.isolate === false) return true
|
|
188
|
+
|
|
189
|
+
return config?.poolOptions?.[config.pool]?.isolate === false
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Conservatively include files covered by earlier suites when Vitest reuses its module cache.
|
|
194
|
+
*
|
|
195
|
+
* @param {string[] | undefined} coverageFiles
|
|
196
|
+
* @returns {string[] | undefined}
|
|
197
|
+
*/
|
|
198
|
+
function includePreviouslyCoveredFiles (coverageFiles) {
|
|
199
|
+
if (!coverageFiles || !isNonIsolatedRun()) return coverageFiles
|
|
200
|
+
|
|
201
|
+
// TODO: Track module cache hits per suite instead; cumulative coverage can under-skip with isolate:false.
|
|
202
|
+
for (const filename of coverageFiles) {
|
|
203
|
+
nonIsolatedCoverageFiles.add(filename)
|
|
204
|
+
}
|
|
205
|
+
return [...nonIsolatedCoverageFiles]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function usesVitestV8CoverageSnapshot (coverageOptions) {
|
|
209
|
+
return coverageOptions?.enabled === true &&
|
|
210
|
+
coverageOptions.provider === 'v8'
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function getPreciseCoverageFiles (repositoryRoot) {
|
|
214
|
+
if (!await startPreciseCoverage()) return
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const coverage = await postInspectorCommand(preciseCoverageSession, 'Profiler.takePreciseCoverage')
|
|
218
|
+
return getCoveredFilesFromV8Result(coverage, repositoryRoot)
|
|
219
|
+
} catch (error) {
|
|
220
|
+
isPreciseCoverageUnavailable = true
|
|
221
|
+
try {
|
|
222
|
+
preciseCoverageSession.disconnect()
|
|
223
|
+
} catch {}
|
|
224
|
+
preciseCoverageSession = undefined
|
|
225
|
+
log.warn('Could not collect Vitest TIA code coverage: %s', error?.message)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function getVitestCoverageFiles (repositoryRoot) {
|
|
230
|
+
return getCoveredFilesFromV8Result(vitestCoverageSnapshot, repositoryRoot)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function wrapVitestCoverageRpc () {
|
|
234
|
+
const workerState = globalThis.__vitest_worker__
|
|
235
|
+
if (!workerState?.rpc || wrappedCoverageWorkerStates.has(workerState)) return
|
|
236
|
+
|
|
237
|
+
wrappedCoverageWorkerStates.add(workerState)
|
|
238
|
+
workerState.rpc = new Proxy(workerState.rpc, {
|
|
239
|
+
get (target, property, receiver) {
|
|
240
|
+
const value = Reflect.get(target, property, receiver)
|
|
241
|
+
if (property !== 'onAfterSuiteRun' || typeof value !== 'function') return value
|
|
242
|
+
|
|
243
|
+
return function (metadata) {
|
|
244
|
+
vitestCoverageSnapshot = metadata?.coverage
|
|
245
|
+
return value.apply(this, arguments)
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
})
|
|
249
|
+
}
|
|
59
250
|
|
|
60
251
|
function waitForHitProbe () {
|
|
61
252
|
const promises = {}
|
|
@@ -166,6 +357,123 @@ function hasConcurrentTests (file) {
|
|
|
166
357
|
return hasConcurrent
|
|
167
358
|
}
|
|
168
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Returns whether a collected Vitest file contains a runnable new test eligible for EFD.
|
|
362
|
+
*
|
|
363
|
+
* @param {{ filepath: string, tasks?: object[] }} file
|
|
364
|
+
* @param {object} providedContext
|
|
365
|
+
* @returns {boolean}
|
|
366
|
+
*/
|
|
367
|
+
function hasRunnableNewTest (file, providedContext) {
|
|
368
|
+
for (const task of getTypeTasks(file.tasks)) {
|
|
369
|
+
if (task.mode === 'skip' || task.mode === 'todo') continue
|
|
370
|
+
|
|
371
|
+
const testProperties = getVitestTestProperties(providedContext, file.filepath, getTestName(task))
|
|
372
|
+
if (testProperties.isNew && !testProperties.isAttemptToFix && !testProperties.isDisabled) {
|
|
373
|
+
return true
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return false
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Resolves and removes one pending EFD suite admission request.
|
|
381
|
+
*
|
|
382
|
+
* @param {number} requestId
|
|
383
|
+
* @param {boolean} allowed
|
|
384
|
+
* @returns {void}
|
|
385
|
+
*/
|
|
386
|
+
function finishEfdSuiteAdmissionRequest (requestId, allowed) {
|
|
387
|
+
const request = pendingEfdSuiteAdmissionRequests.get(requestId)
|
|
388
|
+
if (!request) return
|
|
389
|
+
|
|
390
|
+
clearTimeout(request.timeout)
|
|
391
|
+
pendingEfdSuiteAdmissionRequests.delete(requestId)
|
|
392
|
+
request.resolve(allowed)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Handles an EFD suite admission response from the Vitest main process.
|
|
397
|
+
*
|
|
398
|
+
* @param {unknown} message
|
|
399
|
+
* @returns {void}
|
|
400
|
+
*/
|
|
401
|
+
function handleEfdSuiteAdmissionResponse (message) {
|
|
402
|
+
if (!Array.isArray(message) || message[0] !== VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE) return
|
|
403
|
+
|
|
404
|
+
const { allowed, requestId } = message[1] || {}
|
|
405
|
+
if (Number.isSafeInteger(requestId)) {
|
|
406
|
+
finishEfdSuiteAdmissionRequest(requestId, allowed === true)
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Returns the child-process or worker-thread sender used by the current Vitest worker.
|
|
412
|
+
*
|
|
413
|
+
* @returns {((message: unknown) => void)|undefined}
|
|
414
|
+
*/
|
|
415
|
+
function getEfdSuiteAdmissionSender () {
|
|
416
|
+
if (didInitializeEfdSuiteAdmissionTransport) return sendEfdSuiteAdmissionMessage
|
|
417
|
+
didInitializeEfdSuiteAdmissionTransport = true
|
|
418
|
+
|
|
419
|
+
if (typeof process.send === 'function') {
|
|
420
|
+
process.on('message', handleEfdSuiteAdmissionResponse)
|
|
421
|
+
sendEfdSuiteAdmissionMessage = process.send.bind(process)
|
|
422
|
+
} else if (!isMainThread && parentPort) {
|
|
423
|
+
parentPort.on('message', handleEfdSuiteAdmissionResponse)
|
|
424
|
+
sendEfdSuiteAdmissionMessage = parentPort.postMessage.bind(parentPort)
|
|
425
|
+
}
|
|
426
|
+
return sendEfdSuiteAdmissionMessage
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Requests permission from the Vitest main process to schedule EFD retries for one suite.
|
|
431
|
+
*
|
|
432
|
+
* @param {string} testSuite
|
|
433
|
+
* @param {boolean} hasNewTest
|
|
434
|
+
* @returns {Promise<boolean>}
|
|
435
|
+
*/
|
|
436
|
+
function requestEfdSuiteAdmission (testSuite, hasNewTest) {
|
|
437
|
+
const sendMessage = getEfdSuiteAdmissionSender()
|
|
438
|
+
if (!sendMessage) return Promise.resolve(false)
|
|
439
|
+
|
|
440
|
+
const requestId = ++nextEfdSuiteAdmissionRequestId
|
|
441
|
+
return new Promise(resolve => {
|
|
442
|
+
const timeout = setTimeout(
|
|
443
|
+
() => finishEfdSuiteAdmissionRequest(requestId, false),
|
|
444
|
+
EFD_SUITE_ADMISSION_TIMEOUT_MS
|
|
445
|
+
)
|
|
446
|
+
timeout.unref?.()
|
|
447
|
+
pendingEfdSuiteAdmissionRequests.set(requestId, { resolve, timeout })
|
|
448
|
+
|
|
449
|
+
try {
|
|
450
|
+
sendMessage([VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE, { hasNewTest, requestId, testSuite }])
|
|
451
|
+
} catch {
|
|
452
|
+
finishEfdSuiteAdmissionRequest(requestId, false)
|
|
453
|
+
}
|
|
454
|
+
})
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Requests a single EFD admission decision for all tests collected in a Vitest file.
|
|
459
|
+
*
|
|
460
|
+
* @param {{ file: { filepath: string, tasks?: object[] } }} task
|
|
461
|
+
* @param {object} providedContext
|
|
462
|
+
* @param {string|undefined} testSuite
|
|
463
|
+
* @returns {Promise<boolean>}
|
|
464
|
+
*/
|
|
465
|
+
function isEfdSuiteAdmissionAllowed (task, providedContext, testSuite) {
|
|
466
|
+
let admission = fileToEfdSuiteAdmission.get(task.file)
|
|
467
|
+
if (admission) return admission
|
|
468
|
+
|
|
469
|
+
admission = requestEfdSuiteAdmission(
|
|
470
|
+
testSuite || task.file.filepath,
|
|
471
|
+
hasRunnableNewTest(task.file, providedContext)
|
|
472
|
+
)
|
|
473
|
+
fileToEfdSuiteAdmission.set(task.file, admission)
|
|
474
|
+
return admission
|
|
475
|
+
}
|
|
476
|
+
|
|
169
477
|
/**
|
|
170
478
|
* Gets the task associated with a Vitest hook invocation.
|
|
171
479
|
*
|
|
@@ -201,14 +509,14 @@ function wrapSuiteHookFn (hookType, fn, fallbackTask) {
|
|
|
201
509
|
function wrapVitestTestRunner (VitestTestRunner) {
|
|
202
510
|
// `onBeforeRunTask` is run before any repetition or attempt is run
|
|
203
511
|
// `onBeforeRunTask` is an async function
|
|
204
|
-
shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => function (task) {
|
|
512
|
+
shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => async function (task) {
|
|
205
513
|
const testName = getTestName(task)
|
|
206
514
|
|
|
207
515
|
const providedContext = getProvidedContext()
|
|
208
516
|
const {
|
|
209
517
|
isEarlyFlakeDetectionEnabled,
|
|
210
518
|
isKnownTestsEnabled,
|
|
211
|
-
|
|
519
|
+
earlyFlakeDetectionRetryPolicy,
|
|
212
520
|
isTestManagementTestsEnabled,
|
|
213
521
|
testManagementAttemptToFixRetries,
|
|
214
522
|
isImpactedTestsEnabled,
|
|
@@ -244,35 +552,38 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
244
552
|
}
|
|
245
553
|
|
|
246
554
|
if (isImpactedTestsEnabled && testProperties.isModified) {
|
|
247
|
-
if (isEarlyFlakeDetectionEnabled) {
|
|
248
|
-
efdRetryTasks.add(task)
|
|
249
|
-
disableFrameworkRetries(task)
|
|
250
|
-
task.repeats = numRepeats
|
|
251
|
-
}
|
|
252
555
|
modifiedTasks.add(task)
|
|
253
|
-
taskToStatuses.set(task, [])
|
|
254
556
|
}
|
|
255
557
|
|
|
256
558
|
if (isKnownTestsEnabled && testProperties.isNew && !attemptToFixTasks.has(task)) {
|
|
257
|
-
if (isEarlyFlakeDetectionEnabled && !modifiedTasks.has(task)) {
|
|
258
|
-
efdRetryTasks.add(task)
|
|
259
|
-
disableFrameworkRetries(task)
|
|
260
|
-
task.repeats = numRepeats
|
|
261
|
-
}
|
|
262
559
|
newTasks.add(task)
|
|
263
|
-
taskToStatuses.set(task, [])
|
|
264
560
|
if (DYNAMIC_NAME_RE.test(testName)) {
|
|
265
561
|
dynamicNameTasks.add(task)
|
|
266
562
|
}
|
|
267
563
|
}
|
|
268
564
|
|
|
565
|
+
const isEfdCandidate = isEarlyFlakeDetectionEnabled &&
|
|
566
|
+
!attemptToFixTasks.has(task) &&
|
|
567
|
+
!disabledTasks.has(task) &&
|
|
568
|
+
(modifiedTasks.has(task) || newTasks.has(task))
|
|
569
|
+
if (isEfdCandidate) {
|
|
570
|
+
const isAdmissionAllowed = !providedContext.isEfdSuiteAdmissionEnabled ||
|
|
571
|
+
await isEfdSuiteAdmissionAllowed(task, providedContext, testProperties.testSuite)
|
|
572
|
+
if (isAdmissionAllowed) {
|
|
573
|
+
efdRetryTasks.add(task)
|
|
574
|
+
disableFrameworkRetries(task)
|
|
575
|
+
task.repeats = earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
576
|
+
taskToStatuses.set(task, [])
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
269
580
|
return onBeforeRunTask.apply(this, arguments)
|
|
270
581
|
})
|
|
271
582
|
|
|
272
583
|
// `onAfterRunTask` is run after all repetitions or attempts are run
|
|
273
584
|
// `onAfterRunTask` is an async function
|
|
274
585
|
shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => function (task) {
|
|
275
|
-
const {
|
|
586
|
+
const { isTestManagementTestsEnabled } = getProvidedContext()
|
|
276
587
|
|
|
277
588
|
if (isTestManagementTestsEnabled) {
|
|
278
589
|
const isAttemptingToFix = attemptToFixTasks.has(task)
|
|
@@ -281,25 +592,25 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
281
592
|
if (isAttemptingToFix) {
|
|
282
593
|
const statuses = attemptToFixTaskToStatuses.get(task)
|
|
283
594
|
if (task.result.state === 'pass' && statuses?.includes('fail')) {
|
|
284
|
-
switchedStatuses.
|
|
595
|
+
switchedStatuses.set(task, task.result.state)
|
|
285
596
|
task.result.state = 'fail'
|
|
286
597
|
}
|
|
287
598
|
}
|
|
288
599
|
|
|
289
600
|
if (!isAttemptingToFix && isQuarantined) {
|
|
290
601
|
if (task.result.state === 'fail') {
|
|
291
|
-
switchedStatuses.
|
|
602
|
+
switchedStatuses.set(task, task.result.state)
|
|
292
603
|
}
|
|
293
604
|
task.result.state = 'pass'
|
|
294
605
|
}
|
|
295
606
|
}
|
|
296
607
|
|
|
297
|
-
if (
|
|
608
|
+
if (efdRetryTasks.has(task)) {
|
|
298
609
|
const statuses = taskToStatuses.get(task)
|
|
299
610
|
// If the test has passed at least once, we consider it passed
|
|
300
611
|
if (statuses.includes('pass')) {
|
|
301
612
|
if (task.result.state === 'fail') {
|
|
302
|
-
switchedStatuses.
|
|
613
|
+
switchedStatuses.set(task, task.result.state)
|
|
303
614
|
}
|
|
304
615
|
task.result.state = 'pass'
|
|
305
616
|
}
|
|
@@ -319,9 +630,8 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
319
630
|
const providedContext = getProvidedContext()
|
|
320
631
|
const {
|
|
321
632
|
isKnownTestsEnabled,
|
|
322
|
-
isEarlyFlakeDetectionEnabled,
|
|
323
633
|
isDiEnabled,
|
|
324
|
-
|
|
634
|
+
earlyFlakeDetectionRetryPolicy,
|
|
325
635
|
} = providedContext
|
|
326
636
|
|
|
327
637
|
if (isKnownTestsEnabled) {
|
|
@@ -330,14 +640,14 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
330
640
|
|
|
331
641
|
const { retry: numAttempt, repeats: numRepetition } = retryInfo
|
|
332
642
|
const isFailedTestReplayAllowed = !hasConcurrentTests(task.file)
|
|
333
|
-
const isEfdManagedTask =
|
|
643
|
+
const isEfdManagedTask = efdRetryTasks.has(task)
|
|
334
644
|
|
|
335
645
|
if (isEfdManagedTask && numRepetition > 0 && !efdDeterminedRetries.has(task)) {
|
|
336
646
|
const previousExecutionStart = efdExecutionStartByTask.get(task)
|
|
337
647
|
const duration = previousExecutionStart === undefined
|
|
338
648
|
? task.result?.duration ?? 0
|
|
339
649
|
: performance.now() - previousExecutionStart
|
|
340
|
-
const retryCount =
|
|
650
|
+
const retryCount = getEfdRetryCountForDuration(duration, earlyFlakeDetectionRetryPolicy)
|
|
341
651
|
efdDeterminedRetries.set(task, retryCount)
|
|
342
652
|
task.repeats = retryCount
|
|
343
653
|
if (retryCount === 0) {
|
|
@@ -392,8 +702,9 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
392
702
|
|
|
393
703
|
const lastExecutionStatus = task.result.state
|
|
394
704
|
const isAtf = attemptToFixTasks.has(task)
|
|
395
|
-
const
|
|
396
|
-
const
|
|
705
|
+
const isEfd = efdRetryTasks.has(task)
|
|
706
|
+
const shouldTrackStatuses = isEfd || isAtf
|
|
707
|
+
const shouldFlipStatus = isEfd || isAtf
|
|
397
708
|
const statuses = isAtf ? attemptToFixTaskToStatuses.get(task) : taskToStatuses.get(task)
|
|
398
709
|
|
|
399
710
|
// These clauses handle task.repeats, whether EFD is enabled or not
|
|
@@ -515,9 +826,8 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
515
826
|
const result = await onAfterTryTask.apply(this, arguments)
|
|
516
827
|
|
|
517
828
|
const {
|
|
518
|
-
isEarlyFlakeDetectionEnabled,
|
|
519
829
|
testManagementAttemptToFixRetries,
|
|
520
|
-
|
|
830
|
+
earlyFlakeDetectionRetryPolicy,
|
|
521
831
|
} = getProvidedContext()
|
|
522
832
|
|
|
523
833
|
const status = getVitestTestStatus(task, retryInfo.retry)
|
|
@@ -537,15 +847,13 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
537
847
|
}
|
|
538
848
|
|
|
539
849
|
if (
|
|
540
|
-
|
|
850
|
+
efdRetryTasks.has(task) &&
|
|
541
851
|
(retryInfo.repeats ?? 0) === 0 &&
|
|
542
|
-
taskToStatuses.has(task) &&
|
|
543
|
-
!attemptToFixTasks.has(task) &&
|
|
544
852
|
!efdDeterminedRetries.has(task)
|
|
545
853
|
) {
|
|
546
854
|
const executionStart = efdExecutionStartByTask.get(task)
|
|
547
855
|
const duration = executionStart === undefined ? task.result?.duration ?? 0 : performance.now() - executionStart
|
|
548
|
-
const retryCount =
|
|
856
|
+
const retryCount = getEfdRetryCountForDuration(duration, earlyFlakeDetectionRetryPolicy)
|
|
549
857
|
efdDeterminedRetries.set(task, retryCount)
|
|
550
858
|
task.repeats = retryCount
|
|
551
859
|
if (retryCount === 0) {
|
|
@@ -649,6 +957,19 @@ addHook({
|
|
|
649
957
|
// From >=3.0.1, the first arguments changes from a string to an object containing the filepath
|
|
650
958
|
const testSuiteAbsolutePath = testPaths[0]?.filepath || testPaths[0]
|
|
651
959
|
const providedContext = getProvidedContext()
|
|
960
|
+
const repositoryRoot = providedContext.repositoryRoot || process.cwd()
|
|
961
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, repositoryRoot)
|
|
962
|
+
const coverageOptions = getVitestCoverageOptions()
|
|
963
|
+
const shouldUseVitestCoverage = usesVitestV8CoverageSnapshot(coverageOptions)
|
|
964
|
+
const coverageLibrary = 'v8'
|
|
965
|
+
vitestCoverageSnapshot = undefined
|
|
966
|
+
if (providedContext.isCodeCoverageEnabled) {
|
|
967
|
+
if (shouldUseVitestCoverage) {
|
|
968
|
+
wrapVitestCoverageRpc()
|
|
969
|
+
} else {
|
|
970
|
+
await startPreciseCoverage()
|
|
971
|
+
}
|
|
972
|
+
}
|
|
652
973
|
|
|
653
974
|
const testSuiteCtx = {
|
|
654
975
|
testSuiteAbsolutePath,
|
|
@@ -656,8 +977,13 @@ addHook({
|
|
|
656
977
|
testSessionId: providedContext.testSessionId,
|
|
657
978
|
testModuleId: providedContext.testModuleId,
|
|
658
979
|
testCommand: providedContext.testCommand,
|
|
659
|
-
repositoryRoot
|
|
980
|
+
repositoryRoot,
|
|
660
981
|
codeOwnersEntries: providedContext.codeOwnersEntries,
|
|
982
|
+
isCodeCoverageEnabled: providedContext.isCodeCoverageEnabled,
|
|
983
|
+
coverageLibrary,
|
|
984
|
+
itrCorrelationId: providedContext.itrCorrelationId,
|
|
985
|
+
isUnskippable: providedContext.unskippableSuites?.[testSuite] === true,
|
|
986
|
+
isForcedToRun: providedContext.forcedToRunSuites?.[testSuite] === true,
|
|
661
987
|
}
|
|
662
988
|
testSuiteStartCh.runStores(testSuiteCtx, () => {})
|
|
663
989
|
const startTestsResponse = await startTests.apply(this, arguments)
|
|
@@ -671,14 +997,15 @@ addHook({
|
|
|
671
997
|
const { result } = task
|
|
672
998
|
// We have to trick vitest into thinking that the test has passed
|
|
673
999
|
// but we want to report it as failed if it did fail
|
|
674
|
-
const
|
|
1000
|
+
const switchedStatus = switchedStatuses.get(task)
|
|
1001
|
+
const isSwitchedStatus = switchedStatus !== undefined
|
|
675
1002
|
|
|
676
1003
|
if (result) {
|
|
677
1004
|
const { state, duration, errors } = result
|
|
678
1005
|
const testError = getCurrentAttemptTestError(task, errors)
|
|
679
1006
|
if (attemptToFixTasks.has(task)) {
|
|
680
|
-
const
|
|
681
|
-
recordFinalAttemptToFixExecution(task,
|
|
1007
|
+
const attemptToFixStatus = getFinalAttemptToFixStatus(task, state, isSwitchedStatus, testCtx)
|
|
1008
|
+
recordFinalAttemptToFixExecution(task, attemptToFixStatus, providedContext)
|
|
682
1009
|
}
|
|
683
1010
|
|
|
684
1011
|
if (state === 'skip') { // programmatic skip
|
|
@@ -686,7 +1013,9 @@ addHook({
|
|
|
686
1013
|
testName: getTestName(task),
|
|
687
1014
|
testSuiteAbsolutePath: task.file.filepath,
|
|
688
1015
|
isNew: newTasks.has(task),
|
|
1016
|
+
isAttemptToFix: attemptToFixTasks.has(task),
|
|
689
1017
|
isDisabled: disabledTasks.has(task),
|
|
1018
|
+
isQuarantined: quarantinedTasks.has(task),
|
|
690
1019
|
})
|
|
691
1020
|
} else if (state === 'pass' && !isSwitchedStatus) {
|
|
692
1021
|
if (testCtx) {
|
|
@@ -718,11 +1047,11 @@ addHook({
|
|
|
718
1047
|
}
|
|
719
1048
|
|
|
720
1049
|
// Check if all EFD retries failed
|
|
721
|
-
const isEfdRetry =
|
|
722
|
-
providedContext.isEarlyFlakeDetectionEnabled && (newTasks.has(task) || modifiedTasks.has(task))
|
|
1050
|
+
const isEfdRetry = efdRetryTasks.has(task)
|
|
723
1051
|
if (isEfdRetry) {
|
|
724
1052
|
const statuses = taskToStatuses.get(task)
|
|
725
|
-
const efdRetryCount = efdDeterminedRetries.get(task) ??
|
|
1053
|
+
const efdRetryCount = efdDeterminedRetries.get(task) ??
|
|
1054
|
+
providedContext.earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
726
1055
|
// statuses only includes repetitions (not the initial run), so we check against retry count (not +1)
|
|
727
1056
|
if (efdRetryCount > 0 && statuses && statuses.length === efdRetryCount &&
|
|
728
1057
|
statuses.every(status => status === 'fail')) {
|
|
@@ -783,7 +1112,9 @@ addHook({
|
|
|
783
1112
|
testName: getTestName(task),
|
|
784
1113
|
testSuiteAbsolutePath: task.file.filepath,
|
|
785
1114
|
isNew: newTasks.has(task),
|
|
1115
|
+
isAttemptToFix: attemptToFixTasks.has(task),
|
|
786
1116
|
isDisabled: disabledTasks.has(task),
|
|
1117
|
+
isQuarantined: quarantinedTasks.has(task),
|
|
787
1118
|
})
|
|
788
1119
|
}
|
|
789
1120
|
}
|
|
@@ -807,8 +1138,19 @@ addHook({
|
|
|
807
1138
|
testSuiteErrorCh.runStores(testSuiteCtx, () => {})
|
|
808
1139
|
}
|
|
809
1140
|
|
|
1141
|
+
let coverageFiles
|
|
1142
|
+
if (providedContext.isCodeCoverageEnabled) {
|
|
1143
|
+
const currentCoverageFiles = shouldUseVitestCoverage
|
|
1144
|
+
? getVitestCoverageFiles(repositoryRoot)
|
|
1145
|
+
: await getPreciseCoverageFiles(repositoryRoot)
|
|
1146
|
+
coverageFiles = includePreviouslyCoveredFiles(currentCoverageFiles)
|
|
1147
|
+
}
|
|
1148
|
+
|
|
810
1149
|
await getChannelPromise(testSuiteFinishCh, {
|
|
811
1150
|
status: testSuiteResult.state,
|
|
1151
|
+
coverageFiles,
|
|
1152
|
+
coverageLibrary,
|
|
1153
|
+
testSuiteAbsolutePath,
|
|
812
1154
|
...testSuiteCtx.currentStore,
|
|
813
1155
|
})
|
|
814
1156
|
|