codeceptjs 3.6.4-beta.2 → 3.6.5-beta.1
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 -63
- package/lib/ai.js +47 -1
- package/lib/assert/empty.js +19 -19
- package/lib/assert/equal.js +32 -30
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +42 -42
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +17 -18
- package/lib/command/configMigrate.js +57 -52
- package/lib/command/definitions.js +88 -88
- package/lib/command/dryRun.js +65 -63
- package/lib/command/generate.js +191 -181
- package/lib/command/info.js +39 -37
- package/lib/command/init.js +289 -286
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +22 -22
- package/lib/command/run-workers.js +63 -63
- package/lib/command/run.js +24 -26
- package/lib/command/utils.js +64 -63
- package/lib/data/context.js +60 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/helper/AI.js +114 -35
- package/lib/helper/ApiDataFactory.js +72 -69
- package/lib/helper/Appium.js +409 -379
- package/lib/helper/ExpectHelper.js +214 -248
- package/lib/helper/FileSystem.js +77 -78
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +49 -50
- package/lib/helper/JSONResponse.js +64 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -12
- package/lib/helper/Nightmare.js +664 -572
- package/lib/helper/Playwright.js +1320 -1211
- package/lib/helper/Protractor.js +663 -629
- package/lib/helper/Puppeteer.js +1232 -1124
- package/lib/helper/REST.js +115 -69
- package/lib/helper/TestCafe.js +490 -491
- package/lib/helper/WebDriver.js +1294 -1156
- package/lib/history.js +16 -3
- package/lib/interfaces/bdd.js +38 -51
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +122 -111
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -23
- 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 -51
- package/lib/listener/timeout.js +53 -53
- package/lib/pause.js +17 -3
- package/lib/plugin/allure.js +14 -14
- package/lib/plugin/autoDelay.js +29 -36
- package/lib/plugin/autoLogin.js +70 -66
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +92 -77
- package/lib/plugin/customLocator.js +20 -19
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +37 -37
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +66 -63
- package/lib/plugin/pauseOnFail.js +10 -10
- package/lib/plugin/retryFailedStep.js +31 -38
- package/lib/plugin/retryTo.js +28 -28
- package/lib/plugin/screenshotOnFail.js +107 -86
- package/lib/plugin/selenoid.js +131 -117
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +102 -92
- package/lib/plugin/stepTimeout.js +23 -22
- package/lib/plugin/subtitles.js +34 -34
- package/lib/plugin/tryTo.js +39 -29
- package/lib/plugin/wdio.js +77 -72
- package/lib/template/heal.js +11 -14
- package/package.json +5 -3
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -9
- 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 +42 -19
- package/typings/promiseBasedTypes.d.ts +280 -1
- package/typings/types.d.ts +76 -1
package/lib/helper/REST.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
const axios = require('axios').default
|
|
2
|
-
const Helper = require('@codeceptjs/helper')
|
|
3
|
-
const
|
|
1
|
+
const axios = require('axios').default
|
|
2
|
+
const Helper = require('@codeceptjs/helper')
|
|
3
|
+
const { Agent } = require('https')
|
|
4
|
+
const Secret = require('../secret')
|
|
4
5
|
|
|
5
|
-
const { beautify } = require('../utils')
|
|
6
|
+
const { beautify } = require('../utils')
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* ## Configuration
|
|
@@ -14,11 +15,12 @@ const { beautify } = require('../utils');
|
|
|
14
15
|
* @prop {boolean} [printCurl=false] - print cURL request on console logs. False by default.
|
|
15
16
|
* @prop {number} [timeout=1000] - timeout for requests in milliseconds. 10000ms by default.
|
|
16
17
|
* @prop {object} [defaultHeaders] - a list of default headers.
|
|
18
|
+
* @prop {object} [httpAgent] - create an agent with SSL certificate
|
|
17
19
|
* @prop {function} [onRequest] - an async function which can update request object.
|
|
18
20
|
* @prop {function} [onResponse] - an async function which can update response object.
|
|
19
21
|
* @prop {number} [maxUploadFileSize] - set the max content file size in MB when performing api calls.
|
|
20
22
|
*/
|
|
21
|
-
const config = {}
|
|
23
|
+
const config = {}
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* REST helper allows to send additional requests to the REST API during acceptance tests.
|
|
@@ -42,6 +44,25 @@ const config = {};
|
|
|
42
44
|
*}
|
|
43
45
|
* ```
|
|
44
46
|
*
|
|
47
|
+
* With httpAgent
|
|
48
|
+
*
|
|
49
|
+
* ```js
|
|
50
|
+
* {
|
|
51
|
+
* helpers: {
|
|
52
|
+
* REST: {
|
|
53
|
+
* endpoint: 'http://site.com/api',
|
|
54
|
+
* prettyPrintJson: true,
|
|
55
|
+
* httpAgent: {
|
|
56
|
+
* key: fs.readFileSync(__dirname + '/path/to/keyfile.key'),
|
|
57
|
+
* cert: fs.readFileSync(__dirname + '/path/to/certfile.cert'),
|
|
58
|
+
* rejectUnauthorized: false,
|
|
59
|
+
* keepAlive: true
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
45
66
|
* ## Access From Helpers
|
|
46
67
|
*
|
|
47
68
|
* Send REST requests by accessing `_executeRequest` method:
|
|
@@ -57,7 +78,7 @@ const config = {};
|
|
|
57
78
|
*/
|
|
58
79
|
class REST extends Helper {
|
|
59
80
|
constructor(config) {
|
|
60
|
-
super(config)
|
|
81
|
+
super(config)
|
|
61
82
|
this.options = {
|
|
62
83
|
timeout: 10000,
|
|
63
84
|
defaultHeaders: {},
|
|
@@ -65,39 +86,51 @@ class REST extends Helper {
|
|
|
65
86
|
prettyPrintJson: false,
|
|
66
87
|
onRequest: null,
|
|
67
88
|
onResponse: null,
|
|
68
|
-
}
|
|
89
|
+
}
|
|
69
90
|
|
|
70
91
|
if (this.options.maxContentLength) {
|
|
71
|
-
const maxContentLength = this.options.maxUploadFileSize * 1024 * 1024
|
|
72
|
-
this.options.maxContentLength = maxContentLength
|
|
73
|
-
this.options.maxBodyLength = maxContentLength
|
|
92
|
+
const maxContentLength = this.options.maxUploadFileSize * 1024 * 1024
|
|
93
|
+
this.options.maxContentLength = maxContentLength
|
|
94
|
+
this.options.maxBodyLength = maxContentLength
|
|
74
95
|
}
|
|
75
96
|
|
|
76
97
|
// override defaults with config
|
|
77
|
-
this._setConfig(config)
|
|
98
|
+
this._setConfig(config)
|
|
78
99
|
|
|
79
|
-
this.headers = { ...this.options.defaultHeaders }
|
|
80
|
-
|
|
100
|
+
this.headers = { ...this.options.defaultHeaders }
|
|
101
|
+
|
|
102
|
+
// Create an agent with SSL certificate
|
|
103
|
+
if (this.options.httpAgent) {
|
|
104
|
+
if (!this.options.httpAgent.key || !this.options.httpAgent.cert)
|
|
105
|
+
throw Error('Please recheck your httpAgent config!')
|
|
106
|
+
this.httpsAgent = new Agent(this.options.httpAgent)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.axios = this.httpsAgent ? axios.create({ httpsAgent: this.httpsAgent }) : axios.create()
|
|
81
110
|
// @ts-ignore
|
|
82
|
-
this.axios.defaults.headers = this.options.defaultHeaders
|
|
111
|
+
this.axios.defaults.headers = this.options.defaultHeaders
|
|
83
112
|
}
|
|
84
113
|
|
|
85
114
|
static _config() {
|
|
86
115
|
return [
|
|
87
|
-
{
|
|
88
|
-
|
|
116
|
+
{
|
|
117
|
+
name: 'endpoint',
|
|
118
|
+
message: 'Endpoint of API you are going to test',
|
|
119
|
+
default: 'http://localhost:3000/api',
|
|
120
|
+
},
|
|
121
|
+
]
|
|
89
122
|
}
|
|
90
123
|
|
|
91
124
|
static _checkRequirements() {
|
|
92
125
|
try {
|
|
93
|
-
require('axios')
|
|
126
|
+
require('axios')
|
|
94
127
|
} catch (e) {
|
|
95
|
-
return ['axios']
|
|
128
|
+
return ['axios']
|
|
96
129
|
}
|
|
97
130
|
}
|
|
98
131
|
|
|
99
132
|
_before() {
|
|
100
|
-
this.headers = { ...this.options.defaultHeaders }
|
|
133
|
+
this.headers = { ...this.options.defaultHeaders }
|
|
101
134
|
}
|
|
102
135
|
|
|
103
136
|
/**
|
|
@@ -106,7 +139,7 @@ class REST extends Helper {
|
|
|
106
139
|
* @param {object} headers headers list
|
|
107
140
|
*/
|
|
108
141
|
haveRequestHeaders(headers) {
|
|
109
|
-
this.headers = { ...this.headers, ...headers }
|
|
142
|
+
this.headers = { ...this.headers, ...headers }
|
|
110
143
|
}
|
|
111
144
|
|
|
112
145
|
/**
|
|
@@ -120,7 +153,7 @@ class REST extends Helper {
|
|
|
120
153
|
* @param {string | CodeceptJS.Secret} accessToken Bearer access token
|
|
121
154
|
*/
|
|
122
155
|
amBearerAuthenticated(accessToken) {
|
|
123
|
-
this.haveRequestHeaders({ Authorization: `Bearer ${accessToken}` })
|
|
156
|
+
this.haveRequestHeaders({ Authorization: `Bearer ${accessToken}` })
|
|
124
157
|
}
|
|
125
158
|
|
|
126
159
|
/**
|
|
@@ -132,55 +165,65 @@ class REST extends Helper {
|
|
|
132
165
|
*/
|
|
133
166
|
async _executeRequest(request) {
|
|
134
167
|
// Add custom headers. They can be set by amBearerAuthenticated() or haveRequestHeaders()
|
|
135
|
-
request.headers = { ...this.headers, ...request.headers }
|
|
168
|
+
request.headers = { ...this.headers, ...request.headers }
|
|
136
169
|
|
|
137
|
-
const _debugRequest = { ...request }
|
|
138
|
-
this.axios.defaults.timeout = request.timeout || this.options.timeout
|
|
170
|
+
const _debugRequest = { ...request }
|
|
171
|
+
this.axios.defaults.timeout = request.timeout || this.options.timeout
|
|
139
172
|
|
|
140
173
|
if (this.headers && this.headers.auth) {
|
|
141
|
-
request.auth = this.headers.auth
|
|
174
|
+
request.auth = this.headers.auth
|
|
142
175
|
}
|
|
143
176
|
|
|
144
177
|
if (typeof request.data === 'object') {
|
|
145
|
-
const returnedValue = {}
|
|
178
|
+
const returnedValue = {}
|
|
146
179
|
for (const [key, value] of Object.entries(request.data)) {
|
|
147
|
-
returnedValue[key] = value
|
|
148
|
-
if (value instanceof Secret) returnedValue[key] = value.getMasked()
|
|
180
|
+
returnedValue[key] = value
|
|
181
|
+
if (value instanceof Secret) returnedValue[key] = value.getMasked()
|
|
149
182
|
}
|
|
150
|
-
_debugRequest.data = returnedValue
|
|
183
|
+
_debugRequest.data = returnedValue
|
|
151
184
|
}
|
|
152
185
|
|
|
153
186
|
if (request.data instanceof Secret) {
|
|
154
|
-
_debugRequest.data = '*****'
|
|
155
|
-
request.data =
|
|
187
|
+
_debugRequest.data = '*****'
|
|
188
|
+
request.data =
|
|
189
|
+
typeof request.data === 'object' && !(request.data instanceof Secret)
|
|
190
|
+
? { ...request.data.toString() }
|
|
191
|
+
: request.data.toString()
|
|
156
192
|
}
|
|
157
193
|
|
|
158
|
-
if (
|
|
194
|
+
if (typeof request.data === 'string') {
|
|
159
195
|
if (!request.headers || !request.headers['Content-Type']) {
|
|
160
|
-
request.headers = { ...request.headers, ...{ 'Content-Type': 'application/x-www-form-urlencoded' } }
|
|
196
|
+
request.headers = { ...request.headers, ...{ 'Content-Type': 'application/x-www-form-urlencoded' } }
|
|
161
197
|
}
|
|
162
198
|
}
|
|
163
199
|
|
|
164
200
|
if (this.config.onRequest) {
|
|
165
|
-
await this.config.onRequest(request)
|
|
201
|
+
await this.config.onRequest(request)
|
|
166
202
|
}
|
|
167
203
|
|
|
168
|
-
this.options.prettyPrintJson
|
|
169
|
-
|
|
204
|
+
this.options.prettyPrintJson
|
|
205
|
+
? this.debugSection('Request', beautify(JSON.stringify(_debugRequest)))
|
|
206
|
+
: this.debugSection('Request', JSON.stringify(_debugRequest))
|
|
170
207
|
|
|
171
|
-
|
|
208
|
+
if (this.options.printCurl) {
|
|
209
|
+
this.debugSection('CURL Request', curlize(request));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let response
|
|
172
213
|
try {
|
|
173
|
-
response = await this.axios(request)
|
|
214
|
+
response = await this.axios(request)
|
|
174
215
|
} catch (err) {
|
|
175
|
-
if (!err.response) throw err
|
|
176
|
-
this.debugSection('Response', `Response error. Status code: ${err.response.status}`)
|
|
177
|
-
response = err.response
|
|
216
|
+
if (!err.response) throw err
|
|
217
|
+
this.debugSection('Response', `Response error. Status code: ${err.response.status}`)
|
|
218
|
+
response = err.response
|
|
178
219
|
}
|
|
179
220
|
if (this.config.onResponse) {
|
|
180
|
-
await this.config.onResponse(response)
|
|
221
|
+
await this.config.onResponse(response)
|
|
181
222
|
}
|
|
182
|
-
this.options.prettyPrintJson
|
|
183
|
-
|
|
223
|
+
this.options.prettyPrintJson
|
|
224
|
+
? this.debugSection('Response', beautify(JSON.stringify(response.data)))
|
|
225
|
+
: this.debugSection('Response', JSON.stringify(response.data))
|
|
226
|
+
return response
|
|
184
227
|
}
|
|
185
228
|
|
|
186
229
|
/**
|
|
@@ -189,7 +232,7 @@ class REST extends Helper {
|
|
|
189
232
|
* @param {*} url
|
|
190
233
|
*/
|
|
191
234
|
_url(url) {
|
|
192
|
-
return /^\w+\:\/\//.test(url) ? url : this.options.endpoint + url
|
|
235
|
+
return /^\w+\:\/\//.test(url) ? url : this.options.endpoint + url
|
|
193
236
|
}
|
|
194
237
|
|
|
195
238
|
/**
|
|
@@ -202,7 +245,7 @@ class REST extends Helper {
|
|
|
202
245
|
* @param {number} newTimeout - timeout in milliseconds
|
|
203
246
|
*/
|
|
204
247
|
setRequestTimeout(newTimeout) {
|
|
205
|
-
this.options.timeout = newTimeout
|
|
248
|
+
this.options.timeout = newTimeout
|
|
206
249
|
}
|
|
207
250
|
|
|
208
251
|
/**
|
|
@@ -221,8 +264,8 @@ class REST extends Helper {
|
|
|
221
264
|
const request = {
|
|
222
265
|
baseURL: this._url(url),
|
|
223
266
|
headers,
|
|
224
|
-
}
|
|
225
|
-
return this._executeRequest(request)
|
|
267
|
+
}
|
|
268
|
+
return this._executeRequest(request)
|
|
226
269
|
}
|
|
227
270
|
|
|
228
271
|
/**
|
|
@@ -248,14 +291,14 @@ class REST extends Helper {
|
|
|
248
291
|
method: 'POST',
|
|
249
292
|
data: payload,
|
|
250
293
|
headers,
|
|
251
|
-
}
|
|
294
|
+
}
|
|
252
295
|
|
|
253
296
|
if (this.options.maxContentLength) {
|
|
254
|
-
request.maxContentLength = this.options.maxContentLength
|
|
255
|
-
request.maxBodyLength = this.options.maxContentLength
|
|
297
|
+
request.maxContentLength = this.options.maxContentLength
|
|
298
|
+
request.maxBodyLength = this.options.maxContentLength
|
|
256
299
|
}
|
|
257
300
|
|
|
258
|
-
return this._executeRequest(request)
|
|
301
|
+
return this._executeRequest(request)
|
|
259
302
|
}
|
|
260
303
|
|
|
261
304
|
/**
|
|
@@ -281,14 +324,14 @@ class REST extends Helper {
|
|
|
281
324
|
method: 'PATCH',
|
|
282
325
|
data: payload,
|
|
283
326
|
headers,
|
|
284
|
-
}
|
|
327
|
+
}
|
|
285
328
|
|
|
286
329
|
if (this.options.maxContentLength) {
|
|
287
|
-
request.maxContentLength = this.options.maxContentLength
|
|
288
|
-
request.maxBodyLength = this.options.maxBodyLength
|
|
330
|
+
request.maxContentLength = this.options.maxContentLength
|
|
331
|
+
request.maxBodyLength = this.options.maxBodyLength
|
|
289
332
|
}
|
|
290
333
|
|
|
291
|
-
return this._executeRequest(request)
|
|
334
|
+
return this._executeRequest(request)
|
|
292
335
|
}
|
|
293
336
|
|
|
294
337
|
/**
|
|
@@ -314,14 +357,14 @@ class REST extends Helper {
|
|
|
314
357
|
method: 'PUT',
|
|
315
358
|
data: payload,
|
|
316
359
|
headers,
|
|
317
|
-
}
|
|
360
|
+
}
|
|
318
361
|
|
|
319
362
|
if (this.options.maxContentLength) {
|
|
320
|
-
request.maxContentLength = this.options.maxContentLength
|
|
321
|
-
request.maxBodyLength = this.options.maxBodyLength
|
|
363
|
+
request.maxContentLength = this.options.maxContentLength
|
|
364
|
+
request.maxBodyLength = this.options.maxBodyLength
|
|
322
365
|
}
|
|
323
366
|
|
|
324
|
-
return this._executeRequest(request)
|
|
367
|
+
return this._executeRequest(request)
|
|
325
368
|
}
|
|
326
369
|
|
|
327
370
|
/**
|
|
@@ -341,28 +384,31 @@ class REST extends Helper {
|
|
|
341
384
|
baseURL: this._url(url),
|
|
342
385
|
method: 'DELETE',
|
|
343
386
|
headers,
|
|
344
|
-
}
|
|
387
|
+
}
|
|
345
388
|
|
|
346
|
-
return this._executeRequest(request)
|
|
389
|
+
return this._executeRequest(request)
|
|
347
390
|
}
|
|
348
391
|
}
|
|
349
|
-
|
|
392
|
+
|
|
393
|
+
module.exports = REST
|
|
350
394
|
|
|
351
395
|
function curlize(request) {
|
|
352
|
-
|
|
396
|
+
if (request.data?.constructor.name.toLowerCase() === 'formdata') return 'cURL is not printed as the request body is not a JSON'
|
|
397
|
+
let curl = `curl --location --request ${request.method ? request.method.toUpperCase() : 'GET'} ${request.baseURL} `.replace("'", '')
|
|
353
398
|
|
|
354
399
|
if (request.headers) {
|
|
355
400
|
Object.entries(request.headers).forEach(([key, value]) => {
|
|
356
|
-
curl += `-H "${key}: ${value}"
|
|
357
|
-
})
|
|
401
|
+
curl += `-H "${key}: ${value}" `
|
|
402
|
+
})
|
|
358
403
|
}
|
|
359
404
|
|
|
360
405
|
if (!curl.toLowerCase().includes('content-type: application/json')) {
|
|
361
|
-
curl += '-H "Content-Type: application/json" '
|
|
406
|
+
curl += '-H "Content-Type: application/json" '
|
|
362
407
|
}
|
|
363
408
|
|
|
364
409
|
if (request.data) {
|
|
365
|
-
curl += `-d '${JSON.stringify(request.data)}'
|
|
410
|
+
curl += `-d '${JSON.stringify(request.data)}'`
|
|
366
411
|
}
|
|
367
|
-
return curl
|
|
412
|
+
return curl
|
|
368
413
|
}
|
|
414
|
+
|