dd-trace 6.16.0 → 6.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ci/diagnose.js +0 -23
- package/ci/test-optimization-validation/approval-artifacts.js +0 -3
- package/ci/test-optimization-validation/approval.js +0 -6
- package/ci/test-optimization-validation/artifact-id.js +0 -1
- package/ci/test-optimization-validation/bounded-json.js +0 -1
- package/ci/test-optimization-validation/cli.js +0 -12
- package/ci/test-optimization-validation/command-output-policy.js +0 -1
- package/ci/test-optimization-validation/command-runner.js +0 -3
- package/ci/test-optimization-validation/environment.js +0 -4
- package/ci/test-optimization-validation/executable-approval.js +0 -1
- package/ci/test-optimization-validation/executable.js +0 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +0 -6
- package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
- package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
- package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
- package/ci/test-optimization-validation/generated-test-contract.js +0 -5
- package/ci/test-optimization-validation/generated-verifier.js +0 -1
- package/ci/test-optimization-validation/literal-environment.js +0 -1
- package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
- package/ci/test-optimization-validation/manifest-schema.js +0 -21
- package/ci/test-optimization-validation/offline-fixtures.js +0 -4
- package/ci/test-optimization-validation/plan-writer.js +0 -11
- package/ci/test-optimization-validation/preflight-runner.js +0 -1
- package/ci/test-optimization-validation/redaction.js +0 -4
- package/ci/test-optimization-validation/report-writer.js +0 -16
- package/ci/test-optimization-validation/runner-command.js +0 -3
- package/ci/test-optimization-validation/runner-contract.js +0 -4
- package/ci/test-optimization-validation/safe-files.js +0 -1
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +0 -1
- package/ci/test-optimization-validation/source-text.js +0 -3
- package/ci/vitest-no-worker-init-setup.mjs +41 -16
- package/index.d.ts +208 -0
- package/package.json +17 -16
- package/packages/datadog-esbuild/src/utils.js +0 -2
- package/packages/datadog-instrumentations/src/aerospike.js +28 -6
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -2
- package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +0 -2
- package/packages/datadog-instrumentations/src/console.js +97 -0
- package/packages/datadog-instrumentations/src/cucumber.js +77 -12
- package/packages/datadog-instrumentations/src/cypress-config.js +27 -38
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +6 -0
- package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -6
- package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +0 -3
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
- package/packages/datadog-instrumentations/src/helpers/register.js +24 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +111 -26
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +41 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +55 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -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 +20 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
- package/packages/datadog-instrumentations/src/jest.js +165 -51
- package/packages/datadog-instrumentations/src/knex.js +0 -1
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
- package/packages/datadog-instrumentations/src/mariadb.js +0 -2
- package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +25 -26
- package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
- package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
- package/packages/datadog-instrumentations/src/mysql2.js +0 -2
- package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
- package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
- package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
- package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
- package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
- package/packages/datadog-instrumentations/src/openai.js +51 -12
- package/packages/datadog-instrumentations/src/oracledb.js +9 -3
- package/packages/datadog-instrumentations/src/playwright-reporter.js +6 -20
- package/packages/datadog-instrumentations/src/playwright.js +280 -56
- package/packages/datadog-instrumentations/src/{azure-cosmos.js → postgres.js} +1 -1
- package/packages/datadog-instrumentations/src/router.js +0 -2
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
- package/packages/datadog-instrumentations/src/sequelize.js +0 -1
- package/packages/datadog-instrumentations/src/supabase.js +15 -0
- package/packages/datadog-instrumentations/src/undici.js +7 -3
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
- package/packages/datadog-instrumentations/src/vitest-main.js +121 -30
- package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
- package/packages/datadog-instrumentations/src/vitest-worker.js +49 -13
- package/packages/datadog-instrumentations/src/webdriverio.js +44 -47
- package/packages/datadog-instrumentations/src/ws.js +41 -2
- package/packages/datadog-plugin-ai/src/utils.js +0 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +0 -1
- package/packages/datadog-plugin-cucumber/src/index.js +9 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +211 -85
- package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
- package/packages/datadog-plugin-cypress/src/index.js +3 -1
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
- package/packages/datadog-plugin-cypress/src/support.js +52 -7
- package/packages/datadog-plugin-graphql/src/resolve-error.js +1 -2
- package/packages/datadog-plugin-graphql/src/utils.js +0 -5
- package/packages/datadog-plugin-jest/src/index.js +12 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
- package/packages/datadog-plugin-mocha/src/index.js +38 -11
- package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
- package/packages/datadog-plugin-openai/src/index.js +16 -1
- package/packages/datadog-plugin-openai/src/realtime.js +144 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
- package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
- package/packages/datadog-plugin-playwright/src/index.js +81 -9
- package/packages/datadog-plugin-postgres/src/index.js +167 -0
- package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
- package/packages/datadog-plugin-redis/src/index.js +15 -1
- package/packages/datadog-plugin-supabase/src/error.js +18 -0
- package/packages/datadog-plugin-supabase/src/index.js +21 -0
- package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
- package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
- package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
- package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
- package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
- package/packages/datadog-plugin-supabase/src/url.js +17 -0
- package/packages/datadog-plugin-vitest/src/index.js +9 -0
- package/packages/datadog-plugin-ws/src/producer.js +1 -1
- package/packages/datadog-plugin-ws/src/util.js +0 -4
- package/packages/datadog-shimmer/src/shimmer.js +14 -10
- package/packages/datadog-turbopack/index.js +4 -7
- package/packages/datadog-turbopack/src/loader.js +6 -18
- package/packages/datadog-webpack/src/loader.js +0 -1
- package/packages/dd-trace/src/agent/info.js +5 -4
- package/packages/dd-trace/src/aiguard/client.js +2 -3
- package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
- package/packages/dd-trace/src/aiguard/index.js +2 -2
- package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
- package/packages/dd-trace/src/aiguard/integrations/openai.js +81 -7
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
- package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
- package/packages/dd-trace/src/aiguard/messages/utils.js +0 -1
- package/packages/dd-trace/src/aiguard/redaction.js +0 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/activation.js +1 -1
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
- package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
- package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
- package/packages/dd-trace/src/appsec/index.js +2 -2
- package/packages/dd-trace/src/appsec/lambda.js +71 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
- package/packages/dd-trace/src/appsec/remote_config.js +8 -6
- package/packages/dd-trace/src/appsec/reporter.js +10 -6
- package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
- package/packages/dd-trace/src/carrier.js +0 -5
- package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
- package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
- package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
- package/packages/dd-trace/src/config/defaults.js +3 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +88 -82
- package/packages/dd-trace/src/config/helper.js +0 -1
- package/packages/dd-trace/src/config/index.js +31 -30
- package/packages/dd-trace/src/config/parsers.js +34 -6
- package/packages/dd-trace/src/config/remote_config.js +25 -109
- package/packages/dd-trace/src/config/supported-configurations.json +150 -10
- package/packages/dd-trace/src/datastreams/encoding.js +0 -1
- package/packages/dd-trace/src/datastreams/pathway.js +0 -1
- package/packages/dd-trace/src/debugger/constants.js +10 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +62 -10
- package/packages/dd-trace/src/debugger/devtools_client/config.js +4 -1
- package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
- package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
- package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +21 -8
- package/packages/dd-trace/src/debugger/devtools_client/send.js +41 -15
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +5 -3
- package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +21 -7
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
- package/packages/dd-trace/src/debugger/index.js +51 -3
- package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
- package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
- package/packages/dd-trace/src/dogstatsd.js +0 -23
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
- package/packages/dd-trace/src/encode/0.4.js +0 -7
- package/packages/dd-trace/src/encode/0.5.js +0 -2
- package/packages/dd-trace/src/encode/tags-processors.js +0 -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 -11
- package/packages/dd-trace/src/evp_proxy/path.js +21 -9
- package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
- package/packages/dd-trace/src/exporters/common/request.js +1 -0
- package/packages/dd-trace/src/exporters/common/url.js +33 -4
- package/packages/dd-trace/src/exporters/common/writer.js +0 -2
- package/packages/dd-trace/src/id.js +0 -11
- package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
- package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
- package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
- package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
- package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
- package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
- package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
- package/packages/dd-trace/src/llmobs/index.js +1 -3
- package/packages/dd-trace/src/llmobs/noop.js +10 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
- package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
- package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
- package/packages/dd-trace/src/llmobs/prompts/manager.js +647 -0
- package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +158 -0
- package/packages/dd-trace/src/llmobs/sdk.js +21 -6
- package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
- package/packages/dd-trace/src/llmobs/tagger.js +39 -11
- package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
- package/packages/dd-trace/src/llmobs/util.js +0 -34
- package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
- package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
- package/packages/dd-trace/src/log/channels.js +3 -0
- package/packages/dd-trace/src/log/index.js +23 -5
- package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
- package/packages/dd-trace/src/msgpack/chunk.js +0 -1
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
- package/packages/dd-trace/src/openfeature/configuration_source.js +4 -1
- package/packages/dd-trace/src/openfeature/encoding.js +0 -2
- package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -3
- package/packages/dd-trace/src/openfeature/index.js +6 -6
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
- package/packages/dd-trace/src/openfeature/writers/base.js +90 -23
- package/packages/dd-trace/src/openfeature/writers/exposures.js +4 -5
- package/packages/dd-trace/src/openfeature/writers/util.js +104 -37
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -14
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +30 -13
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
- package/packages/dd-trace/src/opentracing/span_context.js +0 -1
- package/packages/dd-trace/src/opentracing/tracer.js +3 -3
- package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
- package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
- package/packages/dd-trace/src/plugin_manager.js +27 -8
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -2
- package/packages/dd-trace/src/plugins/database.js +2 -6
- package/packages/dd-trace/src/plugins/index.js +7 -0
- package/packages/dd-trace/src/plugins/plugin.js +0 -4
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/git.js +1 -3
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
- package/packages/dd-trace/src/plugins/util/llm.js +0 -2
- package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
- package/packages/dd-trace/src/plugins/util/test.js +26 -20
- package/packages/dd-trace/src/plugins/util/url.js +0 -5
- package/packages/dd-trace/src/priority_sampler.js +0 -6
- package/packages/dd-trace/src/process-tags/index.js +0 -1
- package/packages/dd-trace/src/profiler.js +132 -35
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
- package/packages/dd-trace/src/profiling/profiler.js +101 -41
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
- package/packages/dd-trace/src/propagation-hash/index.js +0 -1
- package/packages/dd-trace/src/proxy.js +23 -47
- package/packages/dd-trace/src/random_sampler.js +0 -4
- package/packages/dd-trace/src/rate_limiter.js +0 -4
- package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
- package/packages/dd-trace/src/remote_config/index.js +0 -1
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
- package/packages/dd-trace/src/sampler.js +0 -4
- package/packages/dd-trace/src/sampling_rule.js +0 -7
- package/packages/dd-trace/src/serverless/vercel.js +0 -1
- package/packages/dd-trace/src/serverless.js +0 -1
- package/packages/dd-trace/src/service-naming/index.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
- package/packages/dd-trace/src/span_processor.js +2 -2
- package/packages/dd-trace/src/span_sampler.js +0 -1
- package/packages/dd-trace/src/standalone/product.js +2 -2
- package/packages/dd-trace/src/standalone/tracesource.js +0 -1
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
- package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
- package/packages/dd-trace/src/telemetry/metrics.js +0 -2
- package/packages/dd-trace/src/telemetry/send-data.js +2 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
- package/packages/dd-trace/src/tracer.js +5 -4
- package/packages/dd-trace/src/util.js +13 -1
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- 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
|
@@ -14,6 +14,9 @@ const {
|
|
|
14
14
|
hasEfdRetries,
|
|
15
15
|
shouldSkipEfdRetry,
|
|
16
16
|
} = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
|
|
17
|
+
const {
|
|
18
|
+
getDynamicAtrRetryCount,
|
|
19
|
+
} = require('../../dd-trace/src/ci-visibility/dynamic-atr-retries')
|
|
17
20
|
const {
|
|
18
21
|
TEST_STATUS,
|
|
19
22
|
setRumTestTags,
|
|
@@ -86,6 +89,7 @@ const {
|
|
|
86
89
|
getPullRequestBaseBranch,
|
|
87
90
|
TEST_FINAL_STATUS,
|
|
88
91
|
getTestOptimizationRequestResults,
|
|
92
|
+
setExpectedEmptyTestSessionTags,
|
|
89
93
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
90
94
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
91
95
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
@@ -229,11 +233,16 @@ function getTestScreenshots (cypressTest, attemptIndex, specScreenshots) {
|
|
|
229
233
|
return specScreenshots.filter(screenshot => isScreenshotForTestAttempt(screenshot, titleParts, attemptIndex))
|
|
230
234
|
}
|
|
231
235
|
|
|
232
|
-
function getSessionStatus (summary) {
|
|
233
|
-
if (summary
|
|
236
|
+
function getSessionStatus (summary, testSuiteStatuses) {
|
|
237
|
+
if (!summary) {
|
|
238
|
+
if (testSuiteStatuses.has('fail')) return 'fail'
|
|
239
|
+
if (testSuiteStatuses.has('skip') && !testSuiteStatuses.has('pass')) return 'skip'
|
|
240
|
+
return 'pass'
|
|
241
|
+
}
|
|
242
|
+
if (summary.status === 'failed' || summary.failures > 0 || summary.totalFailed > 0) {
|
|
234
243
|
return 'fail'
|
|
235
244
|
}
|
|
236
|
-
if (summary.totalSkipped
|
|
245
|
+
if ((summary.totalSkipped ?? 0) + (summary.totalPending ?? 0) === summary.totalTests) {
|
|
237
246
|
return 'skip'
|
|
238
247
|
}
|
|
239
248
|
return 'pass'
|
|
@@ -372,39 +381,16 @@ function getSuiteStatus (suiteStats) {
|
|
|
372
381
|
return 'fail'
|
|
373
382
|
}
|
|
374
383
|
if (suiteStats.tests !== undefined &&
|
|
375
|
-
|
|
384
|
+
suiteStats.tests === (suiteStats.pending ?? 0) + (suiteStats.skipped ?? 0)) {
|
|
376
385
|
return 'skip'
|
|
377
386
|
}
|
|
378
387
|
return 'pass'
|
|
379
388
|
}
|
|
380
389
|
|
|
381
|
-
function getMatchingCypressTest (cypressTests, testName, attemptIndex, testStatus, preferIndexedMatch = false) {
|
|
382
|
-
let matchingTestByIndex
|
|
383
|
-
let matchingTestByStatus
|
|
384
|
-
let matchingTestIndex = 0
|
|
385
|
-
|
|
386
|
-
for (const cypressTest of cypressTests) {
|
|
387
|
-
if (cypressTest.title.join(' ') !== testName) {
|
|
388
|
-
continue
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (matchingTestIndex === attemptIndex) {
|
|
392
|
-
matchingTestByIndex = cypressTest
|
|
393
|
-
}
|
|
394
|
-
matchingTestIndex++
|
|
395
|
-
|
|
396
|
-
if (!matchingTestByStatus && CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state] === testStatus) {
|
|
397
|
-
matchingTestByStatus = cypressTest
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return preferIndexedMatch
|
|
402
|
-
? matchingTestByIndex || matchingTestByStatus
|
|
403
|
-
: matchingTestByStatus || matchingTestByIndex
|
|
404
|
-
}
|
|
405
|
-
|
|
406
390
|
function isCypressHookFailure (cypressTest) {
|
|
407
|
-
|
|
391
|
+
// Duplicate titles can leave the aggregate state passed even when the final attempt has a hook failure.
|
|
392
|
+
const lastAttempt = cypressTest.attempts?.at(-1)
|
|
393
|
+
return (cypressTest.state === 'failed' || lastAttempt?.state === 'failed') &&
|
|
408
394
|
/\bhook\b/.test(String(cypressTest.displayError || ''))
|
|
409
395
|
}
|
|
410
396
|
|
|
@@ -415,7 +401,12 @@ const FINAL_STATUS_RETRY_KIND = {
|
|
|
415
401
|
atf: 'atf',
|
|
416
402
|
}
|
|
417
403
|
|
|
418
|
-
function getFinalStatusRetryKind ({
|
|
404
|
+
function getFinalStatusRetryKind ({
|
|
405
|
+
finishedTest,
|
|
406
|
+
finishedTestAttempts,
|
|
407
|
+
flakyTestRetriesCount,
|
|
408
|
+
isDynamicAtrEnabled,
|
|
409
|
+
}) {
|
|
419
410
|
// Infer retry kind from the executions we actually saw so ATR enabled with
|
|
420
411
|
// a retry count of 0 is still treated as a single final execution.
|
|
421
412
|
if (finishedTest.isAttemptToFix) {
|
|
@@ -426,7 +417,7 @@ function getFinalStatusRetryKind ({ finishedTest, finishedTestAttempts, flakyTes
|
|
|
426
417
|
return FINAL_STATUS_RETRY_KIND.efd
|
|
427
418
|
}
|
|
428
419
|
|
|
429
|
-
if (finishedTestAttempts.length > 1 && flakyTestRetriesCount > 0) {
|
|
420
|
+
if (finishedTestAttempts.length > 1 && (isDynamicAtrEnabled || flakyTestRetriesCount > 0)) {
|
|
430
421
|
return FINAL_STATUS_RETRY_KIND.atr
|
|
431
422
|
}
|
|
432
423
|
|
|
@@ -436,7 +427,7 @@ function getFinalStatusRetryKind ({ finishedTest, finishedTestAttempts, flakyTes
|
|
|
436
427
|
function getFinalStatus ({
|
|
437
428
|
status,
|
|
438
429
|
retryKind,
|
|
439
|
-
|
|
430
|
+
hasFailedAllAttempts,
|
|
440
431
|
hasPassedAllAtfRetries,
|
|
441
432
|
isQuarantined,
|
|
442
433
|
isDisabled,
|
|
@@ -450,7 +441,7 @@ function getFinalStatus ({
|
|
|
450
441
|
case FINAL_STATUS_RETRY_KIND.atr:
|
|
451
442
|
case FINAL_STATUS_RETRY_KIND.efd:
|
|
452
443
|
// These modes report the aggregate result across attempts.
|
|
453
|
-
return
|
|
444
|
+
return hasFailedAllAttempts ? 'fail' : 'pass'
|
|
454
445
|
case FINAL_STATUS_RETRY_KIND.atf:
|
|
455
446
|
// Attempt-to-fix only passes if every execution passed.
|
|
456
447
|
return hasPassedAllAtfRetries ? 'pass' : 'fail'
|
|
@@ -460,10 +451,14 @@ function getFinalStatus ({
|
|
|
460
451
|
}
|
|
461
452
|
|
|
462
453
|
class CypressPlugin {
|
|
454
|
+
#pendingTestSuiteSpans = new Map()
|
|
455
|
+
|
|
463
456
|
_isInit = false
|
|
464
457
|
testEnvironmentMetadata = getTestEnvironmentMetadata(TEST_FRAMEWORK_NAME)
|
|
465
458
|
|
|
466
459
|
finishedTestsByFile = {}
|
|
460
|
+
hasTestsReported = false
|
|
461
|
+
testSuiteStatuses = new Set()
|
|
467
462
|
testStatuses = {}
|
|
468
463
|
hasLibraryConfiguration = false
|
|
469
464
|
isItrEnabled = false
|
|
@@ -473,6 +468,9 @@ class CypressPlugin {
|
|
|
473
468
|
isCoverageReportUploadEnabled = false
|
|
474
469
|
isFlakyTestRetriesEnabled = false
|
|
475
470
|
flakyTestRetriesCount = 0
|
|
471
|
+
isDynamicAtrEnabled = false
|
|
472
|
+
dynamicAtrBuckets = undefined
|
|
473
|
+
dynamicAtrRetryCountByTest = new Map()
|
|
476
474
|
isEarlyFlakeDetectionEnabled = false
|
|
477
475
|
isEarlyFlakeDetectionFaulty = false
|
|
478
476
|
isKnownTestsEnabled = false
|
|
@@ -550,11 +548,13 @@ class CypressPlugin {
|
|
|
550
548
|
* Resets state that is scoped to a single Cypress run so the singleton plugin
|
|
551
549
|
* can be reused safely across multiple programmatic cypress.run() calls.
|
|
552
550
|
*
|
|
553
|
-
* @returns {void}
|
|
554
551
|
*/
|
|
555
552
|
resetRunState () {
|
|
553
|
+
this.#pendingTestSuiteSpans.clear()
|
|
556
554
|
this._isInit = false
|
|
557
555
|
this.finishedTestsByFile = {}
|
|
556
|
+
this.hasTestsReported = false
|
|
557
|
+
this.testSuiteStatuses = new Set()
|
|
558
558
|
this.testStatuses = {}
|
|
559
559
|
this.hasLibraryConfiguration = false
|
|
560
560
|
this.isItrEnabled = false
|
|
@@ -564,6 +564,9 @@ class CypressPlugin {
|
|
|
564
564
|
this.isCoverageReportUploadEnabled = false
|
|
565
565
|
this.isFlakyTestRetriesEnabled = false
|
|
566
566
|
this.flakyTestRetriesCount = 0
|
|
567
|
+
this.isDynamicAtrEnabled = false
|
|
568
|
+
this.dynamicAtrBuckets = undefined
|
|
569
|
+
this.dynamicAtrRetryCountByTest = new Map()
|
|
567
570
|
this.isEarlyFlakeDetectionEnabled = false
|
|
568
571
|
this.isEarlyFlakeDetectionFaulty = false
|
|
569
572
|
this.isKnownTestsEnabled = false
|
|
@@ -630,7 +633,6 @@ class CypressPlugin {
|
|
|
630
633
|
*
|
|
631
634
|
* @param {string} traceId - Test trace id used for the upload
|
|
632
635
|
* @param {Promise<string|undefined>} uploadPromise - Promise resolving to the upload outcome
|
|
633
|
-
* @returns {void}
|
|
634
636
|
*/
|
|
635
637
|
addScreenshotUploadPromise (traceId, uploadPromise) {
|
|
636
638
|
const uploadPromises = this.screenshotUploadPromisesByTraceId.get(traceId)
|
|
@@ -659,7 +661,6 @@ class CypressPlugin {
|
|
|
659
661
|
* Cancels screenshot work that must not outlive an errored after:spec finalization boundary.
|
|
660
662
|
*
|
|
661
663
|
* @param {Error} error - Error that triggered finalization
|
|
662
|
-
* @returns {void}
|
|
663
664
|
*/
|
|
664
665
|
abortPendingScreenshotUploads (error) {
|
|
665
666
|
for (const controller of this.screenshotUploadAbortControllers) controller.abort(error)
|
|
@@ -673,7 +674,6 @@ class CypressPlugin {
|
|
|
673
674
|
* start/finish. Captured at session span creation so it shares the same
|
|
674
675
|
* epoch as the trace without reaching into span internals.
|
|
675
676
|
*
|
|
676
|
-
* @returns {number}
|
|
677
677
|
*/
|
|
678
678
|
_now () {
|
|
679
679
|
return this._timeOrigin + performance.now() - this._perfOrigin
|
|
@@ -682,7 +682,6 @@ class CypressPlugin {
|
|
|
682
682
|
/**
|
|
683
683
|
* Returns the directory used to normalize coverage file names.
|
|
684
684
|
*
|
|
685
|
-
* @returns {string}
|
|
686
685
|
*/
|
|
687
686
|
getCoverageRootDir () {
|
|
688
687
|
return this.repositoryRoot || this.rootDir || process.cwd()
|
|
@@ -691,7 +690,6 @@ class CypressPlugin {
|
|
|
691
690
|
/**
|
|
692
691
|
* Returns whether skipped test coverage should be backfilled into the session coverage map.
|
|
693
692
|
*
|
|
694
|
-
* @returns {boolean}
|
|
695
693
|
*/
|
|
696
694
|
shouldBackfillSkippedCoverage () {
|
|
697
695
|
return this.isItrEnabled &&
|
|
@@ -704,7 +702,6 @@ class CypressPlugin {
|
|
|
704
702
|
* Adds a test's Istanbul coverage to the aggregated session coverage map.
|
|
705
703
|
*
|
|
706
704
|
* @param {object} coverage
|
|
707
|
-
* @returns {void}
|
|
708
705
|
*/
|
|
709
706
|
addTestSessionCoverage (coverage) {
|
|
710
707
|
mergeCoverage(coverage, this.testSessionCoverageMap)
|
|
@@ -713,7 +710,6 @@ class CypressPlugin {
|
|
|
713
710
|
/**
|
|
714
711
|
* Applies backend skipped-test coverage to the aggregated session coverage map.
|
|
715
712
|
*
|
|
716
|
-
* @returns {boolean}
|
|
717
713
|
*/
|
|
718
714
|
applySkippedCoverageToTestSessionCoverage () {
|
|
719
715
|
if (!this.shouldBackfillSkippedCoverage()) {
|
|
@@ -756,7 +752,6 @@ class CypressPlugin {
|
|
|
756
752
|
/**
|
|
757
753
|
* Uploads executable-line coverage for the test session when backend configuration enables it.
|
|
758
754
|
*
|
|
759
|
-
* @returns {void}
|
|
760
755
|
*/
|
|
761
756
|
reportTestSessionCoverage () {
|
|
762
757
|
const exporter = this.tracer._tracer._exporter
|
|
@@ -785,7 +780,6 @@ class CypressPlugin {
|
|
|
785
780
|
* @param {object} cypressConfig - Cypress resolved config
|
|
786
781
|
* @param {object} tracer - dd-trace proxy tracer
|
|
787
782
|
* @param {object} testOptimizationConfig - Test Optimization config
|
|
788
|
-
* @returns {void}
|
|
789
783
|
*/
|
|
790
784
|
warnIfMisconfiguredTestFailureScreenshots (cypressConfig, tracer, testOptimizationConfig) {
|
|
791
785
|
if (!testOptimizationConfig.DD_TEST_FAILURE_SCREENSHOTS_ENABLED) {
|
|
@@ -816,7 +810,6 @@ class CypressPlugin {
|
|
|
816
810
|
* @param {object} cypressConfig - Cypress resolved config
|
|
817
811
|
* @param {object} tracer - dd-trace proxy tracer
|
|
818
812
|
* @param {object} testOptimizationConfig - Test Optimization config
|
|
819
|
-
* @returns {void}
|
|
820
813
|
*/
|
|
821
814
|
warnIfMisconfiguredTestFailureVideos (cypressConfig, tracer, testOptimizationConfig) {
|
|
822
815
|
if (!testOptimizationConfig.DD_TEST_FAILURE_VIDEOS_ENABLED) return
|
|
@@ -897,6 +890,8 @@ class CypressPlugin {
|
|
|
897
890
|
earlyFlakeDetectionFaultyThreshold,
|
|
898
891
|
isFlakyTestRetriesEnabled,
|
|
899
892
|
flakyTestRetriesCount,
|
|
893
|
+
isDynamicAtrEnabled,
|
|
894
|
+
dynamicAtrBuckets,
|
|
900
895
|
isKnownTestsEnabled,
|
|
901
896
|
isTestManagementEnabled,
|
|
902
897
|
testManagementAttemptToFixRetries,
|
|
@@ -914,13 +909,26 @@ class CypressPlugin {
|
|
|
914
909
|
if (isFlakyTestRetriesEnabled && this.isTestIsolationEnabled) {
|
|
915
910
|
this.isFlakyTestRetriesEnabled = true
|
|
916
911
|
this.flakyTestRetriesCount = flakyTestRetriesCount ?? 0
|
|
912
|
+
this.isDynamicAtrEnabled = isDynamicAtrEnabled ?? false
|
|
913
|
+
this.dynamicAtrBuckets = dynamicAtrBuckets
|
|
917
914
|
if (typeof this.cypressConfig.retries === 'number') {
|
|
918
915
|
this.cypressConfig.retries = {
|
|
919
916
|
openMode: this.cypressConfig.retries,
|
|
920
917
|
runMode: this.cypressConfig.retries,
|
|
921
918
|
}
|
|
922
919
|
}
|
|
923
|
-
|
|
920
|
+
// Dynamic ATR starts at the maximum budget, then narrows each test
|
|
921
|
+
// after its initial duration is known.
|
|
922
|
+
if (this.isDynamicAtrEnabled) {
|
|
923
|
+
this.cypressConfig.retries.runMode = Math.max(
|
|
924
|
+
1,
|
|
925
|
+
this.dynamicAtrBuckets
|
|
926
|
+
? Math.max(...this.dynamicAtrBuckets)
|
|
927
|
+
: this.earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
928
|
+
)
|
|
929
|
+
} else {
|
|
930
|
+
this.cypressConfig.retries.runMode = this.flakyTestRetriesCount
|
|
931
|
+
}
|
|
924
932
|
} else {
|
|
925
933
|
this.flakyTestRetriesCount = 0
|
|
926
934
|
}
|
|
@@ -962,7 +970,6 @@ class CypressPlugin {
|
|
|
962
970
|
* @param {string} testSuite
|
|
963
971
|
* @param {string} testName
|
|
964
972
|
* @param {number | undefined} duration
|
|
965
|
-
* @returns {number}
|
|
966
973
|
*/
|
|
967
974
|
setEfdRetryCountForTest (testSuite, testName, duration) {
|
|
968
975
|
if (!this.efdRetryCountByTest[testSuite]) {
|
|
@@ -979,19 +986,51 @@ class CypressPlugin {
|
|
|
979
986
|
return retryCount
|
|
980
987
|
}
|
|
981
988
|
|
|
989
|
+
/**
|
|
990
|
+
* Stores the dynamic ATR retry count for a test after its first execution duration is known.
|
|
991
|
+
*
|
|
992
|
+
* @param {string} testSuite
|
|
993
|
+
* @param {string} testId
|
|
994
|
+
* @param {number | undefined} duration
|
|
995
|
+
*/
|
|
996
|
+
setDynamicAtrRetryCountForTest (testSuite, testId, duration) {
|
|
997
|
+
if (!this.dynamicAtrRetryCountByTest) {
|
|
998
|
+
this.dynamicAtrRetryCountByTest = new Map()
|
|
999
|
+
}
|
|
1000
|
+
let retryCountByTestId = this.dynamicAtrRetryCountByTest.get(testSuite)
|
|
1001
|
+
if (!retryCountByTestId) {
|
|
1002
|
+
retryCountByTestId = new Map()
|
|
1003
|
+
this.dynamicAtrRetryCountByTest.set(testSuite, retryCountByTestId)
|
|
1004
|
+
}
|
|
1005
|
+
const retryCount = getDynamicAtrRetryCount(
|
|
1006
|
+
duration ?? 0,
|
|
1007
|
+
this.earlyFlakeDetectionRetryPolicy,
|
|
1008
|
+
this.dynamicAtrBuckets
|
|
1009
|
+
)
|
|
1010
|
+
retryCountByTestId.set(testId, retryCount)
|
|
1011
|
+
return retryCount
|
|
1012
|
+
}
|
|
1013
|
+
|
|
982
1014
|
/**
|
|
983
1015
|
* Returns whether an EFD retry clone is beyond the selected retry count and should be discarded.
|
|
984
1016
|
*
|
|
985
1017
|
* @param {string} testSuite
|
|
986
1018
|
* @param {string} testName
|
|
987
1019
|
* @param {number} efdRetryIndex
|
|
988
|
-
* @returns {boolean}
|
|
989
1020
|
*/
|
|
990
1021
|
shouldSkipEfdRetry (testSuite, testName, efdRetryIndex) {
|
|
991
1022
|
const testSuiteRetries = this.efdRetryCountByTest[testSuite]
|
|
992
1023
|
return shouldSkipEfdRetry(efdRetryIndex, testSuiteRetries?.[testName])
|
|
993
1024
|
}
|
|
994
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* @param {string} testSuite
|
|
1028
|
+
* @param {string} testId
|
|
1029
|
+
*/
|
|
1030
|
+
getDynamicAtrRetryCountForTest (testSuite, testId) {
|
|
1031
|
+
return this.dynamicAtrRetryCountByTest.get(testSuite)?.get(testId)
|
|
1032
|
+
}
|
|
1033
|
+
|
|
995
1034
|
getTestSuiteSpan ({ testSuite, testSuiteAbsolutePath }) {
|
|
996
1035
|
const testSuiteSpanMetadata = {
|
|
997
1036
|
...getTestSuiteCommonTags(this.command, this.frameworkVersion, testSuite, TEST_FRAMEWORK_NAME),
|
|
@@ -1012,7 +1051,7 @@ class CypressPlugin {
|
|
|
1012
1051
|
}
|
|
1013
1052
|
}
|
|
1014
1053
|
|
|
1015
|
-
|
|
1054
|
+
const testSuiteSpan = this.tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test_suite`, {
|
|
1016
1055
|
childOf: this.testModuleSpan,
|
|
1017
1056
|
tags: {
|
|
1018
1057
|
[COMPONENT]: TEST_FRAMEWORK_NAME,
|
|
@@ -1021,9 +1060,13 @@ class CypressPlugin {
|
|
|
1021
1060
|
},
|
|
1022
1061
|
integrationName: TEST_FRAMEWORK_NAME,
|
|
1023
1062
|
})
|
|
1063
|
+
this.#pendingTestSuiteSpans.set(testSuite, testSuiteSpan)
|
|
1064
|
+
return testSuiteSpan
|
|
1024
1065
|
}
|
|
1025
1066
|
|
|
1026
|
-
getTestSpan ({
|
|
1067
|
+
getTestSpan ({
|
|
1068
|
+
testName, testSuite, isUnskippable, isForcedToRun, testSourceFile, isDisabled, isQuarantined, startTime,
|
|
1069
|
+
}) {
|
|
1027
1070
|
const testSuiteTags = {
|
|
1028
1071
|
[TEST_MODULE]: TEST_FRAMEWORK_NAME,
|
|
1029
1072
|
}
|
|
@@ -1080,6 +1123,7 @@ class CypressPlugin {
|
|
|
1080
1123
|
|
|
1081
1124
|
return this.tracer.startSpan(`${TEST_FRAMEWORK_NAME}.test`, {
|
|
1082
1125
|
childOf,
|
|
1126
|
+
startTime,
|
|
1083
1127
|
tags: {
|
|
1084
1128
|
[COMPONENT]: TEST_FRAMEWORK_NAME,
|
|
1085
1129
|
[ORIGIN_KEY]: CI_APP_ORIGIN,
|
|
@@ -1312,6 +1356,20 @@ class CypressPlugin {
|
|
|
1312
1356
|
}
|
|
1313
1357
|
|
|
1314
1358
|
afterRun (suiteStats, error) {
|
|
1359
|
+
const pendingFinalizations = []
|
|
1360
|
+
// Late manual initialization cannot intercept a later replacement of after:spec.
|
|
1361
|
+
// Run results let us finalize the suites whose browser hooks already created spans.
|
|
1362
|
+
if (this._isInit && suiteStats?.runs) {
|
|
1363
|
+
for (const result of suiteStats.runs) {
|
|
1364
|
+
const testSuiteSpan = this.#pendingTestSuiteSpans.get(result.spec?.relative)
|
|
1365
|
+
if (!testSuiteSpan) continue
|
|
1366
|
+
this.testSuiteSpan = testSuiteSpan
|
|
1367
|
+
const endedAt = Date.parse(result.stats?.endedAt)
|
|
1368
|
+
const finalization = this.afterSpec(result.spec, result, undefined,
|
|
1369
|
+
Number.isFinite(endedAt) ? endedAt : undefined)
|
|
1370
|
+
if (finalization) pendingFinalizations.push(finalization)
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1315
1373
|
const hasPendingVideoSpans = this.pendingVideoUploads.length > 0
|
|
1316
1374
|
const videoUploadsPromise = this.uploadPendingTestSuiteVideos()
|
|
1317
1375
|
if (!this._isInit) {
|
|
@@ -1322,7 +1380,11 @@ class CypressPlugin {
|
|
|
1322
1380
|
}
|
|
1323
1381
|
return
|
|
1324
1382
|
}
|
|
1325
|
-
|
|
1383
|
+
// Recovered screenshot-only tests must finish before the run closes any remaining trace spans.
|
|
1384
|
+
const finalizeRun = () => this.#finalizeRun(suiteStats, error, hasPendingVideoSpans)
|
|
1385
|
+
const finalizationPromise = pendingFinalizations.length > 0
|
|
1386
|
+
? Promise.all(pendingFinalizations).then(finalizeRun)
|
|
1387
|
+
: finalizeRun()
|
|
1326
1388
|
if (videoUploadsPromise) {
|
|
1327
1389
|
return Promise.all([videoUploadsPromise, finalizationPromise])
|
|
1328
1390
|
.then(() => this.#flushExporter(false))
|
|
@@ -1340,12 +1402,21 @@ class CypressPlugin {
|
|
|
1340
1402
|
*/
|
|
1341
1403
|
#finalizeRun (suiteStats, error, hasPendingVideoSpans = false) {
|
|
1342
1404
|
if (this.testSessionSpan && this.testModuleSpan) {
|
|
1343
|
-
const testStatus = error ? 'fail' : getSessionStatus(suiteStats)
|
|
1405
|
+
const testStatus = error ? 'fail' : getSessionStatus(suiteStats, this.testSuiteStatuses)
|
|
1406
|
+
const hasNoTests = suiteStats?.totalTests === 0 ||
|
|
1407
|
+
(suiteStats?.totalTests === undefined && !this.hasTestsReported)
|
|
1344
1408
|
const hasBackfilledCoverage = this.applySkippedCoverageToTestSessionCoverage()
|
|
1345
1409
|
const testCodeCoverageLinesTotal = this.getTestCodeCoverageLinesTotal(hasBackfilledCoverage)
|
|
1346
1410
|
|
|
1347
1411
|
this.testModuleSpan.setTag(TEST_STATUS, testStatus)
|
|
1348
1412
|
this.testSessionSpan.setTag(TEST_STATUS, testStatus)
|
|
1413
|
+
if (testStatus !== 'fail' && (hasNoTests || testStatus === 'skip')) {
|
|
1414
|
+
setExpectedEmptyTestSessionTags(
|
|
1415
|
+
this.testSessionSpan,
|
|
1416
|
+
this.testModuleSpan,
|
|
1417
|
+
hasNoTests ? 'zero_tests' : 'all_tests_skipped'
|
|
1418
|
+
)
|
|
1419
|
+
}
|
|
1349
1420
|
if (error) {
|
|
1350
1421
|
this.testModuleSpan.setTag('error', error)
|
|
1351
1422
|
this.testSessionSpan.setTag('error', error)
|
|
@@ -1434,7 +1505,6 @@ class CypressPlugin {
|
|
|
1434
1505
|
* Uploads failure screenshots as soon as Cypress creates them.
|
|
1435
1506
|
*
|
|
1436
1507
|
* @param {object} details - Cypress screenshot details
|
|
1437
|
-
* @returns {void}
|
|
1438
1508
|
*/
|
|
1439
1509
|
afterScreenshot (details) {
|
|
1440
1510
|
const lastFailedTestSpan = this.lastFinishedTest?.testStatus === 'fail'
|
|
@@ -1459,9 +1529,10 @@ class CypressPlugin {
|
|
|
1459
1529
|
}
|
|
1460
1530
|
}
|
|
1461
1531
|
|
|
1462
|
-
afterSpec (spec, results, error) {
|
|
1463
|
-
const { tests, stats, screenshots, video } = results || {}
|
|
1532
|
+
afterSpec (spec, results, error, finishTime) {
|
|
1533
|
+
const { tests, stats, screenshots, video, error: resultError } = results || {}
|
|
1464
1534
|
const cypressTests = tests || []
|
|
1535
|
+
if (cypressTests.length > 0 || stats?.tests > 0) this.hasTestsReported = true
|
|
1465
1536
|
const specScreenshots = screenshots || []
|
|
1466
1537
|
const finishedTests = this.finishedTestsByFile[spec.relative] || []
|
|
1467
1538
|
const screenshotUploadPromises = []
|
|
@@ -1494,7 +1565,10 @@ class CypressPlugin {
|
|
|
1494
1565
|
? getTestSuitePath(spec.absolute, this.repositoryRoot)
|
|
1495
1566
|
: spec.relative
|
|
1496
1567
|
|
|
1497
|
-
|
|
1568
|
+
// Recovered tests that never ran have no execution time; keep them at the recorded suite end.
|
|
1569
|
+
const skippedTestSpan = this.getTestSpan({
|
|
1570
|
+
testName: cypressTestName, testSuite: spec.relative, testSourceFile, startTime: finishTime,
|
|
1571
|
+
})
|
|
1498
1572
|
skippedTestSpan.setTag(TEST_FINAL_STATUS, 'skip')
|
|
1499
1573
|
|
|
1500
1574
|
skippedTestSpan.setTag(TEST_STATUS, 'skip')
|
|
@@ -1532,7 +1606,7 @@ class CypressPlugin {
|
|
|
1532
1606
|
})
|
|
1533
1607
|
}
|
|
1534
1608
|
|
|
1535
|
-
testSpanFinishes.push({ testSpan: skippedTestSpan, finishTime: this._now() })
|
|
1609
|
+
testSpanFinishes.push({ testSpan: skippedTestSpan, finishTime: finishTime ?? this._now() })
|
|
1536
1610
|
}
|
|
1537
1611
|
|
|
1538
1612
|
// Make sure that reported test statuses are the same as Cypress reports.
|
|
@@ -1540,33 +1614,41 @@ class CypressPlugin {
|
|
|
1540
1614
|
// Cypress will report the last run test as failed, but we don't know that yet at `dd:afterEach`
|
|
1541
1615
|
let latestError
|
|
1542
1616
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1617
|
+
// Cypress preserves IDs across retry clones, so duplicate titles remain independent.
|
|
1618
|
+
const finishedTestsByTest = new Map()
|
|
1619
|
+
for (const finishedTest of finishedTests) {
|
|
1620
|
+
const testIdentifier = finishedTest.testId ?? finishedTest.testName
|
|
1621
|
+
let finishedTestAttempts = finishedTestsByTest.get(testIdentifier)
|
|
1622
|
+
if (!finishedTestAttempts) {
|
|
1623
|
+
finishedTestAttempts = []
|
|
1624
|
+
finishedTestsByTest.set(testIdentifier, finishedTestAttempts)
|
|
1546
1625
|
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
}, {})
|
|
1626
|
+
finishedTestAttempts.push(finishedTest)
|
|
1627
|
+
}
|
|
1550
1628
|
|
|
1551
|
-
|
|
1629
|
+
const matchedCypressTests = new Set()
|
|
1630
|
+
for (const finishedTestAttempts of finishedTestsByTest.values()) {
|
|
1631
|
+
const { testName } = finishedTestAttempts[0]
|
|
1632
|
+
// Cypress reports one result per original runnable, including Datadog-managed clones.
|
|
1633
|
+
// Public results omit runnable IDs but retain declaration order.
|
|
1634
|
+
const cypressTest = cypressTests.find(test =>
|
|
1635
|
+
test.title.join(' ') === testName && !matchedCypressTests.has(test)
|
|
1636
|
+
)
|
|
1637
|
+
matchedCypressTests.add(cypressTest)
|
|
1552
1638
|
for (const [attemptIndex, finishedTest] of finishedTestAttempts.entries()) {
|
|
1553
1639
|
// We can check if this is the last attempt regardless of the retry mechanism
|
|
1554
1640
|
const isLastAttempt = attemptIndex === finishedTestAttempts.length - 1
|
|
1555
1641
|
const isDatadogManagedAttempt = finishedTest.isEfdManagedTest || finishedTest.isAttemptToFix
|
|
1556
|
-
const cypressTest = isDatadogManagedAttempt
|
|
1557
|
-
? getMatchingCypressTest(cypressTests, testName, attemptIndex, finishedTest.testStatus, isLastAttempt) ||
|
|
1558
|
-
cypressTests.find(test => test.title.join(' ') === testName)
|
|
1559
|
-
: cypressTests.find(test => test.title.join(' ') === testName)
|
|
1560
1642
|
if (!cypressTest) {
|
|
1561
1643
|
continue
|
|
1562
1644
|
}
|
|
1563
1645
|
// finishedTests can include multiple tests with the same name if they have been retried
|
|
1564
1646
|
// by early flake detection. Cypress is unaware of this so .attempts does not necessarily have
|
|
1565
1647
|
// the same length as `finishedTestAttempts`
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
? finishedTest.testStatus
|
|
1569
|
-
|
|
1648
|
+
let cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state]
|
|
1649
|
+
if (isDatadogManagedAttempt) {
|
|
1650
|
+
cypressTestStatus = isLastAttempt && isCypressHookFailure(cypressTest) ? 'fail' : finishedTest.testStatus
|
|
1651
|
+
}
|
|
1570
1652
|
if (!finishedTest.isEfdManagedTest && !finishedTest.isAttemptToFix &&
|
|
1571
1653
|
cypressTest.attempts && cypressTest.attempts[attemptIndex]) {
|
|
1572
1654
|
cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.attempts[attemptIndex].state]
|
|
@@ -1648,9 +1730,22 @@ class CypressPlugin {
|
|
|
1648
1730
|
finishedTest,
|
|
1649
1731
|
finishedTestAttempts,
|
|
1650
1732
|
flakyTestRetriesCount: this.flakyTestRetriesCount,
|
|
1733
|
+
isDynamicAtrEnabled: this.isDynamicAtrEnabled,
|
|
1651
1734
|
})
|
|
1652
1735
|
|
|
1653
|
-
|
|
1736
|
+
let hasFailedAllAttempts = testSpanTags[TEST_HAS_FAILED_ALL_RETRIES] === 'true'
|
|
1737
|
+
if (retryKind === FINAL_STATUS_RETRY_KIND.atr) {
|
|
1738
|
+
// Late hooks can change every attempt after dd:afterEach has captured its status.
|
|
1739
|
+
hasFailedAllAttempts = finishedTestAttempts.every(attempt =>
|
|
1740
|
+
attempt.testSpan.context().getTag(TEST_STATUS) === 'fail'
|
|
1741
|
+
)
|
|
1742
|
+
const atrRetryCount = this.isDynamicAtrEnabled
|
|
1743
|
+
? this.getDynamicAtrRetryCountForTest(spec.relative, finishedTest.testId)
|
|
1744
|
+
: this.flakyTestRetriesCount
|
|
1745
|
+
// An aborted run can fail without using the entire selected retry budget.
|
|
1746
|
+
const hasFailedAllRetries = hasFailedAllAttempts && finishedTestAttempts.length > atrRetryCount
|
|
1747
|
+
finishedTest.testSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, hasFailedAllRetries ? 'true' : undefined)
|
|
1748
|
+
}
|
|
1654
1749
|
const hasPassedAllAtfRetries =
|
|
1655
1750
|
testSpanTags[TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED] === 'true'
|
|
1656
1751
|
const isQuarantined = testSpanTags[TEST_MANAGEMENT_IS_QUARANTINED] === 'true'
|
|
@@ -1659,7 +1754,7 @@ class CypressPlugin {
|
|
|
1659
1754
|
const finalStatus = getFinalStatus({
|
|
1660
1755
|
status: cypressTestStatus,
|
|
1661
1756
|
retryKind,
|
|
1662
|
-
|
|
1757
|
+
hasFailedAllAttempts,
|
|
1663
1758
|
hasPassedAllAtfRetries,
|
|
1664
1759
|
isQuarantined,
|
|
1665
1760
|
isDisabled,
|
|
@@ -1682,8 +1777,13 @@ class CypressPlugin {
|
|
|
1682
1777
|
}
|
|
1683
1778
|
}
|
|
1684
1779
|
|
|
1685
|
-
const testSuiteFinishTime = this._now()
|
|
1686
|
-
const
|
|
1780
|
+
const testSuiteFinishTime = finishTime ?? this._now()
|
|
1781
|
+
const suiteError = error || resultError || latestError
|
|
1782
|
+
const suiteStatus = suiteError ||
|
|
1783
|
+
cypressTests.some(test => CYPRESS_STATUS_TO_TEST_STATUS[test.state] === 'fail')
|
|
1784
|
+
? 'fail'
|
|
1785
|
+
: getSuiteStatus(stats)
|
|
1786
|
+
this.testSuiteStatuses.add(suiteStatus)
|
|
1687
1787
|
const testSuiteSpan = this.testSuiteSpan
|
|
1688
1788
|
const uploadOptions = {
|
|
1689
1789
|
filePath: video,
|
|
@@ -1694,11 +1794,12 @@ class CypressPlugin {
|
|
|
1694
1794
|
? testSuiteSpan.context().toSpanId()
|
|
1695
1795
|
: undefined,
|
|
1696
1796
|
}
|
|
1697
|
-
const shouldUploadVideo =
|
|
1797
|
+
const shouldUploadVideo = suiteStatus === 'fail' && this.#canUploadTestSuiteVideo(uploadOptions)
|
|
1698
1798
|
if (testSuiteSpan) {
|
|
1699
|
-
testSuiteSpan.setTag(TEST_STATUS,
|
|
1700
|
-
if (
|
|
1799
|
+
testSuiteSpan.setTag(TEST_STATUS, suiteStatus)
|
|
1800
|
+
if (suiteError) testSuiteSpan.setTag('error', suiteError)
|
|
1701
1801
|
this.testSuiteSpan = null
|
|
1802
|
+
this.#pendingTestSuiteSpans.delete(spec.relative)
|
|
1702
1803
|
}
|
|
1703
1804
|
|
|
1704
1805
|
let testSpansPromise
|
|
@@ -1838,7 +1939,6 @@ class CypressPlugin {
|
|
|
1838
1939
|
* @param {string|undefined} options.filePath - Cypress video path
|
|
1839
1940
|
* @param {string|undefined} options.testSessionId - Test session id
|
|
1840
1941
|
* @param {string|undefined} options.testSuiteId - Test suite id
|
|
1841
|
-
* @returns {boolean}
|
|
1842
1942
|
*/
|
|
1843
1943
|
#canUploadTestSuiteVideo ({ filePath, testSessionId, testSuiteId }) {
|
|
1844
1944
|
const exporter = this.tracer?._tracer?._exporter
|
|
@@ -1936,7 +2036,14 @@ class CypressPlugin {
|
|
|
1936
2036
|
|
|
1937
2037
|
getTasks () {
|
|
1938
2038
|
return {
|
|
1939
|
-
'dd:testSuiteStart': ({ testSuite, testSuiteAbsolutePath }) => {
|
|
2039
|
+
'dd:testSuiteStart': ({ testSuite, testSuiteAbsolutePath, isTextTerminal: browserIsTextTerminal }) => {
|
|
2040
|
+
// Cypress 6 omits the execution mode from the Node plugin configuration.
|
|
2041
|
+
const isTextTerminal = this.cypressConfig.isTextTerminal ?? browserIsTextTerminal
|
|
2042
|
+
if (!isTextTerminal) {
|
|
2043
|
+
this.isFlakyTestRetriesEnabled = false
|
|
2044
|
+
this.isDynamicAtrEnabled = false
|
|
2045
|
+
this.flakyTestRetriesCount = 0
|
|
2046
|
+
}
|
|
1940
2047
|
const suitePayload = {
|
|
1941
2048
|
isEarlyFlakeDetectionEnabled:
|
|
1942
2049
|
this.isEarlyFlakeDetectionEnabled && hasEfdRetries(this.earlyFlakeDetectionRetryPolicy),
|
|
@@ -1950,14 +2057,18 @@ class CypressPlugin {
|
|
|
1950
2057
|
isModifiedTest: this.getIsTestModified(testSuiteAbsolutePath),
|
|
1951
2058
|
repositoryRoot: this.repositoryRoot,
|
|
1952
2059
|
isTestIsolationEnabled: this.isTestIsolationEnabled,
|
|
2060
|
+
isDynamicAtrEnabled: this.isDynamicAtrEnabled,
|
|
2061
|
+
isTextTerminal,
|
|
1953
2062
|
rumFlushWaitMillis: this.rumFlushWaitMillis,
|
|
1954
2063
|
rumTestExecutionIdCookieName: RUM_TEST_EXECUTION_ID_COOKIE_NAME,
|
|
1955
2064
|
}
|
|
1956
2065
|
|
|
1957
|
-
this.testSuiteSpan
|
|
2066
|
+
this.testSuiteSpan = this.#pendingTestSuiteSpans.get(testSuite) ||
|
|
2067
|
+
this.getTestSuiteSpan({ testSuite, testSuiteAbsolutePath })
|
|
1958
2068
|
return suitePayload
|
|
1959
2069
|
},
|
|
1960
2070
|
'dd:beforeEach': (test) => {
|
|
2071
|
+
this.hasTestsReported = true
|
|
1961
2072
|
const { testId, testName, testSuite, isEfdRetry, efdRetryIndex } = test
|
|
1962
2073
|
if (isEfdRetry && this.shouldSkipEfdRetry(testSuite, testName, efdRetryIndex)) {
|
|
1963
2074
|
return { shouldSkip: true, shouldDiscard: true }
|
|
@@ -2016,6 +2127,7 @@ class CypressPlugin {
|
|
|
2016
2127
|
testSourceStack,
|
|
2017
2128
|
testSuite,
|
|
2018
2129
|
testSuiteAbsolutePath,
|
|
2130
|
+
testId,
|
|
2019
2131
|
testName,
|
|
2020
2132
|
testItTitle,
|
|
2021
2133
|
isNew,
|
|
@@ -2064,12 +2176,23 @@ class CypressPlugin {
|
|
|
2064
2176
|
this.activeTestSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'slow')
|
|
2065
2177
|
}
|
|
2066
2178
|
}
|
|
2179
|
+
// Dynamic ATR: after the first attempt, compute the duration-based retry budget.
|
|
2180
|
+
if (
|
|
2181
|
+
this.isDynamicAtrEnabled &&
|
|
2182
|
+
this.isFlakyTestRetriesEnabled &&
|
|
2183
|
+
!isAttemptToFix &&
|
|
2184
|
+
!isEfdRetry &&
|
|
2185
|
+
!isEfdManagedTest &&
|
|
2186
|
+
this.getDynamicAtrRetryCountForTest(testSuite, testId) === undefined
|
|
2187
|
+
) {
|
|
2188
|
+
this.setDynamicAtrRetryCountForTest(testSuite, testId, duration)
|
|
2189
|
+
}
|
|
2067
2190
|
if (didAbortSlowEfdRetries && testStatus === 'skip' && !error && duration > 0) {
|
|
2068
2191
|
testStatus = 'pass'
|
|
2069
2192
|
}
|
|
2070
2193
|
this.activeTestSpan.setTag(TEST_STATUS, testStatus)
|
|
2071
2194
|
|
|
2072
|
-
const testIdentifier = `${testSuite}\0${testName}`
|
|
2195
|
+
const testIdentifier = `${testSuite}\0${testId ?? testName}`
|
|
2073
2196
|
let testStatuses = this.testStatuses[testIdentifier]
|
|
2074
2197
|
if (testStatuses) {
|
|
2075
2198
|
testStatuses.push(testStatus)
|
|
@@ -2160,8 +2283,10 @@ class CypressPlugin {
|
|
|
2160
2283
|
})
|
|
2161
2284
|
}
|
|
2162
2285
|
// ATR: set TEST_HAS_FAILED_ALL_RETRIES when all auto test retries were exhausted and every attempt failed
|
|
2286
|
+
const dynamicAtrRetryCount = this.getDynamicAtrRetryCountForTest(testSuite, testId)
|
|
2287
|
+
const atrRetryCount = this.isDynamicAtrEnabled ? dynamicAtrRetryCount : this.flakyTestRetriesCount
|
|
2163
2288
|
if (this.isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry &&
|
|
2164
|
-
|
|
2289
|
+
atrRetryCount > 0 && testStatuses.length === atrRetryCount + 1 &&
|
|
2165
2290
|
testStatuses.every(status => status === 'fail')) {
|
|
2166
2291
|
this.activeTestSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
|
|
2167
2292
|
}
|
|
@@ -2201,6 +2326,7 @@ class CypressPlugin {
|
|
|
2201
2326
|
}
|
|
2202
2327
|
|
|
2203
2328
|
const finishedTest = {
|
|
2329
|
+
testId,
|
|
2204
2330
|
testName,
|
|
2205
2331
|
testStatus,
|
|
2206
2332
|
finishTime: this._now(),
|
|
@@ -2227,7 +2353,7 @@ class CypressPlugin {
|
|
|
2227
2353
|
})
|
|
2228
2354
|
this.activeTestSpan = null
|
|
2229
2355
|
|
|
2230
|
-
return null
|
|
2356
|
+
return dynamicAtrRetryCount === undefined ? null : { dynamicAtrRetryCount }
|
|
2231
2357
|
},
|
|
2232
2358
|
'dd:addTags': (tags) => {
|
|
2233
2359
|
if (this.activeTestSpan) {
|