dd-trace 6.16.0 → 6.17.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 +165 -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 +72 -12
- package/packages/datadog-instrumentations/src/cypress-config.js +0 -23
- package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -0
- 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 +4 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +72 -24
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +12 -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/targets.json +16 -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 +141 -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 +22 -25
- 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 +3 -16
- package/packages/datadog-instrumentations/src/playwright.js +238 -55
- package/packages/datadog-instrumentations/src/postgres.js +7 -0
- 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/vitest-main-no-worker-init.js +18 -18
- package/packages/datadog-instrumentations/src/vitest-main.js +37 -17
- 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 +23 -42
- package/packages/datadog-instrumentations/src/ws.js +0 -1
- 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 +10 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +171 -75
- package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
- 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 +13 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
- package/packages/datadog-plugin-mocha/src/index.js +39 -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 +76 -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 +10 -0
- package/packages/datadog-plugin-ws/src/util.js +0 -4
- package/packages/datadog-turbopack/index.js +0 -6
- package/packages/datadog-turbopack/src/loader.js +0 -16
- package/packages/datadog-webpack/src/loader.js +0 -1
- 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 +73 -67
- package/packages/dd-trace/src/config/helper.js +0 -1
- package/packages/dd-trace/src/config/index.js +24 -24
- 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 +139 -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 +2 -0
- 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 +40 -14
- 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-pruner.js +0 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -6
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
- package/packages/dd-trace/src/debugger/index.js +50 -2
- 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/discovery.js +0 -1
- package/packages/dd-trace/src/evp_proxy/path.js +0 -2
- 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 +0 -2
- 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 +639 -0
- package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +92 -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 +30 -7
- 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/encoding.js +0 -2
- package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/index.js +0 -4
- 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 +0 -6
- package/packages/dd-trace/src/openfeature/writers/exposures.js +0 -5
- package/packages/dd-trace/src/openfeature/writers/util.js +0 -4
- 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/otel-thread-ctx.js +38 -11
- package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +0 -1
- 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 +21 -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 +21 -45
- 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/telemetry.js +4 -1
- package/packages/dd-trace/src/util.js +13 -1
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
|
@@ -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,8 +233,13 @@ 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
245
|
if (summary.totalSkipped !== undefined && summary.totalSkipped === summary.totalTests) {
|
|
@@ -378,33 +387,10 @@ function getSuiteStatus (suiteStats) {
|
|
|
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'
|
|
@@ -464,6 +455,8 @@ class CypressPlugin {
|
|
|
464
455
|
testEnvironmentMetadata = getTestEnvironmentMetadata(TEST_FRAMEWORK_NAME)
|
|
465
456
|
|
|
466
457
|
finishedTestsByFile = {}
|
|
458
|
+
hasTestsReported = false
|
|
459
|
+
testSuiteStatuses = new Set()
|
|
467
460
|
testStatuses = {}
|
|
468
461
|
hasLibraryConfiguration = false
|
|
469
462
|
isItrEnabled = false
|
|
@@ -473,6 +466,9 @@ class CypressPlugin {
|
|
|
473
466
|
isCoverageReportUploadEnabled = false
|
|
474
467
|
isFlakyTestRetriesEnabled = false
|
|
475
468
|
flakyTestRetriesCount = 0
|
|
469
|
+
isDynamicAtrEnabled = false
|
|
470
|
+
dynamicAtrBuckets = undefined
|
|
471
|
+
dynamicAtrRetryCountByTest = new Map()
|
|
476
472
|
isEarlyFlakeDetectionEnabled = false
|
|
477
473
|
isEarlyFlakeDetectionFaulty = false
|
|
478
474
|
isKnownTestsEnabled = false
|
|
@@ -550,11 +546,12 @@ class CypressPlugin {
|
|
|
550
546
|
* Resets state that is scoped to a single Cypress run so the singleton plugin
|
|
551
547
|
* can be reused safely across multiple programmatic cypress.run() calls.
|
|
552
548
|
*
|
|
553
|
-
* @returns {void}
|
|
554
549
|
*/
|
|
555
550
|
resetRunState () {
|
|
556
551
|
this._isInit = false
|
|
557
552
|
this.finishedTestsByFile = {}
|
|
553
|
+
this.hasTestsReported = false
|
|
554
|
+
this.testSuiteStatuses = new Set()
|
|
558
555
|
this.testStatuses = {}
|
|
559
556
|
this.hasLibraryConfiguration = false
|
|
560
557
|
this.isItrEnabled = false
|
|
@@ -564,6 +561,9 @@ class CypressPlugin {
|
|
|
564
561
|
this.isCoverageReportUploadEnabled = false
|
|
565
562
|
this.isFlakyTestRetriesEnabled = false
|
|
566
563
|
this.flakyTestRetriesCount = 0
|
|
564
|
+
this.isDynamicAtrEnabled = false
|
|
565
|
+
this.dynamicAtrBuckets = undefined
|
|
566
|
+
this.dynamicAtrRetryCountByTest = new Map()
|
|
567
567
|
this.isEarlyFlakeDetectionEnabled = false
|
|
568
568
|
this.isEarlyFlakeDetectionFaulty = false
|
|
569
569
|
this.isKnownTestsEnabled = false
|
|
@@ -630,7 +630,6 @@ class CypressPlugin {
|
|
|
630
630
|
*
|
|
631
631
|
* @param {string} traceId - Test trace id used for the upload
|
|
632
632
|
* @param {Promise<string|undefined>} uploadPromise - Promise resolving to the upload outcome
|
|
633
|
-
* @returns {void}
|
|
634
633
|
*/
|
|
635
634
|
addScreenshotUploadPromise (traceId, uploadPromise) {
|
|
636
635
|
const uploadPromises = this.screenshotUploadPromisesByTraceId.get(traceId)
|
|
@@ -659,7 +658,6 @@ class CypressPlugin {
|
|
|
659
658
|
* Cancels screenshot work that must not outlive an errored after:spec finalization boundary.
|
|
660
659
|
*
|
|
661
660
|
* @param {Error} error - Error that triggered finalization
|
|
662
|
-
* @returns {void}
|
|
663
661
|
*/
|
|
664
662
|
abortPendingScreenshotUploads (error) {
|
|
665
663
|
for (const controller of this.screenshotUploadAbortControllers) controller.abort(error)
|
|
@@ -673,7 +671,6 @@ class CypressPlugin {
|
|
|
673
671
|
* start/finish. Captured at session span creation so it shares the same
|
|
674
672
|
* epoch as the trace without reaching into span internals.
|
|
675
673
|
*
|
|
676
|
-
* @returns {number}
|
|
677
674
|
*/
|
|
678
675
|
_now () {
|
|
679
676
|
return this._timeOrigin + performance.now() - this._perfOrigin
|
|
@@ -682,7 +679,6 @@ class CypressPlugin {
|
|
|
682
679
|
/**
|
|
683
680
|
* Returns the directory used to normalize coverage file names.
|
|
684
681
|
*
|
|
685
|
-
* @returns {string}
|
|
686
682
|
*/
|
|
687
683
|
getCoverageRootDir () {
|
|
688
684
|
return this.repositoryRoot || this.rootDir || process.cwd()
|
|
@@ -691,7 +687,6 @@ class CypressPlugin {
|
|
|
691
687
|
/**
|
|
692
688
|
* Returns whether skipped test coverage should be backfilled into the session coverage map.
|
|
693
689
|
*
|
|
694
|
-
* @returns {boolean}
|
|
695
690
|
*/
|
|
696
691
|
shouldBackfillSkippedCoverage () {
|
|
697
692
|
return this.isItrEnabled &&
|
|
@@ -704,7 +699,6 @@ class CypressPlugin {
|
|
|
704
699
|
* Adds a test's Istanbul coverage to the aggregated session coverage map.
|
|
705
700
|
*
|
|
706
701
|
* @param {object} coverage
|
|
707
|
-
* @returns {void}
|
|
708
702
|
*/
|
|
709
703
|
addTestSessionCoverage (coverage) {
|
|
710
704
|
mergeCoverage(coverage, this.testSessionCoverageMap)
|
|
@@ -713,7 +707,6 @@ class CypressPlugin {
|
|
|
713
707
|
/**
|
|
714
708
|
* Applies backend skipped-test coverage to the aggregated session coverage map.
|
|
715
709
|
*
|
|
716
|
-
* @returns {boolean}
|
|
717
710
|
*/
|
|
718
711
|
applySkippedCoverageToTestSessionCoverage () {
|
|
719
712
|
if (!this.shouldBackfillSkippedCoverage()) {
|
|
@@ -756,7 +749,6 @@ class CypressPlugin {
|
|
|
756
749
|
/**
|
|
757
750
|
* Uploads executable-line coverage for the test session when backend configuration enables it.
|
|
758
751
|
*
|
|
759
|
-
* @returns {void}
|
|
760
752
|
*/
|
|
761
753
|
reportTestSessionCoverage () {
|
|
762
754
|
const exporter = this.tracer._tracer._exporter
|
|
@@ -785,7 +777,6 @@ class CypressPlugin {
|
|
|
785
777
|
* @param {object} cypressConfig - Cypress resolved config
|
|
786
778
|
* @param {object} tracer - dd-trace proxy tracer
|
|
787
779
|
* @param {object} testOptimizationConfig - Test Optimization config
|
|
788
|
-
* @returns {void}
|
|
789
780
|
*/
|
|
790
781
|
warnIfMisconfiguredTestFailureScreenshots (cypressConfig, tracer, testOptimizationConfig) {
|
|
791
782
|
if (!testOptimizationConfig.DD_TEST_FAILURE_SCREENSHOTS_ENABLED) {
|
|
@@ -816,7 +807,6 @@ class CypressPlugin {
|
|
|
816
807
|
* @param {object} cypressConfig - Cypress resolved config
|
|
817
808
|
* @param {object} tracer - dd-trace proxy tracer
|
|
818
809
|
* @param {object} testOptimizationConfig - Test Optimization config
|
|
819
|
-
* @returns {void}
|
|
820
810
|
*/
|
|
821
811
|
warnIfMisconfiguredTestFailureVideos (cypressConfig, tracer, testOptimizationConfig) {
|
|
822
812
|
if (!testOptimizationConfig.DD_TEST_FAILURE_VIDEOS_ENABLED) return
|
|
@@ -897,6 +887,8 @@ class CypressPlugin {
|
|
|
897
887
|
earlyFlakeDetectionFaultyThreshold,
|
|
898
888
|
isFlakyTestRetriesEnabled,
|
|
899
889
|
flakyTestRetriesCount,
|
|
890
|
+
isDynamicAtrEnabled,
|
|
891
|
+
dynamicAtrBuckets,
|
|
900
892
|
isKnownTestsEnabled,
|
|
901
893
|
isTestManagementEnabled,
|
|
902
894
|
testManagementAttemptToFixRetries,
|
|
@@ -914,13 +906,26 @@ class CypressPlugin {
|
|
|
914
906
|
if (isFlakyTestRetriesEnabled && this.isTestIsolationEnabled) {
|
|
915
907
|
this.isFlakyTestRetriesEnabled = true
|
|
916
908
|
this.flakyTestRetriesCount = flakyTestRetriesCount ?? 0
|
|
909
|
+
this.isDynamicAtrEnabled = isDynamicAtrEnabled ?? false
|
|
910
|
+
this.dynamicAtrBuckets = dynamicAtrBuckets
|
|
917
911
|
if (typeof this.cypressConfig.retries === 'number') {
|
|
918
912
|
this.cypressConfig.retries = {
|
|
919
913
|
openMode: this.cypressConfig.retries,
|
|
920
914
|
runMode: this.cypressConfig.retries,
|
|
921
915
|
}
|
|
922
916
|
}
|
|
923
|
-
|
|
917
|
+
// Dynamic ATR starts at the maximum budget, then narrows each test
|
|
918
|
+
// after its initial duration is known.
|
|
919
|
+
if (this.isDynamicAtrEnabled) {
|
|
920
|
+
this.cypressConfig.retries.runMode = Math.max(
|
|
921
|
+
1,
|
|
922
|
+
this.dynamicAtrBuckets
|
|
923
|
+
? Math.max(...this.dynamicAtrBuckets)
|
|
924
|
+
: this.earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
925
|
+
)
|
|
926
|
+
} else {
|
|
927
|
+
this.cypressConfig.retries.runMode = this.flakyTestRetriesCount
|
|
928
|
+
}
|
|
924
929
|
} else {
|
|
925
930
|
this.flakyTestRetriesCount = 0
|
|
926
931
|
}
|
|
@@ -962,7 +967,6 @@ class CypressPlugin {
|
|
|
962
967
|
* @param {string} testSuite
|
|
963
968
|
* @param {string} testName
|
|
964
969
|
* @param {number | undefined} duration
|
|
965
|
-
* @returns {number}
|
|
966
970
|
*/
|
|
967
971
|
setEfdRetryCountForTest (testSuite, testName, duration) {
|
|
968
972
|
if (!this.efdRetryCountByTest[testSuite]) {
|
|
@@ -979,19 +983,51 @@ class CypressPlugin {
|
|
|
979
983
|
return retryCount
|
|
980
984
|
}
|
|
981
985
|
|
|
986
|
+
/**
|
|
987
|
+
* Stores the dynamic ATR retry count for a test after its first execution duration is known.
|
|
988
|
+
*
|
|
989
|
+
* @param {string} testSuite
|
|
990
|
+
* @param {string} testId
|
|
991
|
+
* @param {number | undefined} duration
|
|
992
|
+
*/
|
|
993
|
+
setDynamicAtrRetryCountForTest (testSuite, testId, duration) {
|
|
994
|
+
if (!this.dynamicAtrRetryCountByTest) {
|
|
995
|
+
this.dynamicAtrRetryCountByTest = new Map()
|
|
996
|
+
}
|
|
997
|
+
let retryCountByTestId = this.dynamicAtrRetryCountByTest.get(testSuite)
|
|
998
|
+
if (!retryCountByTestId) {
|
|
999
|
+
retryCountByTestId = new Map()
|
|
1000
|
+
this.dynamicAtrRetryCountByTest.set(testSuite, retryCountByTestId)
|
|
1001
|
+
}
|
|
1002
|
+
const retryCount = getDynamicAtrRetryCount(
|
|
1003
|
+
duration ?? 0,
|
|
1004
|
+
this.earlyFlakeDetectionRetryPolicy,
|
|
1005
|
+
this.dynamicAtrBuckets
|
|
1006
|
+
)
|
|
1007
|
+
retryCountByTestId.set(testId, retryCount)
|
|
1008
|
+
return retryCount
|
|
1009
|
+
}
|
|
1010
|
+
|
|
982
1011
|
/**
|
|
983
1012
|
* Returns whether an EFD retry clone is beyond the selected retry count and should be discarded.
|
|
984
1013
|
*
|
|
985
1014
|
* @param {string} testSuite
|
|
986
1015
|
* @param {string} testName
|
|
987
1016
|
* @param {number} efdRetryIndex
|
|
988
|
-
* @returns {boolean}
|
|
989
1017
|
*/
|
|
990
1018
|
shouldSkipEfdRetry (testSuite, testName, efdRetryIndex) {
|
|
991
1019
|
const testSuiteRetries = this.efdRetryCountByTest[testSuite]
|
|
992
1020
|
return shouldSkipEfdRetry(efdRetryIndex, testSuiteRetries?.[testName])
|
|
993
1021
|
}
|
|
994
1022
|
|
|
1023
|
+
/**
|
|
1024
|
+
* @param {string} testSuite
|
|
1025
|
+
* @param {string} testId
|
|
1026
|
+
*/
|
|
1027
|
+
getDynamicAtrRetryCountForTest (testSuite, testId) {
|
|
1028
|
+
return this.dynamicAtrRetryCountByTest.get(testSuite)?.get(testId)
|
|
1029
|
+
}
|
|
1030
|
+
|
|
995
1031
|
getTestSuiteSpan ({ testSuite, testSuiteAbsolutePath }) {
|
|
996
1032
|
const testSuiteSpanMetadata = {
|
|
997
1033
|
...getTestSuiteCommonTags(this.command, this.frameworkVersion, testSuite, TEST_FRAMEWORK_NAME),
|
|
@@ -1340,12 +1376,22 @@ class CypressPlugin {
|
|
|
1340
1376
|
*/
|
|
1341
1377
|
#finalizeRun (suiteStats, error, hasPendingVideoSpans = false) {
|
|
1342
1378
|
if (this.testSessionSpan && this.testModuleSpan) {
|
|
1343
|
-
const testStatus = error ? 'fail' : getSessionStatus(suiteStats)
|
|
1379
|
+
const testStatus = error ? 'fail' : getSessionStatus(suiteStats, this.testSuiteStatuses)
|
|
1380
|
+
const hasNoTests = suiteStats?.totalTests === 0 ||
|
|
1381
|
+
(suiteStats?.totalTests === undefined && !this.hasTestsReported)
|
|
1344
1382
|
const hasBackfilledCoverage = this.applySkippedCoverageToTestSessionCoverage()
|
|
1345
1383
|
const testCodeCoverageLinesTotal = this.getTestCodeCoverageLinesTotal(hasBackfilledCoverage)
|
|
1346
1384
|
|
|
1347
1385
|
this.testModuleSpan.setTag(TEST_STATUS, testStatus)
|
|
1348
1386
|
this.testSessionSpan.setTag(TEST_STATUS, testStatus)
|
|
1387
|
+
if (testStatus !== 'fail' && hasNoTests) {
|
|
1388
|
+
setExpectedEmptyTestSessionTags(
|
|
1389
|
+
this.testSessionSpan,
|
|
1390
|
+
this.testModuleSpan,
|
|
1391
|
+
'No tests were executed',
|
|
1392
|
+
'zero_tests'
|
|
1393
|
+
)
|
|
1394
|
+
}
|
|
1349
1395
|
if (error) {
|
|
1350
1396
|
this.testModuleSpan.setTag('error', error)
|
|
1351
1397
|
this.testSessionSpan.setTag('error', error)
|
|
@@ -1434,7 +1480,6 @@ class CypressPlugin {
|
|
|
1434
1480
|
* Uploads failure screenshots as soon as Cypress creates them.
|
|
1435
1481
|
*
|
|
1436
1482
|
* @param {object} details - Cypress screenshot details
|
|
1437
|
-
* @returns {void}
|
|
1438
1483
|
*/
|
|
1439
1484
|
afterScreenshot (details) {
|
|
1440
1485
|
const lastFailedTestSpan = this.lastFinishedTest?.testStatus === 'fail'
|
|
@@ -1460,8 +1505,9 @@ class CypressPlugin {
|
|
|
1460
1505
|
}
|
|
1461
1506
|
|
|
1462
1507
|
afterSpec (spec, results, error) {
|
|
1463
|
-
const { tests, stats, screenshots, video } = results || {}
|
|
1508
|
+
const { tests, stats, screenshots, video, error: resultError } = results || {}
|
|
1464
1509
|
const cypressTests = tests || []
|
|
1510
|
+
if (cypressTests.length > 0) this.hasTestsReported = true
|
|
1465
1511
|
const specScreenshots = screenshots || []
|
|
1466
1512
|
const finishedTests = this.finishedTestsByFile[spec.relative] || []
|
|
1467
1513
|
const screenshotUploadPromises = []
|
|
@@ -1540,33 +1586,41 @@ class CypressPlugin {
|
|
|
1540
1586
|
// Cypress will report the last run test as failed, but we don't know that yet at `dd:afterEach`
|
|
1541
1587
|
let latestError
|
|
1542
1588
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1589
|
+
// Cypress preserves IDs across retry clones, so duplicate titles remain independent.
|
|
1590
|
+
const finishedTestsByTest = new Map()
|
|
1591
|
+
for (const finishedTest of finishedTests) {
|
|
1592
|
+
const testIdentifier = finishedTest.testId ?? finishedTest.testName
|
|
1593
|
+
let finishedTestAttempts = finishedTestsByTest.get(testIdentifier)
|
|
1594
|
+
if (!finishedTestAttempts) {
|
|
1595
|
+
finishedTestAttempts = []
|
|
1596
|
+
finishedTestsByTest.set(testIdentifier, finishedTestAttempts)
|
|
1546
1597
|
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
}, {})
|
|
1598
|
+
finishedTestAttempts.push(finishedTest)
|
|
1599
|
+
}
|
|
1550
1600
|
|
|
1551
|
-
|
|
1601
|
+
const matchedCypressTests = new Set()
|
|
1602
|
+
for (const finishedTestAttempts of finishedTestsByTest.values()) {
|
|
1603
|
+
const { testName } = finishedTestAttempts[0]
|
|
1604
|
+
// Cypress reports one result per original runnable, including Datadog-managed clones.
|
|
1605
|
+
// Public results omit runnable IDs but retain declaration order.
|
|
1606
|
+
const cypressTest = cypressTests.find(test =>
|
|
1607
|
+
test.title.join(' ') === testName && !matchedCypressTests.has(test)
|
|
1608
|
+
)
|
|
1609
|
+
matchedCypressTests.add(cypressTest)
|
|
1552
1610
|
for (const [attemptIndex, finishedTest] of finishedTestAttempts.entries()) {
|
|
1553
1611
|
// We can check if this is the last attempt regardless of the retry mechanism
|
|
1554
1612
|
const isLastAttempt = attemptIndex === finishedTestAttempts.length - 1
|
|
1555
1613
|
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
1614
|
if (!cypressTest) {
|
|
1561
1615
|
continue
|
|
1562
1616
|
}
|
|
1563
1617
|
// finishedTests can include multiple tests with the same name if they have been retried
|
|
1564
1618
|
// by early flake detection. Cypress is unaware of this so .attempts does not necessarily have
|
|
1565
1619
|
// the same length as `finishedTestAttempts`
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
? finishedTest.testStatus
|
|
1569
|
-
|
|
1620
|
+
let cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.state]
|
|
1621
|
+
if (isDatadogManagedAttempt) {
|
|
1622
|
+
cypressTestStatus = isLastAttempt && isCypressHookFailure(cypressTest) ? 'fail' : finishedTest.testStatus
|
|
1623
|
+
}
|
|
1570
1624
|
if (!finishedTest.isEfdManagedTest && !finishedTest.isAttemptToFix &&
|
|
1571
1625
|
cypressTest.attempts && cypressTest.attempts[attemptIndex]) {
|
|
1572
1626
|
cypressTestStatus = CYPRESS_STATUS_TO_TEST_STATUS[cypressTest.attempts[attemptIndex].state]
|
|
@@ -1648,9 +1702,22 @@ class CypressPlugin {
|
|
|
1648
1702
|
finishedTest,
|
|
1649
1703
|
finishedTestAttempts,
|
|
1650
1704
|
flakyTestRetriesCount: this.flakyTestRetriesCount,
|
|
1705
|
+
isDynamicAtrEnabled: this.isDynamicAtrEnabled,
|
|
1651
1706
|
})
|
|
1652
1707
|
|
|
1653
|
-
|
|
1708
|
+
let hasFailedAllAttempts = testSpanTags[TEST_HAS_FAILED_ALL_RETRIES] === 'true'
|
|
1709
|
+
if (retryKind === FINAL_STATUS_RETRY_KIND.atr) {
|
|
1710
|
+
// Late hooks can change every attempt after dd:afterEach has captured its status.
|
|
1711
|
+
hasFailedAllAttempts = finishedTestAttempts.every(attempt =>
|
|
1712
|
+
attempt.testSpan.context().getTag(TEST_STATUS) === 'fail'
|
|
1713
|
+
)
|
|
1714
|
+
const atrRetryCount = this.isDynamicAtrEnabled
|
|
1715
|
+
? this.getDynamicAtrRetryCountForTest(spec.relative, finishedTest.testId)
|
|
1716
|
+
: this.flakyTestRetriesCount
|
|
1717
|
+
// An aborted run can fail without using the entire selected retry budget.
|
|
1718
|
+
const hasFailedAllRetries = hasFailedAllAttempts && finishedTestAttempts.length > atrRetryCount
|
|
1719
|
+
finishedTest.testSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, hasFailedAllRetries ? 'true' : undefined)
|
|
1720
|
+
}
|
|
1654
1721
|
const hasPassedAllAtfRetries =
|
|
1655
1722
|
testSpanTags[TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED] === 'true'
|
|
1656
1723
|
const isQuarantined = testSpanTags[TEST_MANAGEMENT_IS_QUARANTINED] === 'true'
|
|
@@ -1659,7 +1726,7 @@ class CypressPlugin {
|
|
|
1659
1726
|
const finalStatus = getFinalStatus({
|
|
1660
1727
|
status: cypressTestStatus,
|
|
1661
1728
|
retryKind,
|
|
1662
|
-
|
|
1729
|
+
hasFailedAllAttempts,
|
|
1663
1730
|
hasPassedAllAtfRetries,
|
|
1664
1731
|
isQuarantined,
|
|
1665
1732
|
isDisabled,
|
|
@@ -1683,7 +1750,12 @@ class CypressPlugin {
|
|
|
1683
1750
|
}
|
|
1684
1751
|
|
|
1685
1752
|
const testSuiteFinishTime = this._now()
|
|
1686
|
-
const
|
|
1753
|
+
const suiteError = error || resultError || latestError
|
|
1754
|
+
const suiteStatus = suiteError ||
|
|
1755
|
+
cypressTests.some(test => CYPRESS_STATUS_TO_TEST_STATUS[test.state] === 'fail')
|
|
1756
|
+
? 'fail'
|
|
1757
|
+
: getSuiteStatus(stats)
|
|
1758
|
+
this.testSuiteStatuses.add(suiteStatus)
|
|
1687
1759
|
const testSuiteSpan = this.testSuiteSpan
|
|
1688
1760
|
const uploadOptions = {
|
|
1689
1761
|
filePath: video,
|
|
@@ -1694,10 +1766,10 @@ class CypressPlugin {
|
|
|
1694
1766
|
? testSuiteSpan.context().toSpanId()
|
|
1695
1767
|
: undefined,
|
|
1696
1768
|
}
|
|
1697
|
-
const shouldUploadVideo =
|
|
1769
|
+
const shouldUploadVideo = suiteStatus === 'fail' && this.#canUploadTestSuiteVideo(uploadOptions)
|
|
1698
1770
|
if (testSuiteSpan) {
|
|
1699
|
-
testSuiteSpan.setTag(TEST_STATUS,
|
|
1700
|
-
if (
|
|
1771
|
+
testSuiteSpan.setTag(TEST_STATUS, suiteStatus)
|
|
1772
|
+
if (suiteError) testSuiteSpan.setTag('error', suiteError)
|
|
1701
1773
|
this.testSuiteSpan = null
|
|
1702
1774
|
}
|
|
1703
1775
|
|
|
@@ -1838,7 +1910,6 @@ class CypressPlugin {
|
|
|
1838
1910
|
* @param {string|undefined} options.filePath - Cypress video path
|
|
1839
1911
|
* @param {string|undefined} options.testSessionId - Test session id
|
|
1840
1912
|
* @param {string|undefined} options.testSuiteId - Test suite id
|
|
1841
|
-
* @returns {boolean}
|
|
1842
1913
|
*/
|
|
1843
1914
|
#canUploadTestSuiteVideo ({ filePath, testSessionId, testSuiteId }) {
|
|
1844
1915
|
const exporter = this.tracer?._tracer?._exporter
|
|
@@ -1936,7 +2007,14 @@ class CypressPlugin {
|
|
|
1936
2007
|
|
|
1937
2008
|
getTasks () {
|
|
1938
2009
|
return {
|
|
1939
|
-
'dd:testSuiteStart': ({ testSuite, testSuiteAbsolutePath }) => {
|
|
2010
|
+
'dd:testSuiteStart': ({ testSuite, testSuiteAbsolutePath, isTextTerminal: browserIsTextTerminal }) => {
|
|
2011
|
+
// Cypress 6 omits the execution mode from the Node plugin configuration.
|
|
2012
|
+
const isTextTerminal = this.cypressConfig.isTextTerminal ?? browserIsTextTerminal
|
|
2013
|
+
if (!isTextTerminal) {
|
|
2014
|
+
this.isFlakyTestRetriesEnabled = false
|
|
2015
|
+
this.isDynamicAtrEnabled = false
|
|
2016
|
+
this.flakyTestRetriesCount = 0
|
|
2017
|
+
}
|
|
1940
2018
|
const suitePayload = {
|
|
1941
2019
|
isEarlyFlakeDetectionEnabled:
|
|
1942
2020
|
this.isEarlyFlakeDetectionEnabled && hasEfdRetries(this.earlyFlakeDetectionRetryPolicy),
|
|
@@ -1950,6 +2028,8 @@ class CypressPlugin {
|
|
|
1950
2028
|
isModifiedTest: this.getIsTestModified(testSuiteAbsolutePath),
|
|
1951
2029
|
repositoryRoot: this.repositoryRoot,
|
|
1952
2030
|
isTestIsolationEnabled: this.isTestIsolationEnabled,
|
|
2031
|
+
isDynamicAtrEnabled: this.isDynamicAtrEnabled,
|
|
2032
|
+
isTextTerminal,
|
|
1953
2033
|
rumFlushWaitMillis: this.rumFlushWaitMillis,
|
|
1954
2034
|
rumTestExecutionIdCookieName: RUM_TEST_EXECUTION_ID_COOKIE_NAME,
|
|
1955
2035
|
}
|
|
@@ -1958,6 +2038,7 @@ class CypressPlugin {
|
|
|
1958
2038
|
return suitePayload
|
|
1959
2039
|
},
|
|
1960
2040
|
'dd:beforeEach': (test) => {
|
|
2041
|
+
this.hasTestsReported = true
|
|
1961
2042
|
const { testId, testName, testSuite, isEfdRetry, efdRetryIndex } = test
|
|
1962
2043
|
if (isEfdRetry && this.shouldSkipEfdRetry(testSuite, testName, efdRetryIndex)) {
|
|
1963
2044
|
return { shouldSkip: true, shouldDiscard: true }
|
|
@@ -2016,6 +2097,7 @@ class CypressPlugin {
|
|
|
2016
2097
|
testSourceStack,
|
|
2017
2098
|
testSuite,
|
|
2018
2099
|
testSuiteAbsolutePath,
|
|
2100
|
+
testId,
|
|
2019
2101
|
testName,
|
|
2020
2102
|
testItTitle,
|
|
2021
2103
|
isNew,
|
|
@@ -2064,12 +2146,23 @@ class CypressPlugin {
|
|
|
2064
2146
|
this.activeTestSpan.setTag(TEST_EARLY_FLAKE_ABORT_REASON, 'slow')
|
|
2065
2147
|
}
|
|
2066
2148
|
}
|
|
2149
|
+
// Dynamic ATR: after the first attempt, compute the duration-based retry budget.
|
|
2150
|
+
if (
|
|
2151
|
+
this.isDynamicAtrEnabled &&
|
|
2152
|
+
this.isFlakyTestRetriesEnabled &&
|
|
2153
|
+
!isAttemptToFix &&
|
|
2154
|
+
!isEfdRetry &&
|
|
2155
|
+
!isEfdManagedTest &&
|
|
2156
|
+
this.getDynamicAtrRetryCountForTest(testSuite, testId) === undefined
|
|
2157
|
+
) {
|
|
2158
|
+
this.setDynamicAtrRetryCountForTest(testSuite, testId, duration)
|
|
2159
|
+
}
|
|
2067
2160
|
if (didAbortSlowEfdRetries && testStatus === 'skip' && !error && duration > 0) {
|
|
2068
2161
|
testStatus = 'pass'
|
|
2069
2162
|
}
|
|
2070
2163
|
this.activeTestSpan.setTag(TEST_STATUS, testStatus)
|
|
2071
2164
|
|
|
2072
|
-
const testIdentifier = `${testSuite}\0${testName}`
|
|
2165
|
+
const testIdentifier = `${testSuite}\0${testId ?? testName}`
|
|
2073
2166
|
let testStatuses = this.testStatuses[testIdentifier]
|
|
2074
2167
|
if (testStatuses) {
|
|
2075
2168
|
testStatuses.push(testStatus)
|
|
@@ -2160,8 +2253,10 @@ class CypressPlugin {
|
|
|
2160
2253
|
})
|
|
2161
2254
|
}
|
|
2162
2255
|
// ATR: set TEST_HAS_FAILED_ALL_RETRIES when all auto test retries were exhausted and every attempt failed
|
|
2256
|
+
const dynamicAtrRetryCount = this.getDynamicAtrRetryCountForTest(testSuite, testId)
|
|
2257
|
+
const atrRetryCount = this.isDynamicAtrEnabled ? dynamicAtrRetryCount : this.flakyTestRetriesCount
|
|
2163
2258
|
if (this.isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry &&
|
|
2164
|
-
|
|
2259
|
+
atrRetryCount > 0 && testStatuses.length === atrRetryCount + 1 &&
|
|
2165
2260
|
testStatuses.every(status => status === 'fail')) {
|
|
2166
2261
|
this.activeTestSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
|
|
2167
2262
|
}
|
|
@@ -2201,6 +2296,7 @@ class CypressPlugin {
|
|
|
2201
2296
|
}
|
|
2202
2297
|
|
|
2203
2298
|
const finishedTest = {
|
|
2299
|
+
testId,
|
|
2204
2300
|
testName,
|
|
2205
2301
|
testStatus,
|
|
2206
2302
|
finishTime: this._now(),
|
|
@@ -2227,7 +2323,7 @@ class CypressPlugin {
|
|
|
2227
2323
|
})
|
|
2228
2324
|
this.activeTestSpan = null
|
|
2229
2325
|
|
|
2230
|
-
return null
|
|
2326
|
+
return dynamicAtrRetryCount === undefined ? null : { dynamicAtrRetryCount }
|
|
2231
2327
|
},
|
|
2232
2328
|
'dd:addTags': (tags) => {
|
|
2233
2329
|
if (this.activeTestSpan) {
|
|
@@ -19,9 +19,6 @@ function runUserHandler (handler) {
|
|
|
19
19
|
return userHandlerContext.run(true, handler)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* @returns {boolean} whether a managed finalizer owns the current lifecycle event
|
|
24
|
-
*/
|
|
25
22
|
function shouldDeferLegacyFinalization () {
|
|
26
23
|
return userHandlerContext.getStore() === true
|
|
27
24
|
}
|
|
@@ -15,7 +15,6 @@ const SOURCE_MAP_CACHE = new Map()
|
|
|
15
15
|
/**
|
|
16
16
|
* Whether a file path references JavaScript.
|
|
17
17
|
* @param {string} absoluteFilePath
|
|
18
|
-
* @returns {boolean}
|
|
19
18
|
*/
|
|
20
19
|
function isJavaScriptFile (absoluteFilePath) {
|
|
21
20
|
return absoluteFilePath.endsWith('.js') || absoluteFilePath.endsWith('.cjs') || absoluteFilePath.endsWith('.mjs')
|
|
@@ -25,7 +24,6 @@ function isJavaScriptFile (absoluteFilePath) {
|
|
|
25
24
|
* Decide whether invocationDetails line can be trusted as final source line.
|
|
26
25
|
* @param {string} absoluteFilePath
|
|
27
26
|
* @param {number} testSourceLine
|
|
28
|
-
* @returns {boolean}
|
|
29
27
|
*/
|
|
30
28
|
function shouldTrustInvocationDetailsLine (absoluteFilePath, testSourceLine) {
|
|
31
29
|
if (!Number.isInteger(testSourceLine) || testSourceLine < 1) return false
|
|
@@ -38,7 +36,6 @@ function shouldTrustInvocationDetailsLine (absoluteFilePath, testSourceLine) {
|
|
|
38
36
|
* Decode one VLQ-encoded integer from `str` at `cursor.pos`, advancing the cursor in place.
|
|
39
37
|
* @param {string} str
|
|
40
38
|
* @param {{ pos: number }} cursor
|
|
41
|
-
* @returns {number}
|
|
42
39
|
*/
|
|
43
40
|
function decodeVLQ (str, cursor) {
|
|
44
41
|
let result = 0
|
|
@@ -243,7 +240,6 @@ function templateBodyToRegExp (templateBody) {
|
|
|
243
240
|
* Count 1-indexed line number for a character index in `content`.
|
|
244
241
|
* @param {string} content
|
|
245
242
|
* @param {number} endIndex
|
|
246
|
-
* @returns {number}
|
|
247
243
|
*/
|
|
248
244
|
function lineNumberForIndex (content, endIndex) {
|
|
249
245
|
let line = 1
|