codeceptjs 3.7.0-beta.9 → 3.7.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 +1 -1
- package/lib/codecept.js +14 -12
- package/lib/command/check.js +33 -9
- package/lib/command/definitions.js +1 -1
- package/lib/command/gherkin/snippets.js +69 -69
- package/lib/command/interactive.js +1 -1
- package/lib/command/run-multiple/chunk.js +48 -45
- package/lib/container.js +14 -7
- package/lib/effects.js +7 -2
- package/lib/event.js +2 -0
- package/lib/helper/AI.js +2 -1
- package/lib/helper/Playwright.js +1 -1
- package/lib/helper/Puppeteer.js +1 -1
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/mocha/asyncWrapper.js +3 -1
- package/lib/mocha/gherkin.js +1 -1
- package/lib/mocha/inject.js +5 -0
- package/lib/mocha/test.js +5 -2
- package/lib/plugin/analyze.js +50 -3
- package/lib/plugin/auth.js +435 -0
- package/lib/plugin/autoDelay.js +2 -2
- package/lib/plugin/autoLogin.js +3 -337
- package/lib/plugin/pageInfo.js +1 -1
- package/lib/plugin/retryFailedStep.js +13 -14
- package/lib/plugin/retryTo.js +6 -17
- package/lib/plugin/screenshotOnFail.js +4 -5
- package/lib/plugin/standardActingHelpers.js +4 -1
- package/lib/plugin/stepByStepReport.js +1 -1
- package/lib/plugin/tryTo.js +6 -15
- package/lib/recorder.js +1 -0
- package/lib/step/base.js +15 -4
- package/lib/step/comment.js +10 -0
- package/lib/store.js +29 -5
- package/lib/utils.js +1 -1
- package/lib/within.js +2 -0
- package/package.json +18 -18
- package/translations/de-DE.js +4 -3
- package/translations/fr-FR.js +4 -3
- package/translations/index.js +1 -0
- 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 +9 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/promiseBasedTypes.d.ts +0 -652
- package/typings/types.d.ts +99 -655
package/lib/plugin/autoLogin.js
CHANGED
|
@@ -1,339 +1,5 @@
|
|
|
1
|
-
const
|
|
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
|
|
1
|
+
const auth = require('./auth')
|
|
9
2
|
|
|
10
|
-
|
|
11
|
-
fetch: I => I.grabCookie(),
|
|
12
|
-
check: () => {},
|
|
13
|
-
restore: (I, cookies) => {
|
|
14
|
-
I.amOnPage('/') // open a page
|
|
15
|
-
I.setCookie(cookies)
|
|
16
|
-
},
|
|
17
|
-
}
|
|
3
|
+
console.log('autoLogin plugin was renamed to auth plugin. Please update your config.')
|
|
18
4
|
|
|
19
|
-
|
|
20
|
-
saveToFile: false,
|
|
21
|
-
inject: 'login',
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Logs user in for the first test and reuses session for next tests.
|
|
26
|
-
* Works by saving cookies into memory or file.
|
|
27
|
-
* If a session expires automatically logs in again.
|
|
28
|
-
*
|
|
29
|
-
* > For better development experience cookies can be saved into file, so a session can be reused while writing tests.
|
|
30
|
-
*
|
|
31
|
-
* #### Usage
|
|
32
|
-
*
|
|
33
|
-
* 1. Enable this plugin and configure as described below
|
|
34
|
-
* 2. Define user session names (example: `user`, `editor`, `admin`, etc).
|
|
35
|
-
* 3. Define how users are logged in and how to check that user is logged in
|
|
36
|
-
* 4. Use `login` object inside your tests to log in:
|
|
37
|
-
*
|
|
38
|
-
* ```js
|
|
39
|
-
* // inside a test file
|
|
40
|
-
* // use login to inject auto-login function
|
|
41
|
-
* Feature('Login');
|
|
42
|
-
*
|
|
43
|
-
* Before(({ login }) => {
|
|
44
|
-
* login('user'); // login using user session
|
|
45
|
-
* });
|
|
46
|
-
*
|
|
47
|
-
* // Alternatively log in for one scenario.
|
|
48
|
-
* Scenario('log me in', ( { I, login } ) => {
|
|
49
|
-
* login('admin');
|
|
50
|
-
* I.see('I am logged in');
|
|
51
|
-
* });
|
|
52
|
-
* ```
|
|
53
|
-
*
|
|
54
|
-
* #### Configuration
|
|
55
|
-
*
|
|
56
|
-
* * `saveToFile` (default: false) - save cookies to file. Allows to reuse session between execution.
|
|
57
|
-
* * `inject` (default: `login`) - name of the login function to use
|
|
58
|
-
* * `users` - an array containing different session names and functions to:
|
|
59
|
-
* * `login` - sign in into the system
|
|
60
|
-
* * `check` - check that user is logged in
|
|
61
|
-
* * `fetch` - to get current cookies (by default `I.grabCookie()`)
|
|
62
|
-
* * `restore` - to set cookies (by default `I.amOnPage('/'); I.setCookie(cookie)`)
|
|
63
|
-
*
|
|
64
|
-
* #### How It Works
|
|
65
|
-
*
|
|
66
|
-
* 1. `restore` method is executed. It should open a page and set credentials.
|
|
67
|
-
* 2. `check` method is executed. It should reload a page (so cookies are applied) and check that this page belongs to logged-in user. When you pass the second args `session`, you could perform the validation using passed session.
|
|
68
|
-
* 3. If `restore` and `check` were not successful, `login` is executed
|
|
69
|
-
* 4. `login` should fill in login form
|
|
70
|
-
* 5. After successful login, `fetch` is executed to save cookies into memory or file.
|
|
71
|
-
*
|
|
72
|
-
* #### Example: Simple login
|
|
73
|
-
*
|
|
74
|
-
* ```js
|
|
75
|
-
* autoLogin: {
|
|
76
|
-
* enabled: true,
|
|
77
|
-
* saveToFile: true,
|
|
78
|
-
* inject: 'login',
|
|
79
|
-
* users: {
|
|
80
|
-
* admin: {
|
|
81
|
-
* // loginAdmin function is defined in `steps_file.js`
|
|
82
|
-
* login: (I) => I.loginAdmin(),
|
|
83
|
-
* // if we see `Admin` on page, we assume we are logged in
|
|
84
|
-
* check: (I) => {
|
|
85
|
-
* I.amOnPage('/');
|
|
86
|
-
* I.see('Admin');
|
|
87
|
-
* }
|
|
88
|
-
* }
|
|
89
|
-
* }
|
|
90
|
-
* }
|
|
91
|
-
* ```
|
|
92
|
-
*
|
|
93
|
-
* #### Example: Multiple users
|
|
94
|
-
*
|
|
95
|
-
* ```js
|
|
96
|
-
* autoLogin: {
|
|
97
|
-
* enabled: true,
|
|
98
|
-
* saveToFile: true,
|
|
99
|
-
* inject: 'loginAs', // use `loginAs` instead of login
|
|
100
|
-
* users: {
|
|
101
|
-
* user: {
|
|
102
|
-
* login: (I) => {
|
|
103
|
-
* I.amOnPage('/login');
|
|
104
|
-
* I.fillField('email', 'user@site.com');
|
|
105
|
-
* I.fillField('password', '123456');
|
|
106
|
-
* I.click('Login');
|
|
107
|
-
* },
|
|
108
|
-
* check: (I) => {
|
|
109
|
-
* I.amOnPage('/');
|
|
110
|
-
* I.see('User', '.navbar');
|
|
111
|
-
* },
|
|
112
|
-
* },
|
|
113
|
-
* admin: {
|
|
114
|
-
* login: (I) => {
|
|
115
|
-
* I.amOnPage('/login');
|
|
116
|
-
* I.fillField('email', 'admin@site.com');
|
|
117
|
-
* I.fillField('password', '123456');
|
|
118
|
-
* I.click('Login');
|
|
119
|
-
* },
|
|
120
|
-
* check: (I) => {
|
|
121
|
-
* I.amOnPage('/');
|
|
122
|
-
* I.see('Admin', '.navbar');
|
|
123
|
-
* },
|
|
124
|
-
* },
|
|
125
|
-
* }
|
|
126
|
-
* }
|
|
127
|
-
* ```
|
|
128
|
-
*
|
|
129
|
-
* #### Example: Keep cookies between tests
|
|
130
|
-
*
|
|
131
|
-
* If you decide to keep cookies between tests you don't need to save/retrieve cookies between tests.
|
|
132
|
-
* But you need to login once work until session expires.
|
|
133
|
-
* For this case, disable `fetch` and `restore` methods.
|
|
134
|
-
*
|
|
135
|
-
* ```js
|
|
136
|
-
* helpers: {
|
|
137
|
-
* WebDriver: {
|
|
138
|
-
* // config goes here
|
|
139
|
-
* keepCookies: true; // keep cookies for all tests
|
|
140
|
-
* }
|
|
141
|
-
* },
|
|
142
|
-
* plugins: {
|
|
143
|
-
* autoLogin: {
|
|
144
|
-
* users: {
|
|
145
|
-
* admin: {
|
|
146
|
-
* login: (I) => {
|
|
147
|
-
* I.amOnPage('/login');
|
|
148
|
-
* I.fillField('email', 'admin@site.com');
|
|
149
|
-
* I.fillField('password', '123456');
|
|
150
|
-
* I.click('Login');
|
|
151
|
-
* },
|
|
152
|
-
* check: (I) => {
|
|
153
|
-
* I.amOnPage('/dashboard');
|
|
154
|
-
* I.see('Admin', '.navbar');
|
|
155
|
-
* },
|
|
156
|
-
* fetch: () => {}, // empty function
|
|
157
|
-
* restore: () => {}, // empty funciton
|
|
158
|
-
* }
|
|
159
|
-
* }
|
|
160
|
-
* }
|
|
161
|
-
* }
|
|
162
|
-
* ```
|
|
163
|
-
*
|
|
164
|
-
* #### Example: Getting sessions from local storage
|
|
165
|
-
*
|
|
166
|
-
* If your session is stored in local storage instead of cookies you still can obtain sessions.
|
|
167
|
-
*
|
|
168
|
-
* ```js
|
|
169
|
-
* plugins: {
|
|
170
|
-
* autoLogin: {
|
|
171
|
-
* admin: {
|
|
172
|
-
* login: (I) => I.loginAsAdmin(),
|
|
173
|
-
* check: (I) => I.see('Admin', '.navbar'),
|
|
174
|
-
* fetch: (I) => {
|
|
175
|
-
* return I.executeScript(() => localStorage.getItem('session_id'));
|
|
176
|
-
* },
|
|
177
|
-
* restore: (I, session) => {
|
|
178
|
-
* I.amOnPage('/');
|
|
179
|
-
* I.executeScript((session) => localStorage.setItem('session_id', session), session);
|
|
180
|
-
* },
|
|
181
|
-
* }
|
|
182
|
-
* }
|
|
183
|
-
* }
|
|
184
|
-
* ```
|
|
185
|
-
*
|
|
186
|
-
* #### Tips: Using async function in the autoLogin
|
|
187
|
-
*
|
|
188
|
-
* If you use async functions in the autoLogin plugin, login function should be used with `await` keyword.
|
|
189
|
-
*
|
|
190
|
-
* ```js
|
|
191
|
-
* autoLogin: {
|
|
192
|
-
* enabled: true,
|
|
193
|
-
* saveToFile: true,
|
|
194
|
-
* inject: 'login',
|
|
195
|
-
* users: {
|
|
196
|
-
* admin: {
|
|
197
|
-
* login: async (I) => { // If you use async function in the autoLogin plugin
|
|
198
|
-
* const phrase = await I.grabTextFrom('#phrase')
|
|
199
|
-
* I.fillField('username', 'admin'),
|
|
200
|
-
* I.fillField('password', 'password')
|
|
201
|
-
* I.fillField('phrase', phrase)
|
|
202
|
-
* },
|
|
203
|
-
* check: (I) => {
|
|
204
|
-
* I.amOnPage('/');
|
|
205
|
-
* I.see('Admin');
|
|
206
|
-
* },
|
|
207
|
-
* }
|
|
208
|
-
* }
|
|
209
|
-
* }
|
|
210
|
-
* ```
|
|
211
|
-
*
|
|
212
|
-
* ```js
|
|
213
|
-
* Scenario('login', async ( {I, login} ) => {
|
|
214
|
-
* await login('admin') // you should use `await`
|
|
215
|
-
* })
|
|
216
|
-
* ```
|
|
217
|
-
*
|
|
218
|
-
* #### Tips: Using session to validate user
|
|
219
|
-
*
|
|
220
|
-
* Instead of asserting on page elements for the current user in `check`, you can use the `session` you saved in `fetch`
|
|
221
|
-
*
|
|
222
|
-
* ```js
|
|
223
|
-
* autoLogin: {
|
|
224
|
-
* enabled: true,
|
|
225
|
-
* saveToFile: true,
|
|
226
|
-
* inject: 'login',
|
|
227
|
-
* users: {
|
|
228
|
-
* admin: {
|
|
229
|
-
* login: async (I) => { // If you use async function in the autoLogin plugin
|
|
230
|
-
* const phrase = await I.grabTextFrom('#phrase')
|
|
231
|
-
* I.fillField('username', 'admin'),
|
|
232
|
-
* I.fillField('password', 'password')
|
|
233
|
-
* I.fillField('phrase', phrase)
|
|
234
|
-
* },
|
|
235
|
-
* check: (I, session) => {
|
|
236
|
-
* // Throwing an error in `check` will make CodeceptJS perform the login step for the user
|
|
237
|
-
* if (session.profile.email !== the.email.you.expect@some-mail.com) {
|
|
238
|
-
* throw new Error ('Wrong user signed in');
|
|
239
|
-
* }
|
|
240
|
-
* },
|
|
241
|
-
* }
|
|
242
|
-
* }
|
|
243
|
-
* }
|
|
244
|
-
* ```
|
|
245
|
-
*
|
|
246
|
-
* ```js
|
|
247
|
-
* Scenario('login', async ( {I, login} ) => {
|
|
248
|
-
* await login('admin') // you should use `await`
|
|
249
|
-
* })
|
|
250
|
-
*
|
|
251
|
-
*
|
|
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
|
-
)
|
|
262
|
-
|
|
263
|
-
if (config.saveToFile) {
|
|
264
|
-
// loading from file
|
|
265
|
-
for (const name in config.users) {
|
|
266
|
-
const fileName = path.join(global.output_dir, `${name}_session.json`)
|
|
267
|
-
if (!fileExists(fileName)) continue
|
|
268
|
-
const data = fs.readFileSync(fileName).toString()
|
|
269
|
-
try {
|
|
270
|
-
store[`${name}_session`] = JSON.parse(data)
|
|
271
|
-
} catch (err) {
|
|
272
|
-
throw new Error(`Could not load session from ${fileName}\n${err}`)
|
|
273
|
-
}
|
|
274
|
-
debug(`Loaded user session for ${name}`)
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const loginFunction = async name => {
|
|
279
|
-
const userSession = config.users[name]
|
|
280
|
-
const I = container.support('I')
|
|
281
|
-
const cookies = store[`${name}_session`]
|
|
282
|
-
const shouldAwait = isAsyncFunction(userSession.login) || isAsyncFunction(userSession.restore) || isAsyncFunction(userSession.check)
|
|
283
|
-
|
|
284
|
-
const loginAndSave = async () => {
|
|
285
|
-
if (shouldAwait) {
|
|
286
|
-
await userSession.login(I)
|
|
287
|
-
} else {
|
|
288
|
-
userSession.login(I)
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const cookies = await userSession.fetch(I)
|
|
292
|
-
if (!cookies) {
|
|
293
|
-
debug("Cannot save user session with empty cookies from auto login's fetch method")
|
|
294
|
-
return
|
|
295
|
-
}
|
|
296
|
-
if (config.saveToFile) {
|
|
297
|
-
debug(`Saved user session into file for ${name}`)
|
|
298
|
-
fs.writeFileSync(path.join(global.output_dir, `${name}_session.json`), JSON.stringify(cookies))
|
|
299
|
-
}
|
|
300
|
-
store[`${name}_session`] = cookies
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (!cookies) return loginAndSave()
|
|
304
|
-
|
|
305
|
-
recorder.session.start('check login')
|
|
306
|
-
if (shouldAwait) {
|
|
307
|
-
await userSession.restore(I, cookies)
|
|
308
|
-
await userSession.check(I, cookies)
|
|
309
|
-
} else {
|
|
310
|
-
userSession.restore(I, cookies)
|
|
311
|
-
userSession.check(I, cookies)
|
|
312
|
-
}
|
|
313
|
-
recorder.session.catch(err => {
|
|
314
|
-
debug(`Failed auto login for ${name} due to ${err}`)
|
|
315
|
-
debug('Logging in again')
|
|
316
|
-
recorder.session.start('auto login')
|
|
317
|
-
return loginAndSave()
|
|
318
|
-
.then(() => {
|
|
319
|
-
recorder.add(() => recorder.session.restore('auto login'))
|
|
320
|
-
recorder.catch(() => debug('continue'))
|
|
321
|
-
})
|
|
322
|
-
.catch(err => {
|
|
323
|
-
recorder.session.restore('auto login')
|
|
324
|
-
recorder.session.restore('check login')
|
|
325
|
-
recorder.throw(err)
|
|
326
|
-
})
|
|
327
|
-
})
|
|
328
|
-
recorder.add(() => {
|
|
329
|
-
recorder.session.restore('check login')
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
return recorder.promise()
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// adding this to DI container
|
|
336
|
-
const support = {}
|
|
337
|
-
support[config.inject] = loginFunction
|
|
338
|
-
container.append({ support })
|
|
339
|
-
}
|
|
5
|
+
module.exports = auth
|
package/lib/plugin/pageInfo.js
CHANGED
|
@@ -3,7 +3,7 @@ const fs = require('fs')
|
|
|
3
3
|
const Container = require('../container')
|
|
4
4
|
const recorder = require('../recorder')
|
|
5
5
|
const event = require('../event')
|
|
6
|
-
const supportedHelpers =
|
|
6
|
+
const supportedHelpers = Container.STANDARD_ACTING_HELPERS
|
|
7
7
|
const { scanForErrorMessages } = require('../html')
|
|
8
8
|
const { output } = require('..')
|
|
9
9
|
const { humanizeString, ucfirst } = require('../utils')
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
const event = require('../event')
|
|
2
2
|
const recorder = require('../recorder')
|
|
3
|
-
const
|
|
4
|
-
const { log } = require('../output')
|
|
5
|
-
|
|
3
|
+
const store = require('../store')
|
|
6
4
|
const defaultConfig = {
|
|
7
5
|
retries: 3,
|
|
8
6
|
defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
|
|
@@ -70,9 +68,9 @@ const defaultConfig = {
|
|
|
70
68
|
* Use scenario configuration to disable plugin for a test
|
|
71
69
|
*
|
|
72
70
|
* ```js
|
|
73
|
-
* Scenario('scenario tite', () => {
|
|
71
|
+
* Scenario('scenario tite', { disableRetryFailedStep: true }, () => {
|
|
74
72
|
* // test goes here
|
|
75
|
-
* })
|
|
73
|
+
* })
|
|
76
74
|
* ```
|
|
77
75
|
*
|
|
78
76
|
*/
|
|
@@ -85,19 +83,14 @@ module.exports = config => {
|
|
|
85
83
|
|
|
86
84
|
const when = err => {
|
|
87
85
|
if (!enableRetry) return
|
|
88
|
-
const store = require('../store')
|
|
89
86
|
if (store.debugMode) return false
|
|
87
|
+
if (!store.autoRetries) return false
|
|
90
88
|
if (customWhen) return customWhen(err)
|
|
91
89
|
return true
|
|
92
90
|
}
|
|
93
91
|
config.when = when
|
|
94
92
|
|
|
95
93
|
event.dispatcher.on(event.step.started, step => {
|
|
96
|
-
if (process.env.TRY_TO === 'true') {
|
|
97
|
-
log('Info: RetryFailedStep plugin is disabled inside tryTo block')
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
94
|
// if a step is ignored - return
|
|
102
95
|
for (const ignored of config.ignoredSteps) {
|
|
103
96
|
if (step.name === ignored) return
|
|
@@ -113,9 +106,15 @@ module.exports = config => {
|
|
|
113
106
|
})
|
|
114
107
|
|
|
115
108
|
event.dispatcher.on(event.test.before, test => {
|
|
116
|
-
|
|
117
|
-
//
|
|
118
|
-
|
|
109
|
+
// pass disableRetryFailedStep is a preferred way to disable retries
|
|
110
|
+
// test.disableRetryFailedStep is used for backward compatibility
|
|
111
|
+
if (test.opts.disableRetryFailedStep || test.disableRetryFailedStep) {
|
|
112
|
+
store.autoRetries = false
|
|
113
|
+
return // disable retry when a test is not active
|
|
114
|
+
}
|
|
115
|
+
// this option is used to set the retries inside _before() block of helpers
|
|
116
|
+
store.autoRetries = true
|
|
117
|
+
test.opts.conditionalRetries = config.retries
|
|
119
118
|
recorder.retry(config)
|
|
120
119
|
})
|
|
121
120
|
}
|
package/lib/plugin/retryTo.js
CHANGED
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
const { retryTo } = require('../effects')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
You should update your tests to use it as follows:
|
|
7
|
-
|
|
8
|
-
\`\`\`javascript
|
|
9
|
-
const { retryTo } = require('codeceptjs/effects');
|
|
10
|
-
|
|
11
|
-
// Example: Retry these steps 5 times before failing
|
|
12
|
-
await retryTo((tryNum) => {
|
|
13
|
-
I.switchTo('#editor frame');
|
|
14
|
-
I.click('Open');
|
|
15
|
-
I.see('Opened');
|
|
16
|
-
}, 5);
|
|
17
|
-
\`\`\`
|
|
3
|
+
const defaultConfig = {
|
|
4
|
+
registerGlobal: true,
|
|
5
|
+
}
|
|
18
6
|
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
module.exports = function (config) {
|
|
8
|
+
config = Object.assign(defaultConfig, config)
|
|
9
|
+
console.log(`Deprecation Warning: 'retryTo' has been moved to the 'codeceptjs/effects' module. Disable retryTo plugin to remove this warning.`)
|
|
21
10
|
|
|
22
11
|
if (config.registerGlobal) {
|
|
23
12
|
global.retryTo = retryTo
|
|
@@ -15,7 +15,7 @@ const defaultConfig = {
|
|
|
15
15
|
fullPageScreenshots: false,
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const supportedHelpers =
|
|
18
|
+
const supportedHelpers = Container.STANDARD_ACTING_HELPERS
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Creates screenshot on failure. Screenshot is saved into `output` directory.
|
|
@@ -83,13 +83,12 @@ module.exports = function (config) {
|
|
|
83
83
|
async () => {
|
|
84
84
|
const dataType = 'image/png'
|
|
85
85
|
// This prevents data driven to be included in the failed screenshot file name
|
|
86
|
-
let fileName
|
|
86
|
+
let fileName
|
|
87
87
|
|
|
88
88
|
if (options.uniqueScreenshotNames && test) {
|
|
89
|
-
|
|
90
|
-
fileName = `${fileName.substring(0, 10)}_${uuid}.failed.png`
|
|
89
|
+
fileName = `${testToFileName(test, _getUUID(test))}.failed.png`
|
|
91
90
|
} else {
|
|
92
|
-
fileName
|
|
91
|
+
fileName = `${testToFileName(test)}.failed.png`
|
|
93
92
|
}
|
|
94
93
|
output.plugin('screenshotOnFail', 'Test failed, try to save a screenshot')
|
|
95
94
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
const
|
|
1
|
+
const Container = require('../container')
|
|
2
|
+
// due to using this in internal tooling we won't post deprecation warning
|
|
3
|
+
// but please switch to Container.STANDARD_ACTING_HELPERS
|
|
4
|
+
const standardActingHelpers = Container.STANDARD_ACTING_HELPERS
|
|
2
5
|
|
|
3
6
|
module.exports = standardActingHelpers
|
|
@@ -12,7 +12,7 @@ const event = require('../event')
|
|
|
12
12
|
const output = require('../output')
|
|
13
13
|
const { template, deleteDir } = require('../utils')
|
|
14
14
|
|
|
15
|
-
const supportedHelpers =
|
|
15
|
+
const supportedHelpers = Container.STANDARD_ACTING_HELPERS
|
|
16
16
|
|
|
17
17
|
const defaultConfig = {
|
|
18
18
|
deleteSuccessful: true,
|
package/lib/plugin/tryTo.js
CHANGED
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
const { tryTo } = require('../effects')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
You should update your tests to use it as follows:
|
|
7
|
-
|
|
8
|
-
\`\`\`javascript
|
|
9
|
-
const { tryTo } = require('codeceptjs/effects');
|
|
10
|
-
|
|
11
|
-
// Example: failed step won't fail a test but will return true/false
|
|
12
|
-
await tryTo(() => {
|
|
13
|
-
I.switchTo('#editor frame');
|
|
14
|
-
});
|
|
15
|
-
\`\`\`
|
|
3
|
+
const defaultConfig = {
|
|
4
|
+
registerGlobal: true,
|
|
5
|
+
}
|
|
16
6
|
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
module.exports = function (config) {
|
|
8
|
+
config = Object.assign(defaultConfig, config)
|
|
9
|
+
console.log(`Deprecation Warning: 'tryTo' has been moved to the 'codeceptjs/effects' module. Disable tryTo plugin to remove this warning.`)
|
|
19
10
|
|
|
20
11
|
if (config.registerGlobal) {
|
|
21
12
|
global.tryTo = tryTo
|
package/lib/recorder.js
CHANGED
|
@@ -192,6 +192,7 @@ module.exports = {
|
|
|
192
192
|
.pop()
|
|
193
193
|
// no retries or unnamed tasks
|
|
194
194
|
debug(`${currentQueue()} Running | ${taskName} | Timeout: ${timeout || 'None'}`)
|
|
195
|
+
if (retryOpts) debug(`${currentQueue()} Retry opts`, JSON.stringify(retryOpts))
|
|
195
196
|
|
|
196
197
|
if (!retryOpts || !taskName || !retry) {
|
|
197
198
|
const [promise, timer] = getTimeoutPromise(timeout, taskName)
|
package/lib/step/base.js
CHANGED
|
@@ -2,6 +2,7 @@ const color = require('chalk')
|
|
|
2
2
|
const Secret = require('../secret')
|
|
3
3
|
const { getCurrentTimeout } = require('../timeout')
|
|
4
4
|
const { ucfirst, humanizeString, serializeError } = require('../utils')
|
|
5
|
+
const recordStep = require('./record')
|
|
5
6
|
|
|
6
7
|
const STACK_LINE = 5
|
|
7
8
|
|
|
@@ -24,8 +25,7 @@ class Step {
|
|
|
24
25
|
this.opts = {}
|
|
25
26
|
/** @member {string} */
|
|
26
27
|
this.actor = 'I' // I = actor
|
|
27
|
-
|
|
28
|
-
this.helperMethod = name // helper method
|
|
28
|
+
|
|
29
29
|
/** @member {string} */
|
|
30
30
|
this.status = 'pending'
|
|
31
31
|
/** @member {string} */
|
|
@@ -37,6 +37,13 @@ class Step {
|
|
|
37
37
|
/** @member {string} */
|
|
38
38
|
this.stack = ''
|
|
39
39
|
|
|
40
|
+
// These are part of HelperStep class
|
|
41
|
+
// but left here for types compatibility
|
|
42
|
+
/** @member {any} */
|
|
43
|
+
this.helper = null
|
|
44
|
+
/** @member {string} */
|
|
45
|
+
this.helperMethod = name
|
|
46
|
+
|
|
40
47
|
this.startTime = 0
|
|
41
48
|
this.endTime = 0
|
|
42
49
|
|
|
@@ -51,6 +58,10 @@ class Step {
|
|
|
51
58
|
throw new Error('Not implemented')
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
addToRecorder(args) {
|
|
62
|
+
return recordStep(this, args)
|
|
63
|
+
}
|
|
64
|
+
|
|
54
65
|
/**
|
|
55
66
|
* @returns {number|undefined}
|
|
56
67
|
*/
|
|
@@ -190,8 +201,8 @@ class Step {
|
|
|
190
201
|
args.push(arg.name)
|
|
191
202
|
} else if (typeof arg == 'string') {
|
|
192
203
|
args.push(arg)
|
|
193
|
-
} else {
|
|
194
|
-
args.push(JSON.stringify(arg).slice(0, 300))
|
|
204
|
+
} else if (arg) {
|
|
205
|
+
args.push((JSON.stringify(arg) || '').slice(0, 300))
|
|
195
206
|
}
|
|
196
207
|
}
|
|
197
208
|
}
|
package/lib/store.js
CHANGED
|
@@ -3,17 +3,41 @@
|
|
|
3
3
|
* @namespace
|
|
4
4
|
*/
|
|
5
5
|
const store = {
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* If we are in --debug mode
|
|
8
|
+
* @type {boolean}
|
|
9
|
+
*/
|
|
7
10
|
debugMode: false,
|
|
8
|
-
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Is timeouts enabled
|
|
14
|
+
* @type {boolean}
|
|
15
|
+
*/
|
|
9
16
|
timeouts: true,
|
|
10
|
-
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* If auto-retries are enabled by retryFailedStep plugin
|
|
20
|
+
* tryTo effect disables them
|
|
21
|
+
* @type {boolean}
|
|
22
|
+
*/
|
|
23
|
+
autoRetries: false,
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Tests are executed via dry-run
|
|
27
|
+
* @type {boolean}
|
|
28
|
+
*/
|
|
11
29
|
dryRun: false,
|
|
12
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* If we are in pause mode
|
|
32
|
+
* @type {boolean}
|
|
33
|
+
*/
|
|
13
34
|
onPause: false,
|
|
35
|
+
|
|
36
|
+
// current object states
|
|
37
|
+
|
|
14
38
|
/** @type {CodeceptJS.Test | null} */
|
|
15
39
|
currentTest: null,
|
|
16
|
-
/** @type {
|
|
40
|
+
/** @type {CodeceptJS.Step | null} */
|
|
17
41
|
currentStep: null,
|
|
18
42
|
/** @type {CodeceptJS.Suite | null} */
|
|
19
43
|
currentSuite: null,
|
package/lib/utils.js
CHANGED
|
@@ -13,7 +13,7 @@ function deepMerge(target, source) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
module.exports.genTestId = test => {
|
|
16
|
-
return require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64').slice(0, -2)
|
|
16
|
+
return this.clearString(require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64').slice(0, -2))
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
module.exports.deepMerge = deepMerge
|
package/lib/within.js
CHANGED