codeceptjs 4.0.0-beta.2 → 4.0.0-beta.4
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 +2 -2
- 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 +56 -49
- package/lib/codecept.js +145 -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 +79 -81
- package/lib/command/generate.js +197 -188
- package/lib/command/gherkin/init.js +27 -16
- package/lib/command/gherkin/snippets.js +21 -21
- 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 +11 -12
- 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 +14 -18
- package/lib/helper/AI.js +130 -41
- package/lib/helper/ApiDataFactory.js +74 -70
- package/lib/helper/Appium.js +416 -388
- 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 +51 -51
- package/lib/helper/JSONResponse.js +65 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/Nightmare.js +664 -571
- package/lib/helper/Playwright.js +1367 -1222
- package/lib/helper/Protractor.js +663 -635
- package/lib/helper/Puppeteer.js +1232 -1132
- package/lib/helper/REST.js +183 -68
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +490 -486
- package/lib/helper/WebDriver.js +1246 -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 +4 -4
- 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 +4 -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 -8
- 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 +7 -11
- package/lib/mochaFactory.js +18 -15
- package/lib/output.js +19 -15
- package/lib/parser.js +15 -12
- package/lib/pause.js +45 -38
- 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 +112 -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 -3
- 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 -33
- package/package.json +67 -68
- package/translations/de-DE.js +2 -1
- package/translations/fr-FR.js +2 -2
- 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 +423 -65
- package/typings/promiseBasedTypes.d.ts +41 -172
- package/typings/types.d.ts +43 -178
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/MockServer.js +0 -223
package/lib/output.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const colors = require('chalk');
|
|
2
|
+
const figures = require('figures');
|
|
3
|
+
const { maskSensitiveData } = require('invisi-data')
|
|
3
4
|
|
|
4
5
|
const styles = {
|
|
5
6
|
error: colors.bgRed.white.bold,
|
|
@@ -19,7 +20,7 @@ let newline = true;
|
|
|
19
20
|
* @alias output
|
|
20
21
|
* @namespace
|
|
21
22
|
*/
|
|
22
|
-
|
|
23
|
+
module.exports = {
|
|
23
24
|
colors,
|
|
24
25
|
styles,
|
|
25
26
|
print,
|
|
@@ -57,22 +58,20 @@ export const output = {
|
|
|
57
58
|
* @param {string} msg
|
|
58
59
|
*/
|
|
59
60
|
debug(msg) {
|
|
61
|
+
const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
|
|
60
62
|
if (outputLevel >= 2) {
|
|
61
|
-
print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${
|
|
63
|
+
print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`));
|
|
62
64
|
}
|
|
63
65
|
},
|
|
64
66
|
|
|
65
|
-
debugSection(section, msg) {
|
|
66
|
-
this.debug(`[${section}] ${msg}`);
|
|
67
|
-
},
|
|
68
|
-
|
|
69
67
|
/**
|
|
70
68
|
* Print information in --verbose mode
|
|
71
69
|
* @param {string} msg
|
|
72
70
|
*/
|
|
73
71
|
log(msg) {
|
|
72
|
+
const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
|
|
74
73
|
if (outputLevel >= 3) {
|
|
75
|
-
print(' '.repeat(this.stepShift), styles.log(truncate(` ${
|
|
74
|
+
print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift)));
|
|
76
75
|
}
|
|
77
76
|
},
|
|
78
77
|
|
|
@@ -117,14 +116,15 @@ export const output = {
|
|
|
117
116
|
|
|
118
117
|
let stepLine = step.toString();
|
|
119
118
|
if (step.metaStep && outputLevel >= 1) {
|
|
120
|
-
this.stepShift += 2;
|
|
119
|
+
// this.stepShift += 2;
|
|
121
120
|
stepLine = colors.green(truncate(stepLine, this.spaceShift));
|
|
122
121
|
}
|
|
123
122
|
if (step.comment) {
|
|
124
|
-
stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4)));
|
|
123
|
+
stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4)));
|
|
125
124
|
}
|
|
126
125
|
|
|
127
|
-
|
|
126
|
+
const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine
|
|
127
|
+
print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift));
|
|
128
128
|
},
|
|
129
129
|
|
|
130
130
|
/** @namespace */
|
|
@@ -172,9 +172,9 @@ export const output = {
|
|
|
172
172
|
/**
|
|
173
173
|
* @param {Mocha.Test} test
|
|
174
174
|
*/
|
|
175
|
-
|
|
175
|
+
|
|
176
176
|
started(test) {},
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
/**
|
|
179
179
|
* @param {Mocha.Test} test
|
|
180
180
|
*/
|
|
@@ -236,7 +236,7 @@ export const output = {
|
|
|
236
236
|
},
|
|
237
237
|
};
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
function print(...msg) {
|
|
240
240
|
if (outputProcess) {
|
|
241
241
|
msg.unshift(outputProcess);
|
|
242
242
|
}
|
|
@@ -258,3 +258,7 @@ function truncate(msg, gap = 0) {
|
|
|
258
258
|
}
|
|
259
259
|
return msg;
|
|
260
260
|
}
|
|
261
|
+
|
|
262
|
+
function isMaskedData() {
|
|
263
|
+
return global.maskSensitiveData === true || false
|
|
264
|
+
}
|
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', () => {
|
|
@@ -90,7 +91,7 @@ async function parseInput(cmd) {
|
|
|
90
91
|
return nextStep();
|
|
91
92
|
}
|
|
92
93
|
for (const k of Object.keys(registeredVariables)) {
|
|
93
|
-
eval(`var ${k} = registeredVariables['${k}'];`);
|
|
94
|
+
eval(`var ${k} = registeredVariables['${k}'];`);
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
let executeCommand = Promise.resolve();
|
|
@@ -105,14 +106,14 @@ async function parseInput(cmd) {
|
|
|
105
106
|
let isAiCommand = false;
|
|
106
107
|
let $res;
|
|
107
108
|
try {
|
|
108
|
-
|
|
109
|
+
|
|
109
110
|
const locate = global.locate; // enable locate in this context
|
|
110
|
-
|
|
111
|
+
|
|
111
112
|
const I = container.support('I');
|
|
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('');
|
|
@@ -142,11 +143,11 @@ async function parseInput(cmd) {
|
|
|
142
143
|
executeCommand = executeCommand.then(async () => {
|
|
143
144
|
const cmd = getCmd();
|
|
144
145
|
if (!cmd) return;
|
|
145
|
-
return eval(cmd);
|
|
146
|
+
return eval(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;
|
|
@@ -155,20 +156,20 @@ async function parseInput(cmd) {
|
|
|
155
156
|
const val = await executeCommand;
|
|
156
157
|
|
|
157
158
|
if (isCustomCommand) {
|
|
158
|
-
if (val !== undefined) console.log('Result', '$res=', val);
|
|
159
|
+
if (val !== undefined) console.log('Result', '$res=', val);
|
|
159
160
|
$res = val;
|
|
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
|
}
|