dd-trace 5.110.0 → 5.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +1 -2
- package/README.md +13 -8
- package/ci/init.js +21 -2
- package/ci/vitest-no-worker-init-setup.mjs +430 -0
- package/ext/tags.js +2 -0
- package/index.d.ts +34 -1
- package/initialize.mjs +5 -6
- package/loader-hook.mjs +76 -55
- package/package.json +37 -34
- package/packages/datadog-instrumentations/src/ai.js +45 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +5 -13
- package/packages/datadog-instrumentations/src/child_process.js +3 -3
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +587 -0
- package/packages/datadog-instrumentations/src/cucumber.js +102 -43
- package/packages/datadog-instrumentations/src/cypress-config.js +11 -3
- package/packages/datadog-instrumentations/src/fastify.js +27 -8
- package/packages/datadog-instrumentations/src/fs.js +8 -6
- package/packages/datadog-instrumentations/src/graphql.js +26 -495
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +7 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +6 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/claude-agent-sdk.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +201 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/jest.js +713 -63
- package/packages/datadog-instrumentations/src/mocha/main.js +24 -3
- package/packages/datadog-instrumentations/src/mocha/utils.js +128 -22
- package/packages/datadog-instrumentations/src/mocha/worker.js +13 -0
- package/packages/datadog-instrumentations/src/mongodb.js +74 -0
- package/packages/datadog-instrumentations/src/mongoose.js +13 -2
- package/packages/datadog-instrumentations/src/playwright.js +13 -9
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1297 -0
- package/packages/datadog-instrumentations/src/vitest-main.js +1594 -0
- package/packages/datadog-instrumentations/src/vitest-util.js +254 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +823 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -1855
- package/packages/datadog-plugin-ai/src/index.js +1 -1
- package/packages/datadog-plugin-ai/src/tracing.js +66 -3
- package/packages/datadog-plugin-ai/src/utils.js +17 -4
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +19 -10
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
- package/packages/datadog-plugin-child_process/src/index.js +13 -2
- package/packages/datadog-plugin-claude-agent-sdk/src/index.js +31 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/tracing.js +107 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/util.js +15 -0
- package/packages/datadog-plugin-cucumber/src/index.js +15 -24
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +360 -14
- package/packages/datadog-plugin-cypress/src/index.js +47 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +1 -0
- package/packages/datadog-plugin-cypress/src/support.js +45 -1
- package/packages/datadog-plugin-express/src/code_origin.js +1 -1
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +639 -12
- package/packages/datadog-plugin-graphql/src/index.js +37 -9
- package/packages/datadog-plugin-graphql/src/parse.js +24 -4
- package/packages/datadog-plugin-graphql/src/utils.js +9 -2
- package/packages/datadog-plugin-graphql/src/validate.js +17 -6
- package/packages/datadog-plugin-http/src/index.js +6 -8
- package/packages/datadog-plugin-jest/src/index.js +31 -15
- package/packages/datadog-plugin-mocha/src/index.js +40 -15
- package/packages/datadog-plugin-mongodb-core/src/bulk-write.js +43 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +8 -443
- package/packages/datadog-plugin-mongodb-core/src/query.js +452 -0
- package/packages/datadog-plugin-openai/src/services.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +4 -3
- package/packages/datadog-plugin-vitest/src/index.js +120 -72
- package/packages/datadog-shimmer/src/shimmer.js +37 -16
- package/packages/dd-trace/src/aiguard/index.js +9 -14
- package/packages/dd-trace/src/aiguard/integrations/index.js +34 -0
- package/packages/dd-trace/src/aiguard/integrations/openai.js +47 -33
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +42 -28
- package/packages/dd-trace/src/aiguard/sdk.js +2 -2
- package/packages/dd-trace/src/appsec/api_security/sampler.js +3 -3
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
- package/packages/dd-trace/src/appsec/graphql.js +14 -11
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +23 -23
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
- package/packages/dd-trace/src/appsec/index.js +10 -1
- package/packages/dd-trace/src/appsec/lambda.js +135 -0
- package/packages/dd-trace/src/appsec/reporter.js +49 -10
- package/packages/dd-trace/src/appsec/telemetry/index.js +1 -1
- package/packages/dd-trace/src/appsec/waf/index.js +16 -4
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +26 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +115 -24
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +21 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +5 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +6 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +130 -20
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +156 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
- package/packages/dd-trace/src/config/defaults.js +3 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +71 -57
- package/packages/dd-trace/src/config/helper.js +1 -0
- package/packages/dd-trace/src/config/index.js +35 -22
- package/packages/dd-trace/src/config/major-overrides.js +4 -2
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +127 -56
- package/packages/dd-trace/src/constants.js +7 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -2
- package/packages/dd-trace/src/datastreams/processor.js +11 -3
- package/packages/dd-trace/src/exporters/agent/index.js +1 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
- package/packages/dd-trace/src/llmobs/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +403 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +8 -395
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +27 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +363 -0
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +270 -0
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +10 -0
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +3 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +3 -3
- package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +38 -39
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +4 -0
- package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
- package/packages/dd-trace/src/opentracing/tracer.js +6 -1
- package/packages/dd-trace/src/plugin_manager.js +23 -7
- package/packages/dd-trace/src/plugins/ci_plugin.js +159 -10
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/llm.js +6 -1
- package/packages/dd-trace/src/plugins/util/test.js +15 -9
- package/packages/dd-trace/src/profiling/exporter_cli.js +2 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +28 -3
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/proxy.js +8 -8
- package/packages/dd-trace/src/span_processor.js +5 -6
- package/packages/dd-trace/src/span_stats.js +96 -78
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
- package/packages/dd-trace/src/telemetry/index.js +2 -2
- package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/telemetry/send-data.js +8 -8
- package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
- 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/vendor/dist/shell-quote/index.js +1 -1
- package/packages/datadog-plugin-graphql/src/resolve.js +0 -170
|
@@ -0,0 +1,1594 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const path = require('node:path')
|
|
4
|
+
const { fileURLToPath } = require('node:url')
|
|
5
|
+
const { MessagePort } = require('node:worker_threads')
|
|
6
|
+
|
|
7
|
+
const shimmer = require('../../datadog-shimmer')
|
|
8
|
+
const log = require('../../dd-trace/src/log')
|
|
9
|
+
const {
|
|
10
|
+
VITEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
11
|
+
VITEST_WORKER_LOGS_PAYLOAD_CODE,
|
|
12
|
+
getMaxEfdRetryCount,
|
|
13
|
+
collectTestOptimizationSummariesFromTraces,
|
|
14
|
+
logTestOptimizationSummary,
|
|
15
|
+
getTestOptimizationRequestResults,
|
|
16
|
+
getTestSuitePath,
|
|
17
|
+
isModifiedTest,
|
|
18
|
+
} = require('../../dd-trace/src/plugins/util/test')
|
|
19
|
+
const { addHook } = require('./helpers/instrument')
|
|
20
|
+
const noWorkerInit = require('./vitest-main-no-worker-init')
|
|
21
|
+
const {
|
|
22
|
+
testStartCh,
|
|
23
|
+
testPassCh,
|
|
24
|
+
testErrorCh,
|
|
25
|
+
testSkipCh,
|
|
26
|
+
testSuiteStartCh,
|
|
27
|
+
testSuiteFinishCh,
|
|
28
|
+
testSuiteErrorCh,
|
|
29
|
+
testSessionStartCh,
|
|
30
|
+
testSessionFinishCh,
|
|
31
|
+
testSessionConfigurationCh,
|
|
32
|
+
libraryConfigurationCh,
|
|
33
|
+
knownTestsCh,
|
|
34
|
+
isEarlyFlakeDetectionFaultyCh,
|
|
35
|
+
testManagementTestsCh,
|
|
36
|
+
modifiedFilesCh,
|
|
37
|
+
workerReportTraceCh,
|
|
38
|
+
workerReportLogsCh,
|
|
39
|
+
codeCoverageReportCh,
|
|
40
|
+
findExportByName,
|
|
41
|
+
getChannelPromise,
|
|
42
|
+
getTypeTasks,
|
|
43
|
+
getWorkspaceProject,
|
|
44
|
+
setProvidedContext,
|
|
45
|
+
getVitestTestProperties,
|
|
46
|
+
} = require('./vitest-util')
|
|
47
|
+
|
|
48
|
+
const newTestsWithDynamicNames = new Set()
|
|
49
|
+
const attemptToFixExecutions = new Map()
|
|
50
|
+
const workerProcesses = new WeakSet()
|
|
51
|
+
const mainProcessSetupStates = new WeakMap()
|
|
52
|
+
const coverageWrappedProviders = new WeakSet()
|
|
53
|
+
const finishWrappedContexts = new WeakSet()
|
|
54
|
+
let isFlakyTestRetriesEnabled = false
|
|
55
|
+
let flakyTestRetriesCount = 0
|
|
56
|
+
let isEarlyFlakeDetectionEnabled = false
|
|
57
|
+
let earlyFlakeDetectionNumRetries = 0
|
|
58
|
+
let earlyFlakeDetectionSlowTestRetries = {}
|
|
59
|
+
let isEarlyFlakeDetectionFaulty = false
|
|
60
|
+
let isKnownTestsEnabled = false
|
|
61
|
+
let isTestManagementTestsEnabled = false
|
|
62
|
+
let isImpactedTestsEnabled = false
|
|
63
|
+
let testManagementAttemptToFixRetries = 0
|
|
64
|
+
let isDiEnabled = false
|
|
65
|
+
let testCodeCoverageLinesTotal
|
|
66
|
+
let coverageRootDir
|
|
67
|
+
let requestErrorTags = {}
|
|
68
|
+
let isSessionStarted = false
|
|
69
|
+
let isVitestNoWorkerInitActive = false
|
|
70
|
+
let vitestPool = null
|
|
71
|
+
let isMessagePortWrapped = false
|
|
72
|
+
const tinyPoolClassWrappers = new WeakMap()
|
|
73
|
+
|
|
74
|
+
function getConfiguredEfdRetryCount (slowTestRetries, fallbackRetryCount) {
|
|
75
|
+
if (!slowTestRetries || !Object.keys(slowTestRetries).length) {
|
|
76
|
+
return fallbackRetryCount
|
|
77
|
+
}
|
|
78
|
+
return getMaxEfdRetryCount(slowTestRetries)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getTestCommand () {
|
|
82
|
+
return `vitest ${process.argv.slice(2).join(' ')}`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isValidKnownTests (receivedKnownTests) {
|
|
86
|
+
return !!receivedKnownTests.vitest
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isReporterPackage (vitestPackage) {
|
|
90
|
+
return vitestPackage.B?.name === 'BaseSequencer'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isReporterPackageNew (vitestPackage) {
|
|
94
|
+
return vitestPackage.e?.name === 'BaseSequencer'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isReporterPackageNewest (vitestPackage) {
|
|
98
|
+
return vitestPackage.h?.name === 'BaseSequencer'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getBaseSequencerExport (vitestPackage) {
|
|
102
|
+
return findExportByName(vitestPackage, 'BaseSequencer')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isCliApiPackage (vitestPackage) {
|
|
106
|
+
return !!findExportByName(vitestPackage, 'startVitest')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getVitestExport (vitestPackage) {
|
|
110
|
+
return findExportByName(vitestPackage, 'Vitest')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function getTypecheckerExport (vitestPackage) {
|
|
114
|
+
return findExportByName(vitestPackage, 'Typechecker')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getForksPoolWorkerExport (vitestPackage) {
|
|
118
|
+
return findExportByName(vitestPackage, 'ForksPoolWorker')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getThreadsPoolWorkerExport (vitestPackage) {
|
|
122
|
+
return findExportByName(vitestPackage, 'ThreadsPoolWorker')
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getSessionStatus (state) {
|
|
126
|
+
if (state.getCountOfFailedTests() > 0) {
|
|
127
|
+
return 'fail'
|
|
128
|
+
}
|
|
129
|
+
if (state.pathsSet.size === 0) {
|
|
130
|
+
return 'skip'
|
|
131
|
+
}
|
|
132
|
+
return 'pass'
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getTestFilepathsFromSpecifications (testSpecifications) {
|
|
136
|
+
if (!Array.isArray(testSpecifications) || !testSpecifications.length) {
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return testSpecifications.map(testSpecification => {
|
|
141
|
+
const testFile = Array.isArray(testSpecification) ? testSpecification[1] : testSpecification
|
|
142
|
+
return testFile?.moduleId || testFile?.filepath || testFile
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function getTestSpecificationsKey (testSpecifications) {
|
|
147
|
+
if (!Array.isArray(testSpecifications) || !testSpecifications.length) return
|
|
148
|
+
|
|
149
|
+
const keyParts = []
|
|
150
|
+
for (const testSpecification of testSpecifications) {
|
|
151
|
+
const testFile = Array.isArray(testSpecification) ? testSpecification[1] : testSpecification
|
|
152
|
+
const testFilepath = testFile?.moduleId || testFile?.filepath || testFile
|
|
153
|
+
if (!testFilepath) continue
|
|
154
|
+
|
|
155
|
+
const projectName = getProjectName(getTestSpecificationProject(testSpecification)) || ''
|
|
156
|
+
const pool = getTestSpecificationPool(testSpecification) || ''
|
|
157
|
+
keyParts.push(`${projectName}\0${pool}\0${testFilepath}`)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!keyParts.length) return
|
|
161
|
+
|
|
162
|
+
keyParts.sort()
|
|
163
|
+
return keyParts.join('\0')
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function getTestFilepaths (ctx, testSpecifications) {
|
|
167
|
+
const testFilepaths = getTestFilepathsFromSpecifications(testSpecifications)
|
|
168
|
+
if (testFilepaths) {
|
|
169
|
+
return testFilepaths
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const getFilePaths = ctx.getTestFilepaths || ctx._globTestFilepaths
|
|
173
|
+
return getFilePaths.call(ctx)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @typedef {{
|
|
178
|
+
* isAttemptToFix?: boolean,
|
|
179
|
+
* isDisabled?: boolean,
|
|
180
|
+
* isQuarantined?: boolean
|
|
181
|
+
* }} VitestTestManagementProperties
|
|
182
|
+
*
|
|
183
|
+
* @typedef {{
|
|
184
|
+
* testSuite?: string,
|
|
185
|
+
* knownTests?: string[],
|
|
186
|
+
* testManagementTests?: Record<string, VitestTestManagementProperties>,
|
|
187
|
+
* isModified?: boolean
|
|
188
|
+
* }} VitestTestProperties
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Normalize a Vitest test file path to the test suite path used by Test Optimization APIs.
|
|
193
|
+
*
|
|
194
|
+
* @param {string} testFilepath
|
|
195
|
+
* @param {string} repositoryRoot
|
|
196
|
+
* @returns {string}
|
|
197
|
+
*/
|
|
198
|
+
function getNormalizedTestSuitePath (testFilepath, repositoryRoot) {
|
|
199
|
+
const testSuiteAbsolutePath = path.isAbsolute(testFilepath) ? testFilepath : path.join(repositoryRoot, testFilepath)
|
|
200
|
+
return getTestSuitePath(testSuiteAbsolutePath, repositoryRoot)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Build simplified Test Management metadata grouped by normalized test suite path.
|
|
205
|
+
*
|
|
206
|
+
* @param {{ vitest?: { suites?: Record<string, { tests?: Record<string, { properties?: {
|
|
207
|
+
* attempt_to_fix?: boolean,
|
|
208
|
+
* disabled?: boolean,
|
|
209
|
+
* quarantined?: boolean
|
|
210
|
+
* } }> }> } }} testManagementTests
|
|
211
|
+
* @returns {Record<string, Record<string, VitestTestManagementProperties>>}
|
|
212
|
+
*/
|
|
213
|
+
function getTestManagementTestsBySuite (testManagementTests) {
|
|
214
|
+
const testManagementTestsBySuite = {}
|
|
215
|
+
const suites = testManagementTests?.vitest?.suites
|
|
216
|
+
if (!suites) return testManagementTestsBySuite
|
|
217
|
+
|
|
218
|
+
for (const [testSuite, suite] of Object.entries(suites)) {
|
|
219
|
+
const tests = suite?.tests
|
|
220
|
+
if (!tests) continue
|
|
221
|
+
|
|
222
|
+
const testsByName = {}
|
|
223
|
+
let hasTests = false
|
|
224
|
+
for (const [testName, test] of Object.entries(tests)) {
|
|
225
|
+
const properties = test?.properties
|
|
226
|
+
const testProperties = {
|
|
227
|
+
isAttemptToFix: properties?.attempt_to_fix,
|
|
228
|
+
isDisabled: properties?.disabled,
|
|
229
|
+
isQuarantined: properties?.quarantined,
|
|
230
|
+
}
|
|
231
|
+
testsByName[testName] = testProperties
|
|
232
|
+
hasTests = true
|
|
233
|
+
}
|
|
234
|
+
if (hasTests) {
|
|
235
|
+
testManagementTestsBySuite[testSuite] = testsByName
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return testManagementTestsBySuite
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Build a set-like object for test suites modified in the current pull request diff.
|
|
244
|
+
*
|
|
245
|
+
* @param {Record<string, number[]>|undefined} modifiedFiles
|
|
246
|
+
* @returns {Record<string, boolean>}
|
|
247
|
+
*/
|
|
248
|
+
function getImpactedTestSuites (modifiedFiles) {
|
|
249
|
+
const impactedTestSuites = {}
|
|
250
|
+
if (!modifiedFiles) return impactedTestSuites
|
|
251
|
+
|
|
252
|
+
for (const testSuite of Object.keys(modifiedFiles)) {
|
|
253
|
+
if (isModifiedTest(testSuite, 0, 0, modifiedFiles, 'vitest')) {
|
|
254
|
+
impactedTestSuites[testSuite] = true
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return impactedTestSuites
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Build the worker-ready test metadata map keyed by Vitest's absolute filepath.
|
|
263
|
+
*
|
|
264
|
+
* @param {string[]} testFilepaths
|
|
265
|
+
* @param {string} repositoryRoot
|
|
266
|
+
* @param {Record<string, string[]>|undefined} knownTestsBySuite
|
|
267
|
+
* @param {Record<string, Record<string, VitestTestManagementProperties>>|undefined} testManagementTestsBySuite
|
|
268
|
+
* @param {Record<string, boolean>|undefined} impactedTestSuites
|
|
269
|
+
* @returns {Record<string, VitestTestProperties>}
|
|
270
|
+
*/
|
|
271
|
+
function getTestPropertiesByFilepath (
|
|
272
|
+
testFilepaths,
|
|
273
|
+
repositoryRoot,
|
|
274
|
+
knownTestsBySuite,
|
|
275
|
+
testManagementTestsBySuite,
|
|
276
|
+
impactedTestSuites
|
|
277
|
+
) {
|
|
278
|
+
const testPropertiesByFilepath = {}
|
|
279
|
+
if (!Array.isArray(testFilepaths)) return testPropertiesByFilepath
|
|
280
|
+
|
|
281
|
+
for (const testFilepath of testFilepaths) {
|
|
282
|
+
if (typeof testFilepath !== 'string') continue
|
|
283
|
+
|
|
284
|
+
const testSuite = getNormalizedTestSuitePath(testFilepath, repositoryRoot)
|
|
285
|
+
const testProperties = { testSuite }
|
|
286
|
+
const hasProperties = knownTestsBySuite !== undefined ||
|
|
287
|
+
testManagementTestsBySuite !== undefined ||
|
|
288
|
+
impactedTestSuites !== undefined
|
|
289
|
+
|
|
290
|
+
if (knownTestsBySuite) {
|
|
291
|
+
testProperties.knownTests = knownTestsBySuite[testSuite] || []
|
|
292
|
+
}
|
|
293
|
+
if (testManagementTestsBySuite) {
|
|
294
|
+
testProperties.testManagementTests = testManagementTestsBySuite[testSuite] || {}
|
|
295
|
+
}
|
|
296
|
+
if (impactedTestSuites?.[testSuite]) {
|
|
297
|
+
testProperties.isModified = true
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (hasProperties) {
|
|
301
|
+
testPropertiesByFilepath[testFilepath] = testProperties
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return testPropertiesByFilepath
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function wrapCoverageProvider (ctx) {
|
|
309
|
+
const { coverageProvider } = ctx
|
|
310
|
+
if (!coverageProvider?.generateCoverage || coverageWrappedProviders.has(coverageProvider)) {
|
|
311
|
+
return
|
|
312
|
+
}
|
|
313
|
+
coverageWrappedProviders.add(coverageProvider)
|
|
314
|
+
|
|
315
|
+
// Capture coverage root directory from config (default is 'coverage' in cwd)
|
|
316
|
+
try {
|
|
317
|
+
const coverageConfig = ctx.config?.coverage
|
|
318
|
+
const reportsDirectory = coverageConfig?.reportsDirectory || 'coverage'
|
|
319
|
+
const rootDir = ctx.config?.root || process.cwd()
|
|
320
|
+
coverageRootDir = path.isAbsolute(reportsDirectory) ? reportsDirectory : path.join(rootDir, reportsDirectory)
|
|
321
|
+
} catch {
|
|
322
|
+
// Fallback to cwd if we can't get config
|
|
323
|
+
coverageRootDir = process.cwd()
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
shimmer.wrap(coverageProvider, 'generateCoverage', generateCoverage => async function () {
|
|
327
|
+
const totalCodeCoverage = await generateCoverage.apply(this, arguments)
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
testCodeCoverageLinesTotal = totalCodeCoverage.getCoverageSummary().lines.pct
|
|
331
|
+
} catch {
|
|
332
|
+
// ignore errors
|
|
333
|
+
}
|
|
334
|
+
return totalCodeCoverage
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function wrapSessionFinish (ctx) {
|
|
339
|
+
if (finishWrappedContexts.has(ctx)) {
|
|
340
|
+
return
|
|
341
|
+
}
|
|
342
|
+
finishWrappedContexts.add(ctx)
|
|
343
|
+
|
|
344
|
+
shimmer.wrap(ctx, 'exit', getFinishWrapper)
|
|
345
|
+
shimmer.wrap(ctx, 'close', getFinishWrapper)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function resetLibraryConfig () {
|
|
349
|
+
isFlakyTestRetriesEnabled = false
|
|
350
|
+
flakyTestRetriesCount = 0
|
|
351
|
+
isEarlyFlakeDetectionEnabled = false
|
|
352
|
+
earlyFlakeDetectionNumRetries = 0
|
|
353
|
+
earlyFlakeDetectionSlowTestRetries = {}
|
|
354
|
+
isEarlyFlakeDetectionFaulty = false
|
|
355
|
+
isDiEnabled = false
|
|
356
|
+
isKnownTestsEnabled = false
|
|
357
|
+
isTestManagementTestsEnabled = false
|
|
358
|
+
isImpactedTestsEnabled = false
|
|
359
|
+
testManagementAttemptToFixRetries = 0
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function applyLibraryConfig (libraryConfig) {
|
|
363
|
+
isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
|
|
364
|
+
flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
|
|
365
|
+
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
366
|
+
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
367
|
+
earlyFlakeDetectionSlowTestRetries = libraryConfig.earlyFlakeDetectionSlowTestRetries ?? {}
|
|
368
|
+
isEarlyFlakeDetectionFaulty = false
|
|
369
|
+
isDiEnabled = libraryConfig.isDiEnabled
|
|
370
|
+
isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
371
|
+
isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
|
|
372
|
+
testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
|
|
373
|
+
isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function resetMainProcessProvidedContext (ctx) {
|
|
377
|
+
setProvidedContext(ctx, {
|
|
378
|
+
_ddIsDiEnabled: false,
|
|
379
|
+
_ddIsEarlyFlakeDetectionEnabled: false,
|
|
380
|
+
_ddEarlyFlakeDetectionNumRetries: 0,
|
|
381
|
+
_ddEarlyFlakeDetectionSlowTestRetries: {},
|
|
382
|
+
_ddIsFlakyTestRetriesEnabled: false,
|
|
383
|
+
_ddFlakyTestRetriesCount: 0,
|
|
384
|
+
_ddFlakyTestRetriesIncludesUnnamedProject: false,
|
|
385
|
+
_ddFlakyTestRetriesProjectNames: undefined,
|
|
386
|
+
_ddIsImpactedTestsEnabled: false,
|
|
387
|
+
_ddIsKnownTestsEnabled: false,
|
|
388
|
+
_ddIsTestManagementTestsEnabled: false,
|
|
389
|
+
_ddTestManagementAttemptToFixRetries: 0,
|
|
390
|
+
_ddTestPropertiesByFilepath: {},
|
|
391
|
+
}, 'Could not reset Test Optimization context for workers.')
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Merges request error tags from a Test Optimization request response into the tags propagated by no-worker mode.
|
|
396
|
+
*
|
|
397
|
+
* @param {{ requestErrorTags?: Record<string, string> }|undefined} requestResponse - Request response.
|
|
398
|
+
*/
|
|
399
|
+
function mergeRequestErrorTags (requestResponse) {
|
|
400
|
+
if (requestResponse?.requestErrorTags) {
|
|
401
|
+
requestErrorTags = {
|
|
402
|
+
...requestErrorTags,
|
|
403
|
+
...requestResponse.requestErrorTags,
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async function runMainProcessSetup (ctx, frameworkVersion, testSpecifications, shouldInstallNoWorkerInit) {
|
|
409
|
+
if (!testSessionFinishCh.hasSubscribers) {
|
|
410
|
+
return
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
let repositoryRoot = process.cwd()
|
|
414
|
+
let testSessionConfiguration
|
|
415
|
+
let testFilepaths
|
|
416
|
+
let shouldSendTestProperties = false
|
|
417
|
+
let testPropertiesByFilepath
|
|
418
|
+
let knownTests
|
|
419
|
+
let knownTestsBySuite
|
|
420
|
+
let testManagementTests
|
|
421
|
+
let testManagementTestsBySuite
|
|
422
|
+
let modifiedFiles
|
|
423
|
+
let impactedTestSuites
|
|
424
|
+
const getCurrentTestFilepaths = async () => {
|
|
425
|
+
if (testFilepaths === undefined) {
|
|
426
|
+
testFilepaths = await getTestFilepaths(ctx, testSpecifications)
|
|
427
|
+
}
|
|
428
|
+
return testFilepaths
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
try {
|
|
432
|
+
const {
|
|
433
|
+
err,
|
|
434
|
+
libraryConfig,
|
|
435
|
+
requestErrorTags: receivedRequestErrorTags = {},
|
|
436
|
+
} = await getChannelPromise(libraryConfigurationCh, frameworkVersion, {
|
|
437
|
+
isVitestNoWorkerInitActive: shouldInstallNoWorkerInit,
|
|
438
|
+
})
|
|
439
|
+
requestErrorTags = receivedRequestErrorTags
|
|
440
|
+
if (err) {
|
|
441
|
+
resetLibraryConfig()
|
|
442
|
+
} else {
|
|
443
|
+
applyLibraryConfig(libraryConfig)
|
|
444
|
+
}
|
|
445
|
+
} catch {
|
|
446
|
+
requestErrorTags = {}
|
|
447
|
+
resetLibraryConfig()
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
resetMainProcessProvidedContext(ctx)
|
|
451
|
+
|
|
452
|
+
if (testSessionConfigurationCh.hasSubscribers) {
|
|
453
|
+
testSessionConfiguration = await getChannelPromise(testSessionConfigurationCh, frameworkVersion)
|
|
454
|
+
const {
|
|
455
|
+
testSessionId,
|
|
456
|
+
testModuleId,
|
|
457
|
+
testCommand,
|
|
458
|
+
repositoryRoot: receivedRepositoryRoot,
|
|
459
|
+
codeOwnersEntries,
|
|
460
|
+
testEnvironmentMetadata,
|
|
461
|
+
} = testSessionConfiguration
|
|
462
|
+
repositoryRoot = receivedRepositoryRoot || repositoryRoot
|
|
463
|
+
if (!shouldInstallNoWorkerInit) {
|
|
464
|
+
setProvidedContext(ctx, {
|
|
465
|
+
_ddTestSessionId: testSessionId,
|
|
466
|
+
_ddTestModuleId: testModuleId,
|
|
467
|
+
_ddTestCommand: testCommand,
|
|
468
|
+
_ddRepositoryRoot: repositoryRoot,
|
|
469
|
+
_ddCodeOwnersEntries: codeOwnersEntries,
|
|
470
|
+
_ddTestEnvironmentMetadata: testEnvironmentMetadata,
|
|
471
|
+
}, 'Could not send test session configuration to workers.')
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const {
|
|
476
|
+
knownTestsResponse,
|
|
477
|
+
testManagementTestsResponse,
|
|
478
|
+
} = await getTestOptimizationRequestResults({
|
|
479
|
+
isKnownTestsEnabled,
|
|
480
|
+
isTestManagementTestsEnabled,
|
|
481
|
+
getKnownTests: () => getChannelPromise(knownTestsCh),
|
|
482
|
+
getTestManagementTests: () => getChannelPromise(testManagementTestsCh),
|
|
483
|
+
})
|
|
484
|
+
mergeRequestErrorTags(knownTestsResponse)
|
|
485
|
+
mergeRequestErrorTags(testManagementTestsResponse)
|
|
486
|
+
|
|
487
|
+
const flakyTestRetriesConfiguration = configureFlakyTestRetries(ctx, testSpecifications)
|
|
488
|
+
if (flakyTestRetriesConfiguration) {
|
|
489
|
+
setProvidedContext(ctx, {
|
|
490
|
+
_ddIsFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled,
|
|
491
|
+
_ddFlakyTestRetriesCount: flakyTestRetriesCount,
|
|
492
|
+
_ddFlakyTestRetriesIncludesUnnamedProject: flakyTestRetriesConfiguration.includesUnnamedProject,
|
|
493
|
+
_ddFlakyTestRetriesProjectNames: flakyTestRetriesConfiguration.projectNames,
|
|
494
|
+
}, 'Could not send library configuration to workers.')
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (isKnownTestsEnabled) {
|
|
498
|
+
const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
|
|
499
|
+
if (currentKnownTestsResponse.err) {
|
|
500
|
+
isEarlyFlakeDetectionEnabled = false
|
|
501
|
+
} else {
|
|
502
|
+
knownTests = currentKnownTestsResponse.knownTests
|
|
503
|
+
const currentTestFilepaths = await getCurrentTestFilepaths()
|
|
504
|
+
|
|
505
|
+
if (isValidKnownTests(knownTests)) {
|
|
506
|
+
isEarlyFlakeDetectionFaultyCh.publish({
|
|
507
|
+
knownTests: knownTests.vitest,
|
|
508
|
+
testFilepaths: currentTestFilepaths,
|
|
509
|
+
onDone: (isFaulty) => {
|
|
510
|
+
isEarlyFlakeDetectionFaulty = isFaulty
|
|
511
|
+
},
|
|
512
|
+
})
|
|
513
|
+
if (isEarlyFlakeDetectionFaulty) {
|
|
514
|
+
isEarlyFlakeDetectionEnabled = false
|
|
515
|
+
log.warn('New test detection is disabled because the number of new tests is too high.')
|
|
516
|
+
} else {
|
|
517
|
+
knownTestsBySuite = knownTests.vitest
|
|
518
|
+
shouldSendTestProperties = true
|
|
519
|
+
if (!shouldInstallNoWorkerInit) {
|
|
520
|
+
setProvidedContext(ctx, {
|
|
521
|
+
_ddIsKnownTestsEnabled: isKnownTestsEnabled,
|
|
522
|
+
_ddIsEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled,
|
|
523
|
+
_ddEarlyFlakeDetectionNumRetries:
|
|
524
|
+
getConfiguredEfdRetryCount(earlyFlakeDetectionSlowTestRetries, earlyFlakeDetectionNumRetries),
|
|
525
|
+
_ddEarlyFlakeDetectionSlowTestRetries: earlyFlakeDetectionSlowTestRetries,
|
|
526
|
+
}, 'Could not send known tests to workers so Early Flake Detection will not work.')
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
} else {
|
|
530
|
+
isEarlyFlakeDetectionFaulty = true
|
|
531
|
+
isEarlyFlakeDetectionEnabled = false
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (!shouldInstallNoWorkerInit && isDiEnabled) {
|
|
537
|
+
setProvidedContext(ctx, {
|
|
538
|
+
_ddIsDiEnabled: isDiEnabled,
|
|
539
|
+
}, 'Could not send Dynamic Instrumentation configuration to workers.')
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (isTestManagementTestsEnabled) {
|
|
543
|
+
const { err, testManagementTests: receivedTestManagementTests } =
|
|
544
|
+
testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
|
|
545
|
+
if (err) {
|
|
546
|
+
isTestManagementTestsEnabled = false
|
|
547
|
+
log.error('Could not get test management tests.')
|
|
548
|
+
} else {
|
|
549
|
+
testManagementTests = receivedTestManagementTests
|
|
550
|
+
testManagementTestsBySuite = getTestManagementTestsBySuite(receivedTestManagementTests)
|
|
551
|
+
shouldSendTestProperties = true
|
|
552
|
+
if (!shouldInstallNoWorkerInit) {
|
|
553
|
+
setProvidedContext(ctx, {
|
|
554
|
+
_ddIsTestManagementTestsEnabled: isTestManagementTestsEnabled,
|
|
555
|
+
_ddTestManagementAttemptToFixRetries: testManagementAttemptToFixRetries,
|
|
556
|
+
}, 'Could not send test management tests to workers so Test Management will not work.')
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (isImpactedTestsEnabled) {
|
|
562
|
+
const modifiedFilesResponse = await getChannelPromise(modifiedFilesCh)
|
|
563
|
+
const { err } = modifiedFilesResponse
|
|
564
|
+
if (err) {
|
|
565
|
+
log.error('Could not get modified tests.')
|
|
566
|
+
} else {
|
|
567
|
+
modifiedFiles = modifiedFilesResponse.modifiedFiles
|
|
568
|
+
impactedTestSuites = getImpactedTestSuites(modifiedFiles)
|
|
569
|
+
shouldSendTestProperties = true
|
|
570
|
+
if (!shouldInstallNoWorkerInit) {
|
|
571
|
+
setProvidedContext(ctx, {
|
|
572
|
+
_ddIsImpactedTestsEnabled: isImpactedTestsEnabled,
|
|
573
|
+
}, 'Could not send modified tests to workers so Impacted Tests will not work.')
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (shouldSendTestProperties) {
|
|
579
|
+
testPropertiesByFilepath = getTestPropertiesByFilepath(
|
|
580
|
+
await getCurrentTestFilepaths(),
|
|
581
|
+
repositoryRoot,
|
|
582
|
+
knownTestsBySuite,
|
|
583
|
+
testManagementTestsBySuite,
|
|
584
|
+
impactedTestSuites
|
|
585
|
+
)
|
|
586
|
+
if (!shouldInstallNoWorkerInit) {
|
|
587
|
+
setProvidedContext(ctx, {
|
|
588
|
+
_ddTestPropertiesByFilepath: testPropertiesByFilepath,
|
|
589
|
+
}, 'Could not send test properties to workers so some Test Optimization features will not work.')
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (shouldInstallNoWorkerInit) {
|
|
594
|
+
noWorkerInit.configure(ctx, frameworkVersion, testSpecifications, {
|
|
595
|
+
knownTests,
|
|
596
|
+
knownTestsBySuite,
|
|
597
|
+
modifiedFiles,
|
|
598
|
+
repositoryRoot,
|
|
599
|
+
flakyTestRetriesConfiguration,
|
|
600
|
+
testManagementTests,
|
|
601
|
+
testManagementTestsBySuite,
|
|
602
|
+
testPropertiesByFilepath: testPropertiesByFilepath || {},
|
|
603
|
+
testSessionConfiguration,
|
|
604
|
+
}, {
|
|
605
|
+
getConfiguredEfdRetryCount,
|
|
606
|
+
state: getNoWorkerInitState(),
|
|
607
|
+
})
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
wrapCoverageProvider(ctx)
|
|
611
|
+
wrapSessionFinish(ctx)
|
|
612
|
+
return shouldInstallNoWorkerInit
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function getNoWorkerInitState () {
|
|
616
|
+
return {
|
|
617
|
+
attemptToFixExecutions,
|
|
618
|
+
earlyFlakeDetectionNumRetries,
|
|
619
|
+
earlyFlakeDetectionSlowTestRetries,
|
|
620
|
+
isEarlyFlakeDetectionEnabled,
|
|
621
|
+
isEarlyFlakeDetectionFaulty,
|
|
622
|
+
isFlakyTestRetriesEnabled,
|
|
623
|
+
isKnownTestsEnabled,
|
|
624
|
+
newTestsWithDynamicNames,
|
|
625
|
+
requestErrorTags,
|
|
626
|
+
testManagementAttemptToFixRetries,
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function ensureMainProcessSetup (ctx, frameworkVersion, testSpecifications, shouldDeactivateOnFallback = false) {
|
|
631
|
+
const shouldInstallNoWorkerInit = shouldUseNoWorkerInit(ctx, frameworkVersion, testSpecifications)
|
|
632
|
+
const specificationsKey = getTestSpecificationsKey(testSpecifications)
|
|
633
|
+
let setupState = mainProcessSetupStates.get(ctx)
|
|
634
|
+
if (shouldDeactivateOnFallback && setupState?.shouldInstallNoWorkerInit && !shouldInstallNoWorkerInit) {
|
|
635
|
+
noWorkerInit.deactivate(ctx)
|
|
636
|
+
}
|
|
637
|
+
if (
|
|
638
|
+
!setupState ||
|
|
639
|
+
setupState.specificationsKey !== specificationsKey ||
|
|
640
|
+
setupState.shouldInstallNoWorkerInit !== shouldInstallNoWorkerInit
|
|
641
|
+
) {
|
|
642
|
+
setupState = {
|
|
643
|
+
setupPromise: runMainProcessSetup(ctx, frameworkVersion, testSpecifications, shouldInstallNoWorkerInit),
|
|
644
|
+
shouldInstallNoWorkerInit,
|
|
645
|
+
specificationsKey,
|
|
646
|
+
}
|
|
647
|
+
mainProcessSetupStates.set(ctx, setupState)
|
|
648
|
+
}
|
|
649
|
+
return setupState.setupPromise
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function shouldUseNoWorkerInit (ctx, frameworkVersion, testSpecifications) {
|
|
653
|
+
return noWorkerInit.shouldUse(ctx, frameworkVersion, testSpecifications, {
|
|
654
|
+
hasVitestWorkerPoolTestSpecification,
|
|
655
|
+
isVitestWorkerPool,
|
|
656
|
+
})
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function configureFlakyTestRetries (ctx, testSpecifications) {
|
|
660
|
+
if (!isFlakyTestRetriesEnabled || flakyTestRetriesCount <= 0) return
|
|
661
|
+
|
|
662
|
+
let configured = false
|
|
663
|
+
let includesUnnamedProject = false
|
|
664
|
+
const projectNames = []
|
|
665
|
+
for (const { config, projectName } of getVitestProjectConfigs(ctx, testSpecifications)) {
|
|
666
|
+
if (!config.retry) {
|
|
667
|
+
config.retry = flakyTestRetriesCount
|
|
668
|
+
configured = true
|
|
669
|
+
if (projectName) {
|
|
670
|
+
projectNames.push(projectName)
|
|
671
|
+
} else {
|
|
672
|
+
includesUnnamedProject = true
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (!configured) return
|
|
678
|
+
|
|
679
|
+
return {
|
|
680
|
+
includesUnnamedProject,
|
|
681
|
+
projectNames,
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
function getVitestProjectConfigs (ctx, testSpecifications) {
|
|
686
|
+
const entries = []
|
|
687
|
+
|
|
688
|
+
addTestSpecificationConfigs(entries, testSpecifications)
|
|
689
|
+
if (entries.length > 0) {
|
|
690
|
+
return entries
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const selectedProjectNames = getSelectedProjectNames()
|
|
694
|
+
addSelectedInlineProjectConfigs(entries, safeConfig(ctx), selectedProjectNames)
|
|
695
|
+
addSelectedRuntimeProjectConfigs(entries, ctx?.projects, selectedProjectNames)
|
|
696
|
+
if (entries.length > 0) {
|
|
697
|
+
return entries
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (Array.isArray(ctx?.projects)) {
|
|
701
|
+
for (const project of ctx.projects) {
|
|
702
|
+
addConfig(entries, safeConfig(project), getProjectName(project))
|
|
703
|
+
}
|
|
704
|
+
if (entries.length > 0) {
|
|
705
|
+
return entries
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
addConfig(entries, safeConfig(ctx))
|
|
710
|
+
addConfig(entries, safeConfig(safeWorkspaceProject(ctx)))
|
|
711
|
+
|
|
712
|
+
return entries
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function addTestSpecificationConfigs (entries, testSpecifications) {
|
|
716
|
+
if (!Array.isArray(testSpecifications)) return
|
|
717
|
+
|
|
718
|
+
for (const testSpecification of testSpecifications) {
|
|
719
|
+
const project = getTestSpecificationProject(testSpecification)
|
|
720
|
+
addConfig(entries, safeConfig(project), getProjectName(project))
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function addSelectedInlineProjectConfigs (entries, rootConfig, selectedProjectNames) {
|
|
725
|
+
if (selectedProjectNames.length === 0 || !Array.isArray(rootConfig?.projects)) return
|
|
726
|
+
|
|
727
|
+
for (const project of rootConfig.projects) {
|
|
728
|
+
const config = getInlineProjectConfig(project)
|
|
729
|
+
const projectName = getProjectName(project)
|
|
730
|
+
if (selectedProjectNames.includes(projectName)) {
|
|
731
|
+
addConfig(entries, config, projectName)
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function addSelectedRuntimeProjectConfigs (entries, projects, selectedProjectNames) {
|
|
737
|
+
if (selectedProjectNames.length === 0 || !Array.isArray(projects)) return
|
|
738
|
+
|
|
739
|
+
for (const project of projects) {
|
|
740
|
+
const projectName = getProjectName(project)
|
|
741
|
+
if (selectedProjectNames.includes(projectName)) {
|
|
742
|
+
addConfig(entries, safeConfig(project), projectName)
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function getSelectedProjectNames () {
|
|
748
|
+
const names = []
|
|
749
|
+
for (let index = 0; index < process.argv.length; index++) {
|
|
750
|
+
const argument = process.argv[index]
|
|
751
|
+
if (argument === '--project' && process.argv[index + 1]) {
|
|
752
|
+
names.push(process.argv[index + 1])
|
|
753
|
+
index++
|
|
754
|
+
} else if (argument.startsWith('--project=')) {
|
|
755
|
+
names.push(argument.slice('--project='.length))
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
return names
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function getInlineProjectConfig (project) {
|
|
762
|
+
return project?.test || project
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function getProjectName (project) {
|
|
766
|
+
return normalizeProjectName(project?.name || project?.config?.name || project?.test?.name)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function normalizeProjectName (name) {
|
|
770
|
+
if (typeof name === 'string') return name
|
|
771
|
+
|
|
772
|
+
const label = name?.label
|
|
773
|
+
return typeof label === 'string' ? label : undefined
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function addConfig (entries, config, projectName) {
|
|
777
|
+
if (config && !entries.some(entry => entry.config === config || (projectName && entry.projectName === projectName))) {
|
|
778
|
+
entries.push({ config, projectName })
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function safeConfig (project) {
|
|
783
|
+
let config
|
|
784
|
+
try {
|
|
785
|
+
config = project?.config
|
|
786
|
+
} catch {}
|
|
787
|
+
return config
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function safeWorkspaceProject (ctx) {
|
|
791
|
+
let project
|
|
792
|
+
try {
|
|
793
|
+
project = getWorkspaceProject(ctx)
|
|
794
|
+
} catch {}
|
|
795
|
+
return project
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function getSortWrapper (sort, frameworkVersion) {
|
|
799
|
+
return async function () {
|
|
800
|
+
await ensureMainProcessSetup(this.ctx, frameworkVersion, arguments[0])
|
|
801
|
+
return sort.apply(this, arguments)
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function getFinishWrapper (exitOrClose) {
|
|
806
|
+
let isClosed = false
|
|
807
|
+
return async function () {
|
|
808
|
+
if (isClosed) { // needed because exit calls close
|
|
809
|
+
return exitOrClose.apply(this, arguments)
|
|
810
|
+
}
|
|
811
|
+
isClosed = true
|
|
812
|
+
|
|
813
|
+
if (!testSessionFinishCh.hasSubscribers) {
|
|
814
|
+
return exitOrClose.apply(this, arguments)
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
let onFinish
|
|
818
|
+
|
|
819
|
+
const flushPromise = new Promise(resolve => {
|
|
820
|
+
onFinish = resolve
|
|
821
|
+
})
|
|
822
|
+
const failedSuites = this.state.getFailedFilepaths()
|
|
823
|
+
let error
|
|
824
|
+
if (failedSuites.length) {
|
|
825
|
+
error = new Error(`Test suites failed: ${failedSuites.length}.`)
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
testSessionFinishCh.publish({
|
|
829
|
+
status: getSessionStatus(this.state),
|
|
830
|
+
testCodeCoverageLinesTotal,
|
|
831
|
+
error,
|
|
832
|
+
isEarlyFlakeDetectionEnabled,
|
|
833
|
+
isEarlyFlakeDetectionFaulty,
|
|
834
|
+
isTestManagementTestsEnabled,
|
|
835
|
+
requestErrorTags,
|
|
836
|
+
vitestPool,
|
|
837
|
+
isVitestNoWorkerInitActive,
|
|
838
|
+
onFinish,
|
|
839
|
+
})
|
|
840
|
+
|
|
841
|
+
logTestOptimizationSummary({ attemptToFixExecutions, newTestsWithDynamicNames })
|
|
842
|
+
|
|
843
|
+
await flushPromise
|
|
844
|
+
|
|
845
|
+
// If coverage was generated, publish coverage report channel for upload
|
|
846
|
+
if (coverageRootDir && codeCoverageReportCh.hasSubscribers) {
|
|
847
|
+
await new Promise((resolve) => {
|
|
848
|
+
codeCoverageReportCh.publish({ rootDir: coverageRootDir, onDone: resolve })
|
|
849
|
+
})
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
return exitOrClose.apply(this, arguments)
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function getCliOrStartVitestWrapper (frameworkVersion) {
|
|
857
|
+
return function (oldCliOrStartVitest) {
|
|
858
|
+
return function (...args) {
|
|
859
|
+
if (!testSessionStartCh.hasSubscribers || isSessionStarted) {
|
|
860
|
+
return oldCliOrStartVitest.apply(this, args)
|
|
861
|
+
}
|
|
862
|
+
isSessionStarted = true
|
|
863
|
+
testSessionStartCh.publish({ command: getTestCommand(), frameworkVersion })
|
|
864
|
+
return oldCliOrStartVitest.apply(this, args)
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function isForkPool (pool) {
|
|
870
|
+
return pool === 'forks' || pool === 'vmForks'
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
function isThreadPool (pool) {
|
|
874
|
+
return pool === 'threads' || pool === 'vmThreads'
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
function isVitestWorkerPool (pool) {
|
|
878
|
+
return isForkPool(pool) || isThreadPool(pool)
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function getTestSpecificationProject (testSpecification) {
|
|
882
|
+
if (Array.isArray(testSpecification)) {
|
|
883
|
+
return testSpecification[0]
|
|
884
|
+
}
|
|
885
|
+
return testSpecification?.project
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
function getTestSpecificationOptions (testSpecification) {
|
|
889
|
+
if (Array.isArray(testSpecification)) {
|
|
890
|
+
return testSpecification[2]
|
|
891
|
+
}
|
|
892
|
+
return testSpecification
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
function getTestSpecificationPool (testSpecification) {
|
|
896
|
+
const options = getTestSpecificationOptions(testSpecification)
|
|
897
|
+
const project = getTestSpecificationProject(testSpecification)
|
|
898
|
+
return options?.pool || project?.config?.pool || project?.serializedConfig?.pool || project?.pool ||
|
|
899
|
+
testSpecification?.pool
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function hasVitestWorkerPoolTestSpecification (testSpecifications) {
|
|
903
|
+
if (!Array.isArray(testSpecifications)) {
|
|
904
|
+
return false
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
for (const testSpecification of testSpecifications) {
|
|
908
|
+
if (isVitestWorkerPool(getTestSpecificationPool(testSpecification))) {
|
|
909
|
+
return true
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return false
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
function shouldMarkVitestWorkerEnv (pool, testSpecifications, shouldSkipWorkerInit) {
|
|
917
|
+
if (!shouldSkipWorkerInit) {
|
|
918
|
+
return isVitestWorkerPool(pool) || hasVitestWorkerPoolTestSpecification(testSpecifications) ||
|
|
919
|
+
(!testSpecifications && pool === undefined)
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
return isVitestWorkerPool(pool) || pool === undefined || hasVitestWorkerPoolTestSpecification(testSpecifications)
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function markVitestWorkerEnv (ctx, testSpecifications, shouldSkipWorkerInit = false) {
|
|
926
|
+
const config = ctx?.config
|
|
927
|
+
isVitestNoWorkerInitActive = shouldSkipWorkerInit
|
|
928
|
+
if (!config || !shouldMarkVitestWorkerEnv(config.pool, testSpecifications, shouldSkipWorkerInit)) {
|
|
929
|
+
return
|
|
930
|
+
}
|
|
931
|
+
config.env = getVitestWorkerEnv(config.env, shouldSkipWorkerInit)
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
function wrapVitestRunFiles (Vitest, frameworkVersion) {
|
|
935
|
+
if (!Vitest?.prototype?.runFiles) {
|
|
936
|
+
return
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
shimmer.wrap(Vitest.prototype, 'runFiles', runFiles => async function (testSpecifications) {
|
|
940
|
+
const shouldSkipWorkerInit = await ensureMainProcessSetup(this, frameworkVersion, testSpecifications, true)
|
|
941
|
+
markVitestWorkerEnv(this, testSpecifications, shouldSkipWorkerInit)
|
|
942
|
+
return runFiles.apply(this, arguments)
|
|
943
|
+
})
|
|
944
|
+
|
|
945
|
+
if (Vitest.prototype.collectTests) {
|
|
946
|
+
shimmer.wrap(Vitest.prototype, 'collectTests', collectTests => function (testSpecifications) {
|
|
947
|
+
const shouldSkipWorkerInit = shouldUseNoWorkerInit(this, frameworkVersion, testSpecifications)
|
|
948
|
+
markVitestWorkerEnv(this, testSpecifications, shouldSkipWorkerInit)
|
|
949
|
+
return collectTests.apply(this, arguments)
|
|
950
|
+
})
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
function getTypecheckTaskStatus (task) {
|
|
955
|
+
const state = task.result?.state
|
|
956
|
+
if (state === 'fail') return 'fail'
|
|
957
|
+
if (state === 'skip' || task.mode === 'skip' || task.mode === 'todo') return 'skip'
|
|
958
|
+
return 'pass'
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Return whether a typecheck suite name represents the synthetic file-level suite.
|
|
963
|
+
*
|
|
964
|
+
* @param {string|undefined} suiteName
|
|
965
|
+
* @param {string} testSuiteAbsolutePath
|
|
966
|
+
* @returns {boolean}
|
|
967
|
+
*/
|
|
968
|
+
function isTypecheckFileSuiteName (suiteName, testSuiteAbsolutePath) {
|
|
969
|
+
if (!suiteName || !testSuiteAbsolutePath) return false
|
|
970
|
+
|
|
971
|
+
const normalizedSuiteName = path.normalize(suiteName).replaceAll('\\', '/')
|
|
972
|
+
const normalizedSuitePath = path.normalize(testSuiteAbsolutePath).replaceAll('\\', '/')
|
|
973
|
+
|
|
974
|
+
return normalizedSuitePath === normalizedSuiteName || normalizedSuitePath.endsWith(`/${normalizedSuiteName}`)
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Return a typecheck test name with describe/suite prefixes and without the file-level suite prefix.
|
|
979
|
+
*
|
|
980
|
+
* @param {object} task
|
|
981
|
+
* @param {string} testSuiteAbsolutePath
|
|
982
|
+
* @returns {string}
|
|
983
|
+
*/
|
|
984
|
+
function getTypecheckTestName (task, testSuiteAbsolutePath) {
|
|
985
|
+
let testName = task.name || task.fullTestName
|
|
986
|
+
let currentTask = task.suite
|
|
987
|
+
|
|
988
|
+
while (currentTask) {
|
|
989
|
+
if (currentTask.name && !isTypecheckFileSuiteName(currentTask.name, testSuiteAbsolutePath)) {
|
|
990
|
+
testName = `${currentTask.name} ${testName}`
|
|
991
|
+
}
|
|
992
|
+
currentTask = currentTask.suite
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
return testName
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Return Test Optimization metadata prepared in Vitest's main process setup.
|
|
1000
|
+
*
|
|
1001
|
+
* @param {object|undefined} ctx
|
|
1002
|
+
* @returns {{ testPropertiesByFilepath: object }}
|
|
1003
|
+
*/
|
|
1004
|
+
function getMainProcessProvidedContext (ctx) {
|
|
1005
|
+
try {
|
|
1006
|
+
const workspaceProject = getWorkspaceProject(ctx)
|
|
1007
|
+
const providedContext = workspaceProject.getProvidedContext?.() || workspaceProject._provided || {}
|
|
1008
|
+
|
|
1009
|
+
return {
|
|
1010
|
+
testPropertiesByFilepath: providedContext._ddTestPropertiesByFilepath || {},
|
|
1011
|
+
}
|
|
1012
|
+
} catch {
|
|
1013
|
+
return {
|
|
1014
|
+
testPropertiesByFilepath: {},
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* Return the Vitest context that owns a Typechecker instance.
|
|
1021
|
+
*
|
|
1022
|
+
* @param {object} typechecker
|
|
1023
|
+
* @returns {object|undefined}
|
|
1024
|
+
*/
|
|
1025
|
+
function getTypecheckerVitestContext (typechecker) {
|
|
1026
|
+
return typechecker.ctx || typechecker.project?.vitest
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Apply Test Management result semantics to Vitest's returned typecheck task result.
|
|
1031
|
+
*
|
|
1032
|
+
* @param {object} task
|
|
1033
|
+
* @param {string} status
|
|
1034
|
+
* @param {{
|
|
1035
|
+
* isAttemptToFix: boolean,
|
|
1036
|
+
* isDisabled: boolean,
|
|
1037
|
+
* isQuarantined: boolean
|
|
1038
|
+
* }} testManagement
|
|
1039
|
+
*/
|
|
1040
|
+
function updateTypecheckTaskResultForTestManagement (task, status, testManagement) {
|
|
1041
|
+
const { isAttemptToFix, isDisabled, isQuarantined } = testManagement
|
|
1042
|
+
if (isAttemptToFix || !task.result) return
|
|
1043
|
+
|
|
1044
|
+
if (isDisabled) {
|
|
1045
|
+
task.mode = 'skip'
|
|
1046
|
+
task.result.state = 'skip'
|
|
1047
|
+
task.result.errors = []
|
|
1048
|
+
return
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
if (isQuarantined && status === 'fail') {
|
|
1052
|
+
task.result.state = 'pass'
|
|
1053
|
+
task.result.errors = []
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Recompute suite/file typecheck results after Test Management rewrites child test results.
|
|
1059
|
+
*
|
|
1060
|
+
* @param {object} task
|
|
1061
|
+
* @returns {string}
|
|
1062
|
+
*/
|
|
1063
|
+
function updateTypecheckTaskTreeResult (task) {
|
|
1064
|
+
if (!Array.isArray(task.tasks)) return getTypecheckTaskStatus(task)
|
|
1065
|
+
|
|
1066
|
+
let hasPassedTest = false
|
|
1067
|
+
let hasSkippedTest = false
|
|
1068
|
+
for (const childTask of task.tasks) {
|
|
1069
|
+
const status = updateTypecheckTaskTreeResult(childTask)
|
|
1070
|
+
if (status === 'fail') {
|
|
1071
|
+
task.result = {
|
|
1072
|
+
...task.result,
|
|
1073
|
+
state: 'fail',
|
|
1074
|
+
}
|
|
1075
|
+
return 'fail'
|
|
1076
|
+
}
|
|
1077
|
+
if (status === 'skip') {
|
|
1078
|
+
hasSkippedTest = true
|
|
1079
|
+
} else {
|
|
1080
|
+
hasPassedTest = true
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
if (task.result?.errors?.length) return 'fail'
|
|
1085
|
+
if (!hasPassedTest && !hasSkippedTest) return getTypecheckTaskStatus(task)
|
|
1086
|
+
|
|
1087
|
+
task.result = {
|
|
1088
|
+
...task.result,
|
|
1089
|
+
state: hasPassedTest ? 'pass' : 'skip',
|
|
1090
|
+
errors: [],
|
|
1091
|
+
}
|
|
1092
|
+
return task.result.state
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Recompute the aggregate typecheck result after Test Management rewrites file results.
|
|
1097
|
+
*
|
|
1098
|
+
* @param {{
|
|
1099
|
+
* files?: object[],
|
|
1100
|
+
* errors?: object[],
|
|
1101
|
+
* diagnostics?: object[],
|
|
1102
|
+
* sourceErrors?: object[],
|
|
1103
|
+
* state?: string
|
|
1104
|
+
* }} result
|
|
1105
|
+
* @returns {boolean}
|
|
1106
|
+
*/
|
|
1107
|
+
function updateTypecheckResult (result) {
|
|
1108
|
+
if (result.sourceErrors?.length) return false
|
|
1109
|
+
|
|
1110
|
+
let hasPassedFile = false
|
|
1111
|
+
let hasSkippedFile = false
|
|
1112
|
+
for (const file of result.files) {
|
|
1113
|
+
const status = getTypecheckTaskStatus(file)
|
|
1114
|
+
if (status === 'fail') return false
|
|
1115
|
+
if (status === 'skip') {
|
|
1116
|
+
hasSkippedFile = true
|
|
1117
|
+
} else {
|
|
1118
|
+
hasPassedFile = true
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if (!hasPassedFile && !hasSkippedFile) return false
|
|
1123
|
+
|
|
1124
|
+
result.state = hasPassedFile ? 'pass' : 'skip'
|
|
1125
|
+
result.errors = []
|
|
1126
|
+
result.diagnostics = []
|
|
1127
|
+
result.sourceErrors = []
|
|
1128
|
+
return true
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* Clear Vitest's typechecker exit code after all typecheck failures were handled by Test Management.
|
|
1133
|
+
*
|
|
1134
|
+
* @param {{ process?: { exitCode?: number|null } }} typechecker
|
|
1135
|
+
*/
|
|
1136
|
+
function clearTypecheckerExitCode (typechecker) {
|
|
1137
|
+
if (typechecker?.process?.exitCode == null) return
|
|
1138
|
+
|
|
1139
|
+
typechecker.process.exitCode = 0
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function reportTypecheckTest (task, testSuiteAbsolutePath, providedContext) {
|
|
1143
|
+
const testName = getTypecheckTestName(task, testSuiteAbsolutePath)
|
|
1144
|
+
const testProperties = getVitestTestProperties(providedContext, testSuiteAbsolutePath, testName)
|
|
1145
|
+
const isAttemptToFix = testProperties.isAttemptToFix === true
|
|
1146
|
+
const isDisabled = testProperties.isDisabled === true
|
|
1147
|
+
const isQuarantined = testProperties.isQuarantined === true
|
|
1148
|
+
const isModified = testProperties.isModified === true
|
|
1149
|
+
const isSkippedByTestManagement = !isAttemptToFix && isDisabled
|
|
1150
|
+
const status = getTypecheckTaskStatus(task)
|
|
1151
|
+
|
|
1152
|
+
if (status === 'skip' || isSkippedByTestManagement) {
|
|
1153
|
+
testSkipCh.publish({
|
|
1154
|
+
testName,
|
|
1155
|
+
testSuiteAbsolutePath,
|
|
1156
|
+
isNew: testProperties.isNew,
|
|
1157
|
+
isDisabled,
|
|
1158
|
+
})
|
|
1159
|
+
updateTypecheckTaskResultForTestManagement(task, status, { isAttemptToFix, isDisabled, isQuarantined })
|
|
1160
|
+
return
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
const ctx = {
|
|
1164
|
+
testName,
|
|
1165
|
+
testSuiteAbsolutePath,
|
|
1166
|
+
isRetry: false,
|
|
1167
|
+
isNew: testProperties.isNew,
|
|
1168
|
+
hasDynamicName: false,
|
|
1169
|
+
mightHitProbe: false,
|
|
1170
|
+
isAttemptToFix,
|
|
1171
|
+
isDisabled,
|
|
1172
|
+
isQuarantined,
|
|
1173
|
+
isModified,
|
|
1174
|
+
}
|
|
1175
|
+
testStartCh.runStores(ctx, () => {})
|
|
1176
|
+
|
|
1177
|
+
const finalStatus = !isAttemptToFix && isQuarantined ? 'skip' : undefined
|
|
1178
|
+
if (status === 'fail') {
|
|
1179
|
+
testErrorCh.publish({
|
|
1180
|
+
error: task.result?.errors?.[0],
|
|
1181
|
+
finalStatus,
|
|
1182
|
+
...ctx.currentStore,
|
|
1183
|
+
})
|
|
1184
|
+
} else {
|
|
1185
|
+
testPassCh.publish({
|
|
1186
|
+
task,
|
|
1187
|
+
finalStatus,
|
|
1188
|
+
...ctx.currentStore,
|
|
1189
|
+
})
|
|
1190
|
+
}
|
|
1191
|
+
updateTypecheckTaskResultForTestManagement(task, status, { isAttemptToFix, isDisabled, isQuarantined })
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
async function reportTypecheckFile (file, sessionConfiguration, frameworkVersion, providedContext) {
|
|
1195
|
+
const testSuiteAbsolutePath = file.filepath
|
|
1196
|
+
const testSuiteCtx = {
|
|
1197
|
+
testSuiteAbsolutePath,
|
|
1198
|
+
frameworkVersion,
|
|
1199
|
+
testSessionId: sessionConfiguration.testSessionId,
|
|
1200
|
+
testModuleId: sessionConfiguration.testModuleId,
|
|
1201
|
+
testCommand: sessionConfiguration.testCommand,
|
|
1202
|
+
repositoryRoot: sessionConfiguration.repositoryRoot,
|
|
1203
|
+
codeOwnersEntries: sessionConfiguration.codeOwnersEntries,
|
|
1204
|
+
}
|
|
1205
|
+
testSuiteStartCh.runStores(testSuiteCtx, () => {})
|
|
1206
|
+
|
|
1207
|
+
for (const task of getTypeTasks(file.tasks)) {
|
|
1208
|
+
reportTypecheckTest(task, testSuiteAbsolutePath, providedContext)
|
|
1209
|
+
}
|
|
1210
|
+
updateTypecheckTaskTreeResult(file)
|
|
1211
|
+
|
|
1212
|
+
const testSuiteError = file.result?.errors?.[0]
|
|
1213
|
+
if (testSuiteError) {
|
|
1214
|
+
testSuiteCtx.error = testSuiteError
|
|
1215
|
+
testSuiteErrorCh.runStores(testSuiteCtx, () => {})
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
let onFinish
|
|
1219
|
+
const onFinishPromise = new Promise(resolve => {
|
|
1220
|
+
onFinish = resolve
|
|
1221
|
+
})
|
|
1222
|
+
testSuiteFinishCh.publish({
|
|
1223
|
+
status: getTypecheckTaskStatus(file),
|
|
1224
|
+
onFinish,
|
|
1225
|
+
...testSuiteCtx.currentStore,
|
|
1226
|
+
})
|
|
1227
|
+
await onFinishPromise
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
async function reportTypecheckResults (result, frameworkVersion, ctx, typechecker) {
|
|
1231
|
+
if (!testSuiteFinishCh.hasSubscribers) return
|
|
1232
|
+
if (!Array.isArray(result?.files)) return
|
|
1233
|
+
|
|
1234
|
+
if (ctx) {
|
|
1235
|
+
await ensureMainProcessSetup(ctx, frameworkVersion, result.files)
|
|
1236
|
+
}
|
|
1237
|
+
const providedContext = getMainProcessProvidedContext(ctx)
|
|
1238
|
+
const sessionConfiguration = testSessionConfigurationCh.hasSubscribers
|
|
1239
|
+
? await getChannelPromise(testSessionConfigurationCh, frameworkVersion)
|
|
1240
|
+
: {}
|
|
1241
|
+
|
|
1242
|
+
await Promise.all(result.files.map(file => reportTypecheckFile(
|
|
1243
|
+
file,
|
|
1244
|
+
sessionConfiguration,
|
|
1245
|
+
frameworkVersion,
|
|
1246
|
+
providedContext
|
|
1247
|
+
)))
|
|
1248
|
+
if (updateTypecheckResult(result)) {
|
|
1249
|
+
clearTypecheckerExitCode(typechecker)
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
function wrapTypechecker (Typechecker, frameworkVersion) {
|
|
1254
|
+
if (!Typechecker?.prototype?.prepareResults) return
|
|
1255
|
+
|
|
1256
|
+
shimmer.wrap(Typechecker.prototype, 'prepareResults', prepareResults => async function () {
|
|
1257
|
+
const result = await prepareResults.apply(this, arguments)
|
|
1258
|
+
await reportTypecheckResults(result, frameworkVersion, getTypecheckerVitestContext(this), this)
|
|
1259
|
+
return result
|
|
1260
|
+
})
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function getTypecheckerWrapper (vitestPackage, frameworkVersion) {
|
|
1264
|
+
const typechecker = getTypecheckerExport(vitestPackage)
|
|
1265
|
+
if (typechecker) {
|
|
1266
|
+
wrapTypechecker(typechecker.value, frameworkVersion)
|
|
1267
|
+
}
|
|
1268
|
+
return vitestPackage
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
function getCreateCliWrapper (vitestPackage, frameworkVersion) {
|
|
1272
|
+
const createCliExport = findExportByName(vitestPackage, 'createCLI')
|
|
1273
|
+
if (!createCliExport) {
|
|
1274
|
+
return vitestPackage
|
|
1275
|
+
}
|
|
1276
|
+
shimmer.wrap(vitestPackage, createCliExport.key, getCliOrStartVitestWrapper(frameworkVersion))
|
|
1277
|
+
|
|
1278
|
+
return vitestPackage
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
function threadHandler (thread) {
|
|
1282
|
+
const { runtime } = thread
|
|
1283
|
+
let workerProcess
|
|
1284
|
+
if (runtime === 'child_process') {
|
|
1285
|
+
vitestPool = 'child_process'
|
|
1286
|
+
workerProcess = thread.process
|
|
1287
|
+
} else if (runtime === 'worker_threads') {
|
|
1288
|
+
vitestPool = 'worker_threads'
|
|
1289
|
+
workerProcess = thread.thread
|
|
1290
|
+
} else {
|
|
1291
|
+
vitestPool = 'unknown'
|
|
1292
|
+
}
|
|
1293
|
+
if (!workerProcess) {
|
|
1294
|
+
log.error('Vitest error: could not get process or thread from TinyPool#run')
|
|
1295
|
+
return
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
if (workerProcesses.has(workerProcess)) {
|
|
1299
|
+
return
|
|
1300
|
+
}
|
|
1301
|
+
workerProcesses.add(workerProcess)
|
|
1302
|
+
workerProcess.on('message', (message) => {
|
|
1303
|
+
if (message.__tinypool_worker_message__ && message.data) {
|
|
1304
|
+
handleWorkerReport(message.interprocessCode, message.data)
|
|
1305
|
+
}
|
|
1306
|
+
})
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
function isVitestTinypoolOptions (options) {
|
|
1310
|
+
if (options?.env?.VITEST !== 'true' || typeof options.filename !== 'string') return false
|
|
1311
|
+
|
|
1312
|
+
let filename = options.filename
|
|
1313
|
+
if (filename.startsWith('file:')) {
|
|
1314
|
+
try {
|
|
1315
|
+
filename = fileURLToPath(filename)
|
|
1316
|
+
} catch {
|
|
1317
|
+
return false
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
const workerPath = path.normalize(filename)
|
|
1322
|
+
const workerDir = path.dirname(workerPath)
|
|
1323
|
+
const packageDir = path.dirname(workerDir)
|
|
1324
|
+
|
|
1325
|
+
return path.basename(workerPath) === 'worker.js' &&
|
|
1326
|
+
path.basename(workerDir) === 'dist' &&
|
|
1327
|
+
path.basename(packageDir) === 'vitest'
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
function markVitestTinypoolOptions (options) {
|
|
1331
|
+
if (!isVitestTinypoolOptions(options)) return
|
|
1332
|
+
|
|
1333
|
+
options.env = getVitestWorkerEnv(options.env, isVitestNoWorkerInitActive)
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
function getVitestWorkerEnv (env = {}, shouldSkipWorkerInit = false) {
|
|
1337
|
+
return noWorkerInit.configureWorkerEnv({
|
|
1338
|
+
...env,
|
|
1339
|
+
DD_VITEST_WORKER: '1',
|
|
1340
|
+
}, shouldSkipWorkerInit)
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
function wrapTinyPoolRun (TinyPool) {
|
|
1344
|
+
if (!TinyPool?.prototype?.run) return
|
|
1345
|
+
|
|
1346
|
+
shimmer.wrap(TinyPool.prototype, 'run', run => async function () {
|
|
1347
|
+
// We have to do this before and after because the threads list gets recycled, that is, the processes are re-created
|
|
1348
|
+
// eslint-disable-next-line unicorn/no-array-for-each
|
|
1349
|
+
this.threads.forEach(threadHandler)
|
|
1350
|
+
const runResult = await run.apply(this, arguments)
|
|
1351
|
+
// eslint-disable-next-line unicorn/no-array-for-each
|
|
1352
|
+
this.threads.forEach(threadHandler)
|
|
1353
|
+
return runResult
|
|
1354
|
+
})
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
function wrapTinyPoolClass (TinyPool) {
|
|
1358
|
+
if (typeof TinyPool !== 'function') return TinyPool
|
|
1359
|
+
|
|
1360
|
+
const wrappedTinyPool = tinyPoolClassWrappers.get(TinyPool)
|
|
1361
|
+
if (wrappedTinyPool) return wrappedTinyPool
|
|
1362
|
+
|
|
1363
|
+
class DatadogTinyPool extends TinyPool {
|
|
1364
|
+
constructor (options) {
|
|
1365
|
+
markVitestTinypoolOptions(options)
|
|
1366
|
+
super(options)
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
tinyPoolClassWrappers.set(TinyPool, DatadogTinyPool)
|
|
1371
|
+
wrapTinyPoolRun(DatadogTinyPool)
|
|
1372
|
+
|
|
1373
|
+
return DatadogTinyPool
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
function wrapTinyPool (TinyPool) {
|
|
1377
|
+
if (typeof TinyPool === 'function') {
|
|
1378
|
+
return wrapTinyPoolClass(TinyPool)
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
const defaultTinyPool = wrapTinyPoolClass(TinyPool?.default)
|
|
1382
|
+
if (defaultTinyPool) {
|
|
1383
|
+
TinyPool.default = defaultTinyPool
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
const namedTinyPool = TinyPool?.Tinypool === TinyPool?.default
|
|
1387
|
+
? defaultTinyPool
|
|
1388
|
+
: wrapTinyPoolClass(TinyPool?.Tinypool)
|
|
1389
|
+
if (namedTinyPool) {
|
|
1390
|
+
TinyPool.Tinypool = namedTinyPool
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
return TinyPool
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
function getWrappedOn (on) {
|
|
1397
|
+
return function (event, callback) {
|
|
1398
|
+
if (event !== 'message') {
|
|
1399
|
+
return on.apply(this, arguments)
|
|
1400
|
+
}
|
|
1401
|
+
// `arguments[1]` is the callback function, which
|
|
1402
|
+
// we modify to intercept our messages to not interfere
|
|
1403
|
+
// with vitest's own messages
|
|
1404
|
+
arguments[1] = shimmer.wrapFunction(callback, callback => function (message) {
|
|
1405
|
+
if (message.type !== 'Buffer' && Array.isArray(message)) {
|
|
1406
|
+
const [interprocessCode, data] = message
|
|
1407
|
+
if (handleWorkerReport(interprocessCode, data)) {
|
|
1408
|
+
// If we execute the callback vitest crashes, as the message is not supported
|
|
1409
|
+
return
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
return callback.apply(this, arguments)
|
|
1413
|
+
})
|
|
1414
|
+
return on.apply(this, arguments)
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function handleWorkerReport (interprocessCode, data) {
|
|
1419
|
+
if (interprocessCode === VITEST_WORKER_TRACE_PAYLOAD_CODE) {
|
|
1420
|
+
collectTestOptimizationSummariesFromTraces(data, {
|
|
1421
|
+
newTestsWithDynamicNames,
|
|
1422
|
+
attemptToFixExecutions,
|
|
1423
|
+
})
|
|
1424
|
+
workerReportTraceCh.publish(data)
|
|
1425
|
+
return true
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
if (interprocessCode === VITEST_WORKER_LOGS_PAYLOAD_CODE) {
|
|
1429
|
+
workerReportLogsCh.publish(data)
|
|
1430
|
+
return true
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
return false
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
function wrapMessagePortOn () {
|
|
1437
|
+
if (isMessagePortWrapped) return
|
|
1438
|
+
|
|
1439
|
+
isMessagePortWrapped = true
|
|
1440
|
+
shimmer.wrap(MessagePort.prototype, 'on', getWrappedOn)
|
|
1441
|
+
shimmer.wrap(MessagePort.prototype, 'addListener', getWrappedOn)
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
function getStartVitestWrapper (cliApiPackage, frameworkVersion) {
|
|
1445
|
+
if (!isCliApiPackage(cliApiPackage)) {
|
|
1446
|
+
return cliApiPackage
|
|
1447
|
+
}
|
|
1448
|
+
const startVitestExport = findExportByName(cliApiPackage, 'startVitest')
|
|
1449
|
+
shimmer.wrap(cliApiPackage, startVitestExport.key, getCliOrStartVitestWrapper(frameworkVersion))
|
|
1450
|
+
wrapMessagePortOn()
|
|
1451
|
+
|
|
1452
|
+
const vitest = getVitestExport(cliApiPackage)
|
|
1453
|
+
if (vitest) {
|
|
1454
|
+
wrapVitestRunFiles(vitest.value, frameworkVersion)
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
const forksPoolWorker = getForksPoolWorkerExport(cliApiPackage)
|
|
1458
|
+
if (forksPoolWorker) {
|
|
1459
|
+
// function is async
|
|
1460
|
+
shimmer.wrap(forksPoolWorker.value.prototype, 'start', start => function (...args) {
|
|
1461
|
+
vitestPool = 'child_process'
|
|
1462
|
+
this.env = getVitestWorkerEnv(this.env, isVitestNoWorkerInitActive)
|
|
1463
|
+
|
|
1464
|
+
return start.apply(this, args)
|
|
1465
|
+
})
|
|
1466
|
+
shimmer.wrap(forksPoolWorker.value.prototype, 'on', getWrappedOn)
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
const threadsPoolWorker = getThreadsPoolWorkerExport(cliApiPackage)
|
|
1470
|
+
if (threadsPoolWorker) {
|
|
1471
|
+
// function is async
|
|
1472
|
+
shimmer.wrap(threadsPoolWorker.value.prototype, 'start', start => function (...args) {
|
|
1473
|
+
vitestPool = 'worker_threads'
|
|
1474
|
+
this.env = getVitestWorkerEnv(this.env, isVitestNoWorkerInitActive)
|
|
1475
|
+
return start.apply(this, args)
|
|
1476
|
+
})
|
|
1477
|
+
shimmer.wrap(threadsPoolWorker.value.prototype, 'on', getWrappedOn)
|
|
1478
|
+
}
|
|
1479
|
+
return cliApiPackage
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
addHook({
|
|
1483
|
+
name: 'tinypool',
|
|
1484
|
+
// version from tinypool@0.8 was used in vitest@1.6.0
|
|
1485
|
+
versions: ['>=0.8.0'],
|
|
1486
|
+
}, (TinyPool) => {
|
|
1487
|
+
return wrapTinyPool(TinyPool)
|
|
1488
|
+
})
|
|
1489
|
+
|
|
1490
|
+
// There are multiple index* files across different versions of vitest,
|
|
1491
|
+
// so we check for the existence of BaseSequencer to determine if we are in the right file
|
|
1492
|
+
addHook({
|
|
1493
|
+
name: 'vitest',
|
|
1494
|
+
versions: ['>=1.6.0 <2.0.0'],
|
|
1495
|
+
filePattern: 'dist/vendor/index.*',
|
|
1496
|
+
}, (vitestPackage) => {
|
|
1497
|
+
if (isReporterPackage(vitestPackage)) {
|
|
1498
|
+
shimmer.wrap(vitestPackage.B.prototype, 'sort', getSortWrapper)
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
return vitestPackage
|
|
1502
|
+
})
|
|
1503
|
+
|
|
1504
|
+
addHook({
|
|
1505
|
+
name: 'vitest',
|
|
1506
|
+
versions: ['>=2.0.0 <2.0.5'],
|
|
1507
|
+
filePattern: 'dist/vendor/index.*',
|
|
1508
|
+
}, (vitestPackage) => {
|
|
1509
|
+
if (isReporterPackageNew(vitestPackage)) {
|
|
1510
|
+
shimmer.wrap(vitestPackage.e.prototype, 'sort', getSortWrapper)
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
return vitestPackage
|
|
1514
|
+
})
|
|
1515
|
+
|
|
1516
|
+
addHook({
|
|
1517
|
+
name: 'vitest',
|
|
1518
|
+
versions: ['>=2.0.5 <2.1.0'],
|
|
1519
|
+
filePattern: 'dist/chunks/index.*',
|
|
1520
|
+
}, (vitestPackage) => {
|
|
1521
|
+
if (isReporterPackageNewest(vitestPackage)) {
|
|
1522
|
+
shimmer.wrap(vitestPackage.h.prototype, 'sort', getSortWrapper)
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
return vitestPackage
|
|
1526
|
+
})
|
|
1527
|
+
|
|
1528
|
+
addHook({
|
|
1529
|
+
name: 'vitest',
|
|
1530
|
+
versions: ['>=3.2.0 <4.0.0'],
|
|
1531
|
+
filePattern: 'dist/chunks/typechecker.*',
|
|
1532
|
+
}, getTypecheckerWrapper)
|
|
1533
|
+
|
|
1534
|
+
addHook({
|
|
1535
|
+
name: 'vitest',
|
|
1536
|
+
versions: ['>=4.0.0'],
|
|
1537
|
+
filePattern: 'dist/chunks/index.*',
|
|
1538
|
+
}, getTypecheckerWrapper)
|
|
1539
|
+
|
|
1540
|
+
addHook({
|
|
1541
|
+
name: 'vitest',
|
|
1542
|
+
versions: ['>=2.1.0 <3.0.0'],
|
|
1543
|
+
filePattern: 'dist/chunks/RandomSequencer.*',
|
|
1544
|
+
}, (randomSequencerPackage) => {
|
|
1545
|
+
shimmer.wrap(randomSequencerPackage.B.prototype, 'sort', getSortWrapper)
|
|
1546
|
+
return randomSequencerPackage
|
|
1547
|
+
})
|
|
1548
|
+
|
|
1549
|
+
addHook({
|
|
1550
|
+
name: 'vitest',
|
|
1551
|
+
versions: ['>=3.0.9'],
|
|
1552
|
+
filePattern: 'dist/chunks/coverage.*',
|
|
1553
|
+
}, (coveragePackage) => {
|
|
1554
|
+
const baseSequencer = getBaseSequencerExport(coveragePackage)
|
|
1555
|
+
if (baseSequencer) {
|
|
1556
|
+
shimmer.wrap(baseSequencer.value.prototype, 'sort', getSortWrapper)
|
|
1557
|
+
}
|
|
1558
|
+
return coveragePackage
|
|
1559
|
+
})
|
|
1560
|
+
|
|
1561
|
+
addHook({
|
|
1562
|
+
name: 'vitest',
|
|
1563
|
+
versions: ['>=3.0.0 <3.0.9'],
|
|
1564
|
+
filePattern: 'dist/chunks/resolveConfig.*',
|
|
1565
|
+
}, (resolveConfigPackage) => {
|
|
1566
|
+
shimmer.wrap(resolveConfigPackage.B.prototype, 'sort', getSortWrapper)
|
|
1567
|
+
return resolveConfigPackage
|
|
1568
|
+
})
|
|
1569
|
+
|
|
1570
|
+
// Can't specify file because compiled vitest includes hashes in their files
|
|
1571
|
+
// Following 3 wrappers are for test session start
|
|
1572
|
+
addHook({
|
|
1573
|
+
name: 'vitest',
|
|
1574
|
+
versions: ['>=1.6.0 <2.0.5'],
|
|
1575
|
+
filePattern: 'dist/vendor/cac.*',
|
|
1576
|
+
}, getCreateCliWrapper)
|
|
1577
|
+
|
|
1578
|
+
addHook({
|
|
1579
|
+
name: 'vitest',
|
|
1580
|
+
versions: ['>=2.0.5'],
|
|
1581
|
+
filePattern: 'dist/chunks/cac.*',
|
|
1582
|
+
}, getCreateCliWrapper)
|
|
1583
|
+
|
|
1584
|
+
addHook({
|
|
1585
|
+
name: 'vitest',
|
|
1586
|
+
versions: ['>=1.6.0 <2.0.5'],
|
|
1587
|
+
filePattern: 'dist/vendor/cli-api.*',
|
|
1588
|
+
}, getStartVitestWrapper)
|
|
1589
|
+
|
|
1590
|
+
addHook({
|
|
1591
|
+
name: 'vitest',
|
|
1592
|
+
versions: ['>=2.0.5'],
|
|
1593
|
+
filePattern: 'dist/chunks/cli-api.*',
|
|
1594
|
+
}, getStartVitestWrapper)
|