codeceptjs 3.0.6 → 3.0.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.
@@ -1,8 +1,6 @@
1
- let axios = require('axios');
1
+ const axios = require('axios').default;
2
2
  const Helper = require('../helper');
3
3
 
4
- let headers = {};
5
-
6
4
  /**
7
5
  * GraphQL helper allows to send additional requests to a GraphQl endpoint during acceptance tests.
8
6
  * [Axios](https://github.com/axios/axios) library is used to perform requests.
@@ -41,15 +39,16 @@ let headers = {};
41
39
  class GraphQL extends Helper {
42
40
  constructor(config) {
43
41
  super(config);
44
- axios = require('axios');
42
+ this.axios = axios.create();
43
+ this.headers = {};
45
44
  this.options = {
46
45
  timeout: 10000,
47
46
  defaultHeaders: {},
48
47
  endpoint: '',
49
48
  };
50
49
  this.options = Object.assign(this.options, config);
51
- headers = { ...this.options.defaultHeaders };
52
- axios.defaults.headers = this.options.defaultHeaders;
50
+ this.headers = { ...this.options.defaultHeaders };
51
+ this.axios.defaults.headers = this.options.defaultHeaders;
53
52
  }
54
53
 
55
54
  static _checkRequirements() {
@@ -66,10 +65,10 @@ class GraphQL extends Helper {
66
65
  * @param {object} request
67
66
  */
