-
Notifications
You must be signed in to change notification settings - Fork 20
/
step-runner.ts
109 lines (95 loc) · 3.3 KB
/
step-runner.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import {
ButStep,
butStepMappings,
GivenStep,
givenStepMappings,
StepMappings,
ThenStep,
thenStepMappings,
WhenStep,
whenStepMappings,
} from './step-mappings';
import { symbols } from './tools/string/symbols';
import { t } from 'testcafe';
import * as chalk from 'chalk';
enum StepLabel {
Given = 'Given',
When = 'When ',
Then = 'Then ',
And = 'And ',
But = 'But ',
}
function executionOfCurrentTestWasCanceledByPreviousStep(): boolean {
const canExecute: boolean | undefined = t.ctx.canExecute;
return canExecute === false ? true : false;
}
function showSuccess(stepName: string, stepLabel: StepLabel): void {
if (!t.ctx.stepRunnerContext) {
t.ctx.stepRunnerContext = {};
// eslint-disable-next-line no-console
console.log('');
}
// eslint-disable-next-line no-console
console.log(` ${chalk.green(symbols.ok)} ${stepLabel} ${stepName}`);
}
async function executeStep(
stepName: GivenStep | WhenStep | ThenStep | ButStep,
stepMappings: StepMappings,
stepLabel: StepLabel
): Promise<void> {
if (executionOfCurrentTestWasCanceledByPreviousStep()) {
return;
}
const foundStep = stepMappings[stepName];
if (typeof foundStep === 'function') {
await foundStep(stepName as string);
showSuccess(stepName, stepLabel);
return;
}
throw new Error(`Step "${stepName}" is not mapped to an executable code.`);
}
export async function given(stepName: GivenStep): Promise<void> {
await executeStep(stepName, givenStepMappings, StepLabel.Given);
}
export async function when(stepName: WhenStep): Promise<void> {
await executeStep(stepName, whenStepMappings, StepLabel.When);
}
export async function then(stepName: ThenStep): Promise<void> {
await executeStep(stepName, thenStepMappings, StepLabel.Then);
}
export async function but(stepName: ButStep): Promise<void> {
await executeStep(stepName, butStepMappings, StepLabel.But);
}
export async function and(stepName: GivenStep | WhenStep | ThenStep | ButStep): Promise<void> {
ensureThat(stepName).isNotAmbiguous();
if (givenStepMappings[stepName as GivenStep]) {
return executeStep(stepName, givenStepMappings, StepLabel.And);
}
if (whenStepMappings[stepName as WhenStep]) {
return executeStep(stepName, whenStepMappings, StepLabel.And);
}
if (thenStepMappings[stepName as ThenStep]) {
return executeStep(stepName, thenStepMappings, StepLabel.And);
}
if (butStepMappings[stepName as ButStep]) {
return executeStep(stepName, butStepMappings, StepLabel.And);
}
throw new Error(`Step "${stepName}" is not mapped to an executable code.`);
}
function ensureThat(
stepName: GivenStep | WhenStep | ThenStep | ButStep
): { isNotAmbiguous: () => void } {
return {
isNotAmbiguous: (): void => {
if (givenStepMappings[stepName as GivenStep] && thenStepMappings[stepName as ThenStep]) {
throw new Error(`Step "${stepName}" is defined as both a 'Given' and a 'Then' step.`);
}
if (whenStepMappings[stepName as WhenStep] && thenStepMappings[stepName as ThenStep]) {
throw new Error(`Step "${stepName}" is defined as both a 'When' and a 'Then' step.`);
}
if (butStepMappings[stepName as ButStep] && thenStepMappings[stepName as ThenStep]) {
throw new Error(`Step "${stepName}" is defined as both a 'But' and a 'Then' step.`);
}
},
};
}