codeceptjs 3.2.3 → 3.3.0-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.
Files changed (48) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/docs/advanced.md +0 -4
  3. package/docs/api.md +227 -188
  4. package/docs/build/ApiDataFactory.js +13 -6
  5. package/docs/build/Appium.js +36 -36
  6. package/docs/build/GraphQL.js +11 -0
  7. package/docs/build/JSONResponse.js +297 -0
  8. package/docs/build/Nightmare.js +48 -48
  9. package/docs/build/Playwright.js +261 -146
  10. package/docs/build/Puppeteer.js +76 -67
  11. package/docs/build/REST.js +36 -0
  12. package/docs/build/TestCafe.js +44 -44
  13. package/docs/build/WebDriver.js +69 -69
  14. package/docs/helpers/ApiDataFactory.md +7 -0
  15. package/docs/helpers/Appium.md +3 -3
  16. package/docs/helpers/JSONResponse.md +230 -0
  17. package/docs/helpers/Playwright.md +282 -218
  18. package/docs/helpers/Puppeteer.md +9 -1
  19. package/docs/helpers/REST.md +30 -9
  20. package/docs/installation.md +2 -0
  21. package/docs/internal-api.md +265 -0
  22. package/docs/playwright.md +70 -15
  23. package/docs/plugins.md +125 -29
  24. package/docs/puppeteer.md +24 -8
  25. package/docs/quickstart.md +2 -3
  26. package/docs/reports.md +43 -2
  27. package/docs/translation.md +1 -1
  28. package/docs/videos.md +2 -2
  29. package/docs/webdriver.md +90 -2
  30. package/lib/command/init.js +5 -15
  31. package/lib/config.js +17 -13
  32. package/lib/helper/ApiDataFactory.js +13 -6
  33. package/lib/helper/Appium.js +3 -3
  34. package/lib/helper/GraphQL.js +11 -0
  35. package/lib/helper/JSONResponse.js +297 -0
  36. package/lib/helper/Playwright.js +199 -84
  37. package/lib/helper/Puppeteer.js +12 -3
  38. package/lib/helper/REST.js +36 -0
  39. package/lib/helper/extras/Console.js +8 -0
  40. package/lib/helper/extras/PlaywrightRestartOpts.js +35 -0
  41. package/lib/interfaces/bdd.js +3 -1
  42. package/lib/plugin/allure.js +12 -0
  43. package/lib/plugin/eachElement.js +127 -0
  44. package/lib/utils.js +20 -0
  45. package/package.json +6 -4
  46. package/translations/pt-BR.js +8 -0
  47. package/typings/index.d.ts +2 -0
  48. package/typings/types.d.ts +237 -11
