dd-trace 5.103.0 → 5.105.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +90 -102
- package/index.d.ts +107 -6
- package/package.json +18 -17
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +15 -2
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
- package/packages/datadog-instrumentations/src/cucumber.js +181 -35
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -67
- package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/kafka.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +31 -229
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/ioredis.js +3 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +390 -183
- package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/memcached.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
- package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
- package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
- package/packages/datadog-instrumentations/src/mongoose.js +10 -12
- package/packages/datadog-instrumentations/src/mysql.js +2 -2
- package/packages/datadog-instrumentations/src/mysql2.js +1 -1
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pg.js +1 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +537 -297
- package/packages/datadog-instrumentations/src/router.js +80 -34
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +246 -149
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +223 -45
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-graphql/src/utils.js +4 -1
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +35 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +311 -35
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-redis/src/index.js +37 -2
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +19 -0
- package/packages/datadog-plugin-vitest/src/index.js +24 -20
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +49 -21
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/blocking.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +11 -4
- package/packages/dd-trace/src/appsec/reporter.js +24 -11
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
- package/packages/dd-trace/src/config/supported-configurations.json +36 -8
- package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
- package/packages/dd-trace/src/datastreams/context.js +4 -2
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +57 -42
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/exporters/common/agents.js +3 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -1
- package/packages/dd-trace/src/id.js +17 -4
- package/packages/dd-trace/src/lambda/handler.js +2 -4
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +10 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/log/writer.js +3 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/noop/span.js +3 -1
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/apollo.js +3 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -46
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +48 -8
- package/packages/dd-trace/src/plugins/util/git.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +318 -13
- package/packages/dd-trace/src/plugins/util/web.js +89 -64
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/scope.js +7 -5
- package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
- package/vendor/dist/opentracing/LICENSE +0 -201
- package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
- package/vendor/dist/opentracing/constants.d.ts +0 -61
- package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
- package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
- package/vendor/dist/opentracing/functions.d.ts +0 -20
- package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
- package/vendor/dist/opentracing/index.d.ts +0 -12
- package/vendor/dist/opentracing/index.js +0 -1
- package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
- package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
- package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
- package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
- package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
- package/vendor/dist/opentracing/noop.d.ts +0 -8
- package/vendor/dist/opentracing/reference.d.ts +0 -33
- package/vendor/dist/opentracing/span.d.ts +0 -147
- package/vendor/dist/opentracing/span_context.d.ts +0 -26
- package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
- package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
- package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
- package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
- package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
- package/vendor/dist/opentracing/tracer.d.ts +0 -127
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// Capture real timers at module load time, before any test can install fake timers.
|
|
4
4
|
const realSetTimeout = setTimeout
|
|
5
|
+
const realClearTimeout = clearTimeout
|
|
5
6
|
|
|
6
7
|
const { performance } = require('node:perf_hooks')
|
|
7
8
|
const satisfies = require('../../../vendor/dist/semifies')
|
|
@@ -18,13 +19,14 @@ const {
|
|
|
18
19
|
recordAttemptToFixExecution,
|
|
19
20
|
logAttemptToFixTestExecution,
|
|
20
21
|
logTestOptimizationSummary,
|
|
22
|
+
getTestOptimizationRequestResults,
|
|
21
23
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
22
24
|
const log = require('../../dd-trace/src/log')
|
|
23
25
|
const {
|
|
24
26
|
getValueFromEnvSources,
|
|
25
27
|
} = require('../../dd-trace/src/config/helper')
|
|
26
28
|
const { DD_MAJOR } = require('../../../version')
|
|
27
|
-
const { addHook, channel } = require('./helpers/instrument')
|
|
29
|
+
const { addHook, channel, tracingChannel } = require('./helpers/instrument')
|
|
28
30
|
|
|
29
31
|
const testStartCh = channel('ci:playwright:test:start')
|
|
30
32
|
const testFinishCh = channel('ci:playwright:test:finish')
|
|
@@ -45,6 +47,12 @@ const testSuiteFinishCh = channel('ci:playwright:test-suite:finish')
|
|
|
45
47
|
const workerReportCh = channel('ci:playwright:worker:report')
|
|
46
48
|
const testPageGotoCh = channel('ci:playwright:test:page-goto')
|
|
47
49
|
|
|
50
|
+
const dispatcherRunCh = tracingChannel('orchestrion:playwright:Dispatcher_run')
|
|
51
|
+
const dispatcherCreateWorkerCh = tracingChannel('orchestrion:playwright:Dispatcher_createWorker')
|
|
52
|
+
const processHostStartRunnerCh = tracingChannel('orchestrion:playwright:ProcessHost_startRunner')
|
|
53
|
+
const createRootSuiteCh = tracingChannel('orchestrion:playwright:createRootSuite')
|
|
54
|
+
const pageGotoCh = tracingChannel('orchestrion:playwright-core:Page_goto')
|
|
55
|
+
|
|
48
56
|
const testToCtx = new WeakMap()
|
|
49
57
|
const testSuiteToCtx = new Map()
|
|
50
58
|
const testSuiteToTestStatuses = new Map()
|
|
@@ -52,6 +60,7 @@ const testSuiteToErrors = new Map()
|
|
|
52
60
|
const testsToTestStatuses = new Map()
|
|
53
61
|
|
|
54
62
|
const RUM_FLUSH_WAIT_TIME = Number(getValueFromEnvSources('DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS')) || 500
|
|
63
|
+
const DD_PROPERTIES_TIMEOUT = 5000
|
|
55
64
|
|
|
56
65
|
let applyRepeatEachIndex = null
|
|
57
66
|
|
|
@@ -94,12 +103,17 @@ const efdRetryTestsById = new Map()
|
|
|
94
103
|
const efdScheduledOriginalTestKeys = new Set()
|
|
95
104
|
const efdStartedOriginalTestKeys = new Set()
|
|
96
105
|
const efdSlowAbortedTests = new Set()
|
|
106
|
+
const ddPropertiesByTestId = new Map()
|
|
107
|
+
const ddPropertiesRequestsByTestId = new Map()
|
|
97
108
|
let rootDir = ''
|
|
98
109
|
let sessionProjects = []
|
|
99
110
|
|
|
100
111
|
const MINIMUM_SUPPORTED_VERSION_RANGE_EFD = '>=1.38.0' // TODO: remove this once we drop support for v5
|
|
101
112
|
const EFD_RETRY_COUNT_REQUEST = 'ddEfdRetryCountRequest'
|
|
102
113
|
const EFD_RETRY_COUNT_RESPONSE = 'ddEfdRetryCountResponse'
|
|
114
|
+
const DD_PROPERTIES_REQUEST = 'ddPropertiesRequest'
|
|
115
|
+
const DD_PROPERTIES_RESPONSE = 'ddProperties'
|
|
116
|
+
const kDdPlaywrightWorkerInstrumented = Symbol('ddPlaywrightWorkerInstrumented')
|
|
103
117
|
|
|
104
118
|
function isValidKnownTests (receivedKnownTests) {
|
|
105
119
|
return !!receivedKnownTests.playwright
|
|
@@ -280,6 +294,43 @@ function sendEfdRetryCountToWorkerWhenAvailable (workerProcess, testId) {
|
|
|
280
294
|
})
|
|
281
295
|
}
|
|
282
296
|
|
|
297
|
+
function sendDdPropertiesToWorker (workerProcess, testId, properties) {
|
|
298
|
+
workerProcess.send({
|
|
299
|
+
type: DD_PROPERTIES_RESPONSE,
|
|
300
|
+
testId,
|
|
301
|
+
properties,
|
|
302
|
+
})
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function setDdPropertiesForTest (workerProcess, testId, properties) {
|
|
306
|
+
ddPropertiesByTestId.set(testId, properties)
|
|
307
|
+
|
|
308
|
+
const requests = ddPropertiesRequestsByTestId.get(testId)
|
|
309
|
+
if (requests) {
|
|
310
|
+
ddPropertiesRequestsByTestId.delete(testId)
|
|
311
|
+
for (const resolveRequest of requests) {
|
|
312
|
+
resolveRequest(properties)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
sendDdPropertiesToWorker(workerProcess, testId, properties)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function sendDdPropertiesToWorkerWhenAvailable (workerProcess, testId) {
|
|
320
|
+
const properties = ddPropertiesByTestId.get(testId)
|
|
321
|
+
if (properties) {
|
|
322
|
+
sendDdPropertiesToWorker(workerProcess, testId, properties)
|
|
323
|
+
return
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (!ddPropertiesRequestsByTestId.has(testId)) {
|
|
327
|
+
ddPropertiesRequestsByTestId.set(testId, [])
|
|
328
|
+
}
|
|
329
|
+
ddPropertiesRequestsByTestId.get(testId).push((properties) => {
|
|
330
|
+
sendDdPropertiesToWorker(workerProcess, testId, properties)
|
|
331
|
+
})
|
|
332
|
+
}
|
|
333
|
+
|
|
283
334
|
/**
|
|
284
335
|
* @param {object} test
|
|
285
336
|
* @returns {boolean}
|
|
@@ -353,11 +404,15 @@ function getSuiteType (test, type) {
|
|
|
353
404
|
return suite
|
|
354
405
|
}
|
|
355
406
|
|
|
407
|
+
function isSuiteEntry (entry) {
|
|
408
|
+
return entry.constructor.name === 'Suite' || entry.constructor.name === '_Suite'
|
|
409
|
+
}
|
|
410
|
+
|
|
356
411
|
// Copy of Suite#_deepClone but with a function to filter tests
|
|
357
412
|
function deepCloneSuite (suite, filterTest, tags = [], configureCopiedTest) {
|
|
358
413
|
const copy = suite._clone()
|
|
359
414
|
for (const entry of suite._entries) {
|
|
360
|
-
if (entry
|
|
415
|
+
if (isSuiteEntry(entry)) {
|
|
361
416
|
copy._addSuite(deepCloneSuite(entry, filterTest, tags, configureCopiedTest))
|
|
362
417
|
} else {
|
|
363
418
|
if (filterTest(entry)) {
|
|
@@ -444,6 +499,10 @@ function getProjectsFromRunner (runner, configArg) {
|
|
|
444
499
|
}
|
|
445
500
|
|
|
446
501
|
function getProjectsFromDispatcher (dispatcher) {
|
|
502
|
+
const bundledConfig = dispatcher._testRun?.config?.config?.projects
|
|
503
|
+
if (bundledConfig) {
|
|
504
|
+
return bundledConfig
|
|
505
|
+
}
|
|
447
506
|
const newConfig = dispatcher._config?.config?.projects
|
|
448
507
|
if (newConfig) {
|
|
449
508
|
return newConfig
|
|
@@ -887,31 +946,118 @@ function deferEfdRetryGroups (testGroups) {
|
|
|
887
946
|
return [...groupsWithOriginalTests, ...efdRetryOnlyGroups]
|
|
888
947
|
}
|
|
889
948
|
|
|
949
|
+
function prepareDispatcherRun (dispatcher, args) {
|
|
950
|
+
let testGroups = args[0]
|
|
951
|
+
|
|
952
|
+
// Filter out disabled tests from testGroups before they get scheduled,
|
|
953
|
+
// unless they have attemptToFix (in which case they should still run and be retried)
|
|
954
|
+
if (isTestManagementTestsEnabled) {
|
|
955
|
+
for (const group of testGroups) {
|
|
956
|
+
group.tests = group.tests.filter(test => !test._ddIsDisabled || test._ddIsAttemptToFix)
|
|
957
|
+
}
|
|
958
|
+
// Remove empty groups
|
|
959
|
+
testGroups = testGroups.filter(group => group.tests.length > 0)
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
963
|
+
testGroups = deferEfdRetryGroups(testGroups)
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if (!dispatcher._allTests) {
|
|
967
|
+
// Removed in https://github.com/microsoft/playwright/commit/1e52c37b254a441cccf332520f60225a5acc14c7
|
|
968
|
+
// Not available from >=1.44.0
|
|
969
|
+
dispatcher._ddAllTests = testGroups.flatMap(g => g.tests)
|
|
970
|
+
}
|
|
971
|
+
remainingTestsByFile = getTestsBySuiteFromTestGroups(testGroups)
|
|
972
|
+
args[0] = testGroups
|
|
973
|
+
}
|
|
974
|
+
|
|
890
975
|
function dispatcherRunWrapperNew (run) {
|
|
891
|
-
return function (
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
976
|
+
return function () {
|
|
977
|
+
prepareDispatcherRun(this, arguments)
|
|
978
|
+
return run.apply(this, arguments)
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function onDispatcherCreateWorker (dispatcher, worker) {
|
|
983
|
+
if (!worker) {
|
|
984
|
+
return worker
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const projects = getProjectsFromDispatcher(dispatcher)
|
|
988
|
+
sessionProjects = projects
|
|
989
|
+
|
|
990
|
+
worker.on('testBegin', ({ testId }) => {
|
|
991
|
+
const test = getTestByTestId(dispatcher, testId)
|
|
992
|
+
const browser = getBrowserNameFromProjects(projects, test)
|
|
993
|
+
const shouldCreateTestSpan = test.expectedStatus === 'skipped'
|
|
994
|
+
testBeginHandler(test, browser, shouldCreateTestSpan)
|
|
995
|
+
})
|
|
996
|
+
worker.on('testEnd', ({ testId, status, errors, annotations }) => {
|
|
997
|
+
const test = getTestByTestId(dispatcher, testId)
|
|
998
|
+
|
|
999
|
+
const isTimeout = status === 'timedOut'
|
|
1000
|
+
const testStatus = STATUS_TO_TEST_STATUS[status]
|
|
1001
|
+
const shouldCreateTestSpan = test.expectedStatus === 'skipped'
|
|
1002
|
+
if (shouldCreateTestSpan && !testToCtx.has(test)) {
|
|
1003
|
+
testBeginHandler(test, getBrowserNameFromProjects(projects, test), true)
|
|
900
1004
|
}
|
|
1005
|
+
testEndHandler(
|
|
1006
|
+
{
|
|
1007
|
+
test,
|
|
1008
|
+
annotations,
|
|
1009
|
+
testStatus,
|
|
1010
|
+
error: errors && errors[0],
|
|
1011
|
+
isTimeout,
|
|
1012
|
+
shouldCreateTestSpan,
|
|
1013
|
+
projects,
|
|
1014
|
+
}
|
|
1015
|
+
)
|
|
1016
|
+
const testResult = test.results.at(-1)
|
|
1017
|
+
const isAtrRetry = testResult?.retry > 0 &&
|
|
1018
|
+
isFlakyTestRetriesEnabled &&
|
|
1019
|
+
!test._ddIsAttemptToFix &&
|
|
1020
|
+
!test._ddIsEfdRetry
|
|
901
1021
|
|
|
902
|
-
|
|
903
|
-
|
|
1022
|
+
// EFD retries (new or modified tests) are implemented as clones with retries=0,
|
|
1023
|
+
// so testWillRetry always returns false for them. Instead, we track how many
|
|
1024
|
+
// executions have been reported via testsToTestStatuses (updated by testEndHandler
|
|
1025
|
+
// above) and mark the execution final once the count reaches the expected total.
|
|
1026
|
+
// This mirrors how ATF finality is detected and centralizes the decision in the
|
|
1027
|
+
// main process, so workers only need to act on the _ddIsFinalExecution flag.
|
|
1028
|
+
const isEfdManagedTest = isTestEfdManaged(test)
|
|
1029
|
+
let isFinalExecution
|
|
1030
|
+
if (isEfdManagedTest) {
|
|
1031
|
+
const efdTestStatuses = testsToTestStatuses.get(getTestEfdKey(test)) || []
|
|
1032
|
+
isFinalExecution = efdTestStatuses.length === getEfdRetryCountForTest(test) + 1
|
|
1033
|
+
} else if (test._ddIsAttemptToFix) {
|
|
1034
|
+
isFinalExecution = !!(test._ddHasPassedAttemptToFixRetries || test._ddHasFailedAttemptToFixRetries)
|
|
1035
|
+
} else {
|
|
1036
|
+
isFinalExecution = !testWillRetry(test, testStatus)
|
|
904
1037
|
}
|
|
905
1038
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1039
|
+
const ddProperties = {
|
|
1040
|
+
_ddIsDisabled: test._ddIsDisabled,
|
|
1041
|
+
_ddIsQuarantined: test._ddIsQuarantined,
|
|
1042
|
+
_ddIsAttemptToFix: test._ddIsAttemptToFix,
|
|
1043
|
+
_ddIsAttemptToFixRetry: test._ddIsAttemptToFixRetry,
|
|
1044
|
+
_ddIsNew: test._ddIsNew,
|
|
1045
|
+
_ddIsEfdRetry: test._ddIsEfdRetry,
|
|
1046
|
+
_ddHasFailedAllRetries: test._ddHasFailedAllRetries,
|
|
1047
|
+
_ddHasPassedAttemptToFixRetries: test._ddHasPassedAttemptToFixRetries,
|
|
1048
|
+
_ddHasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
|
|
1049
|
+
_ddIsAtrRetry: isAtrRetry,
|
|
1050
|
+
_ddIsModified: test._ddIsModified,
|
|
1051
|
+
_ddIsFinalExecution: isFinalExecution,
|
|
1052
|
+
_ddIsEfdManagedTest: isEfdManagedTest,
|
|
1053
|
+
_ddEarlyFlakeAbortReason: efdSlowAbortedTests.has(getTestEfdKey(test)) ? 'slow' : undefined,
|
|
1054
|
+
_ddHasPassedAnyEfdAttempt: (testsToTestStatuses.get(getTestEfdKey(test)) || []).includes('pass'),
|
|
910
1055
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
1056
|
+
|
|
1057
|
+
setDdPropertiesForTest(worker.process, test.id, ddProperties)
|
|
1058
|
+
})
|
|
1059
|
+
|
|
1060
|
+
return worker
|
|
915
1061
|
}
|
|
916
1062
|
|
|
917
1063
|
function dispatcherHook (dispatcherExport) {
|
|
@@ -959,82 +1105,7 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
|
|
|
959
1105
|
shimmer.wrap(dispatcherExport.Dispatcher.prototype, '_createWorker', createWorker => function (...args) {
|
|
960
1106
|
const dispatcher = this
|
|
961
1107
|
const worker = createWorker.apply(this, args)
|
|
962
|
-
|
|
963
|
-
sessionProjects = projects
|
|
964
|
-
|
|
965
|
-
worker.on('testBegin', ({ testId }) => {
|
|
966
|
-
const test = getTestByTestId(dispatcher, testId)
|
|
967
|
-
const browser = getBrowserNameFromProjects(projects, test)
|
|
968
|
-
const shouldCreateTestSpan = test.expectedStatus === 'skipped'
|
|
969
|
-
testBeginHandler(test, browser, shouldCreateTestSpan)
|
|
970
|
-
})
|
|
971
|
-
worker.on('testEnd', ({ testId, status, errors, annotations }) => {
|
|
972
|
-
const test = getTestByTestId(dispatcher, testId)
|
|
973
|
-
|
|
974
|
-
const isTimeout = status === 'timedOut'
|
|
975
|
-
const testStatus = STATUS_TO_TEST_STATUS[status]
|
|
976
|
-
const shouldCreateTestSpan = test.expectedStatus === 'skipped'
|
|
977
|
-
if (shouldCreateTestSpan && !testToCtx.has(test)) {
|
|
978
|
-
testBeginHandler(test, getBrowserNameFromProjects(projects, test), true)
|
|
979
|
-
}
|
|
980
|
-
testEndHandler(
|
|
981
|
-
{
|
|
982
|
-
test,
|
|
983
|
-
annotations,
|
|
984
|
-
testStatus,
|
|
985
|
-
error: errors && errors[0],
|
|
986
|
-
isTimeout,
|
|
987
|
-
shouldCreateTestSpan,
|
|
988
|
-
projects,
|
|
989
|
-
}
|
|
990
|
-
)
|
|
991
|
-
const testResult = test.results.at(-1)
|
|
992
|
-
const isAtrRetry = testResult?.retry > 0 &&
|
|
993
|
-
isFlakyTestRetriesEnabled &&
|
|
994
|
-
!test._ddIsAttemptToFix &&
|
|
995
|
-
!test._ddIsEfdRetry
|
|
996
|
-
|
|
997
|
-
// EFD retries (new or modified tests) are implemented as clones with retries=0,
|
|
998
|
-
// so testWillRetry always returns false for them. Instead, we track how many
|
|
999
|
-
// executions have been reported via testsToTestStatuses (updated by testEndHandler
|
|
1000
|
-
// above) and mark the execution final once the count reaches the expected total.
|
|
1001
|
-
// This mirrors how ATF finality is detected and centralizes the decision in the
|
|
1002
|
-
// main process, so workers only need to act on the _ddIsFinalExecution flag.
|
|
1003
|
-
const isEfdManagedTest = isTestEfdManaged(test)
|
|
1004
|
-
let isFinalExecution
|
|
1005
|
-
if (isEfdManagedTest) {
|
|
1006
|
-
const efdTestStatuses = testsToTestStatuses.get(getTestEfdKey(test)) || []
|
|
1007
|
-
isFinalExecution = efdTestStatuses.length === getEfdRetryCountForTest(test) + 1
|
|
1008
|
-
} else if (test._ddIsAttemptToFix) {
|
|
1009
|
-
isFinalExecution = !!(test._ddHasPassedAttemptToFixRetries || test._ddHasFailedAttemptToFixRetries)
|
|
1010
|
-
} else {
|
|
1011
|
-
isFinalExecution = !testWillRetry(test, testStatus)
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
// We want to send the ddProperties to the worker
|
|
1015
|
-
worker.process.send({
|
|
1016
|
-
type: 'ddProperties',
|
|
1017
|
-
testId: test.id,
|
|
1018
|
-
properties: {
|
|
1019
|
-
_ddIsDisabled: test._ddIsDisabled,
|
|
1020
|
-
_ddIsQuarantined: test._ddIsQuarantined,
|
|
1021
|
-
_ddIsAttemptToFix: test._ddIsAttemptToFix,
|
|
1022
|
-
_ddIsAttemptToFixRetry: test._ddIsAttemptToFixRetry,
|
|
1023
|
-
_ddIsNew: test._ddIsNew,
|
|
1024
|
-
_ddIsEfdRetry: test._ddIsEfdRetry,
|
|
1025
|
-
_ddHasFailedAllRetries: test._ddHasFailedAllRetries,
|
|
1026
|
-
_ddHasPassedAttemptToFixRetries: test._ddHasPassedAttemptToFixRetries,
|
|
1027
|
-
_ddHasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
|
|
1028
|
-
_ddIsAtrRetry: isAtrRetry,
|
|
1029
|
-
_ddIsModified: test._ddIsModified,
|
|
1030
|
-
_ddIsFinalExecution: isFinalExecution,
|
|
1031
|
-
_ddIsEfdManagedTest: isEfdManagedTest,
|
|
1032
|
-
_ddEarlyFlakeAbortReason: efdSlowAbortedTests.has(getTestEfdKey(test)) ? 'slow' : undefined,
|
|
1033
|
-
_ddHasPassedAnyEfdAttempt: (testsToTestStatuses.get(getTestEfdKey(test)) || []).includes('pass'),
|
|
1034
|
-
},
|
|
1035
|
-
})
|
|
1036
|
-
})
|
|
1037
|
-
return worker
|
|
1108
|
+
return onDispatcherCreateWorker(dispatcher, worker)
|
|
1038
1109
|
})
|
|
1039
1110
|
return dispatcherExport
|
|
1040
1111
|
}
|
|
@@ -1045,7 +1116,6 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1045
1116
|
let onDone
|
|
1046
1117
|
|
|
1047
1118
|
rootDir = getRootDir(this, config)
|
|
1048
|
-
|
|
1049
1119
|
const processArgv = process.argv.slice(2).join(' ')
|
|
1050
1120
|
const command = `playwright ${processArgv}`
|
|
1051
1121
|
testSessionStartCh.publish({ command, frameworkVersion: playwrightVersion, rootDir })
|
|
@@ -1075,9 +1145,24 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1075
1145
|
log.error('Playwright session start error', e)
|
|
1076
1146
|
}
|
|
1077
1147
|
|
|
1078
|
-
|
|
1148
|
+
const isTestOptimizationSupported = satisfies(playwrightVersion, MINIMUM_SUPPORTED_VERSION_RANGE_EFD)
|
|
1149
|
+
const shouldGetKnownTests = isKnownTestsEnabled && isTestOptimizationSupported
|
|
1150
|
+
const shouldGetTestManagementTests = isTestManagementTestsEnabled && isTestOptimizationSupported
|
|
1151
|
+
|
|
1152
|
+
const {
|
|
1153
|
+
knownTestsResponse,
|
|
1154
|
+
testManagementTestsResponse,
|
|
1155
|
+
} = await getTestOptimizationRequestResults({
|
|
1156
|
+
isKnownTestsEnabled: shouldGetKnownTests,
|
|
1157
|
+
isTestManagementTestsEnabled: shouldGetTestManagementTests,
|
|
1158
|
+
getKnownTests: () => getChannelPromise(knownTestsCh),
|
|
1159
|
+
getTestManagementTests: () => getChannelPromise(testManagementTestsCh),
|
|
1160
|
+
})
|
|
1161
|
+
|
|
1162
|
+
if (shouldGetKnownTests) {
|
|
1079
1163
|
try {
|
|
1080
|
-
const { err, knownTests: receivedKnownTests } =
|
|
1164
|
+
const { err, knownTests: receivedKnownTests } =
|
|
1165
|
+
knownTestsResponse || await getChannelPromise(knownTestsCh)
|
|
1081
1166
|
if (err) {
|
|
1082
1167
|
isEarlyFlakeDetectionEnabled = false
|
|
1083
1168
|
isKnownTestsEnabled = false
|
|
@@ -1096,9 +1181,10 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1096
1181
|
}
|
|
1097
1182
|
}
|
|
1098
1183
|
|
|
1099
|
-
if (
|
|
1184
|
+
if (shouldGetTestManagementTests) {
|
|
1100
1185
|
try {
|
|
1101
|
-
const { err, testManagementTests: receivedTestManagementTests } =
|
|
1186
|
+
const { err, testManagementTests: receivedTestManagementTests } =
|
|
1187
|
+
testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
|
|
1102
1188
|
if (err) {
|
|
1103
1189
|
isTestManagementTestsEnabled = false
|
|
1104
1190
|
} else {
|
|
@@ -1110,7 +1196,7 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1110
1196
|
}
|
|
1111
1197
|
}
|
|
1112
1198
|
|
|
1113
|
-
if (isImpactedTestsEnabled &&
|
|
1199
|
+
if (isImpactedTestsEnabled && isTestOptimizationSupported) {
|
|
1114
1200
|
try {
|
|
1115
1201
|
const { err, modifiedFiles: receivedModifiedFiles } = await getChannelPromise(modifiedFilesCh)
|
|
1116
1202
|
if (err) {
|
|
@@ -1216,6 +1302,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1216
1302
|
efdScheduledOriginalTestKeys.clear()
|
|
1217
1303
|
efdStartedOriginalTestKeys.clear()
|
|
1218
1304
|
efdSlowAbortedTests.clear()
|
|
1305
|
+
ddPropertiesByTestId.clear()
|
|
1306
|
+
ddPropertiesRequestsByTestId.clear()
|
|
1219
1307
|
|
|
1220
1308
|
// TODO: we can trick playwright into thinking the session passed by returning
|
|
1221
1309
|
// 'passed' here. We might be able to use this for both EFD and Test Management tests.
|
|
@@ -1242,6 +1330,85 @@ function runnerHookNew (runnerExport, playwrightVersion) {
|
|
|
1242
1330
|
return runnerExport
|
|
1243
1331
|
}
|
|
1244
1332
|
|
|
1333
|
+
function runnerIndexHook (runnerExport, playwrightVersion) {
|
|
1334
|
+
let wrappedTestRunner
|
|
1335
|
+
runnerExport = shimmer.wrap(runnerExport, 'testRunner', function (originalGetter) {
|
|
1336
|
+
return function () {
|
|
1337
|
+
if (!wrappedTestRunner) {
|
|
1338
|
+
wrappedTestRunner = runnerHookNew(originalGetter.call(this), playwrightVersion)
|
|
1339
|
+
}
|
|
1340
|
+
return wrappedTestRunner
|
|
1341
|
+
}
|
|
1342
|
+
})
|
|
1343
|
+
|
|
1344
|
+
const baseReporter = runnerExport.base?.TerminalReporter
|
|
1345
|
+
if (baseReporter) {
|
|
1346
|
+
shimmer.wrap(baseReporter.prototype, 'generateSummary', generateSummaryWrapper)
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
return runnerExport
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
function commonIndexHook (commonExport) {
|
|
1353
|
+
applyRepeatEachIndex = commonExport.suiteUtils?.applyRepeatEachIndex
|
|
1354
|
+
|
|
1355
|
+
let wrappedStartProcessRunner
|
|
1356
|
+
commonExport = shimmer.wrap(commonExport, 'startProcessRunner', function (originalGetter) {
|
|
1357
|
+
return function () {
|
|
1358
|
+
if (!wrappedStartProcessRunner) {
|
|
1359
|
+
const startProcessRunner = originalGetter.call(this)
|
|
1360
|
+
wrappedStartProcessRunner = function (create) {
|
|
1361
|
+
return startProcessRunner.call(this, function () {
|
|
1362
|
+
const processRunner = create.apply(this, arguments)
|
|
1363
|
+
instrumentWorkerMainMethods(processRunner)
|
|
1364
|
+
return processRunner
|
|
1365
|
+
})
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return wrappedStartProcessRunner
|
|
1369
|
+
}
|
|
1370
|
+
})
|
|
1371
|
+
|
|
1372
|
+
return commonExport
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
dispatcherRunCh.subscribe({
|
|
1376
|
+
start (ctx) {
|
|
1377
|
+
prepareDispatcherRun(ctx.self, ctx.arguments)
|
|
1378
|
+
},
|
|
1379
|
+
})
|
|
1380
|
+
|
|
1381
|
+
dispatcherCreateWorkerCh.subscribe({
|
|
1382
|
+
end (ctx) {
|
|
1383
|
+
onDispatcherCreateWorker(ctx.self, ctx.result)
|
|
1384
|
+
},
|
|
1385
|
+
})
|
|
1386
|
+
|
|
1387
|
+
processHostStartRunnerCh.subscribe({
|
|
1388
|
+
start (ctx) {
|
|
1389
|
+
prepareProcessHostStartRunner(ctx.self)
|
|
1390
|
+
},
|
|
1391
|
+
asyncEnd (ctx) {
|
|
1392
|
+
finishProcessHostStartRunner(ctx.self)
|
|
1393
|
+
},
|
|
1394
|
+
})
|
|
1395
|
+
|
|
1396
|
+
createRootSuiteCh.subscribe({
|
|
1397
|
+
asyncEnd (ctx) {
|
|
1398
|
+
if (ctx.error) {
|
|
1399
|
+
return
|
|
1400
|
+
}
|
|
1401
|
+
processRootSuite(ctx.result || ctx.arguments?.[0])
|
|
1402
|
+
},
|
|
1403
|
+
})
|
|
1404
|
+
|
|
1405
|
+
pageGotoCh.subscribe({
|
|
1406
|
+
asyncEnd (ctx) {
|
|
1407
|
+
// The Page.goto rewriter waits for this so tests closing immediately after navigation still get RUM tags.
|
|
1408
|
+
ctx.asyncEndPromise = handlePageGoto(ctx.self)
|
|
1409
|
+
},
|
|
1410
|
+
})
|
|
1411
|
+
|
|
1245
1412
|
if (DD_MAJOR < 6) { // <1.38.0 is only supported up to version 5
|
|
1246
1413
|
addHook({
|
|
1247
1414
|
name: '@playwright/test',
|
|
@@ -1274,28 +1441,40 @@ if (DD_MAJOR < 6) { // <1.38.0 is only supported up to version 5
|
|
|
1274
1441
|
}, runnerHook)
|
|
1275
1442
|
}
|
|
1276
1443
|
|
|
1444
|
+
addHook({
|
|
1445
|
+
name: 'playwright',
|
|
1446
|
+
file: 'lib/runner/index.js',
|
|
1447
|
+
versions: ['>=1.60.0'],
|
|
1448
|
+
}, runnerIndexHook)
|
|
1449
|
+
|
|
1450
|
+
addHook({
|
|
1451
|
+
name: 'playwright',
|
|
1452
|
+
file: 'lib/common/index.js',
|
|
1453
|
+
versions: ['>=1.60.0'],
|
|
1454
|
+
}, commonIndexHook)
|
|
1455
|
+
|
|
1277
1456
|
addHook({
|
|
1278
1457
|
name: 'playwright',
|
|
1279
1458
|
file: 'lib/runner/runner.js',
|
|
1280
|
-
versions: ['>=1.38.0'],
|
|
1459
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1281
1460
|
}, runnerHook)
|
|
1282
1461
|
|
|
1283
1462
|
addHook({
|
|
1284
1463
|
name: 'playwright',
|
|
1285
1464
|
file: 'lib/runner/testRunner.js',
|
|
1286
|
-
versions: ['>=1.55.0'],
|
|
1465
|
+
versions: ['>=1.55.0 <1.60.0'],
|
|
1287
1466
|
}, runnerHookNew)
|
|
1288
1467
|
|
|
1289
1468
|
addHook({
|
|
1290
1469
|
name: 'playwright',
|
|
1291
1470
|
file: 'lib/runner/dispatcher.js',
|
|
1292
|
-
versions: ['>=1.38.0'],
|
|
1471
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1293
1472
|
}, (dispatcher) => dispatcherHookNew(dispatcher, dispatcherRunWrapperNew))
|
|
1294
1473
|
|
|
1295
1474
|
addHook({
|
|
1296
1475
|
name: 'playwright',
|
|
1297
1476
|
file: 'lib/common/suiteUtils.js',
|
|
1298
|
-
versions: ['>=1.38.0'],
|
|
1477
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1299
1478
|
}, suiteUtilsPackage => {
|
|
1300
1479
|
// We grab `applyRepeatEachIndex` to use it later
|
|
1301
1480
|
// `applyRepeatEachIndex` needs to be applied to a cloned suite
|
|
@@ -1344,102 +1523,142 @@ function applyRetriesToTests (
|
|
|
1344
1523
|
}
|
|
1345
1524
|
}
|
|
1346
1525
|
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
}, (loadUtilsPackage) => {
|
|
1352
|
-
const oldCreateRootSuite = loadUtilsPackage.createRootSuite
|
|
1526
|
+
function processRootSuite (createRootSuiteReturnValue) {
|
|
1527
|
+
if (!isKnownTestsEnabled && !isTestManagementTestsEnabled && !isImpactedTestsEnabled) {
|
|
1528
|
+
return createRootSuiteReturnValue
|
|
1529
|
+
}
|
|
1353
1530
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
}
|
|
1531
|
+
if (!createRootSuiteReturnValue) {
|
|
1532
|
+
return createRootSuiteReturnValue
|
|
1533
|
+
}
|
|
1358
1534
|
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1535
|
+
// From v1.56.0 on, createRootSuite returns `{ rootSuite, topLevelProjects }`
|
|
1536
|
+
const rootSuite = createRootSuiteReturnValue.rootSuite || createRootSuiteReturnValue
|
|
1537
|
+
if (typeof rootSuite?.allTests !== 'function') {
|
|
1538
|
+
return createRootSuiteReturnValue
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
const allTests = rootSuite.allTests()
|
|
1542
|
+
|
|
1543
|
+
if (isTestManagementTestsEnabled) {
|
|
1544
|
+
const fileSuitesWithManagedTestsToProjects = new Map()
|
|
1545
|
+
for (const test of allTests) {
|
|
1546
|
+
const testProperties = getTestProperties(test)
|
|
1547
|
+
// Disabled tests are skipped unless they have attemptToFix
|
|
1548
|
+
if (testProperties.disabled) {
|
|
1549
|
+
test._ddIsDisabled = true
|
|
1550
|
+
if (!testProperties.attemptToFix) {
|
|
1551
|
+
test.expectedStatus = 'skipped'
|
|
1552
|
+
// setting test.expectedStatus to 'skipped' does not work for every case,
|
|
1553
|
+
// so we need to filter out disabled tests in dispatcherRunWrapperNew,
|
|
1554
|
+
// so they don't get to the workers
|
|
1555
|
+
continue
|
|
1379
1556
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1557
|
+
}
|
|
1558
|
+
if (testProperties.quarantined) {
|
|
1559
|
+
test._ddIsQuarantined = true
|
|
1560
|
+
if (!testProperties.attemptToFix) {
|
|
1561
|
+
// Do not skip quarantined tests, let them run and overwrite results post-run if they fail
|
|
1562
|
+
const testFqn = getTestFullyQualifiedName(test)
|
|
1563
|
+
quarantinedButNotAttemptToFixFqns.add(testFqn)
|
|
1387
1564
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1565
|
+
}
|
|
1566
|
+
if (testProperties.attemptToFix) {
|
|
1567
|
+
test._ddIsAttemptToFix = true
|
|
1568
|
+
// Prevent ATR or `--retries` from retrying attemptToFix tests
|
|
1569
|
+
test.retries = 0
|
|
1570
|
+
const fileSuite = getSuiteType(test, 'file')
|
|
1571
|
+
|
|
1572
|
+
if (!fileSuitesWithManagedTestsToProjects.has(fileSuite)) {
|
|
1573
|
+
fileSuitesWithManagedTestsToProjects.set(fileSuite, getSuiteType(test, 'project'))
|
|
1397
1574
|
}
|
|
1398
1575
|
}
|
|
1399
|
-
applyRetriesToTests(
|
|
1400
|
-
fileSuitesWithManagedTestsToProjects,
|
|
1401
|
-
(test) => test._ddIsAttemptToFix,
|
|
1402
|
-
[
|
|
1403
|
-
(test) => test._ddIsQuarantined && '_ddIsQuarantined',
|
|
1404
|
-
(test) => test._ddIsDisabled && '_ddIsDisabled',
|
|
1405
|
-
'_ddIsAttemptToFix',
|
|
1406
|
-
'_ddIsAttemptToFixRetry',
|
|
1407
|
-
],
|
|
1408
|
-
testManagementAttemptToFixRetries
|
|
1409
|
-
)
|
|
1410
1576
|
}
|
|
1577
|
+
applyRetriesToTests(
|
|
1578
|
+
fileSuitesWithManagedTestsToProjects,
|
|
1579
|
+
(test) => test._ddIsAttemptToFix,
|
|
1580
|
+
[
|
|
1581
|
+
(test) => test._ddIsQuarantined && '_ddIsQuarantined',
|
|
1582
|
+
(test) => test._ddIsDisabled && '_ddIsDisabled',
|
|
1583
|
+
'_ddIsAttemptToFix',
|
|
1584
|
+
'_ddIsAttemptToFixRetry',
|
|
1585
|
+
],
|
|
1586
|
+
testManagementAttemptToFixRetries
|
|
1587
|
+
)
|
|
1588
|
+
}
|
|
1411
1589
|
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
})
|
|
1420
|
-
return isImpacted
|
|
1590
|
+
if (isImpactedTestsEnabled) {
|
|
1591
|
+
const impactedTests = allTests.filter(test => {
|
|
1592
|
+
let isImpacted = false
|
|
1593
|
+
isModifiedCh.publish({
|
|
1594
|
+
filePath: test._requireFile,
|
|
1595
|
+
modifiedFiles,
|
|
1596
|
+
onDone: (isModified) => { isImpacted = isModified },
|
|
1421
1597
|
})
|
|
1598
|
+
return isImpacted
|
|
1599
|
+
})
|
|
1422
1600
|
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1601
|
+
const fileSuitesWithImpactedTestsToProjects = new Map()
|
|
1602
|
+
for (const impactedTest of impactedTests) {
|
|
1603
|
+
impactedTest._ddIsModified = true
|
|
1604
|
+
if (isEarlyFlakeDetectionEnabled && impactedTest.expectedStatus !== 'skipped') {
|
|
1605
|
+
markEfdManagedTest(impactedTest)
|
|
1606
|
+
const fileSuite = getSuiteType(impactedTest, 'file')
|
|
1607
|
+
if (!fileSuitesWithImpactedTestsToProjects.has(fileSuite)) {
|
|
1608
|
+
fileSuitesWithImpactedTestsToProjects.set(fileSuite, getSuiteType(impactedTest, 'project'))
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
// If something change in the file, all tests in the file are impacted, hence the () => true filter
|
|
1613
|
+
applyRetriesToTests(
|
|
1614
|
+
fileSuitesWithImpactedTestsToProjects,
|
|
1615
|
+
() => true,
|
|
1616
|
+
[
|
|
1617
|
+
'_ddIsModified',
|
|
1618
|
+
'_ddIsEfdRetry',
|
|
1619
|
+
(test) => (isKnownTestsEnabled && isNewTest(test) ? '_ddIsNew' : null),
|
|
1620
|
+
],
|
|
1621
|
+
getConfiguredEfdRetryCount(),
|
|
1622
|
+
(copiedTest, originalTest, retryIndex) => {
|
|
1623
|
+
markEfdRetryTest(copiedTest, retryIndex, originalTest)
|
|
1624
|
+
markEfdManagedTest(copiedTest)
|
|
1625
|
+
},
|
|
1626
|
+
getEfdRetryRepeatEachIndex
|
|
1627
|
+
)
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
if (isKnownTestsEnabled) {
|
|
1631
|
+
const newTests = allTests.filter(isNewTest)
|
|
1632
|
+
|
|
1633
|
+
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
1634
|
+
allTests.map(test => getTestSuitePath(test._requireFile, rootDir)),
|
|
1635
|
+
knownTests.playwright,
|
|
1636
|
+
earlyFlakeDetectionFaultyThreshold
|
|
1637
|
+
)
|
|
1638
|
+
|
|
1639
|
+
if (isFaulty) {
|
|
1640
|
+
isEarlyFlakeDetectionEnabled = false
|
|
1641
|
+
isKnownTestsEnabled = false
|
|
1642
|
+
isEarlyFlakeDetectionFaulty = true
|
|
1643
|
+
} else {
|
|
1644
|
+
const fileSuitesWithNewTestsToProjects = new Map()
|
|
1645
|
+
for (const newTest of newTests) {
|
|
1646
|
+
newTest._ddIsNew = true
|
|
1647
|
+
if (isEarlyFlakeDetectionEnabled && newTest.expectedStatus !== 'skipped' && !newTest._ddIsModified) {
|
|
1648
|
+
// Prevent ATR or `--retries` from retrying new tests if EFD is enabled
|
|
1649
|
+
newTest.retries = 0
|
|
1650
|
+
markEfdManagedTest(newTest)
|
|
1651
|
+
const fileSuite = getSuiteType(newTest, 'file')
|
|
1652
|
+
if (!fileSuitesWithNewTestsToProjects.has(fileSuite)) {
|
|
1653
|
+
fileSuitesWithNewTestsToProjects.set(fileSuite, getSuiteType(newTest, 'project'))
|
|
1431
1654
|
}
|
|
1432
1655
|
}
|
|
1433
1656
|
}
|
|
1434
|
-
|
|
1657
|
+
|
|
1435
1658
|
applyRetriesToTests(
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
[
|
|
1439
|
-
'_ddIsModified',
|
|
1440
|
-
'_ddIsEfdRetry',
|
|
1441
|
-
(test) => (isKnownTestsEnabled && isNewTest(test) ? '_ddIsNew' : null),
|
|
1442
|
-
],
|
|
1659
|
+
fileSuitesWithNewTestsToProjects,
|
|
1660
|
+
isNewTest,
|
|
1661
|
+
['_ddIsNew', '_ddIsEfdRetry'],
|
|
1443
1662
|
getConfiguredEfdRetryCount(),
|
|
1444
1663
|
(copiedTest, originalTest, retryIndex) => {
|
|
1445
1664
|
markEfdRetryTest(copiedTest, retryIndex, originalTest)
|
|
@@ -1448,50 +1667,20 @@ addHook({
|
|
|
1448
1667
|
getEfdRetryRepeatEachIndex
|
|
1449
1668
|
)
|
|
1450
1669
|
}
|
|
1670
|
+
}
|
|
1451
1671
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
1456
|
-
allTests.map(test => getTestSuitePath(test._requireFile, rootDir)),
|
|
1457
|
-
knownTests.playwright,
|
|
1458
|
-
earlyFlakeDetectionFaultyThreshold
|
|
1459
|
-
)
|
|
1460
|
-
|
|
1461
|
-
if (isFaulty) {
|
|
1462
|
-
isEarlyFlakeDetectionEnabled = false
|
|
1463
|
-
isKnownTestsEnabled = false
|
|
1464
|
-
isEarlyFlakeDetectionFaulty = true
|
|
1465
|
-
} else {
|
|
1466
|
-
const fileSuitesWithNewTestsToProjects = new Map()
|
|
1467
|
-
for (const newTest of newTests) {
|
|
1468
|
-
newTest._ddIsNew = true
|
|
1469
|
-
if (isEarlyFlakeDetectionEnabled && newTest.expectedStatus !== 'skipped' && !newTest._ddIsModified) {
|
|
1470
|
-
// Prevent ATR or `--retries` from retrying new tests if EFD is enabled
|
|
1471
|
-
newTest.retries = 0
|
|
1472
|
-
markEfdManagedTest(newTest)
|
|
1473
|
-
const fileSuite = getSuiteType(newTest, 'file')
|
|
1474
|
-
if (!fileSuitesWithNewTestsToProjects.has(fileSuite)) {
|
|
1475
|
-
fileSuitesWithNewTestsToProjects.set(fileSuite, getSuiteType(newTest, 'project'))
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1672
|
+
return createRootSuiteReturnValue
|
|
1673
|
+
}
|
|
1479
1674
|
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
markEfdRetryTest(copiedTest, retryIndex, originalTest)
|
|
1487
|
-
markEfdManagedTest(copiedTest)
|
|
1488
|
-
},
|
|
1489
|
-
getEfdRetryRepeatEachIndex
|
|
1490
|
-
)
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1675
|
+
addHook({
|
|
1676
|
+
name: 'playwright',
|
|
1677
|
+
file: 'lib/runner/loadUtils.js',
|
|
1678
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1679
|
+
}, (loadUtilsPackage) => {
|
|
1680
|
+
const oldCreateRootSuite = loadUtilsPackage.createRootSuite
|
|
1493
1681
|
|
|
1494
|
-
|
|
1682
|
+
async function newCreateRootSuite () {
|
|
1683
|
+
return processRootSuite(await oldCreateRootSuite.apply(this, arguments))
|
|
1495
1684
|
}
|
|
1496
1685
|
|
|
1497
1686
|
// We need to proxy the createRootSuite function because the function is not configurable
|
|
@@ -1505,32 +1694,47 @@ addHook({
|
|
|
1505
1694
|
})
|
|
1506
1695
|
})
|
|
1507
1696
|
|
|
1697
|
+
function prepareProcessHostStartRunner (processHost) {
|
|
1698
|
+
processHost._extraEnv = {
|
|
1699
|
+
...processHost._extraEnv,
|
|
1700
|
+
// Used to detect that we're in a playwright worker
|
|
1701
|
+
DD_PLAYWRIGHT_WORKER: '1',
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
function finishProcessHostStartRunner (processHost) {
|
|
1706
|
+
if (!processHost.process) {
|
|
1707
|
+
return
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
// We add a new listener to `processHost.process`, which represents the worker
|
|
1711
|
+
processHost.process.on('message', (message) => {
|
|
1712
|
+
if (message?.type === EFD_RETRY_COUNT_REQUEST) {
|
|
1713
|
+
sendEfdRetryCountToWorkerWhenAvailable(processHost.process, message.testId)
|
|
1714
|
+
return
|
|
1715
|
+
}
|
|
1716
|
+
if (message?.type === DD_PROPERTIES_REQUEST) {
|
|
1717
|
+
sendDdPropertiesToWorkerWhenAvailable(processHost.process, message.testId)
|
|
1718
|
+
return
|
|
1719
|
+
}
|
|
1720
|
+
// These messages are [code, payload]. The payload is test data
|
|
1721
|
+
if (Array.isArray(message) && message[0] === PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE) {
|
|
1722
|
+
workerReportCh.publish(message[1])
|
|
1723
|
+
}
|
|
1724
|
+
})
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1508
1727
|
// main process hook
|
|
1509
1728
|
addHook({
|
|
1510
1729
|
name: 'playwright',
|
|
1511
1730
|
file: 'lib/runner/processHost.js',
|
|
1512
|
-
versions: ['>=1.38.0'],
|
|
1731
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1513
1732
|
}, (processHostPackage) => {
|
|
1514
1733
|
shimmer.wrap(processHostPackage.ProcessHost.prototype, 'startRunner', startRunner => async function () {
|
|
1515
|
-
this
|
|
1516
|
-
...this._extraEnv,
|
|
1517
|
-
// Used to detect that we're in a playwright worker
|
|
1518
|
-
DD_PLAYWRIGHT_WORKER: '1',
|
|
1519
|
-
}
|
|
1734
|
+
prepareProcessHostStartRunner(this)
|
|
1520
1735
|
|
|
1521
1736
|
const res = await startRunner.apply(this, arguments)
|
|
1522
|
-
|
|
1523
|
-
// We add a new listener to `this.process`, which is represents the worker
|
|
1524
|
-
this.process.on('message', (message) => {
|
|
1525
|
-
if (message?.type === EFD_RETRY_COUNT_REQUEST) {
|
|
1526
|
-
sendEfdRetryCountToWorkerWhenAvailable(this.process, message.testId)
|
|
1527
|
-
return
|
|
1528
|
-
}
|
|
1529
|
-
// These messages are [code, payload]. The payload is test data
|
|
1530
|
-
if (Array.isArray(message) && message[0] === PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE) {
|
|
1531
|
-
workerReportCh.publish(message[1])
|
|
1532
|
-
}
|
|
1533
|
-
})
|
|
1737
|
+
finishProcessHostStartRunner(this)
|
|
1534
1738
|
|
|
1535
1739
|
return res
|
|
1536
1740
|
})
|
|
@@ -1538,34 +1742,36 @@ addHook({
|
|
|
1538
1742
|
return processHostPackage
|
|
1539
1743
|
})
|
|
1540
1744
|
|
|
1745
|
+
async function handlePageGoto (page) {
|
|
1746
|
+
try {
|
|
1747
|
+
if (page && typeof page.evaluate === 'function') {
|
|
1748
|
+
const { isRumInstrumented, isRumActive, rumSamplingRate } = await page.evaluate(detectRum)
|
|
1749
|
+
if (isRumInstrumented && rumSamplingRate < 100 && !isRumActive) {
|
|
1750
|
+
log.debug("RUM was detected on the page, but it isn't active because the sampling rate is below 100%")
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
if (isRumActive) {
|
|
1754
|
+
testPageGotoCh.publish({
|
|
1755
|
+
isRumActive,
|
|
1756
|
+
page,
|
|
1757
|
+
})
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
} catch (e) {
|
|
1761
|
+
// ignore errors such as redirects, context destroyed, etc
|
|
1762
|
+
log.error('goto hook error', e)
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1541
1766
|
addHook({
|
|
1542
1767
|
name: 'playwright-core',
|
|
1543
1768
|
file: 'lib/client/page.js',
|
|
1544
|
-
versions: ['>=1.38.0'],
|
|
1769
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1545
1770
|
}, (pagePackage) => {
|
|
1546
1771
|
shimmer.wrap(pagePackage.Page.prototype, 'goto', goto => async function (url, options) {
|
|
1547
1772
|
const response = await goto.apply(this, arguments)
|
|
1548
1773
|
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
try {
|
|
1552
|
-
if (page) {
|
|
1553
|
-
const { isRumInstrumented, isRumActive, rumSamplingRate } = await page.evaluate(detectRum)
|
|
1554
|
-
if (isRumInstrumented && rumSamplingRate < 100 && !isRumActive) {
|
|
1555
|
-
log.debug("RUM was detected on the page, but it isn't active because the sampling rate is below 100%")
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
if (isRumActive) {
|
|
1559
|
-
testPageGotoCh.publish({
|
|
1560
|
-
isRumActive,
|
|
1561
|
-
page,
|
|
1562
|
-
})
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
} catch (e) {
|
|
1566
|
-
// ignore errors such as redirects, context destroyed, etc
|
|
1567
|
-
log.error('goto hook error', e)
|
|
1568
|
-
}
|
|
1774
|
+
await handlePageGoto(this)
|
|
1569
1775
|
|
|
1570
1776
|
return response
|
|
1571
1777
|
})
|
|
@@ -1573,17 +1779,19 @@ addHook({
|
|
|
1573
1779
|
return pagePackage
|
|
1574
1780
|
})
|
|
1575
1781
|
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1782
|
+
function instrumentWorkerMainMethods (workerMain) {
|
|
1783
|
+
if (!workerMain || workerMain[kDdPlaywrightWorkerInstrumented] ||
|
|
1784
|
+
typeof workerMain._runTest !== 'function' || typeof workerMain.dispatchEvent !== 'function') {
|
|
1785
|
+
return workerMain
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
Object.defineProperty(workerMain, kDdPlaywrightWorkerInstrumented, { value: true })
|
|
1789
|
+
|
|
1582
1790
|
// we assume there's only a test running at a time
|
|
1583
1791
|
let steps = []
|
|
1584
1792
|
const stepInfoByStepId = {}
|
|
1585
1793
|
|
|
1586
|
-
shimmer.wrap(
|
|
1794
|
+
shimmer.wrap(workerMain, '_runTest', _runTest => async function (test) {
|
|
1587
1795
|
await waitForEfdRetryCount(test)
|
|
1588
1796
|
if (shouldSkipEfdRetry(test)) {
|
|
1589
1797
|
test._ddShouldSkipEfdRetry = true
|
|
@@ -1619,6 +1827,27 @@ addHook({
|
|
|
1619
1827
|
browserName,
|
|
1620
1828
|
}
|
|
1621
1829
|
testToCtx.set(test, testCtx)
|
|
1830
|
+
|
|
1831
|
+
// Wait for ddProperties to be received and processed. The main process sends
|
|
1832
|
+
// this during Playwright's testEnd event, which can happen before _runTest
|
|
1833
|
+
// resolves in 1.60 when retry clones run across multiple workers.
|
|
1834
|
+
let hasDdProperties = false
|
|
1835
|
+
const ddPropertiesDeferred = {}
|
|
1836
|
+
const ddPropertiesPromise = new Promise(resolve => {
|
|
1837
|
+
ddPropertiesDeferred.resolve = resolve
|
|
1838
|
+
})
|
|
1839
|
+
const ddPropertiesMessageHandler = ({ type, testId, properties }) => {
|
|
1840
|
+
if (type === DD_PROPERTIES_RESPONSE && testId === test.id) {
|
|
1841
|
+
hasDdProperties = true
|
|
1842
|
+
if (properties) {
|
|
1843
|
+
Object.assign(test, properties)
|
|
1844
|
+
}
|
|
1845
|
+
process.removeListener('message', ddPropertiesMessageHandler)
|
|
1846
|
+
ddPropertiesDeferred.resolve()
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
process.on('message', ddPropertiesMessageHandler)
|
|
1850
|
+
|
|
1622
1851
|
// TODO - In the future we may need to implement a mechanism to send test properties
|
|
1623
1852
|
// to the worker process before _runTest is called
|
|
1624
1853
|
testStartCh.runStores(testCtx, () => {
|
|
@@ -1691,6 +1920,16 @@ addHook({
|
|
|
1691
1920
|
}
|
|
1692
1921
|
}
|
|
1693
1922
|
|
|
1923
|
+
if (!hasDdProperties && process.send) {
|
|
1924
|
+
process.send({
|
|
1925
|
+
type: DD_PROPERTIES_REQUEST,
|
|
1926
|
+
testId: test.id,
|
|
1927
|
+
})
|
|
1928
|
+
} else if (!hasDdProperties) {
|
|
1929
|
+
process.removeListener('message', ddPropertiesMessageHandler)
|
|
1930
|
+
ddPropertiesDeferred.resolve()
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1694
1933
|
// testInfo.errors could be better than "error",
|
|
1695
1934
|
// which will only include timeout error (even though the test failed because of a different error)
|
|
1696
1935
|
|
|
@@ -1705,26 +1944,17 @@ addHook({
|
|
|
1705
1944
|
onDone = resolve
|
|
1706
1945
|
})
|
|
1707
1946
|
|
|
1708
|
-
// Wait for
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
process.removeListener('message', messageHandler)
|
|
1718
|
-
resolve()
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
// Add the listener
|
|
1723
|
-
process.on('message', messageHandler)
|
|
1947
|
+
// Wait for the properties to be received, but do not block the worker forever if IPC fails.
|
|
1948
|
+
const ddPropertiesTimeoutPromise = new Promise(resolve => {
|
|
1949
|
+
const ddPropertiesTimeout = realSetTimeout(() => {
|
|
1950
|
+
process.removeListener('message', ddPropertiesMessageHandler)
|
|
1951
|
+
resolve()
|
|
1952
|
+
}, DD_PROPERTIES_TIMEOUT)
|
|
1953
|
+
ddPropertiesPromise.then(() => {
|
|
1954
|
+
realClearTimeout(ddPropertiesTimeout)
|
|
1955
|
+
})
|
|
1724
1956
|
})
|
|
1725
|
-
|
|
1726
|
-
// Wait for the properties to be received
|
|
1727
|
-
await ddPropertiesPromise
|
|
1957
|
+
await Promise.race([ddPropertiesPromise, ddPropertiesTimeoutPromise])
|
|
1728
1958
|
|
|
1729
1959
|
const finalStatus = getFinalStatus({
|
|
1730
1960
|
isFinalExecution: test._ddIsFinalExecution,
|
|
@@ -1770,7 +2000,7 @@ addHook({
|
|
|
1770
2000
|
|
|
1771
2001
|
// We reproduce what happens in `Dispatcher#_onStepBegin` and `Dispatcher#_onStepEnd`,
|
|
1772
2002
|
// since `startTime` and `duration` are not available directly in the worker process
|
|
1773
|
-
shimmer.wrap(
|
|
2003
|
+
shimmer.wrap(workerMain, 'dispatchEvent', dispatchEvent => function (event, payload) {
|
|
1774
2004
|
if (event === 'stepBegin') {
|
|
1775
2005
|
stepInfoByStepId[payload.stepId] = {
|
|
1776
2006
|
startTime: payload.wallTime,
|
|
@@ -1791,6 +2021,16 @@ addHook({
|
|
|
1791
2021
|
return dispatchEvent.apply(this, arguments)
|
|
1792
2022
|
})
|
|
1793
2023
|
|
|
2024
|
+
return workerMain
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// Only in worker
|
|
2028
|
+
addHook({
|
|
2029
|
+
name: 'playwright',
|
|
2030
|
+
file: 'lib/worker/workerMain.js',
|
|
2031
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
2032
|
+
}, (workerPackage) => {
|
|
2033
|
+
instrumentWorkerMainMethods(workerPackage.WorkerMain.prototype)
|
|
1794
2034
|
return workerPackage
|
|
1795
2035
|
})
|
|
1796
2036
|
|
|
@@ -1839,7 +2079,7 @@ function generateSummaryWrapper (generateSummary) {
|
|
|
1839
2079
|
addHook({
|
|
1840
2080
|
name: 'playwright',
|
|
1841
2081
|
file: 'lib/reporters/base.js',
|
|
1842
|
-
versions: ['>=1.38.0'],
|
|
2082
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1843
2083
|
}, (reportersPackage) => {
|
|
1844
2084
|
// v1.50.0 changed the name of the base reporter from BaseReporter to TerminalReporter
|
|
1845
2085
|
if (reportersPackage.TerminalReporter) {
|