codeceptjs 4.0.0-beta.1 → 4.0.0-beta.11.esm-aria
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/README.md +133 -120
- package/bin/codecept.js +107 -96
- package/bin/test-server.js +64 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +5 -1
- package/lib/actor.js +71 -103
- package/lib/ai.js +159 -188
- package/lib/assert/empty.js +22 -24
- package/lib/assert/equal.js +30 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +43 -48
- package/lib/assert/throws.js +11 -11
- package/lib/assert/truth.js +22 -22
- package/lib/assert.js +20 -18
- package/lib/codecept.js +238 -162
- package/lib/colorUtils.js +50 -52
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +56 -51
- package/lib/command/definitions.js +96 -109
- package/lib/command/dryRun.js +77 -79
- package/lib/command/generate.js +234 -194
- package/lib/command/gherkin/init.js +42 -33
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +20 -17
- package/lib/command/info.js +74 -38
- package/lib/command/init.js +300 -290
- package/lib/command/interactive.js +41 -32
- package/lib/command/list.js +28 -27
- package/lib/command/run-multiple/chunk.js +51 -48
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +5 -1
- package/lib/command/run-multiple.js +97 -97
- package/lib/command/run-rerun.js +19 -25
- package/lib/command/run-workers.js +68 -92
- package/lib/command/run.js +39 -27
- package/lib/command/utils.js +80 -64
- package/lib/command/workers/runTests.js +388 -226
- package/lib/config.js +124 -50
- package/lib/container.js +765 -260
- package/lib/data/context.js +60 -61
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +32 -32
- package/lib/data/table.js +22 -22
- package/lib/effects.js +307 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +160 -0
- package/lib/event.js +173 -163
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -85
- package/lib/helper/AI.js +131 -41
- package/lib/helper/ApiDataFactory.js +107 -75
- package/lib/helper/Appium.js +542 -404
- package/lib/helper/FileSystem.js +100 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +52 -52
- package/lib/helper/JSONResponse.js +126 -88
- package/lib/helper/Mochawesome.js +54 -29
- package/lib/helper/Playwright.js +2547 -1316
- package/lib/helper/Puppeteer.js +1578 -1181
- package/lib/helper/REST.js +209 -68
- package/lib/helper/WebDriver.js +1482 -1342
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
- package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +27 -28
- package/lib/helper/network/actions.js +36 -42
- package/lib/helper/network/utils.js +78 -84
- package/lib/helper/scripts/blurElement.js +5 -5
- package/lib/helper/scripts/focusElement.js +5 -5
- package/lib/helper/scripts/highlightElement.js +8 -8
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -3
- package/lib/history.js +23 -19
- package/lib/hooks.js +8 -8
- package/lib/html.js +94 -104
- package/lib/index.js +38 -27
- package/lib/listener/config.js +30 -23
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/enhancedGlobalRetry.js +110 -0
- package/lib/listener/exit.js +16 -18
- package/lib/listener/globalRetry.js +70 -0
- package/lib/listener/globalTimeout.js +181 -0
- package/lib/listener/helpers.js +76 -51
- package/lib/listener/mocha.js +10 -11
- package/lib/listener/result.js +11 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +71 -59
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +214 -197
- package/lib/mocha/asyncWrapper.js +274 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +163 -0
- package/lib/mocha/featureConfig.js +89 -0
- package/lib/mocha/gherkin.js +231 -0
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +184 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +242 -0
- package/lib/output.js +141 -71
- package/lib/parser.js +47 -44
- package/lib/pause.js +173 -145
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +178 -79
- package/lib/plugin/autoDelay.js +36 -40
- package/lib/plugin/coverage.js +131 -78
- package/lib/plugin/customLocator.js +22 -21
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/enhancedRetryFailedStep.js +99 -0
- package/lib/plugin/heal.js +101 -110
- package/lib/plugin/htmlReporter.js +3648 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +12 -11
- package/lib/plugin/retryFailedStep.js +82 -47
- package/lib/plugin/screenshotOnFail.js +111 -92
- package/lib/plugin/stepByStepReport.js +159 -101
- package/lib/plugin/stepTimeout.js +20 -25
- package/lib/plugin/subtitles.js +38 -38
- package/lib/recorder.js +193 -130
- package/lib/rerun.js +94 -49
- package/lib/result.js +238 -0
- package/lib/retryCoordinator.js +207 -0
- package/lib/secret.js +20 -18
- package/lib/session.js +95 -89
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +18 -329
- package/lib/steps.js +54 -0
- package/lib/store.js +38 -7
- package/lib/template/heal.js +3 -12
- package/lib/template/prompts/generatePageObject.js +31 -0
- package/lib/template/prompts/healStep.js +13 -0
- package/lib/template/prompts/writeStep.js +9 -0
- package/lib/test-server.js +334 -0
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +34 -21
- package/lib/utils/mask_data.js +47 -0
- package/lib/utils.js +411 -228
- package/lib/workerStorage.js +37 -34
- package/lib/workers.js +532 -296
- package/package.json +115 -95
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +22 -12
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +10 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +546 -185
- package/typings/promiseBasedTypes.d.ts +150 -879
- package/typings/types.d.ts +547 -996
- package/lib/cli.js +0 -249
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/ExpectHelper.js +0 -399
- package/lib/helper/MockServer.js +0 -223
- package/lib/helper/Nightmare.js +0 -1411
- package/lib/helper/Protractor.js +0 -1835
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1410
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -63
- package/lib/interfaces/bdd.js +0 -98
- package/lib/interfaces/featureConfig.js +0 -69
- package/lib/interfaces/gherkin.js +0 -195
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/retry.js +0 -68
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -110
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -121
- package/lib/plugin/selenoid.js +0 -371
- package/lib/plugin/standardActingHelpers.js +0 -9
- package/lib/plugin/tryTo.js +0 -105
- package/lib/plugin/wdio.js +0 -246
- package/lib/scenario.js +0 -222
- package/lib/ui.js +0 -238
- package/lib/within.js +0 -70
package/lib/plugin/wdio.js
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import debug from 'debug';
|
|
2
|
-
|
|
3
|
-
import container from '../container.js';
|
|
4
|
-
import mainConfig from '../config.js';
|
|
5
|
-
import recorder from '../recorder.js';
|
|
6
|
-
import * as event from '../event.js';
|
|
7
|
-
import * as output from '../output.js';
|
|
8
|
-
|
|
9
|
-
debug('codeceptjs:plugin:wdio');
|
|
10
|
-
|
|
11
|
-
const defaultConfig = {
|
|
12
|
-
services: [],
|
|
13
|
-
capabilities: {},
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
let restartsSession;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Webdriverio services runner.
|
|
20
|
-
*
|
|
21
|
-
* This plugin allows to run webdriverio services like:
|
|
22
|
-
*
|
|
23
|
-
* * selenium-standalone
|
|
24
|
-
* * sauce
|
|
25
|
-
* * testingbot
|
|
26
|
-
* * browserstack
|
|
27
|
-
* * appium
|
|
28
|
-
*
|
|
29
|
-
* A complete list of all available services can be found on [webdriverio website](https://webdriver.io).
|
|
30
|
-
*
|
|
31
|
-
* #### Setup
|
|
32
|
-
*
|
|
33
|
-
* 1. Install a webdriverio service
|
|
34
|
-
* 2. Enable `wdio` plugin in config
|
|
35
|
-
* 3. Add service name to `services` array inside wdio plugin config.
|
|
36
|
-
*
|
|
37
|
-
* See examples below:
|
|
38
|
-
*
|
|
39
|
-
* #### Selenium Standalone Service
|
|
40
|
-
*
|
|
41
|
-
* Install ` @wdio/selenium-standalone-service` package, as [described here](https://webdriver.io/docs/selenium-standalone-service.html).
|
|
42
|
-
* It is important to make sure it is compatible with current webdriverio version.
|
|
43
|
-
*
|
|
44
|
-
* Enable `wdio` plugin in plugins list and add `selenium-standalone` service:
|
|
45
|
-
*
|
|
46
|
-
* ```js
|
|
47
|
-
* plugins: {
|
|
48
|
-
* wdio: {
|
|
49
|
-
* enabled: true,
|
|
50
|
-
* services: ['selenium-standalone']
|
|
51
|
-
* // additional config for service can be passed here
|
|
52
|
-
* }
|
|
53
|
-
* }
|
|
54
|
-
* ```
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* #### Sauce Service
|
|
58
|
-
*
|
|
59
|
-
* Install `@wdio/sauce-service` package, as [described here](https://webdriver.io/docs/sauce-service.html).
|
|
60
|
-
* It is important to make sure it is compatible with current webdriverio version.
|
|
61
|
-
*
|
|
62
|
-
* Enable `wdio` plugin in plugins list and add `sauce` service:
|
|
63
|
-
*
|
|
64
|
-
* ```js
|
|
65
|
-
* plugins: {
|
|
66
|
-
* wdio: {
|
|
67
|
-
* enabled: true,
|
|
68
|
-
* services: ['sauce'],
|
|
69
|
-
* user: ... ,// saucelabs username
|
|
70
|
-
* key: ... // saucelabs api key
|
|
71
|
-
* // additional config, from sauce service
|
|
72
|
-
* }
|
|
73
|
-
* }
|
|
74
|
-
* ```
|
|
75
|
-
*
|
|
76
|
-
* ---
|
|
77
|
-
*
|
|
78
|
-
* In the same manner additional services from webdriverio can be installed, enabled, and configured.
|
|
79
|
-
*
|
|
80
|
-
* #### Configuration
|
|
81
|
-
*
|
|
82
|
-
* * `services` - list of enabled services
|
|
83
|
-
* * ... - additional configuration passed into services.
|
|
84
|
-
*
|
|
85
|
-
*/
|
|
86
|
-
export default (config) => {
|
|
87
|
-
// Keep initial configs to pass as options to wdio services
|
|
88
|
-
const wdioOptions = { ...config };
|
|
89
|
-
const webDriver = container.helpers('WebDriver');
|
|
90
|
-
if (webDriver) {
|
|
91
|
-
config = Object.assign(webDriver.options, config);
|
|
92
|
-
restartsSession = !!config.restart;
|
|
93
|
-
}
|
|
94
|
-
config = Object.assign(defaultConfig, config);
|
|
95
|
-
const seleniumInstallArgs = { ...config.seleniumInstallArgs };
|
|
96
|
-
const seleniumArgs = { ...config.seleniumArgs };
|
|
97
|
-
|
|
98
|
-
const services = [];
|
|
99
|
-
const launchers = [];
|
|
100
|
-
|
|
101
|
-
for (const name of config.services) {
|
|
102
|
-
const Service = safeRequire(`@wdio/${name.toLowerCase()}-service`);
|
|
103
|
-
if (Service) {
|
|
104
|
-
if (Service.launcher && typeof Service.launcher === 'function') {
|
|
105
|
-
const Launcher = Service.launcher;
|
|
106
|
-
|
|
107
|
-
const options = {
|
|
108
|
-
logPath: global.output_dir, installArgs: seleniumInstallArgs, args: seleniumArgs, ...wdioOptions,
|
|
109
|
-
};
|
|
110
|
-
launchers.push(new Launcher(options, [config.capabilities], config));
|
|
111
|
-
}
|
|
112
|
-
if (typeof Service === 'function') {
|
|
113
|
-
services.push(new Service(config, config.capabilities));
|
|
114
|
-
}
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
throw new Error(`Couldn't initialize service ${name} from wdio plugin config.\nIt should be available either in '@wdio/${name.toLowerCase()}-service' package`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
debug(`services ${services}, launchers ${launchers}`);
|
|
122
|
-
|
|
123
|
-
recorder.startUnlessRunning();
|
|
124
|
-
|
|
125
|
-
for (const launcher of launchers) {
|
|
126
|
-
registerLauncher(launcher);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
for (const service of services) {
|
|
130
|
-
registerService(service);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function registerService(service) {
|
|
134
|
-
const name = service.constructor.name;
|
|
135
|
-
if (service.beforeSession) {
|
|
136
|
-
event.dispatcher.on(event.all.before, () => {
|
|
137
|
-
recorder.add(`service ${name} all.before`, async () => {
|
|
138
|
-
await service.beforeSession(config, config.capabilities);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (service.afterSession) {
|
|
144
|
-
event.dispatcher.on(event.all.result, (result) => {
|
|
145
|
-
recorder.add(`service ${name} all.after`, async () => {
|
|
146
|
-
await service.afterSession(result);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (service.beforeSuite) {
|
|
152
|
-
event.dispatcher.on(event.suite.before, (suite) => {
|
|
153
|
-
debug(`suite started: ${suite.title}`);
|
|
154
|
-
recorder.add(`service ${name} suite.before`, () => service.beforeSuite(suite));
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (service.afterSuite) {
|
|
159
|
-
event.dispatcher.on(event.suite.after, (suite) => {
|
|
160
|
-
debug(`suite finished: ${suite.title}`);
|
|
161
|
-
recorder.add(`service ${name} suite.after`, () => service.afterSuite(suite));
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (service.beforeTest) {
|
|
166
|
-
event.dispatcher.on(event.test.started, async (test) => {
|
|
167
|
-
if (test.parent) {
|
|
168
|
-
test.parent.toString = () => test.parent.title;
|
|
169
|
-
}
|
|
170
|
-
// test.parent = test.parent ? test.parent.title : null;
|
|
171
|
-
debug(`test started: ${test.title}`);
|
|
172
|
-
if (webDriver) {
|
|
173
|
-
global.browser = webDriver.browser;
|
|
174
|
-
global.browser.config = Object.assign(mainConfig.get('test', 1), global.browser.config);
|
|
175
|
-
}
|
|
176
|
-
await service.beforeTest(test);
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (service.afterTest) {
|
|
181
|
-
event.dispatcher.on(event.test.finished, async (test) => {
|
|
182
|
-
debug(`test finished: ${test.title}`);
|
|
183
|
-
await service.afterTest(test);
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (restartsSession && service.before) {
|
|
188
|
-
event.dispatcher.on(event.test.started, () => service.before());
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (restartsSession && service.after) {
|
|
192
|
-
event.dispatcher.on(event.test.finished, () => service.after());
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (!restartsSession && service.before) {
|
|
196
|
-
let initializedBrowser = false;
|
|
197
|
-
event.dispatcher.on(event.test.started, async () => {
|
|
198
|
-
if (!initializedBrowser) {
|
|
199
|
-
await service.before();
|
|
200
|
-
initializedBrowser = true;
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (!restartsSession && service.after) {
|
|
206
|
-
event.dispatcher.on(event.all.result, result => service.after(result));
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function registerLauncher(launcher) {
|
|
211
|
-
const name = launcher.constructor.name;
|
|
212
|
-
if (launcher.onPrepare) {
|
|
213
|
-
event.dispatcher.on(event.all.before, () => {
|
|
214
|
-
recorder.add(`launcher ${name} start`, async () => {
|
|
215
|
-
// browserstack-service expects capabilities as array
|
|
216
|
-
if (launcher.constructor.name === 'BrowserstackLauncherService') {
|
|
217
|
-
await launcher.onPrepare(config, [config.capabilities]);
|
|
218
|
-
} else {
|
|
219
|
-
await launcher.onPrepare(config, config.capabilities);
|
|
220
|
-
}
|
|
221
|
-
output.debug(`Started ${name}`);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (launcher.onComplete) {
|
|
227
|
-
event.dispatcher.on(event.all.after, () => {
|
|
228
|
-
recorder.add(`launcher ${name} start`, async () => {
|
|
229
|
-
await launcher.onComplete(process.exitCode, config, config.capabilities);
|
|
230
|
-
output.debug(`Stopped ${name}`);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
function safeRequire(name) {
|
|
238
|
-
try {
|
|
239
|
-
return require(name);
|
|
240
|
-
} catch (e) {
|
|
241
|
-
if (!e.message.match(`Cannot find module '${name}'`)) {
|
|
242
|
-
throw new Error(`Couldn't initialise "${name}".\n${e.stack}`);
|
|
243
|
-
}
|
|
244
|
-
return null;
|
|
245
|
-
}
|
|
246
|
-
}
|
package/lib/scenario.js
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
import promiseRetry from 'promise-retry';
|
|
2
|
-
import * as event from './event.js';
|
|
3
|
-
import recorder from './recorder.js';
|
|
4
|
-
import assertThrown from './assert/throws.js';
|
|
5
|
-
import { ucfirst, isAsyncFunction } from './utils.js';
|
|
6
|
-
import * as parser from './parser.js';
|
|
7
|
-
import Container from './container.js';
|
|
8
|
-
|
|
9
|
-
const injectHook = function (inject, suite) {
|
|
10
|
-
try {
|
|
11
|
-
inject();
|
|
12
|
-
} catch (err) {
|
|
13
|
-
recorder.throw(err);
|
|
14
|
-
}
|
|
15
|
-
recorder.catch((err) => {
|
|
16
|
-
event.emit(event.test.failed, suite, err);
|
|
17
|
-
throw err;
|
|
18
|
-
});
|
|
19
|
-
return recorder.promise();
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function makeDoneCallableOnce(done) {
|
|
23
|
-
let called = false;
|
|
24
|
-
return function (err) {
|
|
25
|
-
if (called) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
called = true;
|
|
29
|
-
return done(err);
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Wraps test function, injects support objects from container,
|
|
34
|
-
* starts promise chain with recorder, performs before/after hooks
|
|
35
|
-
* through event system.
|
|
36
|
-
*/
|
|
37
|
-
export function test(test) {
|
|
38
|
-
const testFn = test.fn;
|
|
39
|
-
if (!testFn) {
|
|
40
|
-
return test;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
test.steps = [];
|
|
44
|
-
test.timeout(0);
|
|
45
|
-
test.async = true;
|
|
46
|
-
|
|
47
|
-
test.fn = function (done) {
|
|
48
|
-
const doneFn = makeDoneCallableOnce(done);
|
|
49
|
-
recorder.errHandler((err) => {
|
|
50
|
-
recorder.session.start('teardown');
|
|
51
|
-
recorder.cleanAsyncErr();
|
|
52
|
-
if (test.throws) {
|
|
53
|
-
// check that test should actually fail
|
|
54
|
-
try {
|
|
55
|
-
assertThrown(err, test.throws);
|
|
56
|
-
event.emit(event.test.passed, test);
|
|
57
|
-
event.emit(event.test.finished, test);
|
|
58
|
-
recorder.add(doneFn);
|
|
59
|
-
return;
|
|
60
|
-
} catch (newErr) {
|
|
61
|
-
err = newErr;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
event.emit(event.test.failed, test, err);
|
|
65
|
-
event.emit(event.test.finished, test);
|
|
66
|
-
recorder.add(() => doneFn(err));
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
if (isAsyncFunction(testFn)) {
|
|
70
|
-
event.emit(event.test.started, test);
|
|
71
|
-
testFn
|
|
72
|
-
.call(test, getInjectedArguments(testFn, test))
|
|
73
|
-
.then(() => {
|
|
74
|
-
recorder.add('fire test.passed', () => {
|
|
75
|
-
event.emit(event.test.passed, test);
|
|
76
|
-
event.emit(event.test.finished, test);
|
|
77
|
-
});
|
|
78
|
-
recorder.add('finish test', doneFn);
|
|
79
|
-
})
|
|
80
|
-
.catch((err) => {
|
|
81
|
-
recorder.throw(err);
|
|
82
|
-
})
|
|
83
|
-
.finally(() => {
|
|
84
|
-
recorder.catch();
|
|
85
|
-
});
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
event.emit(event.test.started, test);
|
|
91
|
-
testFn.call(test, getInjectedArguments(testFn, test));
|
|
92
|
-
} catch (err) {
|
|
93
|
-
recorder.throw(err);
|
|
94
|
-
} finally {
|
|
95
|
-
recorder.add('fire test.passed', () => {
|
|
96
|
-
event.emit(event.test.passed, test);
|
|
97
|
-
event.emit(event.test.finished, test);
|
|
98
|
-
});
|
|
99
|
-
recorder.add('finish test', doneFn);
|
|
100
|
-
recorder.catch();
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
return test;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Injects arguments to function from controller
|
|
108
|
-
*/
|
|
109
|
-
export function injected(fn, suite, hookName) {
|
|
110
|
-
return function (done) {
|
|
111
|
-
const doneFn = makeDoneCallableOnce(done);
|
|
112
|
-
const errHandler = (err) => {
|
|
113
|
-
recorder.session.start('teardown');
|
|
114
|
-
recorder.cleanAsyncErr();
|
|
115
|
-
event.emit(event.test.failed, suite, err);
|
|
116
|
-
if (hookName === 'after') event.emit(event.test.after, suite);
|
|
117
|
-
if (hookName === 'afterSuite') event.emit(event.suite.after, suite);
|
|
118
|
-
recorder.add(() => doneFn(err));
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
recorder.errHandler((err) => {
|
|
122
|
-
errHandler(err);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
if (!fn) throw new Error('fn is not defined');
|
|
126
|
-
|
|
127
|
-
event.emit(event.hook.started, suite);
|
|
128
|
-
|
|
129
|
-
this.test.body = fn.toString();
|
|
130
|
-
|
|
131
|
-
if (!recorder.isRunning()) {
|
|
132
|
-
recorder.errHandler((err) => {
|
|
133
|
-
errHandler(err);
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const opts = suite.opts || {};
|
|
138
|
-
const retries = opts[`retry${ucfirst(hookName)}`] || 0;
|
|
139
|
-
|
|
140
|
-
promiseRetry(
|
|
141
|
-
async (retry, number) => {
|
|
142
|
-
try {
|
|
143
|
-
recorder.startUnlessRunning();
|
|
144
|
-
await fn.call(this, getInjectedArguments(fn));
|
|
145
|
-
await recorder.promise().catch((err) => retry(err));
|
|
146
|
-
} catch (err) {
|
|
147
|
-
retry(err);
|
|
148
|
-
} finally {
|
|
149
|
-
if (number < retries) {
|
|
150
|
-
recorder.stop();
|
|
151
|
-
recorder.start();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
{ retries },
|
|
156
|
-
)
|
|
157
|
-
.then(() => {
|
|
158
|
-
recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite));
|
|
159
|
-
recorder.add(`finish ${hookName} hook`, doneFn);
|
|
160
|
-
recorder.catch();
|
|
161
|
-
})
|
|
162
|
-
.catch((e) => {
|
|
163
|
-
recorder.throw(e);
|
|
164
|
-
recorder.catch((e) => {
|
|
165
|
-
const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr();
|
|
166
|
-
errHandler(err);
|
|
167
|
-
});
|
|
168
|
-
recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e));
|
|
169
|
-
});
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Starts promise chain, so helpers could enqueue their hooks
|
|
175
|
-
*/
|
|
176
|
-
export function setup(suite) {
|
|
177
|
-
return injectHook(() => {
|
|
178
|
-
recorder.startUnlessRunning();
|
|
179
|
-
event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest);
|
|
180
|
-
}, suite);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export function teardown(suite) {
|
|
184
|
-
return injectHook(() => {
|
|
185
|
-
recorder.startUnlessRunning();
|
|
186
|
-
event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest);
|
|
187
|
-
}, suite);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export function suiteSetup(suite) {
|
|
191
|
-
return injectHook(() => {
|
|
192
|
-
recorder.startUnlessRunning();
|
|
193
|
-
event.emit(event.suite.before, suite);
|
|
194
|
-
}, suite);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export function suiteTeardown(suite) {
|
|
198
|
-
return injectHook(() => {
|
|
199
|
-
recorder.startUnlessRunning();
|
|
200
|
-
event.emit(event.suite.after, suite);
|
|
201
|
-
}, suite);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export function getInjectedArguments(fn, test) {
|
|
205
|
-
const testArgs = {};
|
|
206
|
-
const params = parser.getParams(fn) || [];
|
|
207
|
-
const objects = Container.support();
|
|
208
|
-
for (const key of params) {
|
|
209
|
-
testArgs[key] = {};
|
|
210
|
-
if (test && test.inject && test.inject[key]) {
|
|
211
|
-
// @FIX: need fix got inject
|
|
212
|
-
testArgs[key] = test.inject[key];
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
if (!objects[key]) {
|
|
216
|
-
throw new Error(`Object of type ${key} is not defined in container`);
|
|
217
|
-
}
|
|
218
|
-
testArgs[key] = Container.support(key);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return testArgs;
|
|
222
|
-
}
|
package/lib/ui.js
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import escapeRe from 'escape-string-regexp';
|
|
2
|
-
import Suite from 'mocha/lib/suite.js';
|
|
3
|
-
import Test from 'mocha/lib/test.js';
|
|
4
|
-
import mocha0 from 'mocha/lib/interfaces/common.js';
|
|
5
|
-
import * as scenario from './scenario.js';
|
|
6
|
-
import ScenarioConfig from './interfaces/scenarioConfig.js';
|
|
7
|
-
import FeatureConfig from './interfaces/featureConfig.js';
|
|
8
|
-
import addDataContext from './data/context.js';
|
|
9
|
-
import container from './container.js';
|
|
10
|
-
|
|
11
|
-
const setContextTranslation = (context) => {
|
|
12
|
-
const contexts = container.translation().value('contexts');
|
|
13
|
-
|
|
14
|
-
if (contexts) {
|
|
15
|
-
for (const key of Object.keys(contexts)) {
|
|
16
|
-
if (context[key]) {
|
|
17
|
-
context[contexts[key]] = context[key];
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Codecept-style interface:
|
|
25
|
-
*
|
|
26
|
-
* Feature('login');
|
|
27
|
-
*
|
|
28
|
-
* Scenario('login as regular user', ({I}) {
|
|
29
|
-
* I.fillField();
|
|
30
|
-
* I.click();
|
|
31
|
-
* I.see('Hello, '+data.login);
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* @param {Mocha.Suite} suite Root suite.
|
|
35
|
-
* @ignore
|
|
36
|
-
*/
|
|
37
|
-
export function suite(suite) {
|
|
38
|
-
const suites = [suite];
|
|
39
|
-
suite.timeout(0);
|
|
40
|
-
let afterAllHooks;
|
|
41
|
-
let afterEachHooks;
|
|
42
|
-
let afterAllHooksAreLoaded;
|
|
43
|
-
let afterEachHooksAreLoaded;
|
|
44
|
-
|
|
45
|
-
suite.on('pre-require', (context, file, mocha) => {
|
|
46
|
-
const common = mocha0(suites, context, mocha);
|
|
47
|
-
|
|
48
|
-
const addScenario = function (title, opts = {}, fn) {
|
|
49
|
-
const suite = suites[0];
|
|
50
|
-
|
|
51
|
-
if (typeof opts === 'function' && !fn) {
|
|
52
|
-
fn = opts;
|
|
53
|
-
opts = {};
|
|
54
|
-
}
|
|
55
|
-
if (suite.pending) {
|
|
56
|
-
fn = null;
|
|
57
|
-
}
|
|
58
|
-
const test = new Test(title, fn);
|
|
59
|
-
test.fullTitle = () => `${suite.title}: ${test.title}`;
|
|
60
|
-
|
|
61
|
-
test.tags = (suite.tags || []).concat(title.match(/(\@[a-zA-Z0-9-_]+)/g) || []); // match tags from title
|
|
62
|
-
test.file = file;
|
|
63
|
-
if (!test.inject) {
|
|
64
|
-
test.inject = {};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
suite.addTest(scenario.test(test));
|
|
68
|
-
if (opts.retries) test.retries(opts.retries);
|
|
69
|
-
if (opts.timeout) test.totalTimeout = opts.timeout;
|
|
70
|
-
test.opts = opts;
|
|
71
|
-
|
|
72
|
-
return new ScenarioConfig(test);
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// create dispatcher
|
|
76
|
-
|
|
77
|
-
context.BeforeAll = common.before;
|
|
78
|
-
context.AfterAll = common.after;
|
|
79
|
-
|
|
80
|
-
context.run = mocha.options.delay && common.runWithSuite(suite);
|
|
81
|
-
/**
|
|
82
|
-
* Describe a "suite" with the given `title`
|
|
83
|
-
* and callback `fn` containing nested suites
|
|
84
|
-
* and/or tests.
|
|
85
|
-
* @global
|
|
86
|
-
* @param {string} title
|
|
87
|
-
* @param {Object<string, *>} [opts]
|
|
88
|
-
* @returns {FeatureConfig}
|
|
89
|
-
*/
|
|
90
|
-
|
|
91
|
-
context.Feature = function (title, opts) {
|
|
92
|
-
if (suites.length > 1) {
|
|
93
|
-
suites.shift();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
afterAllHooks = [];
|
|
97
|
-
afterEachHooks = [];
|
|
98
|
-
afterAllHooksAreLoaded = false;
|
|
99
|
-
afterEachHooksAreLoaded = false;
|
|
100
|
-
|
|
101
|
-
const suite = Suite.create(suites[0], title);
|
|
102
|
-
if (!opts) opts = {};
|
|
103
|
-
suite.opts = opts;
|
|
104
|
-
suite.timeout(0);
|
|
105
|
-
|
|
106
|
-
if (opts.retries) suite.retries(opts.retries);
|
|
107
|
-
if (opts.timeout) suite.totalTimeout = opts.timeout;
|
|
108
|
-
|
|
109
|
-
suite.tags = title.match(/(\@[a-zA-Z0-9-_]+)/g) || []; // match tags from title
|
|
110
|
-
suite.file = file;
|
|
111
|
-
suite.fullTitle = () => `${suite.title}:`;
|
|
112
|
-
suites.unshift(suite);
|
|
113
|
-
suite.beforeEach('codeceptjs.before', () => scenario.setup(suite));
|
|
114
|
-
afterEachHooks.push(['finalize codeceptjs', () => scenario.teardown(suite)]);
|
|
115
|
-
|
|
116
|
-
suite.beforeAll('codeceptjs.beforeSuite', () => scenario.suiteSetup(suite));
|
|
117
|
-
afterAllHooks.push(['codeceptjs.afterSuite', () => scenario.suiteTeardown(suite)]);
|
|
118
|
-
|
|
119
|
-
if (opts.skipInfo && opts.skipInfo.skipped) {
|
|
120
|
-
suite.pending = true;
|
|
121
|
-
suite.opts = { ...suite.opts, skipInfo: opts.skipInfo };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return new FeatureConfig(suite);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Pending test suite.
|
|
129
|
-
* @global
|
|
130
|
-
* @kind constant
|
|
131
|
-
* @type {CodeceptJS.IFeature}
|
|
132
|
-
*/
|
|
133
|
-
context.xFeature = context.Feature.skip = function (title, opts) {
|
|
134
|
-
const skipInfo = {
|
|
135
|
-
skipped: true,
|
|
136
|
-
message: 'Skipped due to "skip" on Feature.',
|
|
137
|
-
};
|
|
138
|
-
return context.Feature(title, { ...opts, skipInfo });
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
context.BeforeSuite = function (fn) {
|
|
142
|
-
suites[0].beforeAll('BeforeSuite', scenario.injected(fn, suites[0], 'beforeSuite'));
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
context.AfterSuite = function (fn) {
|
|
146
|
-
afterAllHooks.unshift(['AfterSuite', scenario.injected(fn, suites[0], 'afterSuite')]);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
context.Background = context.Before = function (fn) {
|
|
150
|
-
suites[0].beforeEach('Before', scenario.injected(fn, suites[0], 'before'));
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
context.After = function (fn) {
|
|
154
|
-
afterEachHooks.unshift(['After', scenario.injected(fn, suites[0], 'after')]);
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Describe a specification or test-case
|
|
159
|
-
* with the given `title` and callback `fn`
|
|
160
|
-
* acting as a thunk.
|
|
161
|
-
* @ignore
|
|
162
|
-
*/
|
|
163
|
-
context.Scenario = addScenario;
|
|
164
|
-
/**
|
|
165
|
-
* Exclusive test-case.
|
|
166
|
-
* @ignore
|
|
167
|
-
*/
|
|
168
|
-
context.Scenario.only = function (title, opts, fn) {
|
|
169
|
-
const reString = `^${escapeRe(`${suites[0].title}: ${title}`.replace(/( \| {.+})?$/g, ''))}`;
|
|
170
|
-
mocha.grep(new RegExp(reString));
|
|
171
|
-
process.env.SCENARIO_ONLY = true;
|
|
172
|
-
return addScenario(title, opts, fn);
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Pending test case.
|
|
177
|
-
* @global
|
|
178
|
-
* @kind constant
|
|
179
|
-
* @type {CodeceptJS.IScenario}
|
|
180
|
-
*/
|
|
181
|
-
context.xScenario = context.Scenario.skip = function (title, opts = {}, fn) {
|
|
182
|
-
if (typeof opts === 'function' && !fn) {
|
|
183
|
-
opts = {};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return context.Scenario(title, opts);
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Pending test case with message: 'Test not implemented!'.
|
|
191
|
-
* @global
|
|
192
|
-
* @kind constant
|
|
193
|
-
* @type {CodeceptJS.IScenario}
|
|
194
|
-
*/
|
|
195
|
-
context.Scenario.todo = function (title, opts = {}, fn) {
|
|
196
|
-
if (typeof opts === 'function' && !fn) {
|
|
197
|
-
fn = opts;
|
|
198
|
-
opts = {};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const skipInfo = {
|
|
202
|
-
message: 'Test not implemented!',
|
|
203
|
-
description: fn ? fn.toString() : '',
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
return context.Scenario(title, { ...opts, skipInfo });
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* For translation
|
|
211
|
-
*/
|
|
212
|
-
|
|
213
|
-
setContextTranslation(context);
|
|
214
|
-
|
|
215
|
-
addDataContext(context);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
suite.on('post-require', () => {
|
|
219
|
-
/**
|
|
220
|
-
* load hooks from arrays to suite to prevent reordering
|
|
221
|
-
*/
|
|
222
|
-
if (!afterEachHooksAreLoaded && Array.isArray(afterEachHooks)) {
|
|
223
|
-
afterEachHooks.forEach((hook) => {
|
|
224
|
-
suites[0].afterEach(hook[0], hook[1]);
|
|
225
|
-
});
|
|
226
|
-
afterEachHooksAreLoaded = true;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (!afterAllHooksAreLoaded && Array.isArray(afterAllHooks)) {
|
|
230
|
-
afterAllHooks.forEach((hook) => {
|
|
231
|
-
suites[0].afterAll(hook[0], hook[1]);
|
|
232
|
-
});
|
|
233
|
-
afterAllHooksAreLoaded = true;
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export default suite;
|