package/CHANGELOG.md CHANGED
@@ -1,3 +1,53 @@
1
+ ## 3.3.0
2
+
3
+ 🛩️ Features:
4
+
5
+ * [**API Testing introduced**](/api)
6
+ * Introduced [`JSONResponse`](/helpers/JSONResponse) helper which connects to REST, GraphQL or Playwright helper
7
+ * [REST] Added `amBearerAuthenticated` method
8
+ * [REST] Added `haveRequestHeaders` method
9
+ * Added dependency on `joi` and `chai`
10
+ * [Playwright] Added `timeout` option to set [timeout](https://playwright.dev/docs/api/class-page#page-set-default-timeout) for all Playwright actions. If an action fails, Playwright keeps retrying it for a time set by timeout.
11
+ * [Playwright] **Possible breaking change.** By default `timeout` is set to 1000ms. *Previous default was set by Playwright internally to 30s. This was causing contradiction to CodeceptJS retries, so triggered up to 3 retries for 30s of time. This timeout option was lowered so retryFailedStep plugin would not cause long delays.*
12
+ * [Playwright] Extended methods to provide more options from engine. These methods were updated so additional options can be be passed as the last argument:
13
+ * [`click`](/helpers/Playwright#click)
14
+ * [`dragAndDrop`](/helpers/Playwright#dragAndDrop)
15
+ * [`checkOption`](/helpers/Playwright#checkOption)
16
+ * [`uncheckOption`](/helpers/Playwright#uncheckOption)
17
+
18
+ ```js
19
+ // use Playwright click options as 3rd argument
20
+ I.click('canvas', '.model', { position: { x: 20, y: 40 } })
21
+ // check option also has options
22
+ I.checkOption('Agree', '.signup', { position: { x: 5, y: 5 } })
23
+ ```
24
+
25
+ * `eachElement` plugin introduced. It allows you to iterate over elements and perform some action on them using direct engines API
26
+
27
+ ```js
28
+ await eachElement('click all links in .list', '.list a', (el) => {
29
+ await el.click();
30
+ })
31
+ ```
32
+ * [Playwright] Added support to `playwright-core` package if `playwright` is not installed. See #3190, fixes #2663.
33
+ * [Playwright] Added `makeApiRequest` action to perform API requests. Requires Playwright >= 1.18
34
+ * Added support to `codecept.config.js` for name consistency across other JS tools. See motivation at #3195 by @JiLiZART
35
+ * [ApiDataFactory] Added options arg to `have` method. See #3197 by @JJlokidoki
36
+ * Improved pt-br translations to include keywords: 'Funcionalidade', 'Cenário', 'Antes', 'Depois', 'AntesDaSuite', 'DepoisDaSuite'. See #3206 by @danilolutz
37
+ * [allure plugin] Introduced `addStep` method to add comments and attachments. See #3104 by @EgorBodnar
38
+
39
+ 🐛 Bugfixes:
40
+
41
+ * Fixed #3212: using Regex flags for Cucumber steps. See #3214 by @anils92
42
+
43
+ 📖 Documentation
44
+
45
+ * Added [Testomat.io reporter](/reporters#testomatio)
46
+ * Added [api testing](/api) guides
47
+ * Added [internal api](/internal-api) guides
48
+ * [Appium] Fixed documentation for `performSwipe`
49
+ * [Playwright] update docs for `usePlaywrightTo` method by @dbudzins
50
+
1
51
  ## 3.2.3
2
52
 
3
53
  * Documentation improvements by @maojunxyz
package/docs/advanced.md CHANGED
@@ -100,11 +100,7 @@ Scenario('update user profile', ({ }) => {
100
100
  All tests with `@tag` could be executed with `--grep '@tag'` option.
101
101
 
102
102
  ```sh
103
- <<<<<<< HEAD
104
- npx codeceptjs run --grep @slow
105
- =======
106
103
  codeceptjs run --grep '@slow'
107
- >>>>>>> 435964dff7770cb3cd58c78a8579b6221a000d24
108
104
  ```
109
105
 
110
106
  Use regex for more flexible filtering:
package/docs/api.md CHANGED
@@ -1,265 +1,304 @@
1
1
  ---
2
- permalink: /internal-api
3
- title: Internal API
2
+ permalink: /api
3
+ title: API Testing
4
4
  ---
5
5
 
6
- ## Concepts
6
+ ## API Testing
7
7
 
8
- In this guide we will overview the internal API of CodeceptJS.
9
- This knowledge is required for customization, writing plugins, etc.
8
+ CodeceptJS provides a way to write tests in declarative manner for REST and GraphQL APIs.
10
9
 
11
- CodeceptJS provides an API which can be loaded via `require('codeceptjs')` when CodeceptJS is installed locally. Otherwise, you can load codeceptjs API via global `codeceptjs` object:
10
+ Take a look:
12
11
 
13
12
  ```js
14
- // via module
15
- const { recorder, event, output } = require('codeceptjs');
16
- // or using global object
17
- const { recorder, event, output } = codeceptjs;
13
+ I.sendGetRequest('/users/1');
14
+ // returns { "user": { "name": "jon" }, "projects": [] }
15
+ I.seeResponseCodeIsSuccessful();
16
+ I.seeResponseContainsKeys(['user', 'projects']);
17
+ I.seeResponseContainsJson({ user: { name: 'jon' } });
18
+ I.seeResponseMatchesJsonSchema($ => {
19
+ return $.object(
20
+ user: $.object({
21
+ name: $.string(),
22
+ }),
23
+ projects: $.array()
24
+ )
25
+ });
18
26
  ```
27
+ In this code we checked API request for:
19
28
 
20
- These internal objects are available:
29
+ * status code
30
+ * data inclusion
31
+ * data structure
21
32
 
22
- * [`codecept`](https://github.com/Codeception/CodeceptJS/blob/master/lib/codecept.js): test runner class
23
- * [`config`](https://github.com/Codeception/CodeceptJS/blob/master/lib/config.js): current codecept config
24
- * [`event`](https://github.com/Codeception/CodeceptJS/blob/master/lib/event.js): event listener
25
- * [`recorder`](https://github.com/Codeception/CodeceptJS/blob/master/lib/recorder.js): global promise chain
26
- * [`output`](https://github.com/Codeception/CodeceptJS/blob/master/lib/output.js): internal printer
27
- * [`container`](https://github.com/Codeception/CodeceptJS/blob/master/lib/container.js): dependency injection container for tests, includes current helpers and support objects
28
- * [`helper`](https://github.com/Codeception/CodeceptJS/blob/master/lib/helper.js): basic helper class
29
- * [`actor`](https://github.com/Codeception/CodeceptJS/blob/master/lib/actor.js): basic actor (I) class
33
+ These are the things you should generally test your APIs for.
30
34
 
31
- [API reference](https://github.com/Codeception/CodeceptJS/tree/master/docs/api) is available on GitHub.
32
- Also please check the source code of corresponding modules.
35
+ > 🤓 It is recommended to check only invariable parts of responses. Check for required fields and only values you control. For instance, it is not recommended to check id fields, date fields, as they can be frequently changed.
33
36
 
34
- ### Container
37
+ ## Installation
35
38
 
36
- CodeceptJS has a dependency injection container with helpers and support objects.
37
- They can be retrieved from the container:
39
+ Install CodeceptJS if it is not installed yet.
38
40
 
39
- ```js
40
- const { container } = require('codeceptjs');
41
-
42
- // get object with all helpers
43
- const helpers = container.helpers();
41
+ ```
42
+ npm i codeceptjs --save-dev
43
+ ```
44
44
 
45
- // get helper by name
46
- const { WebDriver } = container.helpers();
45
+ Initialize CodeceptJS and select REST or GraphQL helper when asked for a helper:
47
46
 
48
- // get support objects
49
- const supportObjects = container.support();
47
+ ```
48
+ npx codeceptjs init
49
+ ```
50
50
 
51
- // get support object by name
52
- const { UserPage } = container.support();
51
+ ## Configuration
53
52
 
54
- // get all registered plugins
55
- const plugins = container.plugins();
56
- ```
53
+ Ensure that inside `codecept.conf.js` in helpers section `REST` or `GraphQL` helpers are enabled.
57
54
 
58
- New objects can also be added to container in runtime:
55
+ * If you use `REST` helper add `JSONResponse` helper below with no extra config:
59
56
 
60
57
  ```js
61
- const { container } = require('codeceptjs');
58
+ // inside codecept.conf.js
59
+ // ...
60
+ helpers: {
61
+ REST: {
62
+ endpoint: 'http://localhost:3000/api'
63
+ },
64
+ // .. add JSONResponse helper here
65
+ JSONResponse: {}
66
+ }
67
+ ```
68
+ * If you use `GraphQL` helper add `JSONResponse` helper, configuring it to use GraphQL for requests:
62
69
 
63
- container.append({
64
- helpers: { // add helper
65
- MyHelper: new MyHelper({ config1: 'val1' });
66
- },
67
- support: { // add page object
68
- UserPage: require('./pages/user');
70
+ ```js
71
+ helpers: {
72
+ GraphQL: {
73
+ endpoint: 'http://localhost:3000/graphql'
74
+ },
75
+ // .. add JSONResponse helper here
76
+ JSONResponse: {
77
+ requestHelper: 'GraphQL',
78
+ }
69
79
  }
70
- })
71
80
  ```
72
81
 
73
- > Use this trick to define custom objects inside `boostrap` script
82
+ Originally, REST and GraphQL helpers were not designed for API testing.
83
+ They were used to perform API requests for browser tests. As so, they lack assertion methods to API responses.
74
84
 
75
- The container also contains the current Mocha instance:
85
+ [`JSONResponse`](/helpers/JSONResponse/) helper adds response assertions.
76
86
 
77
- ```js
78
- const mocha = container.mocha();
79
- ```
87
+ > 💡 In CodeceptJS assertions start with `see` prefix. Learn more about assertions by [opening reference for JSONResponse](/helpers/JSONResponse/) helper.
80
88
 
81
- ### Event Listeners
89
+ After helpers were configured, you can start writing first API test. By default, CodeceptJS saves tests in `tests` directory and uses `*_test.js` suffix. The `init` command created the first test for you to start.
82
90
 
83
- CodeceptJS provides a module with an [event dispatcher and set of predefined events](https://github.com/Codeception/CodeceptJS/blob/master/lib/event.js).
84
91
 
85
- It can be required from codeceptjs package if it is installed locally.
92
+ ## Requests
93
+
94
+ [REST](/helpers/REST/) or [GraphQL](/helpers/GraphQL/) helpers implement methods for making API requests.
95
+ Both helpers send requests via HTTP protocol from CodeceptJS process.
96
+ For most cases, you will need to have authentication. It can be passed via headers, which can be added to helper's configuration in `codecept.conf.js`.
86
97
 
87
98
  ```js
88
- const { event } = require('codeceptjs');
99
+ helpers: {
100
+ REST: {
101
+ defaultHeaders: {
102
+ // use Bearer Authorization
103
+ 'Authorization': 'Bearer 11111',
104
+ 'Content-Type': 'application/json',
105
+ 'Accept': 'application/json',
106
+ },
107
+ }
108
+ }
109
+ ```
89
110
 
90
- module.exports = function() {
111
+ Or you can use the browser cookies if you are running browser session.
112
+ In this case use `setSharedCookies()` from `@codeceptjs/configure` package:
91
113
 
92
- event.dispatcher.on(event.test.before, function (test) {
114
+ ```js
115
+ const { setSharedCookies } = require('@codeceptjs/configure');
93
116
 
94
- console.log('--- I am before test --');
117
+ // add this before exports.config
118
+ setSharedCookies();
95
119
 
96
- });
120
+ exports.config = {
121
+ // ...
122
+ helpers: {
123
+ // also works with Playwright or Puppeteer
124
+ WebDriver: {
125
+ //...
126
+ },
127
+
128
+ REST: {
129
+ // ...
130
+ }
131
+ }
97
132
  }
98
133
  ```
99
134
 
100
- Available events:
135
+ ### REST
101
136
 
102
- * `event.test.before(test)` - *async* when `Before` hooks from helpers and from test is executed
103
- * `event.test.after(test)` - *async* after each test
104
- * `event.test.started(test)` - *sync* at the very beginning of a test.
105
- * `event.test.passed(test)` - *sync* when test passed
106
- * `event.test.failed(test, error)` - *sync* when test failed
107
- * `event.test.finished(test)` - *sync* when test finished
108
- * `event.suite.before(suite)` - *async* before a suite
109
- * `event.suite.after(suite)` - *async* after a suite
110
- * `event.step.before(step)` - *async* when the step is scheduled for execution
111
- * `event.step.after(step)`- *async* after a step
112
- * `event.step.started(step)` - *sync* when step starts.
113
- * `event.step.passed(step)` - *sync* when step passed.
114
- * `event.step.failed(step, err)` - *sync* when step failed.
115
- * `event.step.finished(step)` - *sync* when step finishes.
116
- * `event.step.comment(step)` - *sync* fired for comments like `I.say`.
117
- * `event.all.before` - before running tests
118
- * `event.all.after` - after running tests
119
- * `event.all.result` - when results are printed
120
- * `event.workers.before` - before spawning workers in parallel run
121
- * `event.workers.after` - after workers finished in parallel run
137
+ REST helper can send GET/POST/PATCH/etc requests to REST API endpoint:
122
138
 
139
+ * [`I.sendGetRequest()`](/helpers/REST#sendGetRequest)
140
+ * [`I.sendPostRequest()`](/helpers/REST#sendPostRequest)
141
+ * [`I.sendPutRequest()`](/helpers/REST#sendPutRequest)
142
+ * [`I.sendPatchRequest()`](/helpers/REST#sendPatchRequest)
143
+ * [`I.sendDeleteRequest()`](/helpers/REST#sendDeleteRequest)
144
+ * ...
123
145
 
124
- > *sync* - means that event is fired in the moment of the action happening.
125
- *async* - means that event is fired when an action is scheduled. Use `recorder` to schedule your actions.
146
+ Authentication headers can be set in [helper's config](https://codecept.io/helpers/REST/#configuration) or per test with headers or special methods like `I.amBearerAuthenticated`.
126
147
 
127
- For further reference look for [currently available listeners](https://github.com/Codeception/CodeceptJS/tree/master/lib/listener) using the event system.
148
+ Example:
128
149
 
150
+ ```js
151
+ // this way we pass Bearer token
152
+ I.amBearerAuthenticated(secret('token-is-here'));
153
+ // for custom authorization with headers use
154
+ // I.haveRequestHeaders method
155
+
156
+ // here we send a POST request
157
+ const response = await I.sendPostRequest('/users', {
158
+ name: 'joe',
159
+ email: 'joe@mail.com'
160
+ });
161
+ // usually we won't need direct access to response object for API testing
162
+ // but you can obtain it from request
163
+
164
+ // check the last request was successful
165
+ // this method introduced by JSONResponse helper
166
+ I.seeResponseCodeIsSuccessful();
167
+ ```
129
168
 
130
- ### Recorder
131
-
132
- To inject asynchronous functions in a test or before/after a test you can subscribe to corresponding event and register a function inside a recorder object. [Recorder](https://github.com/Codeception/CodeceptJS/blob/master/lib/recorder.js) represents a global promises chain.
169
+ ### GraphQL
133
170
 
134
- Provide a function in the first parameter, a function must be async or must return a promise:
171
+ GraphQL have request format different then in REST API, but the response format is the same.
172
+ It's plain old JSON. This why `JSONResponse` helper works for both API types.
173
+ Configure authorization headers in `codecept.conf.js` and make your first query:
135
174
 
136
175
  ```js
137
- const { event, recorder } = require('codeceptjs');
138
-
139
- module.exports = function() {
140
-
141
- event.dispatcher.on(event.test.before, function (test) {
142
-
143
- const request = require('request');
144
-
145
- recorder.add('create fixture data via API', function() {
146
- return new Promise((doneFn, errFn) => {
147
- request({
148
- baseUrl: 'http://api.site.com/',
149
- method: 'POST',
150
- url: '/users',
151
- json: { name: 'john', email: 'john@john.com' }
152
- }), (err, httpResponse, body) => {
153
- if (err) return errFn(err);
154
- doneFn();
155
- }
156
- });
157
- }
158
- });
159
- }
176
+ // make GraphQL query or mutation
177
+ const resp = await I.sendQuery('{ user(id: 0) { id name email }}');
178
+ I.seeResponseCodeIsSuccessful();
179
+
180
+ // GraphQL always returns key data as part of response
181
+ I.seeResponseContainsKeys(['data']);
182
+
183
+ // check data for partial inclusion
184
+ I.seeResponseContainsJson({
185
+ data: {
186
+ user: {
187
+ name: 'john doe',
188
+ email: 'johnd@mutex.com',
189
+ },
190
+ },
191
+ });
160
192
  ```
161
193
 
162
- ### Config
194
+ GraphQL helper has two methods available:
195
+
196
+ * [`I.sendQuery()`](/helpers/GraphQL#sendQuery)
197
+ * [`I.sendMutation()`](/helpers/GraphQL#sendMutation)
163
198
 
164
- CodeceptJS config can be accessed from `require('codeceptjs').config.get()`:
199
+ ## Assertions
200
+
201
+ `JSONResponse` provides set of assertions for responses in JSON format. These assertions were designed to check only invariable parts of responses. So instead of checking that response equals to the one provided, we will check for data inclusion and structure matching.
202
+
203
+ For most of cases, you won't need to perform assertions by accessing `response` object directly. All assretions are performed under hood inside `JSONResponse` module. It is recommended to keep it that way, to keep tests readable and make test log to contain all assertions.
165
204
 
166
205
  ```js
167
- const { config } = require('codeceptjs');
206
+ Scenario('I make API call', ({ I }) => {
207
+ // request was made by REST
208
+ // or by GraphQL helper
168
209
 
169
- // config object has access to all values of the current config file
210
+ // check that response code is 2xx
211
+ I.seeResponseCodeIsSuccessful();
170
212
 
171
- if (config.get().myKey == 'value') {
172
- // run something
173
- }
213
+ // check that response contains keys
214
+ I.seeResponseContainsKeys(['data', 'pages', 'meta']);
215
+ });
174
216
  ```
175
217
 
218
+ ### Response Status Codes
176
219
 
177
- ### Output
220
+ [Response status codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) can be checked to be equal to some value or to be in a specific range.
221
+ To check that response code is `200` call `I.seeResponseCodeIs`:
178
222
 
179
- Output module provides four verbosity levels. Depending on the mode you can have different information printed using corresponding functions.
223
+ ```js
224
+ I.seeResponseCodeIs(200);
225
+ ```
226
+ But because other response codes in 2xx range are also valid responses, you can use `seeResponseCodeIsSuccessful()` which will match 200 (OK), 201 (Created), 206 (Partial Content) and others. Methods to check 3xx, 4xx, 5xx response statuses also available.
180
227
 
181
- * `default`: prints basic information using `output.print`
182
- * `steps`: toggled by `--steps` option, prints step execution
183
- * `debug`: toggled by `--debug` option, prints steps, and debug information with `output.debug`
184
- * `verbose`: toggled by `--verbose` prints debug information and internal logs with `output.log`
228
+ ```js
229
+ // matches 200, 201, 202, ... 206
230
+ I.seeResponseCodeIsSuccessful();
185
231
 
186
- It is recommended to avoid `console.log` and use output.* methods for printing.
232
+ // matches 300...308
233
+ I.seeResponseCodeIsRedirection();
187
234
 
188
- ```js
189
- const output = require('codeceptjs').output;
235
+ // matches 400..451
236
+ I.seeResponseCodeIsClientError();
190
237
 
191
- output.print('This is basic information');
192
- output.debug('This is debug information');
193
- output.log('This is verbose logging information');
238
+ // matches 500-511
239
+ I.seeResponseCodeIsServerError();
194
240
  ```
195
241
 
196
- #### Test Object
242
+ ### Structure
197
243
 
198
- The test events are providing a test object with following properties:
244
+ The most basic thing to check in response is existence of keys in JSON object. Use [`I.seeResponseContainsKeys()`](/helpers/JSONResponse#seeResponseContainsKeys) method for it:
199
245
 
200
- * `title` title of the test
201
- * `body` test function as a string
202
- * `opts` additional test options like retries, and others
203
- * `pending` true if test is scheduled for execution and false if a test has finished
204
- * `tags` array of tags for this test
205
- * `artifacts` list of files attached to this test. Screenshots, videos and other files can be saved here and shared accross different reporters
206
- * `file` path to a file with a test
207
- * `steps` array of executed steps (available only in `test.passed`, `test.failed`, `test.finished` event)
208
- * `skipInfo` additional test options when test skipped
209
- * * `message` string with reason for skip
210
- * * `description` string with test body
211
- and others
246
+ ```js
247
+ // response is { "name": "joe", "email": "joe@joe.com" }
248
+ I.seeResponseContainsKeys(['name', 'email']);
249
+ ```
212
250
 
213
- #### Step Object
251
+ However, this is a very naive approach. It won't work for arrays or nested objects.
252
+ To check complex JSON structures `JSONResponse` helper uses [`joi`](https://joi.dev) library.
253
+ It has rich API to validate JSON by the schema defined using JavaScript.
214
254
 
215
- Step events provide step objects with following fields:
255
+ ```js
256
+ // require joi library,
257
+ // it is installed with CodeceptJS
258
+ const Joi = require('joi');
259
+
260
+ // create schema definition using Joi API
261
+ const schema = Joi.object().keys({
262
+ email: Joi.string().email().required(),
263
+ phone: Joi.string().regex(/^\d{3}-\d{3}-\d{4}$/).required(),
264
+ birthday: Joi.date().max('1-1-2004').iso()
265
+ });
266
+
267
+ // check that response matches that schema
268
+ I.seeResponseMatchesJsonSchema(schema);
269
+ ```
216
270
 
217
- * `name` name of a step, like 'see', 'click', and others
218
- * `actor` current actor, in most cases it is `I`
219
- * `helper` current helper instance used to execute this step
220
- * `helperMethod` corresponding helper method, in most cases is the same as `name`
221
- * `status` status of a step (passed or failed)
222
- * `prefix` if a step is executed inside `within` block contain within text, like: 'Within .js-signup-form'.
223
- * `args` passed arguments
271
+ ### Data Inclusion
224
272
 
225
- Whenever you execute tests with `--verbose` option you will see registered events and promises executed by a recorder.
273
+ To check that response contains expected data use `I.seeResponseContainsJson` method.
274
+ It will check the response data for partial match.
226
275
 
227
- ## Custom Runner
276
+ ```js
277
+ I.seeResponseContainsJson({
278
+ user: {
279
+ email: 'user@user.com'
280
+ }
281
+ })
282
+ ```
228
283
 
229
- You can run CodeceptJS tests from your script.
284
+ To perform arbitrary assertions on a response object use `seeResponseValidByCallback`.
285
+ It allows you to do any kind of assertions by using `expect` from [`chai`](https://www.chaijs.com) library.
230
286
 
231
287
  ```js
232
- const { codecept: Codecept } = require('codeceptjs');
233
-
234
- // define main config
235
- const config = {
236
- helpers: {
237
- WebDriver: {
238
- browser: 'chrome',
239
- url: 'http://localhost'
240
- }
241
- }
242
- };
243
-
244
- const opts = { steps: true };
245
-
246
- // run CodeceptJS inside async function
247
- (async () => {
248
- const codecept = new Codecept(config, options);
249
- codecept.init(__dirname);
250
-
251
- try {
252
- await codecept.bootstrap();
253
- codecept.loadTests('**_test.js');
254
- // run tests
255
- await codecept.run(test);
256
- } catch (err) {
257
- printError(err);
258
- process.exitCode = 1;
259
- } finally {
260
- await codecept.teardown();
261
- }
262
- })();
288
+ I.seeResponseValidByCallback({ data, status, expect } => {
289
+ // we receive data and expect to combine them for good assertion
290
+ expect(data.users.length).to.be.gte(10);
291
+ })
263
292
  ```
264
293
 
265
- > Also, you can run tests inside workers in a custom scripts. Please refer to the [parallel execution](/parallel) guide for more details.
294
+ ## Extending JSONResponse
295
+
296
+ To add more assertions it is recommended to create a custom helper.
297
+ Inside it you can get access to latest JSON response:
298
+
299
+ ```js
300
+ // inside a custom helper
301
+ makeSomeCustomAssertion() {
302
+ const response = this.helpers.JSONResponse.response;
303
+ }
304
+ ```
@@ -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