codeceptjs 3.6.7 → 4.0.0-beta.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/bin/codecept.js +81 -84
- package/lib/actor.js +13 -13
- package/lib/ai.js +13 -10
- package/lib/assert/empty.js +21 -20
- package/lib/assert/equal.js +39 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +47 -46
- package/lib/assert/throws.js +11 -13
- package/lib/assert/truth.js +22 -19
- package/lib/assert.js +2 -4
- package/lib/cli.js +49 -57
- package/lib/codecept.js +155 -142
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +52 -58
- package/lib/command/definitions.js +89 -88
- package/lib/command/dryRun.js +68 -71
- package/lib/command/generate.js +188 -197
- package/lib/command/gherkin/init.js +16 -27
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +38 -40
- package/lib/command/init.js +288 -290
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple/chunk.js +5 -5
- package/lib/command/run-multiple/collection.js +3 -3
- package/lib/command/run-multiple/run.js +2 -6
- package/lib/command/run-multiple.js +93 -113
- package/lib/command/run-rerun.js +25 -20
- package/lib/command/run-workers.js +66 -64
- package/lib/command/run.js +29 -26
- package/lib/command/utils.js +65 -80
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +9 -10
- package/lib/container.js +48 -40
- package/lib/data/context.js +59 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +20 -26
- package/lib/dirname.js +5 -0
- package/lib/event.js +167 -163
- package/lib/heal.js +17 -13
- package/lib/helper/AI.js +41 -130
- package/lib/helper/ApiDataFactory.js +69 -73
- package/lib/helper/Appium.js +381 -412
- package/lib/helper/Expect.js +425 -0
- package/lib/helper/ExpectHelper.js +48 -40
- package/lib/helper/FileSystem.js +79 -80
- package/lib/helper/GraphQL.js +43 -44
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +62 -65
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +14 -12
- package/lib/helper/Nightmare.js +566 -662
- package/lib/helper/Playwright.js +1216 -1361
- package/lib/helper/Protractor.js +627 -663
- package/lib/helper/Puppeteer.js +1128 -1231
- package/lib/helper/REST.js +68 -159
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +484 -490
- package/lib/helper/WebDriver.js +1156 -1297
- package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
- package/lib/helper/errors/ConnectionRefused.js +1 -1
- package/lib/helper/errors/ElementAssertion.js +2 -2
- package/lib/helper/errors/ElementNotFound.js +2 -2
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
- package/lib/helper/extras/Console.js +1 -1
- package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
- package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
- package/lib/helper/extras/PlaywrightRestartOpts.js +18 -21
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +7 -14
- package/lib/helper/network/utils.js +2 -3
- package/lib/helper/scripts/blurElement.js +1 -1
- package/lib/helper/scripts/focusElement.js +1 -1
- package/lib/helper/scripts/highlightElement.js +1 -1
- package/lib/helper/scripts/isElementClickable.js +1 -1
- package/lib/helper/testcafe/testControllerHolder.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +7 -6
- package/lib/helper.js +3 -1
- package/lib/history.js +5 -6
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +41 -25
- package/lib/interfaces/bdd.js +64 -47
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +118 -124
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -24
- package/lib/listener/exit.js +12 -12
- package/lib/listener/helpers.js +42 -42
- package/lib/listener/mocha.js +11 -11
- package/lib/listener/retry.js +30 -32
- package/lib/listener/steps.js +53 -50
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +10 -6
- package/lib/mochaFactory.js +15 -18
- package/lib/output.js +10 -6
- package/lib/parser.js +12 -15
- package/lib/pause.js +33 -40
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +37 -29
- package/lib/plugin/autoLogin.js +65 -70
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +67 -115
- package/lib/plugin/customLocator.js +20 -21
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +38 -38
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +108 -67
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +39 -32
- package/lib/plugin/retryTo.js +40 -46
- package/lib/plugin/screenshotOnFail.js +87 -109
- package/lib/plugin/selenoid.js +118 -131
- package/lib/plugin/standardActingHelpers.js +8 -2
- package/lib/plugin/stepByStepReport.js +91 -110
- package/lib/plugin/stepTimeout.js +23 -24
- package/lib/plugin/subtitles.js +35 -34
- package/lib/plugin/tryTo.js +30 -40
- package/lib/plugin/wdio.js +75 -78
- package/lib/recorder.js +17 -14
- package/lib/rerun.js +10 -11
- package/lib/scenario.js +23 -25
- package/lib/secret.js +2 -4
- package/lib/session.js +10 -10
- package/lib/step.js +9 -12
- package/lib/store.js +3 -2
- package/lib/transform.js +1 -1
- package/lib/translation.js +8 -7
- package/lib/ui.js +14 -12
- package/lib/utils.js +72 -70
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +25 -27
- package/lib/workers.js +32 -29
- package/package.json +53 -51
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +13 -9
- package/translations/it-IT.js +1 -1
- package/translations/ja-JP.js +1 -1
- package/translations/pl-PL.js +1 -1
- package/translations/pt-BR.js +1 -1
- package/translations/ru-RU.js +1 -1
- package/translations/zh-CN.js +1 -1
- package/translations/zh-TW.js +1 -1
- package/typings/index.d.ts +65 -415
package/lib/listener/helpers.js
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import * as event from '../event.js';
|
|
2
|
+
import container from '../container.js';
|
|
3
|
+
import recorder from '../recorder.js';
|
|
4
|
+
import { store } from '../store.js';
|
|
5
|
+
import * as output from '../output.js';
|
|
6
|
+
|
|
7
7
|
/**
|
|
8
8
|
* Enable Helpers to listen to test events
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
|
-
const helpers = container.helpers()
|
|
10
|
+
export default function () {
|
|
11
|
+
const helpers = container.helpers();
|
|
12
12
|
|
|
13
13
|
const runHelpersHook = (hook, param) => {
|
|
14
|
-
if (store.dryRun) return
|
|
14
|
+
if (store.dryRun) return;
|
|
15
15
|
Object.values(helpers).forEach((helper) => {
|
|
16
16
|
if (helper[hook]) {
|
|
17
|
-
helper[hook](param)
|
|
17
|
+
helper[hook](param);
|
|
18
18
|
}
|
|
19
|
-
})
|
|
20
|
-
}
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
21
|
|
|
22
22
|
const runAsyncHelpersHook = (hook, param, force) => {
|
|
23
|
-
if (store.dryRun) return
|
|
23
|
+
if (store.dryRun) return;
|
|
24
24
|
Object.keys(helpers).forEach((key) => {
|
|
25
|
-
if (!helpers[key][hook]) return
|
|
26
|
-
recorder.add(`hook ${key}.${hook}()`, () => helpers[key][hook](param), force, false)
|
|
27
|
-
})
|
|
28
|
-
}
|
|
25
|
+
if (!helpers[key][hook]) return;
|
|
26
|
+
recorder.add(`hook ${key}.${hook}()`, () => helpers[key][hook](param), force, false);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
29
|
|
|
30
30
|
event.dispatcher.on(event.suite.before, (suite) => {
|
|
31
31
|
// if (suite.parent) return; // only for root suite
|
|
32
|
-
runAsyncHelpersHook('_beforeSuite', suite, true)
|
|
33
|
-
})
|
|
32
|
+
runAsyncHelpersHook('_beforeSuite', suite, true);
|
|
33
|
+
});
|
|
34
34
|
|
|
35
35
|
event.dispatcher.on(event.suite.after, (suite) => {
|
|
36
36
|
// if (suite.parent) return; // only for root suite
|
|
37
|
-
runAsyncHelpersHook('_afterSuite', suite, true)
|
|
38
|
-
})
|
|
37
|
+
runAsyncHelpersHook('_afterSuite', suite, true);
|
|
38
|
+
});
|
|
39
39
|
|
|
40
40
|
event.dispatcher.on(event.test.started, (test) => {
|
|
41
|
-
runHelpersHook('_test', test)
|
|
42
|
-
recorder.catch(
|
|
43
|
-
})
|
|
41
|
+
runHelpersHook('_test', test);
|
|
42
|
+
recorder.catch(e => output.output.error(e));
|
|
43
|
+
});
|
|
44
44
|
|
|
45
45
|
event.dispatcher.on(event.test.before, (test) => {
|
|
46
46
|
// schedule config to revert changes
|
|
47
|
-
runAsyncHelpersHook('_before', test, true)
|
|
48
|
-
recorder.catchWithoutStop(
|
|
49
|
-
})
|
|
47
|
+
runAsyncHelpersHook('_before', test, true);
|
|
48
|
+
recorder.catchWithoutStop(e => output.output.error(e));
|
|
49
|
+
});
|
|
50
50
|
|
|
51
51
|
event.dispatcher.on(event.test.passed, (test) => {
|
|
52
|
-
runAsyncHelpersHook('_passed', test, true)
|
|
52
|
+
runAsyncHelpersHook('_passed', test, true);
|
|
53
53
|
// should not fail test execution, so errors should be caught
|
|
54
|
-
recorder.catchWithoutStop(
|
|
55
|
-
})
|
|
54
|
+
recorder.catchWithoutStop(e => output.output.error(e));
|
|
55
|
+
});
|
|
56
56
|
|
|
57
57
|
event.dispatcher.on(event.test.failed, (test) => {
|
|
58
|
-
runAsyncHelpersHook('_failed', test, true)
|
|
58
|
+
runAsyncHelpersHook('_failed', test, true);
|
|
59
59
|
// should not fail test execution, so errors should be caught
|
|
60
|
-
recorder.catchWithoutStop(
|
|
61
|
-
})
|
|
60
|
+
recorder.catchWithoutStop(e => output.output.error(e));
|
|
61
|
+
});
|
|
62
62
|
|
|
63
63
|
event.dispatcher.on(event.test.after, () => {
|
|
64
|
-
runAsyncHelpersHook('_after', {}, true)
|
|
65
|
-
recorder.catchWithoutStop(
|
|
66
|
-
})
|
|
64
|
+
runAsyncHelpersHook('_after', {}, true);
|
|
65
|
+
recorder.catchWithoutStop(e => output.output.error(e));
|
|
66
|
+
});
|
|
67
67
|
|
|
68
68
|
event.dispatcher.on(event.step.before, (step) => {
|
|
69
|
-
runAsyncHelpersHook('_beforeStep', step)
|
|
70
|
-
})
|
|
69
|
+
runAsyncHelpersHook('_beforeStep', step);
|
|
70
|
+
});
|
|
71
71
|
|
|
72
72
|
event.dispatcher.on(event.step.after, (step) => {
|
|
73
|
-
runAsyncHelpersHook('_afterStep', step)
|
|
74
|
-
})
|
|
73
|
+
runAsyncHelpersHook('_afterStep', step);
|
|
74
|
+
});
|
|
75
75
|
|
|
76
76
|
event.dispatcher.on(event.all.result, () => {
|
|
77
|
-
runAsyncHelpersHook('_finishTest', {}, true)
|
|
78
|
-
})
|
|
77
|
+
runAsyncHelpersHook('_finishTest', {}, true);
|
|
78
|
+
});
|
|
79
79
|
}
|
package/lib/listener/mocha.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as event from '../event.js';
|
|
2
|
+
import container from '../container.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
let mocha
|
|
4
|
+
export default function () {
|
|
5
|
+
let mocha;
|
|
6
6
|
|
|
7
7
|
event.dispatcher.on(event.all.before, () => {
|
|
8
|
-
mocha = container.mocha()
|
|
9
|
-
})
|
|
8
|
+
mocha = container.mocha();
|
|
9
|
+
});
|
|
10
10
|
|
|
11
11
|
event.dispatcher.on(event.test.passed, (test) => {
|
|
12
|
-
mocha.Runner.emit('pass', test)
|
|
13
|
-
})
|
|
12
|
+
mocha.Runner.emit('pass', test);
|
|
13
|
+
});
|
|
14
14
|
|
|
15
15
|
event.dispatcher.on(event.test.failed, (test, err) => {
|
|
16
|
-
test.state = 'failed'
|
|
17
|
-
mocha.Runner.emit('fail', test, err)
|
|
18
|
-
})
|
|
16
|
+
test.state = 'failed';
|
|
17
|
+
mocha.Runner.emit('fail', test, err);
|
|
18
|
+
});
|
|
19
19
|
}
|
package/lib/listener/retry.js
CHANGED
|
@@ -1,70 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import * as event from '../event.js';
|
|
2
|
+
import * as output from '../output.js';
|
|
3
|
+
import Config from '../config.js';
|
|
4
|
+
import { isNotSet } from '../utils.js';
|
|
5
5
|
|
|
6
|
-
const hooks = ['Before', 'After', 'BeforeSuite', 'AfterSuite']
|
|
6
|
+
const hooks = ['Before', 'After', 'BeforeSuite', 'AfterSuite'];
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
export default function () {
|
|
9
9
|
event.dispatcher.on(event.suite.before, (suite) => {
|
|
10
|
-
let retryConfig = Config.get('retry')
|
|
11
|
-
if (!retryConfig) return
|
|
10
|
+
let retryConfig = Config.get('retry');
|
|
11
|
+
if (!retryConfig) return;
|
|
12
12
|
|
|
13
13
|
if (Number.isInteger(+retryConfig)) {
|
|
14
14
|
// is number
|
|
15
|
-
const retryNum = +retryConfig
|
|
16
|
-
output.log(`Retries: ${retryNum}`)
|
|
17
|
-
suite.retries(retryNum)
|
|
18
|
-
return
|
|
15
|
+
const retryNum = +retryConfig;
|
|
16
|
+
output.output.log(`Retries: ${retryNum}`);
|
|
17
|
+
suite.retries(retryNum);
|
|
18
|
+
return;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
if (!Array.isArray(retryConfig)) {
|
|
22
|
-
retryConfig = [retryConfig]
|
|
22
|
+
retryConfig = [retryConfig];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
for (const config of retryConfig) {
|
|
26
26
|
if (config.grep) {
|
|
27
|
-
if (!suite.title.includes(config.grep)) continue
|
|
27
|
+
if (!suite.title.includes(config.grep)) continue;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
hooks
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (isNotSet(suite.opts[`retry${hook}`])) suite.opts[`retry${hook}`] = config[hook]
|
|
34
|
-
})
|
|
30
|
+
hooks.filter(hook => !!config[hook]).forEach((hook) => {
|
|
31
|
+
if (isNotSet(suite.opts[`retry${hook}`])) suite.opts[`retry${hook}`] = config[hook];
|
|
32
|
+
});
|
|
35
33
|
|
|
36
34
|
if (config.Feature) {
|
|
37
|
-
if (isNotSet(suite.retries())) suite.retries(config.Feature)
|
|
35
|
+
if (isNotSet(suite.retries())) suite.retries(config.Feature);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
output.log(`Retries: ${JSON.stringify(config)}`)
|
|
38
|
+
output.output.log(`Retries: ${JSON.stringify(config)}`);
|
|
41
39
|
}
|
|
42
|
-
})
|
|
40
|
+
});
|
|
43
41
|
|
|
44
42
|
event.dispatcher.on(event.test.before, (test) => {
|
|
45
|
-
let retryConfig = Config.get('retry')
|
|
46
|
-
if (!retryConfig) return
|
|
43
|
+
let retryConfig = Config.get('retry');
|
|
44
|
+
if (!retryConfig) return;
|
|
47
45
|
|
|
48
46
|
if (Number.isInteger(+retryConfig)) {
|
|
49
|
-
if (test.retries() === -1) test.retries(retryConfig)
|
|
50
|
-
return
|
|
47
|
+
if (test.retries() === -1) test.retries(retryConfig);
|
|
48
|
+
return;
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
if (!Array.isArray(retryConfig)) {
|
|
54
|
-
retryConfig = [retryConfig]
|
|
52
|
+
retryConfig = [retryConfig];
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
retryConfig = retryConfig.filter(
|
|
55
|
+
retryConfig = retryConfig.filter(config => !!config.Scenario);
|
|
58
56
|
|
|
59
57
|
for (const config of retryConfig) {
|
|
60
58
|
if (config.grep) {
|
|
61
|
-
if (!test.fullTitle().includes(config.grep)) continue
|
|
59
|
+
if (!test.fullTitle().includes(config.grep)) continue;
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
if (config.Scenario) {
|
|
65
|
-
if (test.retries() === -1) test.retries(config.Scenario)
|
|
66
|
-
output.log(`Retries: ${config.Scenario}`)
|
|
63
|
+
if (test.retries() === -1) test.retries(config.Scenario);
|
|
64
|
+
output.output.log(`Retries: ${config.Scenario}`);
|
|
67
65
|
}
|
|
68
66
|
}
|
|
69
|
-
})
|
|
67
|
+
});
|
|
70
68
|
}
|
package/lib/listener/steps.js
CHANGED
|
@@ -1,83 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import * as event from '../event.js';
|
|
3
|
+
import { store } from '../store.js';
|
|
4
|
+
import * as output from '../output.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
debug('codeceptjs:steps');
|
|
7
|
+
|
|
8
|
+
let currentTest;
|
|
9
|
+
let currentHook;
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Register steps inside tests
|
|
11
13
|
*/
|
|
12
|
-
|
|
14
|
+
export default function () {
|
|
13
15
|
event.dispatcher.on(event.test.before, (test) => {
|
|
14
|
-
test.startedAt = +new Date()
|
|
15
|
-
test.artifacts = {}
|
|
16
|
-
})
|
|
16
|
+
test.startedAt = +new Date();
|
|
17
|
+
test.artifacts = {};
|
|
18
|
+
});
|
|
17
19
|
|
|
18
20
|
event.dispatcher.on(event.test.started, (test) => {
|
|
19
|
-
currentTest = test
|
|
20
|
-
currentTest.steps = []
|
|
21
|
-
if (!('retryNum' in currentTest)) currentTest.retryNum = 0
|
|
22
|
-
else currentTest.retryNum += 1
|
|
23
|
-
})
|
|
21
|
+
currentTest = test;
|
|
22
|
+
currentTest.steps = [];
|
|
23
|
+
if (!('retryNum' in currentTest)) currentTest.retryNum = 0;
|
|
24
|
+
else currentTest.retryNum += 1;
|
|
25
|
+
});
|
|
24
26
|
|
|
25
27
|
event.dispatcher.on(event.test.after, (test) => {
|
|
26
|
-
currentTest = null
|
|
27
|
-
})
|
|
28
|
+
currentTest = null;
|
|
29
|
+
});
|
|
28
30
|
|
|
29
|
-
event.dispatcher.on(event.test.finished, (test) => {
|
|
31
|
+
event.dispatcher.on(event.test.finished, (test) => {
|
|
32
|
+
});
|
|
30
33
|
|
|
31
34
|
event.dispatcher.on(event.hook.started, (suite) => {
|
|
32
|
-
currentHook = suite.ctx.test
|
|
33
|
-
currentHook.steps = []
|
|
35
|
+
currentHook = suite.ctx.test;
|
|
36
|
+
currentHook.steps = [];
|
|
34
37
|
|
|
35
|
-
if (suite.ctx && suite.ctx.test) output.log(`--- STARTED ${suite.ctx.test.title} ---`)
|
|
36
|
-
})
|
|
38
|
+
if (suite.ctx && suite.ctx.test) output.output.log(`--- STARTED ${suite.ctx.test.title} ---`);
|
|
39
|
+
});
|
|
37
40
|
|
|
38
41
|
event.dispatcher.on(event.hook.passed, (suite) => {
|
|
39
|
-
currentHook = null
|
|
40
|
-
if (suite.ctx && suite.ctx.test) output.log(`--- ENDED ${suite.ctx.test.title} ---`)
|
|
41
|
-
})
|
|
42
|
+
currentHook = null;
|
|
43
|
+
if (suite.ctx && suite.ctx.test) output.output.log(`--- ENDED ${suite.ctx.test.title} ---`);
|
|
44
|
+
});
|
|
42
45
|
|
|
43
46
|
event.dispatcher.on(event.test.failed, () => {
|
|
44
47
|
const cutSteps = function (current) {
|
|
45
|
-
const failureIndex = current.steps.findIndex(
|
|
48
|
+
const failureIndex = current.steps.findIndex(el => el.status === 'failed');
|
|
46
49
|
// To be sure that failed test will be failed in report
|
|
47
|
-
current.state = 'failed'
|
|
48
|
-
current.steps.length = failureIndex + 1
|
|
49
|
-
return current
|
|
50
|
-
}
|
|
50
|
+
current.state = 'failed';
|
|
51
|
+
current.steps.length = failureIndex + 1;
|
|
52
|
+
return current;
|
|
53
|
+
};
|
|
51
54
|
if (currentHook && Array.isArray(currentHook.steps) && currentHook.steps.length) {
|
|
52
|
-
currentHook = cutSteps(currentHook)
|
|
53
|
-
return
|
|
55
|
+
currentHook = cutSteps(currentHook);
|
|
56
|
+
return currentHook = null;
|
|
54
57
|
}
|
|
55
|
-
if (!currentTest) return
|
|
58
|
+
if (!currentTest) return;
|
|
56
59
|
// last step is failing step
|
|
57
|
-
if (!currentTest.steps.length) return
|
|
58
|
-
return
|
|
59
|
-
})
|
|
60
|
+
if (!currentTest.steps.length) return;
|
|
61
|
+
return currentTest = cutSteps(currentTest);
|
|
62
|
+
});
|
|
60
63
|
|
|
61
64
|
event.dispatcher.on(event.test.passed, () => {
|
|
62
|
-
if (!currentTest) return
|
|
65
|
+
if (!currentTest) return;
|
|
63
66
|
// To be sure that passed test will be passed in report
|
|
64
|
-
delete currentTest.err
|
|
65
|
-
currentTest.state = 'passed'
|
|
66
|
-
})
|
|
67
|
+
delete currentTest.err;
|
|
68
|
+
currentTest.state = 'passed';
|
|
69
|
+
});
|
|
67
70
|
|
|
68
71
|
event.dispatcher.on(event.step.started, (step) => {
|
|
69
|
-
step.startedAt = +new Date()
|
|
70
|
-
step.test = currentTest
|
|
72
|
+
step.startedAt = +new Date();
|
|
73
|
+
step.test = currentTest;
|
|
71
74
|
if (currentHook && Array.isArray(currentHook.steps)) {
|
|
72
|
-
return currentHook.steps.push(step)
|
|
75
|
+
return currentHook.steps.push(step);
|
|
73
76
|
}
|
|
74
|
-
if (!currentTest || !currentTest.steps) return
|
|
75
|
-
currentTest.steps.push(step)
|
|
76
|
-
})
|
|
77
|
+
if (!currentTest || !currentTest.steps) return;
|
|
78
|
+
currentTest.steps.push(step);
|
|
79
|
+
});
|
|
77
80
|
|
|
78
81
|
event.dispatcher.on(event.step.finished, (step) => {
|
|
79
|
-
step.finishedAt = +new Date()
|
|
80
|
-
if (step.startedAt) step.duration = step.finishedAt - step.startedAt
|
|
81
|
-
debug(`Step '${step}' finished; Duration: ${step.duration || 0}ms`)
|
|
82
|
-
})
|
|
82
|
+
step.finishedAt = +new Date();
|
|
83
|
+
if (step.startedAt) step.duration = step.finishedAt - step.startedAt;
|
|
84
|
+
debug(`Step '${step}' finished; Duration: ${step.duration || 0}ms`);
|
|
85
|
+
});
|
|
83
86
|
}
|
package/lib/listener/timeout.js
CHANGED
|
@@ -1,109 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let timeout
|
|
10
|
-
let suiteTimeout = []
|
|
11
|
-
let currentTest
|
|
12
|
-
let currentTimeout
|
|
1
|
+
import * as event from '../event.js';
|
|
2
|
+
import * as output from '../output.js';
|
|
3
|
+
import recorder from '../recorder.js';
|
|
4
|
+
import Config from '../config.js';
|
|
5
|
+
import { timeouts } from '../store.js';
|
|
6
|
+
import { Step } from '../step.js';
|
|
7
|
+
|
|
8
|
+
export default function () {
|
|
9
|
+
let timeout;
|
|
10
|
+
let suiteTimeout = [];
|
|
11
|
+
let currentTest;
|
|
12
|
+
let currentTimeout;
|
|
13
13
|
|
|
14
14
|
if (!timeouts) {
|
|
15
|
-
console.log('Timeouts were disabled')
|
|
16
|
-
return
|
|
15
|
+
console.log('Timeouts were disabled');
|
|
16
|
+
return;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
event.dispatcher.on(event.suite.before, (suite) => {
|
|
20
|
-
suiteTimeout = []
|
|
21
|
-
let timeoutConfig = Config.get('timeout')
|
|
20
|
+
suiteTimeout = [];
|
|
21
|
+
let timeoutConfig = Config.get('timeout');
|
|
22
22
|
|
|
23
23
|
if (timeoutConfig) {
|
|
24
24
|
if (!Number.isNaN(+timeoutConfig)) {
|
|
25
|
-
checkForSeconds(timeoutConfig)
|
|
26
|
-
suiteTimeout.push(timeoutConfig)
|
|
25
|
+
checkForSeconds(timeoutConfig);
|
|
26
|
+
suiteTimeout.push(timeoutConfig);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
if (!Array.isArray(timeoutConfig)) {
|
|
30
|
-
timeoutConfig = [timeoutConfig]
|
|
30
|
+
timeoutConfig = [timeoutConfig];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
for (const config of timeoutConfig.filter(
|
|
33
|
+
for (const config of timeoutConfig.filter(c => !!c.Feature)) {
|
|
34
34
|
if (config.grep) {
|
|
35
|
-
if (!suite.title.includes(config.grep)) continue
|
|
35
|
+
if (!suite.title.includes(config.grep)) continue;
|
|
36
36
|
}
|
|
37
|
-
suiteTimeout.push(config.Feature)
|
|
37
|
+
suiteTimeout.push(config.Feature);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if (suite.totalTimeout) suiteTimeout.push(suite.totalTimeout)
|
|
42
|
-
output.log(`Timeouts: ${suiteTimeout}`)
|
|
43
|
-
})
|
|
41
|
+
if (suite.totalTimeout) suiteTimeout.push(suite.totalTimeout);
|
|
42
|
+
output.output.log(`Timeouts: ${suiteTimeout}`);
|
|
43
|
+
});
|
|
44
44
|
|
|
45
45
|
event.dispatcher.on(event.test.before, (test) => {
|
|
46
|
-
currentTest = test
|
|
47
|
-
let testTimeout = null
|
|
46
|
+
currentTest = test;
|
|
47
|
+
let testTimeout = null;
|
|
48
48
|
|
|
49
|
-
let timeoutConfig = Config.get('timeout')
|
|
49
|
+
let timeoutConfig = Config.get('timeout');
|
|
50
50
|
|
|
51
51
|
if (typeof timeoutConfig === 'object' || Array.isArray(timeoutConfig)) {
|
|
52
52
|
if (!Array.isArray(timeoutConfig)) {
|
|
53
|
-
timeoutConfig = [timeoutConfig]
|
|
53
|
+
timeoutConfig = [timeoutConfig];
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
for (const config of timeoutConfig.filter(
|
|
57
|
-
console.log('Test Timeout', config, test.title.includes(config.grep))
|
|
56
|
+
for (const config of timeoutConfig.filter(c => !!c.Scenario)) {
|
|
57
|
+
console.log('Test Timeout', config, test.title.includes(config.grep));
|
|
58
58
|
if (config.grep) {
|
|
59
|
-
if (!test.title.includes(config.grep)) continue
|
|
59
|
+
if (!test.title.includes(config.grep)) continue;
|
|
60
60
|
}
|
|
61
|
-
testTimeout = config.Scenario
|
|
61
|
+
testTimeout = config.Scenario;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
timeout = test.totalTimeout || testTimeout || suiteTimeout[suiteTimeout.length - 1]
|
|
66
|
-
if (!timeout) return
|
|
67
|
-
currentTimeout = timeout
|
|
68
|
-
output.debug(`Test Timeout: ${timeout}s`)
|
|
69
|
-
timeout *= 1000
|
|
70
|
-
})
|
|
65
|
+
timeout = test.totalTimeout || testTimeout || suiteTimeout[suiteTimeout.length - 1];
|
|
66
|
+
if (!timeout) return;
|
|
67
|
+
currentTimeout = timeout;
|
|
68
|
+
output.output.debug(`Test Timeout: ${timeout}s`);
|
|
69
|
+
timeout *= 1000;
|
|
70
|
+
});
|
|
71
71
|
|
|
72
72
|
event.dispatcher.on(event.test.passed, (test) => {
|
|
73
|
-
currentTest = null
|
|
74
|
-
})
|
|
73
|
+
currentTest = null;
|
|
74
|
+
});
|
|
75
75
|
|
|
76
76
|
event.dispatcher.on(event.test.failed, (test) => {
|
|
77
|
-
currentTest = null
|
|
78
|
-
})
|
|
77
|
+
currentTest = null;
|
|
78
|
+
});
|
|
79
79
|
|
|
80
80
|
event.dispatcher.on(event.step.before, (step) => {
|
|
81
|
-
if (typeof timeout !== 'number') return
|
|
81
|
+
if (typeof timeout !== 'number') return;
|
|
82
82
|
|
|
83
83
|
if (timeout < 0) {
|
|
84
|
-
step.setTimeout(0.01, TIMEOUT_ORDER.testOrSuite)
|
|
84
|
+
step.setTimeout(0.01, Step.TIMEOUT_ORDER.testOrSuite);
|
|
85
85
|
} else {
|
|
86
|
-
step.setTimeout(timeout, TIMEOUT_ORDER.testOrSuite)
|
|
86
|
+
step.setTimeout(timeout, Step.TIMEOUT_ORDER.testOrSuite);
|
|
87
87
|
}
|
|
88
|
-
})
|
|
88
|
+
});
|
|
89
89
|
|
|
90
90
|
event.dispatcher.on(event.step.finished, (step) => {
|
|
91
|
-
if (typeof timeout === 'number' && !Number.isNaN(timeout)) timeout -= step.duration
|
|
91
|
+
if (typeof timeout === 'number' && !Number.isNaN(timeout)) timeout -= step.duration;
|
|
92
92
|
|
|
93
93
|
if (typeof timeout === 'number' && timeout <= 0 && recorder.isRunning()) {
|
|
94
94
|
if (currentTest && currentTest.callback) {
|
|
95
|
-
recorder.reset()
|
|
95
|
+
recorder.reset();
|
|
96
96
|
// replace mocha timeout with custom timeout
|
|
97
|
-
currentTest.timeout(0)
|
|
98
|
-
currentTest.callback(new Error(`Timeout ${currentTimeout}s exceeded (with Before hook)`))
|
|
99
|
-
currentTest.timedOut = true
|
|
97
|
+
currentTest.timeout(0);
|
|
98
|
+
currentTest.callback(new Error(`Timeout ${currentTimeout}s exceeded (with Before hook)`));
|
|
99
|
+
currentTest.timedOut = true;
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
-
})
|
|
102
|
+
});
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
function checkForSeconds(timeout) {
|
|
106
106
|
if (timeout >= 1000) {
|
|
107
|
-
console.log(`Warning: Timeout was set to ${timeout}secs.\nGlobal timeout should be specified in seconds.`)
|
|
107
|
+
console.log(`Warning: Timeout was set to ${timeout}secs.\nGlobal timeout should be specified in seconds.`);
|
|
108
108
|
}
|
|
109
109
|
}
|
package/lib/locator.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { sprintf } from 'sprintf-js';
|
|
2
|
+
|
|
3
|
+
import csstoxpath from 'csstoxpath';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
import css_to_xpath from 'css-to-xpath';
|
|
6
|
+
import { xpathLocator } from './utils.js';
|
|
7
|
+
|
|
8
|
+
let cssToXPath;
|
|
5
9
|
|
|
6
10
|
const locatorTypes = ['css', 'by', 'xpath', 'id', 'name', 'fuzzy', 'frame', 'shadow', 'pw'];
|
|
7
11
|
/** @class */
|
|
@@ -178,9 +182,9 @@ class Locator {
|
|
|
178
182
|
const limitation = [':nth-of-type', ':first-of-type', ':last-of-type', ':nth-last-child', ':nth-last-of-type', ':checked', ':disabled', ':enabled', ':required', ':lang', ':nth-child', ':has'];
|
|
179
183
|
|
|
180
184
|
if (limitation.some(item => locator.includes(item))) {
|
|
181
|
-
cssToXPath =
|
|
185
|
+
cssToXPath = css_to_xpath;
|
|
182
186
|
} else {
|
|
183
|
-
cssToXPath =
|
|
187
|
+
cssToXPath = csstoxpath;
|
|
184
188
|
}
|
|
185
189
|
|
|
186
190
|
if (this.isXPath()) return this.value;
|
|
@@ -522,7 +526,7 @@ Locator.select = {
|
|
|
522
526
|
},
|
|
523
527
|
};
|
|
524
528
|
|
|
525
|
-
|
|
529
|
+
export default Locator;
|
|
526
530
|
|
|
527
531
|
/**
|
|
528
532
|
* @private
|
package/lib/mochaFactory.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const ConnectionRefused = require('./helper/errors/ConnectionRefused');
|
|
1
|
+
import Mocha from 'mocha';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import reporter from './cli.js';
|
|
4
|
+
import gherkinParser from './interfaces/gherkin.js';
|
|
5
|
+
import * as output from './output.js';
|
|
6
|
+
import { genTestId } from './utils.js';
|
|
7
|
+
import ConnectionRefused from './helper/errors/ConnectionRefused.js';
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
import scenarioUi from './ui.js';
|
|
11
10
|
|
|
12
11
|
let mocha;
|
|
13
12
|
|
|
14
|
-
class MochaFactory {
|
|
13
|
+
export class MochaFactory {
|
|
15
14
|
static create(config, opts) {
|
|
16
15
|
mocha = new Mocha(Object.assign(config, opts));
|
|
17
|
-
output.process(opts.child);
|
|
16
|
+
output.output.process(opts.child);
|
|
18
17
|
mocha.ui(scenarioUi);
|
|
19
18
|
|
|
20
19
|
Mocha.Runner.prototype.uncaught = function (err) {
|
|
@@ -22,11 +21,11 @@ class MochaFactory {
|
|
|
22
21
|
if (err.toString().indexOf('ECONNREFUSED') >= 0) {
|
|
23
22
|
err = new ConnectionRefused(err);
|
|
24
23
|
}
|
|
25
|
-
output.error(err);
|
|
26
|
-
output.print(err.stack);
|
|
24
|
+
output.output.error(err);
|
|
25
|
+
output.output.print(err.stack);
|
|
27
26
|
process.exit(1);
|
|
28
27
|
}
|
|
29
|
-
output.error('Uncaught undefined exception');
|
|
28
|
+
output.output.error('Uncaught undefined exception');
|
|
30
29
|
process.exit(1);
|
|
31
30
|
};
|
|
32
31
|
|
|
@@ -61,12 +60,12 @@ class MochaFactory {
|
|
|
61
60
|
});
|
|
62
61
|
if (dupes.length) {
|
|
63
62
|
// ideally this should be no-op and throw (breaking change)...
|
|
64
|
-
output.error(`Duplicate test names detected - Feature + Scenario name should be unique:\n${dupes.join('\n')}`);
|
|
63
|
+
output.output.error(`Duplicate test names detected - Feature + Scenario name should be unique:\n${dupes.join('\n')}`);
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
if (missingFeatureInFile.length) {
|
|
68
67
|
missingFeatureInFile = [...new Set(missingFeatureInFile)];
|
|
69
|
-
output.error(`Missing Feature section in:\n${missingFeatureInFile.join('\n')}`);
|
|
68
|
+
output.output.error(`Missing Feature section in:\n${missingFeatureInFile.join('\n')}`);
|
|
70
69
|
}
|
|
71
70
|
}
|
|
72
71
|
};
|
|
@@ -109,5 +108,3 @@ class MochaFactory {
|
|
|
109
108
|
return mocha;
|
|
110
109
|
}
|
|
111
110
|
}
|
|
112
|
-
|
|
113
|
-
module.exports = MochaFactory;
|