codeceptjs 3.5.15 → 3.6.0
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 +68 -31
- package/docs/webapi/startRecordingWebSocketMessages.mustache +8 -0
- package/docs/webapi/stopRecordingWebSocketMessages.mustache +7 -0
- package/lib/ai.js +152 -80
- package/lib/cli.js +1 -0
- package/lib/command/generate.js +34 -0
- package/lib/command/run-workers.js +3 -0
- package/lib/command/run.js +3 -0
- package/lib/container.js +2 -0
- package/lib/heal.js +172 -0
- package/lib/helper/{OpenAI.js → AI.js} +10 -12
- package/lib/helper/Playwright.js +32 -156
- package/lib/helper/Puppeteer.js +222 -3
- package/lib/helper/WebDriver.js +6 -144
- package/lib/helper/extras/PlaywrightReactVueLocator.js +6 -1
- package/lib/helper/network/actions.js +123 -0
- package/lib/helper/{networkTraffics → network}/utils.js +50 -0
- package/lib/index.js +3 -0
- package/lib/listener/steps.js +0 -2
- package/lib/locator.js +23 -1
- package/lib/plugin/heal.js +26 -117
- package/lib/recorder.js +11 -5
- package/lib/store.js +2 -0
- package/lib/template/heal.js +39 -0
- package/package.json +14 -15
- package/typings/index.d.ts +2 -2
- package/typings/promiseBasedTypes.d.ts +206 -25
- package/typings/types.d.ts +219 -26
package/lib/locator.js
CHANGED
|
@@ -3,7 +3,7 @@ const { sprintf } = require('sprintf-js');
|
|
|
3
3
|
|
|
4
4
|
const { xpathLocator } = require('./utils');
|
|
5
5
|
|
|
6
|
-
const locatorTypes = ['css', 'by', 'xpath', 'id', 'name', 'fuzzy', 'frame', 'shadow'];
|
|
6
|
+
const locatorTypes = ['css', 'by', 'xpath', 'id', 'name', 'fuzzy', 'frame', 'shadow', 'pw'];
|
|
7
7
|
/** @class */
|
|
8
8
|
class Locator {
|
|
9
9
|
/**
|
|
@@ -51,6 +51,9 @@ class Locator {
|
|
|
51
51
|
if (isShadow(locator)) {
|
|
52
52
|
this.type = 'shadow';
|
|
53
53
|
}
|
|
54
|
+
if (isPlaywrightLocator(locator)) {
|
|
55
|
+
this.type = 'pw';
|
|
56
|
+
}
|
|
54
57
|
|
|
55
58
|
Locator.filters.forEach(f => f(locator, this));
|
|
56
59
|
}
|
|
@@ -71,6 +74,8 @@ class Locator {
|
|
|
71
74
|
return this.value;
|
|
72
75
|
case 'shadow':
|
|
73
76
|
return { shadow: this.value };
|
|
77
|
+
case 'pw':
|
|
78
|
+
return { pw: this.value };
|
|
74
79
|
}
|
|
75
80
|
return this.value;
|
|
76
81
|
}
|
|
@@ -115,6 +120,13 @@ class Locator {
|
|
|
115
120
|
return this.type === 'css';
|
|
116
121
|
}
|
|
117
122
|
|
|
123
|
+
/**
|
|
124
|
+
* @returns {boolean}
|
|
125
|
+
*/
|
|
126
|
+
isPlaywrightLocator() {
|
|
127
|
+
return this.type === 'pw';
|
|
128
|
+
}
|
|
129
|
+
|
|
118
130
|
/**
|
|
119
131
|
* @returns {boolean}
|
|
120
132
|
*/
|
|
@@ -522,6 +534,16 @@ function removePrefix(xpath) {
|
|
|
522
534
|
.replace(/^(\.|\/)+/, '');
|
|
523
535
|
}
|
|
524
536
|
|
|
537
|
+
/**
|
|
538
|
+
* @private
|
|
539
|
+
* check if the locator is a Playwright locator
|
|
540
|
+
* @param {string} locator
|
|
541
|
+
* @returns {boolean}
|
|
542
|
+
*/
|
|
543
|
+
function isPlaywrightLocator(locator) {
|
|
544
|
+
return locator.includes('_react') || locator.includes('_vue') || locator.includes('data-testid');
|
|
545
|
+
}
|
|
546
|
+
|
|
525
547
|
/**
|
|
526
548
|
* @private
|
|
527
549
|
* @param {CodeceptJS.LocatorOrString} locator
|
package/lib/plugin/heal.js
CHANGED
|
@@ -1,33 +1,19 @@
|
|
|
1
1
|
const debug = require('debug')('codeceptjs:heal');
|
|
2
2
|
const colors = require('chalk');
|
|
3
|
-
const Container = require('../container');
|
|
4
|
-
const AiAssistant = require('../ai');
|
|
5
3
|
const recorder = require('../recorder');
|
|
6
4
|
const event = require('../event');
|
|
7
5
|
const output = require('../output');
|
|
8
|
-
const
|
|
6
|
+
const heal = require('../heal');
|
|
7
|
+
const store = require('../store');
|
|
9
8
|
|
|
10
9
|
const defaultConfig = {
|
|
11
|
-
healTries: 1,
|
|
12
10
|
healLimit: 2,
|
|
13
|
-
healSteps: [
|
|
14
|
-
'click',
|
|
15
|
-
'fillField',
|
|
16
|
-
'appendField',
|
|
17
|
-
'selectOption',
|
|
18
|
-
'attachFile',
|
|
19
|
-
'checkOption',
|
|
20
|
-
'uncheckOption',
|
|
21
|
-
'doubleClick',
|
|
22
|
-
],
|
|
23
11
|
};
|
|
24
12
|
|
|
25
13
|
/**
|
|
26
|
-
* Self-healing tests with
|
|
14
|
+
* Self-healing tests with AI.
|
|
27
15
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* To use it you need to set OPENAI_API_KEY env variable and enable plugin inside the config.
|
|
16
|
+
* Read more about heaking in [Self-Healing Tests](https://codecept.io/heal/)
|
|
31
17
|
*
|
|
32
18
|
* ```js
|
|
33
19
|
* plugins: {
|
|
@@ -40,22 +26,15 @@ const defaultConfig = {
|
|
|
40
26
|
* More config options are available:
|
|
41
27
|
*
|
|
42
28
|
* * `healLimit` - how many steps can be healed in a single test (default: 2)
|
|
43
|
-
* * `healSteps` - which steps can be healed (default: all steps that interact with UI, see list below)
|
|
44
|
-
*
|
|
45
|
-
* Steps to heal:
|
|
46
|
-
*
|
|
47
|
-
* * `click`
|
|
48
|
-
* * `fillField`
|
|
49
|
-
* * `appendField`
|
|
50
|
-
* * `selectOption`
|
|
51
|
-
* * `attachFile`
|
|
52
|
-
* * `checkOption`
|
|
53
|
-
* * `uncheckOption`
|
|
54
|
-
* * `doubleClick`
|
|
55
29
|
*
|
|
56
30
|
*/
|
|
57
31
|
module.exports = function (config = {}) {
|
|
58
|
-
|
|
32
|
+
if (store.debugMode && !process.env.DEBUG) {
|
|
33
|
+
event.dispatcher.on(event.test.failed, () => {
|
|
34
|
+
output.plugin('heal', 'Healing is disabled in --debug mode, use DEBUG="codeceptjs:heal" to enable it in debug mode');
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
59
38
|
|
|
60
39
|
let currentTest = null;
|
|
61
40
|
let currentStep = null;
|
|
@@ -64,8 +43,6 @@ module.exports = function (config = {}) {
|
|
|
64
43
|
let healTries = 0;
|
|
65
44
|
let isHealing = false;
|
|
66
45
|
|
|
67
|
-
const healSuggestions = [];
|
|
68
|
-
|
|
69
46
|
config = Object.assign(defaultConfig, config);
|
|
70
47
|
|
|
71
48
|
event.dispatcher.on(event.test.before, (test) => {
|
|
@@ -78,63 +55,27 @@ module.exports = function (config = {}) {
|
|
|
78
55
|
|
|
79
56
|
event.dispatcher.on(event.step.after, (step) => {
|
|
80
57
|
if (isHealing) return;
|
|
81
|
-
|
|
82
|
-
|
|
58
|
+
if (healTries >= config.healLimit) return; // out of limit
|
|
59
|
+
|
|
60
|
+
if (!heal.hasCorrespondingRecipes(step)) return;
|
|
61
|
+
|
|
83
62
|
recorder.catchWithoutStop(async (err) => {
|
|
84
63
|
isHealing = true;
|
|
85
64
|
if (caughtError === err) throw err; // avoid double handling
|
|
86
65
|
caughtError = err;
|
|
87
|
-
if (!aiAssistant.isEnabled) {
|
|
88
|
-
output.print(colors.yellow('Heal plugin can\'t operate, AI assistant is disabled. Please set OPENAI_API_KEY env variable to enable it.'));
|
|
89
|
-
throw err;
|
|
90
|
-
}
|
|
91
|
-
if (!currentStep) throw err;
|
|
92
|
-
if (!config.healSteps.includes(currentStep.name)) throw err;
|
|
93
|
-
const test = currentTest;
|
|
94
|
-
|
|
95
|
-
if (healTries >= config.healTries) {
|
|
96
|
-
output.print(colors.bold.red(`Healing failed for ${config.healTries} time(s)`));
|
|
97
|
-
output.print('AI couldn\'t identify the correct solution');
|
|
98
|
-
output.print('Probably the entire flow has changed and the test should be updated');
|
|
99
|
-
|
|
100
|
-
throw err;
|
|
101
|
-
}
|
|
102
66
|
|
|
103
|
-
|
|
104
|
-
output.print(colors.bold.red(`Can't heal more than ${config.healLimit} step(s) in a test`));
|
|
105
|
-
output.print('Entire flow can be broken, please check it manually');
|
|
106
|
-
output.print('or increase healing limit in heal plugin config');
|
|
107
|
-
|
|
108
|
-
throw err;
|
|
109
|
-
}
|
|
67
|
+
const test = currentTest;
|
|
110
68
|
|
|
111
69
|
recorder.session.start('heal');
|
|
112
|
-
const helpers = Container.helpers();
|
|
113
|
-
let helper;
|
|
114
|
-
|
|
115
|
-
for (const helperName of supportedHelpers) {
|
|
116
|
-
if (Object.keys(helpers).indexOf(helperName) > -1) {
|
|
117
|
-
helper = helpers[helperName];
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
70
|
|
|
121
|
-
if (!helper) throw err; // no helpers for html
|
|
122
|
-
|
|
123
|
-
const step = test.steps[test.steps.length - 1];
|
|
124
71
|
debug('Self-healing started', step.toCode());
|
|
125
72
|
|
|
126
|
-
|
|
127
|
-
output.level(0);
|
|
128
|
-
const html = await helper.grabHTMLFrom('body');
|
|
129
|
-
output.level(currentOutputLevel);
|
|
130
|
-
|
|
131
|
-
if (!html) throw err;
|
|
73
|
+
await heal.healStep(step, err, { test });
|
|
132
74
|
|
|
133
75
|
healTries++;
|
|
134
|
-
await aiAssistant.setHtmlContext(html);
|
|
135
|
-
await tryToHeal(step, err);
|
|
136
76
|
|
|
137
77
|
recorder.add('close healing session', () => {
|
|
78
|
+
recorder.reset();
|
|
138
79
|
recorder.session.restore('heal');
|
|
139
80
|
recorder.ignoreErr(err);
|
|
140
81
|
});
|
|
@@ -145,7 +86,7 @@ module.exports = function (config = {}) {
|
|
|
145
86
|
});
|
|
146
87
|
|
|
147
88
|
event.dispatcher.on(event.all.result, () => {
|
|
148
|
-
if (!
|
|
89
|
+
if (!heal.fixes?.length) return;
|
|
149
90
|
|
|
150
91
|
const { print } = output;
|
|
151
92
|
|
|
@@ -153,16 +94,20 @@ module.exports = function (config = {}) {
|
|
|
153
94
|
print('===================');
|
|
154
95
|
print(colors.bold.green('Self-Healing Report:'));
|
|
155
96
|
|
|
156
|
-
print(`${colors.bold(
|
|
97
|
+
print(`${colors.bold(heal.fixes.length)} ${heal.fixes.length === 1 ? 'step was' : 'steps were'} healed`);
|
|
98
|
+
|
|
99
|
+
const suggestions = heal.fixes.filter(fix => fix.recipe && heal.recipes[fix.recipe].suggest);
|
|
100
|
+
|
|
101
|
+
if (!suggestions.length) return;
|
|
157
102
|
|
|
158
103
|
let i = 1;
|
|
159
104
|
print('');
|
|
160
105
|
print('Suggested changes:');
|
|
161
106
|
print('');
|
|
162
107
|
|
|
163
|
-
for (const suggestion of
|
|
164
|
-
print(`${i}. To fix ${colors.bold.
|
|
165
|
-
print('Replace the failed code
|
|
108
|
+
for (const suggestion of suggestions) {
|
|
109
|
+
print(`${i}. To fix ${colors.bold.magenta(suggestion.test?.title)}`);
|
|
110
|
+
print(' Replace the failed code:', colors.gray(`(suggested by ${colors.bold(suggestion.recipe)})`));
|
|
166
111
|
print(colors.red(`- ${suggestion.step.toCode()}`));
|
|
167
112
|
print(colors.green(`+ ${suggestion.snippet}`));
|
|
168
113
|
print(suggestion.step.line());
|
|
@@ -170,40 +115,4 @@ module.exports = function (config = {}) {
|
|
|
170
115
|
i++;
|
|
171
116
|
}
|
|
172
117
|
});
|
|
173
|
-
|
|
174
|
-
async function tryToHeal(failedStep, err) {
|
|
175
|
-
output.debug(`Running OpenAI to heal ${failedStep.toCode()} step`);
|
|
176
|
-
|
|
177
|
-
const codeSnippets = await aiAssistant.healFailedStep(failedStep, err, currentTest);
|
|
178
|
-
|
|
179
|
-
output.debug(`Received ${codeSnippets.length} suggestions from OpenAI`);
|
|
180
|
-
const I = Container.support('I'); // eslint-disable-line
|
|
181
|
-
|
|
182
|
-
for (const codeSnippet of codeSnippets) {
|
|
183
|
-
try {
|
|
184
|
-
debug('Executing', codeSnippet);
|
|
185
|
-
recorder.catch((e) => {
|
|
186
|
-
console.log(e);
|
|
187
|
-
});
|
|
188
|
-
await eval(codeSnippet); // eslint-disable-line
|
|
189
|
-
|
|
190
|
-
healSuggestions.push({
|
|
191
|
-
test: currentTest,
|
|
192
|
-
step: failedStep,
|
|
193
|
-
snippet: codeSnippet,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
recorder.add('healed', () => output.print(colors.bold.green(' Code healed successfully')));
|
|
197
|
-
healedSteps++;
|
|
198
|
-
return;
|
|
199
|
-
} catch (err) {
|
|
200
|
-
debug('Failed to execute code', err);
|
|
201
|
-
recorder.ignoreErr(err); // healing ded not help
|
|
202
|
-
// recorder.catch(() => output.print(colors.bold.red(' Failed healing code')));
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
output.debug(`Couldn't heal the code for ${failedStep.toCode()}`);
|
|
207
|
-
}
|
|
208
|
-
return recorder.promise();
|
|
209
118
|
};
|
package/lib/recorder.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const debug = require('debug')('codeceptjs:recorder');
|
|
2
2
|
const promiseRetry = require('promise-retry');
|
|
3
|
+
const chalk = require('chalk');
|
|
3
4
|
const { printObjectProperties } = require('./utils');
|
|
4
5
|
const { log } = require('./output');
|
|
5
6
|
|
|
@@ -179,7 +180,7 @@ module.exports = {
|
|
|
179
180
|
return;
|
|
180
181
|
}
|
|
181
182
|
tasks.push(taskName);
|
|
182
|
-
debug(`${currentQueue()}Queued | ${taskName}`);
|
|
183
|
+
debug(chalk.gray(`${currentQueue()} Queued | ${taskName}`));
|
|
183
184
|
|
|
184
185
|
return promise = Promise.resolve(promise).then((res) => {
|
|
185
186
|
// prefer options for non-conditional retries
|
|
@@ -190,11 +191,14 @@ module.exports = {
|
|
|
190
191
|
return Promise.race([promise, Promise.resolve(res).then(fn)]).finally(() => clearTimeout(timer));
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
debug(`${currentQueue()} Running | ${taskName}`);
|
|
195
|
+
|
|
193
196
|
const retryRules = this.retries.slice().reverse();
|
|
194
197
|
return promiseRetry(Object.assign(defaultRetryOptions, retryOpts), (retry, number) => {
|
|
195
198
|
if (number > 1) log(`${currentQueue()}Retrying... Attempt #${number}`);
|
|
196
199
|
const [promise, timer] = getTimeoutPromise(timeout, taskName);
|
|
197
200
|
return Promise.race([promise, Promise.resolve(res).then(fn)]).finally(() => clearTimeout(timer)).catch((err) => {
|
|
201
|
+
if (ignoredErrs.includes(err)) return;
|
|
198
202
|
for (const retryObj of retryRules) {
|
|
199
203
|
if (!retryObj.when) return retry(err);
|
|
200
204
|
if (retryObj.when && retryObj.when(err)) return retry(err);
|
|
@@ -229,7 +233,7 @@ module.exports = {
|
|
|
229
233
|
*/
|
|
230
234
|
catch(customErrFn) {
|
|
231
235
|
const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
|
|
232
|
-
debug(`${currentQueue()}Queued | catch with error handler ${fnDescription || ''}`);
|
|
236
|
+
debug(chalk.gray(`${currentQueue()} Queued | catch with error handler ${fnDescription || ''}`));
|
|
233
237
|
return promise = promise.catch((err) => {
|
|
234
238
|
log(`${currentQueue()}Error | ${err} ${fnDescription}...`);
|
|
235
239
|
if (!(err instanceof Error)) { // strange things may happen
|
|
@@ -253,7 +257,7 @@ module.exports = {
|
|
|
253
257
|
const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
|
|
254
258
|
return promise = promise.catch((err) => {
|
|
255
259
|
if (ignoredErrs.includes(err)) return; // already caught
|
|
256
|
-
log(`${currentQueue()}Error (Non-Terminated) | ${err} | ${fnDescription || ''}...`);
|
|
260
|
+
log(`${currentQueue()} Error (Non-Terminated) | ${err} | ${fnDescription || ''}...`);
|
|
257
261
|
if (!(err instanceof Error)) { // strange things may happen
|
|
258
262
|
err = new Error(`[Wrapped Error] ${JSON.stringify(err)}`); // we should be prepared for them
|
|
259
263
|
}
|
|
@@ -272,7 +276,9 @@ module.exports = {
|
|
|
272
276
|
*/
|
|
273
277
|
|
|
274
278
|
throw(err) {
|
|
279
|
+
if (ignoredErrs.includes(err)) return promise; // already caught
|
|
275
280
|
return this.add(`throw error: ${err.message}`, () => {
|
|
281
|
+
if (ignoredErrs.includes(err)) return; // already caught
|
|
276
282
|
throw err;
|
|
277
283
|
});
|
|
278
284
|
},
|
|
@@ -313,8 +319,8 @@ module.exports = {
|
|
|
313
319
|
* @inner
|
|
314
320
|
*/
|
|
315
321
|
stop() {
|
|
316
|
-
|
|
317
|
-
log(`${currentQueue()}Stopping recording promises`);
|
|
322
|
+
debug(this.toString());
|
|
323
|
+
log(`${currentQueue()} Stopping recording promises`);
|
|
318
324
|
running = false;
|
|
319
325
|
},
|
|
320
326
|
|
package/lib/store.js
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const { heal, ai } = require('codeceptjs');
|
|
2
|
+
|
|
3
|
+
heal.addRecipe('ai', {
|
|
4
|
+
priority: 10,
|
|
5
|
+
prepare: {
|
|
6
|
+
html: ({ I }) => I.grabHTMLFrom('body'),
|
|
7
|
+
},
|
|
8
|
+
steps: [
|
|
9
|
+
'click',
|
|
10
|
+
'fillField',
|
|
11
|
+
'appendField',
|
|
12
|
+
'selectOption',
|
|
13
|
+
'attachFile',
|
|
14
|
+
'checkOption',
|
|
15
|
+
'uncheckOption',
|
|
16
|
+
'doubleClick',
|
|
17
|
+
],
|
|
18
|
+
fn: async (args) => {
|
|
19
|
+
return ai.healFailedStep(args);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
heal.addRecipe('clickAndType', {
|
|
24
|
+
priority: 1,
|
|
25
|
+
steps: [
|
|
26
|
+
'fillField',
|
|
27
|
+
'appendField',
|
|
28
|
+
],
|
|
29
|
+
fn: async ({ step }) => {
|
|
30
|
+
const locator = step.args[0];
|
|
31
|
+
const text = step.args[1];
|
|
32
|
+
|
|
33
|
+
return ({ I }) => {
|
|
34
|
+
I.click(locator);
|
|
35
|
+
I.wait(1); // to open modal or something
|
|
36
|
+
I.type(text);
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeceptjs",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Supercharged End 2 End Testing Framework for NodeJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acceptance",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@codeceptjs/helper": "2.0.1",
|
|
73
73
|
"@cucumber/cucumber-expressions": "17",
|
|
74
74
|
"@cucumber/gherkin": "26",
|
|
75
|
-
"@cucumber/messages": "24.0
|
|
75
|
+
"@cucumber/messages": "24.1.0",
|
|
76
76
|
"@xmldom/xmldom": "0.8.10",
|
|
77
77
|
"acorn": "8.11.3",
|
|
78
78
|
"arrify": "2.0.1",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"css-to-xpath": "0.1.0",
|
|
91
91
|
"csstoxpath": "1.6.0",
|
|
92
92
|
"devtools": "8.33.1",
|
|
93
|
-
"envinfo": "7.11.
|
|
93
|
+
"envinfo": "7.11.1",
|
|
94
94
|
"escape-string-regexp": "4.0.0",
|
|
95
95
|
"figures": "3.2.0",
|
|
96
96
|
"fn-args": "4.0.0",
|
|
@@ -104,11 +104,10 @@
|
|
|
104
104
|
"lodash.merge": "4.6.2",
|
|
105
105
|
"mkdirp": "1.0.4",
|
|
106
106
|
"mocha": "10.3.0",
|
|
107
|
-
"monocart-coverage-reports": "2.7.
|
|
107
|
+
"monocart-coverage-reports": "2.7.4",
|
|
108
108
|
"ms": "2.1.3",
|
|
109
|
-
"openai": "3.2.1",
|
|
110
109
|
"ora-classic": "5.4.2",
|
|
111
|
-
"pactum": "3.6.
|
|
110
|
+
"pactum": "3.6.6",
|
|
112
111
|
"parse-function": "5.6.10",
|
|
113
112
|
"parse5": "7.1.2",
|
|
114
113
|
"promise-retry": "1.1.1",
|
|
@@ -124,12 +123,12 @@
|
|
|
124
123
|
"@faker-js/faker": "7.6.0",
|
|
125
124
|
"@pollyjs/adapter-puppeteer": "6.0.6",
|
|
126
125
|
"@pollyjs/core": "5.1.0",
|
|
127
|
-
"@types/chai": "4.3.
|
|
126
|
+
"@types/chai": "4.3.12",
|
|
128
127
|
"@types/inquirer": "9.0.3",
|
|
129
|
-
"@types/node": "20.11.
|
|
130
|
-
"@wdio/sauce-service": "8.
|
|
128
|
+
"@types/node": "20.11.30",
|
|
129
|
+
"@wdio/sauce-service": "8.35.1",
|
|
131
130
|
"@wdio/selenium-standalone-service": "8.3.2",
|
|
132
|
-
"@wdio/utils": "8.
|
|
131
|
+
"@wdio/utils": "8.33.1",
|
|
133
132
|
"@xmldom/xmldom": "0.8.10",
|
|
134
133
|
"apollo-server-express": "2.25.3",
|
|
135
134
|
"chai-as-promised": "7.1.1",
|
|
@@ -142,15 +141,15 @@
|
|
|
142
141
|
"eslint-plugin-import": "2.29.1",
|
|
143
142
|
"eslint-plugin-mocha": "6.3.0",
|
|
144
143
|
"expect": "29.7.0",
|
|
145
|
-
"express": "4.
|
|
144
|
+
"express": "4.19.2",
|
|
146
145
|
"graphql": "14.6.0",
|
|
147
146
|
"husky": "8.0.3",
|
|
148
147
|
"inquirer-test": "2.0.1",
|
|
149
148
|
"jsdoc": "3.6.11",
|
|
150
149
|
"jsdoc-typeof-plugin": "1.0.0",
|
|
151
150
|
"json-server": "0.10.1",
|
|
152
|
-
"playwright": "1.
|
|
153
|
-
"puppeteer": "22.
|
|
151
|
+
"playwright": "1.43.0",
|
|
152
|
+
"puppeteer": "22.6.3",
|
|
154
153
|
"qrcode-terminal": "0.12.0",
|
|
155
154
|
"rosie": "2.1.1",
|
|
156
155
|
"runok": "0.9.3",
|
|
@@ -159,13 +158,13 @@
|
|
|
159
158
|
"testcafe": "3.5.0",
|
|
160
159
|
"ts-morph": "21.0.1",
|
|
161
160
|
"ts-node": "10.9.2",
|
|
162
|
-
"tsd": "^0.
|
|
161
|
+
"tsd": "^0.31.0",
|
|
163
162
|
"tsd-jsdoc": "2.5.0",
|
|
164
163
|
"typedoc": "0.25.12",
|
|
165
164
|
"typedoc-plugin-markdown": "3.17.1",
|
|
166
165
|
"typescript": "5.3.3",
|
|
167
166
|
"wdio-docker-service": "1.5.0",
|
|
168
|
-
"webdriverio": "8.
|
|
167
|
+
"webdriverio": "8.35.1",
|
|
169
168
|
"xml2js": "0.6.2",
|
|
170
169
|
"xpath": "0.0.34"
|
|
171
170
|
},
|
package/typings/index.d.ts
CHANGED
|
@@ -442,8 +442,8 @@ declare namespace CodeceptJS {
|
|
|
442
442
|
| { react: string }
|
|
443
443
|
| { vue: string }
|
|
444
444
|
| { shadow: string[] }
|
|
445
|
-
| { custom: string }
|
|
446
|
-
|
|
445
|
+
| { custom: string }
|
|
446
|
+
| { pw: string };
|
|
447
447
|
interface CustomLocators {}
|
|
448
448
|
interface OtherLocators { props?: object }
|
|
449
449
|
type LocatorOrString =
|