Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start adding a new rerun order #2067

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions features/order.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
24 changes: 8 additions & 16 deletions src/api/gherkin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -85,7 +72,12 @@ export async function getFilteredPicklesAndErrors({
pickle,
}
})
orderPickles(filteredPickles, coordinates.order, logger)
orderPickles(
filteredPickles,
coordinates.order,
unexpandedFeaturePaths,
logger
)
return {
filteredPickles,
parseErrors,
Expand Down
7 changes: 7 additions & 0 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -184,3 +185,9 @@ export interface IRunResult {
*/
support: ISupportCodeLibrary
}

export interface PickleWithDocument {
davidjgoss marked this conversation as resolved.
Show resolved Hide resolved
gherkinDocument: GherkinDocument
location: Location
pickle: Pickle
}
27 changes: 26 additions & 1 deletion src/cli/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ 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
eventBroadcaster: EventEmitter
eventDataCollector: EventDataCollector
gherkinMessageStream: Readable
order: string
unexpandedFeaturePaths: string[]
pickleFilter: PickleFilter
}

Expand All @@ -34,13 +36,15 @@ interface IParseGherkinMessageStreamRequest {
* @param eventDataCollector
* @param gherkinMessageStream
* @param order
* @param unexpandedFeaturePaths
* @param pickleFilter
*/
export async function parseGherkinMessageStream({
Copy link
Contributor

@davidjgoss davidjgoss Jun 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is deprecated and will be removed in a future major release, however in the meantime it'd be better to avoid making a breaking change to it. Could we make the new field optional?

(It's fine to change orderPickles, that's an internal one.)

eventBroadcaster,
eventDataCollector,
gherkinMessageStream,
order,
unexpandedFeaturePaths,
pickleFilter,
}: IParseGherkinMessageStreamRequest): Promise<string[]> {
return await new Promise<string[]>((resolve, reject) => {
Expand All @@ -59,7 +63,7 @@ export async function parseGherkinMessageStream({
}
})
gherkinMessageStream.on('end', () => {
orderPickles(result, order, console)
orderPickles(result, order, unexpandedFeaturePaths, console)
resolve(result)
})
gherkinMessageStream.on('error', reject)
Expand All @@ -70,6 +74,7 @@ export async function parseGherkinMessageStream({
export function orderPickles<T = string>(
pickleIds: T[],
order: PickleOrder,
unexpandedFeaturePaths: string[],
logger: Console
): void {
const [type, seed] = OptionSplitter.split(order)
Expand All @@ -85,6 +90,26 @@ export function orderPickles<T = string>(
shuffle(pickleIds, seed)
}
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
Copy link
Member

@charlierudolph charlierudolph Aug 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note I think this could be something like

const ordered = new Array(unexpandedFeaturePaths.length);
picklesWithDocument.forEach(item => {
  // get index in unexpandedFeaturePaths, throw if not found
  ordered[index] = item
})

// remove empty indexes (only occurs if have duplicates in list and we just use the first) 

That should be O(n) instead O(nlogn)

})
}
break
default:
throw new Error(
'Unrecgonized order type. Should be `defined` or `random`'
Expand Down
1 change: 1 addition & 0 deletions src/cli/helpers_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ async function testParseGherkinMessageStream(
eventDataCollector,
gherkinMessageStream: options.gherkinMessageStream,
order: options.order,
unexpandedFeaturePaths: [],
pickleFilter: options.pickleFilter,
})
return { envelopes, result }
Expand Down
2 changes: 1 addition & 1 deletion src/configuration/argv_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const ArgvParser = {

.option(
'--order <TYPE[:SEED]>',
'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 <NAME>',
Expand Down
2 changes: 1 addition & 1 deletion src/models/pickle_order.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export type PickleOrder = 'defined' | 'random' | string
export type PickleOrder = 'defined' | 'random' | 'rerun' | string