codeceptjs 3.3.2 → 3.3.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +44 -2
  2. package/docs/api.md +4 -0
  3. package/docs/basics.md +2 -0
  4. package/docs/bdd.md +12 -0
  5. package/docs/build/JSONResponse.js +44 -3
  6. package/docs/build/Playwright.js +63 -40
  7. package/docs/build/Puppeteer.js +54 -43
  8. package/docs/build/REST.js +23 -9
  9. package/docs/build/WebDriver.js +39 -30
  10. package/docs/changelog.md +6 -2
  11. package/docs/community-helpers.md +1 -0
  12. package/docs/configuration.md +21 -18
  13. package/docs/helpers/Appium.md +0 -723
  14. package/docs/helpers/JSONResponse.md +24 -0
  15. package/docs/helpers/Playwright.md +276 -264
  16. package/docs/helpers/Puppeteer.md +230 -222
  17. package/docs/helpers/REST.md +21 -6
  18. package/docs/helpers/WebDriver.md +265 -259
  19. package/docs/plugins.md +41 -1
  20. package/docs/reports.md +11 -0
  21. package/docs/secrets.md +30 -0
  22. package/docs/wiki/.git/FETCH_HEAD +1 -0
  23. package/docs/wiki/.git/HEAD +1 -0
  24. package/docs/wiki/.git/ORIG_HEAD +1 -0
  25. package/docs/wiki/.git/config +11 -0
  26. package/docs/wiki/.git/description +1 -0
  27. package/docs/wiki/.git/hooks/applypatch-msg.sample +15 -0
  28. package/docs/wiki/.git/hooks/commit-msg.sample +24 -0
  29. package/docs/wiki/.git/hooks/fsmonitor-watchman.sample +173 -0
  30. package/docs/wiki/.git/hooks/post-update.sample +8 -0
  31. package/docs/wiki/.git/hooks/pre-applypatch.sample +14 -0
  32. package/docs/wiki/.git/hooks/pre-commit.sample +49 -0
  33. package/docs/wiki/.git/hooks/pre-merge-commit.sample +13 -0
  34. package/docs/wiki/.git/hooks/pre-push.sample +53 -0
  35. package/docs/wiki/.git/hooks/pre-rebase.sample +169 -0
  36. package/docs/wiki/.git/hooks/pre-receive.sample +24 -0
  37. package/docs/wiki/.git/hooks/prepare-commit-msg.sample +42 -0
  38. package/docs/wiki/.git/hooks/push-to-checkout.sample +78 -0
  39. package/docs/wiki/.git/hooks/update.sample +128 -0
  40. package/docs/wiki/.git/index +0 -0
  41. package/docs/wiki/.git/info/exclude +6 -0
  42. package/docs/wiki/.git/logs/HEAD +1 -0
  43. package/docs/wiki/.git/logs/refs/heads/master +1 -0
  44. package/docs/wiki/.git/logs/refs/remotes/origin/HEAD +1 -0
  45. package/docs/wiki/.git/objects/pack/pack-5938044f9d30daf1c195fda4dec1d54850933935.idx +0 -0
  46. package/docs/wiki/.git/objects/pack/pack-5938044f9d30daf1c195fda4dec1d54850933935.pack +0 -0
  47. package/docs/wiki/.git/packed-refs +2 -0
  48. package/docs/wiki/.git/refs/heads/master +1 -0
  49. package/docs/wiki/.git/refs/remotes/origin/HEAD +1 -0
  50. package/docs/wiki/Community-Helpers-&-Plugins.md +7 -3
  51. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +29 -0
  52. package/docs/wiki/Examples.md +39 -48
  53. package/docs/wiki/Release-Process.md +8 -8
  54. package/docs/wiki/Tests.md +62 -60
  55. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +2 -2
  56. package/lib/cli.js +1 -1
  57. package/lib/command/generate.js +3 -0
  58. package/lib/command/init.js +83 -24
  59. package/lib/command/interactive.js +1 -1
  60. package/lib/command/run-workers.js +1 -1
  61. package/lib/command/workers/runTests.js +15 -0
  62. package/lib/helper/JSONResponse.js +44 -3
  63. package/lib/helper/Playwright.js +63 -40
  64. package/lib/helper/Puppeteer.js +54 -43
  65. package/lib/helper/REST.js +23 -9
  66. package/lib/helper/WebDriver.js +39 -30
  67. package/lib/interfaces/gherkin.js +1 -1
  68. package/lib/output.js +4 -0
  69. package/lib/plugin/customLocator.js +50 -3
  70. package/lib/plugin/retryFailedStep.js +1 -1
  71. package/lib/plugin/retryTo.js +1 -8
  72. package/lib/secret.js +31 -1
  73. package/lib/step.js +22 -10
  74. package/lib/utils.js +1 -6
  75. package/package.json +4 -4
  76. package/typings/index.d.ts +158 -0
  77. package/typings/types.d.ts +367 -96
