codeceptjs 3.5.12-beta.2 → 3.5.12-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.
Files changed (213) hide show
  1. package/lib/locator.js +7 -12
  2. package/package.json +3 -5
  3. package/docs/advanced.md +0 -351
  4. package/docs/ai.md +0 -248
  5. package/docs/api.md +0 -323
  6. package/docs/basics.md +0 -979
  7. package/docs/bdd.md +0 -539
  8. package/docs/best.md +0 -237
  9. package/docs/books.md +0 -37
  10. package/docs/bootstrap.md +0 -135
  11. package/docs/build/ApiDataFactory.js +0 -410
  12. package/docs/build/Appium.js +0 -2027
  13. package/docs/build/Expect.js +0 -422
  14. package/docs/build/FileSystem.js +0 -228
  15. package/docs/build/GraphQL.js +0 -229
  16. package/docs/build/GraphQLDataFactory.js +0 -309
  17. package/docs/build/JSONResponse.js +0 -338
  18. package/docs/build/Mochawesome.js +0 -71
  19. package/docs/build/Nightmare.js +0 -2152
  20. package/docs/build/OpenAI.js +0 -126
  21. package/docs/build/Playwright.js +0 -5110
  22. package/docs/build/Protractor.js +0 -2706
  23. package/docs/build/Puppeteer.js +0 -3905
  24. package/docs/build/REST.js +0 -344
  25. package/docs/build/TestCafe.js +0 -2125
  26. package/docs/build/WebDriver.js +0 -4240
  27. package/docs/changelog.md +0 -2572
  28. package/docs/commands.md +0 -266
  29. package/docs/community-helpers.md +0 -58
  30. package/docs/configuration.md +0 -157
  31. package/docs/continuous-integration.md +0 -22
  32. package/docs/custom-helpers.md +0 -306
  33. package/docs/data.md +0 -379
  34. package/docs/detox.md +0 -235
  35. package/docs/docker.md +0 -136
  36. package/docs/email.md +0 -183
  37. package/docs/examples.md +0 -149
  38. package/docs/helpers/ApiDataFactory.md +0 -266
  39. package/docs/helpers/Appium.md +0 -1374
  40. package/docs/helpers/Detox.md +0 -586
  41. package/docs/helpers/Expect.md +0 -275
  42. package/docs/helpers/FileSystem.md +0 -152
  43. package/docs/helpers/GraphQL.md +0 -151
  44. package/docs/helpers/GraphQLDataFactory.md +0 -226
  45. package/docs/helpers/JSONResponse.md +0 -254
  46. package/docs/helpers/Mochawesome.md +0 -8
  47. package/docs/helpers/MockRequest.md +0 -377
  48. package/docs/helpers/Nightmare.md +0 -1305
  49. package/docs/helpers/OpenAI.md +0 -70
  50. package/docs/helpers/Playwright.md +0 -2759
  51. package/docs/helpers/Polly.md +0 -44
  52. package/docs/helpers/Protractor.md +0 -1769
  53. package/docs/helpers/Puppeteer-firefox.md +0 -86
  54. package/docs/helpers/Puppeteer.md +0 -2317
  55. package/docs/helpers/REST.md +0 -218
  56. package/docs/helpers/TestCafe.md +0 -1321
  57. package/docs/helpers/WebDriver.md +0 -2547
  58. package/docs/hooks.md +0 -340
  59. package/docs/index.md +0 -111
  60. package/docs/installation.md +0 -75
  61. package/docs/internal-api.md +0 -266
  62. package/docs/locators.md +0 -339
  63. package/docs/mobile-react-native-locators.md +0 -67
  64. package/docs/mobile.md +0 -338
  65. package/docs/pageobjects.md +0 -291
  66. package/docs/parallel.md +0 -400
  67. package/docs/playwright.md +0 -632
  68. package/docs/plugins.md +0 -1259
  69. package/docs/puppeteer.md +0 -316
  70. package/docs/quickstart.md +0 -162
  71. package/docs/react.md +0 -70
  72. package/docs/reports.md +0 -392
  73. package/docs/secrets.md +0 -36
  74. package/docs/shadow.md +0 -68
  75. package/docs/shared/keys.mustache +0 -31
  76. package/docs/shared/react.mustache +0 -1
  77. package/docs/testcafe.md +0 -174
  78. package/docs/translation.md +0 -247
  79. package/docs/tutorial.md +0 -271
  80. package/docs/typescript.md +0 -180
  81. package/docs/ui.md +0 -59
  82. package/docs/videos.md +0 -28
  83. package/docs/visual.md +0 -202
  84. package/docs/vue.md +0 -143
  85. package/docs/webapi/amOnPage.mustache +0 -11
  86. package/docs/webapi/appendField.mustache +0 -11
  87. package/docs/webapi/attachFile.mustache +0 -12
  88. package/docs/webapi/blur.mustache +0 -18
  89. package/docs/webapi/checkOption.mustache +0 -13
  90. package/docs/webapi/clearCookie.mustache +0 -9
  91. package/docs/webapi/clearField.mustache +0 -9
  92. package/docs/webapi/click.mustache +0 -25
  93. package/docs/webapi/clickLink.mustache +0 -8
  94. package/docs/webapi/closeCurrentTab.mustache +0 -7
  95. package/docs/webapi/closeOtherTabs.mustache +0 -8
  96. package/docs/webapi/dontSee.mustache +0 -11
  97. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  98. package/docs/webapi/dontSeeCookie.mustache +0 -8
  99. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  100. package/docs/webapi/dontSeeElement.mustache +0 -8
  101. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  102. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  103. package/docs/webapi/dontSeeInField.mustache +0 -11
  104. package/docs/webapi/dontSeeInSource.mustache +0 -8
  105. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  106. package/docs/webapi/doubleClick.mustache +0 -13
  107. package/docs/webapi/downloadFile.mustache +0 -12
  108. package/docs/webapi/dragAndDrop.mustache +0 -9
  109. package/docs/webapi/dragSlider.mustache +0 -11
  110. package/docs/webapi/executeAsyncScript.mustache +0 -24
  111. package/docs/webapi/executeScript.mustache +0 -26
  112. package/docs/webapi/fillField.mustache +0 -16
  113. package/docs/webapi/focus.mustache +0 -13
  114. package/docs/webapi/forceClick.mustache +0 -28
  115. package/docs/webapi/forceRightClick.mustache +0 -18
  116. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  117. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  118. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  119. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  120. package/docs/webapi/grabCookie.mustache +0 -11
  121. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  122. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  123. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  124. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  125. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  126. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  127. package/docs/webapi/grabGeoLocation.mustache +0 -8
  128. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  129. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  130. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  131. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  132. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  133. package/docs/webapi/grabPopupText.mustache +0 -5
  134. package/docs/webapi/grabSource.mustache +0 -8
  135. package/docs/webapi/grabTextFrom.mustache +0 -10
  136. package/docs/webapi/grabTextFromAll.mustache +0 -9
  137. package/docs/webapi/grabTitle.mustache +0 -8
  138. package/docs/webapi/grabValueFrom.mustache +0 -9
  139. package/docs/webapi/grabValueFromAll.mustache +0 -8
  140. package/docs/webapi/grabWebElement.mustache +0 -9
  141. package/docs/webapi/grabWebElements.mustache +0 -9
  142. package/docs/webapi/moveCursorTo.mustache +0 -12
  143. package/docs/webapi/openNewTab.mustache +0 -7
  144. package/docs/webapi/pressKey.mustache +0 -12
  145. package/docs/webapi/pressKeyDown.mustache +0 -12
  146. package/docs/webapi/pressKeyUp.mustache +0 -12
  147. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  148. package/docs/webapi/refreshPage.mustache +0 -6
  149. package/docs/webapi/resizeWindow.mustache +0 -6
  150. package/docs/webapi/rightClick.mustache +0 -14
  151. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  152. package/docs/webapi/saveScreenshot.mustache +0 -12
  153. package/docs/webapi/say.mustache +0 -10
  154. package/docs/webapi/scrollIntoView.mustache +0 -11
  155. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  156. package/docs/webapi/scrollPageToTop.mustache +0 -6
  157. package/docs/webapi/scrollTo.mustache +0 -12
  158. package/docs/webapi/see.mustache +0 -11
  159. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  160. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  161. package/docs/webapi/seeCookie.mustache +0 -8
  162. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  163. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  164. package/docs/webapi/seeElement.mustache +0 -8
  165. package/docs/webapi/seeElementInDOM.mustache +0 -8
  166. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  167. package/docs/webapi/seeInField.mustache +0 -12
  168. package/docs/webapi/seeInPopup.mustache +0 -8
  169. package/docs/webapi/seeInSource.mustache +0 -7
  170. package/docs/webapi/seeInTitle.mustache +0 -8
  171. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  172. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  173. package/docs/webapi/seeTextEquals.mustache +0 -9
  174. package/docs/webapi/seeTitleEquals.mustache +0 -8
  175. package/docs/webapi/selectOption.mustache +0 -21
  176. package/docs/webapi/setCookie.mustache +0 -16
  177. package/docs/webapi/setGeoLocation.mustache +0 -12
  178. package/docs/webapi/switchTo.mustache +0 -9
  179. package/docs/webapi/switchToNextTab.mustache +0 -10
  180. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  181. package/docs/webapi/type.mustache +0 -21
  182. package/docs/webapi/uncheckOption.mustache +0 -13
  183. package/docs/webapi/wait.mustache +0 -8
  184. package/docs/webapi/waitForClickable.mustache +0 -11
  185. package/docs/webapi/waitForDetached.mustache +0 -10
  186. package/docs/webapi/waitForElement.mustache +0 -11
  187. package/docs/webapi/waitForEnabled.mustache +0 -6
  188. package/docs/webapi/waitForFunction.mustache +0 -17
  189. package/docs/webapi/waitForInvisible.mustache +0 -10
  190. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  191. package/docs/webapi/waitForText.mustache +0 -13
  192. package/docs/webapi/waitForValue.mustache +0 -10
  193. package/docs/webapi/waitForVisible.mustache +0 -10
  194. package/docs/webapi/waitInUrl.mustache +0 -9
  195. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  196. package/docs/webapi/waitToHide.mustache +0 -10
  197. package/docs/webapi/waitUrlEquals.mustache +0 -10
  198. package/docs/webdriver.md +0 -701
  199. package/docs/wiki/Books-&-Posts.md +0 -27
  200. package/docs/wiki/Community-Helpers-&-Plugins.md +0 -53
  201. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -61
  202. package/docs/wiki/Examples.md +0 -145
  203. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
  204. package/docs/wiki/Home.md +0 -16
  205. package/docs/wiki/Migration-to-Appium-v2---CodeceptJS.md +0 -83
  206. package/docs/wiki/Release-Process.md +0 -24
  207. package/docs/wiki/Roadmap.md +0 -23
  208. package/docs/wiki/Tests.md +0 -1393
  209. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
  210. package/docs/wiki/Videos.md +0 -19
  211. package/lib/css2xpath/js/css_to_xpath.js +0 -20
  212. package/lib/css2xpath/js/expression.js +0 -23
  213. package/lib/css2xpath/js/renderer.js +0 -239
