codeceptjs 3.5.12-beta.5 → 3.5.12-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/lib/helper/MockServer.js +215 -0
  2. package/lib/helper/Playwright.js +43 -22
  3. package/lib/helper/Puppeteer.js +25 -6
  4. package/lib/helper/WebDriver.js +25 -4
  5. package/lib/helper/errors/ElementAssertion.js +38 -0
  6. package/package.json +6 -5
  7. package/typings/index.d.ts +16 -0
  8. package/typings/promiseBasedTypes.d.ts +182 -0
  9. package/typings/types.d.ts +182 -0
  10. package/docs/advanced.md +0 -351
  11. package/docs/ai.md +0 -248
  12. package/docs/api.md +0 -323
  13. package/docs/basics.md +0 -979
  14. package/docs/bdd.md +0 -539
  15. package/docs/best.md +0 -237
  16. package/docs/books.md +0 -37
  17. package/docs/bootstrap.md +0 -135
  18. package/docs/build/ApiDataFactory.js +0 -410
  19. package/docs/build/Appium.js +0 -2027
  20. package/docs/build/Expect.js +0 -422
  21. package/docs/build/FileSystem.js +0 -228
  22. package/docs/build/GraphQL.js +0 -229
  23. package/docs/build/GraphQLDataFactory.js +0 -309
  24. package/docs/build/JSONResponse.js +0 -338
  25. package/docs/build/Mochawesome.js +0 -71
  26. package/docs/build/Nightmare.js +0 -2152
  27. package/docs/build/OpenAI.js +0 -126
  28. package/docs/build/Playwright.js +0 -5110
  29. package/docs/build/Protractor.js +0 -2706
  30. package/docs/build/Puppeteer.js +0 -3905
  31. package/docs/build/REST.js +0 -344
  32. package/docs/build/TestCafe.js +0 -2125
  33. package/docs/build/WebDriver.js +0 -4240
  34. package/docs/changelog.md +0 -2572
  35. package/docs/commands.md +0 -266
  36. package/docs/community-helpers.md +0 -58
  37. package/docs/configuration.md +0 -157
  38. package/docs/continuous-integration.md +0 -22
  39. package/docs/custom-helpers.md +0 -306
  40. package/docs/data.md +0 -379
  41. package/docs/detox.md +0 -235
  42. package/docs/docker.md +0 -136
  43. package/docs/email.md +0 -183
  44. package/docs/examples.md +0 -149
  45. package/docs/helpers/ApiDataFactory.md +0 -266
  46. package/docs/helpers/Appium.md +0 -1374
  47. package/docs/helpers/Detox.md +0 -586
  48. package/docs/helpers/Expect.md +0 -275
  49. package/docs/helpers/FileSystem.md +0 -152
  50. package/docs/helpers/GraphQL.md +0 -151
  51. package/docs/helpers/GraphQLDataFactory.md +0 -226
  52. package/docs/helpers/JSONResponse.md +0 -254
  53. package/docs/helpers/Mochawesome.md +0 -8
  54. package/docs/helpers/MockRequest.md +0 -377
  55. package/docs/helpers/Nightmare.md +0 -1305
  56. package/docs/helpers/OpenAI.md +0 -70
  57. package/docs/helpers/Playwright.md +0 -2759
  58. package/docs/helpers/Polly.md +0 -44
  59. package/docs/helpers/Protractor.md +0 -1769
  60. package/docs/helpers/Puppeteer-firefox.md +0 -86
  61. package/docs/helpers/Puppeteer.md +0 -2317
  62. package/docs/helpers/REST.md +0 -218
  63. package/docs/helpers/TestCafe.md +0 -1321
  64. package/docs/helpers/WebDriver.md +0 -2547
  65. package/docs/hooks.md +0 -340
  66. package/docs/index.md +0 -111
  67. package/docs/installation.md +0 -75
  68. package/docs/internal-api.md +0 -266
  69. package/docs/locators.md +0 -339
  70. package/docs/mobile-react-native-locators.md +0 -67
  71. package/docs/mobile.md +0 -338
  72. package/docs/pageobjects.md +0 -291
  73. package/docs/parallel.md +0 -400
  74. package/docs/playwright.md +0 -632
  75. package/docs/plugins.md +0 -1259
  76. package/docs/puppeteer.md +0 -316
  77. package/docs/quickstart.md +0 -162
  78. package/docs/react.md +0 -70
  79. package/docs/reports.md +0 -392
  80. package/docs/secrets.md +0 -36
  81. package/docs/shadow.md +0 -68
  82. package/docs/shared/keys.mustache +0 -31
  83. package/docs/shared/react.mustache +0 -1
  84. package/docs/testcafe.md +0 -174
  85. package/docs/translation.md +0 -247
  86. package/docs/tutorial.md +0 -271
  87. package/docs/typescript.md +0 -180
  88. package/docs/ui.md +0 -59
  89. package/docs/videos.md +0 -28
  90. package/docs/visual.md +0 -202
  91. package/docs/vue.md +0 -143
  92. package/docs/webapi/amOnPage.mustache +0 -11
  93. package/docs/webapi/appendField.mustache +0 -11
  94. package/docs/webapi/attachFile.mustache +0 -12
  95. package/docs/webapi/blur.mustache +0 -18
  96. package/docs/webapi/checkOption.mustache +0 -13
  97. package/docs/webapi/clearCookie.mustache +0 -9
  98. package/docs/webapi/clearField.mustache +0 -9
  99. package/docs/webapi/click.mustache +0 -25
  100. package/docs/webapi/clickLink.mustache +0 -8
  101. package/docs/webapi/closeCurrentTab.mustache +0 -7
  102. package/docs/webapi/closeOtherTabs.mustache +0 -8
  103. package/docs/webapi/dontSee.mustache +0 -11
  104. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  105. package/docs/webapi/dontSeeCookie.mustache +0 -8
  106. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  107. package/docs/webapi/dontSeeElement.mustache +0 -8
  108. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  109. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  110. package/docs/webapi/dontSeeInField.mustache +0 -11
  111. package/docs/webapi/dontSeeInSource.mustache +0 -8
  112. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  113. package/docs/webapi/doubleClick.mustache +0 -13
  114. package/docs/webapi/downloadFile.mustache +0 -12
  115. package/docs/webapi/dragAndDrop.mustache +0 -9
  116. package/docs/webapi/dragSlider.mustache +0 -11
  117. package/docs/webapi/executeAsyncScript.mustache +0 -24
  118. package/docs/webapi/executeScript.mustache +0 -26
  119. package/docs/webapi/fillField.mustache +0 -16
  120. package/docs/webapi/focus.mustache +0 -13
  121. package/docs/webapi/forceClick.mustache +0 -28
  122. package/docs/webapi/forceRightClick.mustache +0 -18
  123. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  124. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  125. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  126. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  127. package/docs/webapi/grabCookie.mustache +0 -11
  128. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  129. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  130. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  131. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  132. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  133. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  134. package/docs/webapi/grabGeoLocation.mustache +0 -8
  135. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  136. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  137. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  138. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  139. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  140. package/docs/webapi/grabPopupText.mustache +0 -5
  141. package/docs/webapi/grabSource.mustache +0 -8
  142. package/docs/webapi/grabTextFrom.mustache +0 -10
  143. package/docs/webapi/grabTextFromAll.mustache +0 -9
  144. package/docs/webapi/grabTitle.mustache +0 -8
  145. package/docs/webapi/grabValueFrom.mustache +0 -9
  146. package/docs/webapi/grabValueFromAll.mustache +0 -8
  147. package/docs/webapi/grabWebElement.mustache +0 -9
  148. package/docs/webapi/grabWebElements.mustache +0 -9
  149. package/docs/webapi/moveCursorTo.mustache +0 -12
  150. package/docs/webapi/openNewTab.mustache +0 -7
  151. package/docs/webapi/pressKey.mustache +0 -12
  152. package/docs/webapi/pressKeyDown.mustache +0 -12
  153. package/docs/webapi/pressKeyUp.mustache +0 -12
  154. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  155. package/docs/webapi/refreshPage.mustache +0 -6
  156. package/docs/webapi/resizeWindow.mustache +0 -6
  157. package/docs/webapi/rightClick.mustache +0 -14
  158. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  159. package/docs/webapi/saveScreenshot.mustache +0 -12
  160. package/docs/webapi/say.mustache +0 -10
  161. package/docs/webapi/scrollIntoView.mustache +0 -11
  162. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  163. package/docs/webapi/scrollPageToTop.mustache +0 -6
  164. package/docs/webapi/scrollTo.mustache +0 -12
  165. package/docs/webapi/see.mustache +0 -11
  166. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  167. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  168. package/docs/webapi/seeCookie.mustache +0 -8
  169. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  170. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  171. package/docs/webapi/seeElement.mustache +0 -8
  172. package/docs/webapi/seeElementInDOM.mustache +0 -8
  173. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  174. package/docs/webapi/seeInField.mustache +0 -12
  175. package/docs/webapi/seeInPopup.mustache +0 -8
  176. package/docs/webapi/seeInSource.mustache +0 -7
  177. package/docs/webapi/seeInTitle.mustache +0 -8
  178. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  179. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  180. package/docs/webapi/seeTextEquals.mustache +0 -9
  181. package/docs/webapi/seeTitleEquals.mustache +0 -8
  182. package/docs/webapi/selectOption.mustache +0 -21
  183. package/docs/webapi/setCookie.mustache +0 -16
  184. package/docs/webapi/setGeoLocation.mustache +0 -12
  185. package/docs/webapi/switchTo.mustache +0 -9
  186. package/docs/webapi/switchToNextTab.mustache +0 -10
  187. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  188. package/docs/webapi/type.mustache +0 -21
  189. package/docs/webapi/uncheckOption.mustache +0 -13
  190. package/docs/webapi/wait.mustache +0 -8
  191. package/docs/webapi/waitForClickable.mustache +0 -11
  192. package/docs/webapi/waitForDetached.mustache +0 -10
  193. package/docs/webapi/waitForElement.mustache +0 -11
  194. package/docs/webapi/waitForEnabled.mustache +0 -6
  195. package/docs/webapi/waitForFunction.mustache +0 -17
  196. package/docs/webapi/waitForInvisible.mustache +0 -10
  197. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  198. package/docs/webapi/waitForText.mustache +0 -13
  199. package/docs/webapi/waitForValue.mustache +0 -10
  200. package/docs/webapi/waitForVisible.mustache +0 -10
  201. package/docs/webapi/waitInUrl.mustache +0 -9
  202. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  203. package/docs/webapi/waitToHide.mustache +0 -10
  204. package/docs/webapi/waitUrlEquals.mustache +0 -10
  205. package/docs/webdriver.md +0 -701
  206. package/docs/wiki/Books-&-Posts.md +0 -27
  207. package/docs/wiki/Community-Helpers-&-Plugins.md +0 -53
  208. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -61
  209. package/docs/wiki/Examples.md +0 -145
  210. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
  211. package/docs/wiki/Home.md +0 -16
  212. package/docs/wiki/Migration-to-Appium-v2---CodeceptJS.md +0 -83
  213. package/docs/wiki/Release-Process.md +0 -24
  214. package/docs/wiki/Roadmap.md +0 -23
  215. package/docs/wiki/Tests.md +0 -1393
  216. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
  217. package/docs/wiki/Videos.md +0 -19
