codeceptjs 4.0.0-rc.2 → 4.0.0-rc.20

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 (294) hide show
  1. package/README.md +39 -27
  2. package/bin/codecept.js +15 -2
  3. package/bin/codeceptq.js +49 -0
  4. package/bin/mcp-server.js +1187 -0
  5. package/docs/advanced.md +201 -0
  6. package/docs/agents.md +159 -0
  7. package/docs/ai.md +537 -0
  8. package/docs/aitrace.md +266 -0
  9. package/docs/api.md +332 -0
  10. package/docs/assertions.md +415 -0
  11. package/docs/auth.md +318 -0
  12. package/docs/basics.md +424 -0
  13. package/docs/bdd.md +539 -0
  14. package/docs/best.md +240 -0
  15. package/docs/bootstrap.md +132 -0
  16. package/docs/commands.md +352 -0
  17. package/docs/community-helpers.md +63 -0
  18. package/docs/configuration.md +230 -0
  19. package/docs/continuous-integration.md +497 -0
  20. package/docs/custom-helpers.md +297 -0
  21. package/docs/data.md +448 -0
  22. package/docs/debugging.md +332 -0
  23. package/docs/detox.md +235 -0
  24. package/docs/docker.md +136 -0
  25. package/docs/effects.md +179 -0
  26. package/docs/element-based-testing.md +295 -0
  27. package/docs/element-selection.md +125 -0
  28. package/docs/els.md +328 -0
  29. package/docs/examples.md +161 -0
  30. package/docs/heal.md +213 -0
  31. package/docs/helpers/ApiDataFactory.md +267 -0
  32. package/docs/helpers/Appium.md +1405 -0
  33. package/docs/helpers/Detox.md +665 -0
  34. package/docs/helpers/ExpectHelper.md +275 -0
  35. package/docs/helpers/FileSystem.md +152 -0
  36. package/docs/helpers/GraphQL.md +152 -0
  37. package/docs/helpers/GraphQLDataFactory.md +226 -0
  38. package/docs/helpers/JSONResponse.md +255 -0
  39. package/docs/helpers/Mochawesome.md +8 -0
  40. package/docs/helpers/MockRequest.md +377 -0
  41. package/docs/helpers/MockServer.md +212 -0
  42. package/docs/helpers/Playwright.md +2969 -0
  43. package/docs/helpers/Polly.md +44 -0
  44. package/docs/helpers/Protractor.md +1769 -0
  45. package/docs/helpers/Puppeteer-firefox.md +86 -0
  46. package/docs/helpers/Puppeteer.md +2690 -0
  47. package/docs/helpers/REST.md +289 -0
  48. package/docs/helpers/SoftExpectHelper.md +352 -0
  49. package/docs/helpers/WebDriver.md +2682 -0
  50. package/docs/hooks.md +339 -0
  51. package/docs/index.md +111 -0
  52. package/docs/installation.md +83 -0
  53. package/docs/internal-api.md +265 -0
  54. package/docs/internal-test-server.md +89 -0
  55. package/docs/locators.md +355 -0
  56. package/docs/mcp.md +485 -0
  57. package/docs/migration-4.md +556 -0
  58. package/docs/mobile.md +338 -0
  59. package/docs/pageobjects.md +399 -0
  60. package/docs/parallel.md +585 -0
  61. package/docs/playwright.md +714 -0
  62. package/docs/plugins.md +866 -0
  63. package/docs/puppeteer.md +314 -0
  64. package/docs/quickstart.md +120 -0
  65. package/docs/react.md +70 -0
  66. package/docs/reports.md +483 -0
  67. package/docs/retry.md +274 -0
  68. package/docs/secrets.md +150 -0
  69. package/docs/sessions.md +80 -0
  70. package/docs/shadow.md +68 -0
  71. package/docs/test-structure.md +275 -0
  72. package/docs/timeouts.md +183 -0
  73. package/docs/translation.md +247 -0
  74. package/docs/tutorial.md +271 -0
  75. package/docs/typescript.md +374 -0
  76. package/docs/web-element.md +251 -0
  77. package/docs/webdriver.md +708 -0
  78. package/docs/within.md +55 -0
  79. package/lib/ai.js +3 -2
  80. package/lib/aria.js +260 -0
  81. package/lib/assertions.js +18 -0
  82. package/lib/codecept.js +26 -23
  83. package/lib/command/check.js +2 -1
  84. package/lib/command/dryRun.js +24 -5
  85. package/lib/command/generate.js +2 -0
  86. package/lib/command/gherkin/snippets.js +5 -4
  87. package/lib/command/init.js +248 -269
  88. package/lib/command/list.js +150 -10
  89. package/lib/command/query.js +218 -0
  90. package/lib/command/run-multiple.js +2 -0
  91. package/lib/command/run-workers.js +2 -0
  92. package/lib/command/run.js +1 -1
  93. package/lib/command/workers/runTests.js +10 -10
  94. package/lib/config.js +77 -4
  95. package/lib/container.js +114 -17
  96. package/lib/effects.js +17 -0
  97. package/lib/element/WebElement.js +246 -2
  98. package/lib/els.js +12 -6
  99. package/lib/globals.js +32 -19
  100. package/lib/heal.js +4 -3
  101. package/lib/helper/ApiDataFactory.js +2 -1
  102. package/lib/helper/Appium.js +8 -8
  103. package/lib/helper/FileSystem.js +3 -2
  104. package/lib/helper/GraphQLDataFactory.js +2 -1
  105. package/lib/helper/Playwright.js +228 -162
  106. package/lib/helper/Puppeteer.js +208 -76
  107. package/lib/helper/WebDriver.js +173 -68
  108. package/lib/helper/errors/MultipleElementsFound.js +27 -110
  109. package/lib/helper/errors/NonFocusedType.js +8 -0
  110. package/lib/helper/extras/Download.js +45 -0
  111. package/lib/helper/extras/PlaywrightReactVueLocator.js +45 -36
  112. package/lib/helper/extras/elementSelection.js +58 -0
  113. package/lib/helper/extras/focusCheck.js +43 -0
  114. package/lib/helper/extras/richTextEditor.js +178 -0
  115. package/lib/helper/scripts/dropFile.js +11 -0
  116. package/lib/history.js +3 -2
  117. package/lib/html.js +103 -16
  118. package/lib/index.js +9 -1
  119. package/lib/listener/config.js +6 -4
  120. package/lib/listener/emptyRun.js +2 -1
  121. package/lib/listener/globalRetry.js +32 -6
  122. package/lib/listener/helpers.js +4 -1
  123. package/lib/listener/mocha.js +2 -1
  124. package/lib/listener/pageobjects.js +43 -0
  125. package/lib/listener/result.js +3 -2
  126. package/lib/locator.js +126 -3
  127. package/lib/mocha/cli.js +14 -2
  128. package/lib/mocha/factory.js +7 -2
  129. package/lib/mocha/inject.js +1 -1
  130. package/lib/mocha/scenarioConfig.js +2 -1
  131. package/lib/mocha/ui.js +5 -6
  132. package/lib/parser.js +2 -2
  133. package/lib/pause.js +38 -4
  134. package/lib/plugin/aiTrace.js +453 -0
  135. package/lib/plugin/analyze.js +1 -1
  136. package/lib/plugin/auth.js +3 -3
  137. package/lib/plugin/browser.js +77 -0
  138. package/lib/plugin/expose.js +159 -0
  139. package/lib/plugin/heal.js +44 -1
  140. package/lib/plugin/pageInfo.js +53 -49
  141. package/lib/plugin/pause.js +131 -0
  142. package/lib/plugin/pauseOnFail.js +10 -34
  143. package/lib/plugin/retryFailedStep.js +28 -19
  144. package/lib/plugin/screencast.js +287 -0
  145. package/lib/plugin/screenshot.js +563 -0
  146. package/lib/plugin/screenshotOnFail.js +8 -171
  147. package/lib/rerun.js +2 -1
  148. package/lib/result.js +2 -1
  149. package/lib/step/base.js +3 -2
  150. package/lib/step/config.js +15 -2
  151. package/lib/step/record.js +2 -2
  152. package/lib/store.js +72 -3
  153. package/lib/translation.js +2 -1
  154. package/lib/utils/mask_data.js +2 -1
  155. package/lib/utils/pluginParser.js +151 -0
  156. package/lib/utils/trace.js +297 -0
  157. package/lib/utils.js +77 -3
  158. package/lib/workers.js +52 -22
  159. package/package.json +19 -13
  160. package/typings/index.d.ts +19 -5
  161. package/docs/webapi/amOnPage.mustache +0 -11
  162. package/docs/webapi/appendField.mustache +0 -11
  163. package/docs/webapi/attachFile.mustache +0 -12
  164. package/docs/webapi/blur.mustache +0 -18
  165. package/docs/webapi/checkOption.mustache +0 -13
  166. package/docs/webapi/clearCookie.mustache +0 -9
  167. package/docs/webapi/clearField.mustache +0 -9
  168. package/docs/webapi/click.mustache +0 -29
  169. package/docs/webapi/clickLink.mustache +0 -8
  170. package/docs/webapi/closeCurrentTab.mustache +0 -7
  171. package/docs/webapi/closeOtherTabs.mustache +0 -8
  172. package/docs/webapi/dontSee.mustache +0 -11
  173. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  174. package/docs/webapi/dontSeeCookie.mustache +0 -8
  175. package/docs/webapi/dontSeeCurrentPathEquals.mustache +0 -10
  176. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  177. package/docs/webapi/dontSeeElement.mustache +0 -8
  178. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  179. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  180. package/docs/webapi/dontSeeInField.mustache +0 -11
  181. package/docs/webapi/dontSeeInSource.mustache +0 -8
  182. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  183. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  184. package/docs/webapi/doubleClick.mustache +0 -13
  185. package/docs/webapi/downloadFile.mustache +0 -12
  186. package/docs/webapi/dragAndDrop.mustache +0 -9
  187. package/docs/webapi/dragSlider.mustache +0 -11
  188. package/docs/webapi/executeAsyncScript.mustache +0 -24
  189. package/docs/webapi/executeScript.mustache +0 -26
  190. package/docs/webapi/fillField.mustache +0 -16
  191. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  192. package/docs/webapi/focus.mustache +0 -13
  193. package/docs/webapi/forceClick.mustache +0 -28
  194. package/docs/webapi/forceRightClick.mustache +0 -18
  195. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  196. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  197. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  198. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  199. package/docs/webapi/grabCookie.mustache +0 -11
  200. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  201. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  202. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  203. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  204. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  205. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  206. package/docs/webapi/grabGeoLocation.mustache +0 -8
  207. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  208. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  209. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  210. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  211. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  212. package/docs/webapi/grabPopupText.mustache +0 -5
  213. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  214. package/docs/webapi/grabSource.mustache +0 -8
  215. package/docs/webapi/grabTextFrom.mustache +0 -10
  216. package/docs/webapi/grabTextFromAll.mustache +0 -9
  217. package/docs/webapi/grabTitle.mustache +0 -8
  218. package/docs/webapi/grabValueFrom.mustache +0 -9
  219. package/docs/webapi/grabValueFromAll.mustache +0 -8
  220. package/docs/webapi/grabWebElement.mustache +0 -9
  221. package/docs/webapi/grabWebElements.mustache +0 -9
  222. package/docs/webapi/moveCursorTo.mustache +0 -12
  223. package/docs/webapi/openNewTab.mustache +0 -7
  224. package/docs/webapi/pressKey.mustache +0 -12
  225. package/docs/webapi/pressKeyDown.mustache +0 -12
  226. package/docs/webapi/pressKeyUp.mustache +0 -12
  227. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  228. package/docs/webapi/refreshPage.mustache +0 -6
  229. package/docs/webapi/resizeWindow.mustache +0 -6
  230. package/docs/webapi/rightClick.mustache +0 -14
  231. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  232. package/docs/webapi/saveScreenshot.mustache +0 -12
  233. package/docs/webapi/say.mustache +0 -10
  234. package/docs/webapi/scrollIntoView.mustache +0 -11
  235. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  236. package/docs/webapi/scrollPageToTop.mustache +0 -6
  237. package/docs/webapi/scrollTo.mustache +0 -12
  238. package/docs/webapi/see.mustache +0 -11
  239. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  240. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  241. package/docs/webapi/seeCookie.mustache +0 -8
  242. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  243. package/docs/webapi/seeCurrentPathEquals.mustache +0 -10
  244. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  245. package/docs/webapi/seeElement.mustache +0 -8
  246. package/docs/webapi/seeElementInDOM.mustache +0 -8
  247. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  248. package/docs/webapi/seeInField.mustache +0 -12
  249. package/docs/webapi/seeInPopup.mustache +0 -8
  250. package/docs/webapi/seeInSource.mustache +0 -7
  251. package/docs/webapi/seeInTitle.mustache +0 -8
  252. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  253. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  254. package/docs/webapi/seeTextEquals.mustache +0 -9
  255. package/docs/webapi/seeTitleEquals.mustache +0 -8
  256. package/docs/webapi/seeTraffic.mustache +0 -36
  257. package/docs/webapi/selectOption.mustache +0 -21
  258. package/docs/webapi/setCookie.mustache +0 -16
  259. package/docs/webapi/setGeoLocation.mustache +0 -12
  260. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  261. package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
  262. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  263. package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
  264. package/docs/webapi/switchTo.mustache +0 -9
  265. package/docs/webapi/switchToNextTab.mustache +0 -10
  266. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  267. package/docs/webapi/type.mustache +0 -21
  268. package/docs/webapi/uncheckOption.mustache +0 -13
  269. package/docs/webapi/wait.mustache +0 -8
  270. package/docs/webapi/waitForClickable.mustache +0 -11
  271. package/docs/webapi/waitForCookie.mustache +0 -9
  272. package/docs/webapi/waitForDetached.mustache +0 -10
  273. package/docs/webapi/waitForDisabled.mustache +0 -6
  274. package/docs/webapi/waitForElement.mustache +0 -11
  275. package/docs/webapi/waitForEnabled.mustache +0 -6
  276. package/docs/webapi/waitForFunction.mustache +0 -17
  277. package/docs/webapi/waitForInvisible.mustache +0 -10
  278. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  279. package/docs/webapi/waitForText.mustache +0 -13
  280. package/docs/webapi/waitForValue.mustache +0 -10
  281. package/docs/webapi/waitForVisible.mustache +0 -10
  282. package/docs/webapi/waitInUrl.mustache +0 -9
  283. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  284. package/docs/webapi/waitToHide.mustache +0 -10
  285. package/docs/webapi/waitUrlEquals.mustache +0 -10
  286. package/lib/helper/AI.js +0 -214
  287. package/lib/listener/enhancedGlobalRetry.js +0 -110
  288. package/lib/plugin/enhancedRetryFailedStep.js +0 -99
  289. package/lib/plugin/htmlReporter.js +0 -3648
  290. package/lib/plugin/stepByStepReport.js +0 -427
  291. package/lib/plugin/subtitles.js +0 -89
  292. package/lib/retryCoordinator.js +0 -207
  293. package/typings/promiseBasedTypes.d.ts +0 -9469
  294. package/typings/types.d.ts +0 -11402
