@zohodesk/testinglibrary 2.9.1 → 3.0.2
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/.gitlab-ci.yml +16 -23
- package/README.md +32 -1
- package/build/core/playwright/constants/fileMutexConfig.js +11 -0
- package/build/core/playwright/fixtures.js +24 -0
- package/build/core/playwright/helpers/auth/checkAuthCookies.js +2 -8
- package/build/core/playwright/helpers/auth/loginSteps.js +25 -18
- package/build/core/playwright/helpers/checkAuthDirectory.js +17 -0
- package/build/core/playwright/helpers/fileMutex.js +58 -0
- package/build/core/playwright/index.js +10 -23
- package/build/core/playwright/setup/config-creator.js +3 -3
- package/build/core/playwright/setup/config-utils.js +8 -25
- package/build/core/playwright/test-runner.js +1 -1
- package/build/decorators.d.ts +1 -1
- package/build/decorators.js +1 -1
- package/build/setup-folder-structure/samples/actors-index.js +2 -0
- package/build/setup-folder-structure/samples/auth-setup-sample.js +14 -66
- package/build/setup-folder-structure/samples/editions-index.js +3 -0
- package/build/setup-folder-structure/samples/free-sample.json +25 -0
- package/build/setup-folder-structure/samples/settings.json +7 -0
- package/build/setup-folder-structure/setupProject.js +18 -5
- package/build/test/core/playwright/helpers/__tests__/fileMutex.test.js +94 -0
- package/nobdd/uat/conf/default/actors/index.js +1 -4
- package/nobdd/uat/conf/default/settings.json +1 -1
- package/nobdd/uat/conf/nobdd/uat.config.js +11 -4
- package/nobdd/uat/env-config.json +3 -3
- package/nobdd/uat/fixtures/setup.teardown.js +2 -1
- package/nobdd/uat/modules/nobdd/steps/VerifyNoBDD.feature.spec.js +3 -3
- package/nobdd/uat.config.js +8 -3
- package/package.json +8 -7
- package/build/bdd-framework/cli/commands/env.js +0 -42
- package/build/bdd-framework/cli/commands/export.js +0 -62
- package/build/bdd-framework/cli/commands/test.js +0 -64
- package/build/bdd-framework/cli/index.js +0 -11
- package/build/bdd-framework/cli/options.js +0 -19
- package/build/bdd-framework/cli/worker.js +0 -13
- package/build/bdd-framework/config/configDir.js +0 -35
- package/build/bdd-framework/config/enrichReporterData.js +0 -23
- package/build/bdd-framework/config/env.js +0 -50
- package/build/bdd-framework/config/index.js +0 -94
- package/build/bdd-framework/config/lang.js +0 -14
- package/build/bdd-framework/cucumber/buildStepDefinition.js +0 -43
- package/build/bdd-framework/cucumber/createTestStep.js +0 -43
- package/build/bdd-framework/cucumber/formatter/EventDataCollector.js +0 -126
- package/build/bdd-framework/cucumber/formatter/GherkinDocumentParser.js +0 -72
- package/build/bdd-framework/cucumber/formatter/PickleParser.js +0 -25
- package/build/bdd-framework/cucumber/formatter/durationHelpers.js +0 -13
- package/build/bdd-framework/cucumber/formatter/getColorFns.js +0 -57
- package/build/bdd-framework/cucumber/formatter/index.js +0 -16
- package/build/bdd-framework/cucumber/formatter/locationHelpers.js +0 -16
- package/build/bdd-framework/cucumber/loadConfig.js +0 -17
- package/build/bdd-framework/cucumber/loadFeatures.js +0 -70
- package/build/bdd-framework/cucumber/loadSnippetBuilder.js +0 -20
- package/build/bdd-framework/cucumber/loadSteps.js +0 -47
- package/build/bdd-framework/cucumber/resolveFeaturePaths.js +0 -62
- package/build/bdd-framework/cucumber/stepArguments.js +0 -21
- package/build/bdd-framework/cucumber/types.js +0 -5
- package/build/bdd-framework/cucumber/valueChecker.js +0 -23
- package/build/bdd-framework/decorators.js +0 -18
- package/build/bdd-framework/gen/fixtures.js +0 -48
- package/build/bdd-framework/gen/formatter.js +0 -167
- package/build/bdd-framework/gen/i18n.js +0 -39
- package/build/bdd-framework/gen/index.js +0 -197
- package/build/bdd-framework/gen/specialTags.js +0 -70
- package/build/bdd-framework/gen/testFile.js +0 -470
- package/build/bdd-framework/gen/testMeta.js +0 -60
- package/build/bdd-framework/gen/testNode.js +0 -35
- package/build/bdd-framework/gen/testPoms.js +0 -133
- package/build/bdd-framework/hooks/scenario.js +0 -130
- package/build/bdd-framework/hooks/worker.js +0 -89
- package/build/bdd-framework/index.js +0 -52
- package/build/bdd-framework/playwright/fixtureParameterNames.js +0 -93
- package/build/bdd-framework/playwright/getLocationInFile.js +0 -79
- package/build/bdd-framework/playwright/loadConfig.js +0 -42
- package/build/bdd-framework/playwright/loadUtils.js +0 -33
- package/build/bdd-framework/playwright/testTypeImpl.js +0 -79
- package/build/bdd-framework/playwright/transform.js +0 -88
- package/build/bdd-framework/playwright/types.js +0 -12
- package/build/bdd-framework/playwright/utils.js +0 -56
- package/build/bdd-framework/reporter/cucumber/base.js +0 -52
- package/build/bdd-framework/reporter/cucumber/custom.js +0 -73
- package/build/bdd-framework/reporter/cucumber/helper.js +0 -12
- package/build/bdd-framework/reporter/cucumber/html.js +0 -40
- package/build/bdd-framework/reporter/cucumber/index.js +0 -74
- package/build/bdd-framework/reporter/cucumber/json.js +0 -312
- package/build/bdd-framework/reporter/cucumber/junit.js +0 -205
- package/build/bdd-framework/reporter/cucumber/message.js +0 -20
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/AttachmentMapper.js +0 -82
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Builder.js +0 -197
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocument.js +0 -43
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocumentClone.js +0 -52
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocuments.js +0 -105
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Hook.js +0 -70
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Meta.js +0 -45
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Pickles.js +0 -27
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Projects.js +0 -38
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCase.js +0 -128
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCaseRun.js +0 -154
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCaseRunHooks.js +0 -123
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestStepAttachments.js +0 -67
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestStepRun.js +0 -114
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/index.js +0 -30
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/pwStepUtils.js +0 -70
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/timing.js +0 -35
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/types.js +0 -5
- package/build/bdd-framework/run/StepInvoker.js +0 -69
- package/build/bdd-framework/run/bddData/index.js +0 -59
- package/build/bdd-framework/run/bddData/types.js +0 -5
- package/build/bdd-framework/run/bddFixtures.js +0 -192
- package/build/bdd-framework/run/bddWorld.js +0 -79
- package/build/bdd-framework/run/bddWorldInternal.js +0 -11
- package/build/bdd-framework/snippets/index.js +0 -132
- package/build/bdd-framework/snippets/snippetSyntax.js +0 -43
- package/build/bdd-framework/snippets/snippetSyntaxDecorators.js +0 -26
- package/build/bdd-framework/snippets/snippetSyntaxTs.js +0 -18
- package/build/bdd-framework/stepDefinitions/createBdd.js +0 -66
- package/build/bdd-framework/stepDefinitions/decorators/class.js +0 -68
- package/build/bdd-framework/stepDefinitions/decorators/steps.js +0 -99
- package/build/bdd-framework/stepDefinitions/defineStep.js +0 -62
- package/build/bdd-framework/stepDefinitions/stepConfig.js +0 -24
- package/build/bdd-framework/steps/createBdd.js +0 -78
- package/build/bdd-framework/steps/decorators/class.js +0 -68
- package/build/bdd-framework/steps/decorators/steps.js +0 -98
- package/build/bdd-framework/steps/defineStep.js +0 -62
- package/build/bdd-framework/steps/stepConfig.js +0 -24
- package/build/bdd-framework/utils/AutofillMap.js +0 -20
- package/build/bdd-framework/utils/exit.js +0 -62
- package/build/bdd-framework/utils/index.js +0 -93
- package/build/bdd-framework/utils/jsStringWrap.js +0 -44
- package/build/bdd-framework/utils/logger.js +0 -30
- package/build/bdd-framework/utils/stripAnsiEscapes.js +0 -20
- package/build/setup-folder-structure/samples/authUsers-sample.json +0 -9
- package/build/setup-folder-structure/samples/env-config-sample.json +0 -21
- package/nobdd/uat/conf/default/actors/beta/custom-module.json +0 -24
- package/nobdd/uat/conf/default/actors/beta/index.js +0 -6
- package/nobdd/uat/conf/default/actors/beta/parent-child.json +0 -24
- package/npm-shrinkwrap.json +0 -6475
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.TestCase = void 0;
|
|
7
|
-
var _utils = require("../../../utils");
|
|
8
|
-
class TestCase {
|
|
9
|
-
id;
|
|
10
|
-
gherkinDocuments;
|
|
11
|
-
#pickle;
|
|
12
|
-
#projectInfo;
|
|
13
|
-
beforeHooks = new Map();
|
|
14
|
-
afterHooks = new Map();
|
|
15
|
-
mainSteps = [];
|
|
16
|
-
constructor(id, gherkinDocuments) {
|
|
17
|
-
this.id = id;
|
|
18
|
-
this.gherkinDocuments = gherkinDocuments;
|
|
19
|
-
}
|
|
20
|
-
get projectInfo() {
|
|
21
|
-
if (!this.#projectInfo) {
|
|
22
|
-
throw new Error(`Empty projectInfo for testCase: ${this.id}`);
|
|
23
|
-
}
|
|
24
|
-
return this.#projectInfo;
|
|
25
|
-
}
|
|
26
|
-
get pickle() {
|
|
27
|
-
if (!this.#pickle) {
|
|
28
|
-
throw new Error(`Empty pickle for testCase: ${this.id}`);
|
|
29
|
-
}
|
|
30
|
-
return this.#pickle;
|
|
31
|
-
}
|
|
32
|
-
addRun(testCaseRun) {
|
|
33
|
-
if (!this.#projectInfo) {
|
|
34
|
-
this.#projectInfo = testCaseRun.projectInfo;
|
|
35
|
-
}
|
|
36
|
-
this.addHooks(testCaseRun, 'before');
|
|
37
|
-
this.addHooks(testCaseRun, 'after');
|
|
38
|
-
if (!this.#pickle) {
|
|
39
|
-
this.#pickle = this.findPickle(testCaseRun.bddData);
|
|
40
|
-
this.addStepsFromPickle(this.#pickle);
|
|
41
|
-
}
|
|
42
|
-
this.addStepsArgumentsLists(testCaseRun);
|
|
43
|
-
}
|
|
44
|
-
getHooks(hookType) {
|
|
45
|
-
return hookType == 'before' ? this.beforeHooks : this.afterHooks;
|
|
46
|
-
}
|
|
47
|
-
getMainSteps() {
|
|
48
|
-
return this.mainSteps;
|
|
49
|
-
}
|
|
50
|
-
buildMessage() {
|
|
51
|
-
const testSteps = [...Array.from(this.beforeHooks.values()).map(hook => hook.testStep), ...(this.mainSteps || []), ...Array.from(this.afterHooks.values()).map(hook => hook.testStep)];
|
|
52
|
-
const testCase = {
|
|
53
|
-
id: this.id,
|
|
54
|
-
pickleId: this.pickle.id,
|
|
55
|
-
testSteps
|
|
56
|
-
};
|
|
57
|
-
return {
|
|
58
|
-
testCase
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* We collect hooks from all runs of this test case, avoiding duplicates.
|
|
63
|
-
*/
|
|
64
|
-
addHooks(testCaseRun, hookType) {
|
|
65
|
-
const testCaseHooks = hookType === 'before' ? this.beforeHooks : this.afterHooks;
|
|
66
|
-
const testRunHooks = testCaseRun.getExecutedHooks(hookType);
|
|
67
|
-
testRunHooks.forEach(({
|
|
68
|
-
hook
|
|
69
|
-
}) => {
|
|
70
|
-
if (testCaseHooks.has(hook.internalId)) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const testStep = {
|
|
74
|
-
id: `${this.id}-${hookType}-${testCaseHooks.size}`,
|
|
75
|
-
hookId: hook.id
|
|
76
|
-
};
|
|
77
|
-
testCaseHooks.set(hook.internalId, {
|
|
78
|
-
hook,
|
|
79
|
-
testStep
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Initially create steps from pickle steps, with empty stepMatchArgumentsLists.
|
|
85
|
-
*/
|
|
86
|
-
addStepsFromPickle(pickle) {
|
|
87
|
-
this.mainSteps = pickle.steps.map((pickleStep, stepIndex) => {
|
|
88
|
-
return {
|
|
89
|
-
id: `${this.id}-step-${stepIndex}`,
|
|
90
|
-
pickleStepId: pickleStep.id,
|
|
91
|
-
stepDefinitionIds: [],
|
|
92
|
-
stepMatchArgumentsLists: []
|
|
93
|
-
};
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Fill stepMatchArgumentsLists from all test runs.
|
|
98
|
-
* It allows to fill as many steps as possible.
|
|
99
|
-
* Possibly, we write the same stepMatchArgumentsLists several times,
|
|
100
|
-
* looks like it's not a problem as they should be equal for all runs.
|
|
101
|
-
*/
|
|
102
|
-
addStepsArgumentsLists(testCaseRun) {
|
|
103
|
-
testCaseRun.bddData.steps.forEach((bddDataStep, stepIndex) => {
|
|
104
|
-
var _this$mainSteps;
|
|
105
|
-
const testCaseStep = (_this$mainSteps = this.mainSteps) === null || _this$mainSteps === void 0 ? void 0 : _this$mainSteps[stepIndex];
|
|
106
|
-
if (testCaseStep && bddDataStep.stepMatchArgumentsLists) {
|
|
107
|
-
testCaseStep.stepMatchArgumentsLists = bddDataStep.stepMatchArgumentsLists;
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
findPickle({
|
|
112
|
-
uri,
|
|
113
|
-
pickleLocation
|
|
114
|
-
}) {
|
|
115
|
-
const doc = this.gherkinDocuments.find(doc => doc.uri === uri);
|
|
116
|
-
if (!doc) {
|
|
117
|
-
throw new Error('GherkinDocument not found');
|
|
118
|
-
}
|
|
119
|
-
const pickle = doc.pickles.find(pickle => {
|
|
120
|
-
return (0, _utils.stringifyLocation)(pickle.location) === pickleLocation;
|
|
121
|
-
});
|
|
122
|
-
if (!pickle) {
|
|
123
|
-
throw new Error('Pickle not found');
|
|
124
|
-
}
|
|
125
|
-
return pickle;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
exports.TestCase = TestCase;
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.TestCaseRun = void 0;
|
|
7
|
-
var _utils = require("../../../utils");
|
|
8
|
-
var _TestStepRun = require("./TestStepRun");
|
|
9
|
-
var _timing = require("./timing");
|
|
10
|
-
var _pwStepUtils = require("./pwStepUtils");
|
|
11
|
-
var _AttachmentMapper = require("./AttachmentMapper");
|
|
12
|
-
var _TestCaseRunHooks = require("./TestCaseRunHooks");
|
|
13
|
-
var _Projects = require("./Projects");
|
|
14
|
-
var _bddData = require("../../../run/bddData");
|
|
15
|
-
class TestCaseRun {
|
|
16
|
-
test;
|
|
17
|
-
result;
|
|
18
|
-
hooks;
|
|
19
|
-
id;
|
|
20
|
-
bddData;
|
|
21
|
-
testCase;
|
|
22
|
-
attachmentMapper;
|
|
23
|
-
projectInfo;
|
|
24
|
-
// collect steps with error and show only these errors in report.
|
|
25
|
-
// it allows to not show the same error on parent steps
|
|
26
|
-
errorSteps = new Set();
|
|
27
|
-
timeoutedStep;
|
|
28
|
-
executedBeforeHooks;
|
|
29
|
-
executedAfterHooks;
|
|
30
|
-
executedSteps;
|
|
31
|
-
// eslint-disable-next-line max-params
|
|
32
|
-
constructor(test, result, hooks) {
|
|
33
|
-
this.test = test;
|
|
34
|
-
this.result = result;
|
|
35
|
-
this.hooks = hooks;
|
|
36
|
-
this.id = this.generateTestRunId();
|
|
37
|
-
this.bddData = this.extractBddData();
|
|
38
|
-
this.projectInfo = (0, _Projects.getProjectInfo)(this.test);
|
|
39
|
-
this.attachmentMapper = new _AttachmentMapper.AttachmentMapper(this.result);
|
|
40
|
-
this.executedSteps = this.fillExecutedSteps();
|
|
41
|
-
this.executedBeforeHooks = this.fillExecutedHooks('before');
|
|
42
|
-
this.executedAfterHooks = this.fillExecutedHooks('after');
|
|
43
|
-
}
|
|
44
|
-
getTestCase() {
|
|
45
|
-
if (!this.testCase) {
|
|
46
|
-
throw new Error(`TestCase is not set.`);
|
|
47
|
-
}
|
|
48
|
-
return this.testCase;
|
|
49
|
-
}
|
|
50
|
-
isTimeouted() {
|
|
51
|
-
return this.result.status === 'timedOut';
|
|
52
|
-
}
|
|
53
|
-
generateTestRunId() {
|
|
54
|
-
return `${this.test.id}-attempt-${this.result.retry}`;
|
|
55
|
-
}
|
|
56
|
-
extractBddData() {
|
|
57
|
-
const {
|
|
58
|
-
bddData,
|
|
59
|
-
annotationIndex
|
|
60
|
-
} = (0, _bddData.getBddDataFromTest)(this.test);
|
|
61
|
-
if (!bddData) {
|
|
62
|
-
throw new Error(`__bddData annotation is not found for test "${this.test.title}".`);
|
|
63
|
-
}
|
|
64
|
-
// remove __bddData annotation from test (mutate)
|
|
65
|
-
this.test.annotations.splice(annotationIndex, 1);
|
|
66
|
-
return bddData;
|
|
67
|
-
}
|
|
68
|
-
fillExecutedSteps() {
|
|
69
|
-
const possiblePwSteps = this.getPossiblePlaywrightBddSteps();
|
|
70
|
-
return this.bddData.steps.map(bddDataStep => {
|
|
71
|
-
const pwStep = this.findPlaywrightStep(possiblePwSteps, bddDataStep);
|
|
72
|
-
this.registerErrorStep(pwStep);
|
|
73
|
-
this.registerTimeoutedStep(pwStep);
|
|
74
|
-
return {
|
|
75
|
-
bddDataStep,
|
|
76
|
-
pwStep
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
fillExecutedHooks(hookType) {
|
|
81
|
-
return new _TestCaseRunHooks.TestCaseRunHooks(this, hookType).fill(this.executedSteps);
|
|
82
|
-
}
|
|
83
|
-
registerErrorStep(pwStep) {
|
|
84
|
-
if (pwStep !== null && pwStep !== void 0 && pwStep.error) {
|
|
85
|
-
this.errorSteps.add(pwStep);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
// eslint-disable-next-line complexity
|
|
89
|
-
registerTimeoutedStep(pwStep) {
|
|
90
|
-
if (!pwStep || !this.isTimeouted() || this.timeoutedStep) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
const {
|
|
94
|
-
error
|
|
95
|
-
} = pwStep;
|
|
96
|
-
if ((0, _pwStepUtils.isUnknownDuration)(pwStep) || this.result.errors.some(e => e.message === (error === null || error === void 0 ? void 0 : error.message))) {
|
|
97
|
-
this.timeoutedStep = pwStep;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
buildMessages() {
|
|
101
|
-
return [this.buildTestCaseStarted(), ...this.executedBeforeHooks.buildMessages(), ...this.buildStepRuns(), ...this.executedAfterHooks.buildMessages(), this.buildTestCaseFinished()];
|
|
102
|
-
}
|
|
103
|
-
getExecutedHooks(hookType) {
|
|
104
|
-
return hookType === 'before' ? this.executedBeforeHooks.executedHooks : this.executedAfterHooks.executedHooks;
|
|
105
|
-
}
|
|
106
|
-
buildTestCaseStarted() {
|
|
107
|
-
const testCaseStarted = {
|
|
108
|
-
id: this.id,
|
|
109
|
-
attempt: this.result.retry,
|
|
110
|
-
testCaseId: this.getTestCase().id,
|
|
111
|
-
// workerId: 'worker-1'
|
|
112
|
-
timestamp: (0, _timing.toCucumberTimestamp)(this.result.startTime.getTime())
|
|
113
|
-
};
|
|
114
|
-
return {
|
|
115
|
-
testCaseStarted
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
buildStepRuns() {
|
|
119
|
-
return this.getTestCase().getMainSteps().reduce((messages, testStep, stepIndex) => {
|
|
120
|
-
const {
|
|
121
|
-
pwStep
|
|
122
|
-
} = this.executedSteps[stepIndex] || {};
|
|
123
|
-
const testStepRun = new _TestStepRun.TestStepRun(this, testStep, pwStep);
|
|
124
|
-
return messages.concat(testStepRun.buildMessages());
|
|
125
|
-
}, []);
|
|
126
|
-
}
|
|
127
|
-
buildTestCaseFinished() {
|
|
128
|
-
const {
|
|
129
|
-
startTime,
|
|
130
|
-
duration
|
|
131
|
-
} = this.result;
|
|
132
|
-
const testCaseFinished = {
|
|
133
|
-
testCaseStartedId: this.id,
|
|
134
|
-
willBeRetried: Boolean(this.result.error && this.result.retry < this.test.retries),
|
|
135
|
-
timestamp: (0, _timing.toCucumberTimestamp)(startTime.getTime() + duration)
|
|
136
|
-
};
|
|
137
|
-
return {
|
|
138
|
-
testCaseFinished
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
findPlaywrightStep(possiblePwSteps, bddDataStep) {
|
|
142
|
-
return possiblePwSteps.find(pwStep => {
|
|
143
|
-
return pwStep.location && (0, _utils.stringifyLocation)(pwStep.location) === bddDataStep.pwStepLocation;
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
getPossiblePlaywrightBddSteps() {
|
|
147
|
-
// Before we collected only top-level steps and steps from before hooks (as they are background)
|
|
148
|
-
// But it's more reliable to just collect all test.step items b/c some Playwright versions
|
|
149
|
-
// move steps to fixtures (see: https://github.com/microsoft/playwright/issues/30075)
|
|
150
|
-
// Collecting all test.step items should be ok, as later we anyway map them by location.
|
|
151
|
-
return (0, _pwStepUtils.collectStepsWithCategory)(this.result, 'test.step');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
exports.TestCaseRun = TestCaseRun;
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.TestCaseRunHooks = void 0;
|
|
7
|
-
var _Hook = require("./Hook");
|
|
8
|
-
var _pwStepUtils = require("./pwStepUtils");
|
|
9
|
-
var _TestStepRun = require("./TestStepRun");
|
|
10
|
-
class TestCaseRunHooks {
|
|
11
|
-
testCaseRun;
|
|
12
|
-
hookType;
|
|
13
|
-
rootPwStep;
|
|
14
|
-
candidateSteps = [];
|
|
15
|
-
hookSteps = new Set();
|
|
16
|
-
executedHooks = new Map();
|
|
17
|
-
constructor(testCaseRun, hookType) {
|
|
18
|
-
this.testCaseRun = testCaseRun;
|
|
19
|
-
this.hookType = hookType;
|
|
20
|
-
}
|
|
21
|
-
fill(mainSteps) {
|
|
22
|
-
this.setRootStep();
|
|
23
|
-
this.setCandidateSteps();
|
|
24
|
-
this.addStepsWithName();
|
|
25
|
-
this.addStepWithError();
|
|
26
|
-
this.addStepWithTimeout();
|
|
27
|
-
this.addStepsWithAttachment();
|
|
28
|
-
this.excludeMainSteps(mainSteps);
|
|
29
|
-
this.setExecutedHooks();
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
buildMessages() {
|
|
33
|
-
const messages = [];
|
|
34
|
-
this.testCaseRun.getTestCase().getHooks(this.hookType).forEach(hookInfo => {
|
|
35
|
-
const executedHook = this.executedHooks.get(hookInfo.hook.internalId);
|
|
36
|
-
// todo: if pwStep is not found in this.executedBeforeHooks,
|
|
37
|
-
// it means that this hook comes from another attempt of this test case.
|
|
38
|
-
// We can stil try to find it in test result, as otherwise it will be marked as skipped,
|
|
39
|
-
// but actually it was executed.
|
|
40
|
-
const testStepRun = new _TestStepRun.TestStepRun(this.testCaseRun, hookInfo.testStep, executedHook === null || executedHook === void 0 ? void 0 : executedHook.pwStep);
|
|
41
|
-
messages.push(...testStepRun.buildMessages());
|
|
42
|
-
});
|
|
43
|
-
return messages;
|
|
44
|
-
}
|
|
45
|
-
setRootStep() {
|
|
46
|
-
this.rootPwStep = (0, _pwStepUtils.getHooksRootPwStep)(this.testCaseRun.result, this.hookType);
|
|
47
|
-
}
|
|
48
|
-
setCandidateSteps() {
|
|
49
|
-
if (this.rootPwStep) {
|
|
50
|
-
this.candidateSteps.push(this.rootPwStep);
|
|
51
|
-
}
|
|
52
|
-
this.candidateSteps.push(...(0, _pwStepUtils.collectStepsDfs)(this.rootPwStep));
|
|
53
|
-
}
|
|
54
|
-
addStepsWithName() {
|
|
55
|
-
this.candidateSteps.forEach(pwStep => {
|
|
56
|
-
if (pwStep.category === 'test.step' && pwStep.title) {
|
|
57
|
-
this.hookSteps.add(pwStep);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
addStepsWithAttachment() {
|
|
62
|
-
const {
|
|
63
|
-
attachmentMapper
|
|
64
|
-
} = this.testCaseRun;
|
|
65
|
-
this.candidateSteps.forEach(pwStep => {
|
|
66
|
-
if (attachmentMapper.getStepAttachments(pwStep).length > 0) {
|
|
67
|
-
this.hookSteps.add(pwStep);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
addStepWithError() {
|
|
72
|
-
const stepWithError = (0, _pwStepUtils.findDeepestStepWithError)(this.rootPwStep);
|
|
73
|
-
if (stepWithError) {
|
|
74
|
-
this.hookSteps.add(stepWithError);
|
|
75
|
-
// in Playwright error is inherited by all parent steps,
|
|
76
|
-
// but we want to show it once (in the deepest step)
|
|
77
|
-
this.testCaseRun.registerErrorStep(stepWithError);
|
|
78
|
-
this.testCaseRun.registerTimeoutedStep(stepWithError);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
addStepWithTimeout() {
|
|
82
|
-
if (!this.testCaseRun.isTimeouted()) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
if (this.testCaseRun.timeoutedStep) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const timeoutedStep = this.hookType === 'before' ?
|
|
89
|
-
// Timeouted steps have duration = -1 in PW <= 1.39 and no error field.
|
|
90
|
-
// In PW > 1.39 timeouted steps have '.error' populated
|
|
91
|
-
(0, _pwStepUtils.findDeepestStepWithUnknownDuration)(this.rootPwStep) :
|
|
92
|
-
// Timeouted after hooks don't have duration = -1,
|
|
93
|
-
// so there is no way to find which exactly fixture timed out.
|
|
94
|
-
// We mark root 'After Hooks' step as timeouted.
|
|
95
|
-
this.rootPwStep;
|
|
96
|
-
if (timeoutedStep) {
|
|
97
|
-
this.hookSteps.add(timeoutedStep);
|
|
98
|
-
this.testCaseRun.timeoutedStep = timeoutedStep;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
excludeMainSteps(mainSteps) {
|
|
102
|
-
// - exclude background steps, b/c they are in pickle and should not in hooks.
|
|
103
|
-
// - exclude other test.step items that are bdd steps and should not be in hooks.
|
|
104
|
-
// Important to run this fn after this.fillExecutedSteps()
|
|
105
|
-
// as we assume steps are already populated
|
|
106
|
-
mainSteps.forEach(stepInfo => {
|
|
107
|
-
if (stepInfo.pwStep) {
|
|
108
|
-
this.hookSteps.delete(stepInfo.pwStep);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
setExecutedHooks() {
|
|
113
|
-
this.hookSteps.forEach(pwStep => {
|
|
114
|
-
const internalId = _Hook.Hook.getInternalId(pwStep);
|
|
115
|
-
const hook = this.testCaseRun.hooks.getOrCreate(internalId, () => new _Hook.Hook(internalId, pwStep));
|
|
116
|
-
this.executedHooks.set(internalId, {
|
|
117
|
-
hook,
|
|
118
|
-
pwStep
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
exports.TestCaseRunHooks = TestCaseRunHooks;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.TestStepAttachments = void 0;
|
|
8
|
-
var _fs = _interopRequireDefault(require("fs"));
|
|
9
|
-
var messages = _interopRequireWildcard(require("@cucumber/messages"));
|
|
10
|
-
var _path = _interopRequireDefault(require("path"));
|
|
11
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
12
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
13
|
-
/**
|
|
14
|
-
* Class for getting attachment messages for a particular step.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
class TestStepAttachments {
|
|
18
|
-
testCaseRun;
|
|
19
|
-
testStep;
|
|
20
|
-
pwStep;
|
|
21
|
-
constructor(testCaseRun, testStep, pwStep) {
|
|
22
|
-
this.testCaseRun = testCaseRun;
|
|
23
|
-
this.testStep = testStep;
|
|
24
|
-
this.pwStep = pwStep;
|
|
25
|
-
}
|
|
26
|
-
buildMessages() {
|
|
27
|
-
if (!this.pwStep) {
|
|
28
|
-
return [];
|
|
29
|
-
}
|
|
30
|
-
return this.testCaseRun.attachmentMapper.getStepAttachments(this.pwStep).map(pwAttachment => this.buildAttachmentMessage(pwAttachment));
|
|
31
|
-
}
|
|
32
|
-
buildAttachmentMessage(pwAttachment) {
|
|
33
|
-
const attachment = {
|
|
34
|
-
testCaseStartedId: this.testCaseRun.id,
|
|
35
|
-
testStepId: this.testStep.id,
|
|
36
|
-
// for now always attach as base64
|
|
37
|
-
// todo: for text/plain and application/json use raw to save some bytes
|
|
38
|
-
body: this.getAttachmentBodyBase64(pwAttachment),
|
|
39
|
-
contentEncoding: messages.AttachmentContentEncoding.BASE64,
|
|
40
|
-
mediaType: pwAttachment.contentType,
|
|
41
|
-
fileName: pwAttachment.name
|
|
42
|
-
};
|
|
43
|
-
return {
|
|
44
|
-
attachment
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
getAttachmentBodyBase64(pwAttachment) {
|
|
48
|
-
if (pwAttachment.path) {
|
|
49
|
-
if (_fs.default.existsSync(pwAttachment.path)) {
|
|
50
|
-
return _fs.default.readFileSync(pwAttachment.path, 'base64');
|
|
51
|
-
}
|
|
52
|
-
throw createMissingAttachmentError(pwAttachment.path);
|
|
53
|
-
}
|
|
54
|
-
if (pwAttachment.body) {
|
|
55
|
-
return pwAttachment.body.toString('base64');
|
|
56
|
-
}
|
|
57
|
-
throw new Error(`Playwright attachment without path and body`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
exports.TestStepAttachments = TestStepAttachments;
|
|
61
|
-
function createMissingAttachmentError(attachmentPath) {
|
|
62
|
-
const attachmentDir = _path.default.join(_path.default.dirname(attachmentPath));
|
|
63
|
-
const attachmentDirExists = _fs.default.existsSync(attachmentDir);
|
|
64
|
-
const files = attachmentDirExists ? _fs.default.readdirSync(attachmentDir) : [];
|
|
65
|
-
const errorMsg = [`Attachment file is not found:`, attachmentPath, `Attachment dir ${attachmentDirExists ? 'exists' : 'does not exist'}.`, ...(attachmentDirExists ? [`Available files (${files.length}):`, ...files] : []), ''].join('\n');
|
|
66
|
-
return new Error(errorMsg);
|
|
67
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.TestStepRun = void 0;
|
|
7
|
-
var messages = _interopRequireWildcard(require("@cucumber/messages"));
|
|
8
|
-
var _stripAnsiEscapes = require("../../../utils/stripAnsiEscapes");
|
|
9
|
-
var _timing = require("./timing");
|
|
10
|
-
var _TestStepAttachments = require("./TestStepAttachments");
|
|
11
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
12
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
13
|
-
class TestStepRun {
|
|
14
|
-
testCaseRun;
|
|
15
|
-
testStep;
|
|
16
|
-
pwStep;
|
|
17
|
-
constructor(testCaseRun, testStep, pwStep) {
|
|
18
|
-
this.testCaseRun = testCaseRun;
|
|
19
|
-
this.testStep = testStep;
|
|
20
|
-
this.pwStep = pwStep;
|
|
21
|
-
}
|
|
22
|
-
buildMessages() {
|
|
23
|
-
const stepAttachments = new _TestStepAttachments.TestStepAttachments(this.testCaseRun, this.testStep, this.pwStep);
|
|
24
|
-
return [this.buildTestStepStarted(),
|
|
25
|
-
// prettier-ignore
|
|
26
|
-
...stepAttachments.buildMessages(), this.buildTestStepFinished()];
|
|
27
|
-
}
|
|
28
|
-
isHook() {
|
|
29
|
-
return Boolean(this.testStep.hookId);
|
|
30
|
-
}
|
|
31
|
-
wasExecuted() {
|
|
32
|
-
return Boolean(this.pwStep);
|
|
33
|
-
}
|
|
34
|
-
get startTime() {
|
|
35
|
-
return this.wasExecuted() ? this.pwStep.startTime : this.testCaseRun.result.startTime;
|
|
36
|
-
}
|
|
37
|
-
get duration() {
|
|
38
|
-
return this.wasExecuted() ? this.pwStep.duration : 0;
|
|
39
|
-
}
|
|
40
|
-
buildTestStepStarted() {
|
|
41
|
-
const testStepStarted = {
|
|
42
|
-
testCaseStartedId: this.testCaseRun.id,
|
|
43
|
-
testStepId: this.testStep.id,
|
|
44
|
-
timestamp: (0, _timing.toCucumberTimestamp)(this.startTime.getTime())
|
|
45
|
-
};
|
|
46
|
-
return {
|
|
47
|
-
testStepStarted
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
buildTestStepFinished() {
|
|
51
|
-
const error = this.getStepError();
|
|
52
|
-
const testStepFinished = {
|
|
53
|
-
testCaseStartedId: this.testCaseRun.id,
|
|
54
|
-
testStepId: this.testStep.id,
|
|
55
|
-
testStepResult: {
|
|
56
|
-
duration: messages.TimeConversion.millisecondsToDuration(this.duration),
|
|
57
|
-
status: this.getStatus(error),
|
|
58
|
-
// 'message' is deprecated since cucumber 10.4 in favor of 'exception' field
|
|
59
|
-
// See: https://github.com/cucumber/react-components/pull/345
|
|
60
|
-
message: error ? buildErrorMessage(error) : undefined,
|
|
61
|
-
exception: error ? buildException(error) : undefined
|
|
62
|
-
},
|
|
63
|
-
timestamp: (0, _timing.toCucumberTimestamp)(this.startTime.getTime() + this.duration)
|
|
64
|
-
};
|
|
65
|
-
return {
|
|
66
|
-
testStepFinished
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
getStatus(error) {
|
|
70
|
-
switch (true) {
|
|
71
|
-
case Boolean(error):
|
|
72
|
-
return messages.TestStepResultStatus.FAILED;
|
|
73
|
-
// For hooks that were not executted we return PASSED, not SKIPPED.
|
|
74
|
-
// Because these hooks can be from another run attempt of this testCase.
|
|
75
|
-
// If marked as skipped, the whole run is marked as skipped in reporter.
|
|
76
|
-
case !this.isHook() && !this.wasExecuted():
|
|
77
|
-
return messages.TestStepResultStatus.SKIPPED;
|
|
78
|
-
default:
|
|
79
|
-
return messages.TestStepResultStatus.PASSED;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// eslint-disable-next-line complexity
|
|
83
|
-
getStepError() {
|
|
84
|
-
if (!this.pwStep) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (this.testCaseRun.errorSteps.has(this.pwStep)) {
|
|
88
|
-
return this.pwStep.error;
|
|
89
|
-
}
|
|
90
|
-
if (this.testCaseRun.isTimeouted() && this.pwStep === this.testCaseRun.timeoutedStep) {
|
|
91
|
-
var _this$testCaseRun$res;
|
|
92
|
-
return {
|
|
93
|
-
message: (_this$testCaseRun$res = this.testCaseRun.result.errors) === null || _this$testCaseRun$res === void 0 ? void 0 : _this$testCaseRun$res.map(e => e.message).join('\n\n')
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
exports.TestStepRun = TestStepRun;
|
|
99
|
-
function buildErrorMessage(error) {
|
|
100
|
-
return (0, _stripAnsiEscapes.stripAnsiEscapes)([error.message, error.snippet].filter(Boolean).join('\n'));
|
|
101
|
-
}
|
|
102
|
-
function buildException(error) {
|
|
103
|
-
return {
|
|
104
|
-
type: 'Error',
|
|
105
|
-
message: buildErrorMessage(error),
|
|
106
|
-
// todo: extract only trace?
|
|
107
|
-
stackTrace: error.stack ? extractStackTrace((0, _stripAnsiEscapes.stripAnsiEscapes)(error.stack)) : undefined
|
|
108
|
-
// Use type casting b/c older versions of @cucumber/messages don't have 'stackTrace' field
|
|
109
|
-
// todo: add direct dependency on @cucumber/messages
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
function extractStackTrace(errorStack) {
|
|
113
|
-
return errorStack.split('\n').filter(line => line.match(/^\s+at .*/)).join('\n');
|
|
114
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.getMessagesBuilderRef = getMessagesBuilderRef;
|
|
7
|
-
var _Builder = require("./Builder");
|
|
8
|
-
/**
|
|
9
|
-
* Returns reference to a messagesBuilder singleton.
|
|
10
|
-
* We pass onTestEnd and onEnd calls only for the first reference (reporter),
|
|
11
|
-
* otherwise all events will be duplicated.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
let instance;
|
|
15
|
-
let referenceCount = 0;
|
|
16
|
-
function getMessagesBuilderRef() {
|
|
17
|
-
if (!instance) {
|
|
18
|
-
instance = new _Builder.MessagesBuilder();
|
|
19
|
-
}
|
|
20
|
-
const isFirstRef = ++referenceCount === 1;
|
|
21
|
-
return {
|
|
22
|
-
builder: instance,
|
|
23
|
-
onTestEnd(test, result) {
|
|
24
|
-
isFirstRef && this.builder.onTestEnd(test, result);
|
|
25
|
-
},
|
|
26
|
-
onEnd(fullResult) {
|
|
27
|
-
isFirstRef && this.builder.onEnd(fullResult);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.collectStepsDfs = collectStepsDfs;
|
|
7
|
-
exports.collectStepsWithCategory = collectStepsWithCategory;
|
|
8
|
-
exports.findDeepestStepWithError = findDeepestStepWithError;
|
|
9
|
-
exports.findDeepestStepWithUnknownDuration = findDeepestStepWithUnknownDuration;
|
|
10
|
-
exports.getHooksRootPwStep = getHooksRootPwStep;
|
|
11
|
-
exports.isUnknownDuration = isUnknownDuration;
|
|
12
|
-
/**
|
|
13
|
-
* Utility functions for filtering Playwright steps.
|
|
14
|
-
*/
|
|
15
|
-
// Playwright step categoires, that can be mapped to testStep / hook in Cucumber messages
|
|
16
|
-
const MEANINGFUL_STEP_CATEGORIES = ['hook', 'fixture', 'test.step'];
|
|
17
|
-
function collectStepsWithCategory(parent, category) {
|
|
18
|
-
const categories = Array.isArray(category) ? category : [category];
|
|
19
|
-
const steps = collectStepsDfs(parent);
|
|
20
|
-
return steps.filter(step => categories.includes(step.category));
|
|
21
|
-
}
|
|
22
|
-
function getHooksRootPwStep(result, type) {
|
|
23
|
-
const rootStepTitle = type === 'before' ? 'Before Hooks' : 'After Hooks';
|
|
24
|
-
return result.steps.find(step => step.category === 'hook' && step.title === rootStepTitle);
|
|
25
|
-
}
|
|
26
|
-
function findDeepestStepWithError(root) {
|
|
27
|
-
if (!root) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
return findDeepestStepWith(root, pwStep => {
|
|
31
|
-
return Boolean(pwStep.error) && MEANINGFUL_STEP_CATEGORIES.includes(pwStep.category);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
function findDeepestStepWithUnknownDuration(root) {
|
|
35
|
-
if (!root) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
return findDeepestStepWith(root, pwStep => {
|
|
39
|
-
return isUnknownDuration(pwStep) && MEANINGFUL_STEP_CATEGORIES.includes(pwStep.category);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Finds the deepest step that satisfies predicate function.
|
|
44
|
-
*/
|
|
45
|
-
function findDeepestStepWith(root, predicate) {
|
|
46
|
-
let currentStep = predicate(root) ? root : undefined;
|
|
47
|
-
while (currentStep) {
|
|
48
|
-
const nextStep = currentStep.steps.find(pwStep => predicate(pwStep));
|
|
49
|
-
if (!nextStep) {
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
currentStep = nextStep;
|
|
53
|
-
}
|
|
54
|
-
return currentStep;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Returns all steps in DFS order.
|
|
58
|
-
* See: https://en.wikipedia.org/wiki/Depth-first_search
|
|
59
|
-
*/
|
|
60
|
-
function collectStepsDfs(parent) {
|
|
61
|
-
var _parent$steps;
|
|
62
|
-
return (parent === null || parent === void 0 || (_parent$steps = parent.steps) === null || _parent$steps === void 0 ? void 0 : _parent$steps.reduce((res, step) => {
|
|
63
|
-
res.push(step);
|
|
64
|
-
res.push(...collectStepsDfs(step));
|
|
65
|
-
return res;
|
|
66
|
-
}, [])) || [];
|
|
67
|
-
}
|
|
68
|
-
function isUnknownDuration(pwStep) {
|
|
69
|
-
return pwStep.duration === -1;
|
|
70
|
-
}
|