68
67
  async _executeQuery(request) {
69
- axios.defaults.timeout = request.timeout || this.options.timeout;
68
+ this.axios.defaults.timeout = request.timeout || this.options.timeout;
70
69
 
71
- if (headers && headers.auth) {
72
- request.auth = headers.auth;
70
+ if (this.headers && this.headers.auth) {
71
+ request.auth = this.headers.auth;
73
72
  }
74
73
 
75
74
  request.headers = Object.assign(request.headers, {
@@ -84,7 +83,7 @@ class GraphQL extends Helper {
84
83
 
85
84
  let response;
86
85
  try {
87
- response = await axios(request);
86
+ response = await this.axios(request);
88
87
  } catch (err) {
89
88
  if (!err.response) throw err;
90
89
  this.debugSection(
@@ -38,6 +38,7 @@ const consoleLogStore = new Console();
38
38
  const availableBrowsers = ['chromium', 'webkit', 'firefox', 'electron'];
39
39
 
40
40
  const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
41
+
41
42
  /**
42
43
  * Uses [Playwright](https://github.com/microsoft/playwright) library to run tests inside:
43
44
  *
@@ -515,6 +516,7 @@ class Playwright extends Helper {
515
516
  if (!page) return;
516
517
  page.setDefaultNavigationTimeout(this.options.getPageTimeout);
517
518
  this.context = await this.page;
519
+ this.contextLocator = null;
518
520
  if (this.config.browser === 'chrome') {
519
521
  await page.bringToFront();
520
522
  }
@@ -656,6 +658,7 @@ class Playwright extends Helper {
656
658
  const els = await this._locate(locator);
657
659
  assertElementExists(els, locator);
658
660
  this.context = els[0];
661
+ this.contextLocator = locator;
659
662
 
660
663
  this.withinLocator = new Locator(locator);
661
664
  }
@@ -663,6 +666,7 @@ class Playwright extends Helper {
663
666
  async _withinEnd() {
664
667
  this.withinLocator = null;
665
668
  this.context = await this.page;
669
+ this.contextLocator = null;
666
670
  }
667
671
 
668
672
  _extractDataFromPerformanceTiming(timing, ...dataNames) {
@@ -1562,15 +1566,32 @@ class Playwright extends Helper {
1562
1566
  return context.evaluate.apply(context, [fn, arg]);
1563
1567
  }
1564
1568
 
1569
+ /**
1570
+ * Grab Locator if called within Context
1571
+ *
1572
+ * @param {*} locator
1573
+ */
1574
+ _contextLocator(locator) {
1575
+ locator = buildLocatorString(new Locator(locator, 'css'));
1576
+
1577
+ if (this.contextLocator) {
1578
+ const contextLocator = buildLocatorString(new Locator(this.contextLocator, 'css'));
1579
+ locator = `${contextLocator} >> ${locator}`;
1580
+ }
1581
+
1582
+ return locator;
1583
+ }
1584
+
1565
1585
  /**
1566
1586
  * {{> grabTextFrom }}
1567
1587
  *
1568
1588
  */
1569
1589
  async grabTextFrom(locator) {
1570
- const texts = await this.grabTextFromAll(locator);
1571
- assertElementExists(texts, locator);
1572
- this.debugSection('Text', texts[0]);
1573
- return texts[0];
1590
+ locator = this._contextLocator(locator);
1591
+ const text = await this.page.textContent(locator);
1592
+ assertElementExists(text, locator);
1593
+ this.debugSection('Text', text);
1594
+ return text;
1574
1595
  }
1575
1596
 
1576
1597
  /**
@@ -2093,6 +2114,7 @@ class Playwright extends Helper {
2093
2114
 
2094
2115
  if (locator >= 0 && locator < childFrames.length) {
2095
2116
  this.context = childFrames[locator];
2117
+ this.contextLocator = locator;
2096
2118
  } else {
2097
2119
  throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath');
2098
2120
  }
@@ -2100,6 +2122,7 @@ class Playwright extends Helper {
2100
2122
  }
2101
2123
  if (!locator) {
2102
2124
  this.context = this.page;
2125
+ this.contextLocator = null;
2103
2126
  return;
2104
2127
  }
2105
2128
 
@@ -2110,8 +2133,10 @@ class Playwright extends Helper {
2110
2133
 
2111
2134
  if (contentFrame) {
2112
2135
  this.context = contentFrame;
2136
+ this.contextLocator = null;
2113
2137
  } else {
2114
2138
  this.context = els[0];
2139
+ this.contextLocator = locator;
2115
2140
  }
2116
2141
  }
2117
2142
 
@@ -2228,6 +2253,19 @@ async function findElements(matcher, locator) {
2228
2253
  return matcher.$$(buildLocatorString(locator));
2229
2254
  }
2230
2255
 
2256
+ async function getVisibleElements(elements) {
2257
+ const visibleElements = [];
2258
+ for (const element of elements) {
2259
+ if (await element.isVisible()) {
2260
+ visibleElements.push(element);
2261
+ }
2262
+ }
2263
+ if (visibleElements.length === 0) {
2264
+ return elements;
2265
+ }
2266
+ return visibleElements;
2267
+ }
2268
+
2231
2269
  async function proceedClick(locator, context = null, options = {}) {
2232
2270
  let matcher = await this._getContext();
2233
2271
  if (context) {
@@ -2247,7 +2285,8 @@ async function proceedClick(locator, context = null, options = {}) {
2247
2285
  if (options.force) {
2248
2286
  await els[0].dispatchEvent('click');
2249
2287
  } else {
2250
- await els[0].click(options);
2288
+ const element = els.length > 1 ? (await getVisibleElements(els))[0] : els[0];
2289
+ await element.click(options);
2251
2290
  }
2252
2291
  const promises = [];
2253
2292
  if (options.waitForNavigation) {
@@ -2505,11 +2544,13 @@ async function targetCreatedHandler(page) {
2505
2544
  // we are inside iframe?
2506
2545
  const frameEl = await this.context.frameElement();
2507
2546
  this.context = await frameEl.contentFrame();
2547
+ this.contextLocator = null;
2508
2548
  return;
2509
2549
  }
2510
2550
  // if context element was in iframe - keep it
2511
2551
  // if (await this.context.ownerFrame()) return;
2512
2552
  this.context = page;
2553
+ this.contextLocator = null;
2513
2554
  });
2514
2555
  });
2515
2556
  page.on('console', (msg) => {
@@ -396,6 +396,7 @@ class WebDriver extends Helper {
396
396
  this.isRunning = false;
397
397
  this.sessionWindows = {};
398
398
  this.activeSessionName = '';
399
+ this.customLocatorStrategies = config.customLocatorStrategies;
399
400
 
400
401
  this._setConfig(config);
401
402
 
@@ -503,6 +504,33 @@ class WebDriver extends Helper {
503
504
  }
504
505
  }
505
506
 
507
+ _lookupCustomLocator(customStrategy) {
508
+ if (typeof (this.customLocatorStrategies) !== 'object') {
509
+ return null;
510
+ }
511
+ const strategy = this.customLocatorStrategies[customStrategy];
512
+ return typeof (strategy) === 'function' ? strategy : null;
513
+ }
514
+
515
+ _isCustomLocator(locator) {
516
+ const locatorObj = new Locator(locator);
517
+ if (locatorObj.isCustom()) {
518
+ const customLocator = this._lookupCustomLocator(locatorObj.type);
519
+ if (customLocator) {
520
+ return true;
521
+ }
522
+ throw new Error('Please define "customLocatorStrategies" as an Object and the Locator Strategy as a "function".');
523
+ }
524
+ return false;
525
+ }
526
+
527
+ async _res(locator) {
528
+ const res = (this._isShadowLocator(locator) || this._isCustomLocator(locator))
529
+ ? await this._locate(locator)
530
+ : await this.$$(withStrictLocator(locator));
531
+ return res;
532
+ }
533
+
506
534
  async _startBrowser() {
507
535
  try {
508
536
  if (this.options.multiremote) {
@@ -530,9 +558,22 @@ class WebDriver extends Helper {
530
558
  await this._resizeWindowIfNeeded(this.browser, this.options.windowSize);
531
559
 
532
560
  this.$$ = this.browser.$$.bind(this.browser);
561
+
562
+ if (this._isCustomLocatorStrategyDefined()) {
563
+ Object.keys(this.customLocatorStrategies).forEach(async (customLocator) => {
564
+ this.debugSection('Weddriver', `adding custom locator strategy: ${customLocator}`);
565
+ const locatorFunction = this._lookupCustomLocator(customLocator);
566
+ this.browser.addLocatorStrategy(customLocator, locatorFunction);
567
+ });
568
+ }
569
+
533
570
  return this.browser;
534
571
  }
535
572
 
573
+ _isCustomLocatorStrategyDefined() {
574
+ return this.customLocatorStrategies && Object.keys(this.customLocatorStrategies).length;
575
+ }
576
+
536
577
  async _stopBrowser() {
537
578
  if (this.browser && this.isRunning) await this.browser.deleteSession();
538
579
  }
@@ -755,17 +796,34 @@ class WebDriver extends Helper {
755
796
  }
756
797
 
757
798
  if (!this.options.smartWait || !smartWait) {
799
+ if (this._isCustomLocator(locator)) {
800
+ const locatorObj = new Locator(locator);
801
+ return this.browser.custom$$(locatorObj.type, locatorObj.value);
802
+ }
803
+
758
804
  const els = await this.$$(withStrictLocator(locator));
759
805
  return els;
760
806
  }
761
807
 
762
808
  await this._smartWait(locator);
763
809
 
810
+ if (this._isCustomLocator(locator)) {
811
+ const locatorObj = new Locator(locator);
812
+ return this.browser.custom$$(locatorObj.type, locatorObj.value);
813
+ }
814
+
764
815
  const els = await this.$$(withStrictLocator(locator));
765
816
  await this.defineTimeout({ implicit: 0 });
766
817
  return els;
767
818
  }
768
819
 
820
+ _grabCustomLocator(locator) {
821
+ if (typeof locator === 'string') {
822
+ locator = new Locator(locator);
823
+ }
824
+ return locator.value ? locator.value : locator.custom;
825
+ }
826
+
769
827
  /**
770
828
  * Find a checkbox by providing human readable text:
771
829
  *
@@ -962,6 +1020,7 @@ class WebDriver extends Helper {
962
1020
  /**
963
1021
  * {{> fillField }}
964
1022
  * {{ react }}
1023
+ * {{ custom }}
965
1024
  *
966
1025
  */
967
1026
  async fillField(field, value) {
@@ -1335,7 +1394,7 @@ class WebDriver extends Helper {
1335
1394
  *
1336
1395
  */
1337
1396
  async seeElementInDOM(locator) {
1338
- const res = await this.$$(withStrictLocator(locator));
1397
+ const res = await this._res(locator);
1339
1398
  return empty('elements').negate(res);
1340
1399
  }
1341
1400
 
@@ -1344,7 +1403,7 @@ class WebDriver extends Helper {
1344
1403
  *
1345
1404
  */
1346
1405
  async dontSeeElementInDOM(locator) {
1347
- const res = await this.$$(withStrictLocator(locator));
1406
+ const res = await this._res(locator);
1348
1407
  return empty('elements').assert(res);
1349
1408
  }
1350
1409
 
@@ -1991,7 +2050,7 @@ class WebDriver extends Helper {
1991
2050
  }, aSec * 1000, `element (${new Locator(locator)}) still not enabled after ${aSec} sec`);
1992
2051
  }
1993
2052
  return this.browser.waitUntil(async () => {
1994
- const res = await this.$$(withStrictLocator(locator));
2053
+ const res = await this._res(locator);
1995
2054
  if (!res || res.length === 0) {
1996
2055
  return false;
1997
2056
  }
@@ -2018,7 +2077,7 @@ class WebDriver extends Helper {
2018
2077
  }, aSec * 1000, `element (${locator}) still not present on page after ${aSec} sec`);
2019
2078
  }
2020
2079
  return this.browser.waitUntil(async () => {
2021
- const res = await this.$$(withStrictLocator(locator));
2080
+ const res = await this._res(locator);
2022
2081
  return res && res.length;
2023
2082
  }, { timeout: aSec * 1000, timeoutMsg: `element (${locator}) still not present on page after ${aSec} sec` });
2024
2083
  }
@@ -2188,9 +2247,7 @@ class WebDriver extends Helper {
2188
2247
  }, aSec * 1000, `element (${new Locator(locator)}) still not visible after ${aSec} sec`);
2189
2248
  }
2190
2249
  return this.browser.waitUntil(async () => {
2191
- const res = (this._isShadowLocator(locator))
2192
- ? await this._locate(withStrictLocator(locator))
2193
- : await this.$$(withStrictLocator(locator));
2250
+ const res = await this._res(locator);
2194
2251
  if (!res || res.length === 0) return false;
2195
2252
  const selected = await forEachAsync(res, async el => el.isDisplayed());
2196
2253
  if (Array.isArray(selected)) {
@@ -2217,7 +2274,7 @@ class WebDriver extends Helper {
2217
2274
  }, aSec * 1000, `The number of elements (${new Locator(locator)}) is not ${num} after ${aSec} sec`);
2218
2275
  }
2219
2276
  return this.browser.waitUntil(async () => {
2220
- const res = await this.$$(withStrictLocator(locator));
2277
+ const res = await this._res(locator);
2221
2278
  if (!res || res.length === 0) return false;
2222
2279
  let selected = await forEachAsync(res, async el => el.isDisplayed());
2223
2280
 
@@ -2241,7 +2298,7 @@ class WebDriver extends Helper {
2241
2298
  }, aSec * 1000, `element (${new Locator(locator)}) still visible after ${aSec} sec`);
2242
2299
  }
2243
2300
  return this.browser.waitUntil(async () => {
2244
- const res = await this.$$(withStrictLocator(locator));
2301
+ const res = await this._res(locator);
2245
2302
  if (!res || res.length === 0) return true;
2246
2303
  const selected = await forEachAsync(res, async el => el.isDisplayed());
2247
2304
  return !selected.length;
@@ -2262,7 +2319,7 @@ class WebDriver extends Helper {
2262
2319
  const aSec = sec || this.options.waitForTimeout;
2263
2320
  if (isWebDriver5()) {
2264
2321
  return this.browser.waitUntil(async () => {
2265
- const res = await this.$$(withStrictLocator(locator));
2322
+ const res = await this._res(locator);
2266
2323
  if (!res || res.length === 0) {
2267
2324
  return true;
2268
2325
  }
@@ -2270,7 +2327,7 @@ class WebDriver extends Helper {
2270
2327
  }, aSec * 1000, `element (${new Locator(locator)}) still on page after ${aSec} sec`);
2271
2328
  }
2272
2329
  return this.browser.waitUntil(async () => {
2273
- const res = await this.$$(withStrictLocator(locator));
2330
+ const res = await this._res(locator);
2274
2331
  if (!res || res.length === 0) {
2275
2332
  return true;
2276
2333
  }
@@ -2543,12 +2600,9 @@ async function proceedSee(assertType, text, context, strict = false) {
2543
2600
  }
2544
2601
 
2545
2602
  const smartWaitEnabled = assertType === 'assert';
2546
-
2547
2603
  const res = await this._locate(withStrictLocator(context), smartWaitEnabled);
2548
2604
  assertElementExists(res, context);
2549
-
2550
2605
  const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)));
2551
-
2552
2606
  if (strict) {
2553
2607
  if (Array.isArray(selected) && selected.length !== 0) {
2554
2608
  return selected.map(elText => equals(description)[assertType](text, elText));
@@ -2616,6 +2670,11 @@ async function filterAsync(array, callback) {
2616
2670
 
2617
2671
  async function findClickable(locator, locateFn) {
2618
2672
  locator = new Locator(locator);
2673
+
2674
+ if (this._isCustomLocator(locator)) {
2675
+ return locateFn(locator.value);
2676
+ }
2677
+
2619
2678
  if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true);
2620
2679
  if (!locator.isFuzzy()) return locateFn(locator, true);
2621
2680
 
@@ -2637,6 +2696,10 @@ async function findClickable(locator, locateFn) {
2637
2696
  async function findFields(locator) {
2638
2697
  locator = new Locator(locator);
2639
2698
 
2699
+ if (this._isCustomLocator(locator)) {
2700
+ return this._locate(locator);
2701
+ }
2702
+
2640
2703
  if (locator.isAccessibilityId() && !this.isWeb) return this._locate(locator, true);
2641
2704
  if (!locator.isFuzzy()) return this._locate(locator, true);
2642
2705
 
@@ -2742,6 +2805,10 @@ async function findCheckable(locator, locateFn) {
2742
2805
  let els;
2743
2806
  locator = new Locator(locator);
2744
2807
 
2808
+ if (this._isCustomLocator(locator)) {
2809
+ return locateFn(locator.value);
2810
+ }
2811
+
2745
2812
  if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true);
2746
2813
  if (!locator.isFuzzy()) return locateFn(locator, true);
2747
2814
 
@@ -2787,6 +2854,7 @@ function getElementId(el) {
2787
2854
  if (el.ELEMENT) {
2788
2855
  return el.ELEMENT;
2789
2856
  }
2857
+
2790
2858
  return null;
2791
2859
  }
2792
2860
 
package/lib/output.js CHANGED
@@ -190,6 +190,9 @@ module.exports = {
190
190
  * @param {string} [color]
191
191
  */
192
192
  say(message, color = 'cyan') {
193
+ if (colors[color] === undefined) {
194
+ color = 'cyan';
195
+ }
193
196
  if (outputLevel >= 1) print(` ${colors[color].bold(message)}`);
194
197
  },
195
198
 
@@ -107,6 +107,11 @@ module.exports = function (config) {
107
107
  if (allureReporter) {
108
108
  allureReporter.addAttachment('Last Seen Screenshot', fs.readFileSync(path.join(global.output_dir, fileName)), 'image/png');
109
109
  }
110
+
111
+ const cucumberReporter = Container.plugins('cucumberJsonReporter');
112
+ if (cucumberReporter) {
113
+ cucumberReporter.addScreenshot(test.artifacts.screenshot);
114
+ }
110
115
  } catch (err) {
111
116
  output.plugin(err);
112
117
  if (
package/lib/ui.js CHANGED
@@ -176,8 +176,12 @@ module.exports = function (suite) {
176
176
  * @kind constant
177
177
  * @type {CodeceptJS.IScenario}
178
178
  */
179
- context.xScenario = context.Scenario.skip = function (title) {
180
- return context.Scenario(title, {});
179
+ context.xScenario = context.Scenario.skip = function (title, opts = {}, fn) {
180
+ if (typeof opts === 'function' && !fn) {
181
+ opts = {};
182
+ }
183
+
184
+ return context.Scenario(title, opts);
181
185
  };
182
186
 
183
187
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.0.6",
3
+ "version": "3.0.7",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -84,7 +84,6 @@
84
84
  "promise-retry": "^1.1.1",
85
85
  "requireg": "^0.2.2",
86
86
  "resq": "^1.10.0",
87
- "semver": "^6.2.0",
88
87
  "sprintf-js": "^1.1.1"
89
88
  },
90
89
  "devDependencies": {
@@ -127,6 +126,7 @@
127
126
  "qrcode-terminal": "^0.12.0",
128
127
  "rosie": "^1.6.0",
129
128
  "runok": "^0.9.2",
129
+ "semver": "^6.3.0",
130
130
  "sinon": "^9.2.2",
131
131
  "sinon-chai": "^3.5.0",
132
132
  "testcafe": "^1.9.4",
@@ -8,13 +8,13 @@ declare namespace CodeceptJS {
8
8
  import("./utils").Translate<T, Translation.Actions>;
9
9
 
10
10
  type Cookie = {
11
- name: string
12
- value: string
13
- }
11
+ name: string;
12
+ value: string;
13
+ };
14
14
 
15
15
  interface PageScrollPosition {
16
- x: number,
17
- y: number
16
+ x: number;
17
+ y: number;
18
18
  }
19
19
 
20
20
  // Could get extended by user generated typings
@@ -23,7 +23,7 @@ declare namespace CodeceptJS {
23
23
  interface IHook {}
24
24
  interface IScenario {}
25
25
  interface IFeature {
26
- (title: string): FeatureConfig
26
+ (title: string): FeatureConfig;
27
27
  }
28
28
  interface CallbackOrder extends Array<any> {}
29
29
  interface SupportObject {
@@ -51,25 +51,48 @@ declare namespace CodeceptJS {
51
51
  | { frame: string }
52
52
  | { android: string }
53
53
  | { ios: string }
54
- | { android: string, ios: string }
55
- | { react: string };
56
-
57
- interface CustomLocators { }
58
- type LocatorOrString = string | ILocator | Locator | CustomLocators[keyof CustomLocators];
54
+ | { android: string; ios: string }
55
+ | { react: string }
56
+ | { shadow: string }
57
+ | { custom: string };
58
+
59
+ interface CustomLocators {}
60
+ type LocatorOrString =
61
+ | string
62
+ | ILocator
63
+ | Locator
64
+ | CustomLocators[keyof CustomLocators];
59
65
 
60
66
  type StringOrSecret = string | CodeceptJS.Secret;
61
67
 
62
- interface HookCallback { (args: SupportObject): void; }
63
- interface Scenario extends IScenario { only: IScenario, skip: IScenario, todo: IScenario}
64
- interface Feature extends IFeature { skip: IFeature }
65
- interface IData { Scenario: IScenario, only: { Scenario: IScenario } }
68
+ interface HookCallback {
69
+ (args: SupportObject): void;
70
+ }
71
+ interface Scenario extends IScenario {
72
+ only: IScenario;
73
+ skip: IScenario;
74
+ todo: IScenario;
75
+ }
76
+ interface Feature extends IFeature {
77
+ skip: IFeature;
78
+ }
79
+ interface IData {
80
+ Scenario: IScenario;
81
+ only: { Scenario: IScenario };
82
+ }
66
83
 
67
84
  interface IScenario {
68
85
  // Scenario.todo can be called only with a title.
69
86
  (title: string, callback?: HookCallback): ScenarioConfig;
70
- (title: string, opts: { [key: string]: any }, callback: HookCallback): ScenarioConfig;
87
+ (
88
+ title: string,
89
+ opts: { [key: string]: any },
90
+ callback: HookCallback
91
+ ): ScenarioConfig;
92
+ }
93
+ interface IHook {
94
+ (callback: HookCallback): void;
71
95
  }
72
- interface IHook { (callback: HookCallback): void; }
73
96
 
74
97
  interface Globals {
75
98
  codeceptjs: typeof codeceptjs;
@@ -164,12 +187,12 @@ declare namespace Mocha {
164
187
  }
165
188
 
166
189
  interface Suite extends SuiteRunnable {
167
- tags: any[]
168
- comment: string
169
- feature: any
190
+ tags: any[];
191
+ comment: string;
192
+ feature: any;
170
193
  }
171
194
 
172
- interface Test extends Runnable {
195
+ interface Test extends Runnable {
173
196
  tags: any[];
174
197
  }
175
198
  }
@@ -2363,7 +2363,7 @@ declare namespace CodeceptJS {
2363
2363
  * This helper should be configured in codecept.json or codecept.conf.js
2364
2364
  *
2365
2365
  * * `url`: base url of website to be tested
2366
- * * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`. Default: chromium.
2366
+ * * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
2367
2367
  * * `show`: (optional, default: false) - show browser window.
2368
2368
  * * `restart`: (optional, default: true) - restart browser between tests.
2369
2369
  * * `disableScreenshots`: (optional, default: false) - don't save screenshot on failure.
@@ -2382,6 +2382,7 @@ declare namespace CodeceptJS {
2382
2382
  * * `userAgent`: (optional) user-agent string.
2383
2383
  * * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
2384
2384
  * * `chromium`: (optional) pass additional chromium options
2385
+ * * `electron`: (optional) pass additional electron options
2385
2386
  *
2386
2387
  * #### Example #1: Wait for 0 network connections.
2387
2388
  *
@@ -2426,7 +2427,7 @@ declare namespace CodeceptJS {
2426
2427
  * }
2427
2428
  * ```
2428
2429
  *
2429
- * #### Example #4: Connect to remote browser by specifying [websocket endpoint](https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target)
2430
+ * #### Example #4: Connect to remote browser by specifying [websocket endpoint](https://playwright.dev/docs/api/class-browsertype#browsertypeconnectparams)
2430
2431
  *
2431
2432
  * ```js
2432
2433
  * {
@@ -2434,7 +2435,7 @@ declare namespace CodeceptJS {
2434
2435
  * Playwright: {
2435
2436
  * url: "http://localhost",
2436
2437
  * chromium: {
2437
- * browserWSEndpoint: "ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a"
2438
+ * browserWSEndpoint: { wsEndpoint: 'ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a' }
2438
2439
  * }
2439
2440
  * }
2440
2441
  * }
@@ -2452,6 +2453,7 @@ declare namespace CodeceptJS {
2452
2453
  * url: "http://localhost",
2453
2454
  * show: true // headless mode not supported for extensions
2454
2455
  * chromium: {
2456
+ * userDataDir: '/tmp/playwright-tmp', // necessary to launch the browser in normal mode instead of incognito,
2455
2457
  * args: [
2456
2458
  * `--disable-extensions-except=${pathToExtension}`,
2457
2459
  * `--load-extension=${pathToExtension}`
@@ -3466,6 +3468,10 @@ declare namespace CodeceptJS {
3466
3468
  * @param [arg] - optional argument to pass to the function
3467
3469
  */
3468
3470
  executeScript(fn: string | ((...params: any[]) => any), arg?: any): Promise<any>;
3471
+ /**
3472
+ * Grab Locator if called within Context
3473
+ */
3474
+ _contextLocator(locator: any): void;
3469
3475
  /**
3470
3476
  * Retrieves a text from an element located by CSS or XPath and returns it to test.
3471
3477
  * Resumes test execution, so **should be used inside async with `await`** operator.
@@ -8451,6 +8457,7 @@ declare namespace CodeceptJS {
8451
8457
  * @param value - text value to fill.
8452
8458
  *
8453
8459
  * {{ react }}
8460
+ * {{ custom }}
8454
8461
  */
8455
8462
  fillField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret): void;
8456
8463
  /**
@@ -9753,7 +9760,7 @@ declare namespace CodeceptJS {
9753
9760
  /**
9754
9761
  * Get current config.
9755
9762
  */
9756
- static get(key: string, val: any): any;
9763
+ static get(key?: string, val?: any): any;
9757
9764
  /**
9758
9765
  * Appends values to current config
9759
9766
  */
@@ -9868,6 +9875,7 @@ declare namespace CodeceptJS {
9868
9875
  before: 'global.before';
9869
9876
  after: 'global.after';
9870
9877
  result: 'global.result';
9878
+ failures: 'global.failures';
9871
9879
  };
9872
9880
  const multiple: {
9873
9881
  before: 'multiple.before';
@@ -10048,7 +10056,7 @@ declare namespace CodeceptJS {
10048
10056
  * Print information for a process
10049
10057
  * Used in multiple-run
10050
10058
  */
10051
- function process(process: string): string;
10059
+ function process(process: string | null): string;
10052
10060
  /**
10053
10061
  * Print information in --debug mode
10054
10062
  */
@@ -10149,6 +10157,10 @@ declare namespace CodeceptJS {
10149
10157
  * Get a list of all chained tasks
10150
10158
  */
10151
10159
  scheduled(): string;
10160
+ /**
10161
+ * Get the queue id
10162
+ */
10163
+ getQueueId(): number;
10152
10164
  /**
10153
10165
  * Get a state of current queue and tasks
10154
10166
  */