dd-trace 5.52.0 → 5.53.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/README.md +5 -0
- package/index.d.ts +54 -6
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/amqplib.js +8 -5
- package/packages/datadog-instrumentations/src/child_process.js +2 -1
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +16 -1
- package/packages/datadog-instrumentations/src/couchbase.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +41 -46
- package/packages/datadog-instrumentations/src/express.js +2 -6
- package/packages/datadog-instrumentations/src/fs.js +6 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +17 -12
- package/packages/datadog-instrumentations/src/http/client.js +2 -1
- package/packages/datadog-instrumentations/src/iovalkey.js +51 -0
- package/packages/datadog-instrumentations/src/jest.js +49 -41
- package/packages/datadog-instrumentations/src/kafkajs.js +21 -8
- package/packages/datadog-instrumentations/src/mocha/main.js +33 -46
- package/packages/datadog-instrumentations/src/mocha/utils.js +72 -75
- package/packages/datadog-instrumentations/src/mysql2.js +3 -1
- package/packages/datadog-instrumentations/src/net.js +3 -1
- package/packages/datadog-instrumentations/src/next.js +6 -14
- package/packages/datadog-instrumentations/src/pg.js +5 -11
- package/packages/datadog-instrumentations/src/playwright.js +60 -69
- package/packages/datadog-instrumentations/src/url.js +9 -17
- package/packages/datadog-instrumentations/src/vitest.js +55 -75
- package/packages/datadog-plugin-cucumber/src/index.js +29 -18
- package/packages/datadog-plugin-iovalkey/src/index.js +18 -0
- package/packages/datadog-plugin-jest/src/index.js +14 -8
- package/packages/datadog-plugin-kafkajs/src/producer.js +8 -5
- package/packages/datadog-plugin-mocha/src/index.js +55 -35
- package/packages/datadog-plugin-playwright/src/index.js +26 -20
- package/packages/datadog-plugin-redis/src/index.js +8 -3
- package/packages/datadog-plugin-vitest/src/index.js +53 -42
- package/packages/datadog-shimmer/src/shimmer.js +164 -33
- package/packages/dd-trace/src/appsec/graphql.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +14 -11
- package/packages/dd-trace/src/appsec/rasp/index.js +4 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +11 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
- package/packages/dd-trace/src/appsec/telemetry/index.js +1 -2
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +0 -9
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +6 -6
- package/packages/dd-trace/src/config.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +59 -7
- package/packages/dd-trace/src/debugger/devtools_client/index.js +10 -26
- package/packages/dd-trace/src/debugger/devtools_client/send.js +8 -7
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +15 -7
- package/packages/dd-trace/src/debugger/devtools_client/state.js +21 -1
- package/packages/dd-trace/src/dogstatsd.js +2 -0
- package/packages/dd-trace/src/llmobs/tagger.js +3 -3
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/proxy.js +0 -4
- package/packages/dd-trace/src/serverless.js +0 -48
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +8 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
addAttemptToFixStringToTestName,
|
|
8
8
|
removeAttemptToFixStringFromTestName
|
|
9
9
|
} = require('../../../dd-trace/src/plugins/util/test')
|
|
10
|
-
const { channel
|
|
10
|
+
const { channel } = require('../helpers/instrument')
|
|
11
11
|
const shimmer = require('../../../datadog-shimmer')
|
|
12
12
|
|
|
13
13
|
// test channels
|
|
@@ -17,15 +17,16 @@ const testFinishCh = channel('ci:mocha:test:finish')
|
|
|
17
17
|
const testRetryCh = channel('ci:mocha:test:retry')
|
|
18
18
|
const errorCh = channel('ci:mocha:test:error')
|
|
19
19
|
const skipCh = channel('ci:mocha:test:skip')
|
|
20
|
+
const testFnCh = channel('ci:mocha:test:fn')
|
|
20
21
|
|
|
21
22
|
// suite channels
|
|
22
23
|
const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
|
|
23
24
|
|
|
24
25
|
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
25
|
-
const
|
|
26
|
+
const testToContext = new WeakMap()
|
|
26
27
|
const originalFns = new WeakMap()
|
|
27
28
|
const testToStartLine = new WeakMap()
|
|
28
|
-
const
|
|
29
|
+
const testFileToSuiteCtx = new Map()
|
|
29
30
|
const wrappedFunctions = new WeakSet()
|
|
30
31
|
const newTests = {}
|
|
31
32
|
const testsAttemptToFix = new Set()
|
|
@@ -125,7 +126,7 @@ function getTestStatus (test) {
|
|
|
125
126
|
return 'pass'
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
function
|
|
129
|
+
function getTestToContextKey (test) {
|
|
129
130
|
if (!test.fn) {
|
|
130
131
|
return test
|
|
131
132
|
}
|
|
@@ -136,14 +137,14 @@ function getTestToArKey (test) {
|
|
|
136
137
|
return originalFn
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
function
|
|
140
|
-
const key =
|
|
141
|
-
return
|
|
140
|
+
function getTestContext (test) {
|
|
141
|
+
const key = getTestToContextKey(test)
|
|
142
|
+
return testToContext.get(key)
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
function runnableWrapper (RunnablePackage, libraryConfig) {
|
|
145
146
|
shimmer.wrap(RunnablePackage.prototype, 'run', run => function () {
|
|
146
|
-
if (!
|
|
147
|
+
if (!testFinishCh.hasSubscribers) {
|
|
147
148
|
return run.apply(this, arguments)
|
|
148
149
|
}
|
|
149
150
|
// Flaky test retries does not work in parallel mode
|
|
@@ -167,14 +168,17 @@ function runnableWrapper (RunnablePackage, libraryConfig) {
|
|
|
167
168
|
|
|
168
169
|
if (isTestHook || this.type === 'test') {
|
|
169
170
|
const test = isTestHook ? this.ctx.currentTest : this
|
|
170
|
-
const
|
|
171
|
+
const ctx = getTestContext(test)
|
|
171
172
|
|
|
172
|
-
if (
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
if (ctx) {
|
|
174
|
+
const originalFn = this.fn
|
|
175
|
+
// we bind the test fn to the correct context
|
|
176
|
+
const newFn = function () {
|
|
177
|
+
return testFnCh.runStores(ctx, () => originalFn.apply(this, arguments))
|
|
178
|
+
}
|
|
175
179
|
|
|
176
180
|
// we store the original function, not to lose it
|
|
177
|
-
originalFns.set(newFn,
|
|
181
|
+
originalFns.set(newFn, originalFn)
|
|
178
182
|
this.fn = newFn
|
|
179
183
|
|
|
180
184
|
wrappedFunctions.add(this.fn)
|
|
@@ -189,7 +193,6 @@ function runnableWrapper (RunnablePackage, libraryConfig) {
|
|
|
189
193
|
function getOnTestHandler (isMain) {
|
|
190
194
|
return function (test) {
|
|
191
195
|
const testStartLine = testToStartLine.get(test)
|
|
192
|
-
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
193
196
|
|
|
194
197
|
// This may be a retry. If this is the case, `test.fn` is already wrapped,
|
|
195
198
|
// so we need to restore it.
|
|
@@ -198,7 +201,6 @@ function getOnTestHandler (isMain) {
|
|
|
198
201
|
test.fn = originalFn
|
|
199
202
|
wrappedFunctions.delete(test.fn)
|
|
200
203
|
}
|
|
201
|
-
testToAr.set(test.fn, asyncResource)
|
|
202
204
|
|
|
203
205
|
const {
|
|
204
206
|
file: testSuiteAbsolutePath,
|
|
@@ -242,15 +244,15 @@ function getOnTestHandler (isMain) {
|
|
|
242
244
|
test.pending = true
|
|
243
245
|
}
|
|
244
246
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
})
|
|
247
|
+
const ctx = testInfo
|
|
248
|
+
testToContext.set(test.fn, ctx)
|
|
249
|
+
testStartCh.runStores(ctx, () => { })
|
|
248
250
|
}
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
function getOnTestEndHandler (config) {
|
|
252
254
|
return async function (test) {
|
|
253
|
-
const
|
|
255
|
+
const ctx = getTestContext(test)
|
|
254
256
|
const status = getTestStatus(test)
|
|
255
257
|
|
|
256
258
|
// After finishing it might take a bit for the snapshot to be handled.
|
|
@@ -295,18 +297,17 @@ function getOnTestEndHandler (config) {
|
|
|
295
297
|
!test._ddIsEfdRetry
|
|
296
298
|
|
|
297
299
|
// if there are afterEach to be run, we don't finish the test yet
|
|
298
|
-
if (
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
})
|
|
300
|
+
if (ctx && !getAfterEachHooks(test).length) {
|
|
301
|
+
testFinishCh.publish({
|
|
302
|
+
status,
|
|
303
|
+
hasBeenRetried: isMochaRetry(test),
|
|
304
|
+
isLastRetry: getIsLastRetry(test),
|
|
305
|
+
hasFailedAllRetries,
|
|
306
|
+
attemptToFixPassed,
|
|
307
|
+
attemptToFixFailed,
|
|
308
|
+
isAttemptToFixRetry,
|
|
309
|
+
isAtrRetry,
|
|
310
|
+
...ctx.currentStore
|
|
310
311
|
})
|
|
311
312
|
}
|
|
312
313
|
}
|
|
@@ -320,10 +321,13 @@ function getOnHookEndHandler () {
|
|
|
320
321
|
const isLastAfterEach = afterEachHooks.indexOf(hook) === afterEachHooks.length - 1
|
|
321
322
|
if (isLastAfterEach) {
|
|
322
323
|
const status = getTestStatus(test)
|
|
323
|
-
const
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
const ctx = getTestContext(test)
|
|
325
|
+
if (ctx) {
|
|
326
|
+
testFinishCh.publish({
|
|
327
|
+
status,
|
|
328
|
+
hasBeenRetried: isMochaRetry(test),
|
|
329
|
+
isLastRetry: getIsLastRetry(test),
|
|
330
|
+
...ctx.currentStore
|
|
327
331
|
})
|
|
328
332
|
}
|
|
329
333
|
}
|
|
@@ -339,35 +343,34 @@ function getOnFailHandler (isMain) {
|
|
|
339
343
|
if (isHook && testOrHook.ctx) {
|
|
340
344
|
test = testOrHook.ctx.currentTest
|
|
341
345
|
}
|
|
342
|
-
let
|
|
346
|
+
let testContext
|
|
343
347
|
if (test) {
|
|
344
|
-
|
|
348
|
+
testContext = getTestContext(test)
|
|
345
349
|
}
|
|
346
|
-
if (
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
}
|
|
350
|
+
if (testContext) {
|
|
351
|
+
if (isHook) {
|
|
352
|
+
err.message = `${testOrHook.fullTitle()}: ${err.message}`
|
|
353
|
+
testContext.err = err
|
|
354
|
+
errorCh.runStores(testContext, () => { })
|
|
355
|
+
// if it's a hook and it has failed, 'test end' will not be called
|
|
356
|
+
testFinishCh.publish({ status: 'fail', hasBeenRetried: isMochaRetry(test), ...testContext.currentStore })
|
|
357
|
+
} else {
|
|
358
|
+
testContext.err = err
|
|
359
|
+
errorCh.runStores(testContext, () => { })
|
|
360
|
+
}
|
|
357
361
|
}
|
|
358
362
|
|
|
359
363
|
if (isMain) {
|
|
360
|
-
const
|
|
364
|
+
const testSuiteContext = testFileToSuiteCtx.get(testFile)
|
|
361
365
|
|
|
362
|
-
if (
|
|
366
|
+
if (testSuiteContext) {
|
|
363
367
|
// we propagate the error to the suite
|
|
364
368
|
const testSuiteError = new Error(
|
|
365
369
|
`"${testOrHook.parent.fullTitle()}" failed with message "${err.message}"`
|
|
366
370
|
)
|
|
367
371
|
testSuiteError.stack = err.stack
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
})
|
|
372
|
+
testSuiteContext.error = testSuiteError
|
|
373
|
+
testSuiteErrorCh.runStores(testSuiteContext, () => { })
|
|
371
374
|
}
|
|
372
375
|
}
|
|
373
376
|
}
|
|
@@ -375,20 +378,18 @@ function getOnFailHandler (isMain) {
|
|
|
375
378
|
|
|
376
379
|
function getOnTestRetryHandler (config) {
|
|
377
380
|
return function (test, err) {
|
|
378
|
-
const
|
|
379
|
-
if (
|
|
381
|
+
const ctx = getTestContext(test)
|
|
382
|
+
if (ctx) {
|
|
380
383
|
const isFirstAttempt = test._currentRetry === 0
|
|
381
384
|
const willBeRetried = test._currentRetry < test._retries
|
|
382
385
|
const isAtrRetry = !isFirstAttempt &&
|
|
383
386
|
config.isFlakyTestRetriesEnabled &&
|
|
384
387
|
!test._ddIsAttemptToFix &&
|
|
385
388
|
!test._ddIsEfdRetry
|
|
386
|
-
|
|
387
|
-
testRetryCh.publish({ isFirstAttempt, err, willBeRetried, test, isAtrRetry })
|
|
388
|
-
})
|
|
389
|
+
testRetryCh.publish({ isFirstAttempt, err, willBeRetried, test, isAtrRetry, ...ctx.currentStore })
|
|
389
390
|
}
|
|
390
|
-
const key =
|
|
391
|
-
|
|
391
|
+
const key = getTestToContextKey(test)
|
|
392
|
+
testToContext.delete(key)
|
|
392
393
|
}
|
|
393
394
|
}
|
|
394
395
|
|
|
@@ -407,23 +408,19 @@ function getOnPendingHandler () {
|
|
|
407
408
|
testStartLine
|
|
408
409
|
}
|
|
409
410
|
|
|
410
|
-
const
|
|
411
|
-
if (
|
|
412
|
-
|
|
413
|
-
skipCh.publish(testInfo)
|
|
414
|
-
})
|
|
411
|
+
const ctx = getTestContext(test)
|
|
412
|
+
if (ctx) {
|
|
413
|
+
skipCh.publish(testInfo)
|
|
415
414
|
} else {
|
|
416
|
-
// if there is no
|
|
415
|
+
// if there is no context, the test has been skipped through `test.skip`
|
|
417
416
|
// or the parent suite is skipped
|
|
418
|
-
const
|
|
417
|
+
const testCtx = testInfo
|
|
419
418
|
if (test.fn) {
|
|
420
|
-
|
|
419
|
+
testToContext.set(test.fn, testCtx)
|
|
421
420
|
} else {
|
|
422
|
-
|
|
421
|
+
testToContext.set(test, testCtx)
|
|
423
422
|
}
|
|
424
|
-
|
|
425
|
-
skipCh.publish(testInfo)
|
|
426
|
-
})
|
|
423
|
+
skipCh.runStores(testCtx, () => { })
|
|
427
424
|
}
|
|
428
425
|
}
|
|
429
426
|
}
|
|
@@ -484,9 +481,9 @@ module.exports = {
|
|
|
484
481
|
getTestFullName,
|
|
485
482
|
getTestStatus,
|
|
486
483
|
runnableWrapper,
|
|
487
|
-
|
|
484
|
+
testToContext,
|
|
488
485
|
originalFns,
|
|
489
|
-
|
|
486
|
+
getTestContext,
|
|
490
487
|
testToStartLine,
|
|
491
488
|
getOnTestHandler,
|
|
492
489
|
getOnTestEndHandler,
|
|
@@ -494,7 +491,7 @@ module.exports = {
|
|
|
494
491
|
getOnHookEndHandler,
|
|
495
492
|
getOnFailHandler,
|
|
496
493
|
getOnPendingHandler,
|
|
497
|
-
|
|
494
|
+
testFileToSuiteCtx,
|
|
498
495
|
getRunTestsWrapper,
|
|
499
496
|
newTests,
|
|
500
497
|
testsQuarantined,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { errorMonitor } = require('node:events')
|
|
4
|
+
|
|
3
5
|
const {
|
|
4
6
|
channel,
|
|
5
7
|
addHook,
|
|
@@ -138,7 +140,7 @@ function wrapConnection (Connection, version) {
|
|
|
138
140
|
onResult.apply(this, arguments)
|
|
139
141
|
}, 'bound-anonymous-fn', this))
|
|
140
142
|
} else {
|
|
141
|
-
this.on(
|
|
143
|
+
this.on(errorMonitor, asyncResource.bind(error => errorCh.publish(error)))
|
|
142
144
|
this.on('end', asyncResource.bind(() => finishCh.publish(undefined)))
|
|
143
145
|
}
|
|
144
146
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { errorMonitor } = require('events')
|
|
4
|
+
|
|
3
5
|
const { channel, addHook } = require('./helpers/instrument')
|
|
4
6
|
const shimmer = require('../../datadog-shimmer')
|
|
5
7
|
|
|
@@ -99,7 +101,7 @@ function getOptions (args) {
|
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
function setupListeners (socket, protocol, ctx, finishCh, errorCh) {
|
|
102
|
-
const events = ['connect',
|
|
104
|
+
const events = ['connect', errorMonitor, 'close', 'timeout']
|
|
103
105
|
|
|
104
106
|
const wrapListener = function (error) {
|
|
105
107
|
if (error) {
|
|
@@ -70,7 +70,7 @@ function wrapRenderToHTML (renderToHTML) {
|
|
|
70
70
|
|
|
71
71
|
function wrapRenderErrorToHTML (renderErrorToHTML) {
|
|
72
72
|
return function (err, req, res, pathname, query) {
|
|
73
|
-
return instrument(req, res,
|
|
73
|
+
return instrument(req, res, () => renderErrorToHTML.apply(this, arguments), err)
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -82,7 +82,7 @@ function wrapRenderToResponse (renderToResponse) {
|
|
|
82
82
|
|
|
83
83
|
function wrapRenderErrorToResponse (renderErrorToResponse) {
|
|
84
84
|
return function (ctx, err) {
|
|
85
|
-
return instrument(ctx.req, ctx.res,
|
|
85
|
+
return instrument(ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments), err)
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -121,12 +121,7 @@ function getRequestMeta (req, key) {
|
|
|
121
121
|
return typeof key === 'string' ? meta[key] : meta
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
function instrument (req, res,
|
|
125
|
-
if (typeof error === 'function') {
|
|
126
|
-
handler = error
|
|
127
|
-
error = null
|
|
128
|
-
}
|
|
129
|
-
|
|
124
|
+
function instrument (req, res, handler, error) {
|
|
130
125
|
req = req.originalRequest || req
|
|
131
126
|
res = res.originalResponse || res
|
|
132
127
|
|
|
@@ -216,13 +211,13 @@ addHook({
|
|
|
216
211
|
name: 'next',
|
|
217
212
|
versions: ['>=11.1'],
|
|
218
213
|
file: 'dist/server/serve-static.js'
|
|
219
|
-
}, serveStatic => shimmer.wrap(serveStatic, 'serveStatic', wrapServeStatic))
|
|
214
|
+
}, serveStatic => shimmer.wrap(serveStatic, 'serveStatic', wrapServeStatic, { replaceGetter: true }))
|
|
220
215
|
|
|
221
216
|
addHook({
|
|
222
217
|
name: 'next',
|
|
223
218
|
versions: ['>=10.2 <11.1'],
|
|
224
219
|
file: 'dist/next-server/server/serve-static.js'
|
|
225
|
-
}, serveStatic => shimmer.wrap(serveStatic, 'serveStatic', wrapServeStatic))
|
|
220
|
+
}, serveStatic => shimmer.wrap(serveStatic, 'serveStatic', wrapServeStatic, { replaceGetter: true }))
|
|
226
221
|
|
|
227
222
|
addHook({ name: 'next', versions: ['>=11.1'], file: 'dist/server/next-server.js' }, nextServer => {
|
|
228
223
|
const Server = nextServer.default
|
|
@@ -282,8 +277,7 @@ addHook({
|
|
|
282
277
|
versions: ['>=13'],
|
|
283
278
|
file: 'dist/server/web/spec-extension/request.js'
|
|
284
279
|
}, request => {
|
|
285
|
-
|
|
286
|
-
shimmer.wrap(nextUrlDescriptor, 'get', function (originalGet) {
|
|
280
|
+
shimmer.wrap(request.NextRequest.prototype, 'nextUrl', function (originalGet) {
|
|
287
281
|
return function wrappedGet () {
|
|
288
282
|
const nextUrl = originalGet.apply(this, arguments)
|
|
289
283
|
if (queryParsedChannel.hasSubscribers) {
|
|
@@ -300,8 +294,6 @@ addHook({
|
|
|
300
294
|
}
|
|
301
295
|
})
|
|
302
296
|
|
|
303
|
-
Object.defineProperty(request.NextRequest.prototype, 'nextUrl', nextUrlDescriptor)
|
|
304
|
-
|
|
305
297
|
shimmer.massWrap(request.NextRequest.prototype, ['text', 'json'], function (originalMethod) {
|
|
306
298
|
return async function wrappedJson () {
|
|
307
299
|
const body = await originalMethod.apply(this, arguments)
|
|
@@ -45,7 +45,7 @@ function wrapQuery (query) {
|
|
|
45
45
|
const textProp = Object.getOwnPropertyDescriptor(textPropObj, 'text')
|
|
46
46
|
const stream = typeof textPropObj.read === 'function'
|
|
47
47
|
|
|
48
|
-
// Only alter `text` property if safe to do so.
|
|
48
|
+
// Only alter `text` property if safe to do so. Initially, it's a property, not a getter.
|
|
49
49
|
if (!textProp || textProp.configurable) {
|
|
50
50
|
const originalText = textPropObj.text
|
|
51
51
|
|
|
@@ -129,21 +129,15 @@ function wrapQuery (query) {
|
|
|
129
129
|
}
|
|
130
130
|
} else if (newQuery.once) {
|
|
131
131
|
newQuery
|
|
132
|
-
.once(
|
|
132
|
+
.once(errorMonitor, finish)
|
|
133
133
|
.once('end', (res) => finish(null, res))
|
|
134
134
|
} else {
|
|
135
|
+
// TODO: This code is never reached in our tests.
|
|
136
|
+
// Internally, pg always uses callbacks or streams, even for promise based queries.
|
|
137
|
+
// Investigate if this code should just be removed.
|
|
135
138
|
newQuery.then((res) => finish(null, res), finish)
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
if (stream) {
|
|
139
|
-
newQuery.on('end', () => {
|
|
140
|
-
finish(null, [])
|
|
141
|
-
})
|
|
142
|
-
newQuery.on(errorMonitor, (err) => {
|
|
143
|
-
finish(err)
|
|
144
|
-
})
|
|
145
|
-
}
|
|
146
|
-
|
|
147
141
|
try {
|
|
148
142
|
return retval
|
|
149
143
|
} catch (err) {
|
|
@@ -25,8 +25,8 @@ const testSuiteFinishCh = channel('ci:playwright:test-suite:finish')
|
|
|
25
25
|
const workerReportCh = channel('ci:playwright:worker:report')
|
|
26
26
|
const testPageGotoCh = channel('ci:playwright:test:page-goto')
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
const
|
|
28
|
+
const testToCtx = new WeakMap()
|
|
29
|
+
const testSuiteToCtx = new Map()
|
|
30
30
|
const testSuiteToTestStatuses = new Map()
|
|
31
31
|
const testSuiteToErrors = new Map()
|
|
32
32
|
const testsToTestStatuses = new Map()
|
|
@@ -279,11 +279,9 @@ function testBeginHandler (test, browserName, isMainProcess) {
|
|
|
279
279
|
|
|
280
280
|
if (isNewTestSuite) {
|
|
281
281
|
startedSuites.push(testSuiteAbsolutePath)
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
testSuiteStartCh.publish(testSuiteAbsolutePath)
|
|
286
|
-
})
|
|
282
|
+
const testSuiteCtx = { testSuiteAbsolutePath }
|
|
283
|
+
testSuiteToCtx.set(testSuiteAbsolutePath, testSuiteCtx)
|
|
284
|
+
testSuiteStartCh.runStores(testSuiteCtx, () => { })
|
|
287
285
|
}
|
|
288
286
|
|
|
289
287
|
// We disable retries by default if attemptToFix is true
|
|
@@ -293,19 +291,17 @@ function testBeginHandler (test, browserName, isMainProcess) {
|
|
|
293
291
|
|
|
294
292
|
// this handles tests that do not go through the worker process (because they're skipped)
|
|
295
293
|
if (isMainProcess) {
|
|
296
|
-
const testAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
297
|
-
testToAr.set(test, testAsyncResource)
|
|
298
294
|
const testName = getTestFullname(test)
|
|
295
|
+
const testCtx = {
|
|
296
|
+
testName,
|
|
297
|
+
testSuiteAbsolutePath,
|
|
298
|
+
testSourceLine,
|
|
299
|
+
browserName,
|
|
300
|
+
isDisabled: test._ddIsDisabled
|
|
301
|
+
}
|
|
302
|
+
testToCtx.set(test, testCtx)
|
|
299
303
|
|
|
300
|
-
|
|
301
|
-
testStartCh.publish({
|
|
302
|
-
testName,
|
|
303
|
-
testSuiteAbsolutePath,
|
|
304
|
-
testSourceLine,
|
|
305
|
-
browserName,
|
|
306
|
-
isDisabled: test._ddIsDisabled
|
|
307
|
-
})
|
|
308
|
-
})
|
|
304
|
+
testStartCh.runStores(testCtx, () => { })
|
|
309
305
|
}
|
|
310
306
|
}
|
|
311
307
|
|
|
@@ -350,28 +346,27 @@ function testEndHandler (test, annotations, testStatus, error, isTimeout, isMain
|
|
|
350
346
|
// this handles tests that do not go through the worker process (because they're skipped)
|
|
351
347
|
if (isMainProcess) {
|
|
352
348
|
const testResult = results[results.length - 1]
|
|
353
|
-
const
|
|
349
|
+
const testCtx = testToCtx.get(test)
|
|
354
350
|
const isAtrRetry = testResult?.retry > 0 &&
|
|
355
351
|
isFlakyTestRetriesEnabled &&
|
|
356
352
|
!test._ddIsAttemptToFix &&
|
|
357
353
|
!test._ddIsEfdRetry
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
})
|
|
354
|
+
testFinishCh.publish({
|
|
355
|
+
testStatus,
|
|
356
|
+
steps: testResult?.steps || [],
|
|
357
|
+
isRetry: testResult?.retry > 0,
|
|
358
|
+
error,
|
|
359
|
+
extraTags: annotationTags,
|
|
360
|
+
isNew: test._ddIsNew,
|
|
361
|
+
isAttemptToFix: test._ddIsAttemptToFix,
|
|
362
|
+
isAttemptToFixRetry: test._ddIsAttemptToFixRetry,
|
|
363
|
+
isQuarantined: test._ddIsQuarantined,
|
|
364
|
+
isEfdRetry: test._ddIsEfdRetry,
|
|
365
|
+
hasFailedAllRetries: test._ddHasFailedAllRetries,
|
|
366
|
+
hasPassedAttemptToFixRetries: test._ddHasPassedAttemptToFixRetries,
|
|
367
|
+
hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
|
|
368
|
+
isAtrRetry,
|
|
369
|
+
...testCtx.currentStore
|
|
375
370
|
})
|
|
376
371
|
}
|
|
377
372
|
|
|
@@ -401,10 +396,8 @@ function testEndHandler (test, annotations, testStatus, error, isTimeout, isMain
|
|
|
401
396
|
}
|
|
402
397
|
|
|
403
398
|
const suiteError = getTestSuiteError(testSuiteAbsolutePath)
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
testSuiteFinishCh.publish({ status: testSuiteStatus, error: suiteError })
|
|
407
|
-
})
|
|
399
|
+
const testSuiteCtx = testSuiteToCtx.get(testSuiteAbsolutePath)
|
|
400
|
+
testSuiteFinishCh.publish({ status: testSuiteStatus, error: suiteError, ...testSuiteCtx.currentStore })
|
|
408
401
|
}
|
|
409
402
|
}
|
|
410
403
|
|
|
@@ -610,7 +603,7 @@ function runnerHook (runnerExport, playwrightVersion) {
|
|
|
610
603
|
totalAttemptToFixFailedTestCount += testStatuses.filter(status => status === 'fail').length
|
|
611
604
|
}
|
|
612
605
|
|
|
613
|
-
if (totalFailedTestCount === totalAttemptToFixFailedTestCount) {
|
|
606
|
+
if (totalFailedTestCount > 0 && totalFailedTestCount === totalAttemptToFixFailedTestCount) {
|
|
614
607
|
runAllTestsReturn = 'passed'
|
|
615
608
|
}
|
|
616
609
|
}
|
|
@@ -873,17 +866,16 @@ addHook({
|
|
|
873
866
|
// If test events are created in the worker process I need to stop creating it in the main process
|
|
874
867
|
// Probably yet another test worker exporter is needed in addition to the ones for mocha, jest and cucumber
|
|
875
868
|
// it's probably hard to tell that's a playwright worker though, as I don't think there is a specific env variable
|
|
876
|
-
const
|
|
869
|
+
const testCtx = {
|
|
870
|
+
testName,
|
|
871
|
+
testSuiteAbsolutePath,
|
|
872
|
+
testSourceLine,
|
|
873
|
+
browserName
|
|
874
|
+
}
|
|
875
|
+
testToCtx.set(test, testCtx)
|
|
877
876
|
// TODO - In the future we may need to implement a mechanism to send test properties
|
|
878
877
|
// to the worker process before _runTest is called
|
|
879
|
-
|
|
880
|
-
testStartCh.publish({
|
|
881
|
-
testName,
|
|
882
|
-
testSuiteAbsolutePath,
|
|
883
|
-
testSourceLine,
|
|
884
|
-
browserName
|
|
885
|
-
})
|
|
886
|
-
|
|
878
|
+
testStartCh.runStores(testCtx, () => {
|
|
887
879
|
let existAfterEachHook = false
|
|
888
880
|
|
|
889
881
|
// We try to find an existing afterEach hook with _ddHook to avoid adding a new one
|
|
@@ -976,25 +968,24 @@ addHook({
|
|
|
976
968
|
// Wait for the properties to be received
|
|
977
969
|
await ddPropertiesPromise
|
|
978
970
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
})
|
|
971
|
+
testFinishCh.publish({
|
|
972
|
+
testStatus: STATUS_TO_TEST_STATUS[status],
|
|
973
|
+
steps: steps.filter(step => step.testId === testId),
|
|
974
|
+
error,
|
|
975
|
+
extraTags: annotationTags,
|
|
976
|
+
isNew: test._ddIsNew,
|
|
977
|
+
isRetry: retry > 0,
|
|
978
|
+
isEfdRetry: test._ddIsEfdRetry,
|
|
979
|
+
isAttemptToFix: test._ddIsAttemptToFix,
|
|
980
|
+
isDisabled: test._ddIsDisabled,
|
|
981
|
+
isQuarantined: test._ddIsQuarantined,
|
|
982
|
+
isAttemptToFixRetry: test._ddIsAttemptToFixRetry,
|
|
983
|
+
hasFailedAllRetries: test._ddHasFailedAllRetries,
|
|
984
|
+
hasPassedAttemptToFixRetries: test._ddHasPassedAttemptToFixRetries,
|
|
985
|
+
hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
|
|
986
|
+
isAtrRetry: test._ddIsAtrRetry,
|
|
987
|
+
onDone,
|
|
988
|
+
...testCtx.currentStore
|
|
998
989
|
})
|
|
999
990
|
|
|
1000
991
|
await flushPromise
|
|
@@ -26,23 +26,17 @@ addHook({ name: names }, function (url) {
|
|
|
26
26
|
|
|
27
27
|
const URLPrototype = url.URL.prototype.constructor.prototype
|
|
28
28
|
instrumentedGetters.forEach(property => {
|
|
29
|
-
|
|
29
|
+
shimmer.wrap(URLPrototype, property, function (originalGet) {
|
|
30
|
+
return function get () {
|
|
31
|
+
const result = originalGet.call(this)
|
|
32
|
+
if (!urlGetterChannel.hasSubscribers) return result
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return function get () {
|
|
34
|
-
const result = originalGet.apply(this, arguments)
|
|
35
|
-
if (!urlGetterChannel.hasSubscribers) return result
|
|
34
|
+
const context = { urlObject: this, result, property }
|
|
35
|
+
urlGetterChannel.publish(context)
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return context.result
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
Object.defineProperty(URLPrototype, property, newDescriptor)
|
|
45
|
-
}
|
|
37
|
+
return context.result
|
|
38
|
+
}
|
|
39
|
+
})
|
|
46
40
|
})
|
|
47
41
|
|
|
48
42
|
shimmer.wrap(url, 'URL', (URL) => {
|
|
@@ -83,6 +77,4 @@ addHook({ name: names }, function (url) {
|
|
|
83
77
|
}
|
|
84
78
|
})
|
|
85
79
|
}
|
|
86
|
-
|
|
87
|
-
return url
|
|
88
80
|
})
|