package/CHANGELOG.md CHANGED
@@ -1,3 +1,47 @@
1
+ ## 3.3.4
2
+
3
+ * Added support for masking fields in objects via `secret` function:
4
+
5
+ ```js
6
+ I.sendPostRequest('/auth', secret({ name: 'jon', password: '123456' }, 'password'));
7
+ ```
8
+ * Added [a guide about using of `secret`](/secrets) function
9
+ * [Appium] Use `touchClick` when interacting with elements in iOS. See #3317 by @mikk150
10
+ * [Playwright] Added `cdpConnection` option to connect over CDP. See #3309 by @Hmihaly
11
+ * [customLocator plugin] Allowed to specify multiple attributes for custom locator. Thanks to @aruiz-caritsqa
12
+
13
+ ```js
14
+ plugins: {
15
+ customLocator: {
16
+ enabled: true,
17
+ prefix: '$',
18
+ attribute: ['data-qa', 'data-test'],
19
+ }
20
+ }
21
+ ```
22
+ * [retryTo plugin] Fixed #3147 using `pollInterval` option. See #3351 by @cyonkee
23
+ * [Playwright] Fixed grabbing of browser console messages and window resize in new tab. Thanks to @mirao
24
+ * [REST] Added `prettyPrintJson` option to print JSON in nice way by @PeterNgTr
25
+ * [JSONResponse] Updated response validation to iterate over array items if response is array. Thanks to @PeterNgTr
26
+
27
+ ```js
28
+ // response.data == [
29
+ // { user: { name: 'jon', email: 'jon@doe.com' } },
30
+ // { user: { name: 'matt', email: 'matt@doe.com' } },
31
+ //]
32
+
33
+ I.seeResponseContainsKeys(['user']);
34
+ I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
35
+ I.seeResponseContainsJson({ user: { email: 'matt@doe.com' } });
36
+ I.dontSeeResponseContainsJson({ user: 2 });
37
+ ```
38
+
39
+ ## 3.3.3
40
+
41
+ * Fixed `DataCloneError: () => could not be cloned` when running data tests in run-workers
42
+ * 🇺🇦 Added #StandWithUkraine notice to CLI
43
+
44
+
1
45
  ## 3.3.2
2
46
 
3
47
  * [REST] Fixed override of headers/token in `haveRequestHeaders()` and `amBearerAuthenticated()`. See #3304 by @mirao
