dd-trace 6.10.0 → 6.12.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 +5 -0
- package/README.md +0 -17
- package/index.d.ts +128 -6
- package/initialize.mjs +28 -17
- package/openfeature.js +2 -2
- package/package.json +27 -23
- package/packages/datadog-esbuild/index.js +0 -34
- package/packages/datadog-instrumentations/src/anthropic.js +210 -15
- package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
- package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
- package/packages/datadog-instrumentations/src/bunyan.js +3 -16
- package/packages/datadog-instrumentations/src/cucumber.js +30 -15
- package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
- package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
- package/packages/datadog-instrumentations/src/cypress.js +2 -0
- package/packages/datadog-instrumentations/src/fastify.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
- package/packages/datadog-instrumentations/src/jest.js +25 -17
- package/packages/datadog-instrumentations/src/mariadb.js +278 -21
- package/packages/datadog-instrumentations/src/mocha/main.js +539 -55
- package/packages/datadog-instrumentations/src/mocha/utils.js +135 -19
- package/packages/datadog-instrumentations/src/playwright-reporter.js +247 -0
- package/packages/datadog-instrumentations/src/playwright.js +182 -35
- package/packages/datadog-instrumentations/src/router.js +2 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +6 -8
- package/packages/datadog-instrumentations/src/vitest-main.js +11 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -8
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
- package/packages/datadog-plugin-bunyan/src/index.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +11 -0
- package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
- package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +81 -29
- package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
- package/packages/datadog-plugin-cypress/src/index.js +12 -6
- package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
- package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
- package/packages/datadog-plugin-electron/src/index.js +2 -0
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +6 -0
- package/packages/datadog-plugin-mocha/src/index.js +56 -1
- package/packages/datadog-plugin-nats/src/index.js +1 -1
- package/packages/datadog-plugin-openai/src/tracing.js +41 -30
- package/packages/datadog-plugin-openai-agents/src/integration.js +1 -0
- package/packages/datadog-plugin-playwright/src/index.js +46 -13
- package/packages/datadog-plugin-vitest/src/index.js +6 -0
- package/packages/datadog-webpack/index.js +0 -11
- package/packages/dd-trace/index.js +0 -1
- package/packages/dd-trace/src/agent/info.js +6 -5
- package/packages/dd-trace/src/aiguard/client.js +100 -1
- package/packages/dd-trace/src/aiguard/errors.js +41 -0
- package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
- package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
- package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
- package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
- package/packages/dd-trace/src/aiguard/sdk.js +22 -278
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -12
- package/packages/dd-trace/src/appsec/reporter.js +2 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +13 -0
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +16 -0
- package/packages/dd-trace/src/appsec/telemetry/waf.js +24 -0
- package/packages/dd-trace/src/carrier.js +107 -48
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +5 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +29 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +27 -9
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +26 -8
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -4
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +7 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +10 -4
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +5 -5
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
- package/packages/dd-trace/src/config/index.js +13 -2
- package/packages/dd-trace/src/config/major-overrides.js +7 -0
- package/packages/dd-trace/src/config/supported-configurations.json +14 -0
- package/packages/dd-trace/src/datastreams/index.js +2 -0
- package/packages/dd-trace/src/datastreams/manager.js +9 -2
- package/packages/dd-trace/src/datastreams/processor.js +15 -13
- package/packages/dd-trace/src/datastreams/size.js +5 -0
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/index.js +5 -11
- package/packages/dd-trace/src/debugger/index.js +4 -2
- package/packages/dd-trace/src/debugger/inspect-segment.js +154 -0
- package/packages/dd-trace/src/evp_proxy/constants.js +8 -0
- package/packages/dd-trace/src/evp_proxy/direct.js +64 -0
- package/packages/dd-trace/src/evp_proxy/discovery.js +133 -0
- package/packages/dd-trace/src/evp_proxy/path.js +22 -0
- package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
- package/packages/dd-trace/src/exporters/common/request.js +5 -2
- package/packages/dd-trace/src/exporters/common/writer.js +11 -6
- package/packages/dd-trace/src/llmobs/experiments/client.js +167 -5
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +484 -92
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +302 -29
- package/packages/dd-trace/src/llmobs/experiments/index.js +75 -64
- package/packages/dd-trace/src/llmobs/experiments/noop.js +135 -7
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +101 -9
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -2
- package/packages/dd-trace/src/noop/proxy.js +3 -4
- package/packages/dd-trace/src/openfeature/constants/constants.js +0 -18
- package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
- package/packages/dd-trace/src/openfeature/index.js +7 -4
- package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/base.js +153 -11
- package/packages/dd-trace/src/openfeature/writers/exposures.js +62 -14
- package/packages/dd-trace/src/openfeature/writers/util.js +97 -15
- package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +22 -13
- package/packages/dd-trace/src/opentracing/tracer.js +5 -2
- package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
- package/packages/dd-trace/src/plugin_manager.js +3 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/jest.js +4 -3
- package/packages/dd-trace/src/plugins/util/test.js +9 -9
- package/packages/dd-trace/src/plugins/util/web.js +3 -0
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
- package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
- package/packages/dd-trace/src/proxy.js +38 -29
- package/packages/dd-trace/src/ritm.js +9 -2
- package/packages/dd-trace/src/serverless.js +37 -0
- package/packages/dd-trace/src/span_format.js +1 -0
- package/packages/dd-trace/src/span_stats.js +30 -3
- package/packages/dd-trace/src/storage-channels.js +86 -0
- package/packages/dd-trace/src/telemetry/metrics.js +62 -8
- package/packages/dd-trace/src/telemetry/send-data.js +1 -0
- package/packages/dd-trace/src/tracer.js +9 -2
- package/packages/dd-trace/src/tracer_metadata.js +14 -1
- package/packages/dd-trace/src/web-tags-cache.js +132 -0
- package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/https-proxy-agent/LICENSE +22 -0
- package/vendor/dist/https-proxy-agent/index.js +4 -0
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/proxy-from-env/LICENSE +20 -0
- package/vendor/dist/proxy-from-env/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
- package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
- package/packages/dd-trace/src/feature-registry.js +0 -29
- package/packages/dd-trace/src/openfeature/register.js +0 -35
- package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
|
@@ -35,9 +35,13 @@ const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
|
|
|
35
35
|
/** @typedef {{ length: number, [index: number]: unknown } & Iterable<unknown>} ArgumentsLike */
|
|
36
36
|
|
|
37
37
|
const testToContext = new WeakMap()
|
|
38
|
+
const originalEfdFns = new WeakMap()
|
|
38
39
|
const originalFns = new WeakMap()
|
|
40
|
+
const originalPendingByTest = new WeakMap()
|
|
41
|
+
const originalRetriesByTest = new WeakMap()
|
|
39
42
|
const testToStartLine = new WeakMap()
|
|
40
43
|
const testFileToSuiteCtx = new Map()
|
|
44
|
+
const datadogRetryOriginals = new WeakMap()
|
|
41
45
|
const wrappedFunctions = new WeakSet()
|
|
42
46
|
const newTests = {}
|
|
43
47
|
const efdTests = {}
|
|
@@ -169,6 +173,7 @@ function wrapOriginalEfdTest (test, retryPolicy) {
|
|
|
169
173
|
}
|
|
170
174
|
test._ddEfdDurationWrapped = true
|
|
171
175
|
const originalFn = test.fn
|
|
176
|
+
originalEfdFns.set(test, originalFn)
|
|
172
177
|
test.fn = shimmer.wrapFunction(originalFn, originalFn => function () {
|
|
173
178
|
const start = performance.now()
|
|
174
179
|
const recordDuration = () => {
|
|
@@ -265,6 +270,7 @@ function isEarlyFlakeDetectionTest (test, config) {
|
|
|
265
270
|
function retryTest (test, numRetries, tags, retryPolicy) {
|
|
266
271
|
const suite = test.parent
|
|
267
272
|
const isEfdRetry = tags.includes('_ddIsEfdRetry')
|
|
273
|
+
if (!originalRetriesByTest.has(test)) originalRetriesByTest.set(test, test.retries())
|
|
268
274
|
disableMochaRetries(test)
|
|
269
275
|
if (isEfdRetry) {
|
|
270
276
|
wrapOriginalEfdTest(test, retryPolicy)
|
|
@@ -272,6 +278,7 @@ function retryTest (test, numRetries, tags, retryPolicy) {
|
|
|
272
278
|
for (let retryIndex = 0; retryIndex < numRetries; retryIndex++) {
|
|
273
279
|
const clonedTest = test.clone()
|
|
274
280
|
disableMochaRetries(clonedTest)
|
|
281
|
+
datadogRetryOriginals.set(clonedTest, test)
|
|
275
282
|
suite.addTest(clonedTest)
|
|
276
283
|
if (isEfdRetry) {
|
|
277
284
|
clonedTest._ddEfdRetryIndex = retryIndex + 1
|
|
@@ -292,6 +299,94 @@ function retryTest (test, numRetries, tags, retryPolicy) {
|
|
|
292
299
|
clonedTest[tag] = true
|
|
293
300
|
}
|
|
294
301
|
}
|
|
302
|
+
if (clonedTest._ddIsQuarantined && !clonedTest._ddIsAttemptToFix) {
|
|
303
|
+
testsQuarantined.add(clonedTest)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Restores a runnable function wrapped with its Test Optimization context.
|
|
310
|
+
*
|
|
311
|
+
* @param {import('mocha').Runnable} runnable
|
|
312
|
+
* @returns {void}
|
|
313
|
+
*/
|
|
314
|
+
function restoreRunnableFunction (runnable) {
|
|
315
|
+
const wrappedFunction = runnable.fn
|
|
316
|
+
if (!wrappedFunctions.has(wrappedFunction)) return
|
|
317
|
+
|
|
318
|
+
runnable.fn = originalFns.get(wrappedFunction)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Restores a test function wrapped to measure its EFD duration.
|
|
323
|
+
*
|
|
324
|
+
* @param {import('mocha').Test} test
|
|
325
|
+
* @returns {void}
|
|
326
|
+
*/
|
|
327
|
+
function restoreEfdTestFunction (test) {
|
|
328
|
+
if (!originalEfdFns.has(test)) return
|
|
329
|
+
|
|
330
|
+
test.fn = originalEfdFns.get(test)
|
|
331
|
+
originalEfdFns.delete(test)
|
|
332
|
+
delete test._ddEfdDurationWrapped
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Clears state that belongs to one Mocha runner execution and removes retry clones from prior executions.
|
|
337
|
+
*
|
|
338
|
+
* @param {import('mocha').Suite} rootSuite
|
|
339
|
+
* @returns {void}
|
|
340
|
+
*/
|
|
341
|
+
function resetRunState (rootSuite) {
|
|
342
|
+
for (const key of Object.keys(newTests)) delete newTests[key]
|
|
343
|
+
for (const key of Object.keys(efdTests)) delete efdTests[key]
|
|
344
|
+
newTestsWithDynamicNames.clear()
|
|
345
|
+
testsAttemptToFix.clear()
|
|
346
|
+
testsQuarantined.clear()
|
|
347
|
+
testsStatuses.clear()
|
|
348
|
+
efdRetryCountByTestFullName.clear()
|
|
349
|
+
efdSlowAbortedTests.clear()
|
|
350
|
+
attemptToFixExecutions.clear()
|
|
351
|
+
loggedAttemptToFixTests.clear()
|
|
352
|
+
|
|
353
|
+
const suites = [rootSuite]
|
|
354
|
+
while (suites.length) {
|
|
355
|
+
const suite = suites.pop()
|
|
356
|
+
const originalTests = []
|
|
357
|
+
const retainedTests = new Set()
|
|
358
|
+
for (const runnable of suite.tests) {
|
|
359
|
+
const test = datadogRetryOriginals.get(runnable) || runnable
|
|
360
|
+
if (retainedTests.has(test)) continue
|
|
361
|
+
retainedTests.add(test)
|
|
362
|
+
|
|
363
|
+
restoreRunnableFunction(test)
|
|
364
|
+
restoreEfdTestFunction(test)
|
|
365
|
+
if (originalPendingByTest.has(test)) {
|
|
366
|
+
test.pending = originalPendingByTest.get(test)
|
|
367
|
+
originalPendingByTest.delete(test)
|
|
368
|
+
}
|
|
369
|
+
if (originalRetriesByTest.has(test)) {
|
|
370
|
+
test.retries(originalRetriesByTest.get(test))
|
|
371
|
+
originalRetriesByTest.delete(test)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
delete test._ddIsAttemptToFix
|
|
375
|
+
delete test._ddIsDisabled
|
|
376
|
+
delete test._ddIsQuarantined
|
|
377
|
+
delete test._ddIsModified
|
|
378
|
+
delete test._ddIsNew
|
|
379
|
+
delete test._ddShouldSkipEfdRetry
|
|
380
|
+
delete test._ddTestFinishStarted
|
|
381
|
+
delete test._ddTestFinishPublished
|
|
382
|
+
delete test._ddIsFinalAttempt
|
|
383
|
+
delete test._ddHookFailed
|
|
384
|
+
delete test._ddReporterStartFailed
|
|
385
|
+
delete test._ddReporterTerminalFailed
|
|
386
|
+
originalTests.push(test)
|
|
387
|
+
}
|
|
388
|
+
suite.tests = originalTests
|
|
389
|
+
suites.push(...suite.suites)
|
|
295
390
|
}
|
|
296
391
|
}
|
|
297
392
|
|
|
@@ -371,6 +466,19 @@ function getTestContext (test) {
|
|
|
371
466
|
return testToContext.get(key)
|
|
372
467
|
}
|
|
373
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Claims publication of a test finish event across Mocha's terminal event paths.
|
|
471
|
+
*
|
|
472
|
+
* @param {object} test
|
|
473
|
+
* @returns {boolean}
|
|
474
|
+
*/
|
|
475
|
+
function startTestFinish (test) {
|
|
476
|
+
if (test._ddTestFinishStarted || test._ddTestFinishPublished) return false
|
|
477
|
+
|
|
478
|
+
test._ddTestFinishStarted = true
|
|
479
|
+
return true
|
|
480
|
+
}
|
|
481
|
+
|
|
374
482
|
/**
|
|
375
483
|
* Copies Test Management metadata from Mocha's original runnable to its native retry clone.
|
|
376
484
|
* @param {{
|
|
@@ -413,11 +521,7 @@ function runnableWrapper (RunnablePackage, libraryConfig) {
|
|
|
413
521
|
const test = isTestHook ? this.ctx.currentTest : this
|
|
414
522
|
|
|
415
523
|
// we restore the original user defined function
|
|
416
|
-
|
|
417
|
-
const originalFn = originalFns.get(this.fn)
|
|
418
|
-
this.fn = originalFn
|
|
419
|
-
wrappedFunctions.delete(this.fn)
|
|
420
|
-
}
|
|
524
|
+
restoreRunnableFunction(this)
|
|
421
525
|
|
|
422
526
|
if (isDatadogManagedRetryTest(test, libraryConfig)) {
|
|
423
527
|
disableMochaRetries(this)
|
|
@@ -460,11 +564,7 @@ function getOnTestHandler (isMain) {
|
|
|
460
564
|
|
|
461
565
|
// This may be a retry. If this is the case, `test.fn` is already wrapped,
|
|
462
566
|
// so we need to restore it.
|
|
463
|
-
|
|
464
|
-
const originalFn = originalFns.get(test.fn)
|
|
465
|
-
test.fn = originalFn
|
|
466
|
-
wrappedFunctions.delete(test.fn)
|
|
467
|
-
}
|
|
567
|
+
restoreRunnableFunction(test)
|
|
468
568
|
|
|
469
569
|
inheritDatadogPropertiesFromRetriedTest(test)
|
|
470
570
|
|
|
@@ -527,6 +627,9 @@ function getOnTestHandler (isMain) {
|
|
|
527
627
|
}
|
|
528
628
|
|
|
529
629
|
if (!isAttemptToFix && isDisabled) {
|
|
630
|
+
if (!originalPendingByTest.has(test)) {
|
|
631
|
+
originalPendingByTest.set(test, test.pending)
|
|
632
|
+
}
|
|
530
633
|
test.pending = true
|
|
531
634
|
}
|
|
532
635
|
|
|
@@ -701,9 +804,16 @@ function getOnTestEndHandler (config, finalAttemptHandlers) {
|
|
|
701
804
|
if (test._ddShouldSkipEfdRetry) {
|
|
702
805
|
return
|
|
703
806
|
}
|
|
807
|
+
const shouldWaitForHitProbe = test._retriedTest?._ddShouldWaitForHitProbe
|
|
704
808
|
const ctx = getTestContext(test)
|
|
705
809
|
const status = getTestStatus(test)
|
|
706
|
-
const shouldFinishTest = ctx && (
|
|
810
|
+
const shouldFinishTest = ctx && (
|
|
811
|
+
test._ddReporterStartFailed ||
|
|
812
|
+
test._ddReporterTerminalFailed ||
|
|
813
|
+
!getAfterEachHooks(test).length ||
|
|
814
|
+
(test._ddIsDisabled && !test._ddIsAttemptToFix)
|
|
815
|
+
)
|
|
816
|
+
if (shouldFinishTest && !startTestFinish(test)) return
|
|
707
817
|
let testFinishInfo
|
|
708
818
|
let isFinalAttempt = false
|
|
709
819
|
|
|
@@ -729,11 +839,12 @@ function getOnTestEndHandler (config, finalAttemptHandlers) {
|
|
|
729
839
|
finalAttemptHandlers?.onStart?.(test)
|
|
730
840
|
}
|
|
731
841
|
|
|
732
|
-
if (
|
|
842
|
+
if (shouldWaitForHitProbe) {
|
|
733
843
|
await waitForHitProbe()
|
|
734
844
|
}
|
|
735
845
|
|
|
736
846
|
if (shouldFinishTest) {
|
|
847
|
+
test._ddTestFinishPublished = true
|
|
737
848
|
testFinishCh.publish({
|
|
738
849
|
status,
|
|
739
850
|
hasBeenRetried: isMochaRetry(test),
|
|
@@ -760,10 +871,11 @@ function getOnHookEndHandler (config, finalAttemptHandlers) {
|
|
|
760
871
|
const ctx = getTestContext(test)
|
|
761
872
|
// Disabled tests are already finished in getOnTestEndHandler,
|
|
762
873
|
// skip to avoid double-publishing
|
|
763
|
-
if (ctx && (!test._ddIsDisabled || test._ddIsAttemptToFix)) {
|
|
874
|
+
if (ctx && (!test._ddIsDisabled || test._ddIsAttemptToFix) && startTestFinish(test)) {
|
|
764
875
|
const testFinishInfo = getTestFinishInfo(test, status, config, ctx.err || test.err)
|
|
765
876
|
const isFinalAttempt = testFinishInfo.finalStatus !== undefined
|
|
766
877
|
const publishTestFinish = () => {
|
|
878
|
+
test._ddTestFinishPublished = true
|
|
767
879
|
testFinishCh.publish({
|
|
768
880
|
status,
|
|
769
881
|
hasBeenRetried: isMochaRetry(test),
|
|
@@ -887,11 +999,13 @@ function getOnFailHandler (isMain, config) {
|
|
|
887
999
|
testContext = getTestContext(test)
|
|
888
1000
|
}
|
|
889
1001
|
if (testContext) {
|
|
890
|
-
if (isHook) {
|
|
891
|
-
|
|
892
|
-
|
|
1002
|
+
if (isHook && startTestFinish(test)) {
|
|
1003
|
+
const hookError = new Error(`${testOrHook.fullTitle()}: ${err.message}`, { cause: err })
|
|
1004
|
+
hookError.name = err.name
|
|
1005
|
+
hookError.stack = err.stack
|
|
1006
|
+
testContext.err = hookError
|
|
893
1007
|
errorCh.runStores(testContext, () => {})
|
|
894
|
-
const testFinishInfo = getTestFinishInfo(test, 'fail', config,
|
|
1008
|
+
const testFinishInfo = getTestFinishInfo(test, 'fail', config, hookError)
|
|
895
1009
|
// ATR never retries hook failures: this.retries(N) is set in runnableWrapper
|
|
896
1010
|
// which only runs when the test function executes — hooks bypass that path,
|
|
897
1011
|
// so _retries stays at -1 and getIsLastRetry returns false, leaving finalStatus
|
|
@@ -906,6 +1020,7 @@ function getOnFailHandler (isMain, config) {
|
|
|
906
1020
|
// test.state is never set to 'failed' for hook failures (Mocha marks the hook,
|
|
907
1021
|
// not the test). Flag it so finishRootSuiteForFile can compute the correct status.
|
|
908
1022
|
test._ddHookFailed = true
|
|
1023
|
+
test._ddTestFinishPublished = true
|
|
909
1024
|
testFinishCh.publish({
|
|
910
1025
|
status: 'fail',
|
|
911
1026
|
hasBeenRetried: isMochaRetry(test),
|
|
@@ -1034,7 +1149,7 @@ function getRunTestsWrapper (runTests, config) {
|
|
|
1034
1149
|
retryTest(
|
|
1035
1150
|
test,
|
|
1036
1151
|
config.earlyFlakeDetectionRetryPolicy.schedulingRetryCount,
|
|
1037
|
-
['_ddIsModified', '_ddIsEfdRetry'],
|
|
1152
|
+
['_ddIsModified', '_ddIsEfdRetry', test._ddIsQuarantined && '_ddIsQuarantined'],
|
|
1038
1153
|
config.earlyFlakeDetectionRetryPolicy
|
|
1039
1154
|
)
|
|
1040
1155
|
}
|
|
@@ -1053,7 +1168,7 @@ function getRunTestsWrapper (runTests, config) {
|
|
|
1053
1168
|
retryTest(
|
|
1054
1169
|
test,
|
|
1055
1170
|
config.earlyFlakeDetectionRetryPolicy.schedulingRetryCount,
|
|
1056
|
-
['_ddIsNew', '_ddIsEfdRetry'],
|
|
1171
|
+
['_ddIsNew', '_ddIsEfdRetry', test._ddIsQuarantined && '_ddIsQuarantined'],
|
|
1057
1172
|
config.earlyFlakeDetectionRetryPolicy
|
|
1058
1173
|
)
|
|
1059
1174
|
}
|
|
@@ -1088,6 +1203,7 @@ module.exports = {
|
|
|
1088
1203
|
getOnPendingHandler,
|
|
1089
1204
|
testFileToSuiteCtx,
|
|
1090
1205
|
getRunTestsWrapper,
|
|
1206
|
+
resetRunState,
|
|
1091
1207
|
newTests,
|
|
1092
1208
|
efdTests,
|
|
1093
1209
|
newTestsWithDynamicNames,
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
|
+
|
|
5
|
+
const reporterErrorCh = channel('ci:playwright:reporter:error')
|
|
6
|
+
const reporterRunSummaryCh = channel('ci:playwright:reporter:run-summary')
|
|
7
|
+
const reporterSuiteHookErrorCh = channel('ci:playwright:reporter:suite-hook-error')
|
|
8
|
+
const suitesWithHookErrors = new Set()
|
|
9
|
+
const PLAYWRIGHT_REPORTER_ERROR_MESSAGE = 'Error in reporter'
|
|
10
|
+
const PLAYWRIGHT_REPORTER_ERROR_CALLER_RE =
|
|
11
|
+
/^\s*at wrapAsync .*?[\\/]playwright[\\/]lib[\\/]runner[\\/]index\.js:\d+:\d+\)?$/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Identifies the private Playwright 1.60-1.61 reporter error fallback without
|
|
15
|
+
* interpreting identical user console output as a framework error.
|
|
16
|
+
*
|
|
17
|
+
* @param {unknown} message - First console.error argument
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function isPlaywrightReporterError (message) {
|
|
21
|
+
if (message !== PLAYWRIGHT_REPORTER_ERROR_MESSAGE) return false
|
|
22
|
+
|
|
23
|
+
const originalPrepareStackTrace = Error.prepareStackTrace
|
|
24
|
+
try {
|
|
25
|
+
Error.prepareStackTrace = (_, callSites) => callSites
|
|
26
|
+
const stack = new Error('Playwright reporter error provenance').stack
|
|
27
|
+
return PLAYWRIGHT_REPORTER_ERROR_CALLER_RE.test(`at ${stack?.[2]?.toString() || ''}`)
|
|
28
|
+
} finally {
|
|
29
|
+
Error.prepareStackTrace = originalPrepareStackTrace
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns whether a finalized Playwright result contains a failed suite hook.
|
|
35
|
+
*
|
|
36
|
+
* @param {Array<object>} steps
|
|
37
|
+
* @returns {boolean}
|
|
38
|
+
*/
|
|
39
|
+
function hasFailedSuiteHook (steps) {
|
|
40
|
+
if (!steps) return false
|
|
41
|
+
|
|
42
|
+
for (const step of steps) {
|
|
43
|
+
if (step.error && (step.title === 'beforeAll hook' || step.title === 'afterAll hook')) return true
|
|
44
|
+
if (hasFailedSuiteHook(step.steps)) return true
|
|
45
|
+
}
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class DatadogPlaywrightReporter {
|
|
50
|
+
/**
|
|
51
|
+
* Creates a reporter that observes the finalized Playwright result independently of user reporters.
|
|
52
|
+
*
|
|
53
|
+
* @param {object} [options]
|
|
54
|
+
* @param {boolean} [options.captureReporterErrors]
|
|
55
|
+
*/
|
|
56
|
+
constructor ({ captureReporterErrors = true } = {}) {
|
|
57
|
+
this.captureReporterErrors = captureReporterErrors
|
|
58
|
+
this.fatalErrorCount = 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Identifies this reporter as implementing Playwright's reporter v2 contract.
|
|
63
|
+
*
|
|
64
|
+
* @returns {'v2'}
|
|
65
|
+
*/
|
|
66
|
+
version () {
|
|
67
|
+
return 'v2'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
72
|
+
*
|
|
73
|
+
* @param {object} config
|
|
74
|
+
* @returns {void}
|
|
75
|
+
*/
|
|
76
|
+
onConfigure (config) {
|
|
77
|
+
this.failOnFlakyTests = config.failOnFlakyTests
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Restores console error after Playwright completes the reporter lifecycle.
|
|
82
|
+
*
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
85
|
+
static restoreConsoleError () {
|
|
86
|
+
// eslint-disable-next-line no-console
|
|
87
|
+
if (console.error === DatadogPlaywrightReporter.consoleError) {
|
|
88
|
+
try {
|
|
89
|
+
// eslint-disable-next-line no-console
|
|
90
|
+
console.error = DatadogPlaywrightReporter.originalConsoleError
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
93
|
+
DatadogPlaywrightReporter.consoleError = undefined
|
|
94
|
+
DatadogPlaywrightReporter.originalConsoleError = undefined
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Records the suite so finalized test outcomes can be counted in onEnd.
|
|
99
|
+
*
|
|
100
|
+
* @param {object} configOrSuite
|
|
101
|
+
* @param {object} [suite]
|
|
102
|
+
* @returns {void}
|
|
103
|
+
*/
|
|
104
|
+
onBegin (configOrSuite, suite) {
|
|
105
|
+
this.suite = suite || configOrSuite
|
|
106
|
+
if (suite) this.failOnFlakyTests = configOrSuite.failOnFlakyTests
|
|
107
|
+
suitesWithHookErrors.clear()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
112
|
+
*
|
|
113
|
+
* @returns {void}
|
|
114
|
+
*/
|
|
115
|
+
onTestBegin () {}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
119
|
+
*
|
|
120
|
+
* @returns {void}
|
|
121
|
+
*/
|
|
122
|
+
onStdOut () {}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
126
|
+
*
|
|
127
|
+
* @returns {void}
|
|
128
|
+
*/
|
|
129
|
+
onStdErr () {}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
133
|
+
*
|
|
134
|
+
* @returns {void}
|
|
135
|
+
*/
|
|
136
|
+
onTestEnd () {}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
140
|
+
*
|
|
141
|
+
* @returns {void}
|
|
142
|
+
*/
|
|
143
|
+
onStepBegin () {}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
147
|
+
*
|
|
148
|
+
* @returns {void}
|
|
149
|
+
*/
|
|
150
|
+
onStepEnd () {}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Marks the beginning of reporter finalization so later reporter errors can be identified.
|
|
154
|
+
*
|
|
155
|
+
* @returns {void}
|
|
156
|
+
*/
|
|
157
|
+
onEnd () {
|
|
158
|
+
let failureCount = this.fatalErrorCount
|
|
159
|
+
let quarantinedFailureCount = 0
|
|
160
|
+
let hasIncompleteTests = suitesWithHookErrors.size > 0
|
|
161
|
+
const tests = this.suite?.allTests?.()
|
|
162
|
+
if (tests) {
|
|
163
|
+
for (const test of tests) {
|
|
164
|
+
const outcome = test.outcome()
|
|
165
|
+
const finalResult = test.results.at(-1)
|
|
166
|
+
hasIncompleteTests ||= hasFailedSuiteHook(finalResult?.steps)
|
|
167
|
+
if (outcome === 'unexpected' || (outcome === 'flaky' && this.failOnFlakyTests)) {
|
|
168
|
+
failureCount += 1
|
|
169
|
+
const finalResultStatus = finalResult?.status
|
|
170
|
+
const hasFailed = finalResultStatus === 'failed' || finalResultStatus === 'timedOut'
|
|
171
|
+
if (outcome === 'unexpected' && hasFailed && test._ddIsQuarantined && !test._ddIsAttemptToFix) {
|
|
172
|
+
quarantinedFailureCount += 1
|
|
173
|
+
}
|
|
174
|
+
} else if (outcome === 'skipped' && !test._ddShouldSkipEfdRetry &&
|
|
175
|
+
(!test._ddIsDisabled || test._ddIsAttemptToFix)) {
|
|
176
|
+
const { results } = test
|
|
177
|
+
hasIncompleteTests ||= results.some(result => result.status === 'interrupted') ||
|
|
178
|
+
!results.length || test.expectedStatus !== 'skipped'
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
reporterRunSummaryCh.publish({ failureCount, quarantinedFailureCount, hasIncompleteTests })
|
|
183
|
+
suitesWithHookErrors.clear()
|
|
184
|
+
|
|
185
|
+
if (!this.captureReporterErrors) return
|
|
186
|
+
|
|
187
|
+
this.isFinalizing = true
|
|
188
|
+
// Playwright 1.60 and 1.61 only expose reporter errors through this exact console call.
|
|
189
|
+
// eslint-disable-next-line no-console
|
|
190
|
+
const originalConsoleError = console.error
|
|
191
|
+
const reporter = this
|
|
192
|
+
const consoleError = function (message, error) {
|
|
193
|
+
if (isPlaywrightReporterError(message)) {
|
|
194
|
+
reporter.onError(error)
|
|
195
|
+
}
|
|
196
|
+
return originalConsoleError.apply(this, arguments)
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
// eslint-disable-next-line no-console
|
|
200
|
+
console.error = consoleError
|
|
201
|
+
} catch {
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
// An accessor may ignore the assignment without throwing.
|
|
205
|
+
// eslint-disable-next-line no-console
|
|
206
|
+
if (console.error !== consoleError) return
|
|
207
|
+
|
|
208
|
+
DatadogPlaywrightReporter.originalConsoleError = originalConsoleError
|
|
209
|
+
DatadogPlaywrightReporter.consoleError = consoleError
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Implements the reporter v2 lifecycle hook required by older Playwright versions.
|
|
214
|
+
*
|
|
215
|
+
* @returns {void}
|
|
216
|
+
*/
|
|
217
|
+
onExit () {}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Reports errors emitted by Playwright while later reporters are finalizing.
|
|
221
|
+
*
|
|
222
|
+
* @param {unknown} error
|
|
223
|
+
* @returns {void}
|
|
224
|
+
*/
|
|
225
|
+
onError (error) {
|
|
226
|
+
if (this.isFinalizing) {
|
|
227
|
+
reporterErrorCh.publish(error)
|
|
228
|
+
} else {
|
|
229
|
+
this.fatalErrorCount += 1
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Keeps the internal reporter from affecting Playwright's output reporter selection.
|
|
235
|
+
*
|
|
236
|
+
* @returns {boolean}
|
|
237
|
+
*/
|
|
238
|
+
printsToStdio () {
|
|
239
|
+
return false
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
reporterSuiteHookErrorCh.subscribe((testSuiteAbsolutePath) => {
|
|
244
|
+
suitesWithHookErrors.add(testSuiteAbsolutePath)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
module.exports = DatadogPlaywrightReporter
|