@cucumber/query 13.2.0 → 13.4.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/.mocharc.json +1 -0
- package/.prettierrc.json +6 -0
- package/dist/src/Query.d.ts +12 -7
- package/dist/src/Query.d.ts.map +1 -1
- package/dist/src/Query.js +64 -34
- package/dist/src/Query.js.map +1 -1
- package/dist/src/helpers.d.ts +2 -8
- package/dist/src/helpers.d.ts.map +1 -1
- package/dist/src/helpers.js +3 -26
- package/dist/src/helpers.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/eslint.config.mjs +67 -0
- package/package.json +28 -35
- package/src/Query.spec.ts +86 -9
- package/src/Query.ts +127 -70
- package/src/acceptance.spec.ts +236 -160
- package/src/helpers.ts +16 -44
- package/src/helpers.spec.ts +0 -15
package/src/Query.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getWorstTestStepResult,
|
|
7
7
|
GherkinDocument,
|
|
8
8
|
Hook,
|
|
9
|
+
Location,
|
|
9
10
|
Meta,
|
|
10
11
|
Pickle,
|
|
11
12
|
PickleStep,
|
|
@@ -21,11 +22,14 @@ import {
|
|
|
21
22
|
TestStepFinished,
|
|
22
23
|
TestStepResult,
|
|
23
24
|
TestStepResultStatus,
|
|
25
|
+
TestStepStarted,
|
|
24
26
|
TimeConversion,
|
|
25
27
|
} from '@cucumber/messages'
|
|
26
|
-
import {ArrayMultimap} from '@teppeis/multimaps'
|
|
27
|
-
import
|
|
28
|
-
|
|
28
|
+
import { ArrayMultimap } from '@teppeis/multimaps'
|
|
29
|
+
import sortBy from 'lodash.sortby'
|
|
30
|
+
|
|
31
|
+
import { assert, statusOrdinal } from './helpers'
|
|
32
|
+
import { Lineage, NamingStrategy } from './Lineage'
|
|
29
33
|
|
|
30
34
|
export default class Query {
|
|
31
35
|
private readonly testStepResultByPickleId = new ArrayMultimap<string, messages.TestStepResult>()
|
|
@@ -51,7 +55,7 @@ export default class Query {
|
|
|
51
55
|
private meta: Meta
|
|
52
56
|
private testRunStarted: TestRunStarted
|
|
53
57
|
private testRunFinished: TestRunFinished
|
|
54
|
-
private readonly
|
|
58
|
+
private readonly testCaseStartedById: Map<string, TestCaseStarted> = new Map()
|
|
55
59
|
private readonly lineageById: Map<string, Lineage> = new Map()
|
|
56
60
|
private readonly stepById: Map<string, Step> = new Map()
|
|
57
61
|
private readonly pickleById: Map<string, Pickle> = new Map()
|
|
@@ -59,10 +63,12 @@ export default class Query {
|
|
|
59
63
|
private readonly testCaseById: Map<string, TestCase> = new Map()
|
|
60
64
|
private readonly testStepById: Map<string, TestStep> = new Map()
|
|
61
65
|
private readonly testCaseFinishedByTestCaseStartedId: Map<string, TestCaseFinished> = new Map()
|
|
66
|
+
private readonly testStepStartedByTestCaseStartedId: ArrayMultimap<string, TestStepStarted> =
|
|
67
|
+
new ArrayMultimap()
|
|
62
68
|
private readonly testStepFinishedByTestCaseStartedId: ArrayMultimap<string, TestStepFinished> =
|
|
63
|
-
|
|
69
|
+
new ArrayMultimap()
|
|
64
70
|
private readonly attachmentsByTestCaseStartedId: ArrayMultimap<string, Attachment> =
|
|
65
|
-
|
|
71
|
+
new ArrayMultimap()
|
|
66
72
|
|
|
67
73
|
public update(envelope: messages.Envelope) {
|
|
68
74
|
if (envelope.meta) {
|
|
@@ -86,6 +92,9 @@ export default class Query {
|
|
|
86
92
|
if (envelope.testCaseStarted) {
|
|
87
93
|
this.updateTestCaseStarted(envelope.testCaseStarted)
|
|
88
94
|
}
|
|
95
|
+
if (envelope.testStepStarted) {
|
|
96
|
+
this.updateTestStepStarted(envelope.testStepStarted)
|
|
97
|
+
}
|
|
89
98
|
if (envelope.attachment) {
|
|
90
99
|
this.updateAttachment(envelope.attachment)
|
|
91
100
|
}
|
|
@@ -187,14 +196,14 @@ export default class Query {
|
|
|
187
196
|
this.pickleStepIdByTestStepId.set(testStep.id, testStep.pickleStepId)
|
|
188
197
|
this.testStepIdsByPickleStepId.put(testStep.pickleStepId, testStep.id)
|
|
189
198
|
this.stepMatchArgumentsListsByPickleStepId.set(
|
|
190
|
-
|
|
191
|
-
|
|
199
|
+
testStep.pickleStepId,
|
|
200
|
+
testStep.stepMatchArgumentsLists
|
|
192
201
|
)
|
|
193
202
|
})
|
|
194
203
|
}
|
|
195
204
|
|
|
196
205
|
private updateTestCaseStarted(testCaseStarted: TestCaseStarted) {
|
|
197
|
-
this.
|
|
206
|
+
this.testCaseStartedById.set(testCaseStarted.id, testCaseStarted)
|
|
198
207
|
|
|
199
208
|
/*
|
|
200
209
|
when a test case attempt starts besides the first one, clear all existing results
|
|
@@ -202,14 +211,20 @@ export default class Query {
|
|
|
202
211
|
(applies to legacy pickle-oriented query methods only)
|
|
203
212
|
*/
|
|
204
213
|
const testCase = this.testCaseById.get(testCaseStarted.testCaseId)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
if (testCase) {
|
|
215
|
+
this.testStepResultByPickleId.delete(testCase.pickleId)
|
|
216
|
+
for (const testStep of testCase.testSteps) {
|
|
217
|
+
this.testStepResultsByPickleStepId.delete(testStep.pickleStepId)
|
|
218
|
+
this.testStepResultsbyTestStepId.delete(testStep.id)
|
|
219
|
+
this.attachmentsByTestStepId.delete(testStep.id)
|
|
220
|
+
}
|
|
210
221
|
}
|
|
211
222
|
}
|
|
212
223
|
|
|
224
|
+
private updateTestStepStarted(testStepStarted: TestStepStarted) {
|
|
225
|
+
this.testStepStartedByTestCaseStartedId.put(testStepStarted.testCaseStartedId, testStepStarted)
|
|
226
|
+
}
|
|
227
|
+
|
|
213
228
|
private updateAttachment(attachment: Attachment) {
|
|
214
229
|
if (attachment.testStepId) {
|
|
215
230
|
this.attachmentsByTestStepId.put(attachment.testStepId, attachment)
|
|
@@ -221,24 +236,21 @@ export default class Query {
|
|
|
221
236
|
|
|
222
237
|
private updateTestStepFinished(testStepFinished: TestStepFinished) {
|
|
223
238
|
this.testStepFinishedByTestCaseStartedId.put(
|
|
224
|
-
|
|
225
|
-
|
|
239
|
+
testStepFinished.testCaseStartedId,
|
|
240
|
+
testStepFinished
|
|
226
241
|
)
|
|
227
242
|
|
|
228
243
|
const pickleId = this.pickleIdByTestStepId.get(testStepFinished.testStepId)
|
|
229
244
|
this.testStepResultByPickleId.put(pickleId, testStepFinished.testStepResult)
|
|
230
245
|
const testStep = this.testStepById.get(testStepFinished.testStepId)
|
|
231
|
-
this.testStepResultsByPickleStepId.put(
|
|
232
|
-
testStep.pickleStepId,
|
|
233
|
-
testStepFinished.testStepResult
|
|
234
|
-
)
|
|
246
|
+
this.testStepResultsByPickleStepId.put(testStep.pickleStepId, testStepFinished.testStepResult)
|
|
235
247
|
this.testStepResultsbyTestStepId.put(testStep.id, testStepFinished.testStepResult)
|
|
236
248
|
}
|
|
237
249
|
|
|
238
250
|
private updateTestCaseFinished(testCaseFinished: TestCaseFinished) {
|
|
239
251
|
this.testCaseFinishedByTestCaseStartedId.set(
|
|
240
|
-
|
|
241
|
-
|
|
252
|
+
testCaseFinished.testCaseStartedId,
|
|
253
|
+
testCaseFinished
|
|
242
254
|
)
|
|
243
255
|
}
|
|
244
256
|
|
|
@@ -353,7 +365,11 @@ export default class Query {
|
|
|
353
365
|
|
|
354
366
|
for (const step of testCase.testSteps) {
|
|
355
367
|
if (step.hookId) {
|
|
356
|
-
|
|
368
|
+
if (pickleStepFound) {
|
|
369
|
+
onAfterHookFound(step)
|
|
370
|
+
} else {
|
|
371
|
+
onBeforeHookFound(step)
|
|
372
|
+
}
|
|
357
373
|
} else {
|
|
358
374
|
pickleStepFound = true
|
|
359
375
|
}
|
|
@@ -389,10 +405,12 @@ export default class Query {
|
|
|
389
405
|
[TestStepResultStatus.UNKNOWN]: 0,
|
|
390
406
|
}
|
|
391
407
|
for (const testCaseStarted of this.findAllTestCaseStarted()) {
|
|
392
|
-
const mostSevereResult =
|
|
393
|
-
.
|
|
394
|
-
|
|
395
|
-
|
|
408
|
+
const mostSevereResult = sortBy(
|
|
409
|
+
this.findTestStepFinishedAndTestStepBy(testCaseStarted).map(
|
|
410
|
+
([testStepFinished]) => testStepFinished.testStepResult
|
|
411
|
+
),
|
|
412
|
+
[(testStepResult) => statusOrdinal(testStepResult.status)]
|
|
413
|
+
).at(-1)
|
|
396
414
|
if (mostSevereResult) {
|
|
397
415
|
result[mostSevereResult.status]++
|
|
398
416
|
}
|
|
@@ -406,41 +424,54 @@ export default class Query {
|
|
|
406
424
|
|
|
407
425
|
public findAllPickles(): ReadonlyArray<Pickle> {
|
|
408
426
|
const pickles = [...this.pickleById.values()]
|
|
409
|
-
return pickles
|
|
427
|
+
return sortBy(pickles, ['id'])
|
|
410
428
|
}
|
|
411
429
|
|
|
412
430
|
public findAllPickleSteps(): ReadonlyArray<PickleStep> {
|
|
413
431
|
const pickleSteps = [...this.pickleStepById.values()]
|
|
414
|
-
return pickleSteps
|
|
432
|
+
return sortBy(pickleSteps, ['id'])
|
|
415
433
|
}
|
|
416
434
|
|
|
417
435
|
public findAllTestCaseStarted(): ReadonlyArray<TestCaseStarted> {
|
|
418
|
-
return
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
436
|
+
return sortBy(
|
|
437
|
+
[...this.testCaseStartedById.values()].filter((testCaseStarted) => {
|
|
438
|
+
const testCaseFinished = this.testCaseFinishedByTestCaseStartedId.get(testCaseStarted.id)
|
|
439
|
+
// only include if not yet finished OR won't be retried
|
|
440
|
+
return !testCaseFinished?.willBeRetried
|
|
441
|
+
}),
|
|
442
|
+
[
|
|
443
|
+
(testCaseStarted) =>
|
|
444
|
+
TimeConversion.timestampToMillisecondsSinceEpoch(testCaseStarted.timestamp),
|
|
445
|
+
'id',
|
|
446
|
+
]
|
|
447
|
+
)
|
|
423
448
|
}
|
|
424
449
|
|
|
425
|
-
public findAllTestCaseStartedGroupedByFeature(): Map<
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
450
|
+
public findAllTestCaseStartedGroupedByFeature(): Map<
|
|
451
|
+
Feature | undefined,
|
|
452
|
+
ReadonlyArray<TestCaseStarted>
|
|
453
|
+
> {
|
|
454
|
+
const results = new Map()
|
|
455
|
+
sortBy(
|
|
456
|
+
this.findAllTestCaseStarted().map(
|
|
457
|
+
(testCaseStarted) => [this.findLineageBy(testCaseStarted), testCaseStarted] as const
|
|
458
|
+
),
|
|
459
|
+
[([lineage]) => lineage.gherkinDocument.uri]
|
|
460
|
+
).forEach(([{ feature }, testCaseStarted]) => {
|
|
461
|
+
results.set(feature, [...(results.get(feature) ?? []), testCaseStarted])
|
|
462
|
+
})
|
|
433
463
|
return results
|
|
434
464
|
}
|
|
435
465
|
|
|
436
466
|
public findAllTestSteps(): ReadonlyArray<TestStep> {
|
|
437
467
|
const testSteps = [...this.testStepById.values()]
|
|
438
|
-
return testSteps
|
|
468
|
+
return sortBy(testSteps, ['id'])
|
|
439
469
|
}
|
|
440
470
|
|
|
441
471
|
public findAttachmentsBy(testStepFinished: TestStepFinished): ReadonlyArray<Attachment> {
|
|
442
|
-
return this.attachmentsByTestCaseStartedId
|
|
443
|
-
|
|
472
|
+
return this.attachmentsByTestCaseStartedId
|
|
473
|
+
.get(testStepFinished.testCaseStartedId)
|
|
474
|
+
.filter((attachment) => attachment.testStepId === testStepFinished.testStepId)
|
|
444
475
|
}
|
|
445
476
|
|
|
446
477
|
public findFeatureBy(testCaseStarted: TestCaseStarted): Feature | undefined {
|
|
@@ -448,21 +479,25 @@ export default class Query {
|
|
|
448
479
|
}
|
|
449
480
|
|
|
450
481
|
public findHookBy(testStep: TestStep): Hook | undefined {
|
|
451
|
-
if (!testStep.hookId){
|
|
482
|
+
if (!testStep.hookId) {
|
|
452
483
|
return undefined
|
|
453
484
|
}
|
|
454
485
|
return this.hooksById.get(testStep.hookId)
|
|
455
486
|
}
|
|
456
487
|
|
|
457
488
|
public findMeta(): Meta | undefined {
|
|
458
|
-
return this.meta
|
|
489
|
+
return this.meta
|
|
459
490
|
}
|
|
460
491
|
|
|
461
|
-
public findMostSevereTestStepResultBy(
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
.
|
|
492
|
+
public findMostSevereTestStepResultBy(
|
|
493
|
+
testCaseStarted: TestCaseStarted
|
|
494
|
+
): TestStepResult | undefined {
|
|
495
|
+
return sortBy(
|
|
496
|
+
this.findTestStepFinishedAndTestStepBy(testCaseStarted).map(
|
|
497
|
+
([testStepFinished]) => testStepFinished.testStepResult
|
|
498
|
+
),
|
|
499
|
+
[(testStepResult) => statusOrdinal(testStepResult.status)]
|
|
500
|
+
).at(-1)
|
|
466
501
|
}
|
|
467
502
|
|
|
468
503
|
public findNameOf(pickle: Pickle, namingStrategy: NamingStrategy): string {
|
|
@@ -470,14 +505,22 @@ export default class Query {
|
|
|
470
505
|
return lineage ? namingStrategy.reduce(lineage, pickle) : pickle.name
|
|
471
506
|
}
|
|
472
507
|
|
|
473
|
-
public
|
|
474
|
-
const
|
|
508
|
+
public findLocationOf(pickle: Pickle): Location | undefined {
|
|
509
|
+
const lineage = this.findLineageBy(pickle)
|
|
510
|
+
if (lineage?.example) {
|
|
511
|
+
return lineage.example.location
|
|
512
|
+
}
|
|
513
|
+
return lineage?.scenario?.location
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
public findPickleBy(element: TestCaseStarted | TestStepStarted): Pickle | undefined {
|
|
517
|
+
const testCase = this.findTestCaseBy(element)
|
|
475
518
|
assert.ok(testCase, 'Expected to find TestCase from TestCaseStarted')
|
|
476
519
|
return this.pickleById.get(testCase.pickleId)
|
|
477
520
|
}
|
|
478
521
|
|
|
479
522
|
public findPickleStepBy(testStep: TestStep): PickleStep | undefined {
|
|
480
|
-
if (!testStep.pickleStepId){
|
|
523
|
+
if (!testStep.pickleStepId) {
|
|
481
524
|
return undefined
|
|
482
525
|
}
|
|
483
526
|
return this.pickleStepById.get(testStep.pickleStepId)
|
|
@@ -489,7 +532,10 @@ export default class Query {
|
|
|
489
532
|
return this.stepById.get(astNodeId)
|
|
490
533
|
}
|
|
491
534
|
|
|
492
|
-
public findTestCaseBy(
|
|
535
|
+
public findTestCaseBy(element: TestCaseStarted | TestStepStarted): TestCase | undefined {
|
|
536
|
+
const testCaseStarted =
|
|
537
|
+
'testCaseStartedId' in element ? this.findTestCaseStartedBy(element) : element
|
|
538
|
+
assert.ok(testCaseStarted, 'Expected to find TestCaseStarted by TestStepStarted')
|
|
493
539
|
return this.testCaseById.get(testCaseStarted.testCaseId)
|
|
494
540
|
}
|
|
495
541
|
|
|
@@ -499,11 +545,15 @@ export default class Query {
|
|
|
499
545
|
return undefined
|
|
500
546
|
}
|
|
501
547
|
return TimeConversion.millisecondsToDuration(
|
|
502
|
-
|
|
548
|
+
TimeConversion.timestampToMillisecondsSinceEpoch(testCaseFinished.timestamp) -
|
|
503
549
|
TimeConversion.timestampToMillisecondsSinceEpoch(testCaseStarted.timestamp)
|
|
504
550
|
)
|
|
505
551
|
}
|
|
506
552
|
|
|
553
|
+
public findTestCaseStartedBy(testStepStarted: TestStepStarted): TestCaseStarted | undefined {
|
|
554
|
+
return this.testCaseStartedById.get(testStepStarted.testCaseStartedId)
|
|
555
|
+
}
|
|
556
|
+
|
|
507
557
|
public findTestCaseFinishedBy(testCaseStarted: TestCaseStarted): TestCaseFinished | undefined {
|
|
508
558
|
return this.testCaseFinishedByTestCaseStartedId.get(testCaseStarted.id)
|
|
509
559
|
}
|
|
@@ -513,7 +563,7 @@ export default class Query {
|
|
|
513
563
|
return undefined
|
|
514
564
|
}
|
|
515
565
|
return TimeConversion.millisecondsToDuration(
|
|
516
|
-
|
|
566
|
+
TimeConversion.timestampToMillisecondsSinceEpoch(this.testRunFinished.timestamp) -
|
|
517
567
|
TimeConversion.timestampToMillisecondsSinceEpoch(this.testRunStarted.timestamp)
|
|
518
568
|
)
|
|
519
569
|
}
|
|
@@ -526,29 +576,36 @@ export default class Query {
|
|
|
526
576
|
return this.testRunStarted
|
|
527
577
|
}
|
|
528
578
|
|
|
529
|
-
public findTestStepBy(
|
|
530
|
-
return this.testStepById.get(
|
|
579
|
+
public findTestStepBy(element: TestStepStarted | TestStepFinished): TestStep | undefined {
|
|
580
|
+
return this.testStepById.get(element.testStepId)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
public findTestStepsStartedBy(testCaseStarted: TestCaseStarted): ReadonlyArray<TestStepStarted> {
|
|
584
|
+
// multimaps `get` implements `getOrDefault([])` behaviour internally
|
|
585
|
+
return [...this.testStepStartedByTestCaseStartedId.get(testCaseStarted.id)]
|
|
531
586
|
}
|
|
532
587
|
|
|
533
|
-
public findTestStepsFinishedBy(
|
|
588
|
+
public findTestStepsFinishedBy(
|
|
589
|
+
testCaseStarted: TestCaseStarted
|
|
590
|
+
): ReadonlyArray<TestStepFinished> {
|
|
534
591
|
// multimaps `get` implements `getOrDefault([])` behaviour internally
|
|
535
592
|
return [...this.testStepFinishedByTestCaseStartedId.get(testCaseStarted.id)]
|
|
536
593
|
}
|
|
537
594
|
|
|
538
595
|
public findTestStepFinishedAndTestStepBy(
|
|
539
|
-
|
|
596
|
+
testCaseStarted: TestCaseStarted
|
|
540
597
|
): ReadonlyArray<[TestStepFinished, TestStep]> {
|
|
541
598
|
return this.testStepFinishedByTestCaseStartedId
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
599
|
+
.get(testCaseStarted.id)
|
|
600
|
+
.map((testStepFinished) => {
|
|
601
|
+
const testStep = this.findTestStepBy(testStepFinished)
|
|
602
|
+
assert.ok(testStep, 'Expected to find TestStep by TestStepFinished')
|
|
603
|
+
return [testStepFinished, testStep]
|
|
604
|
+
})
|
|
548
605
|
}
|
|
549
606
|
|
|
550
|
-
|
|
551
|
-
const pickle =
|
|
607
|
+
public findLineageBy(element: Pickle | TestCaseStarted): Lineage | undefined {
|
|
608
|
+
const pickle = 'testCaseId' in element ? this.findPickleBy(element) : element
|
|
552
609
|
const deepestAstNodeId = pickle.astNodeIds.at(-1)
|
|
553
610
|
assert.ok(deepestAstNodeId, 'Expected Pickle to have at least one astNodeId')
|
|
554
611
|
return this.lineageById.get(deepestAstNodeId)
|