@@ -41,8 +85,6 @@ npx codeceptjs run test-dir/*"
41
85
  * Improving the typings in many places
42
86
  * Improving the return type of helpers for TS users (#3245) - @nlespiaucq
43
87
 
44
- 🇺🇦 Added #StandWithUkraine hashtag notice to CLI
45
-
46
88
  ## 3.3.0
47
89
 
48
90
  🛩️ Features:
package/docs/api.md CHANGED
@@ -263,6 +263,8 @@ The most basic thing to check in response is existence of keys in JSON object. U
263
263
  I.seeResponseContainsKeys(['name', 'email']);
264
264
  ```
265
265
 
266
+ > ℹ️ If response is an array, it will check that every element in array have provided keys
267
+
266
268
  However, this is a very naive approach. It won't work for arrays or nested objects.
267
269
  To check complex JSON structures `JSONResponse` helper uses [`joi`](https://joi.dev) library.
268
270
  It has rich API to validate JSON by the schema defined using JavaScript.
@@ -296,6 +298,8 @@ I.seeResponseContainsJson({
296
298
  })
297
299
  ```
298
300
 
301
+ > ℹ️ If response is an array, it will check that at least one element in array matches JSON
302
+
299
303
  To perform arbitrary assertions on a response object use `seeResponseValidByCallback`.
300
304
  It allows you to do any kind of assertions by using `expect` from [`chai`](https://www.chaijs.com) library.
301
305
 
package/docs/basics.md CHANGED
@@ -212,6 +212,8 @@ To fill in sensitive data use the `secret` function, it won't expose actual valu
212
212
  I.fillField('password', secret('123456'));
213
213
  ```
214
214
 
215
+ > ℹ️ Learn more about [masking secret](/secrets/) output
216
+
215
217
  ### Assertions
216
218
 
217
219
  In order to verify the expected behavior of a web application, its content should be checked.
package/docs/bdd.md CHANGED
@@ -356,6 +356,18 @@ In case scenarios represent the same logic but differ on data, we can use *Scena
356
356
  | 50 | 45 |
357
357
  ```
358
358
 
359
+ It might be the case that the same column value needs to be utilized multiple times in the same step, that also can be possible with scenario outline.
360
+
361
+ ```gherkin
362
+ Scenario Outline: check parameter substitution
363
+ Given I have a defined step
364
+ When I see "<text>" text and "<text>" is not "xyz"
365
+ Examples:
366
+ | text |
367
+ | Google |
368
+
369
+ ```
370
+
359
371
  ### Long Strings
360
372
 
361
373
  Text values inside a scenarios can be set inside a `"""` block:
@@ -1,3 +1,4 @@
1
+ const assert = require('assert');
1
2
  const chai = require('chai');
2
3
  const joi = require('joi');
3
4
  const chaiDeepMatch = require('chai-deep-match');
@@ -173,12 +174,30 @@ class JSONResponse extends Helper {
173
174
  *
174
175
  * I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
175
176
  * ```
177
+ * If an array is received, checks that at least one element contains JSON
178
+ * ```js
179
+ * // response.data == [{ user: { name: 'jon', email: 'jon@doe.com' } }]
180
+ *
181
+ * I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
182
+ * ```
176
183
  *
177
184
  * @param {object} json
178
185
  */
179
186
  seeResponseContainsJson(json = {}) {
180
187
  this._checkResponseReady();
181
- expect(this.response.data).to.deep.match(json);
188
+ if (Array.isArray(this.response.data)) {
189
+ let fails = 0;
190
+ for (const el of this.response.data) {
191
+ try {
192
+ expect(el).to.deep.match(json);
193
+ } catch (err) {
194
+ fails++;
195
+ }
196
+ }
197
+ assert.ok(fails < this.response.data.length, `No elements in array matched ${JSON.stringify(json)}`);
198
+ } else {
199
+ expect(this.response.data).to.deep.match(json);
200
+ }
182
201
  }
183
202
 
184
203
  /**
@@ -189,12 +208,22 @@ class JSONResponse extends Helper {
189
208
  *
190
209
  * I.dontSeeResponseContainsJson({ user: 2 });
191
210
  * ```
211
+ * If an array is received, checks that no element of array contains json:
212
+ * ```js
213
+ * // response.data == [{ user: 1 }, { user: 3 }]
214
+ *
215
+ * I.dontSeeResponseContainsJson({ user: 2 });
216
+ * ```
192
217
  *
193
218
  * @param {object} json
194
219
  */
195
220
  dontSeeResponseContainsJson(json = {}) {
196
221
  this._checkResponseReady();
197
- expect(this.response.data).not.to.deep.match(json);
222
+ if (Array.isArray(this.response.data)) {
223
+ this.response.data.forEach(data => expect(data).not.to.deep.match(json));
224
+ } else {
225
+ expect(this.response.data).not.to.deep.match(json);
226
+ }
198
227
  }
199
228
 
200
229
  /**
@@ -206,11 +235,23 @@ class JSONResponse extends Helper {
206
235
  * I.seeResponseContainsKeys(['user']);
207
236
  * ```
208
237
  *
238
+ * If an array is received, check is performed for each element of array:
239
+ *
240
+ * ```js
241
+ * // response.data == [{ user: 'jon' }, { user: 'matt'}]
242
+ *
243
+ * I.seeResponseContainsKeys(['user']);
244
+ * ```
245
+ *
209
246
  * @param {array} keys
210
247
  */
