@cucumber/query 14.7.0 → 15.0.1
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/dist/src/Lineage.d.ts +3 -1
- package/dist/src/Lineage.d.ts.map +1 -1
- package/dist/src/Lineage.js.map +1 -1
- package/dist/src/Query.d.ts +3 -37
- package/dist/src/Query.d.ts.map +1 -1
- package/dist/src/Query.js +37 -174
- package/dist/src/Query.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +7 -10
- package/src/Lineage.ts +3 -0
- package/src/Query.spec.ts +79 -584
- package/src/Query.ts +43 -196
- package/src/acceptance.spec.ts +28 -6
package/src/Query.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
Attachment,
|
|
4
4
|
Duration,
|
|
5
5
|
Feature,
|
|
6
|
-
getWorstTestStepResult,
|
|
7
6
|
GherkinDocument,
|
|
8
7
|
Hook,
|
|
9
8
|
Location,
|
|
@@ -37,26 +36,6 @@ import { assert, statusOrdinal } from './helpers'
|
|
|
37
36
|
import { Lineage } from './Lineage'
|
|
38
37
|
|
|
39
38
|
export default class Query {
|
|
40
|
-
private readonly testStepResultByPickleId = new ArrayMultimap<string, messages.TestStepResult>()
|
|
41
|
-
private readonly testStepResultsByPickleStepId = new ArrayMultimap<
|
|
42
|
-
string,
|
|
43
|
-
messages.TestStepResult
|
|
44
|
-
>()
|
|
45
|
-
private readonly testCaseByPickleId = new Map<string, messages.TestCase>()
|
|
46
|
-
private readonly pickleIdByTestStepId = new Map<string, string>()
|
|
47
|
-
private readonly pickleStepIdByTestStepId = new Map<string, string>()
|
|
48
|
-
private readonly testStepResultsbyTestStepId = new ArrayMultimap<
|
|
49
|
-
string,
|
|
50
|
-
messages.TestStepResult
|
|
51
|
-
>()
|
|
52
|
-
private readonly testStepIdsByPickleStepId = new ArrayMultimap<string, string>()
|
|
53
|
-
private readonly hooksById = new Map<string, messages.Hook>()
|
|
54
|
-
private readonly attachmentsByTestStepId = new ArrayMultimap<string, messages.Attachment>()
|
|
55
|
-
private readonly stepMatchArgumentsListsByPickleStepId = new Map<
|
|
56
|
-
string,
|
|
57
|
-
readonly messages.StepMatchArgumentsList[]
|
|
58
|
-
>()
|
|
59
|
-
|
|
60
39
|
private meta: Meta
|
|
61
40
|
private testRunStarted: TestRunStarted
|
|
62
41
|
private testRunFinished: TestRunFinished
|
|
@@ -65,6 +44,7 @@ export default class Query {
|
|
|
65
44
|
private readonly stepById: Map<string, Step> = new Map()
|
|
66
45
|
private readonly pickleById: Map<string, Pickle> = new Map()
|
|
67
46
|
private readonly pickleStepById: Map<string, PickleStep> = new Map()
|
|
47
|
+
private readonly hookById: Map<string, Hook> = new Map()
|
|
68
48
|
private readonly stepDefinitionById: Map<string, StepDefinition> = new Map()
|
|
69
49
|
private readonly testCaseById: Map<string, TestCase> = new Map()
|
|
70
50
|
private readonly testStepById: Map<string, TestStep> = new Map()
|
|
@@ -95,7 +75,7 @@ export default class Query {
|
|
|
95
75
|
this.updatePickle(envelope.pickle)
|
|
96
76
|
}
|
|
97
77
|
if (envelope.hook) {
|
|
98
|
-
this.
|
|
78
|
+
this.hookById.set(envelope.hook.id, envelope.hook)
|
|
99
79
|
}
|
|
100
80
|
if (envelope.stepDefinition) {
|
|
101
81
|
this.stepDefinitionById.set(envelope.stepDefinition.id, envelope.stepDefinition)
|
|
@@ -149,6 +129,7 @@ export default class Query {
|
|
|
149
129
|
private updateFeature(feature: Feature, lineage: Lineage) {
|
|
150
130
|
feature.children.forEach((featureChild) => {
|
|
151
131
|
if (featureChild.background) {
|
|
132
|
+
lineage.background = featureChild.background
|
|
152
133
|
this.updateSteps(featureChild.background.steps)
|
|
153
134
|
}
|
|
154
135
|
if (featureChild.scenario) {
|
|
@@ -169,6 +150,7 @@ export default class Query {
|
|
|
169
150
|
private updateRule(rule: Rule, lineage: Lineage) {
|
|
170
151
|
rule.children.forEach((ruleChild) => {
|
|
171
152
|
if (ruleChild.background) {
|
|
153
|
+
lineage.ruleBackground = ruleChild.background
|
|
172
154
|
this.updateSteps(ruleChild.background.steps)
|
|
173
155
|
}
|
|
174
156
|
if (ruleChild.scenario) {
|
|
@@ -228,37 +210,13 @@ export default class Query {
|
|
|
228
210
|
|
|
229
211
|
private updateTestCase(testCase: TestCase) {
|
|
230
212
|
this.testCaseById.set(testCase.id, testCase)
|
|
231
|
-
|
|
232
|
-
this.testCaseByPickleId.set(testCase.pickleId, testCase)
|
|
233
213
|
testCase.testSteps.forEach((testStep) => {
|
|
234
214
|
this.testStepById.set(testStep.id, testStep)
|
|
235
|
-
this.pickleIdByTestStepId.set(testStep.id, testCase.pickleId)
|
|
236
|
-
this.pickleStepIdByTestStepId.set(testStep.id, testStep.pickleStepId)
|
|
237
|
-
this.testStepIdsByPickleStepId.put(testStep.pickleStepId, testStep.id)
|
|
238
|
-
this.stepMatchArgumentsListsByPickleStepId.set(
|
|
239
|
-
testStep.pickleStepId,
|
|
240
|
-
testStep.stepMatchArgumentsLists
|
|
241
|
-
)
|
|
242
215
|
})
|
|
243
216
|
}
|
|
244
217
|
|
|
245
218
|
private updateTestCaseStarted(testCaseStarted: TestCaseStarted) {
|
|
246
219
|
this.testCaseStartedById.set(testCaseStarted.id, testCaseStarted)
|
|
247
|
-
|
|
248
|
-
/*
|
|
249
|
-
when a test case attempt starts besides the first one, clear all existing results
|
|
250
|
-
and attachments for that test case, so we always report on the latest attempt
|
|
251
|
-
(applies to legacy pickle-oriented query methods only)
|
|
252
|
-
*/
|
|
253
|
-
const testCase = this.testCaseById.get(testCaseStarted.testCaseId)
|
|
254
|
-
if (testCase) {
|
|
255
|
-
this.testStepResultByPickleId.delete(testCase.pickleId)
|
|
256
|
-
for (const testStep of testCase.testSteps) {
|
|
257
|
-
this.testStepResultsByPickleStepId.delete(testStep.pickleStepId)
|
|
258
|
-
this.testStepResultsbyTestStepId.delete(testStep.id)
|
|
259
|
-
this.attachmentsByTestStepId.delete(testStep.id)
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
220
|
}
|
|
263
221
|
|
|
264
222
|
private updateTestStepStarted(testStepStarted: TestStepStarted) {
|
|
@@ -266,9 +224,6 @@ export default class Query {
|
|
|
266
224
|
}
|
|
267
225
|
|
|
268
226
|
private updateAttachment(attachment: Attachment) {
|
|
269
|
-
if (attachment.testStepId) {
|
|
270
|
-
this.attachmentsByTestStepId.put(attachment.testStepId, attachment)
|
|
271
|
-
}
|
|
272
227
|
if (attachment.testCaseStartedId) {
|
|
273
228
|
this.attachmentsByTestCaseStartedId.put(attachment.testCaseStartedId, attachment)
|
|
274
229
|
}
|
|
@@ -282,12 +237,6 @@ export default class Query {
|
|
|
282
237
|
testStepFinished.testCaseStartedId,
|
|
283
238
|
testStepFinished
|
|
284
239
|
)
|
|
285
|
-
|
|
286
|
-
const pickleId = this.pickleIdByTestStepId.get(testStepFinished.testStepId)
|
|
287
|
-
this.testStepResultByPickleId.put(pickleId, testStepFinished.testStepResult)
|
|
288
|
-
const testStep = this.testStepById.get(testStepFinished.testStepId)
|
|
289
|
-
this.testStepResultsByPickleStepId.put(testStep.pickleStepId, testStepFinished.testStepResult)
|
|
290
|
-
this.testStepResultsbyTestStepId.put(testStep.id, testStepFinished.testStepResult)
|
|
291
240
|
}
|
|
292
241
|
|
|
293
242
|
private updateTestCaseFinished(testCaseFinished: TestCaseFinished) {
|
|
@@ -305,146 +254,6 @@ export default class Query {
|
|
|
305
254
|
this.undefinedParameterTypes.push(undefinedParameterType)
|
|
306
255
|
}
|
|
307
256
|
|
|
308
|
-
/**
|
|
309
|
-
* Gets all the results for multiple pickle steps
|
|
310
|
-
* @param pickleStepIds
|
|
311
|
-
*/
|
|
312
|
-
public getPickleStepTestStepResults(
|
|
313
|
-
pickleStepIds: readonly string[]
|
|
314
|
-
): readonly messages.TestStepResult[] {
|
|
315
|
-
if (pickleStepIds.length === 0) {
|
|
316
|
-
return [
|
|
317
|
-
{
|
|
318
|
-
status: messages.TestStepResultStatus.UNKNOWN,
|
|
319
|
-
duration: messages.TimeConversion.millisecondsToDuration(0),
|
|
320
|
-
},
|
|
321
|
-
]
|
|
322
|
-
}
|
|
323
|
-
return pickleStepIds.reduce((testStepResults: messages.TestStepResult[], pickleId) => {
|
|
324
|
-
return testStepResults.concat(this.testStepResultsByPickleStepId.get(pickleId))
|
|
325
|
-
}, [])
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Gets all the results for multiple pickles
|
|
330
|
-
* @param pickleIds
|
|
331
|
-
*/
|
|
332
|
-
public getPickleTestStepResults(
|
|
333
|
-
pickleIds: readonly string[]
|
|
334
|
-
): readonly messages.TestStepResult[] {
|
|
335
|
-
if (pickleIds.length === 0) {
|
|
336
|
-
return [
|
|
337
|
-
{
|
|
338
|
-
status: messages.TestStepResultStatus.UNKNOWN,
|
|
339
|
-
duration: messages.TimeConversion.millisecondsToDuration(0),
|
|
340
|
-
},
|
|
341
|
-
]
|
|
342
|
-
}
|
|
343
|
-
return pickleIds.reduce((testStepResults: messages.TestStepResult[], pickleId) => {
|
|
344
|
-
return testStepResults.concat(this.testStepResultByPickleId.get(pickleId))
|
|
345
|
-
}, [])
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Gets all the attachments for multiple pickle steps
|
|
350
|
-
* @param pickleStepIds
|
|
351
|
-
*/
|
|
352
|
-
public getPickleStepAttachments(
|
|
353
|
-
pickleStepIds: readonly string[]
|
|
354
|
-
): readonly messages.Attachment[] {
|
|
355
|
-
return this.getTestStepsAttachments(
|
|
356
|
-
pickleStepIds.reduce((testStepIds: string[], pickleStepId: string) => {
|
|
357
|
-
return testStepIds.concat(this.testStepIdsByPickleStepId.get(pickleStepId))
|
|
358
|
-
}, [])
|
|
359
|
-
)
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
public getTestStepsAttachments(testStepIds: readonly string[]): readonly messages.Attachment[] {
|
|
363
|
-
return testStepIds.reduce((attachments: messages.Attachment[], testStepId) => {
|
|
364
|
-
return attachments.concat(this.attachmentsByTestStepId.get(testStepId))
|
|
365
|
-
}, [])
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Get StepMatchArguments for a pickle step
|
|
370
|
-
* @param pickleStepId
|
|
371
|
-
*/
|
|
372
|
-
public getStepMatchArgumentsLists(
|
|
373
|
-
pickleStepId: string
|
|
374
|
-
): readonly messages.StepMatchArgumentsList[] | undefined {
|
|
375
|
-
return this.stepMatchArgumentsListsByPickleStepId.get(pickleStepId)
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
public getHook(hookId: string): messages.Hook {
|
|
379
|
-
return this.hooksById.get(hookId)
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
public getBeforeHookSteps(pickleId: string): readonly messages.TestStep[] {
|
|
383
|
-
const hookSteps: messages.TestStep[] = []
|
|
384
|
-
|
|
385
|
-
this.identifyHookSteps(
|
|
386
|
-
pickleId,
|
|
387
|
-
(hook) => hookSteps.push(hook),
|
|
388
|
-
() => null
|
|
389
|
-
)
|
|
390
|
-
return hookSteps
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
public getAfterHookSteps(pickleId: string): readonly messages.TestStep[] {
|
|
394
|
-
const hookSteps: messages.TestStep[] = []
|
|
395
|
-
|
|
396
|
-
this.identifyHookSteps(
|
|
397
|
-
pickleId,
|
|
398
|
-
() => null,
|
|
399
|
-
(hook) => hookSteps.push(hook)
|
|
400
|
-
)
|
|
401
|
-
return hookSteps
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
private identifyHookSteps(
|
|
405
|
-
pickleId: string,
|
|
406
|
-
onBeforeHookFound: (hook: messages.TestStep) => void,
|
|
407
|
-
onAfterHookFound: (hook: messages.TestStep) => void
|
|
408
|
-
): void {
|
|
409
|
-
const testCase = this.testCaseByPickleId.get(pickleId)
|
|
410
|
-
|
|
411
|
-
if (!testCase) {
|
|
412
|
-
return
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
let pickleStepFound = false
|
|
416
|
-
|
|
417
|
-
for (const step of testCase.testSteps) {
|
|
418
|
-
if (step.hookId) {
|
|
419
|
-
if (pickleStepFound) {
|
|
420
|
-
onAfterHookFound(step)
|
|
421
|
-
} else {
|
|
422
|
-
onBeforeHookFound(step)
|
|
423
|
-
}
|
|
424
|
-
} else {
|
|
425
|
-
pickleStepFound = true
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
public getTestStepResults(testStepId: string): messages.TestStepResult[] {
|
|
431
|
-
return this.testStepResultsbyTestStepId.get(testStepId)
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
public getStatusCounts(
|
|
435
|
-
pickleIds: readonly string[]
|
|
436
|
-
): Partial<Record<messages.TestStepResultStatus, number>> {
|
|
437
|
-
const result: Partial<Record<messages.TestStepResultStatus, number>> = {}
|
|
438
|
-
for (const pickleId of pickleIds) {
|
|
439
|
-
const testStepResult = getWorstTestStepResult(this.getPickleTestStepResults([pickleId]))
|
|
440
|
-
const count = result[testStepResult.status] || 0
|
|
441
|
-
result[testStepResult.status] = count + 1
|
|
442
|
-
}
|
|
443
|
-
return result
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/* new common interface with Java starts here */
|
|
447
|
-
|
|
448
257
|
public countMostSevereTestStepResultStatus(): Record<TestStepResultStatus, number> {
|
|
449
258
|
const result: Record<TestStepResultStatus, number> = {
|
|
450
259
|
[TestStepResultStatus.AMBIGUOUS]: 0,
|
|
@@ -514,6 +323,44 @@ export default class Query {
|
|
|
514
323
|
)
|
|
515
324
|
}
|
|
516
325
|
|
|
326
|
+
public findAllTestCaseStartedOrderBy<T>(
|
|
327
|
+
findOrderBy: (query: Query, testCaseStarted: TestCaseStarted) => T | undefined,
|
|
328
|
+
order: (a: T, b: T) => number
|
|
329
|
+
): ReadonlyArray<TestCaseStarted> {
|
|
330
|
+
const withOrderBy = this.findAllTestCaseStarted().map((testCaseStarted) => ({
|
|
331
|
+
testCaseStarted,
|
|
332
|
+
orderBy: findOrderBy(this, testCaseStarted),
|
|
333
|
+
}))
|
|
334
|
+
|
|
335
|
+
const sorted = withOrderBy.sort((a, b) => {
|
|
336
|
+
if (a.orderBy === undefined && b.orderBy === undefined) return 0
|
|
337
|
+
if (a.orderBy === undefined) return 1
|
|
338
|
+
if (b.orderBy === undefined) return -1
|
|
339
|
+
return order(a.orderBy, b.orderBy)
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
return sorted.map((item) => item.testCaseStarted)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
public findAllTestCaseFinishedOrderBy<T>(
|
|
346
|
+
findOrderBy: (query: Query, testCaseFinished: TestCaseFinished) => T | undefined,
|
|
347
|
+
order: (a: T, b: T) => number
|
|
348
|
+
): ReadonlyArray<TestCaseFinished> {
|
|
349
|
+
const withOrderBy = this.findAllTestCaseFinished().map((testCaseFinished) => ({
|
|
350
|
+
testCaseFinished,
|
|
351
|
+
orderBy: findOrderBy(this, testCaseFinished),
|
|
352
|
+
}))
|
|
353
|
+
|
|
354
|
+
const sorted = withOrderBy.sort((a, b) => {
|
|
355
|
+
if (a.orderBy === undefined && b.orderBy === undefined) return 0
|
|
356
|
+
if (a.orderBy === undefined) return 1
|
|
357
|
+
if (b.orderBy === undefined) return -1
|
|
358
|
+
return order(a.orderBy, b.orderBy)
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
return sorted.map((item) => item.testCaseFinished)
|
|
362
|
+
}
|
|
363
|
+
|
|
517
364
|
public findAllTestSteps(): ReadonlyArray<TestStep> {
|
|
518
365
|
return [...this.testStepById.values()]
|
|
519
366
|
}
|
|
@@ -559,7 +406,7 @@ export default class Query {
|
|
|
559
406
|
if (!item.hookId) {
|
|
560
407
|
return undefined
|
|
561
408
|
}
|
|
562
|
-
return this.
|
|
409
|
+
return this.hookById.get(item.hookId)
|
|
563
410
|
}
|
|
564
411
|
|
|
565
412
|
public findMeta(): Meta | undefined {
|
package/src/acceptance.spec.ts
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import * as path from 'node:path'
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { Writable } from 'node:stream'
|
|
5
|
+
import { pipeline } from 'node:stream/promises'
|
|
6
6
|
|
|
7
|
-
// eslint-disable-next-line n/no-extraneous-import
|
|
8
7
|
import { NdjsonToMessageStream } from '@cucumber/message-streams'
|
|
9
|
-
import { Envelope } from '@cucumber/messages'
|
|
8
|
+
import { Envelope, Pickle } from '@cucumber/messages'
|
|
10
9
|
|
|
11
10
|
import Query from './Query'
|
|
12
11
|
|
|
13
|
-
const
|
|
12
|
+
const reversePickleComparator = (a: Pickle, b: Pickle): number => {
|
|
13
|
+
if (a.uri !== b.uri) {
|
|
14
|
+
return b.uri.localeCompare(a.uri)
|
|
15
|
+
}
|
|
16
|
+
if (a.location.line !== b.location.line) {
|
|
17
|
+
return b.location.line - a.location.line
|
|
18
|
+
}
|
|
19
|
+
return b.location.column - a.location.column
|
|
20
|
+
}
|
|
14
21
|
|
|
15
22
|
describe('Acceptance Tests', async () => {
|
|
16
23
|
const sources = [
|
|
@@ -32,6 +39,21 @@ describe('Acceptance Tests', async () => {
|
|
|
32
39
|
findAllPickleSteps: (query: Query) => query.findAllPickleSteps().length,
|
|
33
40
|
findAllStepDefinitions: (query: Query) => query.findAllStepDefinitions().length,
|
|
34
41
|
findAllTestCaseStarted: (query: Query) => query.findAllTestCaseStarted().length,
|
|
42
|
+
findAllTestCaseStartedOrderBy: (query: Query) =>
|
|
43
|
+
query
|
|
44
|
+
.findAllTestCaseStartedOrderBy(
|
|
45
|
+
(q, testCaseStarted) => q.findPickleBy(testCaseStarted),
|
|
46
|
+
reversePickleComparator
|
|
47
|
+
)
|
|
48
|
+
.map((testCaseStarted) => testCaseStarted.id),
|
|
49
|
+
findAllTestCaseFinished: (query: Query) => query.findAllTestCaseFinished().length,
|
|
50
|
+
findAllTestCaseFinishedOrderBy: (query: Query) =>
|
|
51
|
+
query
|
|
52
|
+
.findAllTestCaseFinishedOrderBy(
|
|
53
|
+
(q, testCaseFinished) => q.findPickleBy(testCaseFinished),
|
|
54
|
+
reversePickleComparator
|
|
55
|
+
)
|
|
56
|
+
.map((testCaseFinished) => testCaseFinished.testCaseStartedId),
|
|
35
57
|
findAllTestRunHookStarted: (query: Query) => query.findAllTestRunHookStarted().length,
|
|
36
58
|
findAllTestRunHookFinished: (query: Query) => query.findAllTestRunHookFinished().length,
|
|
37
59
|
findTestRunHookStartedBy: (query: Query) =>
|
|
@@ -281,7 +303,7 @@ describe('Acceptance Tests', async () => {
|
|
|
281
303
|
it(suiteName + ' -> ' + methodName, async () => {
|
|
282
304
|
const query = new Query()
|
|
283
305
|
|
|
284
|
-
await
|
|
306
|
+
await pipeline(
|
|
285
307
|
fs.createReadStream(source, { encoding: 'utf-8' }),
|
|
286
308
|
new NdjsonToMessageStream(),
|
|
287
309
|
new Writable({
|