@cucumber/query 10.0.0 → 12.0.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 -1
- package/default.mk +12 -3
- package/dist/src/Query.d.ts +2 -0
- package/dist/src/Query.d.ts.map +1 -1
- package/dist/src/Query.js +31 -3
- package/dist/src/Query.js.map +1 -1
- package/dist/test/QueryTest.js +71 -6
- package/dist/test/QueryTest.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -5170
- package/package.json +11 -11
- package/src/Query.ts +30 -2
- package/test/QueryTest.ts +99 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cucumber/query",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.0.0",
|
|
4
4
|
"description": "Cucumber Query - query messages",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -22,18 +22,18 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://github.com/cucumber/cucumber#readme",
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@cucumber/fake-cucumber": "^
|
|
26
|
-
"@cucumber/gherkin": "^
|
|
27
|
-
"@cucumber/gherkin-streams": "^
|
|
28
|
-
"@cucumber/gherkin-utils": "^
|
|
29
|
-
"@types/mocha": "
|
|
30
|
-
"@types/node": "
|
|
31
|
-
"mocha": "
|
|
32
|
-
"ts-node": "
|
|
33
|
-
"typescript": "4.2
|
|
25
|
+
"@cucumber/fake-cucumber": "^16.0.0",
|
|
26
|
+
"@cucumber/gherkin": "^24.0.0",
|
|
27
|
+
"@cucumber/gherkin-streams": "^5.0.1",
|
|
28
|
+
"@cucumber/gherkin-utils": "^8.0.0",
|
|
29
|
+
"@types/mocha": "9.1.1",
|
|
30
|
+
"@types/node": "16.11.38",
|
|
31
|
+
"mocha": "10.0.0",
|
|
32
|
+
"ts-node": "10.8.0",
|
|
33
|
+
"typescript": "4.7.2"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@cucumber/messages": "^
|
|
36
|
+
"@cucumber/messages": "^19.0.0",
|
|
37
37
|
"@teppeis/multimaps": "2.0.0"
|
|
38
38
|
},
|
|
39
39
|
"directories": {
|
package/src/Query.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as messages from '@cucumber/messages'
|
|
2
|
+
import { getWorstTestStepResult } from '@cucumber/messages'
|
|
2
3
|
import { ArrayMultimap } from '@teppeis/multimaps'
|
|
3
4
|
|
|
4
5
|
export default class Query {
|
|
@@ -9,6 +10,7 @@ export default class Query {
|
|
|
9
10
|
>()
|
|
10
11
|
private readonly testStepById = new Map<string, messages.TestStep>()
|
|
11
12
|
private readonly testCaseByPickleId = new Map<string, messages.TestCase>()
|
|
13
|
+
private readonly testCaseByTestCaseId = new Map<string, messages.TestCase>()
|
|
12
14
|
private readonly pickleIdByTestStepId = new Map<string, string>()
|
|
13
15
|
private readonly pickleStepIdByTestStepId = new Map<string, string>()
|
|
14
16
|
private readonly testStepResultsbyTestStepId = new ArrayMultimap<
|
|
@@ -27,6 +29,7 @@ export default class Query {
|
|
|
27
29
|
|
|
28
30
|
public update(envelope: messages.Envelope) {
|
|
29
31
|
if (envelope.testCase) {
|
|
32
|
+
this.testCaseByTestCaseId.set(envelope.testCase.id, envelope.testCase)
|
|
30
33
|
this.testCaseByPickleId.set(envelope.testCase.pickleId, envelope.testCase)
|
|
31
34
|
for (const testStep of envelope.testCase.testSteps) {
|
|
32
35
|
this.testStepById.set(testStep.id, testStep)
|
|
@@ -40,6 +43,21 @@ export default class Query {
|
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
|
|
46
|
+
/*
|
|
47
|
+
when a test case attempt starts besides the first one, clear all existing results
|
|
48
|
+
and attachments for that test case, so we always report on the latest attempt
|
|
49
|
+
TODO keep track of results and attachments from all attempts, expand API accordingly
|
|
50
|
+
*/
|
|
51
|
+
if (envelope.testCaseStarted && envelope.testCaseStarted.attempt > 0) {
|
|
52
|
+
const testCase = this.testCaseByTestCaseId.get(envelope.testCaseStarted.testCaseId)
|
|
53
|
+
this.testStepResultByPickleId.delete(testCase.pickleId)
|
|
54
|
+
for (const testStep of testCase.testSteps) {
|
|
55
|
+
this.testStepResultsByPickleStepId.delete(testStep.pickleStepId)
|
|
56
|
+
this.testStepResultsbyTestStepId.delete(testStep.id)
|
|
57
|
+
this.attachmentsByTestStepId.delete(testStep.id)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
43
61
|
if (envelope.testStepFinished) {
|
|
44
62
|
const pickleId = this.pickleIdByTestStepId.get(envelope.testStepFinished.testStepId)
|
|
45
63
|
this.testStepResultByPickleId.put(pickleId, envelope.testStepFinished.testStepResult)
|
|
@@ -73,7 +91,6 @@ export default class Query {
|
|
|
73
91
|
{
|
|
74
92
|
status: messages.TestStepResultStatus.UNKNOWN,
|
|
75
93
|
duration: messages.TimeConversion.millisecondsToDuration(0),
|
|
76
|
-
willBeRetried: false,
|
|
77
94
|
},
|
|
78
95
|
]
|
|
79
96
|
}
|
|
@@ -94,7 +111,6 @@ export default class Query {
|
|
|
94
111
|
{
|
|
95
112
|
status: messages.TestStepResultStatus.UNKNOWN,
|
|
96
113
|
duration: messages.TimeConversion.millisecondsToDuration(0),
|
|
97
|
-
willBeRetried: false,
|
|
98
114
|
},
|
|
99
115
|
]
|
|
100
116
|
}
|
|
@@ -184,4 +200,16 @@ export default class Query {
|
|
|
184
200
|
public getTestStepResults(testStepId: string): messages.TestStepResult[] {
|
|
185
201
|
return this.testStepResultsbyTestStepId.get(testStepId)
|
|
186
202
|
}
|
|
203
|
+
|
|
204
|
+
public getStatusCounts(
|
|
205
|
+
pickleIds: readonly string[]
|
|
206
|
+
): Partial<Record<messages.TestStepResultStatus, number>> {
|
|
207
|
+
const result: Partial<Record<messages.TestStepResultStatus, number>> = {}
|
|
208
|
+
for (const pickleId of pickleIds) {
|
|
209
|
+
const testStepResult = getWorstTestStepResult(this.getPickleTestStepResults([pickleId]))
|
|
210
|
+
const count = result[testStepResult.status] || 0
|
|
211
|
+
result[testStepResult.status] = count + 1
|
|
212
|
+
}
|
|
213
|
+
return result
|
|
214
|
+
}
|
|
187
215
|
}
|
package/test/QueryTest.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
makeTestCase,
|
|
11
11
|
IncrementClock,
|
|
12
12
|
IncrementStopwatch,
|
|
13
|
+
RunOptions,
|
|
13
14
|
} from '@cucumber/fake-cucumber'
|
|
14
15
|
|
|
15
16
|
import { promisify } from 'util'
|
|
@@ -381,6 +382,24 @@ describe('Query', () => {
|
|
|
381
382
|
assert.deepStrictEqual(results.length, 1)
|
|
382
383
|
assert.deepStrictEqual(results[0].status, 'PASSED')
|
|
383
384
|
})
|
|
385
|
+
|
|
386
|
+
it('returns the result from the last attempt only where retry has been used', async () => {
|
|
387
|
+
const emittedMessages: Array<messages.Envelope> = []
|
|
388
|
+
await execute(
|
|
389
|
+
`Feature: hello
|
|
390
|
+
Scenario: hi
|
|
391
|
+
Given a step that passes the second time
|
|
392
|
+
`,
|
|
393
|
+
(message) => emittedMessages.push(message),
|
|
394
|
+
{ allowedRetries: 1 }
|
|
395
|
+
)
|
|
396
|
+
const testCase = emittedMessages.find((child) => child.testCase).testCase
|
|
397
|
+
const testStep = testCase.testSteps[0]
|
|
398
|
+
const results = cucumberQuery.getTestStepResults(testStep.id)
|
|
399
|
+
|
|
400
|
+
assert.deepStrictEqual(results.length, 1)
|
|
401
|
+
assert.deepStrictEqual(results[0].status, 'PASSED')
|
|
402
|
+
})
|
|
384
403
|
})
|
|
385
404
|
|
|
386
405
|
describe('#getHook(HookId)', () => {
|
|
@@ -423,14 +442,84 @@ describe('Query', () => {
|
|
|
423
442
|
|
|
424
443
|
assert.strictEqual(attachments[0].body, 'Hello')
|
|
425
444
|
})
|
|
445
|
+
|
|
446
|
+
it('returns attachments from the last attempt only where retry has been used', async () => {
|
|
447
|
+
const testCases: messages.TestCase[] = []
|
|
448
|
+
await execute(
|
|
449
|
+
`Feature: hello
|
|
450
|
+
Scenario: ok
|
|
451
|
+
Given a passed step with attachment
|
|
452
|
+
And a step that passes the second time
|
|
453
|
+
`,
|
|
454
|
+
(envelope) => {
|
|
455
|
+
if (envelope.testCase) {
|
|
456
|
+
testCases.push(envelope.testCase)
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
{ allowedRetries: 1 }
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
const attachments = cucumberQuery.getTestStepsAttachments([testCases[0].testSteps[0].id])
|
|
463
|
+
assert.strictEqual(attachments.length, 1)
|
|
464
|
+
|
|
465
|
+
assert.strictEqual(attachments[0].body, 'Hello')
|
|
466
|
+
})
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
describe('#getStatusCounts', () => {
|
|
470
|
+
it('returns the number of pickles for each status', async () => {
|
|
471
|
+
await execute(
|
|
472
|
+
`Feature: hello
|
|
473
|
+
Scenario: ok
|
|
474
|
+
Given a passed step
|
|
475
|
+
`,
|
|
476
|
+
() => undefined
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
await execute(
|
|
480
|
+
`Feature: hello
|
|
481
|
+
Scenario: ok
|
|
482
|
+
Given a passed step
|
|
483
|
+
`,
|
|
484
|
+
() => undefined
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
await execute(
|
|
488
|
+
`Feature: hello
|
|
489
|
+
Scenario: ok
|
|
490
|
+
Given a failed step
|
|
491
|
+
`,
|
|
492
|
+
() => undefined
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
await execute(
|
|
496
|
+
`Feature: hello
|
|
497
|
+
Scenario: ok
|
|
498
|
+
Given an undefined step
|
|
499
|
+
`,
|
|
500
|
+
() => undefined
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
const statuses = cucumberQuery.getStatusCounts(
|
|
504
|
+
gherkinQuery.getPickles().map((pickle) => pickle.id)
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
const expectedStatuses: Partial<Record<messages.TestStepResultStatus, number>> = {
|
|
508
|
+
PASSED: 2,
|
|
509
|
+
FAILED: 1,
|
|
510
|
+
UNDEFINED: 1,
|
|
511
|
+
}
|
|
512
|
+
assert.deepStrictEqual(statuses, expectedStatuses)
|
|
513
|
+
})
|
|
426
514
|
})
|
|
427
515
|
})
|
|
428
516
|
|
|
429
517
|
async function execute(
|
|
430
518
|
gherkinSource: string,
|
|
431
|
-
messagesHandler: (envelope: messages.Envelope) => void = () => null
|
|
519
|
+
messagesHandler: (envelope: messages.Envelope) => void = () => null,
|
|
520
|
+
runOptions: RunOptions = { allowedRetries: 0 }
|
|
432
521
|
): Promise<void> {
|
|
433
|
-
const newId = messages.IdGenerator.
|
|
522
|
+
const newId = messages.IdGenerator.uuid()
|
|
434
523
|
const clock = new IncrementClock()
|
|
435
524
|
const stopwatch = new IncrementStopwatch()
|
|
436
525
|
const makeErrorMessage = withFullStackTrace()
|
|
@@ -453,6 +542,13 @@ describe('Query', () => {
|
|
|
453
542
|
supportCode.defineStepDefinition(null, 'I have {int} cukes in my {word}', (cukes: number) => {
|
|
454
543
|
assert.ok(cukes)
|
|
455
544
|
})
|
|
545
|
+
let passesSecondTime = 0
|
|
546
|
+
supportCode.defineStepDefinition(null, 'a step that passes the second time', () => {
|
|
547
|
+
passesSecondTime++
|
|
548
|
+
if (passesSecondTime < 2) {
|
|
549
|
+
throw new Error(`This step failed.`)
|
|
550
|
+
}
|
|
551
|
+
})
|
|
456
552
|
|
|
457
553
|
const queryUpdateStream = new Writable({
|
|
458
554
|
objectMode: true,
|
|
@@ -473,7 +569,7 @@ describe('Query', () => {
|
|
|
473
569
|
})
|
|
474
570
|
await pipelinePromise(gherkinMessages(gherkinSource, 'test.feature', newId), queryUpdateStream)
|
|
475
571
|
|
|
476
|
-
const testPlan = makeTestPlan(gherkinQuery, supportCode, makeTestCase)
|
|
572
|
+
const testPlan = makeTestPlan(gherkinQuery, supportCode, runOptions, makeTestCase)
|
|
477
573
|
await testPlan.execute((envelope: messages.Envelope) => {
|
|
478
574
|
messagesHandler(envelope)
|
|
479
575
|
cucumberQuery.update(envelope)
|