211
248
  seeResponseContainsKeys(keys = []) {
212
249
  this._checkResponseReady();
213
- expect(this.response.data).to.include.keys(keys);
250
+ if (Array.isArray(this.response.data)) {
251
+ this.response.data.forEach(data => expect(data).to.include.keys(keys));
252
+ } else {
253
+ expect(this.response.data).to.include.keys(keys);
254
+ }
214
255
  }
215
256
 
216
257
  /**
@@ -44,6 +44,46 @@ const {
44
44
  } = require('./extras/PlaywrightRestartOpts');
45
45
  const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
46
46
 
47
+ /**
48
+ * ## Configuration
49
+ *
50
+ * This helper should be configured in codecept.conf.js
51
+ *
52
+ * @typedef PlaywrightConfig
53
+ * @type {object}
54
+ * @prop {string} url - base url of website to be tested
55
+ * @prop {string} browser - a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
56
+ * @prop {boolean} [show=false] - show browser window.
57
+ * @prop {string|boolean} [restart=false] - restart strategy between tests. Possible values:
58
+ * * 'context' or **false** - restarts [browser context](https://playwright.dev/docs/api/class-browsercontext) but keeps running browser. Recommended by Playwright team to keep tests isolated.
59
+ * * 'browser' or **true** - closes browser and opens it again between tests.
60
+ * * 'session' or 'keep' - keeps browser context and session, but cleans up cookies and localStorage between tests. The fastest option when running tests in windowed mode. Works with `keepCookies` and `keepBrowserState` options. This behavior was default before CodeceptJS 3.1
61
+ * @prop {number} [timeout=1000] - - [timeout](https://playwright.dev/docs/api/class-page#page-set-default-timeout) in ms of all Playwright actions .
62
+ * @prop {boolean} [disableScreenshots=false] - don't save screenshot on failure.
63
+ * @prop {any} [emulate] - browser in device emulation mode.
64
+ * @prop {boolean} [video=false] - enables video recording for failed tests; videos are saved into `output/videos` folder
65
+ * @prop {boolean} [trace=false] - record [tracing information](https://playwright.dev/docs/trace-viewer) with screenshots and snapshots.
66
+ * @prop {boolean} [fullPageScreenshots=false] - make full page screenshots on failure.
67
+ * @prop {boolean} [uniqueScreenshotNames=false] - option to prevent screenshot override if you have scenarios with the same name in different suites.
68
+ * @prop {boolean} [keepBrowserState=false] - keep browser state between tests when `restart` is set to 'session'.
69
+ * @prop {boolean} [keepCookies=false] - keep cookies between tests when `restart` is set to 'session'.
70
+ * @prop {number} [waitForAction] - how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
71
+ * @prop {number} [waitForNavigation] - When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API](https://github.com/microsoft/playwright/blob/main/docs/api.md#pagewaitfornavigationoptions).
72
+ * @prop {number} [pressKeyDelay=10] - Delay between key presses in ms. Used when calling Playwrights page.type(...) in fillField/appendField
73
+ * @prop {number} [getPageTimeout] - config option to set maximum navigation time in milliseconds.
74
+ * @prop {number} [waitForTimeout] - default wait* timeout in ms. Default: 1000.
75
+ * @prop {object} [basicAuth] - the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
76
+ * @prop {string} [windowSize] - default window size. Set a dimension like `640x480`.
77
+ * @prop {string} [colorScheme] - default color scheme. Possible values: `dark` | `light` | `no-preference`.
78
+ * @prop {string} [userAgent] - user-agent string.
79
+ * @prop {string} [locale] - locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
80
+ * @prop {boolean} [manualStart] - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
81
+ * @prop {object} [chromium] - pass additional chromium options
82
+ * @prop {object} [electron] - (pass additional electron options
83
+ * @prop {any} [channel] - (While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge](https://playwright.dev/docs/browsers/#google-chrome--microsoft-edge).
84
+ */
85
+ const config = {};
86
+
47
87
  /**
48
88
  * Uses [Playwright](https://github.com/microsoft/playwright) library to run tests inside:
49
89
  *
@@ -65,46 +105,14 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
65
105
  *
66
106
  * Using playwright-core package, will prevent the download of browser binaries and allow connecting to an existing browser installation or for connecting to a remote one.
67
107
  *
68
- * ## Configuration
69
108
  *
70
- * This helper should be configured in codecept.json or codecept.conf.js
71
- *
72
- * * `url`: base url of website to be tested
73
- * * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
74
- * * `show`: (optional, default: false) - show browser window.
75
- * * `restart`: (optional, default: false) - restart strategy between tests. Possible values:
76
- * * 'context' or **false** - restarts [browser context](https://playwright.dev/docs/api/class-browsercontext) but keeps running browser. Recommended by Playwright team to keep tests isolated.
77
- * * 'browser' or **true** - closes browser and opens it again between tests.
78
- * * 'session' or 'keep' - keeps browser context and session, but cleans up cookies and localStorage between tests. The fastest option when running tests in windowed mode. Works with `keepCookies` and `keepBrowserState` options. This behavior was default before CodeceptJS 3.1
79
- * * `timeout`: (optional, default: 1000) - [timeout](https://playwright.dev/docs/api/class-page#page-set-default-timeout) in ms of all Playwright actions .
80
- * * `disableScreenshots`: (optional, default: false) - don't save screenshot on failure.
81
- * * `emulate`: (optional, default: {}) launch browser in device emulation mode.
82
- * * `video`: (optional, default: false) enables video recording for failed tests; videos are saved into `output/videos` folder
83
- * * `trace`: (optional, default: false) record [tracing information](https://playwright.dev/docs/trace-viewer) with screenshots and snapshots.
84
- * * `fullPageScreenshots` (optional, default: false) - make full page screenshots on failure.
85
- * * `uniqueScreenshotNames`: (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites.
86
- * * `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to 'session'.
87
- * * `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to 'session'.
88
- * * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
89
- * * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API](https://github.com/microsoft/playwright/blob/main/docs/api.md#pagewaitfornavigationoptions).
90
- * * `pressKeyDelay`: (optional, default: '10'). Delay between key presses in ms. Used when calling Playwrights page.type(...) in fillField/appendField
91
- * * `getPageTimeout` (optional, default: '0') config option to set maximum navigation time in milliseconds.
92
- * * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
93
- * * `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
94
- * * `windowSize`: (optional) default window size. Set a dimension like `640x480`.
95
- * * `colorScheme`: (optional) default color scheme. Possible values: `dark` | `light` | `no-preference`.
96
- * * `userAgent`: (optional) user-agent string.
97
- * * `locale`: (optional) locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
98
- * * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
99
- * * `chromium`: (optional) pass additional chromium options
100
- * * `electron`: (optional) pass additional electron options
101
- * * `channel`: (optional) While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge](https://playwright.dev/docs/browsers/#google-chrome--microsoft-edge).
109
+ * <!-- configuration -->
102
110
  *
103
111
  * #### Video Recording Customization
104
112
  *
105
113
  * By default, video is saved to `output/video` dir. You can customize this path by passing `dir` option to `recordVideo` option.
106
114
  *
107
- * * `video`: enables video recording for failed tests; videos are saved into `output/videos` folder
115
+ * `video`: enables video recording for failed tests; videos are saved into `output/videos` folder
108
116
  * * `keepVideoForPassedTests`: - save videos for passed tests
109
117
  * * `recordVideo`: [additional options for videos customization](https://playwright.dev/docs/next/api/class-browser#browser-new-context)
110
118
  *
@@ -167,7 +175,8 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
167
175
  * Playwright: {
168
176
  * url: "http://localhost",
169
177
  * chromium: {
170
- * browserWSEndpoint: 'ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a'
178
+ * browserWSEndpoint: 'ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a',
179
+ * cdpConnection: false // default is false
171
180
  * }
172
181
  * }
173
182
  * }
@@ -256,8 +265,6 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
256
265
  * const { browserContext } = this.helpers.Playwright;
257
266
  * await browserContext.cookies(); // get current browser context
258
267
  * ```
259
- *
260
- * ## Methods
261
268
  */