package/docs/data.md ADDED
@@ -0,0 +1,448 @@
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 helpers for Data Management via REST and GraphQL API, as well as **[Data Objects](/pageobjects#data-objects)** — class-based page objects with automatic cleanup via lifecycle hooks.
22
+
23
+ ## Data Objects
24
+
25
+ Data Objects are page object classes designed to manage test data via API. They use the REST helper (through `I`) to create data in a test and clean it up automatically via the `_after()` hook.
26
+
27
+ This is a lightweight alternative to [ApiDataFactory](#api-data-factory) — ideal when you want full control over data creation and cleanup logic without factory configuration.
28
+
29
+ ### Defining a Data Object
30
+
31
+ ```js
32
+ const { I } = inject();
33
+
34
+ class UserData {
35
+ constructor() {
36
+ this._created = [];
37
+ }
38
+
39
+ async createUser(data = {}) {
40
+ const response = await I.sendPostRequest('/api/users', {
41
+ name: data.name || 'Test User',
42
+ email: data.email || `test-${Date.now()}@example.com`,
43
+ ...data,
44
+ });
45
+ this._created.push(response.data.id);
46
+ return response.data;
47
+ }
48
+
49
+ async createPost(userId, data = {}) {
50
+ const response = await I.sendPostRequest('/api/posts', {
51
+ userId,
52
+ title: data.title || 'Test Post',
53
+ body: data.body || 'Test body',
54
+ ...data,
55
+ });
56
+ this._created.push({ type: 'post', id: response.data.id });
57
+ return response.data;
58
+ }
59
+
60
+ async _after() {
61
+ for (const record of this._created.reverse()) {
62
+ const id = typeof record === 'object' ? record.id : record;
63
+ const type = typeof record === 'object' ? record.type : 'user';
64
+ try {
65
+ await I.sendDeleteRequest(`/api/${type}s/${id}`);
66
+ } catch (e) {
67
+ // cleanup errors should not fail the test
68
+ }
69
+ }
70
+ this._created = [];
71
+ }
72
+ }
73
+
74
+ export default UserData
75
+ ```
76
+
77
+ ### Configuration
78
+
79
+ Add the REST helper and the Data Object to your config:
80
+
81
+ ```js
82
+ helpers: {
83
+ Playwright: { url: 'http://localhost', browser: 'chromium' },
84
+ REST: {
85
+ endpoint: 'http://localhost/api',
86
+ defaultHeaders: { 'Content-Type': 'application/json' },
87
+ },
88
+ },
89
+ include: {
90
+ I: './steps_file.js',
91
+ userData: './data/UserData.js',
92
+ }
93
+ ```
94
+
95
+ ### Usage in Tests
96
+
97
+ ```js
98
+ Scenario('user sees their profile', async ({ I, userData }) => {
99
+ const user = await userData.createUser({ name: 'John Doe' });
100
+ I.amOnPage(`/users/${user.id}`);
101
+ I.see('John Doe');
102
+ // userData._after() runs automatically — deletes the created user
103
+ });
104
+ ```
105
+
106
+ Data Objects can use any helper methods available via `I`, including `sendGetRequest`, `sendPutRequest`, and browser actions. They combine the convenience of managed test data with the flexibility of page objects.
107
+
108
+ **Learn more:** See [Page Objects](/pageobjects) for general page object patterns.
109
+
110
+ ## REST
111
+
112
+ [REST helper](https://codecept.io/helpers/REST/) allows sending raw HTTP requests to application.
113
+ 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.
114
+
115
+ 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.
116
+
117
+ See the sample config:
118
+
119
+ ```js
120
+ helpers: {
121
+ REST: {
122
+ endpoint: "http://localhost/api/v1/",
123
+ defaultHeaders: {
124
+ 'Auth': '11111',
125
+ 'Content-Type': 'application/json',
126
+ 'Accept': 'application/json',
127
+ },
128
+ },
129
+ WebDriver : {
130
+ url: 'http://localhost',
131
+ browser: 'chrome'
132
+ }
133
+ }
134
+ ```
135
+
136
+ REST helper provides basic methods to send requests to application:
137
+
138
+ ```js
139
+ I.sendGetRequest()
140
+ I.sendPostRequest()
141
+ I.sendPutRequest()
142
+ I.sendPatchRequest()
143
+ I.sendDeleteRequest()
144
+ I.sendDeleteRequestWithPayload()
145
+ ```
146
+
147
+ As well as a method for setting headers: `haveRequestHeaders`.
148
+
149
+ Here is a usage example:
150
+
151
+ ```js
152
+ let postId = null
153
+
154
+ Scenario('check post page', async ({ I }) => {
155
+ // valid access token
156
+ I.haveRequestHeaders({ auth: '1111111' })
157
+ // get the first user
158
+ let user = await I.sendGetRequest('/api/users/1')
159
+ // create a post and save its Id
160
+ postId = await I.sendPostRequest('/api/posts', { author: user.id, body: 'some text' })
161
+ // open browser page of new post
162
+ I.amOnPage('/posts/2.html')
163
+ I.see('some text', 'p.body')
164
+ })
165
+
166
+ // cleanup created data
167
+ After(({ I }) => {
168
+ I.sendDeleteRequest('/api/posts/' + postId)
169
+ })
170
+ ```
171
+
172
+ This can also be used to emulate Ajax requests:
173
+
174
+ ```js
175
+ I.sendPostRequest('/update-status', {}, { http_x_requested_with: 'xmlhttprequest' })
176
+ ```
177
+
178
+ > See complete reference on [REST](https://codecept.io/helpers/REST) helper
179
+
180
+ ## GraphQL
181
+
182
+ [GraphQL helper](https://codecept.io/helpers/GraphQL/) allows sending GraphQL queries and mutations to application, over Http.
183
+
184
+ This tool allows you to create shortcuts and manage your data pragmatically via a GraphQL endpoint. However, it does not include tools for testing the endpoint, so it should be used in conjunction with WebDriver helpers for browser testing.
185
+
186
+ 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.
187
+
188
+ See the sample config:
189
+
190
+ ```js
191
+ helpers: {
192
+ GraphQL: {
193
+ endpoint: "http://localhost/graphql/",
194
+ defaultHeaders: {
195
+ 'Auth': '11111',
196
+ 'Content-Type': 'application/json',
197
+ 'Accept': 'application/json',
198
+ },
199
+ },
200
+ WebDriver : {
201
+ url: 'http://localhost',
202
+ browser: 'chrome'
203
+ }
204
+ }
205
+ ```
206
+
207
+ GraphQL helper provides two basic methods to queries and mutations to application:
208
+
209
+ ```js
210
+ I.sendQuery()
211
+ I.sendMutation()
212
+ ```
213
+
214
+ As well as a method for setting headers: `haveRequestHeaders`.
215
+
216
+ Here is a usage example:
217
+
218
+ ```js
219
+ let postData = null
220
+
221
+ Scenario('check post page', async ({ I }) => {
222
+ // valid access token
223
+ I.haveRequestHeaders({ auth: '1111111' })
224
+ // get the first user
225
+ let response = await I.sendQuery('{ user(id:1) { id }}')
226
+ let user = response.data
227
+ // create a post and save its Id
228
+ response = await I.sendMutation('mutation createPost($input: PostInput!) { createPost(input: $input) { id }}', {
229
+ input: {
230
+ author: user.data.id,
231
+ body: 'some text',
232
+ },
233
+ })
234
+ postData = response.data.data['createPost']
235
+ // open browser page of new post
236
+ I.amOnPage(`/posts/${postData.slug}.html`)
237
+ I.see(postData.body, 'p.body')
238
+ })
239
+
240
+ // cleanup created data
241
+ After(({ I }) => {
242
+ I.sendMutation('mutation deletePost($id: ID!) { deletePost(id: $id) }', { id: postData.id })
243
+ })
244
+ ```
245
+
246
+ > See complete reference on [GraphQL](https://codecept.io/helpers/GraphQL) helper
247
+
248
+ ## Data Generation with Factories
249
+
250
+ This concept is extended by:
251
+
252
+ - [ApiDataFactory](https://codecept.io/helpers/ApiDataFactory/) helper, and,
253
+ - [GraphQLDataFactory](https://codecept.io/helpers/GraphQLDataFactory/) helper.
254
+
255
+ 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.
256
+
257
+ Just define how many items of any kind you need and the data factory helper will create them for you.
258
+
259
+ To make this work some preparations are required.
260
+
261
+ At first, you need data generation libraries which are [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://fakerjs.dev). Faker can generate random names, emails, texts, and Rosie uses them
262
+ to generate objects using factories.
263
+
264
+ Install rosie and faker to create a first factory:
265
+
266
+ ```sh
267
+ npm i rosie @faker-js/faker --save-dev
268
+ ```
269
+
270
+ Then create a module which will export a factory for an entity.
271
+ And add that module as a part of the configuration for the helper.
272
+
273
+ Please look at the respective Factory sections for examples for factory modules and configuration.
274
+
275
+ ### API Data Factory
276
+
277
+ This helper uses REST API to store the built data and automatically clean them up after a test,
278
+ The way for setting data for a test is as simple as writing:
279
+
280
+ ```js
281
+ // inside async function
282
+ let post = await I.have('post')
283
+ I.haveMultiple('comment', 5, { postId: post.id })
284
+ ```
285
+
286
+ After completing the preparations under 'Data Generation with Factories', create a factory module which will export a factory.
287
+
288
+ See the example providing a factory for User generation:
289
+
290
+ ```js
291
+ // factories/post.js
292
+ import { Factory } from 'rosie'
293
+ import { faker } from '@faker-js/faker'
294
+
295
+ export default new Factory().attr('name', () => faker.person.findName()).attr('email', () => faker.internet.email())
296
+ ```
297
+
298
+ Next is to configure helper to match factories with API:
299
+
300
+ ```js
301
+ ApiDataFactory: {
302
+ endpoint: "http://user.com/api",
303
+ headers: {
304
+ 'Content-Type': 'application/json',
305
+ 'Accept': 'application/json',
306
+ },
307
+ factories: {
308
+ user: {
309
+ uri: "/users",
310
+ factory: "./factories/user"
311
+ }
312
+ }
313
+ }
314
+ ```
315
+
316
+ Then, calling `I.have('user')` inside a test will create a new user for you.
317
+ This is done by sending POST request to `/api/users` URL. Response is returned and can be used in tests.
318
+
319
+ At the end of a test ApiDataFactory will clean up created record for you. This is done by collecting
320
+ ids from crated records and running `DELETE /api/users/{id}` requests at the end of a test.
321
+ This rules can be customized in helper configuration.
322
+
323
+ > See complete reference on [ApiDataFactory](https://codecept.io/helpers/ApiDataFactory) helper
324
+
325
+ ### GraphQL Data Factory
326
+
327
+ The helper uses GraphQL mutations to store the built data and automatically clean them up after a test.
328
+ This way for setting data for a test is as simple as writing:
329
+
330
+ ```js
331
+ // inside async function
332
+ let post = await I.mutateData('createPost')
333
+ I.mutateMultiple('createComment', 5, { postId: post.id })
334
+ ```
335
+
336
+ After completing the preparations under 'Data Generation with Factories', create a factory module which will export a factory.
337
+
338
+ 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.
339
+
340
+ See the example providing a factory for User generation:
341
+
342
+ ```js
343
+ // factories/post.js
344
+ import { Factory } from 'rosie'
345
+ import { faker } from '@faker-js/faker'
346
+
347
+ export default new Factory((buildObj) => {
348
+ return {
349
+ input: { ...buildObj },
350
+ }
351
+ })
352
+ .attr('name', () => faker.person.findName())
353
+ .attr('email', () => faker.internet.email())
354
+ ```
355
+
356
+ Next is to configure helper to match factories with API:
357
+
358
+ ```js
359
+ GraphQLDataFactory: {
360
+ endpoint: "http://user.com/graphql",
361
+ cleanup: true,
362
+ headers: {
363
+ 'Content-Type': 'application/json',
364
+ 'Accept': 'application/json',
365
+ },
366
+ factories: {
367
+ createUser: {
368
+ query: 'mutation createUser($input: UserInput!) { createUser(input: $input) { id name }}',
369
+ factory: './factories/users',
370
+ revert: (data) => ({
371
+ query: 'mutation deleteUser($id: ID!) { deleteUser(id: $id) }',
372
+ variables: { id : data.id},
373
+ }),
374
+ },
375
+ }
376
+ ```
377
+
378
+ Then, calling `I.mutateData('createUser')` inside a test will create a new user for you.
379
+ This is done by sending a GraphQL mutation request over Http to `/graphql` endpoint. Response is returned and can be used in tests.
380
+
381
+ At the end of a test GraphQLDataFactory will clean up created record for you. This is done by collecting
382
+ 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.
383
+ This behavior is according the `revert` function be customized in helper configuration.
384
+ The revert function returns an object, that contains the query for deletion, and the variables object to go along with it.
385
+
386
+ > See complete reference on [GraphQLDataFactory](https://codecept.io/helpers/GraphQLDataFactory) helper
387
+
388
+ ## Requests Using Browser Session
389
+
390
+ All the REST, GraphQL, GraphQLDataFactory, and ApiDataFactory helpers allow override requests before sending.
391
+ This feature can be used to fetch current browser cookies and set them to REST API or GraphQL client.
392
+ By doing this we can make requests within the current browser session without a need of additional authentication.
393
+
394
+ > Sharing browser session with ApiDataFactory or GraphQLDataFactory can be especially useful when you test Single Page Applications
395
+
396
+ CodeceptJS bundles [`@codeceptjs/configure`](https://github.com/codeceptjs/configure), which exposes `setSharedCookies` for this case. Call it before exporting your config:
397
+
398
+ ```js
399
+ // in codecept.conf.js
400
+ import { setSharedCookies } from '@codeceptjs/configure'
401
+
402
+ // share cookies between browser helpers and REST/GraphQL
403
+ setSharedCookies()
404
+
405
+ export const config = {}
406
+ ```
407
+
408
+ 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:
409
+
410
+ ```js
411
+
412
+ let cookies; // share cookies
413
+
414
+ export const config = {
415
+ helpers: {
416
+ ApiDataFactory: {
417
+ endpoint: 'http://local.app/api',
418
+ cleanup: true,
419
+ headers: {
420
+ 'Content-Type': 'application/json',
421
+ 'Accept': 'application/json',
422
+ },
423
+ factories: {
424
+ user: {
425
+ uri: "/users",
426
+ factory: "./factories/user",
427
+ }
428
+ },
429
+ onRequest: async (request) => {
430
+ // get a cookie if it's not obtained yet
431
+ if (cookies) cookies = await codeceptjs.container.helpers('WebDriver').grabCookie();
432
+ // add cookies to request for a current request
433
+ request.headers = { Cookie: cookies.map(c => `${c.name}=${c.value}`).join('; ') };
434
+ },
435
+ }
436
+ WebDriver: {
437
+ url: 'https://local.app/',
438
+ browser: 'chrome',
439
+ }
440
+ }
441
+ ```
442
+
443
+ In this case we are accessing WebDriver helper. However, you can replace WebDriver with any helper you use.
444
+
445
+ The same can be done with GraphQLDataFactory.
446
+
447
+ The order of helpers is important! ApiDataFactory will clean up created users after a test,
448
+ so it needs browser to be still opened to obtain its cookies.