codeceptjs 3.7.5 → 3.7.6-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/codecept.js CHANGED
@@ -122,6 +122,7 @@ class Codecept {
122
122
  /**
123
123
  * Executes bootstrap.
124
124
  *
125
+ * @returns {Promise<void>}
125
126
  */
126
127
  async bootstrap() {
127
128
  return runHook(this.config.bootstrap, 'bootstrap')
@@ -129,7 +130,8 @@ class Codecept {
129
130
 
130
131
  /**
131
132
  * Executes teardown.
132
-
133
+ *
134
+ * @returns {Promise<void>}
133
135
  */
134
136
  async teardown() {
135
137
  return runHook(this.config.teardown, 'teardown')
@@ -262,6 +264,11 @@ class Codecept {
262
264
  })
263
265
  }
264
266
 
267
+ /**
268
+ * Returns the version string of CodeceptJS.
269
+ *
270
+ * @returns {string} The version string.
271
+ */
265
272
  static version() {
266
273
  return JSON.parse(readFileSync(`${__dirname}/../package.json`, 'utf8')).version
267
274
  }
@@ -23,11 +23,49 @@ const Codecept = require(process.env.CODECEPT_CLASS_PATH || '../../codecept')
23
23
  const { options, tests, testRoot, workerIndex, poolMode } = workerData
24
24
 
25
25
  // hide worker output
26
- if (!options.debug && !options.verbose)
26
+ // In pool mode, only suppress output if debug is NOT enabled
27
+ // In regular mode, hide result output but allow step output in verbose/debug
28
+ if (poolMode && !options.debug) {
29
+ // In pool mode without debug, suppress only result summaries and failures, but allow Scenario Steps
30
+ const originalWrite = process.stdout.write
31
+ process.stdout.write = string => {
32
+ // Always allow Scenario Steps output (including the circle symbol)
33
+ if (string.includes('Scenario Steps:') || string.includes('◯ Scenario Steps:')) {
34
+ return originalWrite.call(process.stdout, string)
35
+ }
36
+ if (string.includes(' FAIL |') || string.includes(' OK |') || string.includes('-- FAILURES:') || string.includes('AssertionError:') || string.includes('◯ File:')) {
37
+ return true
38
+ }
39
+ return originalWrite.call(process.stdout, string)
40
+ }
41
+ } else if (!poolMode && !options.debug && !options.verbose) {
27
42
  process.stdout.write = string => {
28
43
  stdout += string
29
44
  return true
30
45
  }
46
+ } else {
47
+ // In verbose/debug mode for test/suite modes, show step details
48
+ // but suppress individual worker result summaries to avoid duplicate output
49
+ const originalWrite = process.stdout.write
50
+ const originalConsoleLog = console.log
51
+
52
+ process.stdout.write = string => {
53
+ // Suppress individual worker result summaries and failure reports
54
+ if (string.includes(' FAIL |') || string.includes(' OK |') || string.includes('-- FAILURES:') || string.includes('AssertionError:') || string.includes('◯ File:') || string.includes('◯ Scenario Steps:')) {
55
+ return true
56
+ }
57
+ return originalWrite.call(process.stdout, string)
58
+ }
59
+
60
+ // Override console.log to catch result summaries
61
+ console.log = (...args) => {
62
+ const fullMessage = args.join(' ')
63
+ if (fullMessage.includes(' FAIL |') || fullMessage.includes(' OK |') || fullMessage.includes('-- FAILURES:')) {
64
+ return
65
+ }
66
+ return originalConsoleLog.apply(console, args)
67
+ }
68
+ }
31
69
 
32
70
  const overrideConfigs = tryOrDefault(() => JSON.parse(options.override), {})
33
71
 
package/lib/effects.js CHANGED
@@ -89,7 +89,7 @@ async function hopeThat(callback) {
89
89
  * - Restores the session state after each attempt, whether successful or not.
90
90
  *
91
91
  * @example
92
- * const { hopeThat } = require('codeceptjs/effects')
92
+ * const { retryTo } = require('codeceptjs/effects')
93
93
  * await retryTo((tries) => {
94
94
  * if (tries < 3) {
95
95
  * I.see('Non-existent element'); // Simulates a failure
@@ -261,11 +261,13 @@ class Appium extends Webdriver {
261
261
 
262
262
  this.platform = null
263
263
  if (config.capabilities[`${vendorPrefix.appium}:platformName`]) {
264
- this.platform = config.capabilities[`${vendorPrefix.appium}:platformName`].toLowerCase()
264
+ config.capabilities[`${vendorPrefix.appium}:platformName`] = config.capabilities[`${vendorPrefix.appium}:platformName`].toLowerCase()
265
+ this.platform = config.capabilities[`${vendorPrefix.appium}:platformName`]
265
266
  }
266
267
 
267
268
  if (config.capabilities.platformName) {
268
- this.platform = config.capabilities.platformName.toLowerCase()
269
+ config.capabilities.platformName = config.capabilities.platformName.toLowerCase()
270
+ this.platform = config.capabilities.platformName
269
271
  }
270
272
 
271
273
  return config
@@ -275,7 +277,7 @@ class Appium extends Webdriver {
275
277
  const _convertedCaps = {}
276
278
  for (const [key, value] of Object.entries(capabilities)) {
277
279
  if (!key.startsWith(vendorPrefix.appium)) {
278
- if (key !== 'platformName' && key !== 'bstack:options') {
280
+ if (key !== 'platformName' && key !== 'bstack:options' && key !== 'sauce:options') {
279
281
  _convertedCaps[`${vendorPrefix.appium}:${key}`] = value
280
282
  } else {
281
283
  _convertedCaps[`${key}`] = value
@@ -98,7 +98,13 @@ const pathSeparator = path.sep
98
98
  * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
99
99
  * @prop {object} [recordHar] - record HAR and will be saved to `output/har`. See more of [HAR options](https://playwright.dev/docs/api/class-browser#browser-new-context-option-record-har).
100
100
  * @prop {string} [testIdAttribute=data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id).
101
- * @prop {object} [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(\`[role="\${selector}\"]\`) } }`
101
+ * @prop {object} [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(`[role="${selector}"]`) } }`
102
+ * @prop {string|object} [storageState] - Playwright storage state (path to JSON file or object)
103
+ * passed directly to `browser.newContext`.
104
+ * If a Scenario is declared with a `cookies` option (e.g. `Scenario('name', { cookies: [...] }, fn)`),
105
+ * those cookies are used instead and the configured `storageState` is ignored (no merge).
106
+ * May include session cookies, auth tokens, localStorage and (if captured with
107
+ * `grabStorageState({ indexedDB: true })`) IndexedDB data; treat as sensitive and do not commit.
102
108
  */
103
109
  const config = {}
104
110
 
@@ -360,10 +366,11 @@ class Playwright extends Helper {
360
366
  // override defaults with config
361
367
  this._setConfig(config)
362
368
 
363
- // Call _init() to register selector engines - use setTimeout to avoid blocking constructor
364
- setTimeout(() => {
365
- this._init().catch(console.error)
366
- }, 0)
369
+ // pass storageState directly (string path or object) and let Playwright handle errors/missing file
370
+ if (typeof config.storageState !== 'undefined') {
371
+ this.storageState = config.storageState
372
+ }
373
+
367
374
  }
368
375
 
369
376
  _validateConfig(config) {
@@ -390,6 +397,7 @@ class Playwright extends Helper {
390
397
  use: { actionTimeout: 0 },
391
398
  ignoreHTTPSErrors: false, // Adding it here o that context can be set up to ignore the SSL errors,
392
399
  highlightElement: false,
400
+ storageState: undefined,
393
401
  }
394
402
 
395
403
  process.env.testIdAttribute = 'data-testid'
@@ -593,8 +601,7 @@ class Playwright extends Helper {
593
601
 
594
602
  // load pre-saved cookies
595
603
  if (test?.opts?.cookies) contextOptions.storageState = { cookies: test.opts.cookies }
596
-
597
- if (this.storageState) contextOptions.storageState = this.storageState
604
+ else if (this.storageState) contextOptions.storageState = this.storageState
598
605
  if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent
599
606
  if (this.options.locale) contextOptions.locale = this.options.locale
600
607
  if (this.options.colorScheme) contextOptions.colorScheme = this.options.colorScheme
@@ -2166,6 +2173,30 @@ class Playwright extends Helper {
2166
2173
  if (cookie[0]) return cookie[0]
2167
2174
  }
2168
2175
 
2176
+ /**
2177
+ * Grab the current storage state (cookies, localStorage, etc.) via Playwright's `browserContext.storageState()`.
2178
+ * Returns the raw object that Playwright provides.
2179
+ *
2180
+ * Security: The returned object can contain authentication tokens, session cookies
2181
+ * and (when `indexedDB: true` is used) data that may include user PII. Treat it as a secret.
2182
+ * Avoid committing it to source control and prefer storing it in a protected secrets store / CI artifact vault.
2183
+ *
2184
+ * @param {object} [options]
2185
+ * @param {boolean} [options.indexedDB] set to true to include IndexedDB in snapshot (Playwright >=1.51)
2186
+ *
2187
+ * ```js
2188
+ * // basic usage
2189
+ * const state = await I.grabStorageState();
2190
+ * require('fs').writeFileSync('authState.json', JSON.stringify(state));
2191
+ *
2192
+ * // include IndexedDB when using Firebase Auth, etc.
2193
+ * const stateWithIDB = await I.grabStorageState({ indexedDB: true });
2194
+ * ```
2195
+ */
2196
+ async grabStorageState(options = {}) {
2197
+ return this.browserContext.storageState(options)
2198
+ }
2199
+
2169
2200
  /**
2170
2201
  * {{> clearCookie }}
2171
2202
  */
@@ -281,6 +281,27 @@ class REST extends Helper {
281
281
  return this._executeRequest(request)
282
282
  }
283
283
 
284
+ /**
285
+ * Send HEAD request to REST API
286
+ *
287
+ * ```js
288
+ * I.sendHeadRequest('/api/users.json');
289
+ * ```
290
+ *
291
+ * @param {*} url
292
+ * @param {object} [headers={}] - the headers object to be sent. By default, it is sent as an empty object
293
+ *
294
+ * @returns {Promise<*>} response
295
+ */
296
+ async sendHeadRequest(url, headers = {}) {
297
+ const request = {
298
+ baseURL: this._url(url),
299
+ method: 'HEAD',
300
+ headers,
301
+ }
302
+ return this._executeRequest(request)
303
+ }
304
+
284
305
  /**
285
306
  * Sends POST request to API.
286
307
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.7.5",
3
+ "version": "3.7.6-beta.2",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -29,14 +29,19 @@
29
29
  "docs/webapi/**"
30
30
  ],
31
31
  "main": "lib/index.js",
32
+ "module": "lib/index.js",
33
+ "types": "typings/index.d.ts",
32
34
  "exports": {
33
- ".": "./lib/index.js",
35
+ ".": {
36
+ "import": "./lib/index.js",
37
+ "require": "./lib/index.js",
38
+ "types": "./typings/index.d.ts"
39
+ },
34
40
  "./lib/*": "./lib/*.js",
35
41
  "./els": "./lib/els.js",
36
42
  "./effects": "./lib/effects.js",
37
43
  "./steps": "./lib/steps.js"
38
44
  },
39
- "types": "typings/index.d.ts",
40
45
  "bin": {
41
46
  "codeceptjs": "./bin/codecept.js"
42
47
  },
@@ -91,7 +96,7 @@
91
96
  "cross-spawn": "7.0.6",
92
97
  "css-to-xpath": "0.1.0",
93
98
  "csstoxpath": "1.6.0",
94
- "envinfo": "7.14.0",
99
+ "envinfo": "7.15.0",
95
100
  "escape-string-regexp": "4.0.0",
96
101
  "figures": "3.2.0",
97
102
  "fn-args": "4.0.0",
@@ -120,7 +125,7 @@
120
125
  "uuid": "11.1.0"
121
126
  },
122
127
  "optionalDependencies": {
123
- "@codeceptjs/detox-helper": "1.1.12"
128
+ "@codeceptjs/detox-helper": "1.1.13"
124
129
  },
125
130
  "devDependencies": {
126
131
  "@apollo/server": "^5",
@@ -133,20 +138,20 @@
133
138
  "@pollyjs/core": "6.0.6",
134
139
  "@types/chai": "5.2.2",
135
140
  "@types/inquirer": "9.0.9",
136
- "@types/node": "24.5.2",
141
+ "@types/node": "24.6.0",
137
142
  "@wdio/sauce-service": "9.12.5",
138
143
  "@wdio/selenium-standalone-service": "8.15.0",
139
- "@wdio/utils": "9.15.0",
144
+ "@wdio/utils": "9.19.2",
140
145
  "@xmldom/xmldom": "0.9.8",
141
146
  "chai": "^4.0.0",
142
147
  "chai-as-promised": "7.1.2",
143
148
  "chai-subset": "1.6.0",
144
149
  "documentation": "14.0.3",
145
- "electron": "38.1.2",
150
+ "electron": "38.2.0",
146
151
  "eslint": "^9.36.0",
147
152
  "eslint-plugin-import": "2.32.0",
148
153
  "eslint-plugin-mocha": "11.1.0",
149
- "expect": "30.1.2",
154
+ "expect": "30.2.0",
150
155
  "express": "^5.1.0",
151
156
  "globals": "16.4.0",
152
157
  "graphql": "16.11.0",
@@ -157,7 +162,7 @@
157
162
  "jsdoc-typeof-plugin": "1.0.0",
158
163
  "json-server": "0.17.4",
159
164
  "mochawesome": "^7.1.3",
160
- "playwright": "1.55.0",
165
+ "playwright": "1.55.1",
161
166
  "prettier": "^3.3.2",
162
167
  "puppeteer": "24.15.0",
163
168
  "qrcode-terminal": "0.12.0",
@@ -97,7 +97,7 @@ declare namespace CodeceptJS {
97
97
  * tests: 'tests/**.test.ts'
98
98
  * ```
99
99
  */
100
- tests: string
100
+ tests: string | string[]
101
101
  /**
102
102
  * Where to store failure screenshots, artifacts, etc
103
103
  *
@@ -520,17 +520,16 @@ declare namespace CodeceptJS {
520
520
  }
521
521
  }
522
522
 
523
- type TryTo = <T>(fn: () => Promise<T> | T) => Promise<T | false>;
524
- type HopeThat = <T>(fn: () => Promise<T> | T) => Promise<T | false>;
525
- type RetryTo = <T>(fn: () => Promise<T> | T, retries?: number) => Promise<T>;
526
-
523
+ type TryTo = <T>(fn: () => Promise<T> | T) => Promise<T | false>
524
+ type HopeThat = <T>(fn: () => Promise<T> | T) => Promise<T | false>
525
+ type RetryTo = <T>(fn: () => Promise<T> | T, retries?: number) => Promise<T>
527
526
 
528
527
  // Globals
529
528
  declare const codecept_dir: string
530
529
  declare const output_dir: string
531
- declare const tryTo: TryTo;
532
- declare const retryTo: RetryTo;
533
- declare const hopeThat: HopeThat;
530
+ declare const tryTo: TryTo
531
+ declare const retryTo: RetryTo
532
+ declare const hopeThat: HopeThat
534
533
 
535
534
  declare const actor: CodeceptJS.actor
536
535
  declare const codecept_actor: CodeceptJS.actor
@@ -643,7 +642,7 @@ declare module '@codeceptjs/helper' {
643
642
  }
644
643
 
645
644
  declare module 'codeceptjs/effects' {
646
- export const tryTo: TryTo;
647
- export const retryTo: RetryTo;
648
- export const hopeThat: HopeThat;
645
+ export const tryTo: TryTo
646
+ export const retryTo: RetryTo
647
+ export const hopeThat: HopeThat
649
648
  }
@@ -2735,6 +2735,10 @@ declare namespace CodeceptJS {
2735
2735
  * @property [testIdAttribute = data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id).
2736
2736
  * @property [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(\`[role="\${selector}\"]\`) } }`
2737
2737
  */
2738
+ // @ts-ignore
2739
+ // @ts-ignore
2740
+ // @ts-ignore
2741
+ // @ts-ignore
2738
2742
  type PlaywrightConfig = {
2739
2743
  url?: string;
2740
2744
  browser?: 'chromium' | 'firefox' | 'webkit' | 'electron';
@@ -6112,6 +6116,10 @@ declare namespace CodeceptJS {
6112
6116
  * @property [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
6113
6117
  * @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
6114
6118
  */
6119
+ // @ts-ignore
6120
+ // @ts-ignore
6121
+ // @ts-ignore
6122
+ // @ts-ignore
6115
6123
  type PuppeteerConfig = {
6116
6124
  url: string;
6117
6125
  basicAuth?: any;
@@ -7956,6 +7964,10 @@ declare namespace CodeceptJS {
7956
7964
  * @property [onResponse] - an async function which can update response object.
7957
7965
  * @property [maxUploadFileSize] - set the max content file size in MB when performing api calls.
7958
7966
  */
7967
+ // @ts-ignore
7968
+ // @ts-ignore
7969
+ // @ts-ignore
7970
+ // @ts-ignore
7959
7971
  type RESTConfig = {
7960
7972
  endpoint?: string;
7961
7973
  prettyPrintJson?: boolean;
@@ -8081,6 +8093,16 @@ declare namespace CodeceptJS {
8081
8093
  * @returns response
8082
8094
  */
8083
8095
  sendGetRequest(url: any, headers?: any): Promise<any>;
8096
+ /**
8097
+ * Send HEAD request to REST API
8098
+ *
8099
+ * ```js
8100
+ * I.sendHeadRequest('/api/users.json');
8101
+ * ```
8102
+ * @param [headers = {}] - the headers object to be sent. By default, it is sent as an empty object
8103
+ * @returns response
8104
+ */
8105
+ sendHeadRequest(url: any, headers?: any): Promise<any>;
8084
8106
  /**
8085
8107
  * Sends POST request to API.
8086
8108
  *
@@ -9101,6 +9123,10 @@ declare namespace CodeceptJS {
9101
9123
  * @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
9102
9124
  * @property [logLevel = silent] - level of logging verbosity. Default: silent. Options: trace | debug | info | warn | error | silent. More info: https://webdriver.io/docs/configuration/#loglevel
9103
9125
  */
9126
+ // @ts-ignore
9127
+ // @ts-ignore
9128
+ // @ts-ignore
9129
+ // @ts-ignore
9104
9130
  type WebDriverConfig = {
9105
9131
  url: string;
9106
9132
  browser: string;
@@ -2825,6 +2825,10 @@ declare namespace CodeceptJS {
2825
2825
  * @property [testIdAttribute = data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id).
2826
2826
  * @property [customLocatorStrategies] - custom locator strategies. An object with keys as strategy names and values as JavaScript functions. Example: `{ byRole: (selector, root) => { return root.querySelector(\`[role="\${selector}\"]\`) } }`
2827
2827
  */
2828
+ // @ts-ignore
2829
+ // @ts-ignore
2830
+ // @ts-ignore
2831
+ // @ts-ignore
2828
2832
  type PlaywrightConfig = {
2829
2833
  url?: string;
2830
2834
  browser?: 'chromium' | 'firefox' | 'webkit' | 'electron';
@@ -6353,6 +6357,10 @@ declare namespace CodeceptJS {
6353
6357
  * @property [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
6354
6358
  * @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
6355
6359
  */
6360
+ // @ts-ignore
6361
+ // @ts-ignore
6362
+ // @ts-ignore
6363
+ // @ts-ignore
6356
6364
  type PuppeteerConfig = {
6357
6365
  url: string;
6358
6366
  basicAuth?: any;
@@ -8333,6 +8341,10 @@ declare namespace CodeceptJS {
8333
8341
  * @property [onResponse] - an async function which can update response object.
8334
8342
  * @property [maxUploadFileSize] - set the max content file size in MB when performing api calls.
8335
8343
  */
8344
+ // @ts-ignore
8345
+ // @ts-ignore
8346
+ // @ts-ignore
8347
+ // @ts-ignore
8336
8348
  type RESTConfig = {
8337
8349
  endpoint?: string;
8338
8350
  prettyPrintJson?: boolean;
@@ -8458,6 +8470,16 @@ declare namespace CodeceptJS {
8458
8470
  * @returns response
8459
8471
  */
8460
8472
  sendGetRequest(url: any, headers?: any): Promise<any>;
8473
+ /**
8474
+ * Send HEAD request to REST API
8475
+ *
8476
+ * ```js
8477
+ * I.sendHeadRequest('/api/users.json');
8478
+ * ```
8479
+ * @param [headers = {}] - the headers object to be sent. By default, it is sent as an empty object
8480
+ * @returns response
8481
+ */
8482
+ sendHeadRequest(url: any, headers?: any): Promise<any>;
8461
8483
  /**
8462
8484
  * Sends POST request to API.
8463
8485
  *
@@ -9538,6 +9560,10 @@ declare namespace CodeceptJS {
9538
9560
  * @property [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
9539
9561
  * @property [logLevel = silent] - level of logging verbosity. Default: silent. Options: trace | debug | info | warn | error | silent. More info: https://webdriver.io/docs/configuration/#loglevel
9540
9562
  */
9563
+ // @ts-ignore
9564
+ // @ts-ignore
9565
+ // @ts-ignore
9566
+ // @ts-ignore
9541
9567
  type WebDriverConfig = {
9542
9568
  url: string;
9543
9569
  browser: string;
@@ -11757,7 +11783,7 @@ declare namespace CodeceptJS {
11757
11783
  * - Logs errors and retries the callback until it either succeeds or the maximum number of attempts is reached.
11758
11784
  * - Restores the session state after each attempt, whether successful or not.
11759
11785
  * @example
11760
- * const { hopeThat } = require('codeceptjs/effects')
11786
+ * const { retryTo } = require('codeceptjs/effects')
11761
11787
  * await retryTo((tries) => {
11762
11788
  * if (tries < 3) {
11763
11789
  * I.see('Non-existent element'); // Simulates a failure