@@ -0,0 +1,215 @@
1
+ const { mock, settings } = require('pactum');
2
+
3
+ /**
4
+ * ## Configuration
5
+ *
6
+ * This helper should be configured in codecept.conf.(js|ts)
7
+ *
8
+ * @typedef MockServerConfig
9
+ * @type {object}
10
+ * @prop {number} [port=9393] - Mock server port
11
+ * @prop {string} [host="0.0.0.0"] - Mock server host
12
+ * @prop {object} [httpsOpts] - key & cert values are the paths to .key and .crt files
13
+ */
14
+ let config = {
15
+ port: 9393,
16
+ host: '0.0.0.0',
17
+ httpsOpts: {
18
+ key: '',
19
+ cert: '',
20
+ },
21
+ };
22
+
23
+ /**
24
+ * MockServer
25
+ *
26
+ * The MockServer Helper in CodeceptJS empowers you to mock any server or service via HTTP or HTTPS, making it an excellent tool for simulating REST endpoints and other HTTP-based APIs.
27
+ *
28
+ * <!-- configuration -->
29
+ *
30
+ * #### Examples
31
+ *
32
+ * You can seamlessly integrate MockServer with other helpers like REST or Playwright. Here's a configuration example inside the `codecept.conf.js` file:
33
+ *
34
+ * ```javascript
35
+ * {
36
+ * helpers: {
37
+ * REST: {...},
38
+ * MockServer: {
39
+ * // default mock server config
40
+ * port: 9393,
41
+ * host: '0.0.0.0',
42
+ * httpsOpts: {
43
+ * key: '',
44
+ * cert: '',
45
+ * },
46
+ * },
47
+ * }
48
+ * }
49
+ * ```
50
+ *
51
+ * #### Adding Interactions
52
+ *
53
+ * Interactions add behavior to the mock server. Use the `I.addInteractionToMockServer()` method to include interactions. It takes an interaction object as an argument, containing request and response details.
54
+ *
55
+ * ```javascript
56
+ * I.addInteractionToMockServer({
57
+ * request: {
58
+ * method: 'GET',
59
+ * path: '/api/hello'
60
+ * },
61
+ * response: {
62
+ * status: 200,
63
+ * body: {
64
+ * 'say': 'hello to mock server'
65
+ * }
66
+ * }
67
+ * });
68
+ * ```
69
+ *
70
+ * #### Request Matching
71
+ *
72
+ * When a real request is sent to the mock server, it matches the received request with the interactions. If a match is found, it returns the specified response; otherwise, a 404 status code is returned.
73
+ *
74
+ * - Strong match on HTTP Method, Path, Query Params & JSON body.
75
+ * - Loose match on Headers.
76
+ *
77
+ * ##### Strong Match on Query Params
78
+ *
79
+ * You can send different responses based on query parameters:
80
+ *
81
+ * ```javascript
82
+ * I.addInteractionToMockServer({
83
+ * request: {
84
+ * method: 'GET',
85
+ * path: '/api/users',
86
+ * queryParams: {
87
+ * id: 1
88
+ * }
89
+ * },
90
+ * response: {
91
+ * status: 200,
92
+ * body: 'user 1'
93
+ * }
94
+ * });
95
+ *
96
+ * I.addInteractionToMockServer({
97
+ * request: {
98
+ * method: 'GET',
99
+ * path: '/api/users',
100
+ * queryParams: {
101
+ * id: 2
102
+ * }
103
+ * },
104
+ * response: {
105
+ * status: 200,
106
+ * body: 'user 2'
107
+ * }
108
+ * });
109
+ * ```
110
+ *
111
+ * - GET to `/api/users?id=1` will return 'user 1'.
112
+ * - GET to `/api/users?id=2` will return 'user 2'.
113
+ * - For all other requests, it returns a 404 status code.
114
+ *
115
+ * ##### Loose Match on Body
116
+ *
117
+ * When `strict` is set to false, it performs a loose match on query params and response body:
118
+ *
119
+ * ```javascript
120
+ * I.addInteractionToMockServer({
121
+ * strict: false,
122
+ * request: {
123
+ * method: 'POST',
124
+ * path: '/api/users',
125
+ * body: {
126
+ * name: 'john'
127
+ * }
128
+ * },
129
+ * response: {
130
+ * status: 200
131
+ * }
132
+ * });
133
+ * ```
134
+ *
135
+ * - POST to `/api/users` with the body containing `name` as 'john' will return a 200 status code.
136
+ * - POST to `/api/users` without the `name` property in the body will return a 404 status code.
137
+ *
138
+ * Happy testing with MockServer in CodeceptJS! 🚀
139
+ *
140
+ * ## Methods
141
+ */
142
+ class MockServer {
143
+ constructor(passedConfig) {
144
+ settings.setLogLevel('SILENT');
145
+ config = { ...passedConfig };
146
+ if (global.debugMode) {
147
+ settings.setLogLevel('VERBOSE');
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Start the mock server
153
+ * @param {number} [port] start the mock server with given port
154
+ */
155
+ async startMockServer(port) {
156
+ const _config = { ...config };
157
+ if (port) _config.port = port;
158
+ await mock.setDefaults(_config);
159
+ await mock.start();
160
+ }
161
+
162
+ /**
163
+ * Stop the mock server
164
+ *
165
+ */
166
+ async stopMockServer() {
167
+ await mock.stop();
168
+ }
169
+
170
+ /**
171
+ * An interaction adds behavior to the mock server
172
+ *
173
+ *
174
+ * ```js
175
+ * I.addInteractionToMockServer({
176
+ * request: {
177
+ * method: 'GET',
178
+ * path: '/api/hello'
179
+ * },
180
+ * response: {
181
+ * status: 200,
182
+ * body: {
183
+ * 'say': 'hello to mock server'
184
+ * }
185
+ * }
186
+ * });
187
+ * ```
188
+ * ```js
189
+ * // with query params
190
+ * I.addInteractionToMockServer({
191
+ * request: {
192
+ * method: 'GET',
193
+ * path: '/api/hello',
194
+ * queryParams: {
195
+ * id: 2
196
+ * }
197
+ * },
198
+ * response: {
199
+ * status: 200,
200
+ * body: {
201
+ * 'say': 'hello to mock server'
202
+ * }
203
+ * }
204
+ * });
205
+ * ```
206
+ *
207
+ * @param {CodeceptJS.MockInteraction|object} interaction add behavior to the mock server
208
+ *
209
+ */
210
+ async addInteractionToMockServer(interaction) {
211
+ await mock.addInteraction(interaction);
212
+ }
213
+ }
214
+
215
+ module.exports = MockServer;
@@ -47,6 +47,9 @@ const {
47
47
  setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
48
48
  } = require('./extras/PlaywrightRestartOpts');
49
49
  const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
50
+ const {
51
+ seeElementError, dontSeeElementError, dontSeeElementInDOMError, seeElementInDOMError,
52
+ } = require('./errors/ElementAssertion');
50
53
 
51
54
  const pathSeparator = path.sep;
52
55
 
@@ -1451,7 +1454,11 @@ class Playwright extends Helper {
1451
1454
  async seeElement(locator) {
1452
1455
  let els = await this._locate(locator);
1453
1456
  els = await Promise.all(els.map(el => el.isVisible()));
1454
- return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1457
+ try {
1458
+ return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1459
+ } catch (e) {
1460
+ dontSeeElementError(locator);
1461
+ }
1455
1462
  }
1456
1463
 
1457
1464
  /**
@@ -1461,7 +1468,11 @@ class Playwright extends Helper {
1461
1468
  async dontSeeElement(locator) {
1462
1469
  let els = await this._locate(locator);
1463
1470
  els = await Promise.all(els.map(el => el.isVisible()));
1464
- return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1471
+ try {
1472
+ return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1473
+ } catch (e) {
1474
+ seeElementError(locator);
1475
+ }
1465
1476
  }
1466
1477
 
1467
1478
  /**
@@ -1469,7 +1480,11 @@ class Playwright extends Helper {
1469
1480
  */
1470
1481
  async seeElementInDOM(locator) {
1471
1482
  const els = await this._locate(locator);
1472
- return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1483
+ try {
1484
+ return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1485
+ } catch (e) {
1486
+ dontSeeElementInDOMError(locator);
1487
+ }
1473
1488
  }
1474
1489
 
1475
1490
  /**
@@ -1477,7 +1492,11 @@ class Playwright extends Helper {
1477
1492
  */
1478
1493
  async dontSeeElementInDOM(locator) {
1479
1494
  const els = await this._locate(locator);
1480
- return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1495
+ try {
1496
+ return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1497
+ } catch (e) {
1498
+ seeElementInDOMError(locator);
1499
+ }
1481
1500
  }
1482
1501
 
1483
1502
  /**
@@ -2169,6 +2188,8 @@ class Playwright extends Helper {
2169
2188
  let chunked = chunkArray(attrs, values.length);
2170
2189
  chunked = chunked.filter((val) => {
2171
2190
  for (let i = 0; i < val.length; ++i) {
2191
+ // the attribute could be a boolean
2192
+ if (typeof val[i] === 'boolean') return val[i] === values[i];
2172
2193
  // if the attribute doesn't exist, returns false as well
2173
2194
  if (!val[i] || !val[i].includes(values[i])) return false;
2174
2195
  }
@@ -2974,27 +2995,27 @@ class Playwright extends Helper {
2974
2995
  throw new Error('Failure in test automation. You use "I.grabRecordedNetworkTraffics", but "I.startRecordingTraffic" was never called before.');
2975
2996
  }
2976
2997
 
2977
- const requests = await this.requests;
2978
- const promises = requests.map(async (request) => request.response.then(
2979
- async (response) => {
2980
- let body;
2981
- try {
2982
- // There's no 'body' for some requests (redirect etc...)
2983
- body = JSON.parse((await response.body()).toString());
2984
- } catch (e) {
2985
- // only interested in JSON, not HTML responses.
2986
- }
2998
+ const promises = this.requests.map(async (request) => {
2999
+ const resp = await request.response;
3000
+ let body;
3001
+ try {
3002
+ // There's no 'body' for some requests (redirect etc...)
3003
+ body = JSON.parse((await resp.body()).toString());
3004
+ } catch (e) {
3005
+ // only interested in JSON, not HTML responses.
3006
+ }
2987
3007
 
2988
- request.response = {
2989
- status: response.status(),
2990
- statusText: response.statusText(),
3008
+ return {
3009
+ url: resp.url(),
3010
+ response: {
3011
+ status: resp.status(),
3012
+ statusText: resp.statusText(),
2991
3013
  body,
2992
- };
2993
- },
2994
- ));
2995
- await Promise.all(promises);
3014
+ },
3015
+ };
3016
+ });
2996
3017
 
2997
- return this.requests;
3018
+ return Promise.all(promises);
2998
3019
  }
2999
3020
 
3000
3021
  /**
@@ -39,6 +39,9 @@ const findReact = require('./extras/React');
39
39
  const { highlightElement } = require('./scripts/highlightElement');
40
40
  const { blurElement } = require('./scripts/blurElement');
41
41
  const { focusElement } = require('./scripts/focusElement');
42
+ const {
43
+ dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElementInDOMError,
44
+ } = require('./errors/ElementAssertion');
42
45
 
43
46
  let puppeteer;
44
47
  let perfTiming;
@@ -1038,8 +1041,11 @@ class Puppeteer extends Helper {
1038
1041
  els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v);
1039
1042
  // Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
1040
1043
  els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el));
1041
-
1042
- return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1044
+ try {
1045
+ return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1046
+ } catch (e) {
1047
+ dontSeeElementError(locator);
1048
+ }
1043
1049
  }
1044
1050
 
1045
1051
  /**
@@ -1051,8 +1057,11 @@ class Puppeteer extends Helper {
1051
1057
  els = (await Promise.all(els.map(el => el.boundingBox() && el))).filter(v => v);
1052
1058
  // Puppeteer visibility was ignored? | Remove when Puppeteer is fixed
1053
1059
  els = await Promise.all(els.map(async el => (await el.evaluate(node => window.getComputedStyle(node).visibility !== 'hidden' && window.getComputedStyle(node).display !== 'none')) && el));
1054
-
1055
- return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1060
+ try {
1061
+ return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1062
+ } catch (e) {
1063
+ seeElementError(locator);
1064
+ }
1056
1065
  }
1057
1066
 
1058
1067
  /**
@@ -1060,7 +1069,11 @@ class Puppeteer extends Helper {
1060
1069
  */
1061
1070
  async seeElementInDOM(locator) {
1062
1071
  const els = await this._locate(locator);
1063
- return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1072
+ try {
1073
+ return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1074
+ } catch (e) {
1075
+ dontSeeElementInDOMError(locator);
1076
+ }
1064
1077
  }
1065
1078
 
1066
1079
  /**
@@ -1068,7 +1081,11 @@ class Puppeteer extends Helper {
1068
1081
  */
1069
1082
  async dontSeeElementInDOM(locator) {
1070
1083
  const els = await this._locate(locator);
1071
- return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1084
+ try {
1085
+ return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1086
+ } catch (e) {
1087
+ seeElementInDOMError(locator);
1088
+ }
1072
1089
  }
1073
1090
 
1074
1091
  /**
@@ -1825,6 +1842,8 @@ class Puppeteer extends Helper {
1825
1842
  for (let i = 0; i < val.length; ++i) {
1826
1843
  const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(values[i], 10);
1827
1844
  const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
1845
+ // the attribute could be a boolean
1846
+ if (typeof _actual === 'boolean') return _actual === _expected;
1828
1847
  // if the attribute doesn't exist, returns false as well
1829
1848
  if (!_actual || !_actual.includes(_expected)) return false;
1830
1849
  }
@@ -32,6 +32,9 @@ const { highlightElement } = require('./scripts/highlightElement');
32
32
  const store = require('../store');
33
33
  const { focusElement } = require('./scripts/focusElement');
34
34
  const { blurElement } = require('./scripts/blurElement');
35
+ const {
36
+ dontSeeElementError, seeElementError, seeElementInDOMError, dontSeeElementInDOMError,
37
+ } = require('./errors/ElementAssertion');
35
38
 
36
39
  const SHADOW = 'shadow';
37
40
  const webRoot = 'body';
@@ -1461,7 +1464,11 @@ class WebDriver extends Helper {
1461
1464
  const res = await this._locate(locator, true);
1462
1465
  assertElementExists(res, locator);
1463
1466
  const selected = await forEachAsync(res, async el => el.isDisplayed());
1464
- return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
1467
+ try {
1468
+ return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
1469
+ } catch (e) {
1470
+ dontSeeElementError(locator);
1471
+ }
1465
1472
  }
1466
1473
 
1467
1474
  /**
@@ -1474,7 +1481,11 @@ class WebDriver extends Helper {
1474
1481
  return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(false);
1475
1482
  }
1476
1483
  const selected = await forEachAsync(res, async el => el.isDisplayed());
1477
- return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
1484
+ try {
1485
+ return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
1486
+ } catch (e) {
1487
+ seeElementError(locator);
1488
+ }
1478
1489
  }
1479
1490
 
1480
1491
  /**
@@ -1483,7 +1494,11 @@ class WebDriver extends Helper {
1483
1494
  */
1484
1495
  async seeElementInDOM(locator) {
1485
1496
  const res = await this._res(locator);
1486
- return empty('elements').negate(res);
1497
+ try {
1498
+ return empty('elements').negate(res);
1499
+ } catch (e) {
1500
+ dontSeeElementInDOMError(locator);
1501
+ }
1487
1502
  }
1488
1503
 
1489
1504
  /**
@@ -1492,7 +1507,11 @@ class WebDriver extends Helper {
1492
1507
  */
1493
1508
  async dontSeeElementInDOM(locator) {
1494
1509
  const res = await this._res(locator);
1495
- return empty('elements').assert(res);
1510
+ try {
1511
+ return empty('elements').assert(res);
1512
+ } catch (e) {
1513
+ seeElementInDOMError(locator);
1514
+ }
1496
1515
  }
1497
1516
 
1498
1517
  /**
@@ -1612,6 +1631,8 @@ class WebDriver extends Helper {
1612
1631
  for (let i = 0; i < val.length; ++i) {
1613
1632
  const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(val[i], 10);
1614
1633
  const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
1634
+ // the attribute could be a boolean
1635
+ if (typeof _actual === 'boolean') return _actual === _expected;
1615
1636
  if (_actual !== _expected) return false;
1616
1637
  }
1617
1638
  return true;
@@ -0,0 +1,38 @@
1
+ const Locator = require('../../locator');
2
+
3
+ const prefixMessage = 'Element';
4
+
5
+ function seeElementError(locator) {
6
+ if (typeof locator === 'object') {
7
+ locator = JSON.stringify(locator);
8
+ }
9
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is still visible on page.`);
10
+ }
11
+
12
+ function seeElementInDOMError(locator) {
13
+ if (typeof locator === 'object') {
14
+ locator = JSON.stringify(locator);
15
+ }
16
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is still seen in DOM.`);
17
+ }
18
+
19
+ function dontSeeElementError(locator) {
20
+ if (typeof locator === 'object') {
21
+ locator = JSON.stringify(locator);
22
+ }
23
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is not visible on page.`);
24
+ }
25
+
26
+ function dontSeeElementInDOMError(locator) {
27
+ if (typeof locator === 'object') {
28
+ locator = JSON.stringify(locator);
29
+ }
30
+ throw new Error(`${prefixMessage} "${(new Locator(locator))}" is not seen in DOM.`);
31
+ }
32
+
33
+ module.exports = {
34
+ seeElementError,
35
+ dontSeeElementError,
36
+ seeElementInDOMError,
37
+ dontSeeElementInDOMError,
38
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.5.12-beta.5",
3
+ "version": "3.5.12-beta.7",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -23,7 +23,6 @@
23
23
  },
24
24
  "files": [
25
25
  "bin",
26
- "docs",
27
26
  "lib",
28
27
  "translations",
29
28
  "typings/**/*.d.ts"
@@ -56,6 +55,7 @@
56
55
  "test:unit:webbapi:webDriver:devtools": "mocha test/helper/WebDriver_devtools_test.js --exit",
57
56
  "test:unit:webbapi:testCafe": "mocha test/helper/TestCafe_test.js",
58
57
  "test:unit:expect": "mocha test/helper/Expect_test.js",
58
+ "test:unit:mockServer": "mocha test/helper/MockServer_test.js",
59
59
  "test:plugin": "mocha test/plugin/plugin_test.js",
60
60
  "def": "./runok.js def",
61
61
  "dev:graphql": "node test/data/graphql/index.js",
@@ -105,6 +105,7 @@
105
105
  "ms": "2.1.3",
106
106
  "openai": "3.2.1",
107
107
  "ora-classic": "5.4.2",
108
+ "pactum": "3.6.0",
108
109
  "parse-function": "5.6.4",
109
110
  "parse5": "7.1.2",
110
111
  "promise-retry": "1.1.1",
@@ -133,7 +134,7 @@
133
134
  "contributor-faces": "1.1.0",
134
135
  "documentation": "12.3.0",
135
136
  "dtslint": "4.2.1",
136
- "electron": "28.0.0",
137
+ "electron": "28.1.4",
137
138
  "eslint": "8.56.0",
138
139
  "eslint-config-airbnb-base": "15.0.0",
139
140
  "eslint-plugin-import": "2.29.1",
@@ -146,7 +147,7 @@
146
147
  "jsdoc": "3.6.11",
147
148
  "jsdoc-typeof-plugin": "1.0.0",
148
149
  "json-server": "0.10.1",
149
- "playwright": "1.40.1",
150
+ "playwright": "1.41.1",
150
151
  "puppeteer": "21.1.1",
151
152
  "qrcode-terminal": "0.12.0",
152
153
  "rosie": "2.1.1",
@@ -161,7 +162,7 @@
161
162
  "typedoc-plugin-markdown": "3.17.1",
162
163
  "typescript": "5.3.3",
163
164
  "wdio-docker-service": "1.5.0",
164
- "webdriverio": "8.27.2",
165
+ "webdriverio": "8.28.8",
165
166
  "xml2js": "0.6.2",
166
167
  "xpath": "0.0.34"
167
168
  },
@@ -382,6 +382,22 @@ declare namespace CodeceptJS {
382
382
  [key: string]: any;
383
383
  };
384
384
 
385
+ type MockRequest = {
386
+ method: 'GET'|'PUT'|'POST'|'PATCH'|'DELETE'|string;
387
+ path: string;
388
+ queryParams?: object;
389
+ }
390
+
391
+ type MockResponse = {
392
+ status: number;
393
+ body?: object;
394
+ }
395
+
396
+ type MockInteraction = {
397
+ request: MockRequest;
398
+ response: MockResponse;
399
+ }
400
+
385
401
  interface PageScrollPosition {
386
402
  x: number;
387
403
  y: number;