codeceptjs 4.0.0-beta.1 → 4.0.0-beta.3
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 +84 -81
- package/lib/actor.js +13 -13
- package/lib/ai.js +10 -13
- package/lib/assert/empty.js +20 -21
- package/lib/assert/equal.js +37 -39
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +46 -47
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +19 -22
- package/lib/assert.js +4 -2
- package/lib/cli.js +57 -49
- package/lib/codecept.js +142 -155
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +58 -52
- package/lib/command/definitions.js +88 -89
- package/lib/command/dryRun.js +71 -68
- package/lib/command/generate.js +197 -188
- package/lib/command/gherkin/init.js +27 -16
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +40 -38
- package/lib/command/init.js +290 -288
- 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 +6 -2
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +20 -25
- package/lib/command/run-workers.js +64 -66
- package/lib/command/run.js +26 -29
- package/lib/command/utils.js +80 -65
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +10 -9
- package/lib/container.js +40 -48
- package/lib/data/context.js +60 -59
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/event.js +163 -167
- package/lib/heal.js +13 -17
- package/lib/helper/AI.js +130 -41
- package/lib/helper/ApiDataFactory.js +73 -69
- package/lib/helper/Appium.js +413 -382
- package/lib/helper/ExpectHelper.js +40 -48
- package/lib/helper/FileSystem.js +80 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +65 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -14
- package/lib/helper/Nightmare.js +662 -566
- package/lib/helper/Playwright.js +1361 -1216
- package/lib/helper/Protractor.js +663 -627
- package/lib/helper/Puppeteer.js +1231 -1128
- package/lib/helper/REST.js +159 -68
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +490 -484
- package/lib/helper/WebDriver.js +1297 -1156
- 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 +21 -18
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +14 -7
- package/lib/helper/network/utils.js +3 -2
- 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 +6 -7
- package/lib/helper.js +1 -3
- package/lib/history.js +6 -5
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +25 -41
- package/lib/interfaces/bdd.js +47 -64
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +124 -118
- 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 +32 -30
- package/lib/listener/steps.js +50 -53
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +6 -10
- package/lib/mochaFactory.js +18 -15
- package/lib/output.js +6 -10
- package/lib/parser.js +15 -12
- package/lib/pause.js +40 -33
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +29 -37
- package/lib/plugin/autoLogin.js +70 -65
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +115 -67
- package/lib/plugin/customLocator.js +21 -20
- 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 +67 -108
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +32 -39
- package/lib/plugin/retryTo.js +46 -40
- package/lib/plugin/screenshotOnFail.js +109 -87
- package/lib/plugin/selenoid.js +131 -118
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +110 -91
- package/lib/plugin/stepTimeout.js +24 -23
- package/lib/plugin/subtitles.js +34 -35
- package/lib/plugin/tryTo.js +40 -30
- package/lib/plugin/wdio.js +78 -75
- package/lib/recorder.js +14 -17
- package/lib/rerun.js +11 -10
- package/lib/scenario.js +25 -23
- package/lib/secret.js +4 -2
- package/lib/session.js +10 -10
- package/lib/step.js +12 -9
- package/lib/store.js +2 -3
- package/lib/transform.js +1 -1
- package/lib/translation.js +7 -8
- package/lib/ui.js +12 -14
- package/lib/utils.js +70 -72
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +27 -25
- package/lib/workers.js +29 -32
- package/package.json +56 -57
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -13
- 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 +415 -65
- package/typings/promiseBasedTypes.d.ts +32 -0
- package/typings/types.d.ts +32 -0
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
package/lib/output.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const colors = require('chalk');
|
|
2
|
+
const figures = require('figures');
|
|
3
3
|
|
|
4
4
|
const styles = {
|
|
5
5
|
error: colors.bgRed.white.bold,
|
|
@@ -19,7 +19,7 @@ let newline = true;
|
|
|
19
19
|
* @alias output
|
|
20
20
|
* @namespace
|
|
21
21
|
*/
|
|
22
|
-
|
|
22
|
+
module.exports = {
|
|
23
23
|
colors,
|
|
24
24
|
styles,
|
|
25
25
|
print,
|
|
@@ -62,10 +62,6 @@ export const output = {
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
|
|
65
|
-
debugSection(section, msg) {
|
|
66
|
-
this.debug(`[${section}] ${msg}`);
|
|
67
|
-
},
|
|
68
|
-
|
|
69
65
|
/**
|
|
70
66
|
* Print information in --verbose mode
|
|
71
67
|
* @param {string} msg
|
|
@@ -117,7 +113,7 @@ export const output = {
|
|
|
117
113
|
|
|
118
114
|
let stepLine = step.toString();
|
|
119
115
|
if (step.metaStep && outputLevel >= 1) {
|
|
120
|
-
this.stepShift += 2;
|
|
116
|
+
// this.stepShift += 2;
|
|
121
117
|
stepLine = colors.green(truncate(stepLine, this.spaceShift));
|
|
122
118
|
}
|
|
123
119
|
if (step.comment) {
|
|
@@ -171,7 +167,7 @@ export const output = {
|
|
|
171
167
|
scenario: {
|
|
172
168
|
/**
|
|
173
169
|
* @param {Mocha.Test} test
|
|
174
|
-
|
|
170
|
+
*/
|
|
175
171
|
/* eslint-disable */
|
|
176
172
|
started(test) {},
|
|
177
173
|
/* eslint-enable */
|
|
@@ -236,7 +232,7 @@ export const output = {
|
|
|
236
232
|
},
|
|
237
233
|
};
|
|
238
234
|
|
|
239
|
-
|
|
235
|
+
function print(...msg) {
|
|
240
236
|
if (outputProcess) {
|
|
241
237
|
msg.unshift(outputProcess);
|
|
242
238
|
}
|
package/lib/parser.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
function _interopDefault(ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex.default : ex; }
|
|
2
|
+
const acorn = require('acorn');
|
|
3
|
+
const parser = _interopDefault(require('parse-function'))({ parse: acorn.parse, ecmaVersion: 11, plugins: ['objectRestSpread'] });
|
|
4
|
+
const { error } = require('./output');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
parser.use(destructuredArgs);
|
|
7
|
+
|
|
8
|
+
module.exports.getParamsToString = function (fn) {
|
|
8
9
|
const newFn = fn.toString().replace(/^async/, 'async function');
|
|
9
10
|
return getParams(newFn).join(', ');
|
|
10
|
-
}
|
|
11
|
+
};
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
function getParams(fn) {
|
|
13
14
|
if (fn.isSinonProxy) return [];
|
|
14
15
|
try {
|
|
15
|
-
const reflected =
|
|
16
|
+
const reflected = parser.parse(fn);
|
|
16
17
|
if (reflected.args.length > 1 || reflected.args[0] === 'I') {
|
|
17
|
-
|
|
18
|
+
error('Error: old CodeceptJS v2 format detected. Upgrade your project to the new format -> https://bit.ly/codecept3Up');
|
|
18
19
|
}
|
|
19
20
|
if (reflected.destructuredArgs.length > 0) reflected.args = [...reflected.destructuredArgs];
|
|
20
21
|
const params = reflected.args.map((p) => {
|
|
@@ -27,11 +28,13 @@ export function getParams(fn) {
|
|
|
27
28
|
return params;
|
|
28
29
|
} catch (err) {
|
|
29
30
|
console.log(`Error in ${fn.toString()}`);
|
|
30
|
-
|
|
31
|
+
error(err);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
module.exports.getParams = getParams;
|
|
36
|
+
|
|
37
|
+
function destructuredArgs() {
|
|
35
38
|
return (node, result) => {
|
|
36
39
|
result.destructuredArgs = result.destructuredArgs || [];
|
|
37
40
|
|
package/lib/pause.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
debug('codeceptjs:pause');
|
|
1
|
+
const colors = require('chalk');
|
|
2
|
+
const readline = require('readline');
|
|
3
|
+
const ora = require('ora-classic');
|
|
4
|
+
const debug = require('debug')('codeceptjs:pause');
|
|
5
|
+
|
|
6
|
+
const container = require('./container');
|
|
7
|
+
const history = require('./history');
|
|
8
|
+
const store = require('./store');
|
|
9
|
+
const aiAssistant = require('./ai');
|
|
10
|
+
const recorder = require('./recorder');
|
|
11
|
+
const event = require('./event');
|
|
12
|
+
const output = require('./output');
|
|
13
|
+
const { methodsOfObject } = require('./utils');
|
|
16
14
|
|
|
17
15
|
// npm install colors
|
|
18
16
|
let rl;
|
|
@@ -20,7 +18,6 @@ let nextStep;
|
|
|
20
18
|
let finish;
|
|
21
19
|
let next;
|
|
22
20
|
let registeredVariables = {};
|
|
23
|
-
let aiAssistant;
|
|
24
21
|
/**
|
|
25
22
|
* Pauses test execution and starts interactive shell
|
|
26
23
|
* @param {Object<string, *>} [passedObject]
|
|
@@ -46,8 +43,6 @@ function pauseSession(passedObject = {}) {
|
|
|
46
43
|
let vars = Object.keys(registeredVariables).join(', ');
|
|
47
44
|
if (vars) vars = `(vars: ${vars})`;
|
|
48
45
|
|
|
49
|
-
aiAssistant = AiAssistant.getInstance();
|
|
50
|
-
|
|
51
46
|
output.print(colors.yellow(' Interactive shell started'));
|
|
52
47
|
output.print(colors.yellow(' Use JavaScript syntax to try steps in action'));
|
|
53
48
|
output.print(colors.yellow(` - Press ${colors.bold('ENTER')} to run the next step`));
|
|
@@ -56,14 +51,20 @@ function pauseSession(passedObject = {}) {
|
|
|
56
51
|
output.print(colors.yellow(` - Prefix ${colors.bold('=>')} to run js commands ${colors.bold(vars)}`));
|
|
57
52
|
|
|
58
53
|
if (aiAssistant.isEnabled) {
|
|
59
|
-
output.print(colors.blue(` ${colors.bold('
|
|
60
|
-
output.print(colors.blue(' Please note, only HTML fragments with interactive elements are sent to
|
|
54
|
+
output.print(colors.blue(` ${colors.bold('AI is enabled! (experimental)')} Write what you want and make AI run it`));
|
|
55
|
+
output.print(colors.blue(' Please note, only HTML fragments with interactive elements are sent to AI provider'));
|
|
61
56
|
output.print(colors.blue(' Ideas: ask it to fill forms for you or to click'));
|
|
62
|
-
} else {
|
|
63
|
-
output.print(colors.blue(` Enable OpenAI assistant by setting ${colors.bold('OPENAI_API_KEY')} env variable`));
|
|
64
57
|
}
|
|
65
58
|
}
|
|
66
|
-
|
|
59
|
+
|
|
60
|
+
rl = readline.createInterface({
|
|
61
|
+
input: process.stdin,
|
|
62
|
+
output: process.stdout,
|
|
63
|
+
terminal: true,
|
|
64
|
+
completer,
|
|
65
|
+
history: history.load(),
|
|
66
|
+
historySize: 50, // Adjust the history size as needed
|
|
67
|
+
});
|
|
67
68
|
|
|
68
69
|
rl.on('line', parseInput);
|
|
69
70
|
rl.on('close', () => {
|
|
@@ -112,7 +113,7 @@ async function parseInput(cmd) {
|
|
|
112
113
|
if (cmd.trim().startsWith('=>')) {
|
|
113
114
|
isCustomCommand = true;
|
|
114
115
|
cmd = cmd.trim().substring(2, cmd.length);
|
|
115
|
-
} else if (aiAssistant.isEnabled && !cmd.match(/^\w+\(/) && cmd.includes(' ')) {
|
|
116
|
+
} else if (aiAssistant.isEnabled && cmd.trim() && !cmd.match(/^\w+\(/) && cmd.includes(' ')) {
|
|
116
117
|
const currentOutputLevel = output.level();
|
|
117
118
|
output.level(0);
|
|
118
119
|
const res = I.grabSource();
|
|
@@ -122,13 +123,13 @@ async function parseInput(cmd) {
|
|
|
122
123
|
const html = await res;
|
|
123
124
|
await aiAssistant.setHtmlContext(html);
|
|
124
125
|
} catch (err) {
|
|
125
|
-
output.print(output.
|
|
126
|
+
output.print(output.styles.error(' ERROR '), 'Can\'t get HTML context', err.stack);
|
|
126
127
|
return;
|
|
127
128
|
} finally {
|
|
128
129
|
output.level(currentOutputLevel);
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
-
const spinner = ora("Processing
|
|
131
|
+
|
|
132
|
+
const spinner = ora("Processing AI request...").start();
|
|
132
133
|
cmd = await aiAssistant.writeSteps(cmd);
|
|
133
134
|
spinner.stop();
|
|
134
135
|
output.print('');
|
|
@@ -146,7 +147,7 @@ async function parseInput(cmd) {
|
|
|
146
147
|
}).catch((err) => {
|
|
147
148
|
debug(err);
|
|
148
149
|
if (isAiCommand) return;
|
|
149
|
-
if (!lastError) output.print(output.
|
|
150
|
+
if (!lastError) output.print(output.styles.error(' ERROR '), err.message);
|
|
150
151
|
debug(err.stack)
|
|
151
152
|
|
|
152
153
|
lastError = err.message;
|
|
@@ -160,15 +161,15 @@ async function parseInput(cmd) {
|
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
if (cmd?.startsWith('I.see') || cmd?.startsWith('I.dontSee')) {
|
|
163
|
-
output.print(output.
|
|
164
|
+
output.print(output.styles.success(' OK '), cmd);
|
|
164
165
|
}
|
|
165
166
|
if (cmd?.startsWith('I.grab')) {
|
|
166
|
-
output.print(output.
|
|
167
|
+
output.print(output.styles.debug(val));
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
history.push(cmd); // add command to history when successful
|
|
170
171
|
} catch (err) {
|
|
171
|
-
if (!lastError) output.print(output.
|
|
172
|
+
if (!lastError) output.print(output.styles.error(' ERROR '), err.message);
|
|
172
173
|
lastError = err.message;
|
|
173
174
|
}
|
|
174
175
|
recorder.session.catch((err) => {
|
|
@@ -178,7 +179,7 @@ async function parseInput(cmd) {
|
|
|
178
179
|
history.pop();
|
|
179
180
|
|
|
180
181
|
if (isAiCommand) return;
|
|
181
|
-
if (!lastError) output.print(output.
|
|
182
|
+
if (!lastError) output.print(output.styles.error(' FAIL '), msg);
|
|
182
183
|
lastError = err.message;
|
|
183
184
|
});
|
|
184
185
|
recorder.add('ask for next step', askForStep);
|
|
@@ -207,4 +208,10 @@ function completer(line) {
|
|
|
207
208
|
return [hits && hits.length ? hits : completions, line];
|
|
208
209
|
}
|
|
209
210
|
|
|
210
|
-
|
|
211
|
+
function registerVariable(name, value) {
|
|
212
|
+
registeredVariables[name] = value;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = pause;
|
|
216
|
+
|
|
217
|
+
module.exports.registerVariable = registerVariable;
|
package/lib/plugin/allure.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
console.log('Allure plugin was moved to @codeceptjs/allure-legacy. Please install it and update your config')
|
|
3
|
-
console.log()
|
|
4
|
-
console.log('npm install @codeceptjs/allure-legacy --save-dev')
|
|
5
|
-
console.log()
|
|
6
|
-
console.log('Then update your config to use it:')
|
|
7
|
-
console.log()
|
|
8
|
-
console.log('plugins: {')
|
|
9
|
-
console.log(' allure: {')
|
|
10
|
-
console.log(' enabled: true,')
|
|
11
|
-
console.log(
|
|
12
|
-
console.log(' }')
|
|
13
|
-
console.log('}')
|
|
14
|
-
console.log()
|
|
15
|
-
}
|
|
1
|
+
module.exports = () => {
|
|
2
|
+
console.log('Allure plugin was moved to @codeceptjs/allure-legacy. Please install it and update your config')
|
|
3
|
+
console.log()
|
|
4
|
+
console.log('npm install @codeceptjs/allure-legacy --save-dev')
|
|
5
|
+
console.log()
|
|
6
|
+
console.log('Then update your config to use it:')
|
|
7
|
+
console.log()
|
|
8
|
+
console.log('plugins: {')
|
|
9
|
+
console.log(' allure: {')
|
|
10
|
+
console.log(' enabled: true,')
|
|
11
|
+
console.log(" require: '@codeceptjs/allure-legacy',")
|
|
12
|
+
console.log(' }')
|
|
13
|
+
console.log('}')
|
|
14
|
+
console.log()
|
|
15
|
+
}
|
package/lib/plugin/autoDelay.js
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const Container = require('../container')
|
|
2
|
+
const store = require('../store')
|
|
3
|
+
const recorder = require('../recorder')
|
|
4
|
+
const event = require('../event')
|
|
5
|
+
const log = require('../output').log
|
|
6
|
+
const supportedHelpers = require('./standardActingHelpers').slice()
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const methodsToDelay = [
|
|
10
|
-
'click',
|
|
11
|
-
'fillField',
|
|
12
|
-
'checkOption',
|
|
13
|
-
'pressKey',
|
|
14
|
-
'doubleClick',
|
|
15
|
-
'rightClick',
|
|
16
|
-
];
|
|
8
|
+
const methodsToDelay = ['click', 'fillField', 'checkOption', 'pressKey', 'doubleClick', 'rightClick']
|
|
17
9
|
|
|
18
10
|
const defaultConfig = {
|
|
19
11
|
methods: methodsToDelay,
|
|
20
12
|
delayBefore: 100,
|
|
21
13
|
delayAfter: 200,
|
|
22
|
-
}
|
|
14
|
+
}
|
|
23
15
|
|
|
24
16
|
/**
|
|
25
17
|
*
|
|
@@ -59,42 +51,42 @@ const defaultConfig = {
|
|
|
59
51
|
* * `delayAfter`: put a delay after a command. 200ms by default
|
|
60
52
|
*
|
|
61
53
|
*/
|
|
62
|
-
|
|
63
|
-
supportedHelpers.push('REST')
|
|
64
|
-
const helpers = Container.helpers()
|
|
65
|
-
let helper
|
|
54
|
+
module.exports = function (config) {
|
|
55
|
+
supportedHelpers.push('REST')
|
|
56
|
+
const helpers = Container.helpers()
|
|
57
|
+
let helper
|
|
66
58
|
|
|
67
|
-
config = Object.assign(defaultConfig, config)
|
|
59
|
+
config = Object.assign(defaultConfig, config)
|
|
68
60
|
|
|
69
61
|
for (const helperName of supportedHelpers) {
|
|
70
62
|
if (Object.keys(helpers).indexOf(helperName) > -1) {
|
|
71
|
-
helper = helpers[helperName]
|
|
63
|
+
helper = helpers[helperName]
|
|
72
64
|
}
|
|
73
65
|
}
|
|
74
66
|
|
|
75
|
-
if (!helper) return
|
|
67
|
+
if (!helper) return // no helpers for auto-delay
|
|
76
68
|
|
|
77
69
|
event.dispatcher.on(event.step.before, (step) => {
|
|
78
|
-
if (config.methods.indexOf(step.helperMethod) < 0) return
|
|
70
|
+
if (config.methods.indexOf(step.helperMethod) < 0) return // skip non-actions
|
|
79
71
|
|
|
80
72
|
recorder.add('auto-delay', async () => {
|
|
81
|
-
if (store.debugMode) return
|
|
82
|
-
log(`Delaying for ${config.delayBefore}ms`)
|
|
73
|
+
if (store.debugMode) return // no need to delay in debug
|
|
74
|
+
log(`Delaying for ${config.delayBefore}ms`)
|
|
83
75
|
return new Promise((resolve) => {
|
|
84
|
-
setTimeout(resolve, config.delayBefore)
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
})
|
|
76
|
+
setTimeout(resolve, config.delayBefore)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
})
|
|
88
80
|
|
|
89
81
|
event.dispatcher.on(event.step.after, (step) => {
|
|
90
|
-
if (config.methods.indexOf(step.helperMethod) < 0) return
|
|
82
|
+
if (config.methods.indexOf(step.helperMethod) < 0) return // skip non-actions
|
|
91
83
|
|
|
92
84
|
recorder.add('auto-delay', async () => {
|
|
93
|
-
if (store.debugMode) return
|
|
94
|
-
log(`Delaying for ${config.delayAfter}ms`)
|
|
85
|
+
if (store.debugMode) return // no need to delay in debug
|
|
86
|
+
log(`Delaying for ${config.delayAfter}ms`)
|
|
95
87
|
return new Promise((resolve) => {
|
|
96
|
-
setTimeout(resolve, config.delayAfter)
|
|
97
|
-
})
|
|
98
|
-
})
|
|
99
|
-
})
|
|
88
|
+
setTimeout(resolve, config.delayAfter)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
})
|
|
100
92
|
}
|
package/lib/plugin/autoLogin.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const { fileExists } = require('../utils')
|
|
4
|
+
const container = require('../container')
|
|
5
|
+
const store = require('../store')
|
|
6
|
+
const recorder = require('../recorder')
|
|
7
|
+
const { debug } = require('../output')
|
|
8
|
+
const isAsyncFunction = require('../utils').isAsyncFunction
|
|
8
9
|
|
|
9
10
|
const defaultUser = {
|
|
10
|
-
fetch: I => I.grabCookie(),
|
|
11
|
+
fetch: (I) => I.grabCookie(),
|
|
11
12
|
check: () => {},
|
|
12
13
|
restore: (I, cookies) => {
|
|
13
|
-
I.amOnPage('/')
|
|
14
|
-
I.setCookie(cookies)
|
|
14
|
+
I.amOnPage('/') // open a page
|
|
15
|
+
I.setCookie(cookies)
|
|
15
16
|
},
|
|
16
|
-
}
|
|
17
|
+
}
|
|
17
18
|
|
|
18
19
|
const defaultConfig = {
|
|
19
20
|
saveToFile: false,
|
|
20
21
|
inject: 'login',
|
|
21
|
-
}
|
|
22
|
+
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Logs user in for the first test and reuses session for next tests.
|
|
@@ -248,88 +249,92 @@ const defaultConfig = {
|
|
|
248
249
|
* })
|
|
249
250
|
*
|
|
250
251
|
*
|
|
251
|
-
*/
|
|
252
|
-
|
|
253
|
-
config = Object.assign(defaultConfig, config)
|
|
254
|
-
Object.keys(config.users).map(
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
*/
|
|
253
|
+
module.exports = function (config) {
|
|
254
|
+
config = Object.assign(defaultConfig, config)
|
|
255
|
+
Object.keys(config.users).map(
|
|
256
|
+
(u) =>
|
|
257
|
+
(config.users[u] = {
|
|
258
|
+
...defaultUser,
|
|
259
|
+
...config.users[u],
|
|
260
|
+
}),
|
|
261
|
+
)
|
|
258
262
|
|
|
259
263
|
if (config.saveToFile) {
|
|
260
264
|
// loading from file
|
|
261
265
|
for (const name in config.users) {
|
|
262
|
-
const fileName = path.join(global.output_dir, `${name}_session.json`)
|
|
263
|
-
if (!fileExists(fileName)) continue
|
|
264
|
-
const data = fs.readFileSync(fileName).toString()
|
|
266
|
+
const fileName = path.join(global.output_dir, `${name}_session.json`)
|
|
267
|
+
if (!fileExists(fileName)) continue
|
|
268
|
+
const data = fs.readFileSync(fileName).toString()
|
|
265
269
|
try {
|
|
266
|
-
store[`${name}_session`] = JSON.parse(data)
|
|
270
|
+
store[`${name}_session`] = JSON.parse(data)
|
|
267
271
|
} catch (err) {
|
|
268
|
-
throw new Error(`Could not load session from ${fileName}\n${err}`)
|
|
272
|
+
throw new Error(`Could not load session from ${fileName}\n${err}`)
|
|
269
273
|
}
|
|
270
|
-
debug(`Loaded user session for ${name}`)
|
|
274
|
+
debug(`Loaded user session for ${name}`)
|
|
271
275
|
}
|
|
272
276
|
}
|
|
273
277
|
|
|
274
278
|
const loginFunction = async (name) => {
|
|
275
|
-
const userSession = config.users[name]
|
|
276
|
-
const I = container.support('I')
|
|
277
|
-
const cookies = store[`${name}_session`]
|
|
278
|
-
const shouldAwait =
|
|
279
|
-
|| isAsyncFunction(userSession.restore)
|
|
280
|
-
|| isAsyncFunction(userSession.check);
|
|
279
|
+
const userSession = config.users[name]
|
|
280
|
+
const I = container.support('I')
|
|
281
|
+
const cookies = store[`${name}_session`]
|
|
282
|
+
const shouldAwait =
|
|
283
|
+
isAsyncFunction(userSession.login) || isAsyncFunction(userSession.restore) || isAsyncFunction(userSession.check)
|
|
281
284
|
|
|
282
285
|
const loginAndSave = async () => {
|
|
283
286
|
if (shouldAwait) {
|
|
284
|
-
await userSession.login(I)
|
|
287
|
+
await userSession.login(I)
|
|
285
288
|
} else {
|
|
286
|
-
userSession.login(I)
|
|
289
|
+
userSession.login(I)
|
|
287
290
|
}
|
|
288
291
|
|
|
289
|
-
const cookies = await userSession.fetch(I)
|
|
292
|
+
const cookies = await userSession.fetch(I)
|
|
290
293
|
if (!cookies) {
|
|
291
|
-
debug(
|
|
292
|
-
return
|
|
294
|
+
debug("Cannot save user session with empty cookies from auto login's fetch method")
|
|
295
|
+
return
|
|
293
296
|
}
|
|
294
297
|
if (config.saveToFile) {
|
|
295
|
-
debug(`Saved user session into file for ${name}`)
|
|
296
|
-
fs.writeFileSync(path.join(global.output_dir, `${name}_session.json`), JSON.stringify(cookies))
|
|
298
|
+
debug(`Saved user session into file for ${name}`)
|
|
299
|
+
fs.writeFileSync(path.join(global.output_dir, `${name}_session.json`), JSON.stringify(cookies))
|
|
297
300
|
}
|
|
298
|
-
store[`${name}_session`] = cookies
|
|
299
|
-
}
|
|
301
|
+
store[`${name}_session`] = cookies
|
|
302
|
+
}
|
|
300
303
|
|
|
301
|
-
if (!cookies) return loginAndSave()
|
|
304
|
+
if (!cookies) return loginAndSave()
|
|
302
305
|
|
|
303
|
-
recorder.session.start('check login')
|
|
306
|
+
recorder.session.start('check login')
|
|
304
307
|
if (shouldAwait) {
|
|
305
|
-
await userSession.restore(I, cookies)
|
|
306
|
-
await userSession.check(I, cookies)
|
|
308
|
+
await userSession.restore(I, cookies)
|
|
309
|
+
await userSession.check(I, cookies)
|
|
307
310
|
} else {
|
|
308
|
-
userSession.restore(I, cookies)
|
|
309
|
-
userSession.check(I, cookies)
|
|
311
|
+
userSession.restore(I, cookies)
|
|
312
|
+
userSession.check(I, cookies)
|
|
310
313
|
}
|
|
311
314
|
recorder.session.catch((err) => {
|
|
312
|
-
debug(`Failed auto login for ${name} due to ${err}`)
|
|
313
|
-
debug('Logging in again')
|
|
314
|
-
recorder.session.start('auto login')
|
|
315
|
-
return loginAndSave()
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
315
|
+
debug(`Failed auto login for ${name} due to ${err}`)
|
|
316
|
+
debug('Logging in again')
|
|
317
|
+
recorder.session.start('auto login')
|
|
318
|
+
return loginAndSave()
|
|
319
|
+
.then(() => {
|
|
320
|
+
recorder.add(() => recorder.session.restore('auto login'))
|
|
321
|
+
recorder.catch(() => debug('continue'))
|
|
322
|
+
})
|
|
323
|
+
.catch((err) => {
|
|
324
|
+
recorder.session.restore('auto login')
|
|
325
|
+
recorder.session.restore('check login')
|
|
326
|
+
recorder.throw(err)
|
|
327
|
+
})
|
|
328
|
+
})
|
|
324
329
|
recorder.add(() => {
|
|
325
|
-
recorder.session.restore('check login')
|
|
326
|
-
})
|
|
330
|
+
recorder.session.restore('check login')
|
|
331
|
+
})
|
|
327
332
|
|
|
328
|
-
return recorder.promise()
|
|
329
|
-
}
|
|
333
|
+
return recorder.promise()
|
|
334
|
+
}
|
|
330
335
|
|
|
331
336
|
// adding this to DI container
|
|
332
|
-
const support = {}
|
|
333
|
-
support[config.inject] = loginFunction
|
|
334
|
-
container.append({ support })
|
|
337
|
+
const support = {}
|
|
338
|
+
support[config.inject] = loginFunction
|
|
339
|
+
container.append({ support })
|
|
335
340
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const recorder = require('../recorder')
|
|
3
|
+
const { MetaStep } = require('../step')
|
|
4
4
|
|
|
5
|
-
let currentCommentStep
|
|
5
|
+
let currentCommentStep
|
|
6
6
|
|
|
7
|
-
const defaultGlobalName = '__'
|
|
7
|
+
const defaultGlobalName = '__'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Add descriptive nested steps for your tests:
|
|
@@ -99,38 +99,38 @@ const defaultGlobalName = '__';
|
|
|
99
99
|
* });
|
|
100
100
|
* ```
|
|
101
101
|
*/
|
|
102
|
-
|
|
102
|
+
module.exports = function (config) {
|
|
103
103
|
event.dispatcher.on(event.test.started, () => {
|
|
104
|
-
currentCommentStep = null
|
|
105
|
-
})
|
|
104
|
+
currentCommentStep = null
|
|
105
|
+
})
|
|
106
106
|
|
|
107
107
|
event.dispatcher.on(event.step.started, (step) => {
|
|
108
108
|
if (currentCommentStep) {
|
|
109
|
-
const metaStep = getRootMetaStep(step)
|
|
109
|
+
const metaStep = getRootMetaStep(step)
|
|
110
110
|
|
|
111
111
|
if (metaStep !== currentCommentStep) {
|
|
112
|
-
metaStep.metaStep = currentCommentStep
|
|
112
|
+
metaStep.metaStep = currentCommentStep
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
})
|
|
115
|
+
})
|
|
116
116
|
|
|
117
117
|
if (config.registerGlobal) {
|
|
118
118
|
if (config.registerGlobal === true) {
|
|
119
|
-
config.registerGlobal = defaultGlobalName
|
|
119
|
+
config.registerGlobal = defaultGlobalName
|
|
120
120
|
}
|
|
121
|
-
global[config.registerGlobal] = setCommentString
|
|
121
|
+
global[config.registerGlobal] = setCommentString
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
return setCommentString
|
|
124
|
+
return setCommentString
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
function getRootMetaStep(step) {
|
|
128
|
-
if (step.metaStep) return getRootMetaStep(step.metaStep)
|
|
129
|
-
return step
|
|
128
|
+
if (step.metaStep) return getRootMetaStep(step.metaStep)
|
|
129
|
+
return step
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
function setCommentString(string) {
|
|
133
133
|
recorder.add('set comment metastep', () => {
|
|
134
|
-
currentCommentStep = new MetaStep(String.raw(string), '')
|
|
135
|
-
})
|
|
134
|
+
currentCommentStep = new MetaStep(String.raw(string), '')
|
|
135
|
+
})
|
|
136
136
|
}
|