262
269
  class Playwright extends Helper {
263
270
  constructor(config) {
@@ -272,6 +279,7 @@ class Playwright extends Helper {
272
279
  this.sessionPages = {};
273
280
  this.activeSessionName = '';
274
281
  this.isElectron = false;
282
+ this.isCDPConnection = false;
275
283
  this.electronSessions = [];
276
284
  this.storageState = null;
277
285
 
@@ -347,6 +355,7 @@ class Playwright extends Helper {
347
355
  this.isRemoteBrowser = !!this.playwrightOptions.browserWSEndpoint;
348
356
  this.isElectron = this.options.browser === 'electron';
349
357
  this.userDataDir = this.playwrightOptions.userDataDir;
358
+ this.isCDPConnection = this.playwrightOptions.cdpConnection;
350
359
  popupStore.defaultAction = this.options.defaultPopupAction;
351
360
  }
352
361
 
@@ -699,6 +708,15 @@ class Playwright extends Helper {
699
708
  async _startBrowser() {
700
709
  if (this.isElectron) {
701
710
  this.browser = await playwright._electron.launch(this.playwrightOptions);
711
+ } else if (this.isRemoteBrowser && this.isCDPConnection) {
712
+ try {
713
+ this.browser = await playwright[this.options.browser].connectOverCDP(this.playwrightOptions);
714
+ } catch (err) {
715
+ if (err.toString().indexOf('ECONNREFUSED')) {
716
+ throw new RemoteBrowserConnectionRefused(err);
717
+ }
718
+ throw err;
719
+ }
702
720
  } else if (this.isRemoteBrowser) {
703
721
  try {
704
722
  this.browser = await playwright[this.options.browser].connect(this.playwrightOptions);
@@ -1157,6 +1175,7 @@ class Playwright extends Helper {
1157
1175
  if (!page) {
1158
1176
  throw new Error(`There is no ability to switch to next tab with offset ${num}`);
1159
1177
  }
1178
+ targetCreatedHandler.call(this, page);
1160
1179
  await this._setPage(page);
1161
1180
  return this._waitForAction();
1162
1181
  }
@@ -1239,7 +1258,9 @@ class Playwright extends Helper {
1239
1258
  if (this.isElectron) {
1240
1259
  throw new Error('Cannot open new tabs inside an Electron container');
1241
1260
  }
1242
- await this._setPage(await this.browserContext.newPage(options));
1261
+ const page = await this.browserContext.newPage(options);
1262
+ targetCreatedHandler.call(this, page);
1263
+ await this._setPage(page);
1243
1264
  return this._waitForAction();
1244
1265
  }
1245
1266
 
@@ -2071,9 +2092,11 @@ class Playwright extends Helper {
2071
2092
  * Get JS log from browser.
2072
2093
  *
2073
2094
  * ```js
2074
- * let logs = await I.grabBrowserLogs();
2075
- * console.log(JSON.stringify(logs))
2095
+ * const logs = await I.grabBrowserLogs();
2096
+ * const errors = logs.map(l => ({ type: l.type(), text: l.text() })).filter(l => l.type === 'error');
2097
+ * console.log(JSON.stringify(errors));
2076
2098
  * ```
2099
+ * [Learn more about console messages](https://playwright.dev/docs/api/class-consolemessage)
2077
2100
  * @return {Promise<any[]>}
2078
2101
  */
2079
2102
  async grabBrowserLogs() {
@@ -39,6 +39,35 @@ let perfTiming;
39
39
  const popupStore = new Popup();
40
40
  const consoleLogStore = new Console();
41
41
 
42
+ /**
43
+ * ## Configuration
44
+ *
45
+ * This helper should be configured in codecept.conf.js
46
+ *
47
+ * @typedef PuppeteerConfig
48
+ * @type {object}
49
+ * @prop {string} url - base url of website to be tested
50
+ * @prop {object} [basicAuth] (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
51
+ * @prop {boolean} [show] - show Google Chrome window for debug.
52
+ * @prop {boolean} [restart=true] - restart browser between tests.
53
+ * @prop {boolean} [disableScreenshots=false] - don't save screenshot on failure.
54
+ * @prop {boolean} [fullPageScreenshots=false] - make full page screenshots on failure.
55
+ * @prop {boolean} [uniqueScreenshotNames=false] - option to prevent screenshot override if you have scenarios with the same name in different suites.
56
+ * @prop {boolean} [keepBrowserState=false] - keep browser state between tests when `restart` is set to false.
57
+ * @prop {boolean} [keepCookies=false] - keep cookies between tests when `restart` is set to false.
58
+ * @prop {number} [waitForAction=100] - how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
59
+ * @prop {string} [waitForNavigation=load] - when to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions). Array values are accepted as well.
60
+ * @prop {number} [pressKeyDelay=10] - delay between key presses in ms. Used when calling Puppeteers page.type(...) in fillField/appendField
61
+ * @prop {number} [getPageTimeout=30000] - config option to set maximum navigation time in milliseconds. If the timeout is set to 0, then timeout will be disabled.
62
+ * @prop {number} [waitForTimeout=1000] - default wait* timeout in ms.
63
+ * @prop {string} [windowSize] - default window size. Set a dimension in format WIDTHxHEIGHT like `640x480`.
64
+ * @prop {string} [userAgent] - user-agent string.
65
+ * @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
66
+ * @prop {string} [browser=chrome] - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox).
67
+ * @prop {object} [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
68
+ */
69
+ const config = {};
70
+
42
71
  /**
43
72
  * Uses [Google Chrome's Puppeteer](https://github.com/GoogleChrome/puppeteer) library to run tests inside headless Chrome.
44
73
  * Browser control is executed via DevTools Protocol (instead of Selenium).
@@ -56,30 +85,7 @@ const consoleLogStore = new Console();
56
85
  *
57
86
  * > Experimental Firefox support [can be activated](https://codecept.io/helpers/Puppeteer-firefox).
58
87
  *
59
- * ## Configuration
60
- *
61
- * This helper should be configured in codecept.json or codecept.conf.js
62
- *
63
- * * `url`: base url of website to be tested
64
- * * `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
65
- * * `show`: (optional, default: false) - show Google Chrome window for debug.
66
- * * `restart`: (optional, default: true) - restart browser between tests.
67
- * * `disableScreenshots`: (optional, default: false) - don't save screenshot on failure.
68
- * * `fullPageScreenshots` (optional, default: false) - make full page screenshots on failure.
69
- * * `uniqueScreenshotNames`: (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites.
70
- * * `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to false.
71
- * * `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to false.
72
- * * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
73
- * * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions). Array values are accepted as well.
74
- * * `pressKeyDelay`: (optional, default: '10'). Delay between key presses in ms. Used when calling Puppeteers page.type(...) in fillField/appendField
75
- * * `getPageTimeout` (optional, default: '30000') config option to set maximum navigation time in milliseconds. If the timeout is set to 0, then timeout will be disabled.
76
- * * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
77
- * * `windowSize`: (optional) default window size. Set a dimension like `640x480`.
78
- * * `userAgent`: (optional) user-agent string.
79
- * * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
80
- * * `browser`: (optional, default: chrome) - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox).
81
- * * `chrome`: (optional) pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
82
- *
88
+ * <!-- configuration -->
83
89
  *
84
90
  * #### Example #1: Wait for 0 network connections.
85
91
  *
@@ -192,7 +198,6 @@ class Puppeteer extends Helper {
192
198
  super(config);
193
199
 
194
200
  puppeteer = requireWithFallback('puppeteer', 'puppeteer-core');
195
-
196
201
  // set defaults
197
202
  this.isRemoteBrowser = false;
198
203
  this.isRunning = false;
@@ -372,22 +377,22 @@ class Puppeteer extends Helper {
372
377
  }
373
378
 
374
379
  /**
375
- * Use Puppeteer API inside a test.
376
- *
377
- * First argument is a description of an action.
378
- * Second argument is async function that gets this helper as parameter.
379
- *
380
- * { [`page`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page), [`browser`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser) } from Puppeteer API are available.
381
- *
382
- * ```js
383
- * I.usePuppeteerTo('emulate offline mode', async ({ page }) {
384
- * await page.setOfflineMode(true);
385
- * });
386
- * ```
387
- *
388
- * @param {string} description used to show in logs.
389
- * @param {function} fn async function that is executed with Puppeteer as argument
390
- */
380
+ * Use Puppeteer API inside a test.
381
+ *
382
+ * First argument is a description of an action.
383
+ * Second argument is async function that gets this helper as parameter.
384
+ *
385
+ * { [`page`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page), [`browser`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser) } from Puppeteer API are available.
386
+ *
387
+ * ```js
388
+ * I.usePuppeteerTo('emulate offline mode', async ({ page }) {
389
+ * await page.setOfflineMode(true);
390
+ * });
391
+ * ```
392
+ *
393
+ * @param {string} description used to show in logs.
394
+ * @param {function} fn async function that is executed with Puppeteer as argument
395
+ */
391
396
  usePuppeteerTo(description, fn) {
392
397
  return this._useTo(...arguments);
393
398
  }
@@ -816,7 +821,8 @@ class Puppeteer extends Helper {
816
821
  if (locator) {
817
822
  const els = await this._locate(locator);
818
823
  assertElementExists(els, locator, 'Element');
819
- await els[0]._scrollIntoViewIfNeeded();
824
+ const el = els[0];
825
+ await el.evaluate((el) => el.scrollIntoView());
820
826
  const elementCoordinates = await getClickablePoint(els[0]);
821
827
  await this.executeScript((x, y) => window.scrollBy(x, y), elementCoordinates.x + offsetX, elementCoordinates.y + offsetY);
822
828
  } else {
@@ -1268,7 +1274,12 @@ class Puppeteer extends Helper {
1268
1274
  fs.mkdirSync(downloadPath, '0777');
1269
1275
  }
1270
1276
  fsExtra.emptyDirSync(downloadPath);
1271
- return this.page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath });
1277
+
1278
+ try {
1279
+ return this.page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath });
1280
+ } catch (e) {
1281
+ return this.page._client().send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath });
1282
+ }
1272
1283
  }
1273
1284
 
1274
1285
  /**
@@ -2,18 +2,28 @@ const axios = require('axios').default;
2
2
  const Secret = require('../secret');
3
3
 
4
4
  const Helper = require('../helper');
5
+ const { beautify } = require('../utils');
6
+
7
+ /**
8
+ * ## Configuration
9
+ *
10
+ * @typedef RESTConfig
11
+ * @type {object}
12
+ * @prop {string} endpoint - API base URL
13
+ * @prop {boolean} [prettyPrintJson=false] - pretty print json for response/request on console logs
14
+ * @prop {number} [timeout=1000] - timeout for requests in milliseconds. 10000ms by default
15
+ * @prop {object} [defaultHeaders] - a list of default headers
16
+ * @prop {function} [onRequest] - a async function which can update request object.
17
+ * @prop {function} [onResponse] - a async function which can update response object.
18
+ * @prop {number} [maxUploadFileSize] - set the max content file size in MB when performing api calls.
19
+ */
20
+ const config = {};
5
21
 
6
22
  /**
7
23
  * REST helper allows to send additional requests to the REST API during acceptance tests.
8
24
  * [Axios](https://github.com/axios/axios) library is used to perform requests.
9
25
  *
10
- * ## Configuration
11
- *
12
- * * endpoint: API base URL
13
- * * timeout: timeout for requests in milliseconds. 10000ms by default
14
- * * defaultHeaders: a list of default headers
15
- * * onRequest: a async function which can update request object.
16
- * * maxUploadFileSize: set the max content file size in MB when performing api calls.
26
+ * <!-- configuration -->
17
27
  *
18
28
  * ## Example
19
29
  *
@@ -22,6 +32,7 @@ const Helper = require('../helper');
22
32
  * helpers: {
23
33
  * REST: {
24
34
  * endpoint: 'http://site.com/api',
35
+ * prettyPrintJson: true,
25
36
  * onRequest: (request) => {
26
37
  * request.headers.auth = '123';
27
38
  * }
@@ -49,6 +60,9 @@ class REST extends Helper {
49
60
  timeout: 10000,
50
61
  defaultHeaders: {},
51
62
  endpoint: '',
63
+ prettyPrintJson: false,
64
+ onRequest: null,
65
+ onResponse: null,
52
66
  };
53
67
 
54
68
  if (this.options.maxContentLength) {
@@ -137,7 +151,7 @@ class REST extends Helper {
137
151
  await this.config.onRequest(request);
138
152
  }
139
153
 
140
- this.debugSection('Request', JSON.stringify(_debugRequest));
154
+ this.options.prettyPrintJson ? this.debugSection('Request', beautify(JSON.stringify(_debugRequest))) : this.debugSection('Request', JSON.stringify(_debugRequest));
141
155
 
142
156
  let response;
143
157
  try {
@@ -150,7 +164,7 @@ class REST extends Helper {
150
164
  if (this.config.onResponse) {
151
165
  await this.config.onResponse(response);
152
166
  }
153
- this.debugSection('Response', JSON.stringify(response.data));
167
+ this.options.prettyPrintJson ? this.debugSection('Response', beautify(JSON.stringify(response.data))) : this.debugSection('Response', JSON.stringify(response.data));
154
168
  return response;
155
169
  }
156
170