package/docs/mobile.md DELETED
@@ -1,338 +0,0 @@
1
- ---
2
- permalink: /mobile
3
- title: Mobile Testing with Appium
4
- ---
5
-
6
- # Mobile Testing with Appium
7
-
8
- CodeceptJS allows to test mobile and hybrid apps in a similar manner web applications are tested.
9
- Such tests are executed using [Appium](https://appium.io) on emulated or physical devices. Also, Appium allows to test web application on mobile devices.
10
-
11
- What makes CodeceptJS better for mobile testing?
12
- Take a look. Here is the sample test for a native mobile application written in CodeceptJS:
13
-
14
- ```js
15
- I.seeAppIsInstalled("io.super.app");
16
- I.click('~startUserRegistrationCD');
17
- I.fillField('~email of the customer', 'Nothing special');
18
- I.see('davert@codecept.io', '~email of the customer');
19
- I.clearField('~email of the customer');
20
- I.dontSee('Nothing special', '~email of the customer');
21
- I.seeElement({
22
- android: 'android.widget.Button',
23
- ios: '//UIAApplication[1]/UIAWindow[1]/UIAButton[1]'
24
- });
25
- ```
26
-
27
- This test is easy to read and write. Also, it will work both on iOS and Android devices.
28
- Doesn't it sound cool?
29
-
30
- ## Setting Up
31
-
32
- Ensure that you have [CodeceptJS installed](https://codecept.io/installation/).
33
- You will also need to install [Appium](https://appium.io/docs/en/2.1/).
34
- We suggest to use [appium-doctor](https://www.npmjs.com/package/appium-doctor) to check if your system is ready for mobile testing.
35
-
36
- ```sh
37
- npm i -g appium-doctor
38
- ```
39
-
40
- If everything is OK, continue with installing Appium. If not, consider using cloud based alternatives like [SauceLabs](https://saucelabs.com) or [BrowserStack](https://browserstack.com). Cloud services provide hosted appium with real and emulated mobile devices.
41
-
42
- To install Appium use npm:
43
-
44
- ```sh
45
- npm i -g appium
46
- ```
47
-
48
- Appium 2x reenvisions Appium as a platform where “drivers” and “plugins” can be easily created and shared independently.
49
-
50
- ** Note: ** Appium v1 is no longer maintained, so it's advised to migrate to Appium v2.
51
-
52
- Install an Appium driver and its dependencies
53
- To install the Appium driver and its dependencies, we'll be using the `uiautomator2` (Android), `XCUITest` (iOS) drivers.
54
-
55
- ```
56
- appium driver install xcuitest
57
- appium driver install uiautomator2
58
- ```
59
- To make sure that all the drivers are installed successfully, run the following command:
60
-
61
- ```
62
- appium driver list
63
-
64
- tth~$appium driver list
65
- ✔ Listing available drivers
66
- - espresso@2.17.0 [installed (NPM)]
67
- - uiautomator2@2.12.6 [installed (NPM)]
68
- - xcuitest@4.19.1 [installed (NPM)]
69
- - mac2 [not installed]
70
- - safari [not installed]
71
- - gecko [not installed]
72
- - chromium [not installed]
73
- ```
74
-
75
- Then you need to prepare application for execution.
76
- It should be packed into apk (for Android) or .ipa (for iOS) or zip.
77
-
78
- Next, is to launch the emulator or connect a physical device.
79
- Once they are prepared, launch Appium:
80
-
81
- ```sh
82
- tth~$npx appium --base-path=/wd/hub
83
- [Appium] Welcome to Appium v2.0.0-beta.57 (REV 3e675c32ae71dc0b00749d5d29213e2ea5b53c5b)
84
- [Appium] Non-default server args:
85
- [Appium] {
86
- [Appium] basePath: '/wd/hub'
87
- [Appium] }
88
- [Appium] Attempting to load driver espresso...
89
- [debug] [Appium] Requiring driver at /Users/trung-thanh/Desktop/thanh-nguyen/task2/node_modules/appium-espresso-driver
90
- [Appium] Attempting to load driver uiautomator2...
91
- [debug] [Appium] Requiring driver at /Users/trung-thanh/Desktop/thanh-nguyen/task2/node_modules/appium-uiautomator2-driver
92
- [Appium] Appium REST http interface listener started on 0.0.0.0:4723
93
- [Appium] Available drivers:
94
- [Appium] - espresso@2.17.0 (automationName 'Espresso')
95
- [Appium] - uiautomator2@2.12.6 (automationName 'UiAutomator2')
96
- [Appium] No plugins have been installed. Use the "appium plugin" command to install the one(s) you want to use.
97
- ```
98
-
99
- ** Note: ** Appium v2 doesn't use the same base path as Appium v1, hence if you want to use the same base path you should pass `--base-path=/wd/hub` when launching the Appium server.
100
-
101
- To run mobile test you need either a device emulator (available with Android SDK or iOS) or real device connected for mobile testing. Alternatively, you may execute Appium with device emulator inside Docker container.
102
-
103
- CodeceptJS should be installed with webdriverio support:
104
-
105
- ```bash
106
- npm install codeceptjs webdriverio@8.6.3 --save
107
- ```
108
-
109
- ## Configuring
110
-
111
- Initialize CodeceptJS with `init` command:
112
-
113
- ```sh
114
- npx codeceptjs init
115
- ```
116
-
117
- Select [Appium helper](https://codecept.io/helpers/Appium/) when asked.
118
-
119
- ```sh
120
- ? What helpers do you want to use?
121
- ◯ WebDriver
122
- ◯ Puppeteer
123
- ❯◉ Appium
124
- ◯ REST
125
- ```
126
-
127
- You will also be asked for the platform and the application package.
128
-
129
- ```sh
130
- ? [Appium] Application package. Path to file or url
131
- ```
132
-
133
- Check the newly created `codecept.conf.js` configuration file.
134
- You may want to set some additional Appium settings via [desiredCapabilities](https://appium.io/docs/en/2.1/guides/caps/)
135
-
136
- ```js
137
- helpers: {
138
- Appium: {
139
- app: "my_app.apk",
140
- platform: "Android",
141
- desiredCapabilities: {}
142
- }
143
- }
144
- ```
145
-
146
- Once you configured Appium, create the first test by running:
147
-
148
- ```sh
149
- npx codeceptjs gt
150
- ```
151
-
152
- ## BrowserStack Configuration
153
-
154
- If you wish to use BrowserStack's [Automated Mobile App Testing](https://www.browserstack.com/app-automate) platform. Configure the Appium helper like this:
155
-
156
- ```js
157
- helpers: {
158
- Appium: {
159
- app: "bs://<hashed app-id>",
160
- host: "hub-cloud.browserstack.com",
161
- port: 4444,
162
- platform: "ios",
163
- user: "BROWSERSTACK_USER",
164
- key: "BROWSERSTACK_KEY",
165
- device: "iPhone 7"
166
- }
167
- }
168
- ```
169
- Here is the full list of [capabilities](https://www.browserstack.com/app-automate/capabilities).
170
-
171
- You need to upload your Android app (.apk) or iOS app (.ipa) to the BrowserStack servers using the REST API before running your tests. The App URL (`bs://hashed appid`) is returned in the response of this call.
172
-
173
- ```sh
174
- curl -u "USERNAME:ACCESS_KEY" \
175
- -X POST "https://api-cloud.browserstack.com/app-automate/upload" \
176
- -F "file=@/path/to/app/file/Application-debug.apk"
177
- ```
178
-
179
- ## Writing a Test
180
-
181
- A test is written in a scenario-driven manner, listing an actions taken by a user.
182
- This is the sample test for a native mobile application:
183
-
184
- ```js
185
- Scenario('test registration', ({ I }) => {
186
- I.click('~startUserRegistrationCD');
187
- I.fillField('~inputUsername', 'davert');
188
- I.fillField('~inputEmail', 'davert@codecept.io');
189
- I.fillField('~inputPassword', '123456');
190
- I.hideDeviceKeyboard();
191
- I.click('~input_preferredProgrammingLanguage');
192
- I.click('Javascript');
193
- I.checkOption('#io.demo.testapp:id/input_adds');
194
- I.click('Register User (verify)');
195
- I.swipeUp("#io.selendroid.testapp:id/LinearLayout1");
196
- I.see('Javascript'); // see on the screen
197
- I.see('davert', '~label_username_data'); // see in element
198
- });
199
- ```
200
-
201
- Mobile test is pretty similar to a web test. And it is much the same, if you test hybrid app with a web view context inside.
202
- However, mobile apps do not have URLs, Cookies, they have other features which may vary on a running platform.
203
-
204
- There are mobile-only methods like:
205
-
206
- * `swipeUp`, `swipeLeft`, ...
207
- * `hideDeviceKeyboard`,
208
- * `seeAppIsInstalled`, `installApp`, `removeApp`, `seeAppIsNotInstalled` - Android only
209
-
210
- and [others](https://codecept.io/helpers/Appium/).
211
-
212
- ## Locating Elements
213
-
214
- To start writing a test it is important to understand how to locate elements for native mobile applications.
215
- In both Android and iPhone elements are defined in XML format and can be searched by XPath locators.
216
-
217
- ```js
218
- I.seeElement('//android.widget.ScrollView/android.widget.LinearLayout')
219
- ```
220
-
221
- > Despite showing XPath in this guide we **do not recommend using XPath for testing iOS native apps. XPath runs very slow on iOS. Consider using ID or Accessibility ID locators instead.
222
-
223
- CSS locators are not supported in native mobile apps, you need to switch to web context to use them.
224
-
225
- Elements can also be located by their accessability id, available both at Android and iOS.
226
- Accessibility id is recommended to use for locating element, as it rarely changed.
227
-
228
- * iOS uses [UIAccessibilityIdentification](https://developer.apple.com/documentation/uikit/uiaccessibilityidentification)
229
- * Android `accessibility id` matches the content-description
230
- * Web view uses `[aria-label]` attribute as accessibility id
231
- * For [React Native for Android see our special guide](mobile-react-native-locators.md).
232
-
233
- > If you test React Native application, consider using [Detox helper](/detox) for faster tests.
234
-
235
- Add `~` prefix to search for element by its accessibility id:
236
-
237
- ```js
238
- I.seeElement('~startUserRegistrationButton');
239
- ```
240
-
241
- Elements can also have ids, which can be located with `#` prefix.
242
- On Android, it is important to keep full package name in id locator:
243
-
244
- ```js
245
- I.seeElement('#io.selendroid.testapp:id/inputUsername');
246
- ```
247
-
248
- Buttons can be matched by their visible text:
249
-
250
- ```js
251
- I.tap('Click me!');
252
- I.click('Click me!');
253
- ```
254
-
255
- Native iOS/Android locators can be used with `android=` and `ios=` prefixes. [Learn more](https://webdriver.io/guide/usage/selectors.html#Mobile-Selectors).
256
-
257
- But how to get all those locators? We recommend to use [Appium Inspector](https://github.com/appium/appium-inspector).
258
-
259
- For Android, you can use **UI Automator Viewer** bundled with Android SDK:
260
-
261
- ![](https://user-images.githubusercontent.com/220264/27566310-1f631604-5aed-11e7-8b92-1ffe9e9f14f9.png)
262
-
263
- ## Hybrid Apps and Contexts
264
-
265
- Mobile applications may have different contexts. For instance, there can be native view and web view with a browser instance in it.
266
-
267
- To execute commands in context of a webview use `within('webview')` function:
268
-
269
- ```js
270
- I.click('~startWebView');
271
- within('webview', () => {
272
- I.see('Preferred car');
273
- I.click('Send me your name!');
274
- });
275
- ```
276
-
277
- It will locate first available webview, switch to it, and switch back to native application after.
278
- Inside WebView all browser features are enabled: CSS locators, JavaScript, etc.
279
-
280
- To set a specific context use `{ web: 'webview.context' }` instead:
281
-
282
- ```js
283
- within({webview: 'MyWEBVIEW_com.my.app'}, () => {});
284
- ```
285
-
286
- Alternatively use `switchToWeb` or `switchToNative` methods to switch between contexts.
287
-
288
- ```js
289
- I.click('~startWebView');
290
- I.switchToWeb();
291
- I.see('Preferred car');
292
- I.click('Send me your name!');
293
- I.switchToNative();
294
- ```
295
-
296
- To get a list of all contexts use `grabAllContexts` method:
297
-
298
- ```js
299
- let contexts = await I.grabAllContexts();
300
- ```
301
-
302
- ## Cross-Platform Testing
303
-
304
- It is often happen that mobile applications behave similarly on different platforms. Can we build one test for them? Yes!
305
- CodeceptJS provides a way to specify different locators for Android and iOS platforms:
306
-
307
- ```js
308
- I.click({android: '//android.widget.Button', ios: '//UIAApplication[1]/UIAWindow[1]/UIAButton[1]'});
309
- ```
310
-
311
- In case some code should be executed on one platform and ignored on others use `runOnAndroid` and `runOnIOS` methods:
312
-
313
- ```js
314
- I.runOnAndroid(() => {
315
- I.click('Hello Android');
316
- });
317
- I.runOnIOS(() => {
318
- I.click('Hello iOS');
319
- });
320
- ```
321
-
322
- The same code can be shared for web applications as well. To execute some code in web browser only, use `I.runInWeb`:
323
-
324
- ```js
325
- I.runInWeb(() => {
326
- I.amOnPage('/login'); // not available for mobile
327
- I.fillField('name', 'jon');
328
- I.fillField('password', '123456');
329
- I.click('Login');
330
- I.waitForElement('#success'); // no available for mobile
331
- });
332
- ```
333
-
334
- Just as you can specify android, and ios-specific locators, you can do so for web:
335
-
336
- ```js
337
- I.click({web: '#login', ios: '//UIAApplication[1]/UIAWindow[1]/UIAButton[1]'});
338
- ```
@@ -1,291 +0,0 @@
1
- ---
2
- permalink: /pageobjects
3
- title: Page Objects
4
- ---
5
-
6
- # Page Objects
7
-
8
- The UI of your web application has interaction areas which can be shared across different tests.
9
- To avoid code duplication you can put common locators and methods in one place.
10
-
11
- ## Dependency Injection
12
-
13
- All objects described here are injected via Dependency Injection, in a similar way AngularJS does. If you want an object to be injected in a scenario by its name, you can add it to the configuration:
14
-
15
- ```js
16
- include: {
17
- I: "./custom_steps.js",
18
- Smth: "./pages/Smth.js",
19
- loginPage: "./pages/Login.js",
20
- signinFragment: "./fragments/Signin.js"
21
- }
22
- ```
23
-
24
- These objects can now be retrieved by the name specified in the configuration.
25
-
26
- Required objects can be obtained via parameters in tests or via a global `inject()` call.
27
-
28
- ```js
29
- // globally inject objects by name
30
- const { I, myPage, mySteps } = inject();
31
-
32
- // inject objects for a test by name
33
- Scenario('sample test', ({ I, myPage, mySteps }) => {
34
- // ...
35
- });
36
- ```
37
-
38
- ## Actor
39
-
40
- During initialization you were asked to create a custom steps file. If you accepted this option, you are now able to use the `custom_steps.js` file to extend `I`. See how the `login` method can be added to `I`:
41
-
42
- ```js
43
- module.exports = function() {
44
- return actor({
45
-
46
- login: function(email, password) {
47
- this.fillField('Email', email);
48
- this.fillField('Password', password);
49
- this.click('Submit');
50
- }
51
- });
52
- }
53
- ```
54
-
55
- > ℹ Instead of `I` you should use `this` in the current context.
56
-
57
- ## PageObject
58
-
59
- If an application has different pages (login, admin, etc) you should use a page object.
60
- CodeceptJS can generate a template for it with the following command:
61
-
62
- ```sh
63
- npx codeceptjs gpo
64
- ```
65
-
66
- This will create a sample template for a page object and include it in the `codecept.json` config file.
67
-
68
- ```js
69
- const { I, otherPage } = inject();
70
-
71
- module.exports = {
72
-
73
- // insert your locators and methods here
74
- }
75
- ```
76
-
77
- As you see, the `I` object is available in scope, so you can use it just like you would do in tests.
78
- A general page object for a login page could look like this:
79
-
80
- ```js
81
- // enable I and another page object
82
- const { I, registerPage } = inject();
83
-
84
- module.exports = {
85
-
86
- // setting locators
87
- fields: {
88
- email: '#user_basic_email',
89
- password: '#user_basic_password'
90
- },
91
- submitButton: {css: '#new_user_basic input[type=submit]'},
92
-
93
- // introducing methods
94
- sendForm(email, password) {
95
- I.fillField(this.fields.email, email);
96
- I.fillField(this.fields.password, password);
97
- I.click(this.submitButton);
98
- },
99
-
100
- register(email, password) {
101
- // use another page object inside current one
102
- registerPage.registerUser({ email, password });
103
- }
104
- }
105
- ```
106
-
107
- You can include this pageobject in a test by its name (defined in `codecept.json`). If you created a `loginPage` object,
108
- it should be added to the list of arguments to be included in the test:
109
-
110
- ```js
111
- Scenario('login', ({ I, loginPage }) => {
112
- loginPage.sendForm('john@doe.com','123456');
113
- I.see('Hello, John');
114
- });
115
- ```
116
-
117
- Also, you can use `async/await` inside a Page Object:
118
-
119
- ```js
120
- const { I } = inject();
121
-
122
- module.exports = {
123
-
124
- // setting locators
125
- container: "//div[@class = 'numbers']",
126
- mainItem: {
127
- number: ".//div[contains(@class, 'numbers__main-number')]",
128
- title: ".//div[contains(@class, 'numbers__main-title-block')]"
129
- },
130
-
131
- // introducing methods
132
- async openMainArticle() {
133
- I.waitForVisible(this.container)
134
- let _this = this
135
- let title;
136
- await within(this.container, async () => {
137
- title = await I.grabTextFrom(_this.mainItem.number);
138
- let subtitle = await I.grabTextFrom(_this.mainItem.title);
139
- title = title + " " + subtitle.charAt(0).toLowerCase() + subtitle.slice(1);
140
- await I.click(_this.mainItem.title)
141
- })
142
- return title;
143
- }
144
- }
145
- ```
146
-
147
- and use them in your tests:
148
-
149
- ```js
150
- Scenario('login2', async ({ I, loginPage, basePage }) => {
151
- let title = await mainPage.openMainArticle()
152
- basePage.pageShouldBeOpened(title)
153
- });
154
- ```
155
-
156
- Page Objects can be be functions, arrays or classes. When declared as classes you can easily extend them in other page objects.
157
-
158
- Here is an example of declaring page object as a class:
159
-
160
- ```js
161
- const { expect } = require('chai');
162
- const { I } = inject();
163
-
164
- class AttachFile {
165
- constructor() {
166
- this.inputFileField = 'input[name=fileUpload]';
167
- this.fileSize = '.file-size';
168
- this.fileName = '.file-name'
169
- }
170
-
171
- async attachFileFrom(path) {
172
- await I.waitForVisible(this.inputFileField)
173
- await I.attachFile(this.inputFileField, path)
174
- }
175
-
176
- async hasFileSize(fileSizeText) {
177
- await I.waitForElement(this.fileSize)
178
- const size = await I.grabTextFrom(this.fileSize)
179
- expect(size).toEqual(fileSizeText)
180
- }
181
-
182
- async hasFileSizeInPosition(fileNameText, position) {
183
- await I.waitNumberOfVisibleElements(this.fileName, position)
184
- const text = await I.grabTextFrom(this.fileName)
185
- expect(text[position - 1]).toEqual(fileNameText)
186
- }
187
- }
188
-
189
- // For inheritance
190
- module.exports = new AttachFile();
191
- module.exports.AttachFile = AttachFile;
192
- ```
193
-
194
- > ⚠ While building complex page objects it is important to keep all `async` functions to be called with `await`. While CodeceptJS allows to run commands synchronously if async function has `I.grab*` or any custom function that returns a promise it must be called with `await`. If you see `UnhandledPromiseRejectionWarning` it might be caused by async page object function that was called without `await`.
195
-
196
- ## Page Fragments
197
-
198
- Similarly, CodeceptJS allows you to generate **PageFragments** and any other abstractions
199
- by running the `go` command with `--type` (or `-t`) option:
200
-
201
- ```sh
202
- npx codeceptjs go --type fragment
203
- ```
204
-
205
- Page Fragments represent autonomous parts of a page, like modal boxes, components, widgets.
206
- Technically, they are the same as PageObject but conceptually they are a bit different.
207
- For instance, it is recommended that Page Fragment includes a root locator of a component.
208
- Methods of page fragments can use `within` block to narrow scope to a root locator:
209
-
210
- ```js
211
- const { I } = inject();
212
- // fragments/modal.js
213
- module.exports = {
214
-
215
- root: '#modal',
216
-
217
- // we are clicking "Accept: inside a popup window
218
- accept() {
219
- within(this.root, function() {
220
- I.click('Accept');
221
- });
222
- }
223
- }
224
- ```
225
-
226
- To use a Page Fragment within a Test Scenario, just inject it into your Scenario:
227
-
228
- ```js
229
- Scenario('failed_login', async ({ I, loginPage, modal }) => {
230
- loginPage.sendForm('john@doe.com','wrong password');
231
- I.waitForVisible(modal.root);
232
- within(modal.root, function () {
233
- I.see('Login failed');
234
- })
235
- });
236
- ```
237
-
238
- To use a Page Fragment within a Page Object, you can use `inject` method to get it by its name.
239
-
240
- ```js
241
- const { I, modal } = inject();
242
-
243
- module.exports = {
244
- doStuff() {
245
- ...
246
- modal.accept();
247
- ...
248
- }
249
- }
250
- ```
251
-
252
- > PageObject and PageFragment names are declared inside `include` section of `codecept.conf.js`. See [Dependency Injection](#dependency-injection)
253
-
254
- ## StepObjects
255
-
256
- StepObjects represent complex actions which involve the usage of multiple web pages. For instance, creating users in the backend, changing permissions, etc.
257
- StepObject can be created similarly to PageObjects or PageFragments:
258
-
259
- ```sh
260
- npx codeceptjs go --type step
261
- ```
262
-
263
- Technically, they are the same as PageObjects. StepObjects can inject PageObjects and use multiple POs to make a complex scenarios:
264
-
265
- ```js
266
- const { I, userPage, permissionPage } = inject();
267
-
268
- module.exports = {
269
-
270
- createUser(name) {
271
- // action composed from actions of page objects
272
- userPage.open();
273
- userPage.create(name);
274
- permissionPage.activate(name);
275
- }
276
-
277
- };
278
- ```
279
-
280
- ## Dynamic Injection
281
-
282
- You can inject objects per test by calling `injectDependencies` function in a Scenario:
283
-
284
- ```js
285
- Scenario('search @grop', ({ I, Data }) => {
286
- I.fillField('Username', Data.username);
287
- I.pressKey('Enter');
288
- }).injectDependencies({ Data: require('./data.js') });
289
- ```
290
-
291
- This requires the `./data.js` module and assigns it to a `Data` argument in a test.