codeceptjs 2.1.3 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +125 -37
- package/README.md +15 -22
- package/bin/codecept.js +4 -1
- package/docs/acceptance.md +44 -1
- package/docs/advanced.md +1 -1
- package/docs/angular.md +6 -9
- package/docs/basics.md +388 -75
- package/docs/bdd.md +4 -3
- package/docs/best.md +1 -1
- package/docs/books.md +31 -0
- package/docs/build/Appium.js +215 -176
- package/docs/build/Nightmare.js +618 -489
- package/docs/build/Polly.js +189 -0
- package/docs/build/Protractor.js +747 -608
- package/docs/build/Puppeteer.js +914 -633
- package/docs/build/REST.js +1 -1
- package/docs/build/TestCafe.js +1835 -0
- package/docs/build/WebDriver.js +861 -805
- package/docs/build/WebDriverIO.js +616 -617
- package/docs/changelog.md +410 -316
- package/docs/commands.md +6 -6
- package/docs/community-helpers.md +2 -0
- package/docs/detox.md +235 -0
- package/docs/examples.md +23 -0
- package/docs/helpers/ApiDataFactory.md +11 -10
- package/docs/helpers/Appium.md +130 -61
- package/docs/helpers/Detox.md +579 -0
- package/docs/helpers/FileSystem.md +2 -1
- package/docs/helpers/Mochawesome.md +1 -0
- package/docs/helpers/Nightmare.md +348 -128
- package/docs/helpers/Polly.md +85 -0
- package/docs/helpers/Protractor.md +451 -184
- package/docs/helpers/Puppeteer-firefox.md +55 -0
- package/docs/helpers/Puppeteer.md +619 -183
- package/docs/helpers/REST.md +17 -16
- package/docs/helpers/SeleniumWebdriver.md +9 -8
- package/docs/helpers/TestCafe.md +1168 -0
- package/docs/helpers/WebDriver.md +600 -291
- package/docs/helpers/WebDriverIO.md +393 -278
- package/docs/helpers.md +37 -18
- package/docs/locators.md +2 -0
- package/docs/mobile-react-native-locators.md +64 -0
- package/docs/mobile.md +5 -0
- package/docs/plugins.md +54 -13
- package/docs/puppeteer.md +74 -26
- package/docs/quickstart.md +47 -12
- package/docs/react.md +67 -0
- package/docs/reports.md +1 -1
- package/docs/{webapi/_keys.mustache → shared/keys.mustache} +0 -0
- package/docs/shared/react.mustache +1 -0
- package/docs/testcafe.md +157 -0
- package/docs/videos.md +19 -0
- package/docs/webapi/amOnPage.mustache +1 -1
- package/docs/webapi/appendField.mustache +2 -2
- package/docs/webapi/attachFile.mustache +2 -2
- package/docs/webapi/checkOption.mustache +2 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/clearField.mustache +1 -1
- package/docs/webapi/click.mustache +2 -2
- package/docs/webapi/clickLink.mustache +3 -3
- package/docs/webapi/dontSee.mustache +6 -3
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +7 -1
- package/docs/webapi/dontSeeCookie.mustache +5 -1
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +6 -1
- package/docs/webapi/dontSeeElement.mustache +5 -1
- package/docs/webapi/dontSeeElementInDOM.mustache +5 -1
- package/docs/webapi/dontSeeInCurrentUrl.mustache +1 -1
- package/docs/webapi/dontSeeInField.mustache +7 -2
- package/docs/webapi/dontSeeInSource.mustache +5 -1
- package/docs/webapi/dontSeeInTitle.mustache +5 -1
- package/docs/webapi/doubleClick.mustache +2 -2
- package/docs/webapi/downloadFile.mustache +2 -2
- package/docs/webapi/dragAndDrop.mustache +2 -2
- package/docs/webapi/dragSlider.mustache +2 -2
- package/docs/webapi/executeAsyncScript.mustache +1 -1
- package/docs/webapi/executeScript.mustache +1 -1
- package/docs/webapi/fillField.mustache +2 -2
- package/docs/webapi/grabAttributeFrom.mustache +3 -2
- package/docs/webapi/grabBrowserLogs.mustache +3 -1
- package/docs/webapi/grabCookie.mustache +2 -1
- package/docs/webapi/grabCssPropertyFrom.mustache +3 -2
- package/docs/webapi/grabCurrentUrl.mustache +3 -1
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +19 -0
- package/docs/webapi/grabHTMLFrom.mustache +2 -1
- package/docs/webapi/grabNumberOfOpenTabs.mustache +4 -2
- package/docs/webapi/grabNumberOfVisibleElements.mustache +3 -2
- package/docs/webapi/grabPageScrollPosition.mustache +3 -1
- package/docs/webapi/grabSource.mustache +3 -1
- package/docs/webapi/grabTextFrom.mustache +2 -1
- package/docs/webapi/grabTitle.mustache +3 -1
- package/docs/webapi/grabValueFrom.mustache +2 -1
- package/docs/webapi/moveCursorTo.mustache +3 -3
- package/docs/webapi/pressKey.mustache +1 -1
- package/docs/webapi/resizeWindow.mustache +2 -2
- package/docs/webapi/rightClick.mustache +2 -2
- package/docs/webapi/saveScreenshot.mustache +3 -3
- package/docs/webapi/say.mustache +2 -2
- package/docs/webapi/scrollPageToBottom.mustache +1 -1
- package/docs/webapi/scrollPageToTop.mustache +1 -1
- package/docs/webapi/scrollTo.mustache +3 -3
- package/docs/webapi/see.mustache +2 -2
- package/docs/webapi/seeAttributesOnElements.mustache +3 -3
- package/docs/webapi/seeCheckboxIsChecked.mustache +2 -1
- package/docs/webapi/seeCookie.mustache +1 -1
- package/docs/webapi/seeCssPropertiesOnElements.mustache +2 -2
- package/docs/webapi/seeCurrentUrlEquals.mustache +1 -1
- package/docs/webapi/seeElement.mustache +1 -1
- package/docs/webapi/seeElementInDOM.mustache +1 -1
- package/docs/webapi/seeInCurrentUrl.mustache +1 -1
- package/docs/webapi/seeInField.mustache +2 -2
- package/docs/webapi/seeInSource.mustache +1 -1
- package/docs/webapi/seeInTitle.mustache +5 -1
- package/docs/webapi/seeNumberOfElements.mustache +10 -0
- package/docs/webapi/seeNumberOfVisibleElements.mustache +2 -2
- package/docs/webapi/selectOption.mustache +2 -2
- package/docs/webapi/setCookie.mustache +1 -1
- package/docs/webapi/switchTo.mustache +6 -1
- package/docs/webapi/uncheckOption.mustache +2 -2
- package/docs/webapi/wait.mustache +1 -2
- package/docs/webapi/waitForDetached.mustache +3 -3
- package/docs/webapi/waitForElement.mustache +2 -2
- package/docs/webapi/waitForEnabled.mustache +1 -1
- package/docs/webapi/waitForFunction.mustache +3 -3
- package/docs/webapi/waitForInvisible.mustache +3 -3
- package/docs/webapi/waitForText.mustache +3 -3
- package/docs/webapi/waitForValue.mustache +3 -3
- package/docs/webapi/waitForVisible.mustache +3 -3
- package/docs/webapi/waitInUrl.mustache +2 -2
- package/docs/webapi/waitNumberOfVisibleElements.mustache +3 -3
- package/docs/webapi/waitToHide.mustache +3 -3
- package/docs/webapi/waitUntil.mustache +3 -3
- package/docs/webapi/waitUrlEquals.mustache +2 -2
- package/docs/webdriver.md +453 -0
- package/lib/codecept.js +11 -9
- package/lib/command/definitions.js +183 -30
- package/lib/command/gherkin/snippets.js +29 -9
- package/lib/command/init.js +31 -9
- package/lib/command/run-multiple.js +46 -59
- package/lib/command/utils.js +1 -1
- package/lib/container.js +30 -4
- package/lib/data/dataScenarioConfig.js +18 -0
- package/lib/helper/Appium.js +24 -24
- package/lib/helper/Nightmare.js +81 -84
- package/lib/helper/Polly.js +189 -0
- package/lib/helper/Protractor.js +96 -86
- package/lib/helper/Puppeteer.js +238 -113
- package/lib/helper/REST.js +1 -1
- package/lib/helper/TestCafe.js +1257 -0
- package/lib/helper/WebDriver.js +217 -277
- package/lib/helper/WebDriverIO.js +75 -75
- package/lib/helper/clientscripts/nightmare.js +8 -0
- package/lib/helper/extras/React.js +55 -0
- package/lib/helper/testcafe/testControllerHolder.js +42 -0
- package/lib/helper/testcafe/testcafe-utils.js +63 -0
- package/lib/history.js +39 -0
- package/lib/hooks.js +25 -1
- package/lib/interfaces/gherkin.js +17 -1
- package/lib/interfaces/scenarioConfig.js +2 -2
- package/lib/listener/config.js +3 -3
- package/lib/locator.js +6 -0
- package/lib/pause.js +22 -1
- package/lib/plugin/allure.js +63 -0
- package/lib/plugin/autoLogin.js +65 -16
- package/lib/plugin/puppeteerCoverage.js +6 -1
- package/lib/plugin/stepByStepReport.js +4 -3
- package/lib/scenario.js +23 -17
- package/lib/step.js +5 -2
- package/lib/ui.js +1 -1
- package/lib/utils.js +70 -20
- package/package.json +20 -19
- package/translations/de-DE.js +69 -0
- package/translations/index.js +1 -0
- package/docs/video.md +0 -26
package/docs/basics.md
CHANGED
|
@@ -30,20 +30,23 @@ Here is the diagram of CodeceptJS architecture
|
|
|
30
30
|
All helpers share the same API so it's easy to migrate tests from one backend to other.
|
|
31
31
|
However, because of difference in backends and their limitations, they are not guaranteed to be compatible with each other. For instance, you can't set request headers in WebDriver or Protractor, but you can do so in Puppteer or Nightmare.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
**Pick one helper, as it defines how tests are executed.** If requirements change it's easy to migrate to another, but don't use few helpers of same kind at once.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
---
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
Refer to following guides to more information on:
|
|
38
|
+
|
|
39
|
+
* [▶ WebDriver](https://codecept.io/webdriver)
|
|
40
|
+
* [▶ Protractor](https://codecept.io/angular)
|
|
41
|
+
* [▶ Puppeteer](https://codecept.io/puppeteer)
|
|
42
|
+
* [▶ Nightmare](https://codecept.io/nightmare)
|
|
43
|
+
* TestCafe
|
|
44
|
+
|
|
45
|
+
> ℹ Depending on a helper selected a list of available actions may change.
|
|
46
|
+
|
|
47
|
+
To list all available commands for current configuration run `codeceptjs list`
|
|
48
|
+
or enable [auto-completion by generating TypeScript definitions](#intellisense).
|
|
45
49
|
|
|
46
|
-
In this config config all methods of `I` will be taken from `WebDriver` helper.
|
|
47
50
|
|
|
48
51
|
## Writing Tests
|
|
49
52
|
|
|
@@ -56,11 +59,221 @@ I.see('Please Login', 'h1');
|
|
|
56
59
|
// ...
|
|
57
60
|
```
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
### Opening a Page
|
|
63
|
+
|
|
64
|
+
A test should usually start with navigating browser to the website.
|
|
65
|
+
|
|
66
|
+
Start a test by opening a page. Use `I.amOnPage()` command for this:
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
// When "http://site.com" is url in config
|
|
70
|
+
I.amOnPage('/'); // -> opens http://site.com/
|
|
71
|
+
I.amOnPage('/about'); // -> opens http://site.com/about
|
|
72
|
+
I.amOnPage('https://google.com'); // -> https://google.com
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
When URL doesn't start with a protocol (http:// or https://) it is considered to be a relative URL and appended to URL which was initially set in the config.
|
|
76
|
+
|
|
77
|
+
> It is recommended to use relative URLs and keep base URL in config file, so you could easily switch between development, staging, and production environments.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
### Locating Element
|
|
81
|
+
|
|
82
|
+
Element can be found by CSS or XPath locators.
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
I.seeElement('.user'); // element with CSS class user
|
|
86
|
+
I.seeElement('//button[contains(., "press me")]'); // button
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
By default CodeceptJS tries to guess the locator type.
|
|
90
|
+
In order to specify exact locator type you can pass an object called **strict locator**.
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
I.seeElement({css: 'div.user'});
|
|
94
|
+
I.seeElement({xpath: '//div[@class=user]'});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Strict locators allow to specify additional locator types:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
// locate form element by name
|
|
101
|
+
I.seeElement({name: 'password'});
|
|
102
|
+
// locate element by id
|
|
103
|
+
I.seeElement({id: 'users'});
|
|
104
|
+
// locate element by React component and props
|
|
105
|
+
I.seeElement({react: 'user-profile', props: {name: 'davert'}});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
In [mobile testing](http://codecept.io/mobile/#locating-elements) you can use `~` to specify accessibility id to locate an element. In web application you can locate element by their `aria-label` value.
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
// locate element by [aria-label] attribute in web
|
|
112
|
+
// or by accessibility id in mobile
|
|
113
|
+
I.seeElement('~username');
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> [▶ Learn more about using locators in CodeceptJS](https://codecept.io/locators).
|
|
117
|
+
|
|
118
|
+
### Clicking
|
|
119
|
+
|
|
120
|
+
CodeceptJS provides a flexible syntax to specify an element to click.
|
|
121
|
+
|
|
122
|
+
By default CodeceptJS tries to find button or link with exact text on it
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
// search for link or button
|
|
126
|
+
I.click('Login');
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
If none found, CodeceptJS tries to find link or button containing that text. In case an image is clickable its `alt` attribute will be checked for text inclusion. Form buttons will also be searched by name.
|
|
130
|
+
|
|
131
|
+
To narrow down the results you can specify a context in second parameter.
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
I.click('Login', '.nav'); // search only in .nav
|
|
135
|
+
I.click('Login', {css: 'footer'}); // search only in footer
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> To skip guessing locator type pass in a strict locator. A locator starting with '#' or '.' is considered to be CSS. Locator starting with '//' or './/' is considered to be XPath.
|
|
139
|
+
|
|
140
|
+
You are not limited to buttons and links. Any element can be found by passing in valid CSS or XPath:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
// click element by CSS
|
|
144
|
+
I.click('#signup');
|
|
145
|
+
// click element located by special test-id attribute
|
|
146
|
+
I.click('//dev[@test-id="myid"]');
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Filling Fields
|
|
150
|
+
|
|
151
|
+
Clicking the links is not what takes the most time during testing a web site. If your site consists only of links you can skip test automation. The most routine waste of time goes into the testing of forms. CodeceptJS provides several ways of doing that.
|
|
152
|
+
|
|
153
|
+
Let's submit this sample form for a test:
|
|
154
|
+
|
|
155
|
+
```html
|
|
156
|
+
<form method="post" action="/update" id="update_form">
|
|
157
|
+
<label for="user_name">Name</label>
|
|
158
|
+
<input type="text" name="user[name]" id="user_name" />
|
|
159
|
+
<label for="user_email">Email</label>
|
|
160
|
+
<input type="text" name="user[email]" id="user_email" />
|
|
161
|
+
<label for="user_gender">Gender</label>
|
|
162
|
+
<select id="user_gender" name="user[gender]">
|
|
163
|
+
<option value="m">Male</option>
|
|
164
|
+
<option value="f">Female</option>
|
|
165
|
+
</select>
|
|
166
|
+
<input type="submit" name="submitButton" value="Update" />
|
|
167
|
+
</form>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
We need to fill in all those fields and click "Update" button. CodeceptJS matches form elements by their label, name, or by CSS or XPath locators.
|
|
171
|
+
|
|
172
|
+
```js
|
|
173
|
+
// we are using label to match user_name field
|
|
174
|
+
I.fillField('Name', 'Miles');
|
|
175
|
+
// we can use input name
|
|
176
|
+
I.fillField('user[email]','miles@davis.com');
|
|
177
|
+
// select element by label, choose option by text
|
|
178
|
+
I.selectOption('Gender','Male');
|
|
179
|
+
// click 'Update' button, found by text
|
|
180
|
+
I.click('Update');
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Alternative scenario:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
// we are using CSS
|
|
187
|
+
I.fillField('#user_name', 'Miles');
|
|
188
|
+
I.fillField('#user_email','miles@davis.com');
|
|
189
|
+
// select element by label, option by value
|
|
190
|
+
I.selectOption('#user_gender','m');
|
|
191
|
+
// click 'Update' button, found by name
|
|
192
|
+
I.click('submitButton', '#update_form');
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
To fill in sensitive data use `secret` function:
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
I.fillField('password', secret('123456'));
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Assertions
|
|
202
|
+
|
|
203
|
+
In order to verify the expected behavior of a web application, a content should be checked.
|
|
204
|
+
CodeceptJS provides built-in assertions for that. They start with `see` (or `dontSee`) prefix.
|
|
205
|
+
|
|
206
|
+
The most general and common assertion is `see`, which checks visilibility of a text on a page:
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
// Just a visible text on a page
|
|
210
|
+
I.see('Hello');
|
|
211
|
+
// text inside .msg element
|
|
212
|
+
I.see('Hello', '.msg');
|
|
213
|
+
// opposite
|
|
214
|
+
I.dontSee('Bye');
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
You should provide a text as first argument and optionally a locator to search for a text in a context.
|
|
218
|
+
|
|
219
|
+
You can check that specific element exists (or not) on a page, as it was described in [Locating Element](#locating-element) section.
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
I.seeElement('.notice');
|
|
223
|
+
I.dontSeeElement('.error');
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Additional assertions:
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
I.seeInCurrentUrl('/user/miles');
|
|
230
|
+
I.seeInField('user[name]', 'Miles');
|
|
231
|
+
I.seeInTitle('My Website');
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
To see all possible assertions see the helper's reference.
|
|
235
|
+
|
|
236
|
+
### Grabbing
|
|
237
|
+
|
|
238
|
+
Sometimes you need to retrieve a data from a page to use it in next steps of a scenario.
|
|
239
|
+
Imagine, application generates a password and you want to ensure that user can login using this password.
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
Scenario('login with generated password', async (I) => {
|
|
243
|
+
I.fillField('email', 'miles@davis.com');
|
|
244
|
+
I.click('Generate Password');
|
|
245
|
+
const password = await I.grabTextFrom('#password');
|
|
246
|
+
I.click('Login');
|
|
247
|
+
I.fillField('email', 'miles@davis.com');
|
|
248
|
+
I.fillField('password', password);
|
|
249
|
+
I.click('Log in!');
|
|
250
|
+
I.see('Hello, Miles');
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`grabTextFrom` action is used here to retrieve text from an element. All actions starting with `grab` prefix are expected to return data. In order to synchronize this step with a scenario you should pause test execution with `await` keyword of ES6. To make it work your test should be written inside a async function (notice `async` in its definition).
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
Scenario('use page title', async (I) => {
|
|
258
|
+
// ...
|
|
259
|
+
const password = await I.grabTextFrom('#password');
|
|
260
|
+
I.fillField('password', password);
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Waiting
|
|
61
265
|
|
|
62
|
-
|
|
63
|
-
|
|
266
|
+
In modern web applications rendering is happen on client side.
|
|
267
|
+
Sometimes that may cause delays. A test may fail while trying to click an element which has not appeared on a page yet.
|
|
268
|
+
To handle this cases `wait*` methods introduced.
|
|
269
|
+
|
|
270
|
+
```js
|
|
271
|
+
I.waitForElement('#agree_button', 30); // secs
|
|
272
|
+
// clicks a button only when it is visible
|
|
273
|
+
I.click('#agree_button');
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
> ℹ See [helpers reference](https://codecept.io/reference) for a complete list of all available commands for a helper you use.
|
|
64
277
|
|
|
65
278
|
## How It Works
|
|
66
279
|
|
|
@@ -197,6 +410,76 @@ This can be configured in [screenshotOnFail Plugin](https://codecept.io/plugins/
|
|
|
197
410
|
To see how the test was executed, use [stepByStepReport Plugin](https://codecept.io/plugins/#stepbystepreport). It saves a screenshot of each passed step and shows them in a nice slideshow.
|
|
198
411
|
|
|
199
412
|
|
|
413
|
+
## Retries
|
|
414
|
+
|
|
415
|
+
### Retry Step
|
|
416
|
+
|
|
417
|
+
If you have a step which often fails you can retry execution for this single step.
|
|
418
|
+
Use `retry()` function before an action to ask CodeceptJS to retry this step on failure:
|
|
419
|
+
|
|
420
|
+
```js
|
|
421
|
+
I.retry().see('Welcome');
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
If you'd like to retry step more than once pass the amount as parameter:
|
|
425
|
+
|
|
426
|
+
```js
|
|
427
|
+
I.retry(3).see('Welcome');
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Additional options can be provided to retry so you can set the additional options (defined in [promise-retry](https://www.npmjs.com/package/promise-retry) library).
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
```js
|
|
434
|
+
// retry action 3 times waiting for 0.1 second before next try
|
|
435
|
+
I.retry({ retries: 3, minTimeout: 100 }).see('Hello');
|
|
436
|
+
|
|
437
|
+
// retry action 3 times waiting no more than 3 seconds for last retry
|
|
438
|
+
I.retry({ retries: 3, maxTimeout: 3000 }).see('Hello');
|
|
439
|
+
|
|
440
|
+
// retry 2 times if error with message 'Node not visible' happens
|
|
441
|
+
I.retry({
|
|
442
|
+
retries: 2,
|
|
443
|
+
when: err => err.message === 'Node not visible'
|
|
444
|
+
}).seeElement('#user');
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Pass a function to `when` option to retry only when error matches the expected one.
|
|
448
|
+
|
|
449
|
+
### Auto Retry
|
|
450
|
+
|
|
451
|
+
You can auto-retry a failed step by enabling [retryFailedStep Plugin](https://codecept.io/plugins/#retryfailedstep).
|
|
452
|
+
|
|
453
|
+
### Retry Scenario
|
|
454
|
+
|
|
455
|
+
When you need to rerun scenarios few times just add `retries` option added to `Scenario` declaration.
|
|
456
|
+
|
|
457
|
+
CodeceptJS implements retries the same way [Mocha do](https://mochajs.org#retry-tests);
|
|
458
|
+
You can set number of a retries for a feature:
|
|
459
|
+
|
|
460
|
+
```js
|
|
461
|
+
Scenario('Really complex', (I) => {
|
|
462
|
+
// test goes here
|
|
463
|
+
}).retry(2);
|
|
464
|
+
|
|
465
|
+
// alternative
|
|
466
|
+
Scenario('Really complex', { retries: 2 }, (I) => {});
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
This scenario will be restarted two times on a failure.
|
|
470
|
+
|
|
471
|
+
### Retry Feature
|
|
472
|
+
|
|
473
|
+
To set this option for all scenarios in a file, add retry to a feature:
|
|
474
|
+
|
|
475
|
+
```js
|
|
476
|
+
Feature('Complex JS Stuff').retry(3);
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Every Scenario inside this feature will be rerun 3 times.
|
|
480
|
+
You can make an exception for a specific scenario by passing `retries` option to a Scenario.
|
|
481
|
+
|
|
482
|
+
|
|
200
483
|
## Before
|
|
201
484
|
|
|
202
485
|
Common preparation steps like opening a web page, logging in a user, can be placed in `Before` or `Background` hook:
|
|
@@ -258,7 +541,23 @@ within('.js-signup-form', () => {
|
|
|
258
541
|
I.see('There were problems creating your account.');
|
|
259
542
|
```
|
|
260
543
|
|
|
261
|
-
`within` can also work with
|
|
544
|
+
`within` can also work with IFrames. Special `frame` locator is required to locate the iframe and get into its context.
|
|
545
|
+
|
|
546
|
+
See example:
|
|
547
|
+
|
|
548
|
+
```js
|
|
549
|
+
within({frame: "#editor"}, () => {
|
|
550
|
+
I.see('Page');
|
|
551
|
+
});
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
Nested IFrames can be set by passing array *(WebDriver, Nightmare & Puppeteer only)*:
|
|
555
|
+
|
|
556
|
+
```js
|
|
557
|
+
within({frame: [".content", "#editor"]}, () => {
|
|
558
|
+
I.see('Page');
|
|
559
|
+
});
|
|
560
|
+
```
|
|
262
561
|
|
|
263
562
|
When running steps inside a within block will be shown with a shift:
|
|
264
563
|
|
|
@@ -293,91 +592,105 @@ I.say('This is blue', 'blue'); //blue is used
|
|
|
293
592
|
I.say('This is by default'); //cyan is used
|
|
294
593
|
```
|
|
295
594
|
|
|
296
|
-
##
|
|
595
|
+
## Multiple Sessions
|
|
297
596
|
|
|
298
|
-
|
|
299
|
-
you can generate step definitions with
|
|
597
|
+
CodeceptJS allows to run several browser sessions inside a test. This can be useful for testing communication between users inside a system, for instance in chats. To open another browser use `session()` function as shown in example:
|
|
300
598
|
|
|
301
|
-
```
|
|
302
|
-
|
|
599
|
+
```js
|
|
600
|
+
Scenario('test app', (I) => {
|
|
601
|
+
I.amOnPage('/chat');
|
|
602
|
+
I.fillField('name', 'davert');
|
|
603
|
+
I.click('Sign In');
|
|
604
|
+
I.see('Hello, davert');
|
|
605
|
+
session('john', () => {
|
|
606
|
+
// another session started
|
|
607
|
+
I.amOnPage('/chat');
|
|
608
|
+
I.fillField('name', 'john');
|
|
609
|
+
I.click('Sign In');
|
|
610
|
+
I.see('Hello, john');
|
|
611
|
+
});
|
|
612
|
+
// switching back to default session
|
|
613
|
+
I.fillField('message', 'Hi, john');
|
|
614
|
+
// there is a message from current user
|
|
615
|
+
I.see('me: Hi, john', '.messages');
|
|
616
|
+
session('john', () => {
|
|
617
|
+
// let's check if john received it
|
|
618
|
+
I.see('davert: Hi, john', '.messages');
|
|
619
|
+
});
|
|
620
|
+
});
|
|
303
621
|
```
|
|
304
622
|
|
|
305
|
-
|
|
306
|
-
method autocompletion while writing tests.
|
|
307
|
-
|
|
308
|
-
## Skipping
|
|
309
|
-
|
|
310
|
-
Like in Mocha you can use `x` and `only` to skip tests or making a single test to run.
|
|
311
|
-
|
|
312
|
-
* `xScenario` - skips current test
|
|
313
|
-
* `Scenario.only` - executes only the current test
|
|
314
|
-
|
|
623
|
+
`session` function expects a first parameter to be a name of a session. You can switch back to session by using the same name.
|
|
315
624
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
### Retry Step
|
|
319
|
-
|
|
320
|
-
If you have a step which often fails you can retry execution for this single step.
|
|
321
|
-
Use `retry()` function before an action to ask CodeceptJS to retry this step on failure:
|
|
625
|
+
You can override config for session by passing second parameter:
|
|
322
626
|
|
|
323
627
|
```js
|
|
324
|
-
|
|
628
|
+
session('john', { browser: 'firefox' } , () => {
|
|
629
|
+
// run this steps in firefox
|
|
630
|
+
I.amOnPage('/');
|
|
631
|
+
});
|
|
325
632
|
```
|
|
326
633
|
|
|
327
|
-
|
|
634
|
+
or just start session without switching to it. Call `session` passing only its name:
|
|
328
635
|
|
|
329
636
|
```js
|
|
330
|
-
|
|
331
|
-
|
|
637
|
+
Scenario('test', (I) => {
|
|
638
|
+
// opens 3 additional browsers
|
|
639
|
+
session('john');
|
|
640
|
+
session('mary');
|
|
641
|
+
session('jane');
|
|
332
642
|
|
|
333
|
-
|
|
643
|
+
I.amOnPage('/');
|
|
334
644
|
|
|
645
|
+
// switch to session by its name
|
|
646
|
+
session('mary', () => {
|
|
647
|
+
I.amOnPage('/login');
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
`session` can return value which can be used in scenario:
|
|
335
652
|
|
|
336
653
|
```js
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
// retry 2 times if error with message 'Node not visible' happens
|
|
344
|
-
I.retry({
|
|
345
|
-
retries: 2,
|
|
346
|
-
when: err => err.message === 'Node not visible'
|
|
347
|
-
}).seeElement('#user');
|
|
654
|
+
// inside async function
|
|
655
|
+
const val = await session('john', () => {
|
|
656
|
+
I.amOnPage('/info');
|
|
657
|
+
return I.grabTextFrom({ css: 'h1' });
|
|
658
|
+
});
|
|
659
|
+
I.fillField('Description', val);
|
|
348
660
|
```
|
|
349
661
|
|
|
350
|
-
|
|
662
|
+
Function passed into session can use `I`, page objects, and any objects declared for the scenario.
|
|
663
|
+
This function can also be declared as async (but doesn't work as generator).
|
|
351
664
|
|
|
352
|
-
|
|
665
|
+
Also, you can use `within` inside a session but you can't call session from inside `within`.
|
|
353
666
|
|
|
354
|
-
You can auto-retry a failed step by enabling [retryFailedStep Plugin](https://codecept.io/plugins/#retryfailedstep).
|
|
355
667
|
|
|
356
|
-
|
|
668
|
+
## IntelliSense
|
|
357
669
|
|
|
358
|
-
|
|
670
|
+
If you are using Visual Studio Code or other IDE that supports TypeScript Definitions,
|
|
671
|
+
you can generate step definitions with
|
|
359
672
|
|
|
360
|
-
|
|
361
|
-
|
|
673
|
+
```sh
|
|
674
|
+
codeceptjs def
|
|
675
|
+
```
|
|
362
676
|
|
|
363
|
-
|
|
364
|
-
Scenario('Really complex', (I) => {
|
|
365
|
-
// test goes here
|
|
366
|
-
}).retry(2);
|
|
677
|
+
Now you should create `jsconfig.json` in your project root directory.
|
|
367
678
|
|
|
368
|
-
|
|
369
|
-
|
|
679
|
+
```jsconfig.json
|
|
680
|
+
{
|
|
681
|
+
"compilerOptions": {
|
|
682
|
+
"allowJs": true,
|
|
683
|
+
}
|
|
684
|
+
}
|
|
370
685
|
```
|
|
686
|
+
but in usually case, this file has already generated when you execute `codeceptjs init`.
|
|
371
687
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
### Retry Feature
|
|
688
|
+
Alternatively, you can include `/// <reference path="./steps.d.ts" />` into your test files
|
|
689
|
+
to get method autocompletion while writing tests.
|
|
375
690
|
|
|
376
|
-
|
|
691
|
+
## Skipping
|
|
377
692
|
|
|
378
|
-
|
|
379
|
-
Feature('Complex JS Stuff').retry(3);
|
|
380
|
-
```
|
|
693
|
+
Like in Mocha you can use `x` and `only` to skip tests or making a single test to run.
|
|
381
694
|
|
|
382
|
-
|
|
383
|
-
|
|
695
|
+
* `xScenario` - skips current test
|
|
696
|
+
* `Scenario.only` - executes only the current test
|
package/docs/bdd.md
CHANGED
|
@@ -138,11 +138,12 @@ This scenarios are nice as live documentation but they do not test anything yet.
|
|
|
138
138
|
Steps can be defined by executing `gherkin:snippets` command:
|
|
139
139
|
|
|
140
140
|
```bash
|
|
141
|
-
codeceptjs gherkin:snippets
|
|
141
|
+
codeceptjs gherkin:snippets [--path=PATH] [--feature=PATH]
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
This will produce code templates for all undefined steps in
|
|
145
|
-
|
|
144
|
+
This will produce code templates for all undefined steps in the .feature files.
|
|
145
|
+
By default, it will scan all of the .feature files specified in the gherkin.features section of the config and produce code templates for all undefined steps. If the `--feature` option is specified, it will scan the specified .feature file(s).
|
|
146
|
+
The stub definitions by default will be placed into the first file specified in the gherkin.steps section of the config. However, you may also use `--path` to specify a specific file in which to place all undefined steps. This file must exist and be in the gherkin.steps array of the config.
|
|
146
147
|
Our next step will be to define those steps and transforming feature-file into a valid test.
|
|
147
148
|
|
|
148
149
|
### Step Definitions
|
package/docs/best.md
CHANGED
|
@@ -61,7 +61,7 @@ Scenario('editing a metric', async (I, loginAs, metricPage) => {
|
|
|
61
61
|
|
|
62
62
|
## Refactoring and PageObjects
|
|
63
63
|
|
|
64
|
-
When a project is growing and more and more tests are required, it's time to think about reusing test code
|
|
64
|
+
When a project is growing and more and more tests are required, it's time to think about reusing test code across the tests. Some common actions should be moved from tests to other files so to be accessible from different tests.
|
|
65
65
|
|
|
66
66
|
Here is a recommended strategy what to store where:
|
|
67
67
|
|
package/docs/books.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: books
|
|
3
|
+
title: Books & Posts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> Add your own books or posts to our [Wiki Page](https://github.com/Codeception/CodeceptJS/wiki/Books-&-Posts)
|
|
7
|
+
### [Practical End 2 End Testing with CodeceptJS](https://leanpub.com/codeceptjs/)
|
|
8
|
+
|
|
9
|
+
A book by **Paul Vincent Beigang**
|
|
10
|
+
|
|
11
|
+
[](https://leanpub.com/codeceptjs/)
|
|
12
|
+
|
|
13
|
+
#### Contents:
|
|
14
|
+
|
|
15
|
+
1. Preparation for End 2 End Testing with CodeceptJS
|
|
16
|
+
1. Setup CodeceptJS with WebdriverIO
|
|
17
|
+
1. Create Your First CodeceptJS Test
|
|
18
|
+
1. Run Your First CodeceptJS Test Locally
|
|
19
|
+
1. Run Test on BrowserStack Against with the Safari Browser
|
|
20
|
+
1. How to Debug & Fix a Failing E2E Test
|
|
21
|
+
1. Run a CodeceptJS Test in GitLab´s Continuous Integration (CI) Environment
|
|
22
|
+
1. Delicious Test Reports With Allure
|
|
23
|
+
|
|
24
|
+
### Posts
|
|
25
|
+
|
|
26
|
+
A list of good educational posts about CodeceptJS
|
|
27
|
+
|
|
28
|
+
* [Effective End2End Tests with CodeceptJS](https://hackernoon.com/effective-end-2-end-testing-in-javascript-with-codeceptjs-37c8d7d6a928) by @davertmik
|
|
29
|
+
* [Running End to End tests as Google Cloud Functions](https://hackernoon.com/running-end-to-end-tests-as-google-cloud-functions-f5e34ffc3984)
|
|
30
|
+
* [End-To-End Testing With CodeceptJS](https://www.monterail.com/blog/end-to-end-testing-with-codeceptjs) by Piotr Michalski
|
|
31
|
+
* [Getting started with CodeceptJS and Selenium WebDriver](https://medium.com/@garrettvorce/getting-started-with-selenium-and-codeceptjs-c0698e8df677)
|