dd-trace 6.17.0 → 6.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +1 -0
- package/ci/vitest-no-worker-init-setup.mjs +22 -12
- package/index.d.ts +55 -11
- package/package.json +6 -6
- package/packages/datadog-instrumentations/src/anthropic.js +111 -9
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +5 -1
- package/packages/datadog-instrumentations/src/cucumber.js +50 -9
- package/packages/datadog-instrumentations/src/cypress-config.js +27 -15
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +6 -0
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -6
- package/packages/datadog-instrumentations/src/helpers/register.js +20 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +41 -4
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +15 -13
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +51 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +13 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +28 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +6 -0
- package/packages/datadog-instrumentations/src/jest/session-error.js +102 -0
- package/packages/datadog-instrumentations/src/jest.js +30 -13
- package/packages/datadog-instrumentations/src/mocha/main.js +7 -5
- package/packages/datadog-instrumentations/src/mocha/utils.js +8 -8
- package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -4
- package/packages/datadog-instrumentations/src/playwright.js +73 -6
- package/packages/datadog-instrumentations/src/undici.js +7 -3
- package/packages/datadog-instrumentations/src/vitest-main.js +95 -21
- package/packages/datadog-instrumentations/src/vitest-worker.js +34 -3
- package/packages/datadog-instrumentations/src/webdriverio.js +28 -12
- package/packages/datadog-instrumentations/src/ws.js +41 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +83 -29
- package/packages/datadog-plugin-cucumber/src/index.js +22 -8
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +51 -14
- package/packages/datadog-plugin-cypress/src/index.js +3 -1
- package/packages/datadog-plugin-fetch/src/index.js +3 -0
- package/packages/datadog-plugin-jest/src/index.js +3 -4
- package/packages/datadog-plugin-mocha/src/index.js +3 -4
- package/packages/datadog-plugin-oracledb/src/connection-parser.js +3 -1
- package/packages/datadog-plugin-playwright/src/index.js +11 -6
- package/packages/datadog-plugin-undici/src/index.js +5 -0
- package/packages/datadog-plugin-vitest/src/index.js +3 -4
- package/packages/datadog-plugin-ws/src/producer.js +1 -1
- package/packages/datadog-shimmer/src/shimmer.js +14 -10
- package/packages/datadog-turbopack/index.js +4 -1
- package/packages/datadog-turbopack/src/loader.js +6 -2
- package/packages/dd-trace/src/agent/info.js +5 -4
- package/packages/dd-trace/src/aiguard/client.js +38 -19
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +29 -4
- package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
- package/packages/dd-trace/src/aiguard/integrations/openai.js +20 -56
- package/packages/dd-trace/src/aiguard/integrations/stream.js +60 -0
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +64 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +19 -19
- package/packages/dd-trace/src/config/index.js +7 -6
- package/packages/dd-trace/src/config/supported-configurations.json +16 -5
- package/packages/dd-trace/src/constants.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +5 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/debugger/index.js +1 -1
- package/packages/dd-trace/src/evp_proxy/constants.js +2 -0
- package/packages/dd-trace/src/evp_proxy/direct.js +17 -13
- package/packages/dd-trace/src/evp_proxy/discovery.js +14 -10
- package/packages/dd-trace/src/evp_proxy/path.js +21 -7
- package/packages/dd-trace/src/exporters/common/url.js +33 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +31 -8
- package/packages/dd-trace/src/llmobs/gen-ai-tags.js +127 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +33 -8
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +77 -41
- package/packages/dd-trace/src/llmobs/plugins/base.js +154 -15
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +162 -10
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +65 -16
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +14 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +34 -35
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +10 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +25 -2
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +8 -7
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +13 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +5 -0
- package/packages/dd-trace/src/llmobs/plugins/vertexai.js +7 -0
- package/packages/dd-trace/src/llmobs/prompts/manager.js +10 -2
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +79 -12
- package/packages/dd-trace/src/llmobs/span_processor.js +10 -65
- package/packages/dd-trace/src/llmobs/tagger.js +11 -40
- package/packages/dd-trace/src/openfeature/configuration_source.js +4 -1
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -3
- package/packages/dd-trace/src/openfeature/index.js +6 -2
- package/packages/dd-trace/src/openfeature/writers/base.js +90 -17
- package/packages/dd-trace/src/openfeature/writers/exposures.js +4 -0
- package/packages/dd-trace/src/openfeature/writers/util.js +104 -33
- package/packages/dd-trace/src/opentelemetry/trace/index.js +5 -0
- package/packages/dd-trace/src/opentracing/tracer.js +3 -3
- package/packages/dd-trace/src/plugin_manager.js +27 -8
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +13 -4
- package/packages/dd-trace/src/profiler.js +51 -5
- package/packages/dd-trace/src/profiling/profiler.js +24 -20
- package/packages/dd-trace/src/proxy.js +2 -2
- package/packages/dd-trace/src/ritm.js +12 -9
- package/packages/dd-trace/src/span_processor.js +6 -1
- package/packages/dd-trace/src/telemetry/send-data.js +2 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/tracer.js +5 -4
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/packages/datadog-instrumentations/src/azure-cosmos.js +0 -7
- package/packages/datadog-instrumentations/src/bullmq.js +0 -11
- package/packages/datadog-instrumentations/src/langchain.js +0 -7
- package/packages/datadog-instrumentations/src/langgraph.js +0 -7
- package/packages/datadog-instrumentations/src/mercurius.js +0 -11
|
@@ -58,6 +58,7 @@ const {
|
|
|
58
58
|
addCoverageBackfillUntestedFiles,
|
|
59
59
|
getCoverageBackfillFiles,
|
|
60
60
|
} = require('./jest/coverage-backfill')
|
|
61
|
+
const { getSessionError } = require('./jest/session-error')
|
|
61
62
|
const {
|
|
62
63
|
getChannelPromise,
|
|
63
64
|
publishWithCompletion,
|
|
@@ -109,6 +110,10 @@ const CHILD_MESSAGE_CALL = 1
|
|
|
109
110
|
const FLUSH_TIMEOUT = FINAL_FLUSH_TIMEOUT + FINAL_FLUSH_FALLBACK_DELAY + 5000
|
|
110
111
|
const JEST_SESSION_STATE = Symbol.for('dd-trace:jest:session')
|
|
111
112
|
const JEST_BAIL_REPORTER_PATH = require.resolve('./jest/bail-reporter')
|
|
113
|
+
const JEST_CIRCUS_TEST_RUNNER_PATH = /(?:^|[\\/])jest-circus(?:[\\/]|$)/
|
|
114
|
+
const UNSUPPORTED_JEST_TEST_RUNNER_WARNING =
|
|
115
|
+
'dd-trace Test Optimization supports jest-circus; another test runner was detected; ' +
|
|
116
|
+
'suite and test events may be incomplete.'
|
|
112
117
|
const DD_JEST_HANDLE_TEST_EVENT_WRAPPED = Symbol('dd-trace:jest:handle-test-event-wrapped')
|
|
113
118
|
const DD_JEST_HANDLE_TEST_EVENT_DATADOG = Symbol('dd-trace:jest:handle-test-event-datadog')
|
|
114
119
|
const DD_JEST_CONCURRENT_TEST_ORIGINAL = Symbol('dd-trace:jest:concurrent-test-original')
|
|
@@ -248,6 +253,7 @@ const MINIMUM_JEST_TEST_SCHEDULER_VERSION = DD_MAJOR >= 6 ? '>=28.0.0' : '>=27.0
|
|
|
248
253
|
const MINIMUM_JEST_COVERAGE_BACKFILL_VERSION = '>=28.0.0'
|
|
249
254
|
const atrSuppressedErrors = new Map()
|
|
250
255
|
let hasWarnedDeprecatedJestVersion = false
|
|
256
|
+
let hasWarnedUnsupportedJestTestRunner = false
|
|
251
257
|
let isJestCoverageBackfillSupported = false
|
|
252
258
|
let hasFinishedTestSession = false
|
|
253
259
|
let jestEachBind
|
|
@@ -322,6 +328,20 @@ function warnDeprecatedJestVersion (frameworkVersion) {
|
|
|
322
328
|
)
|
|
323
329
|
}
|
|
324
330
|
|
|
331
|
+
/** @param {object[]} configs resolved Jest project configurations */
|
|
332
|
+
function warnIfUnsupportedJestTestRunner (configs) {
|
|
333
|
+
if (hasWarnedUnsupportedJestTestRunner || !testSessionConfigurationCh.hasSubscribers) return
|
|
334
|
+
|
|
335
|
+
const usesUnsupportedTestRunner = getEnvironmentVariable('JEST_JASMINE') === '1' ||
|
|
336
|
+
configs.some(config => !JEST_CIRCUS_TEST_RUNNER_PATH.test(config.testRunner))
|
|
337
|
+
|
|
338
|
+
if (usesUnsupportedTestRunner) {
|
|
339
|
+
hasWarnedUnsupportedJestTestRunner = true
|
|
340
|
+
// eslint-disable-next-line no-console
|
|
341
|
+
console.warn(UNSUPPORTED_JEST_TEST_RUNNER_WARNING)
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
325
345
|
function getTestEnvironmentOptions (config) {
|
|
326
346
|
if (config.projectConfig && config.projectConfig.testEnvironmentOptions) { // newer versions
|
|
327
347
|
return config.projectConfig.testEnvironmentOptions
|
|
@@ -2720,13 +2740,6 @@ function applySkippedCoverageToJestCoverageMap (coverageMap, rootDir) {
|
|
|
2720
2740
|
)
|
|
2721
2741
|
}
|
|
2722
2742
|
|
|
2723
|
-
function getSessionFinishError (results) {
|
|
2724
|
-
const numFailedTestSuites = results?.numFailedTestSuites || 0
|
|
2725
|
-
const numFailedTests = results?.numFailedTests || 0
|
|
2726
|
-
|
|
2727
|
-
return new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
|
|
2728
|
-
}
|
|
2729
|
-
|
|
2730
2743
|
function getTestSessionCoveragePayload (results, fallbackRootDir) {
|
|
2731
2744
|
const payload = {}
|
|
2732
2745
|
if (!shouldReportCodeCoverageLinesPct()) return payload
|
|
@@ -2828,7 +2841,7 @@ function getTestSessionFinishPayload (status, error, extra = {}) {
|
|
|
2828
2841
|
async function finishBailTestSession (results, fallbackRootDir) {
|
|
2829
2842
|
await waitForTestSessionFinish(getTestSessionFinishPayload(
|
|
2830
2843
|
'fail',
|
|
2831
|
-
|
|
2844
|
+
getSessionError(results),
|
|
2832
2845
|
getTestSessionCoveragePayload(results, fallbackRootDir)
|
|
2833
2846
|
))
|
|
2834
2847
|
}
|
|
@@ -3151,8 +3164,8 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
3151
3164
|
|
|
3152
3165
|
const {
|
|
3153
3166
|
results: {
|
|
3154
|
-
numFailedTestSuites,
|
|
3155
3167
|
numFailedTests,
|
|
3168
|
+
numPassedTests,
|
|
3156
3169
|
numRuntimeErrorTestSuites = 0,
|
|
3157
3170
|
numTotalTests,
|
|
3158
3171
|
numTotalTestSuites,
|
|
@@ -3323,16 +3336,19 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
3323
3336
|
|
|
3324
3337
|
// Determine session status after EFD and quarantine checks have potentially modified success
|
|
3325
3338
|
let status, error
|
|
3326
|
-
const
|
|
3339
|
+
const hasExecutedTests = numPassedTests > 0 || numFailedTests > 0 || numSuppressedQuarantinedTests > 0
|
|
3340
|
+
const testSessionEmptyReason = result.results.success && !hasExecutedTests
|
|
3341
|
+
? (numTotalTests > 0 || isSuitesSkipped ? 'all_tests_skipped' : 'zero_tests')
|
|
3342
|
+
: undefined
|
|
3327
3343
|
if (result.results.success) {
|
|
3328
|
-
status =
|
|
3344
|
+
status = testSessionEmptyReason ? 'skip' : 'pass'
|
|
3329
3345
|
} else {
|
|
3330
3346
|
status = 'fail'
|
|
3331
|
-
error =
|
|
3347
|
+
error = getSessionError(result.results)
|
|
3332
3348
|
}
|
|
3333
3349
|
|
|
3334
3350
|
await waitForTestSessionFinish(getTestSessionFinishPayload(status, error, {
|
|
3335
|
-
|
|
3351
|
+
testSessionEmptyReason,
|
|
3336
3352
|
...getTestSessionCoveragePayload(result.results, result.globalConfig?.rootDir),
|
|
3337
3353
|
}))
|
|
3338
3354
|
|
|
@@ -3625,6 +3641,7 @@ addHook({
|
|
|
3625
3641
|
}, jestAdapterWrapper)
|
|
3626
3642
|
|
|
3627
3643
|
function configureTestEnvironment (readConfigsResult) {
|
|
3644
|
+
warnIfUnsupportedJestTestRunner(readConfigsResult.configs)
|
|
3628
3645
|
repositoryRoot = getJestRepositoryRoot(readConfigsResult)
|
|
3629
3646
|
isUserCodeCoverageEnabled = !!readConfigsResult.globalConfig.collectCoverage
|
|
3630
3647
|
const isCodeCoverageEnabledBecauseOfUs = shouldCollectJestCoverageForTia() && !isUserCodeCoverageEnabled
|
|
@@ -316,8 +316,8 @@ function getOnEndHandler (isParallel, onDone) {
|
|
|
316
316
|
let status = 'pass'
|
|
317
317
|
let error = frameworkError
|
|
318
318
|
if (this.stats) {
|
|
319
|
-
status = this.stats.failures === 0 ? 'pass' : 'fail'
|
|
320
|
-
if (this.stats.tests ===
|
|
319
|
+
status = this.stats.failures === 0 && this.failures === 0 ? 'pass' : 'fail'
|
|
320
|
+
if (this.stats.tests === this.stats.pending && status === 'pass') {
|
|
321
321
|
status = 'skip'
|
|
322
322
|
}
|
|
323
323
|
} else if (this.failures !== 0) {
|
|
@@ -329,7 +329,9 @@ function getOnEndHandler (isParallel, onDone) {
|
|
|
329
329
|
} else if (status === 'fail') {
|
|
330
330
|
error = new Error(`Failed tests: ${this.failures}.`)
|
|
331
331
|
}
|
|
332
|
-
const
|
|
332
|
+
const testSessionEmptyReason = status === 'skip'
|
|
333
|
+
? (this.stats.pending > 0 || skippedSuites.length > 0 ? 'all_tests_skipped' : 'zero_tests')
|
|
334
|
+
: undefined
|
|
333
335
|
|
|
334
336
|
testFileToSuiteCtx.clear()
|
|
335
337
|
|
|
@@ -373,7 +375,7 @@ function getOnEndHandler (isParallel, onDone) {
|
|
|
373
375
|
isTestManagementEnabled: config.isTestManagementTestsEnabled,
|
|
374
376
|
isParallel,
|
|
375
377
|
isFrameworkError: arguments.length > 0,
|
|
376
|
-
|
|
378
|
+
testSessionEmptyReason,
|
|
377
379
|
}, () => {
|
|
378
380
|
try {
|
|
379
381
|
onDone()
|
|
@@ -1022,7 +1024,7 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
1022
1024
|
config.isSuitesSkippingEnabled = config.isItrEnabled && libraryConfig.isSuitesSkippingEnabled
|
|
1023
1025
|
config.isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
|
|
1024
1026
|
config.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
|
|
1025
|
-
config.isDynamicAtrEnabled = libraryConfig.isDynamicAtrEnabled
|
|
1027
|
+
config.isDynamicAtrEnabled = libraryConfig.isDynamicAtrEnabled && satisfies(frameworkVersion, '>=8.0.0')
|
|
1026
1028
|
config.dynamicAtrBuckets = libraryConfig.dynamicAtrBuckets
|
|
1027
1029
|
config.isDiEnabled = libraryConfig.isDiEnabled
|
|
1028
1030
|
config.isTestDynamicInstrumentationEnabled = isTestDynamicInstrumentationEnabled
|
|
@@ -54,7 +54,7 @@ const testsQuarantined = new Set()
|
|
|
54
54
|
const testsStatuses = new Map()
|
|
55
55
|
const efdRetryCountByTestFullName = new Map()
|
|
56
56
|
const efdSlowAbortedTests = new Set()
|
|
57
|
-
|
|
57
|
+
let dynamicAtrRetryCountByTest = new WeakMap()
|
|
58
58
|
const attemptToFixExecutions = new Map()
|
|
59
59
|
const isMochaWorker = !!getEnvironmentVariable('MOCHA_WORKER_ID')
|
|
60
60
|
|
|
@@ -343,7 +343,7 @@ function resetRunState (rootSuite) {
|
|
|
343
343
|
testsStatuses.clear()
|
|
344
344
|
efdRetryCountByTestFullName.clear()
|
|
345
345
|
efdSlowAbortedTests.clear()
|
|
346
|
-
|
|
346
|
+
dynamicAtrRetryCountByTest = new WeakMap()
|
|
347
347
|
attemptToFixExecutions.clear()
|
|
348
348
|
loggedAttemptToFixTests.clear()
|
|
349
349
|
|
|
@@ -538,8 +538,7 @@ function runnableWrapper (RunnablePackage, libraryConfig) {
|
|
|
538
538
|
if (libraryConfig.isDynamicAtrEnabled) {
|
|
539
539
|
// Dynamic ATR: set the max possible retries initially.
|
|
540
540
|
// The actual duration-based count is computed after the first attempt.
|
|
541
|
-
const
|
|
542
|
-
const dynamicCount = dynamicAtrRetryCountByTestFullName.get(testName)
|
|
541
|
+
const dynamicCount = dynamicAtrRetryCountByTest.get(test._retriedTest || test)
|
|
543
542
|
if (dynamicCount === undefined) {
|
|
544
543
|
const maxRetries = libraryConfig.dynamicAtrBuckets
|
|
545
544
|
? Math.max(...libraryConfig.dynamicAtrBuckets)
|
|
@@ -723,12 +722,14 @@ function getTestFinishInfo (test, status, config, error) {
|
|
|
723
722
|
}
|
|
724
723
|
|
|
725
724
|
// Dynamic ATR: after the first attempt, compute the duration-based retry budget.
|
|
725
|
+
// Mocha's native retry clones point to the original test, independently of duplicate titles.
|
|
726
|
+
const originalTest = test._retriedTest || test
|
|
726
727
|
if (
|
|
727
728
|
config.isDynamicAtrEnabled &&
|
|
728
729
|
config.isFlakyTestRetriesEnabled &&
|
|
729
730
|
!test._ddIsAttemptToFix &&
|
|
730
731
|
!test._ddIsEfdRetry &&
|
|
731
|
-
!
|
|
732
|
+
!dynamicAtrRetryCountByTest.has(originalTest) &&
|
|
732
733
|
test._currentRetry === 0
|
|
733
734
|
) {
|
|
734
735
|
const duration = test.duration > 0 ? test.duration : performance.now() - test._ddStartTime
|
|
@@ -737,7 +738,7 @@ function getTestFinishInfo (test, status, config, error) {
|
|
|
737
738
|
config.earlyFlakeDetectionRetryPolicy,
|
|
738
739
|
config.dynamicAtrBuckets
|
|
739
740
|
)
|
|
740
|
-
|
|
741
|
+
dynamicAtrRetryCountByTest.set(originalTest, dynamicCount)
|
|
741
742
|
}
|
|
742
743
|
|
|
743
744
|
if (testsStatuses.get(testName)) {
|
|
@@ -1094,13 +1095,12 @@ function getOnTestRetryHandler (config) {
|
|
|
1094
1095
|
!test._ddIsAttemptToFix &&
|
|
1095
1096
|
!isEarlyFlakeDetectionTest(test, config)
|
|
1096
1097
|
if (isDynamicAtrTest && isFirstAttempt) {
|
|
1097
|
-
const testName = getTestFullName(test)
|
|
1098
1098
|
const dynamicCount = getDynamicAtrRetryCount(
|
|
1099
1099
|
test.duration > 0 ? test.duration : performance.now() - test._ddStartTime,
|
|
1100
1100
|
config.earlyFlakeDetectionRetryPolicy,
|
|
1101
1101
|
config.dynamicAtrBuckets
|
|
1102
1102
|
)
|
|
1103
|
-
|
|
1103
|
+
dynamicAtrRetryCountByTest.set(test._retriedTest || test, dynamicCount)
|
|
1104
1104
|
// Mocha emits retry before its next attempt starts; narrow its ceiling here.
|
|
1105
1105
|
test._retries = dynamicCount
|
|
1106
1106
|
}
|
|
@@ -206,16 +206,15 @@ class DatadogPlaywrightReporter {
|
|
|
206
206
|
onExit () {}
|
|
207
207
|
|
|
208
208
|
/**
|
|
209
|
-
* Reports errors
|
|
209
|
+
* Reports global run errors as well as errors from later reporters during finalization.
|
|
210
210
|
*
|
|
211
211
|
* @param {unknown} error
|
|
212
212
|
*/
|
|
213
213
|
onError (error) {
|
|
214
|
-
if (this.isFinalizing) {
|
|
215
|
-
reporterErrorCh.publish(error)
|
|
216
|
-
} else {
|
|
214
|
+
if (!this.isFinalizing) {
|
|
217
215
|
this.fatalErrorCount += 1
|
|
218
216
|
}
|
|
217
|
+
reporterErrorCh.publish(error)
|
|
219
218
|
}
|
|
220
219
|
|
|
221
220
|
/**
|
|
@@ -69,13 +69,16 @@ const dispatcherCreateWorkerCh = tracingChannel('orchestrion:playwright:Dispatch
|
|
|
69
69
|
const filterForShardCh = tracingChannel('orchestrion:playwright:filterForShard')
|
|
70
70
|
const processHostStartRunnerCh = tracingChannel('orchestrion:playwright:ProcessHost_startRunner')
|
|
71
71
|
const createRootSuiteCh = tracingChannel('orchestrion:playwright:createRootSuite')
|
|
72
|
+
const lastRunTestIdCh = tracingChannel('orchestrion:playwright:lastRunTestId')
|
|
72
73
|
const artifactsRecorderScreenshotPathCh =
|
|
73
74
|
tracingChannel('orchestrion:playwright:ArtifactsRecorder_createScreenshotAttachmentPath')
|
|
74
75
|
const snapshotRecorderScreenshotPathCh = tracingChannel('orchestrion:playwright:SnapshotRecorder_createAttachmentPath')
|
|
75
76
|
const saveAutomaticVideoCh = tracingChannel('orchestrion:playwright:saveAutomaticVideo')
|
|
76
77
|
const pageGotoCh = tracingChannel('orchestrion:playwright-core:Page_goto')
|
|
78
|
+
const fullProjectInternalCh = tracingChannel('orchestrion:playwright:FullProjectInternal')
|
|
77
79
|
|
|
78
80
|
const testToCtx = new WeakMap()
|
|
81
|
+
const originalTestIdsByRetry = new WeakMap()
|
|
79
82
|
const testSuiteToCtx = new Map()
|
|
80
83
|
const testSuiteToTestStatuses = new Map()
|
|
81
84
|
const testSuiteToErrors = new Map()
|
|
@@ -89,6 +92,8 @@ const isFailureScreenshotUploadEnabled =
|
|
|
89
92
|
getValueFromEnvSources('DD_TEST_FAILURE_SCREENSHOTS_ENABLED') === true
|
|
90
93
|
const isFailureVideoUploadEnabled =
|
|
91
94
|
getValueFromEnvSources('DD_TEST_FAILURE_VIDEOS_ENABLED') === true
|
|
95
|
+
const shouldEnableFailureScreenshots = getValueFromEnvSources('DD_TEST_FAILURE_SCREENSHOTS_ENABLED', true) === true
|
|
96
|
+
const shouldEnableFailureVideos = getValueFromEnvSources('DD_TEST_FAILURE_VIDEOS_ENABLED', true) === true
|
|
92
97
|
|
|
93
98
|
let applyRepeatEachIndex = null
|
|
94
99
|
let reporterError
|
|
@@ -475,6 +480,7 @@ function deepCloneSuite (suite, filterTest, tags = [], configureCopiedTest) {
|
|
|
475
480
|
} else {
|
|
476
481
|
if (filterTest(entry)) {
|
|
477
482
|
const copiedTest = entry._clone()
|
|
483
|
+
originalTestIdsByRetry.set(copiedTest, originalTestIdsByRetry.get(entry) ?? entry.id)
|
|
478
484
|
if (configureCopiedTest) {
|
|
479
485
|
configureCopiedTest(copiedTest, entry)
|
|
480
486
|
}
|
|
@@ -915,6 +921,7 @@ function testEndHandler ({
|
|
|
915
921
|
testDuration,
|
|
916
922
|
testResultStatus,
|
|
917
923
|
expectedStatus = test.expectedStatus,
|
|
924
|
+
hasNonRetriableError,
|
|
918
925
|
}) {
|
|
919
926
|
const {
|
|
920
927
|
_requireFile: testSuiteAbsolutePath,
|
|
@@ -1053,6 +1060,8 @@ function testEndHandler ({
|
|
|
1053
1060
|
if (isFlakyTestRetriesEnabled && !testProperties.attemptToFix && !test._ddIsEfdRetry &&
|
|
1054
1061
|
!(test._ddIsNew || test._ddIsModified) &&
|
|
1055
1062
|
atrRetryCount != null && atrRetryCount > 0 &&
|
|
1063
|
+
// Serial suites can add skipped results before a test's first execution.
|
|
1064
|
+
results.some((result, index) => index < results.length - 1 && result.status !== 'skipped') &&
|
|
1056
1065
|
!willRetry && testResultStatus !== expectedStatus &&
|
|
1057
1066
|
testStatuses.every(status => status === 'fail')) {
|
|
1058
1067
|
test._ddHasFailedAllRetries = true
|
|
@@ -1087,6 +1096,8 @@ function testEndHandler ({
|
|
|
1087
1096
|
if (testCtx) {
|
|
1088
1097
|
testFinishCh.publish({
|
|
1089
1098
|
testStatus,
|
|
1099
|
+
isExpectedFailure: testResultStatus === 'failed' && expectedStatus === 'failed',
|
|
1100
|
+
hasNonRetriableError,
|
|
1090
1101
|
steps: testResult?.steps || [],
|
|
1091
1102
|
isRetry: testResult?.retry > 0,
|
|
1092
1103
|
error,
|
|
@@ -1278,7 +1289,7 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
1278
1289
|
videos.push(attachment)
|
|
1279
1290
|
}
|
|
1280
1291
|
})
|
|
1281
|
-
worker.on('testEnd', ({ testId, status, errors, annotations, duration, expectedStatus }) => {
|
|
1292
|
+
worker.on('testEnd', ({ testId, status, errors, annotations, duration, expectedStatus, hasNonRetriableError }) => {
|
|
1282
1293
|
const test = getTestByTestId(dispatcher, testId)
|
|
1283
1294
|
if (!test) return
|
|
1284
1295
|
|
|
@@ -1300,6 +1311,7 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
1300
1311
|
testDuration: duration,
|
|
1301
1312
|
testResultStatus: status,
|
|
1302
1313
|
expectedStatus,
|
|
1314
|
+
hasNonRetriableError,
|
|
1303
1315
|
}
|
|
1304
1316
|
)
|
|
1305
1317
|
const testResult = test.results.at(-1)
|
|
@@ -1406,6 +1418,8 @@ function dispatcherHook (dispatcherExport) {
|
|
|
1406
1418
|
annotations: params.annotations,
|
|
1407
1419
|
testStatus: STATUS_TO_TEST_STATUS[testResult.status],
|
|
1408
1420
|
testResultStatus: testResult.status,
|
|
1421
|
+
expectedStatus: params.expectedStatus,
|
|
1422
|
+
hasNonRetriableError: params.hasNonRetriableError,
|
|
1409
1423
|
error: testResult.error,
|
|
1410
1424
|
isTimeout,
|
|
1411
1425
|
shouldCreateTestSpan: true,
|
|
@@ -1431,7 +1445,7 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
|
|
|
1431
1445
|
|
|
1432
1446
|
function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
1433
1447
|
// Config parameter is only available from >=1.55.0
|
|
1434
|
-
return async function (config) {
|
|
1448
|
+
return async function (config, options) {
|
|
1435
1449
|
// A later run must not inherit ATR settings when configuration fails or the plugin is disabled.
|
|
1436
1450
|
isFlakyTestRetriesEnabled = false
|
|
1437
1451
|
flakyTestRetriesCount = 0
|
|
@@ -1682,14 +1696,30 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1682
1696
|
const finalStatus = hasReporterError
|
|
1683
1697
|
? 'fail'
|
|
1684
1698
|
: (preventedToFail ? 'pass' : STATUS_TO_TEST_STATUS[sessionStatus])
|
|
1685
|
-
const
|
|
1686
|
-
Boolean(
|
|
1699
|
+
const isTestDiscovery = finalStatus === 'pass' &&
|
|
1700
|
+
Boolean(
|
|
1701
|
+
config?.listOnly ||
|
|
1702
|
+
config?.cliListOnly ||
|
|
1703
|
+
runnerConfig.cliListOnly ||
|
|
1704
|
+
runnerConfig._internal?.listOnly ||
|
|
1705
|
+
options?.listMode
|
|
1706
|
+
)
|
|
1707
|
+
const isEmptyShard = Boolean(playwrightConfig.shard) &&
|
|
1687
1708
|
hasTestsBeforeSharding &&
|
|
1688
1709
|
!hasTestsAssignedToShard &&
|
|
1689
1710
|
testsReportedInGenerateSummary.size === 0
|
|
1711
|
+
const hasExecutedTests = [...testsToTestStatuses.values()].some(statuses =>
|
|
1712
|
+
statuses.some(status => status !== 'skip')
|
|
1713
|
+
)
|
|
1714
|
+
const hasSkippedTests = testsToTestStatuses.size > 0 || testsReportedInGenerateSummary.size > 0
|
|
1715
|
+
const testSessionEmptyReason = finalStatus === 'pass' && !hasExecutedTests
|
|
1716
|
+
? (isTestDiscovery
|
|
1717
|
+
? 'test_discovery'
|
|
1718
|
+
: isEmptyShard ? 'zero_test_shard' : hasSkippedTests ? 'all_tests_skipped' : 'zero_tests')
|
|
1719
|
+
: undefined
|
|
1690
1720
|
await getChannelPromise(testSessionFinishCh, {
|
|
1691
|
-
status:
|
|
1692
|
-
|
|
1721
|
+
status: testSessionEmptyReason ? 'skip' : finalStatus,
|
|
1722
|
+
testSessionEmptyReason,
|
|
1693
1723
|
error: finalizationError,
|
|
1694
1724
|
isEarlyFlakeDetectionEnabled,
|
|
1695
1725
|
isEarlyFlakeDetectionFaulty,
|
|
@@ -1857,6 +1887,27 @@ dispatcherRunCh.subscribe({
|
|
|
1857
1887
|
},
|
|
1858
1888
|
})
|
|
1859
1889
|
|
|
1890
|
+
fullProjectInternalCh.subscribe({
|
|
1891
|
+
end ({ self, error }) {
|
|
1892
|
+
if (error || !libraryConfigurationCh.hasSubscribers) return
|
|
1893
|
+
|
|
1894
|
+
// Workers reload the config, so apply capture settings as each project is resolved in either process.
|
|
1895
|
+
const { project } = self
|
|
1896
|
+
if (shouldEnableFailureScreenshots && !isFailureScreenshotCaptureEnabled([project])) {
|
|
1897
|
+
const screenshot = project.use.screenshot
|
|
1898
|
+
project.use.screenshot = typeof screenshot === 'object' && screenshot !== null
|
|
1899
|
+
? { ...screenshot, mode: 'only-on-failure' }
|
|
1900
|
+
: 'only-on-failure'
|
|
1901
|
+
}
|
|
1902
|
+
if (shouldEnableFailureVideos && !isFailureVideoCaptureEnabled([project])) {
|
|
1903
|
+
const video = project.use.video
|
|
1904
|
+
project.use.video = typeof video === 'object' && video !== null
|
|
1905
|
+
? { ...video, mode: 'retain-on-failure' }
|
|
1906
|
+
: 'retain-on-failure'
|
|
1907
|
+
}
|
|
1908
|
+
},
|
|
1909
|
+
})
|
|
1910
|
+
|
|
1860
1911
|
dispatcherCreateWorkerCh.subscribe({
|
|
1861
1912
|
end (ctx) {
|
|
1862
1913
|
onDispatcherCreateWorker(ctx.self, ctx.result)
|
|
@@ -1898,6 +1949,14 @@ pageGotoCh.subscribe({
|
|
|
1898
1949
|
},
|
|
1899
1950
|
})
|
|
1900
1951
|
|
|
1952
|
+
// Retry clones exist only after discovery, so persist their original IDs for --last-failed.
|
|
1953
|
+
lastRunTestIdCh.subscribe({
|
|
1954
|
+
end (ctx) {
|
|
1955
|
+
const originalId = originalTestIdsByRetry.get(ctx.arguments[0])
|
|
1956
|
+
if (originalId !== undefined) ctx.result = originalId
|
|
1957
|
+
},
|
|
1958
|
+
})
|
|
1959
|
+
|
|
1901
1960
|
reporterErrorCh.subscribe((error) => {
|
|
1902
1961
|
recordReporterError(error)
|
|
1903
1962
|
})
|
|
@@ -1968,6 +2027,12 @@ snapshotRecorderScreenshotPathCh.subscribe({ end: recordAutomaticFailureScreensh
|
|
|
1968
2027
|
saveAutomaticVideoCh.subscribe({ start: recordAutomaticFailureVideoPath })
|
|
1969
2028
|
|
|
1970
2029
|
if (DD_MAJOR < 6) { // <1.38.0 is only supported up to version 5
|
|
2030
|
+
tracingChannel('orchestrion:@playwright/test:Multiplexer_onError').subscribe({
|
|
2031
|
+
start (ctx) {
|
|
2032
|
+
recordReporterError(ctx.arguments[0])
|
|
2033
|
+
},
|
|
2034
|
+
})
|
|
2035
|
+
|
|
1971
2036
|
addHook({
|
|
1972
2037
|
name: '@playwright/test',
|
|
1973
2038
|
file: 'lib/runner.js',
|
|
@@ -2656,6 +2721,8 @@ function instrumentWorkerMainMethods (workerMain) {
|
|
|
2656
2721
|
|
|
2657
2722
|
await getChannelPromise(testFinishCh, {
|
|
2658
2723
|
testStatus: STATUS_TO_TEST_STATUS[status],
|
|
2724
|
+
isExpectedFailure: status === 'failed' && testInfo.expectedStatus === 'failed',
|
|
2725
|
+
hasNonRetriableError: testInfo._hasNonRetriableError,
|
|
2659
2726
|
retryTestId,
|
|
2660
2727
|
deferFinalStatus: test._ddDeferFinalStatus,
|
|
2661
2728
|
steps: steps.filter(step => step.testId === testId),
|
|
@@ -45,9 +45,13 @@ function wrapRequestUpgrade (Request) {
|
|
|
45
45
|
const method = Request.prototype[methodName]
|
|
46
46
|
|
|
47
47
|
// Orchestrion cannot leave fixed source byte-for-byte untouched after a conditional AST match.
|
|
48
|
-
if (typeof method !== 'function' ||
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
if (typeof method !== 'function' || !requestSource.includes('channels.trailers.publish')) {
|
|
49
|
+
return Request
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const methodSource = Function.prototype.toString.call(method)
|
|
53
|
+
// Undici 6.29 delegates native upgrade completion to a private helper.
|
|
54
|
+
if (methodSource.includes('channels.trailers.publish') || methodSource.includes('#publishUpgradeTrailers')) {
|
|
51
55
|
return Request
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -65,6 +65,9 @@ const workerProcesses = new WeakSet()
|
|
|
65
65
|
const mainProcessSetupStates = new WeakMap()
|
|
66
66
|
const coverageWrappedProviders = new WeakSet()
|
|
67
67
|
const finishWrappedContexts = new WeakSet()
|
|
68
|
+
const finishedSessionContexts = new WeakSet()
|
|
69
|
+
const sessionWrappedPrototypes = new WeakSet()
|
|
70
|
+
const emptyShardContexts = new WeakSet()
|
|
68
71
|
const runFilesWrappedPrototypes = new WeakSet()
|
|
69
72
|
const activeRunFilesContexts = new WeakSet()
|
|
70
73
|
const runErrorsByContext = new WeakMap()
|
|
@@ -163,16 +166,6 @@ function getThreadsPoolWorkerExport (vitestPackage) {
|
|
|
163
166
|
return findExportByName(vitestPackage, 'ThreadsPoolWorker')
|
|
164
167
|
}
|
|
165
168
|
|
|
166
|
-
function getSessionStatus (state) {
|
|
167
|
-
if (state.getCountOfFailedTests() > 0) {
|
|
168
|
-
return 'fail'
|
|
169
|
-
}
|
|
170
|
-
if (state.pathsSet.size === 0) {
|
|
171
|
-
return 'skip'
|
|
172
|
-
}
|
|
173
|
-
return 'pass'
|
|
174
|
-
}
|
|
175
|
-
|
|
176
169
|
function getTestFilepathsFromSpecifications (testSpecifications) {
|
|
177
170
|
if (!Array.isArray(testSpecifications) || !testSpecifications.length) {
|
|
178
171
|
return
|
|
@@ -1194,6 +1187,9 @@ function safeWorkspaceProject (ctx) {
|
|
|
1194
1187
|
|
|
1195
1188
|
function getSortWrapper (sort, frameworkVersion) {
|
|
1196
1189
|
return async function () {
|
|
1190
|
+
if (this.ctx.config.shard && this.ctx.state.pathsSet.size > 0 && arguments[0].length === 0) {
|
|
1191
|
+
emptyShardContexts.add(this.ctx)
|
|
1192
|
+
}
|
|
1197
1193
|
if (!activeRunFilesContexts.has(this.ctx)) {
|
|
1198
1194
|
const testSpecifications = arguments[0]
|
|
1199
1195
|
await ensureMainProcessSetup(this.ctx, frameworkVersion, testSpecifications)
|
|
@@ -1204,18 +1200,18 @@ function getSortWrapper (sort, frameworkVersion) {
|
|
|
1204
1200
|
}
|
|
1205
1201
|
|
|
1206
1202
|
function getFinishWrapper (exitOrClose) {
|
|
1207
|
-
let isClosed = false
|
|
1208
1203
|
return async function () {
|
|
1209
|
-
if (
|
|
1204
|
+
if (finishedSessionContexts.has(this)) {
|
|
1210
1205
|
return exitOrClose.apply(this, arguments)
|
|
1211
1206
|
}
|
|
1212
|
-
isClosed = true
|
|
1213
1207
|
|
|
1214
1208
|
if (!testSessionFinishCh.hasSubscribers) {
|
|
1215
1209
|
return exitOrClose.apply(this, arguments)
|
|
1216
1210
|
}
|
|
1211
|
+
finishedSessionContexts.add(this)
|
|
1217
1212
|
|
|
1218
1213
|
const failedSuites = this.state.getFailedFilepaths()
|
|
1214
|
+
const hasRunError = runErrorsByContext.has(this)
|
|
1219
1215
|
const runError = runErrorsByContext.get(this)
|
|
1220
1216
|
runErrorsByContext.delete(this)
|
|
1221
1217
|
let error = runError
|
|
@@ -1223,19 +1219,30 @@ function getFinishWrapper (exitOrClose) {
|
|
|
1223
1219
|
error = new Error(`Test suites failed: ${failedSuites.length}.`)
|
|
1224
1220
|
}
|
|
1225
1221
|
|
|
1222
|
+
// pathsSet contains candidates before sharding, including files that never run.
|
|
1226
1223
|
const hasNoTestFiles = this.state.pathsSet.size === 0
|
|
1227
|
-
const
|
|
1224
|
+
const isEmptyShard = emptyShardContexts.has(this)
|
|
1225
|
+
const hasUnexpectedEmptySession = hasNoTestFiles && !isEmptyShard &&
|
|
1226
|
+
!areAllSuitesSkipped && !this.config.passWithNoTests
|
|
1228
1227
|
if (!error && hasUnexpectedEmptySession) {
|
|
1229
1228
|
error = new Error('No test files were found.')
|
|
1230
1229
|
}
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1230
|
+
const tests = getTypeTasks(this.state.getFiles())
|
|
1231
|
+
const hasExecutedTests = tests.some(test =>
|
|
1232
|
+
test.mode !== 'skip' && test.mode !== 'todo' &&
|
|
1233
|
+
test.result?.state !== 'skip' && test.result?.state !== 'todo'
|
|
1234
|
+
)
|
|
1235
|
+
const hasErrors = hasRunError || error ||
|
|
1236
|
+
this.state.getCountOfFailedTests() > 0 || this.state.getUnhandledErrors().length > 0
|
|
1237
|
+
const testSessionEmptyReason = !hasErrors && !hasExecutedTests
|
|
1238
|
+
? (isEmptyShard
|
|
1239
|
+
? 'zero_test_shard'
|
|
1240
|
+
: tests.length > 0 || skippedSuites.length > 0 ? 'all_tests_skipped' : 'zero_tests')
|
|
1241
|
+
: undefined
|
|
1242
|
+
const status = hasErrors ? 'fail' : (testSessionEmptyReason ? 'skip' : 'pass')
|
|
1236
1243
|
const flushPromise = getChannelPromise(testSessionFinishCh, {
|
|
1237
1244
|
status,
|
|
1238
|
-
|
|
1245
|
+
testSessionEmptyReason,
|
|
1239
1246
|
testCodeCoverageLinesTotal,
|
|
1240
1247
|
error,
|
|
1241
1248
|
isEarlyFlakeDetectionEnabled,
|
|
@@ -1391,12 +1398,46 @@ function markVitestWorkerEnv (ctx, testSpecifications, shouldSkipWorkerInit = fa
|
|
|
1391
1398
|
config.env = getVitestWorkerEnv(config.env, shouldSkipWorkerInit)
|
|
1392
1399
|
}
|
|
1393
1400
|
|
|
1401
|
+
/**
|
|
1402
|
+
* Installs completion hooks before discovery, which can bypass runFiles entirely.
|
|
1403
|
+
* @param {Function} Vitest
|
|
1404
|
+
*/
|
|
1405
|
+
function wrapVitestSession (Vitest) {
|
|
1406
|
+
if (!Vitest?.prototype?.start || sessionWrappedPrototypes.has(Vitest.prototype)) return
|
|
1407
|
+
sessionWrappedPrototypes.add(Vitest.prototype)
|
|
1408
|
+
|
|
1409
|
+
// Empty discovery bypasses runFiles. Vitest 1 exits directly after reporting coverage,
|
|
1410
|
+
// so its finalization must be awaited before that process.exit rather than only in close.
|
|
1411
|
+
// Hashed bundle names prevent Orchestrion's exact-file matching.
|
|
1412
|
+
shimmer.wrap(Vitest.prototype, 'start', start => function () {
|
|
1413
|
+
if (!testSessionFinishCh.hasSubscribers) return start.apply(this, arguments)
|
|
1414
|
+
wrapSessionFinish(this)
|
|
1415
|
+
return start.apply(this, arguments).then(undefined, error => {
|
|
1416
|
+
if (error?.code !== 'VITEST_FILES_NOT_FOUND') runErrorsByContext.set(this, error)
|
|
1417
|
+
throw error
|
|
1418
|
+
})
|
|
1419
|
+
})
|
|
1420
|
+
shimmer.wrap(Vitest.prototype, 'reportCoverage', reportCoverage => function () {
|
|
1421
|
+
const result = reportCoverage.apply(this, arguments)
|
|
1422
|
+
if (!testSessionFinishCh.hasSubscribers || !isSessionStarted || this.config.watch ||
|
|
1423
|
+
mainProcessSetupStates.has(this) || this.state.pathsSet.size > 0) {
|
|
1424
|
+
return result
|
|
1425
|
+
}
|
|
1426
|
+
return result.then(value => {
|
|
1427
|
+
const finish = getFinishWrapper(() => value)
|
|
1428
|
+
return finish.call(this)
|
|
1429
|
+
})
|
|
1430
|
+
})
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1394
1433
|
function wrapVitestRunFiles (Vitest, frameworkVersion) {
|
|
1395
1434
|
if (!Vitest?.prototype?.runFiles || runFilesWrappedPrototypes.has(Vitest.prototype)) {
|
|
1396
1435
|
return
|
|
1397
1436
|
}
|
|
1398
1437
|
runFilesWrappedPrototypes.add(Vitest.prototype)
|
|
1399
1438
|
|
|
1439
|
+
wrapVitestSession(Vitest)
|
|
1440
|
+
|
|
1400
1441
|
shimmer.wrap(Vitest.prototype, 'runFiles', runFiles => async function (testSpecifications) {
|
|
1401
1442
|
if (activeRunFilesContexts.has(this)) {
|
|
1402
1443
|
return runFiles.apply(this, arguments)
|
|
@@ -1940,6 +1981,9 @@ function getWrappedOn (on) {
|
|
|
1940
1981
|
if (event !== 'message') {
|
|
1941
1982
|
return on.apply(this, arguments)
|
|
1942
1983
|
}
|
|
1984
|
+
// Reply through Vitest's pool worker, which owns its version-specific serialization.
|
|
1985
|
+
// The listener's `this` is the underlying ChildProcess or Worker instead.
|
|
1986
|
+
const worker = this
|
|
1943
1987
|
// `arguments[1]` is the callback function, which
|
|
1944
1988
|
// we modify to intercept our messages to not interfere
|
|
1945
1989
|
// with vitest's own messages
|
|
@@ -1947,7 +1991,7 @@ function getWrappedOn (on) {
|
|
|
1947
1991
|
if (message.type !== 'Buffer' && Array.isArray(message)) {
|
|
1948
1992
|
const [interprocessCode, data] = message
|
|
1949
1993
|
if (
|
|
1950
|
-
handleEfdAdmissionMessage(
|
|
1994
|
+
handleEfdAdmissionMessage(worker, interprocessCode, data) ||
|
|
1951
1995
|
handleWorkerReport(interprocessCode, data)
|
|
1952
1996
|
) {
|
|
1953
1997
|
// If we execute the callback vitest crashes, as the message is not supported
|
|
@@ -2080,6 +2124,36 @@ addHook({
|
|
|
2080
2124
|
return wrapTinyPool(TinyPool)
|
|
2081
2125
|
})
|
|
2082
2126
|
|
|
2127
|
+
/**
|
|
2128
|
+
* Older Vitest versions expose their core instance through the logger constructor.
|
|
2129
|
+
* @param {Record<string, Function>} vitestPackage
|
|
2130
|
+
*/
|
|
2131
|
+
function wrapVitestLogger (vitestPackage) {
|
|
2132
|
+
const logger = findExportByName(vitestPackage, 'Logger')
|
|
2133
|
+
if (logger) {
|
|
2134
|
+
// Hashed bundle names prevent Orchestrion's exact-file matching.
|
|
2135
|
+
shimmer.wrap(vitestPackage, logger.key, Logger => class extends Logger {
|
|
2136
|
+
constructor (...args) {
|
|
2137
|
+
super(...args)
|
|
2138
|
+
if (testSessionFinishCh.hasSubscribers) wrapVitestSession(args[0]?.constructor)
|
|
2139
|
+
}
|
|
2140
|
+
})
|
|
2141
|
+
}
|
|
2142
|
+
return vitestPackage
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
addHook({
|
|
2146
|
+
name: 'vitest',
|
|
2147
|
+
versions: ['>=1.6.0 <2.0.5'],
|
|
2148
|
+
filePattern: 'dist/vendor/index.*',
|
|
2149
|
+
}, wrapVitestLogger)
|
|
2150
|
+
|
|
2151
|
+
addHook({
|
|
2152
|
+
name: 'vitest',
|
|
2153
|
+
versions: ['>=2.0.5 <3.0.0'],
|
|
2154
|
+
filePattern: 'dist/chunks/index.*',
|
|
2155
|
+
}, wrapVitestLogger)
|
|
2156
|
+
|
|
2083
2157
|
// There are multiple index* files across different versions of vitest,
|
|
2084
2158
|
// so we check for the existence of BaseSequencer to determine if we are in the right file
|
|
2085
2159
|
addHook({
|