codeceptjs 3.2.2 â 3.3.0-beta.3
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 +57 -0
- package/docs/advanced.md +2 -2
- package/docs/api.md +227 -188
- package/docs/build/ApiDataFactory.js +13 -6
- package/docs/build/Appium.js +98 -36
- package/docs/build/FileSystem.js +11 -1
- 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 +271 -151
- 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/changelog.md +7 -0
- package/docs/configuration.md +8 -8
- package/docs/custom-helpers.md +1 -1
- package/docs/data.md +9 -9
- package/docs/helpers/ApiDataFactory.md +7 -0
- package/docs/helpers/Appium.md +240 -198
- package/docs/helpers/FileSystem.md +11 -1
- package/docs/helpers/JSONResponse.md +230 -0
- package/docs/helpers/Playwright.md +283 -216
- package/docs/helpers/Puppeteer.md +9 -1
- package/docs/helpers/REST.md +30 -9
- package/docs/installation.md +3 -1
- package/docs/internal-api.md +265 -0
- package/docs/mobile.md +11 -11
- package/docs/nightmare.md +3 -3
- package/docs/playwright.md +73 -18
- package/docs/plugins.md +136 -36
- package/docs/puppeteer.md +28 -12
- package/docs/quickstart.md +2 -3
- package/docs/reports.md +44 -3
- package/docs/testcafe.md +1 -1
- package/docs/translation.md +2 -2
- package/docs/videos.md +2 -2
- package/docs/visual.md +2 -2
- package/docs/vue.md +1 -1
- package/docs/webdriver.md +92 -4
- package/lib/cli.js +25 -20
- package/lib/command/init.js +5 -15
- package/lib/command/workers/runTests.js +25 -7
- package/lib/config.js +17 -13
- package/lib/helper/ApiDataFactory.js +13 -6
- package/lib/helper/Appium.js +65 -3
- package/lib/helper/FileSystem.js +11 -1
- package/lib/helper/GraphQL.js +11 -0
- package/lib/helper/JSONResponse.js +297 -0
- package/lib/helper/Playwright.js +209 -89
- 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/autoLogin.js +1 -1
- package/lib/plugin/eachElement.js +127 -0
- package/lib/plugin/tryTo.js +6 -0
- package/lib/utils.js +20 -0
- package/package.json +25 -23
- package/translations/pt-BR.js +8 -0
- package/typings/index.d.ts +4 -0
- package/typings/types.d.ts +318 -109
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
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
|
+
|
|
51
|
+
## 3.2.3
|
|
52
|
+
|
|
53
|
+
* Documentation improvements by @maojunxyz
|
|
54
|
+
* Guard mocha cli reporter from registering step logger multiple times #3180 by @nikocanvacom
|
|
55
|
+
* [Playwright] Fixed "tracing.stop: tracing.stop: ENAMETOOLONG: name too long" by @hatufacci
|
|
56
|
+
* Fixed #2889: return always the same error contract from simplifyTest. See #3168 by @andremoah
|
|
57
|
+
|
|
1
58
|
## 3.2.2
|
|
2
59
|
|
|
3
60
|
* [Playwright] Reverted removal of retry on context errors. Fixes #3130
|
package/docs/advanced.md
CHANGED
|
@@ -97,10 +97,10 @@ Scenario('update user profile', ({ }) => {
|
|
|
97
97
|
}).tag('@slow').tag('important');
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
All tests with `@tag` could be executed with `--grep @tag` option.
|
|
100
|
+
All tests with `@tag` could be executed with `--grep '@tag'` option.
|
|
101
101
|
|
|
102
102
|
```sh
|
|
103
|
-
|
|
103
|
+
codeceptjs run --grep '@slow'
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
Use regex for more flexible filtering:
|
package/docs/api.md
CHANGED
|
@@ -1,265 +1,304 @@
|
|
|
1
1
|
---
|
|
2
|
-
permalink: /
|
|
3
|
-
title:
|
|
2
|
+
permalink: /api
|
|
3
|
+
title: API Testing
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## API Testing
|
|
7
7
|
|
|
8
|
-
|
|
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
|
-
|
|
10
|
+
Take a look:
|
|
12
11
|
|
|
13
12
|
```js
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
29
|
+
* status code
|
|
30
|
+
* data inclusion
|
|
31
|
+
* data structure
|
|
21
32
|
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
37
|
+
## Installation
|
|
35
38
|
|
|
36
|
-
CodeceptJS
|
|
37
|
-
They can be retrieved from the container:
|
|
39
|
+
Install CodeceptJS if it is not installed yet.
|
|
38
40
|
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// get object with all helpers
|
|
43
|
-
const helpers = container.helpers();
|
|
41
|
+
```
|
|
42
|
+
npm i codeceptjs --save-dev
|
|
43
|
+
```
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
const { WebDriver } = container.helpers();
|
|
45
|
+
Initialize CodeceptJS and select REST or GraphQL helper when asked for a helper:
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
```
|
|
48
|
+
npx codeceptjs init
|
|
49
|
+
```
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
const { UserPage } = container.support();
|
|
51
|
+
## Configuration
|
|
53
52
|
|
|
54
|
-
|
|
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
|
-
|
|
55
|
+
* If you use `REST` helper add `JSONResponse` helper below with no extra config:
|
|
59
56
|
|
|
60
57
|
```js
|
|
61
|
-
|
|
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
|
-
|
|
64
|
-
helpers: {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
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
|
-
|
|
85
|
+
[`JSONResponse`](/helpers/JSONResponse/) helper adds response assertions.
|
|
76
86
|
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
114
|
+
```js
|
|
115
|
+
const { setSharedCookies } = require('@codeceptjs/configure');
|
|
93
116
|
|
|
94
|
-
|
|
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
|
-
|
|
135
|
+
### REST
|
|
101
136
|
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
194
|
+
GraphQL helper has two methods available:
|
|
195
|
+
|
|
196
|
+
* [`I.sendQuery()`](/helpers/GraphQL#sendQuery)
|
|
197
|
+
* [`I.sendMutation()`](/helpers/GraphQL#sendMutation)
|
|
163
198
|
|
|
164
|
-
|
|
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
|
-
|
|
206
|
+
Scenario('I make API call', ({ I }) => {
|
|
207
|
+
// request was made by REST
|
|
208
|
+
// or by GraphQL helper
|
|
168
209
|
|
|
169
|
-
//
|
|
210
|
+
// check that response code is 2xx
|
|
211
|
+
I.seeResponseCodeIsSuccessful();
|
|
170
212
|
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
232
|
+
// matches 300...308
|
|
233
|
+
I.seeResponseCodeIsRedirection();
|
|
187
234
|
|
|
188
|
-
|
|
189
|
-
|
|
235
|
+
// matches 400..451
|
|
236
|
+
I.seeResponseCodeIsClientError();
|
|
190
237
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
output.log('This is verbose logging information');
|
|
238
|
+
// matches 500-511
|
|
239
|
+
I.seeResponseCodeIsServerError();
|
|
194
240
|
```
|
|
195
241
|
|
|
196
|
-
|
|
242
|
+
### Structure
|
|
197
243
|
|
|
198
|
-
The
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
276
|
+
```js
|
|
277
|
+
I.seeResponseContainsJson({
|
|
278
|
+
user: {
|
|
279
|
+
email: 'user@user.com'
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
```
|
|
228
283
|
|
|
229
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
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
|
|