codeceptjs 3.2.3 → 3.3.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/CHANGELOG.md +50 -0
- package/docs/advanced.md +0 -4
- package/docs/api.md +227 -188
- package/docs/build/ApiDataFactory.js +13 -6
- package/docs/build/Appium.js +36 -36
- package/docs/build/GraphQL.js +11 -0
- package/docs/build/JSONResponse.js +297 -0
- package/docs/build/Nightmare.js +48 -48
- package/docs/build/Playwright.js +261 -146
- package/docs/build/Puppeteer.js +76 -67
- package/docs/build/REST.js +36 -0
- package/docs/build/TestCafe.js +44 -44
- package/docs/build/WebDriver.js +69 -69
- package/docs/helpers/ApiDataFactory.md +7 -0
- package/docs/helpers/Appium.md +3 -3
- package/docs/helpers/JSONResponse.md +230 -0
- package/docs/helpers/Playwright.md +282 -218
- package/docs/helpers/Puppeteer.md +9 -1
- package/docs/helpers/REST.md +30 -9
- package/docs/installation.md +2 -0
- package/docs/internal-api.md +265 -0
- package/docs/playwright.md +70 -15
- package/docs/plugins.md +125 -29
- package/docs/puppeteer.md +24 -8
- package/docs/quickstart.md +2 -3
- package/docs/reports.md +43 -2
- package/docs/translation.md +1 -1
- package/docs/videos.md +2 -2
- package/docs/webdriver.md +90 -2
- package/lib/command/init.js +5 -15
- package/lib/config.js +17 -13
- package/lib/helper/ApiDataFactory.js +13 -6
- package/lib/helper/Appium.js +3 -3
- package/lib/helper/GraphQL.js +11 -0
- package/lib/helper/JSONResponse.js +297 -0
- package/lib/helper/Playwright.js +199 -84
- package/lib/helper/Puppeteer.js +12 -3
- package/lib/helper/REST.js +36 -0
- package/lib/helper/extras/Console.js +8 -0
- package/lib/helper/extras/PlaywrightRestartOpts.js +35 -0
- package/lib/interfaces/bdd.js +3 -1
- package/lib/plugin/allure.js +12 -0
- package/lib/plugin/eachElement.js +127 -0
- package/lib/utils.js +20 -0
- package/package.json +24 -23
- package/translations/pt-BR.js +8 -0
- package/typings/index.d.ts +2 -0
- package/typings/types.d.ts +237 -11
|
@@ -257,13 +257,16 @@ class ApiDataFactory extends Helper {
|
|
|
257
257
|
* // create user with defined email
|
|
258
258
|
* // and receive it when inside async function
|
|
259
259
|
* const user = await I.have('user', { email: 'user@user.com'});
|
|
260
|
+
* // create a user with options that will not be included in the final request
|
|
261
|
+
* I.have('user', { }, { age: 33, height: 55 })
|
|
260
262
|
* ```
|
|
261
263
|
*
|
|
262
264
|
* @param {*} factory factory to use
|
|
263
265
|
* @param {*} params predefined parameters
|
|
266
|
+
* @param {*} options options for programmatically generate the attributes
|
|
264
267
|
*/
|
|
265
|
-
have(factory, params) {
|
|
266
|
-
const item = this._createItem(factory, params);
|
|
268
|
+
have(factory, params, options) {
|
|
269
|
+
const item = this._createItem(factory, params, options);
|
|
267
270
|
this.debug(`Creating ${factory} ${JSON.stringify(item)}`);
|
|
268
271
|
return this._requestCreate(factory, item);
|
|
269
272
|
}
|
|
@@ -277,21 +280,25 @@ class ApiDataFactory extends Helper {
|
|
|
277
280
|
*
|
|
278
281
|
* // create 3 posts by one author
|
|
279
282
|
* I.haveMultiple('post', 3, { author: 'davert' });
|
|
283
|
+
*
|
|
284
|
+
* // create 3 posts by one author with options
|
|
285
|
+
* I.haveMultiple('post', 3, { author: 'davert' }, { publish_date: '01.01.1997' });
|
|
280
286
|
* ```
|
|
281
287
|
*
|
|
282
288
|
* @param {*} factory
|
|
283
289
|
* @param {*} times
|
|
284
290
|
* @param {*} params
|
|
291
|
+
* @param {*} options
|
|
285
292
|
*/
|
|
286
|
-
haveMultiple(factory, times, params) {
|
|
293
|
+
haveMultiple(factory, times, params, options) {
|
|
287
294
|
const promises = [];
|
|
288
295
|
for (let i = 0; i < times; i++) {
|
|
289
|
-
promises.push(this.have(factory, params));
|
|
296
|
+
promises.push(this.have(factory, params, options));
|
|
290
297
|
}
|
|
291
298
|
return Promise.all(promises);
|
|
292
299
|
}
|
|
293
300
|
|
|
294
|
-
_createItem(model, data) {
|
|
301
|
+
_createItem(model, data, options) {
|
|
295
302
|
if (!this.factories[model]) {
|
|
296
303
|
throw new Error(`Factory ${model} is not defined in config`);
|
|
297
304
|
}
|
|
@@ -303,7 +310,7 @@ class ApiDataFactory extends Helper {
|
|
|
303
310
|
modulePath = path.join(global.codecept_dir, modulePath);
|
|
304
311
|
}
|
|
305
312
|
const builder = require(modulePath);
|
|
306
|
-
return builder.build(data);
|
|
313
|
+
return builder.build(data, options);
|
|
307
314
|
} catch (err) {
|
|
308
315
|
throw new Error(`Couldn't load factory file from ${modulePath}, check that
|
|
309
316
|
|
package/lib/helper/Appium.js
CHANGED
|
@@ -976,11 +976,11 @@ class Appium extends Webdriver {
|
|
|
976
976
|
* Perform a swipe on the screen.
|
|
977
977
|
*
|
|
978
978
|
* ```js
|
|
979
|
-
* I.
|
|
979
|
+
* I.performSwipe({ x: 300, y: 100 }, { x: 200, y: 100 });
|
|
980
980
|
* ```
|
|
981
981
|
*
|
|
982
|
-
* @param {
|
|
983
|
-
* @param {
|
|
982
|
+
* @param {object} from
|
|
983
|
+
* @param {object} to
|
|
984
984
|
*
|
|
985
985
|
* Appium: support Android and iOS
|
|
986
986
|
*/
|
package/lib/helper/GraphQL.js
CHANGED
|
@@ -59,6 +59,12 @@ class GraphQL extends Helper {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
static _config() {
|
|
63
|
+
return [
|
|
64
|
+
{ name: 'endpoint', message: 'Endpoint of API you are going to test', default: 'http://localhost:3000/graphql' },
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
62
68
|
/**
|
|
63
69
|
* Executes query via axios call
|
|
64
70
|
*
|
|
@@ -92,6 +98,11 @@ class GraphQL extends Helper {
|
|
|
92
98
|
);
|
|
93
99
|
response = err.response;
|
|
94
100
|
}
|
|
101
|
+
|
|
102
|
+
if (this.config.onResponse) {
|
|
103
|
+
await this.config.onResponse(response);
|
|
104
|
+
}
|
|
105
|
+
|
|
95
106
|
this.debugSection('Response', JSON.stringify(response.data));
|
|
96
107
|
return response;
|
|
97
108
|
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
const chai = require('chai');
|
|
2
|
+
const joi = require('joi');
|
|
3
|
+
const chaiDeepMatch = require('chai-deep-match');
|
|
4
|
+
const Helper = require('../helper');
|
|
5
|
+
|
|
6
|
+
chai.use(chaiDeepMatch);
|
|
7
|
+
|
|
8
|
+
const { expect } = chai;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* This helper allows performing assertions on JSON responses paired with following helpers:
|
|
12
|
+
*
|
|
13
|
+
* * REST
|
|
14
|
+
* * GraphQL
|
|
15
|
+
* * Playwright
|
|
16
|
+
*
|
|
17
|
+
* It can check status codes, response data, response structure.
|
|
18
|
+
*
|
|
19
|
+
*
|
|
20
|
+
* ## Configuration
|
|
21
|
+
*
|
|
22
|
+
* * `requestHelper` - a helper which will perform requests. `REST` by default, also `Playwright` or `GraphQL` can be used. Custom helpers must have `onResponse` hook in their config, which will be executed when request is performed.
|
|
23
|
+
*
|
|
24
|
+
* ### Examples
|
|
25
|
+
*
|
|
26
|
+
* Zero-configuration when paired with REST:
|
|
27
|
+
*
|
|
28
|
+
* ```js
|
|
29
|
+
* // inside codecept.conf.js
|
|
30
|
+
*{
|
|
31
|
+
* helpers: {
|
|
32
|
+
* REST: {
|
|
33
|
+
* endpoint: 'http://site.com/api',
|
|
34
|
+
* },
|
|
35
|
+
* JSONResponse: {}
|
|
36
|
+
* }
|
|
37
|
+
*}
|
|
38
|
+
* ```
|
|
39
|
+
* Explicitly setting request helper if you use `makeApiRequest` of Playwright to perform requests and not paired REST:
|
|
40
|
+
*
|
|
41
|
+
* ```js
|
|
42
|
+
* // inside codecept.conf.js
|
|
43
|
+
* // ...
|
|
44
|
+
* helpers: {
|
|
45
|
+
* Playwright: {
|
|
46
|
+
* url: 'https://localhost',
|
|
47
|
+
* browser: 'chromium',
|
|
48
|
+
* },
|
|
49
|
+
* JSONResponse: {
|
|
50
|
+
* requestHelper: 'Playwright',
|
|
51
|
+
* }
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
* ## Access From Helpers
|
|
55
|
+
*
|
|
56
|
+
* If you plan to add custom assertions it is recommended to create a helper that will retrieve response object from JSONResponse:
|
|
57
|
+
*
|
|
58
|
+
*
|
|
59
|
+
* ```js
|
|
60
|
+
* // inside custom helper
|
|
61
|
+
* const response = this.helpers.JSONResponse.response;
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* ## Methods
|
|
65
|
+
*/
|
|
66
|
+
class JSONResponse extends Helper {
|
|
67
|
+
constructor(config = {}) {
|
|
68
|
+
super(config);
|
|
69
|
+
this.options = {
|
|
70
|
+
requestHelper: 'REST',
|
|
71
|
+
};
|
|
72
|
+
this.options = { ...this.options, ...config };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_beforeSuite() {
|
|
76
|
+
this.response = null;
|
|
77
|
+
if (!this.helpers[this.options.requestHelper]) {
|
|
78
|
+
throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`);
|
|
79
|
+
}
|
|
80
|
+
// connect to REST helper
|
|
81
|
+
this.helpers[this.options.requestHelper].config.onResponse = (response) => {
|
|
82
|
+
this.response = response;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_before() {
|
|
87
|
+
this.response = null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static _checkRequirements() {
|
|
91
|
+
try {
|
|
92
|
+
require('joi');
|
|
93
|
+
require('chai');
|
|
94
|
+
} catch (e) {
|
|
95
|
+
return ['joi'];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Checks that response code is equal to the provided one
|
|
101
|
+
*
|
|
102
|
+
* ```js
|
|
103
|
+
* I.seeResponseCodeIs(200);
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @param {number} code
|
|
107
|
+
*/
|
|
108
|
+
seeResponseCodeIs(code) {
|
|
109
|
+
this._checkResponseReady();
|
|
110
|
+
expect(this.response.status).to.eql(code, 'Response code is not the same as expected');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Checks that response code is not equal to the provided one
|
|
115
|
+
*
|
|
116
|
+
* ```js
|
|
117
|
+
* I.dontSeeResponseCodeIs(500);
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @param {number} code
|
|
121
|
+
*/
|
|
122
|
+
dontSeeResponseCodeIs(code) {
|
|
123
|
+
this._checkResponseReady();
|
|
124
|
+
expect(this.response.status).not.to.eql(code);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Checks that the response code is 4xx
|
|
129
|
+
*/
|
|
130
|
+
seeResponseCodeIsClientError() {
|
|
131
|
+
this._checkResponseReady();
|
|
132
|
+
expect(this.response.status).to.be.gte(400);
|
|
133
|
+
expect(this.response.status).to.be.lt(500);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Checks that the response code is 3xx
|
|
138
|
+
*/
|
|
139
|
+
seeResponseCodeIsRedirection() {
|
|
140
|
+
this._checkResponseReady();
|
|
141
|
+
expect(this.response.status).to.be.gte(300);
|
|
142
|
+
expect(this.response.status).to.be.lt(400);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Checks that the response code is 5xx
|
|
147
|
+
*/
|
|
148
|
+
seeResponseCodeIsServerError() {
|
|
149
|
+
this._checkResponseReady();
|
|
150
|
+
expect(this.response.status).to.be.gte(500);
|
|
151
|
+
expect(this.response.status).to.be.lt(600);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Checks that the response code is 2xx
|
|
156
|
+
* Use it instead of seeResponseCodeIs(200) if server can return 204 instead.
|
|
157
|
+
*
|
|
158
|
+
* ```js
|
|
159
|
+
* I.seeResponseCodeIsSuccessful();
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
seeResponseCodeIsSuccessful() {
|
|
163
|
+
this._checkResponseReady();
|
|
164
|
+
expect(this.response.status).to.be.gte(200);
|
|
165
|
+
expect(this.response.status).to.be.lt(300);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Checks for deep inclusion of a provided json in a response data.
|
|
170
|
+
*
|
|
171
|
+
* ```js
|
|
172
|
+
* // response.data == { user: { name: 'jon', email: 'jon@doe.com' } }
|
|
173
|
+
*
|
|
174
|
+
* I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* @param {object} json
|
|
178
|
+
*/
|
|
179
|
+
seeResponseContainsJson(json = {}) {
|
|
180
|
+
this._checkResponseReady();
|
|
181
|
+
expect(this.response.data).to.deep.match(json);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Checks for deep inclusion of a provided json in a response data.
|
|
186
|
+
*
|
|
187
|
+
* ```js
|
|
188
|
+
* // response.data == { data: { user: 1 } }
|
|
189
|
+
*
|
|
190
|
+
* I.dontSeeResponseContainsJson({ user: 2 });
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* @param {object} json
|
|
194
|
+
*/
|
|
195
|
+
dontSeeResponseContainsJson(json = {}) {
|
|
196
|
+
this._checkResponseReady();
|
|
197
|
+
expect(this.response.data).not.to.deep.match(json);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Checks for deep inclusion of a provided json in a response data.
|
|
202
|
+
*
|
|
203
|
+
* ```js
|
|
204
|
+
* // response.data == { user: { name: 'jon', email: 'jon@doe.com' } }
|
|
205
|
+
*
|
|
206
|
+
* I.seeResponseContainsKeys(['user']);
|
|
207
|
+
* ```
|
|
208
|
+
*
|
|
209
|
+
* @param {array} keys
|
|
210
|
+
*/
|
|
211
|
+
seeResponseContainsKeys(keys = []) {
|
|
212
|
+
this._checkResponseReady();
|
|
213
|
+
expect(this.response.data).to.include.keys(keys);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Executes a callback function passing in `response` object and chai assertions with `expect`
|
|
218
|
+
* Use it to perform custom checks of response data
|
|
219
|
+
*
|
|
220
|
+
* ```js
|
|
221
|
+
* I.seeResponseValidByCallback({ data, status, expect } => {
|
|
222
|
+
* expect(status).to.eql(200);
|
|
223
|
+
* expect(data).keys.to.include(['user', 'company']);
|
|
224
|
+
* });
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
227
|
+
* @param {function} fn
|
|
228
|
+
*/
|
|
229
|
+
seeResponseValidByCallback(fn) {
|
|
230
|
+
this._checkResponseReady();
|
|
231
|
+
fn({ ...this.response, expect });
|
|
232
|
+
const body = fn.toString();
|
|
233
|
+
fn.toString = () => `${body.split('\n')[1]}...`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Checks that response data equals to expected:
|
|
238
|
+
*
|
|
239
|
+
* ```js
|
|
240
|
+
* // response.data is { error: 'Not allowed' }
|
|
241
|
+
*
|
|
242
|
+
* I.seeResponseEquals({ error: 'Not allowed' })
|
|
243
|
+
* ```
|
|
244
|
+
* @param {object} resp
|
|
245
|
+
*/
|
|
246
|
+
seeResponseEquals(resp) {
|
|
247
|
+
this._checkResponseReady();
|
|
248
|
+
expect(this.response.data).to.deep.equal(resp);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Validates JSON structure of response using [joi library](https://joi.dev).
|
|
253
|
+
* See [joi API](https://joi.dev/api/) for complete reference on usage.
|
|
254
|
+
*
|
|
255
|
+
* Use pre-initialized joi instance by passing function callback:
|
|
256
|
+
*
|
|
257
|
+
* ```js
|
|
258
|
+
* // response.data is { name: 'jon', id: 1 }
|
|
259
|
+
*
|
|
260
|
+
* I.seeResponseMatchesJsonSchema(joi => {
|
|
261
|
+
* return joi.object({
|
|
262
|
+
* name: joi.string();
|
|
263
|
+
* id: joi.number();
|
|
264
|
+
* })
|
|
265
|
+
* });
|
|
266
|
+
*
|
|
267
|
+
* // or pass a valid schema
|
|
268
|
+
* const joi = require('joi);
|
|
269
|
+
*
|
|
270
|
+
* I.seeResponseMatchesJsonSchema(joi.object({
|
|
271
|
+
* name: joi.string();
|
|
272
|
+
* id: joi.number();
|
|
273
|
+
* });
|
|
274
|
+
* ```
|
|
275
|
+
*
|
|
276
|
+
* @param {any} fnOrSchema
|
|
277
|
+
*/
|
|
278
|
+
seeResponseMatchesJsonSchema(fnOrSchema) {
|
|
279
|
+
this._checkResponseReady();
|
|
280
|
+
let schema = fnOrSchema;
|
|
281
|
+
if (typeof fnOrSchema === 'function') {
|
|
282
|
+
schema = fnOrSchema(joi);
|
|
283
|
+
const body = fnOrSchema.toString();
|
|
284
|
+
fnOrSchema.toString = () => `${body.split('\n')[1]}...`;
|
|
285
|
+
}
|
|
286
|
+
if (!schema) throw new Error('Empty Joi schema provided, see https://joi.dev/ for details');
|
|
287
|
+
if (!joi.isSchema(schema)) throw new Error('Invalid Joi schema provided, see https://joi.dev/ for details');
|
|
288
|
+
schema.toString = () => schema.describe();
|
|
289
|
+
joi.assert(this.response.data, schema);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
_checkResponseReady() {
|
|
293
|
+
if (!this.response) throw new Error('Response is not available');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
module.exports = JSONResponse;
|