codeceptjs 3.5.12-beta.5 → 3.5.12-beta.7
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/lib/helper/MockServer.js +215 -0
- package/lib/helper/Playwright.js +43 -22
- package/lib/helper/Puppeteer.js +25 -6
- package/lib/helper/WebDriver.js +25 -4
- package/lib/helper/errors/ElementAssertion.js +38 -0
- package/package.json +6 -5
- package/typings/index.d.ts +16 -0
- package/typings/promiseBasedTypes.d.ts +182 -0
- package/typings/types.d.ts +182 -0
- package/docs/advanced.md +0 -351
- package/docs/ai.md +0 -248
- package/docs/api.md +0 -323
- package/docs/basics.md +0 -979
- package/docs/bdd.md +0 -539
- package/docs/best.md +0 -237
- package/docs/books.md +0 -37
- package/docs/bootstrap.md +0 -135
- package/docs/build/ApiDataFactory.js +0 -410
- package/docs/build/Appium.js +0 -2027
- package/docs/build/Expect.js +0 -422
- package/docs/build/FileSystem.js +0 -228
- package/docs/build/GraphQL.js +0 -229
- package/docs/build/GraphQLDataFactory.js +0 -309
- package/docs/build/JSONResponse.js +0 -338
- package/docs/build/Mochawesome.js +0 -71
- package/docs/build/Nightmare.js +0 -2152
- package/docs/build/OpenAI.js +0 -126
- package/docs/build/Playwright.js +0 -5110
- package/docs/build/Protractor.js +0 -2706
- package/docs/build/Puppeteer.js +0 -3905
- package/docs/build/REST.js +0 -344
- package/docs/build/TestCafe.js +0 -2125
- package/docs/build/WebDriver.js +0 -4240
- package/docs/changelog.md +0 -2572
- package/docs/commands.md +0 -266
- package/docs/community-helpers.md +0 -58
- package/docs/configuration.md +0 -157
- package/docs/continuous-integration.md +0 -22
- package/docs/custom-helpers.md +0 -306
- package/docs/data.md +0 -379
- package/docs/detox.md +0 -235
- package/docs/docker.md +0 -136
- package/docs/email.md +0 -183
- package/docs/examples.md +0 -149
- package/docs/helpers/ApiDataFactory.md +0 -266
- package/docs/helpers/Appium.md +0 -1374
- package/docs/helpers/Detox.md +0 -586
- package/docs/helpers/Expect.md +0 -275
- package/docs/helpers/FileSystem.md +0 -152
- package/docs/helpers/GraphQL.md +0 -151
- package/docs/helpers/GraphQLDataFactory.md +0 -226
- package/docs/helpers/JSONResponse.md +0 -254
- package/docs/helpers/Mochawesome.md +0 -8
- package/docs/helpers/MockRequest.md +0 -377
- package/docs/helpers/Nightmare.md +0 -1305
- package/docs/helpers/OpenAI.md +0 -70
- package/docs/helpers/Playwright.md +0 -2759
- package/docs/helpers/Polly.md +0 -44
- package/docs/helpers/Protractor.md +0 -1769
- package/docs/helpers/Puppeteer-firefox.md +0 -86
- package/docs/helpers/Puppeteer.md +0 -2317
- package/docs/helpers/REST.md +0 -218
- package/docs/helpers/TestCafe.md +0 -1321
- package/docs/helpers/WebDriver.md +0 -2547
- package/docs/hooks.md +0 -340
- package/docs/index.md +0 -111
- package/docs/installation.md +0 -75
- package/docs/internal-api.md +0 -266
- package/docs/locators.md +0 -339
- package/docs/mobile-react-native-locators.md +0 -67
- package/docs/mobile.md +0 -338
- package/docs/pageobjects.md +0 -291
- package/docs/parallel.md +0 -400
- package/docs/playwright.md +0 -632
- package/docs/plugins.md +0 -1259
- package/docs/puppeteer.md +0 -316
- package/docs/quickstart.md +0 -162
- package/docs/react.md +0 -70
- package/docs/reports.md +0 -392
- package/docs/secrets.md +0 -36
- package/docs/shadow.md +0 -68
- package/docs/shared/keys.mustache +0 -31
- package/docs/shared/react.mustache +0 -1
- package/docs/testcafe.md +0 -174
- package/docs/translation.md +0 -247
- package/docs/tutorial.md +0 -271
- package/docs/typescript.md +0 -180
- package/docs/ui.md +0 -59
- package/docs/videos.md +0 -28
- package/docs/visual.md +0 -202
- package/docs/vue.md +0 -143
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -11
- package/docs/webapi/attachFile.mustache +0 -12
- package/docs/webapi/blur.mustache +0 -18
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -9
- package/docs/webapi/clearField.mustache +0 -9
- package/docs/webapi/click.mustache +0 -25
- package/docs/webapi/clickLink.mustache +0 -8
- package/docs/webapi/closeCurrentTab.mustache +0 -7
- package/docs/webapi/closeOtherTabs.mustache +0 -8
- package/docs/webapi/dontSee.mustache +0 -11
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/dontSeeCookie.mustache +0 -8
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -8
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -11
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/doubleClick.mustache +0 -13
- package/docs/webapi/downloadFile.mustache +0 -12
- package/docs/webapi/dragAndDrop.mustache +0 -9
- package/docs/webapi/dragSlider.mustache +0 -11
- package/docs/webapi/executeAsyncScript.mustache +0 -24
- package/docs/webapi/executeScript.mustache +0 -26
- package/docs/webapi/fillField.mustache +0 -16
- package/docs/webapi/focus.mustache +0 -13
- package/docs/webapi/forceClick.mustache +0 -28
- package/docs/webapi/forceRightClick.mustache +0 -18
- package/docs/webapi/grabAllWindowHandles.mustache +0 -7
- package/docs/webapi/grabAttributeFrom.mustache +0 -10
- package/docs/webapi/grabAttributeFromAll.mustache +0 -9
- package/docs/webapi/grabBrowserLogs.mustache +0 -9
- package/docs/webapi/grabCookie.mustache +0 -11
- package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
- package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
- package/docs/webapi/grabCurrentUrl.mustache +0 -9
- package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
- package/docs/webapi/grabElementBoundingRect.mustache +0 -20
- package/docs/webapi/grabGeoLocation.mustache +0 -8
- package/docs/webapi/grabHTMLFrom.mustache +0 -10
- package/docs/webapi/grabHTMLFromAll.mustache +0 -9
- package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
- package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
- package/docs/webapi/grabPageScrollPosition.mustache +0 -8
- package/docs/webapi/grabPopupText.mustache +0 -5
- package/docs/webapi/grabSource.mustache +0 -8
- package/docs/webapi/grabTextFrom.mustache +0 -10
- package/docs/webapi/grabTextFromAll.mustache +0 -9
- package/docs/webapi/grabTitle.mustache +0 -8
- package/docs/webapi/grabValueFrom.mustache +0 -9
- package/docs/webapi/grabValueFromAll.mustache +0 -8
- package/docs/webapi/grabWebElement.mustache +0 -9
- package/docs/webapi/grabWebElements.mustache +0 -9
- package/docs/webapi/moveCursorTo.mustache +0 -12
- package/docs/webapi/openNewTab.mustache +0 -7
- package/docs/webapi/pressKey.mustache +0 -12
- package/docs/webapi/pressKeyDown.mustache +0 -12
- package/docs/webapi/pressKeyUp.mustache +0 -12
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
- package/docs/webapi/refreshPage.mustache +0 -6
- package/docs/webapi/resizeWindow.mustache +0 -6
- package/docs/webapi/rightClick.mustache +0 -14
- package/docs/webapi/saveElementScreenshot.mustache +0 -10
- package/docs/webapi/saveScreenshot.mustache +0 -12
- package/docs/webapi/say.mustache +0 -10
- package/docs/webapi/scrollIntoView.mustache +0 -11
- package/docs/webapi/scrollPageToBottom.mustache +0 -6
- package/docs/webapi/scrollPageToTop.mustache +0 -6
- package/docs/webapi/scrollTo.mustache +0 -12
- package/docs/webapi/see.mustache +0 -11
- package/docs/webapi/seeAttributesOnElements.mustache +0 -9
- package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/seeCookie.mustache +0 -8
- package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -8
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -12
- package/docs/webapi/seeInPopup.mustache +0 -8
- package/docs/webapi/seeInSource.mustache +0 -7
- package/docs/webapi/seeInTitle.mustache +0 -8
- package/docs/webapi/seeNumberOfElements.mustache +0 -11
- package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/seeTextEquals.mustache +0 -9
- package/docs/webapi/seeTitleEquals.mustache +0 -8
- package/docs/webapi/selectOption.mustache +0 -21
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/switchTo.mustache +0 -9
- package/docs/webapi/switchToNextTab.mustache +0 -10
- package/docs/webapi/switchToPreviousTab.mustache +0 -10
- package/docs/webapi/type.mustache +0 -21
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForElement.mustache +0 -11
- package/docs/webapi/waitForEnabled.mustache +0 -6
- package/docs/webapi/waitForFunction.mustache +0 -17
- package/docs/webapi/waitForInvisible.mustache +0 -10
- package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
- package/docs/webapi/waitForText.mustache +0 -13
- package/docs/webapi/waitForValue.mustache +0 -10
- package/docs/webapi/waitForVisible.mustache +0 -10
- package/docs/webapi/waitInUrl.mustache +0 -9
- package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/waitToHide.mustache +0 -10
- package/docs/webapi/waitUrlEquals.mustache +0 -10
- package/docs/webdriver.md +0 -701
- package/docs/wiki/Books-&-Posts.md +0 -27
- package/docs/wiki/Community-Helpers-&-Plugins.md +0 -53
- package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -61
- package/docs/wiki/Examples.md +0 -145
- package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
- package/docs/wiki/Home.md +0 -16
- package/docs/wiki/Migration-to-Appium-v2---CodeceptJS.md +0 -83
- package/docs/wiki/Release-Process.md +0 -24
- package/docs/wiki/Roadmap.md +0 -23
- package/docs/wiki/Tests.md +0 -1393
- package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
- package/docs/wiki/Videos.md +0 -19
package/docs/custom-helpers.md
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
permalink: /helpers
|
|
3
|
-
title: Custom Helpers
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Extending CodeceptJS With Custom Helpers
|
|
7
|
-
|
|
8
|
-
Helper is the core concept of CodeceptJS. Helper is a wrapper on top of various libraries providing unified interface around them. When `I` object is used in tests it delegates execution of its functions to currently enabled helper classes.
|
|
9
|
-
|
|
10
|
-
Use Helpers to introduce low-level API to your tests without polluting test scenarios. Helpers can also be used to share functionality across different project and installed as npm packages.
|
|
11
|
-
|
|
12
|
-
## Development
|
|
13
|
-
|
|
14
|
-
Helpers can be created by running a generator command:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npx codeceptjs gh
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
> or `npx codeceptjs generate:helper`
|
|
21
|
-
|
|
22
|
-
This command generates a basic helper, append it to `helpers` section of config file:
|
|
23
|
-
|
|
24
|
-
```js
|
|
25
|
-
helpers: {
|
|
26
|
-
WebDriver: { },
|
|
27
|
-
MyHelper: {
|
|
28
|
-
require: './path/to/module'
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Helpers are classes inherited from [corresponding abstract class](https://github.com/codeceptjs/helper).
|
|
34
|
-
Created helper file should look like this:
|
|
35
|
-
|
|
36
|
-
```js
|
|
37
|
-
const Helper = require('@codeceptjs/helper');
|
|
38
|
-
|
|
39
|
-
class MyHelper extends Helper {
|
|
40
|
-
|
|
41
|
-
// before/after hooks
|
|
42
|
-
_before() {
|
|
43
|
-
// remove if not used
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
_after() {
|
|
47
|
-
// remove if not used
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// add custom methods here
|
|
51
|
-
// If you need to access other helpers
|
|
52
|
-
// use: this.helpers['helperName']
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
module.exports = MyHelper;
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
When the helper is enabled in config all methods of a helper class are available in `I` object.
|
|
60
|
-
For instance, if we add a new method to helper class:
|
|
61
|
-
|
|
62
|
-
```js
|
|
63
|
-
const Helper = require('@codeceptjs/helper');
|
|
64
|
-
|
|
65
|
-
class MyHelper extends Helper {
|
|
66
|
-
|
|
67
|
-
doAwesomeThings() {
|
|
68
|
-
console.log('Hello from MyHelpr');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
We can call a new method from within `I`:
|
|
75
|
-
|
|
76
|
-
```js
|
|
77
|
-
I.doAwesomeThings();
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
> Methods starting with `_` are considered special and won't available in `I` object.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
Please note, `I` object can't be used helper class. As `I` object delegates its calls to helper classes, you can't make a circular dependency on it. Instead of calling `I` inside a helper, you can get access to other helpers by using `helpers` property of a helper. This allows you to access any other enabled helper by its name.
|
|
84
|
-
|
|
85
|
-
For instance, to perform a click with Playwright helper, do it like this:
|
|
86
|
-
|
|
87
|
-
```js
|
|
88
|
-
doAwesomeThingsWithPlaywright() {
|
|
89
|
-
const { Playwright } = this.helpers;
|
|
90
|
-
Playwright.click('Awesome');
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
After a custom helper is finished you can update CodeceptJS Type Definitions by running:
|
|
96
|
-
|
|
97
|
-
```sh
|
|
98
|
-
npx codeceptjs def .
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
This way, if your tests are written with TypeScript, your IDE will be able to leverage features like autocomplete and so on.
|
|
102
|
-
|
|
103
|
-
## Accessing Elements
|
|
104
|
-
|
|
105
|
-
WebDriver, Puppeteer and Playwright drivers provide API for web elements.
|
|
106
|
-
However, CodeceptJS do not expose them to tests by design, keeping test to be action focused.
|
|
107
|
-
If you need to get access to web elements, it is recommended to implement operations for web elements in a custom helper.
|
|
108
|
-
|
|
109
|
-
To get access for elements, connect to a corresponding helper and use `_locate` function to match web elements by CSS or XPath, like you usually do:
|
|
110
|
-
|
|
111
|
-
### Accessing Elements in WebDriver
|
|
112
|
-
|
|
113
|
-
```js
|
|
114
|
-
// inside a custom helper
|
|
115
|
-
async clickOnEveryElement(locator) {
|
|
116
|
-
const { WebDriver } = this.helpers;
|
|
117
|
-
const els = await WebDriver._locate(locator);
|
|
118
|
-
|
|
119
|
-
for (let el of els) {
|
|
120
|
-
await el.click();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
In this case an an instance of webdriverio element is used.
|
|
126
|
-
To get a [complete API of an element](https://webdriver.io/docs/api/) refer to webdriverio docs.
|
|
127
|
-
|
|
128
|
-
### Accessing Elements in Playwright & Puppeteer
|
|
129
|
-
|
|
130
|
-
Similar method can be implemented for Playwright & Puppeteer:
|
|
131
|
-
|
|
132
|
-
```js
|
|
133
|
-
// inside a custom helper
|
|
134
|
-
async clickOnEveryElement(locator) {
|
|
135
|
-
const { Playwright } = this.helpers;
|
|
136
|
-
const els = await Playwright._locate(locator);
|
|
137
|
-
|
|
138
|
-
for (let el of els) {
|
|
139
|
-
await el.click();
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
In this case `el` will be an instance of [ElementHandle](https://playwright.dev/#version=master&path=docs%2Fapi.md&q=class-elementhandle) which is similar for Playwright & [Puppeteer](https://pptr.dev/#?product=Puppeteer&version=master&show=api-class-elementhandle).
|
|
145
|
-
|
|
146
|
-
> ℹ There are more `_locate*` methods in each helper. Take a look on documentation of a helper you use to see which exact method it exposes.
|
|
147
|
-
|
|
148
|
-
## Configuration
|
|
149
|
-
|
|
150
|
-
Helpers should be enabled inside `codecept.json` or `codecept.conf.js` files. Command `generate helper`
|
|
151
|
-
does that for you, however you can enable them manually by placing helper to `helpers` section inside config file.
|
|
152
|
-
You can also pass additional config options to your helper from a config - **(please note, this example contains comments, while JSON format doesn't support them)**:
|
|
153
|
-
|
|
154
|
-
```js
|
|
155
|
-
helpers: {
|
|
156
|
-
// here goes standard helpers:
|
|
157
|
-
// WebDriver, Playwright, etc...
|
|
158
|
-
// and their configuration
|
|
159
|
-
MyHelper: {
|
|
160
|
-
require: "./my_helper.js", // path to module
|
|
161
|
-
defaultHost: "http://mysite.com" // custom config param
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Config values will be stored inside helper in `this.config`. To get `defaultHost` value you can use
|
|
168
|
-
|
|
169
|
-
```js
|
|
170
|
-
this.config.defaultHost
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
in any place of your helper. You can also redefine config options inside a constructor:
|
|
174
|
-
|
|
175
|
-
```js
|
|
176
|
-
constructor(config) {
|
|
177
|
-
config.defaultHost += '/api';
|
|
178
|
-
console.log(config.defaultHost); // http://mysite.com/api
|
|
179
|
-
super(config);
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
## Hooks
|
|
184
|
-
|
|
185
|
-
Helpers may contain several hooks you can use to handle events of a test.
|
|
186
|
-
Implement corresponding methods to them.
|
|
187
|
-
|
|
188
|
-
* `_init` - before all tests
|
|
189
|
-
* `_finishTest` - after all tests
|
|
190
|
-
* `_before` - before a test
|
|
191
|
-
* `_after` - after a test
|
|
192
|
-
* `_beforeStep` - before each step
|
|
193
|
-
* `_afterStep` - after each step
|
|
194
|
-
* `_beforeSuite` - before each suite
|
|
195
|
-
* `_afterSuite` - after each suite
|
|
196
|
-
* `_passed` - after a test passed
|
|
197
|
-
* `_failed` - after a test failed
|
|
198
|
-
|
|
199
|
-
Each implemented method should return a value as they will be added to global promise chain as well.
|
|
200
|
-
|
|
201
|
-
## Conditional Retries
|
|
202
|
-
|
|
203
|
-
It is possible to execute global conditional retries to handle unforseen errors.
|
|
204
|
-
Lost connections and network issues are good candidates to be retried whenever they appear.
|
|
205
|
-
|
|
206
|
-
This can be done inside a helper using the global [promise recorder](/hooks/#api):
|
|
207
|
-
|
|
208
|
-
Example: Retrying rendering errors in Puppeteer.
|
|
209
|
-
|
|
210
|
-
```js
|
|
211
|
-
_before() {
|
|
212
|
-
const recorder = require('codeceptjs').recorder;
|
|
213
|
-
recorder.retry({
|
|
214
|
-
retries: 2,
|
|
215
|
-
when: err => err.message.indexOf('Cannot find context with specified id') > -1,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
`recorder.retry` acts similarly to `I.retry()` and accepts the same parameters. It expects the `when` parameter to be set so it would handle only specific errors and not to retry for every failed step.
|
|
221
|
-
|
|
222
|
-
Retry rules are available in array `recorder.retries`. The last retry rule can be disabled by running `recorder.retries.pop()`;
|
|
223
|
-
|
|
224
|
-
## Using Typescript
|
|
225
|
-
|
|
226
|
-
With Typescript, just simply replacing `module.exports` with `export` for autocompletion.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
## Helper Examples
|
|
230
|
-
|
|
231
|
-
### Playwright Example
|
|
232
|
-
|
|
233
|
-
In this example we take the power of Playwright to change geolocation in our tests:
|
|
234
|
-
|
|
235
|
-
```js
|
|
236
|
-
const Helper = require('@codeceptjs/helper');
|
|
237
|
-
|
|
238
|
-
class MyHelper extends Helper {
|
|
239
|
-
|
|
240
|
-
async setGeoLocation(longitude, latitude) {
|
|
241
|
-
const { browserContext } = this.helpers.Playwright;
|
|
242
|
-
await browserContext.setGeolocation({ longitude, latitude });
|
|
243
|
-
await Playwright.refreshPage();
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
### WebDriver Example
|
|
249
|
-
|
|
250
|
-
Next example demonstrates how to use WebDriver library to create your own test action. Method `seeAuthentication` will use `browser` instance of WebDriver to get access to cookies. Standard NodeJS assertion library will be used (you can use any).
|
|
251
|
-
|
|
252
|
-
```js
|
|
253
|
-
const Helper = require('@codeceptjs/helper');
|
|
254
|
-
|
|
255
|
-
// use any assertion library you like
|
|
256
|
-
const assert = require('assert');
|
|
257
|
-
|
|
258
|
-
class MyHelper extends Helper {
|
|
259
|
-
/**
|
|
260
|
-
* checks that authentication cookie is set
|
|
261
|
-
*/
|
|
262
|
-
async seeAuthentication() {
|
|
263
|
-
// access current browser of WebDriver helper
|
|
264
|
-
const { WebDriver } = this.helpers
|
|
265
|
-
const { browser } = WebDriver;
|
|
266
|
-
|
|
267
|
-
// get all cookies according to https://webdriver.io/api/protocol/cookie.html
|
|
268
|
-
// any helper method should return a value in order to be added to promise chain
|
|
269
|
-
const res = await browser.cookie();
|
|
270
|
-
// get values
|
|
271
|
-
let cookies = res.value;
|
|
272
|
-
for (let k in cookies) {
|
|
273
|
-
// check for a cookie
|
|
274
|
-
if (cookies[k].name != 'logged_in') continue;
|
|
275
|
-
assert.equal(cookies[k].value, 'yes');
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
assert.fail(cookies, 'logged_in', "Auth cookie not set");
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
module.exports = MyHelper;
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Puppeteer Example
|
|
286
|
-
|
|
287
|
-
Puppeteer has [nice and elegant API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md) which you can use inside helpers. Accessing `page` instance via `this.helpers.Puppeteer.page` from inside a helper.
|
|
288
|
-
|
|
289
|
-
Let's see how we can use [emulate](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageemulateoptions) function to emulate iPhone browser in a test.
|
|
290
|
-
|
|
291
|
-
```js
|
|
292
|
-
const Helper = require('@codeceptjs/helper');
|
|
293
|
-
const puppeteer = require('puppeteer');
|
|
294
|
-
const iPhone = puppeteer.devices['iPhone 6'];
|
|
295
|
-
|
|
296
|
-
class MyHelper extends Helper {
|
|
297
|
-
|
|
298
|
-
async emulateIPhone() {
|
|
299
|
-
const { page } = this.helpers.Puppeteer;
|
|
300
|
-
await page.emulate(iPhone);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
module.exports = MyHelper;
|
|
306
|
-
```
|
package/docs/data.md
DELETED
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
permalink: /data
|
|
3
|
-
title: Data Management
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Data Management
|
|
7
|
-
|
|
8
|
-
> This chapter describes data management for external sources. If you are looking for using Data Sets in tests, see [Data Driven Tests](https://codecept.io/advanced/#data-drivern-tests) section*
|
|
9
|
-
|
|
10
|
-
Managing data for tests is always a tricky issue. How isolate data between tests, how to prepare data for different tests, etc.
|
|
11
|
-
There are different approaches to solve it:
|
|
12
|
-
|
|
13
|
-
1. reset database completely between tests
|
|
14
|
-
2. create unique non-intersecting data sets per each test
|
|
15
|
-
3. create and delete data for a test
|
|
16
|
-
|
|
17
|
-
The most efficient way would be to allow test to control its data, i.e. the 3rd option.
|
|
18
|
-
However, accessing database directly is not a good idea as database vendor, schema and data are used by application internally and are out of scope of acceptance test.
|
|
19
|
-
|
|
20
|
-
Today all modern web applications have REST or GraphQL API . So it is a good idea to use it to create data for a test and delete it after.
|
|
21
|
-
API is supposed to be a stable interface and it can be used by acceptance tests. CodeceptJS provides 4 helpers for Data Management via REST and GraphQL API.
|
|
22
|
-
|
|
23
|
-
## REST
|
|
24
|
-
|
|
25
|
-
[REST helper](https://codecept.io/helpers/REST/) allows sending raw HTTP requests to application.
|
|
26
|
-
This is a tool to make shortcuts and create your data pragmatically via API. However, it doesn't provide tools for testing APIs, so it should be paired with Playwright or WebDriver helper for browser testing.
|
|
27
|
-
|
|
28
|
-
Enable REST helper in the config. It is recommended to set `endpoint`, a base URL for all API requests. If you need some authorization you can optionally set default headers too.
|
|
29
|
-
|
|
30
|
-
See the sample config:
|
|
31
|
-
|
|
32
|
-
```js
|
|
33
|
-
helpers: {
|
|
34
|
-
REST: {
|
|
35
|
-
endpoint: "http://localhost/api/v1/",
|
|
36
|
-
defaultHeaders: {
|
|
37
|
-
'Auth': '11111',
|
|
38
|
-
'Content-Type': 'application/json',
|
|
39
|
-
'Accept': 'application/json',
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
WebDriver : {
|
|
43
|
-
url: 'http://localhost',
|
|
44
|
-
browser: 'chrome'
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
REST helper provides basic methods to send requests to application:
|
|
50
|
-
|
|
51
|
-
```js
|
|
52
|
-
I.sendGetRequest()
|
|
53
|
-
I.sendPostRequest()
|
|
54
|
-
I.sendPutRequest()
|
|
55
|
-
I.sendPatchRequest()
|
|
56
|
-
I.sendDeleteRequest()
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
As well as a method for setting headers: `haveRequestHeaders`.
|
|
60
|
-
|
|
61
|
-
Here is a usage example:
|
|
62
|
-
|
|
63
|
-
```js
|
|
64
|
-
let postId = null;
|
|
65
|
-
|
|
66
|
-
Scenario('check post page', async ({ I }) => {
|
|
67
|
-
// valid access token
|
|
68
|
-
I.haveRequestHeaders({auth: '1111111'});
|
|
69
|
-
// get the first user
|
|
70
|
-
let user = await I.sendGetRequest('/api/users/1');
|
|
71
|
-
// create a post and save its Id
|
|
72
|
-
postId = await I.sendPostRequest('/api/posts', { author: user.id, body: 'some text' });
|
|
73
|
-
// open browser page of new post
|
|
74
|
-
I.amOnPage('/posts/2.html');
|
|
75
|
-
I.see('some text', 'p.body');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// cleanup created data
|
|
79
|
-
After(({ I }) => {
|
|
80
|
-
I.sendDeleteRequest('/api/posts/'+postId);
|
|
81
|
-
});
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
This can also be used to emulate Ajax requests:
|
|
85
|
-
|
|
86
|
-
```js
|
|
87
|
-
I.sendPostRequest('/update-status', {}, { http_x_requested_with: 'xmlhttprequest' });
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
> See complete reference on [REST](https://codecept.io/helpers/REST) helper
|
|
91
|
-
|
|
92
|
-
## GraphQL
|
|
93
|
-
|
|
94
|
-
[GraphQL helper](https://codecept.io/helpers/GraphQL/) allows sending GraphQL queries and mutations to application, over Http.
|
|
95
|
-
<<<<<<< HEAD
|
|
96
|
-
This is a tool to make shortcuts and create your data pragmatically via GraphQL endpoint. However, it doesn't provide tools for testing the endpoint, so it should be paired with WebDriver helper for browser testing.
|
|
97
|
-
=======
|
|
98
|
-
This is a tool to make shortcuts and create your data pragmatically via GraphQL endpoint. However, it doesn't provide tools for testing the endpoint, so it should be paired with WebDriver helpers for browser testing.
|
|
99
|
-
>>>>>>> 3.x
|
|
100
|
-
|
|
101
|
-
Enable GraphQL helper in the config. It is recommended to set `endpoint`, the URL to which the requests go to. If you need some authorization you can optionally set default headers too.
|
|
102
|
-
|
|
103
|
-
See the sample config:
|
|
104
|
-
|
|
105
|
-
```js
|
|
106
|
-
helpers: {
|
|
107
|
-
GraphQL: {
|
|
108
|
-
endpoint: "http://localhost/graphql/",
|
|
109
|
-
defaultHeaders: {
|
|
110
|
-
'Auth': '11111',
|
|
111
|
-
'Content-Type': 'application/json',
|
|
112
|
-
'Accept': 'application/json',
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
WebDriver : {
|
|
116
|
-
url: 'http://localhost',
|
|
117
|
-
browser: 'chrome'
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
GraphQL helper provides two basic methods to queries and mutations to application:
|
|
123
|
-
|
|
124
|
-
```js
|
|
125
|
-
I.sendQuery()
|
|
126
|
-
I.sendMutation()
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
As well as a method for setting headers: `haveRequestHeaders`.
|
|
130
|
-
|
|
131
|
-
Here is a usage example:
|
|
132
|
-
|
|
133
|
-
```js
|
|
134
|
-
let postData = null;
|
|
135
|
-
|
|
136
|
-
Scenario('check post page', async ({ I }) => {
|
|
137
|
-
// valid access token
|
|
138
|
-
I.haveRequestHeaders({auth: '1111111'});
|
|
139
|
-
// get the first user
|
|
140
|
-
let response = await I.sendQuery('{ user(id:1) { id }}');
|
|
141
|
-
let user = response.data;
|
|
142
|
-
// create a post and save its Id
|
|
143
|
-
response = await I.sendMutation(
|
|
144
|
-
'mutation createPost($input: PostInput!) { createPost(input: $input) { id }}',
|
|
145
|
-
{
|
|
146
|
-
input : {
|
|
147
|
-
author: user.data.id,
|
|
148
|
-
body: 'some text',
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
);
|
|
152
|
-
postData = response.data.data['createPost'];
|
|
153
|
-
// open browser page of new post
|
|
154
|
-
I.amOnPage(`/posts/${postData.slug}.html`);
|
|
155
|
-
I.see(postData.body, 'p.body');
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// cleanup created data
|
|
159
|
-
After(({ I }) => {
|
|
160
|
-
I.sendMutation(
|
|
161
|
-
'mutation deletePost($id: ID!) { deletePost(id: $id) }',
|
|
162
|
-
{ id: postData.id},
|
|
163
|
-
);
|
|
164
|
-
});
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
> See complete reference on [GraphQL](https://codecept.io/helpers/GraphQL) helper
|
|
168
|
-
|
|
169
|
-
## Data Generation with Factories
|
|
170
|
-
|
|
171
|
-
This concept is extended by:
|
|
172
|
-
- [ApiDataFactory](https://codecept.io/helpers/ApiDataFactory/) helper, and,
|
|
173
|
-
- [GraphQLDataFactory](https://codecept.io/helpers/GraphQLDataFactory/) helper.
|
|
174
|
-
|
|
175
|
-
These helpers build data according to defined rules and use REST API or GraphQL mutations to store them and automatically clean them up after a test.
|
|
176
|
-
|
|
177
|
-
Just define how many items of any kind you need and the data factory helper will create them for you.
|
|
178
|
-
|
|
179
|
-
To make this work some preparations are required.
|
|
180
|
-
|
|
181
|
-
At first, you need data generation libraries which are [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker). Faker can generate random names, emails, texts, and Rosie uses them
|
|
182
|
-
to generate objects using factories.
|
|
183
|
-
|
|
184
|
-
Install rosie and faker to create a first factory:
|
|
185
|
-
|
|
186
|
-
```js
|
|
187
|
-
npm i rosie faker --save-dev
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Then create a module which will export a factory for an entity.
|
|
191
|
-
And add that module as a part of the configuration for the helper.
|
|
192
|
-
|
|
193
|
-
Please look at the respective Factory sections for examples for factory modules and configuration.
|
|
194
|
-
|
|
195
|
-
### API Data Factory
|
|
196
|
-
|
|
197
|
-
This helper uses REST API to store the built data and automatically clean them up after a test,
|
|
198
|
-
The way for setting data for a test is as simple as writing:
|
|
199
|
-
|
|
200
|
-
```js
|
|
201
|
-
// inside async function
|
|
202
|
-
let post = await I.have('post');
|
|
203
|
-
I.haveMultiple('comment', 5, { postId: post.id});
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
After completing the preparations under 'Data Generation with Factories', create a factory module which will export a factory.
|
|
207
|
-
|
|
208
|
-
See the example providing a factory for User generation:
|
|
209
|
-
|
|
210
|
-
```js
|
|
211
|
-
// factories/post.js
|
|
212
|
-
var Factory = require('rosie').Factory;
|
|
213
|
-
var faker = require('@faker-js/faker');
|
|
214
|
-
|
|
215
|
-
module.exports = new Factory()
|
|
216
|
-
.attr('name', () => faker.name.findName())
|
|
217
|
-
.attr('email', () => faker.internet.email());
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Next is to configure helper to match factories with API:
|
|
221
|
-
|
|
222
|
-
```js
|
|
223
|
-
ApiDataFactory: {
|
|
224
|
-
endpoint: "http://user.com/api",
|
|
225
|
-
headers: {
|
|
226
|
-
'Content-Type': 'application/json',
|
|
227
|
-
'Accept': 'application/json',
|
|
228
|
-
},
|
|
229
|
-
factories: {
|
|
230
|
-
user: {
|
|
231
|
-
uri: "/users",
|
|
232
|
-
factory: "./factories/user"
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
Then, calling `I.have('user')` inside a test will create a new user for you.
|
|
239
|
-
This is done by sending POST request to `/api/users` URL. Response is returned and can be used in tests.
|
|
240
|
-
|
|
241
|
-
At the end of a test ApiDataFactory will clean up created record for you. This is done by collecting
|
|
242
|
-
ids from crated records and running `DELETE /api/users/{id}` requests at the end of a test.
|
|
243
|
-
This rules can be customized in helper configuration.
|
|
244
|
-
|
|
245
|
-
> See complete reference on [ApiDataFactory](https://codecept.io/helpers/ApiDataFactory) helper
|
|
246
|
-
|
|
247
|
-
### GraphQL Data Factory
|
|
248
|
-
|
|
249
|
-
The helper uses GraphQL mutations to store the built data and automatically clean them up after a test.
|
|
250
|
-
This way for setting data for a test is as simple as writing:
|
|
251
|
-
|
|
252
|
-
```js
|
|
253
|
-
// inside async function
|
|
254
|
-
let post = await I.mutateData('createPost');
|
|
255
|
-
I.mutateMultiple('createComment', 5, { postId: post.id});
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
After completing the preparations under 'Data Generation with Factories', create a factory module which will export a factory.
|
|
261
|
-
|
|
262
|
-
The object built by the factory is sent as the variables object along with the mutation. So make sure it matches the argument type as detailed in the GraphQL schema. You may want to pass a constructor to the factory to achieve that.
|
|
263
|
-
|
|
264
|
-
See the example providing a factory for User generation:
|
|
265
|
-
|
|
266
|
-
```js
|
|
267
|
-
// factories/post.js
|
|
268
|
-
var Factory = require('rosie').Factory;
|
|
269
|
-
var faker = require('@faker-js/faker');
|
|
270
|
-
|
|
271
|
-
module.exports = new Factory((buildObj) => {
|
|
272
|
-
return {
|
|
273
|
-
input: { ...buildObj },
|
|
274
|
-
}
|
|
275
|
-
})
|
|
276
|
-
.attr('name', () => faker.name.findName())
|
|
277
|
-
.attr('email', () => faker.internet.email());
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
Next is to configure helper to match factories with API:
|
|
281
|
-
|
|
282
|
-
```js
|
|
283
|
-
GraphQLDataFactory: {
|
|
284
|
-
endpoint: "http://user.com/graphql",
|
|
285
|
-
cleanup: true,
|
|
286
|
-
headers: {
|
|
287
|
-
'Content-Type': 'application/json',
|
|
288
|
-
'Accept': 'application/json',
|
|
289
|
-
},
|
|
290
|
-
factories: {
|
|
291
|
-
createUser: {
|
|
292
|
-
query: 'mutation createUser($input: UserInput!) { createUser(input: $input) { id name }}',
|
|
293
|
-
factory: './factories/users',
|
|
294
|
-
revert: (data) => ({
|
|
295
|
-
query: 'mutation deleteUser($id: ID!) { deleteUser(id: $id) }',
|
|
296
|
-
variables: { id : data.id},
|
|
297
|
-
}),
|
|
298
|
-
},
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
Then, calling `I.mutateData('createUser')` inside a test will create a new user for you.
|
|
303
|
-
This is done by sending a GraphQL mutation request over Http to `/graphql` endpoint. Response is returned and can be used in tests.
|
|
304
|
-
|
|
305
|
-
At the end of a test GraphQLDataFactory will clean up created record for you. This is done by collecting
|
|
306
|
-
data from crated records, creating deletion mutation objects by passing the data to the `revert` function provided, and sending deletion mutation objects as requests at the end of a test.
|
|
307
|
-
This behavior is according the `revert` function be customized in helper configuration.
|
|
308
|
-
The revert function returns an object, that contains the query for deletion, and the variables object to go along with it.
|
|
309
|
-
|
|
310
|
-
> See complete reference on [GraphQLDataFactory](https://codecept.io/helpers/GraphQLDataFactory) helper
|
|
311
|
-
|
|
312
|
-
## Requests Using Browser Session
|
|
313
|
-
|
|
314
|
-
All the REST, GraphQL, GraphQLDataFactory, and ApiDataFactory helpers allow override requests before sending.
|
|
315
|
-
This feature can be used to fetch current browser cookies and set them to REST API or GraphQL client.
|
|
316
|
-
By doing this we can make requests within the current browser session without a need of additional authentication.
|
|
317
|
-
|
|
318
|
-
> Sharing browser session with ApiDataFactory or GraphQLDataFactory can be especially useful when you test Single Page Applications
|
|
319
|
-
|
|
320
|
-
Since CodeceptJS 2.3.3 there is a simple way to enable shared session for browser and data helpers.
|
|
321
|
-
Install [`@codeceptjs/configure`](https://github.com/codeceptjs/configure) package:
|
|
322
|
-
|
|
323
|
-
```
|
|
324
|
-
npm i @codeceptjs/configure --save
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
Import `setSharedCookies` function and call it inside a config:
|
|
328
|
-
|
|
329
|
-
```js
|
|
330
|
-
// in codecept.conf.js
|
|
331
|
-
const { setSharedCookies } = require('@codeceptjs/configure');
|
|
332
|
-
|
|
333
|
-
// share cookies between browser helpers and REST/GraphQL
|
|
334
|
-
setSharedCookies();
|
|
335
|
-
|
|
336
|
-
exports.config = {}
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
Without `setSharedCookies` you will need to update the config manually, so a data helper could receive cookies from a browser to make a request. If you would like to configure this process manually, here is an example of doing so:
|
|
340
|
-
|
|
341
|
-
```js
|
|
342
|
-
|
|
343
|
-
let cookies; // share cookies
|
|
344
|
-
|
|
345
|
-
exports.config = {
|
|
346
|
-
helpers: {
|
|
347
|
-
ApiDataFactory: {
|
|
348
|
-
endpoint: 'http://local.app/api',
|
|
349
|
-
cleanup: true,
|
|
350
|
-
headers: {
|
|
351
|
-
'Content-Type': 'application/json',
|
|
352
|
-
'Accept': 'application/json',
|
|
353
|
-
},
|
|
354
|
-
factories: {
|
|
355
|
-
user: {
|
|
356
|
-
uri: "/users",
|
|
357
|
-
factory: "./factories/user",
|
|
358
|
-
}
|
|
359
|
-
},
|
|
360
|
-
onRequest: async (request) => {
|
|
361
|
-
// get a cookie if it's not obtained yet
|
|
362
|
-
if (cookies) cookies = await codeceptjs.container.helpers('WebDriver').grabCookie();
|
|
363
|
-
// add cookies to request for a current request
|
|
364
|
-
request.headers = { Cookie: cookies.map(c => `${c.name}=${c.value}`).join('; ') };
|
|
365
|
-
},
|
|
366
|
-
}
|
|
367
|
-
WebDriver: {
|
|
368
|
-
url: 'https://local.app/',
|
|
369
|
-
browser: 'chrome',
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
In this case we are accessing WebDriver helper. However, you can replace WebDriver with any helper you use.
|
|
375
|
-
|
|
376
|
-
The same can be done with GraphQLDataFactory.
|
|
377
|
-
|
|
378
|
-
The order of helpers is important! ApiDataFactory will clean up created users after a test,
|
|
379
|
-
so it needs browser to be still opened to obtain its cookies.
|