From abc19b35075d872e752bd416ab0282ab19b7a5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aslak=20Helles=C3=B8y?= Date: Tue, 28 Jun 2022 10:57:17 +0100 Subject: [PATCH 1/5] Start adding a new rerun order --- features/order.feature | 14 ++++++++++++++ src/api/gherkin.ts | 7 ++++++- src/cli/helpers.ts | 8 +++++++- src/cli/helpers_spec.ts | 1 + src/configuration/argv_parser.ts | 2 +- src/models/pickle_order.ts | 2 +- 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/features/order.feature b/features/order.feature index a2296332f..5de19f8fd 100644 --- a/features/order.feature +++ b/features/order.feature @@ -47,3 +47,17 @@ Feature: Set the execution order | second scenario - X | | second scenario - Y | | first scenario | + + Scenario: run in rerun order + Given a file named "@rerun.txt" with: + """ + features/a.feature:19 + features/a.feature:3 + features/a.feature:14 + """ + When I run cucumber-js with `--order rerun @rerun.txt` + Then it runs the scenarios: + | NAME | + | second scenario - Z | + | first scenario | + | second scenario - Y | diff --git a/src/api/gherkin.ts b/src/api/gherkin.ts index 8fd19c1f2..87a5e1cc8 100644 --- a/src/api/gherkin.ts +++ b/src/api/gherkin.ts @@ -85,7 +85,12 @@ export async function getFilteredPicklesAndErrors({ pickle, } }) - orderPickles(filteredPickles, coordinates.order, logger) + orderPickles( + filteredPickles, + coordinates.order, + unexpandedFeaturePaths, + logger + ) return { filteredPickles, parseErrors, diff --git a/src/cli/helpers.ts b/src/cli/helpers.ts index 866321202..6733b2b59 100644 --- a/src/cli/helpers.ts +++ b/src/cli/helpers.ts @@ -22,6 +22,7 @@ interface IParseGherkinMessageStreamRequest { eventDataCollector: EventDataCollector gherkinMessageStream: Readable order: string + unexpandedFeaturePaths: string[] pickleFilter: PickleFilter } @@ -34,6 +35,7 @@ interface IParseGherkinMessageStreamRequest { * @param eventDataCollector * @param gherkinMessageStream * @param order + * @param unexpandedFeaturePaths * @param pickleFilter */ export async function parseGherkinMessageStream({ @@ -41,6 +43,7 @@ export async function parseGherkinMessageStream({ eventDataCollector, gherkinMessageStream, order, + unexpandedFeaturePaths, pickleFilter, }: IParseGherkinMessageStreamRequest): Promise { return await new Promise((resolve, reject) => { @@ -59,7 +62,7 @@ export async function parseGherkinMessageStream({ } }) gherkinMessageStream.on('end', () => { - orderPickles(result, order, console) + orderPickles(result, order, unexpandedFeaturePaths, console) resolve(result) }) gherkinMessageStream.on('error', reject) @@ -70,6 +73,7 @@ export async function parseGherkinMessageStream({ export function orderPickles( pickleIds: T[], order: PickleOrder, + unexpandedFeaturePaths: string[], logger: Console ): void { const [type, seed] = OptionSplitter.split(order) @@ -85,6 +89,8 @@ export function orderPickles( shuffle(pickleIds, seed) } break + case 'rerun': + break default: throw new Error( 'Unrecgonized order type. Should be `defined` or `random`' diff --git a/src/cli/helpers_spec.ts b/src/cli/helpers_spec.ts index cff1a1ef2..006cce5a6 100644 --- a/src/cli/helpers_spec.ts +++ b/src/cli/helpers_spec.ts @@ -51,6 +51,7 @@ async function testParseGherkinMessageStream( eventDataCollector, gherkinMessageStream: options.gherkinMessageStream, order: options.order, + unexpandedFeaturePaths: [], pickleFilter: options.pickleFilter, }) return { envelopes, result } diff --git a/src/configuration/argv_parser.ts b/src/configuration/argv_parser.ts index 193df328f..396414a54 100644 --- a/src/configuration/argv_parser.ts +++ b/src/configuration/argv_parser.ts @@ -112,7 +112,7 @@ const ArgvParser = { .option( '--order ', - 'run scenarios in the specified order. Type should be `defined` or `random`' + "run scenarios in the specified order. Type should be 'defined', 'random' or 'rerun'" ) .option( '-p, --profile ', diff --git a/src/models/pickle_order.ts b/src/models/pickle_order.ts index d3fc77e0e..35e89b00a 100644 --- a/src/models/pickle_order.ts +++ b/src/models/pickle_order.ts @@ -1 +1 @@ -export type PickleOrder = 'defined' | 'random' | string +export type PickleOrder = 'defined' | 'random' | 'rerun' | string From 35db65eb8628afe27786c7e7666b5c255cc64307 Mon Sep 17 00:00:00 2001 From: Ivan Malaniak Date: Tue, 28 Jun 2022 12:34:50 +0200 Subject: [PATCH 2/5] implement the rerun ordering --- src/api/gherkin.ts | 17 ++--------------- src/api/types.ts | 7 +++++++ src/cli/helpers.ts | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/api/gherkin.ts b/src/api/gherkin.ts index 87a5e1cc8..367c4fb52 100644 --- a/src/api/gherkin.ts +++ b/src/api/gherkin.ts @@ -2,24 +2,11 @@ import { GherkinStreams, IGherkinStreamOptions, } from '@cucumber/gherkin-streams' -import { - Envelope, - GherkinDocument, - IdGenerator, - Location, - ParseError, - Pickle, -} from '@cucumber/messages' +import { Envelope, IdGenerator, ParseError } from '@cucumber/messages' import { Query as GherkinQuery } from '@cucumber/gherkin-utils' import PickleFilter from '../pickle_filter' import { orderPickles } from '../cli/helpers' -import { ISourcesCoordinates } from './types' - -interface PickleWithDocument { - gherkinDocument: GherkinDocument - location: Location - pickle: Pickle -} +import { ISourcesCoordinates, PickleWithDocument } from './types' export async function getFilteredPicklesAndErrors({ newId, diff --git a/src/api/types.ts b/src/api/types.ts index 046cb70b1..f1a619329 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -3,6 +3,7 @@ import { FormatOptions, IFormatterStream } from '../formatter' import { PickleOrder } from '../models/pickle_order' import { IRuntimeOptions } from '../runtime' import { IConfiguration } from '../configuration' +import { GherkinDocument, Location, Pickle } from '@cucumber/messages' /** * @public @@ -184,3 +185,9 @@ export interface IRunResult { */ support: ISupportCodeLibrary } + +export interface PickleWithDocument { + gherkinDocument: GherkinDocument + location: Location + pickle: Pickle +} diff --git a/src/cli/helpers.ts b/src/cli/helpers.ts index 6733b2b59..401822c55 100644 --- a/src/cli/helpers.ts +++ b/src/cli/helpers.ts @@ -15,6 +15,7 @@ import TestRunHookDefinition from '../models/test_run_hook_definition' import { PickleOrder } from '../models/pickle_order' import { builtinParameterTypes } from '../support_code_library_builder' import { version } from '../version' +import { PickleWithDocument } from '../api/types' interface IParseGherkinMessageStreamRequest { cwd?: string @@ -90,6 +91,24 @@ export function orderPickles( } break case 'rerun': + { + const picklesWithDocument = + pickleIds as unknown[] as PickleWithDocument[] + + picklesWithDocument.sort((a, b) => { + const pathA = `${a.pickle.uri}:${a.location.line}` + const pathB = `${b.pickle.uri}:${b.location.line}` + let indexA = unexpandedFeaturePaths.indexOf(pathA) + let indexB = unexpandedFeaturePaths.indexOf(pathB) + if (indexA === -1) { + indexA = Number.MAX_SAFE_INTEGER + } + if (indexB === -1) { + indexB = Number.MIN_SAFE_INTEGER + } + return indexA - indexB + }) + } break default: throw new Error( From ea766bc366e624b29aad1d95c9d9a78e9387c04d Mon Sep 17 00:00:00 2001 From: Ivan Malaniak Date: Tue, 28 Jun 2022 14:55:21 +0200 Subject: [PATCH 3/5] move PickleWithDocuments out of public types --- src/api/gherkin.ts | 4 ++-- src/api/types.ts | 7 ------- src/cli/helpers.ts | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/api/gherkin.ts b/src/api/gherkin.ts index 367c4fb52..9a30e4aa7 100644 --- a/src/api/gherkin.ts +++ b/src/api/gherkin.ts @@ -5,8 +5,8 @@ import { import { Envelope, IdGenerator, ParseError } from '@cucumber/messages' import { Query as GherkinQuery } from '@cucumber/gherkin-utils' import PickleFilter from '../pickle_filter' -import { orderPickles } from '../cli/helpers' -import { ISourcesCoordinates, PickleWithDocument } from './types' +import { orderPickles, PickleWithDocument } from '../cli/helpers' +import { ISourcesCoordinates } from './types' export async function getFilteredPicklesAndErrors({ newId, diff --git a/src/api/types.ts b/src/api/types.ts index f1a619329..046cb70b1 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -3,7 +3,6 @@ import { FormatOptions, IFormatterStream } from '../formatter' import { PickleOrder } from '../models/pickle_order' import { IRuntimeOptions } from '../runtime' import { IConfiguration } from '../configuration' -import { GherkinDocument, Location, Pickle } from '@cucumber/messages' /** * @public @@ -185,9 +184,3 @@ export interface IRunResult { */ support: ISupportCodeLibrary } - -export interface PickleWithDocument { - gherkinDocument: GherkinDocument - location: Location - pickle: Pickle -} diff --git a/src/cli/helpers.ts b/src/cli/helpers.ts index 401822c55..ae993ab5e 100644 --- a/src/cli/helpers.ts +++ b/src/cli/helpers.ts @@ -7,7 +7,12 @@ import { OptionSplitter } from '../configuration' import { Readable } from 'stream' import os from 'os' import * as messages from '@cucumber/messages' -import { IdGenerator } from '@cucumber/messages' +import { + GherkinDocument, + IdGenerator, + Location, + Pickle, +} from '@cucumber/messages' import detectCiEnvironment from '@cucumber/ci-environment' import { ISupportCodeLibrary } from '../support_code_library_builder/types' import TestCaseHookDefinition from '../models/test_case_hook_definition' @@ -15,7 +20,12 @@ import TestRunHookDefinition from '../models/test_run_hook_definition' import { PickleOrder } from '../models/pickle_order' import { builtinParameterTypes } from '../support_code_library_builder' import { version } from '../version' -import { PickleWithDocument } from '../api/types' + +export interface PickleWithDocument { + gherkinDocument: GherkinDocument + location: Location + pickle: Pickle +} interface IParseGherkinMessageStreamRequest { cwd?: string From 82dc72232394592c84146f8ae10bc1d4f4ae29bb Mon Sep 17 00:00:00 2001 From: Ivan Malaniak Date: Tue, 28 Jun 2022 14:55:30 +0200 Subject: [PATCH 4/5] mark unexpandedFeaturePaths as optional --- src/cli/helpers.ts | 10 ++++++---- src/cli/helpers_spec.ts | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/cli/helpers.ts b/src/cli/helpers.ts index ae993ab5e..a811650fd 100644 --- a/src/cli/helpers.ts +++ b/src/cli/helpers.ts @@ -33,7 +33,7 @@ interface IParseGherkinMessageStreamRequest { eventDataCollector: EventDataCollector gherkinMessageStream: Readable order: string - unexpandedFeaturePaths: string[] + unexpandedFeaturePaths?: string[] pickleFilter: PickleFilter } @@ -84,7 +84,7 @@ export async function parseGherkinMessageStream({ export function orderPickles( pickleIds: T[], order: PickleOrder, - unexpandedFeaturePaths: string[], + unexpandedFeaturePaths: string[] | undefined, logger: Console ): void { const [type, seed] = OptionSplitter.split(order) @@ -108,8 +108,10 @@ export function orderPickles( picklesWithDocument.sort((a, b) => { const pathA = `${a.pickle.uri}:${a.location.line}` const pathB = `${b.pickle.uri}:${b.location.line}` - let indexA = unexpandedFeaturePaths.indexOf(pathA) - let indexB = unexpandedFeaturePaths.indexOf(pathB) + let indexA = + unexpandedFeaturePaths?.indexOf(pathA) || Number.MAX_SAFE_INTEGER + let indexB = + unexpandedFeaturePaths?.indexOf(pathB) || Number.MIN_SAFE_INTEGER if (indexA === -1) { indexA = Number.MAX_SAFE_INTEGER } diff --git a/src/cli/helpers_spec.ts b/src/cli/helpers_spec.ts index 006cce5a6..cff1a1ef2 100644 --- a/src/cli/helpers_spec.ts +++ b/src/cli/helpers_spec.ts @@ -51,7 +51,6 @@ async function testParseGherkinMessageStream( eventDataCollector, gherkinMessageStream: options.gherkinMessageStream, order: options.order, - unexpandedFeaturePaths: [], pickleFilter: options.pickleFilter, }) return { envelopes, result } From 25513d19f8328bb2e9074da43adbb057f33acc8f Mon Sep 17 00:00:00 2001 From: Ivan Malaniak Date: Tue, 28 Jun 2022 15:48:59 +0200 Subject: [PATCH 5/5] implement check for correct rerun file --- features/order.feature | 59 +++++++++++++++++++++++++++++------------- src/cli/helpers.ts | 20 +++++++++----- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/features/order.feature b/features/order.feature index 5de19f8fd..03d1d0170 100644 --- a/features/order.feature +++ b/features/order.feature @@ -1,23 +1,23 @@ Feature: Set the execution order - Background: + Background: Given a file named "features/a.feature" with: """ Feature: some feature @a Scenario: first scenario Given a step - + @b Scenario Outline: second scenario - Given a step - + @c Examples: | ID | | X | | Y | - + @d Examples: | ID | @@ -26,7 +26,7 @@ Feature: Set the execution order And a file named "features/step_definitions/cucumber_steps.js" with: """ const {Given} = require('@cucumber/cucumber') - + Given(/^a step$/, function() {}) """ @@ -48,16 +48,39 @@ Feature: Set the execution order | second scenario - Y | | first scenario | - Scenario: run in rerun order - Given a file named "@rerun.txt" with: - """ - features/a.feature:19 - features/a.feature:3 - features/a.feature:14 - """ - When I run cucumber-js with `--order rerun @rerun.txt` - Then it runs the scenarios: - | NAME | - | second scenario - Z | - | first scenario | - | second scenario - Y | + Rule: Scenarios can be run in the order of a rerun file + + Scenario: run in rerun order + Given a file named "@rerun.txt" with: + """ + features/a.feature:19 + features/a.feature:3 + features/a.feature:14 + """ + When I run cucumber-js with `--order rerun @rerun.txt` + Then it runs the scenarios: + | NAME | + | second scenario - Z | + | first scenario | + | second scenario - Y | + + Scenario: run in rerun order with one incorrect line number + Given a file named "@rerun.txt" with: + """ + features/a.feature:19 + features/a.feature:2 + features/a.feature:14 + """ + When I run cucumber-js with `--order rerun @rerun.txt` + Then it runs the scenarios: + | NAME | + | second scenario - Z | + | second scenario - Y | + + Scenario: run in rerun order without a rerun file + When I run cucumber-js with `--order rerun` + Then it fails + And the error output contains the text: + """ + Cannot use rerun order because features/a.feature:13 was not in the rerun order. Did you forget to specify @rerun.txt? + """ diff --git a/src/cli/helpers.ts b/src/cli/helpers.ts index a811650fd..49a3302a7 100644 --- a/src/cli/helpers.ts +++ b/src/cli/helpers.ts @@ -102,21 +102,29 @@ export function orderPickles( break case 'rerun': { + if (unexpandedFeaturePaths === undefined) { + throw new Error( + 'Cannot order by rerun because no unexpandedFeaturePaths were provided' + ) + } + const picklesWithDocument = pickleIds as unknown[] as PickleWithDocument[] picklesWithDocument.sort((a, b) => { const pathA = `${a.pickle.uri}:${a.location.line}` const pathB = `${b.pickle.uri}:${b.location.line}` - let indexA = - unexpandedFeaturePaths?.indexOf(pathA) || Number.MAX_SAFE_INTEGER - let indexB = - unexpandedFeaturePaths?.indexOf(pathB) || Number.MIN_SAFE_INTEGER + const indexA = unexpandedFeaturePaths.indexOf(pathA) + const indexB = unexpandedFeaturePaths.indexOf(pathB) if (indexA === -1) { - indexA = Number.MAX_SAFE_INTEGER + throw new Error( + `Cannot use rerun order because ${pathA} was not in the rerun order. Did you forget to specify @rerun.txt?` + ) } if (indexB === -1) { - indexB = Number.MIN_SAFE_INTEGER + throw new Error( + `Cannot use rerun order because ${pathB} was not in the rerun order. Did you forget to specify @rerun.txt?` + ) } return indexA - indexB })