codeceptjs 3.5.15 → 3.6.0-beta.1.ai-healers

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 (139) hide show
  1. package/README.md +2 -2
  2. package/bin/codecept.js +66 -30
  3. package/docs/advanced.md +351 -0
  4. package/docs/ai.md +365 -0
  5. package/docs/api.md +323 -0
  6. package/docs/basics.md +979 -0
  7. package/docs/bdd.md +539 -0
  8. package/docs/best.md +237 -0
  9. package/docs/books.md +37 -0
  10. package/docs/bootstrap.md +135 -0
  11. package/docs/build/AI.js +124 -0
  12. package/docs/build/ApiDataFactory.js +410 -0
  13. package/docs/build/Appium.js +2027 -0
  14. package/docs/build/Expect.js +422 -0
  15. package/docs/build/FileSystem.js +228 -0
  16. package/docs/build/GraphQL.js +229 -0
  17. package/docs/build/GraphQLDataFactory.js +309 -0
  18. package/docs/build/JSONResponse.js +338 -0
  19. package/docs/build/Mochawesome.js +71 -0
  20. package/docs/build/Nightmare.js +2152 -0
  21. package/docs/build/Playwright.js +5110 -0
  22. package/docs/build/Protractor.js +2706 -0
  23. package/docs/build/Puppeteer.js +3905 -0
  24. package/docs/build/REST.js +344 -0
  25. package/docs/build/TestCafe.js +2125 -0
  26. package/docs/build/WebDriver.js +4240 -0
  27. package/docs/changelog.md +2572 -0
  28. package/docs/commands.md +266 -0
  29. package/docs/community-helpers.md +58 -0
  30. package/docs/configuration.md +157 -0
  31. package/docs/continuous-integration.md +22 -0
  32. package/docs/custom-helpers.md +306 -0
  33. package/docs/data.md +379 -0
  34. package/docs/detox.md +235 -0
  35. package/docs/docker.md +136 -0
  36. package/docs/email.md +183 -0
  37. package/docs/examples.md +149 -0
  38. package/docs/heal.md +186 -0
  39. package/docs/helpers/ApiDataFactory.md +266 -0
  40. package/docs/helpers/Appium.md +1374 -0
  41. package/docs/helpers/Detox.md +586 -0
  42. package/docs/helpers/Expect.md +275 -0
  43. package/docs/helpers/FileSystem.md +152 -0
  44. package/docs/helpers/GraphQL.md +151 -0
  45. package/docs/helpers/GraphQLDataFactory.md +226 -0
  46. package/docs/helpers/JSONResponse.md +254 -0
  47. package/docs/helpers/Mochawesome.md +8 -0
  48. package/docs/helpers/MockRequest.md +377 -0
  49. package/docs/helpers/Nightmare.md +1305 -0
  50. package/docs/helpers/OpenAI.md +70 -0
  51. package/docs/helpers/Playwright.md +2759 -0
  52. package/docs/helpers/Polly.md +44 -0
  53. package/docs/helpers/Protractor.md +1769 -0
  54. package/docs/helpers/Puppeteer-firefox.md +86 -0
  55. package/docs/helpers/Puppeteer.md +2317 -0
  56. package/docs/helpers/REST.md +218 -0
  57. package/docs/helpers/TestCafe.md +1321 -0
  58. package/docs/helpers/WebDriver.md +2547 -0
  59. package/docs/hooks.md +340 -0
  60. package/docs/index.md +111 -0
  61. package/docs/installation.md +75 -0
  62. package/docs/internal-api.md +266 -0
  63. package/docs/locators.md +339 -0
  64. package/docs/mobile-react-native-locators.md +67 -0
  65. package/docs/mobile.md +338 -0
  66. package/docs/pageobjects.md +291 -0
  67. package/docs/parallel.md +400 -0
  68. package/docs/playwright.md +632 -0
  69. package/docs/plugins.md +1247 -0
  70. package/docs/puppeteer.md +316 -0
  71. package/docs/quickstart.md +162 -0
  72. package/docs/react.md +70 -0
  73. package/docs/reports.md +392 -0
  74. package/docs/secrets.md +36 -0
  75. package/docs/shadow.md +68 -0
  76. package/docs/shared/keys.mustache +31 -0
  77. package/docs/shared/react.mustache +1 -0
  78. package/docs/testcafe.md +174 -0
  79. package/docs/translation.md +247 -0
  80. package/docs/tutorial.md +271 -0
  81. package/docs/typescript.md +180 -0
  82. package/docs/ui.md +59 -0
  83. package/docs/videos.md +28 -0
  84. package/docs/visual.md +202 -0
  85. package/docs/vue.md +143 -0
  86. package/docs/webdriver.md +701 -0
  87. package/docs/wiki/Books-&-Posts.md +27 -0
  88. package/docs/wiki/Community-Helpers-&-Plugins.md +53 -0
  89. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +61 -0
  90. package/docs/wiki/Examples.md +145 -0
  91. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +68 -0
  92. package/docs/wiki/Home.md +16 -0
  93. package/docs/wiki/Migration-to-Appium-v2---CodeceptJS.md +83 -0
  94. package/docs/wiki/Release-Process.md +24 -0
  95. package/docs/wiki/Roadmap.md +23 -0
  96. package/docs/wiki/Tests.md +1393 -0
  97. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +153 -0
  98. package/docs/wiki/Videos.md +19 -0
  99. package/lib/actor.js +3 -6
  100. package/lib/ai.js +152 -80
  101. package/lib/cli.js +1 -0
  102. package/lib/command/dryRun.js +13 -44
  103. package/lib/command/generate.js +34 -0
  104. package/lib/command/run-workers.js +3 -0
  105. package/lib/command/run.js +3 -0
  106. package/lib/container.js +2 -0
  107. package/lib/heal.js +172 -0
  108. package/lib/helper/AI.js +124 -0
  109. package/lib/helper/Appium.js +12 -36
  110. package/lib/helper/Expect.js +8 -11
  111. package/lib/helper/JSONResponse.js +8 -8
  112. package/lib/helper/Playwright.js +240 -100
  113. package/lib/helper/Puppeteer.js +68 -182
  114. package/lib/helper/REST.js +1 -4
  115. package/lib/helper/WebDriver.js +10 -324
  116. package/lib/index.js +3 -0
  117. package/lib/listener/steps.js +0 -2
  118. package/lib/locator.js +4 -13
  119. package/lib/plugin/coverage.js +99 -112
  120. package/lib/plugin/heal.js +26 -117
  121. package/lib/recorder.js +11 -5
  122. package/lib/step.js +1 -3
  123. package/lib/store.js +2 -0
  124. package/lib/template/heal.js +39 -0
  125. package/package.json +35 -47
  126. package/typings/index.d.ts +0 -17
  127. package/typings/promiseBasedTypes.d.ts +57 -340
  128. package/typings/types.d.ts +73 -433
  129. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  130. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  131. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  132. package/docs/webapi/seeTraffic.mustache +0 -36
  133. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  134. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  135. package/docs/webapi/waitForCookie.mustache +0 -9
  136. package/lib/helper/MockServer.js +0 -221
  137. package/lib/helper/errors/ElementAssertion.js +0 -38
  138. package/lib/helper/networkTraffics/utils.js +0 -137
  139. /package/{lib/helper → docs/build}/OpenAI.js +0 -0
@@ -6,7 +6,6 @@ const fs = require('fs');
6
6
 
7
7
  const Helper = require('@codeceptjs/helper');
8
8
  const crypto = require('crypto');
9
- const promiseRetry = require('promise-retry');
10
9
  const stringIncludes = require('../assert/include').includes;
11
10
  const { urlEquals, equals } = require('../assert/equal');
12
11
  const { debug } = require('../output');
@@ -33,10 +32,6 @@ const { highlightElement } = require('./scripts/highlightElement');
33
32
  const store = require('../store');
34
33
  const { focusElement } = require('./scripts/focusElement');
35
34
  const { blurElement } = require('./scripts/blurElement');
36
- const {
37
- dontSeeElementError, seeElementError, seeElementInDOMError, dontSeeElementInDOMError,
38
- } = require('./errors/ElementAssertion');
39
- const { allParameterValuePairsMatchExtreme, extractQueryObjects, createAdvancedTestResults } = require('./networkTraffics/utils');
40
35
 
41
36
  const SHADOW = 'shadow';
42
37
  const webRoot = 'body';
@@ -453,11 +448,6 @@ class WebDriver extends Helper {
453
448
  this.activeSessionName = '';
454
449
  this.customLocatorStrategies = config.customLocatorStrategies;
455
450
 
456
- // for network stuff
457
- this.requests = [];
458
- this.recording = false;
459
- this.recordedAtLeastOnce = false;
460
-
461
451
  this._setConfig(config);
462
452
 
463
453
  Locator.addFilter((locator, result) => {
@@ -497,9 +487,8 @@ class WebDriver extends Helper {
497
487
  if (config.host) {
498
488
  // webdriverio spec
499
489
  config.hostname = config.host;
500
- config.path = config.path ? config.path : '/wd/hub';
490
+ config.path = '/wd/hub';
501
491
  }
502
-
503
492
  config.baseUrl = config.url || config.baseUrl;
504
493
  if (config.desiredCapabilities && Object.keys(config.desiredCapabilities).length) {
505
494
  config.capabilities = config.desiredCapabilities;
@@ -640,11 +629,6 @@ class WebDriver extends Helper {
640
629
  if (this.browser.capabilities && this.browser.capabilities.platformName) {
641
630
  this.browser.capabilities.platformName = this.browser.capabilities.platformName.toLowerCase();
642
631
  }
643
-
644
- if (this.options.automationProtocol) {
645
- this.puppeteerBrowser = await this.browser.getPuppeteer();
646
- }
647
-
648
632
  return this.browser;
649
633
  }
650
634
 
@@ -977,12 +961,12 @@ class WebDriver extends Helper {
977
961
  */
978
962
  amOnPage(url) {
979
963
  let split_url;
980
- if (this.options.basicAuth) {
964
+ if (this.config.basicAuth) {
981
965
  if (url.startsWith('/')) {
982
- url = this.options.url + url;
966
+ url = this.config.url + url;
983
967
  }
984
968
  split_url = url.split('//');
985
- url = `${split_url[0]}//${this.options.basicAuth.username}:${this.options.basicAuth.password}@${split_url[1]}`;
969
+ url = `${split_url[0]}//${this.config.basicAuth.username}:${this.config.basicAuth.password}@${split_url[1]}`;
986
970
  }
987
971
  return this.browser.url(url);
988
972
  }
@@ -1477,11 +1461,7 @@ class WebDriver extends Helper {
1477
1461
  const res = await this._locate(locator, true);
1478
1462
  assertElementExists(res, locator);
1479
1463
  const selected = await forEachAsync(res, async el => el.isDisplayed());
1480
- try {
1481
- return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
1482
- } catch (e) {
1483
- dontSeeElementError(locator);
1484
- }
1464
+ return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(selected);
1485
1465
  }
1486
1466
 
1487
1467
  /**
@@ -1494,11 +1474,7 @@ class WebDriver extends Helper {
1494
1474
  return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(false);
1495
1475
  }
1496
1476
  const selected = await forEachAsync(res, async el => el.isDisplayed());
1497
- try {
1498
- return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
1499
- } catch (e) {
1500
- seeElementError(locator);
1501
- }
1477
+ return truth(`elements of ${(new Locator(locator))}`, 'to be seen').negate(selected);
1502
1478
  }
1503
1479
 
1504
1480
  /**
@@ -1507,11 +1483,7 @@ class WebDriver extends Helper {
1507
1483
  */
1508
1484
  async seeElementInDOM(locator) {
1509
1485
  const res = await this._res(locator);
1510
- try {
1511
- return empty('elements').negate(res);
1512
- } catch (e) {
1513
- dontSeeElementInDOMError(locator);
1514
- }
1486
+ return empty('elements').negate(res);
1515
1487
  }
1516
1488
 
1517
1489
  /**
@@ -1520,11 +1492,7 @@ class WebDriver extends Helper {
1520
1492
  */
1521
1493
  async dontSeeElementInDOM(locator) {
1522
1494
  const res = await this._res(locator);
1523
- try {
1524
- return empty('elements').assert(res);
1525
- } catch (e) {
1526
- seeElementInDOMError(locator);
1527
- }
1495
+ return empty('elements').assert(res);
1528
1496
  }
1529
1497
 
1530
1498
  /**
@@ -1644,8 +1612,6 @@ class WebDriver extends Helper {
1644
1612
  for (let i = 0; i < val.length; ++i) {
1645
1613
  const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(val[i], 10);
1646
1614
  const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
1647
- // the attribute could be a boolean
1648
- if (typeof _actual === 'boolean') return _actual === _expected;
1649
1615
  if (_actual !== _expected) return false;
1650
1616
  }
1651
1617
  return true;
@@ -1873,37 +1839,6 @@ class WebDriver extends Helper {
1873
1839
  return cookie[0];
1874
1840
  }
1875
1841
 
1876
- /**
1877
- * {{> waitForCookie }}
1878
- */
1879
- async waitForCookie(name, sec) {
1880
- // by default, we will retry 3 times
1881
- let retries = 3;
1882
- const waitTimeout = sec || this.options.waitForTimeoutInSeconds;
1883
-
1884
- if (sec) {
1885
- retries = sec;
1886
- } else {
1887
- retries = waitTimeout - 1;
1888
- }
1889
-
1890
- return promiseRetry(async (retry, number) => {
1891
- const _grabCookie = async (name) => {
1892
- const cookie = await this.browser.getCookies([name]);
1893
- if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`);
1894
- };
1895
-
1896
- this.debugSection('Wait for cookie: ', name);
1897
- if (number > 1) this.debugSection('Retrying... Attempt #', number);
1898
-
1899
- try {
1900
- await _grabCookie(name);
1901
- } catch (e) {
1902
- retry(e);
1903
- }
1904
- }, { retries, maxTimeout: 1000 });
1905
- }
1906
-
1907
1842
  /**
1908
1843
  * Accepts the active JavaScript native popup window, as created by window.alert|window.confirm|window.prompt.
1909
1844
  * Don't confuse popups with modal windows, as created by [various
@@ -2615,9 +2550,9 @@ class WebDriver extends Helper {
2615
2550
  return;
2616
2551
  }
2617
2552
  this.geoLocation = { latitude, longitude };
2618
-
2553
+ const puppeteerBrowser = await this.browser.getPuppeteer();
2619
2554
  await this.browser.call(async () => {
2620
- const pages = await this.puppeteerBrowser.pages();
2555
+ const pages = await puppeteerBrowser.pages();
2621
2556
  await pages[0].setGeolocation({ latitude, longitude });
2622
2557
  });
2623
2558
  }
@@ -2679,255 +2614,6 @@ class WebDriver extends Helper {
2679
2614
  runInWeb(fn) {
2680
2615
  return fn();
2681
2616
  }
2682
-
2683
- /**
2684
- *
2685
- * _Note:_ Only works when devtoolsProtocol is enabled.
2686
- *
2687
- * {{> flushNetworkTraffics }}
2688
- */
2689
- flushNetworkTraffics() {
2690
- if (!this.options.automationProtocol) {
2691
- console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2692
- return;
2693
- }
2694
- this.requests = [];
2695
- }
2696
-
2697
- /**
2698
- *
2699
- * _Note:_ Only works when devtoolsProtocol is enabled.
2700
- *
2701
- * {{> stopRecordingTraffic }}
2702
- */
2703
- stopRecordingTraffic() {
2704
- if (!this.options.automationProtocol) {
2705
- console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2706
- return;
2707
- }
2708
- this.page.removeAllListeners('request');
2709
- this.recording = false;
2710
- }
2711
-
2712
- /**
2713
- *
2714
- * _Note:_ Only works when devtoolsProtocol is enabled.
2715
- *
2716
- * {{> startRecordingTraffic }}
2717
- *
2718
- */
2719
- async startRecordingTraffic() {
2720
- if (!this.options.automationProtocol) {
2721
- console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2722
- return;
2723
- }
2724
- this.flushNetworkTraffics();
2725
- this.recording = true;
2726
- this.recordedAtLeastOnce = true;
2727
-
2728
- this.page = (await this.puppeteerBrowser.pages())[0];
2729
- await this.page.setRequestInterception(true);
2730
-
2731
- this.page.on('request', (request) => {
2732
- const information = {
2733
- url: request.url(),
2734
- method: request.method(),
2735
- requestHeaders: request.headers(),
2736
- requestPostData: request.postData(),
2737
- response: request.response(),
2738
- };
2739
-
2740
- this.debugSection('REQUEST: ', JSON.stringify(information));
2741
-
2742
- if (typeof information.requestPostData === 'object') {
2743
- information.requestPostData = JSON.parse(information.requestPostData);
2744
- }
2745
- request.continue();
2746
- this.requests.push(information);
2747
- });
2748
- }
2749
-
2750
- /**
2751
- *
2752
- * _Note:_ Only works when devtoolsProtocol is enabled.
2753
- *
2754
- * {{> grabRecordedNetworkTraffics }}
2755
- */
2756
- async grabRecordedNetworkTraffics() {
2757
- if (!this.options.automationProtocol) {
2758
- console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2759
- return;
2760
- }
2761
- if (!this.recording || !this.recordedAtLeastOnce) {
2762
- throw new Error('Failure in test automation. You use "I.grabRecordedNetworkTraffics", but "I.startRecordingTraffic" was never called before.');
2763
- }
2764
-
2765
- const promises = this.requests.map(async (request) => {
2766
- const resp = await request.response;
2767
-
2768
- if (!resp) {
2769
- return {
2770
- url: '',
2771
- response: {
2772
- status: '',
2773
- statusText: '',
2774
- body: '',
2775
- },
2776
- };
2777
- }
2778
-
2779
- let body;
2780
- try {
2781
- // There's no 'body' for some requests (redirect etc...)
2782
- body = JSON.parse((await resp.body()).toString());
2783
- } catch (e) {
2784
- // only interested in JSON, not HTML responses.
2785
- }
2786
-
2787
- return {
2788
- url: resp.url(),
2789
- response: {
2790
- status: resp.status(),
2791
- statusText: resp.statusText(),
2792
- body,
2793
- },
2794
- };
2795
- });
2796
- return Promise.all(promises);
2797
- }
2798
-
2799
- /**
2800
- *
2801
- * _Note:_ Only works when devtoolsProtocol is enabled.
2802
- *
2803
- * {{> seeTraffic }}
2804
- */
2805
- async seeTraffic({
2806
- name, url, parameters, requestPostData, timeout = 10,
2807
- }) {
2808
- if (!this.options.automationProtocol) {
2809
- console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2810
- return;
2811
- }
2812
- if (!name) {
2813
- throw new Error('Missing required key "name" in object given to "I.seeTraffic".');
2814
- }
2815
-
2816
- if (!url) {
2817
- throw new Error('Missing required key "url" in object given to "I.seeTraffic".');
2818
- }
2819
-
2820
- if (!this.recording || !this.recordedAtLeastOnce) {
2821
- throw new Error('Failure in test automation. You use "I.seeTraffic", but "I.startRecordingTraffic" was never called before.');
2822
- }
2823
-
2824
- for (let i = 0; i <= timeout * 2; i++) {
2825
- const found = this._isInTraffic(url, parameters);
2826
- if (found) {
2827
- return true;
2828
- }
2829
- await new Promise((done) => {
2830
- setTimeout(done, 1000);
2831
- });
2832
- }
2833
-
2834
- // check request post data
2835
- if (requestPostData && this._isInTraffic(url)) {
2836
- const advancedTestResults = createAdvancedTestResults(url, requestPostData, this.requests);
2837
-
2838
- assert.equal(advancedTestResults, true, `Traffic named "${name}" found correct URL ${url}, BUT the post data did not match:\n ${advancedTestResults}`);
2839
- } else if (parameters && this._isInTraffic(url)) {
2840
- const advancedTestResults = createAdvancedTestResults(url, parameters, this.requests);
2841
-
2842
- assert.fail(
2843
- `Traffic named "${name}" found correct URL ${url}, BUT the query parameters did not match:\n`
2844
- + `${advancedTestResults}`,
2845
- );
2846
- } else {
2847
- assert.fail(
2848
- `Traffic named "${name}" not found in recorded traffic within ${timeout} seconds.\n`
2849
- + `Expected url: ${url}.\n`
2850
- + `Recorded traffic:\n${this._getTrafficDump()}`,
2851
- );
2852
- }
2853
- }
2854
-
2855
- /**
2856
- *
2857
- * _Note:_ Only works when devtoolsProtocol is enabled.
2858
- *
2859
- * {{> dontSeeTraffic }}
2860
- *
2861
- */
2862
- dontSeeTraffic({ name, url }) {
2863
- if (!this.options.automationProtocol) {
2864
- console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2865
- return;
2866
- }
2867
- if (!this.recordedAtLeastOnce) {
2868
- throw new Error('Failure in test automation. You use "I.dontSeeTraffic", but "I.startRecordingTraffic" was never called before.');
2869
- }
2870
-
2871
- if (!name) {
2872
- throw new Error('Missing required key "name" in object given to "I.dontSeeTraffic".');
2873
- }
2874
-
2875
- if (!url) {
2876
- throw new Error('Missing required key "url" in object given to "I.dontSeeTraffic".');
2877
- }
2878
-
2879
- if (this._isInTraffic(url)) {
2880
- assert.fail(`Traffic with name "${name}" (URL: "${url}') found, but was not expected to be found.`);
2881
- }
2882
- }
2883
-
2884
- /**
2885
- * Checks if URL with parameters is part of network traffic. Returns true or false. Internal method for this helper.
2886
- *
2887
- * @param url URL to look for.
2888
- * @param [parameters] Parameters that this URL needs to contain
2889
- * @return {boolean} Whether or not URL with parameters is part of network traffic.
2890
- * @private
2891
- */
2892
- _isInTraffic(url, parameters) {
2893
- let isInTraffic = false;
2894
- this.requests.forEach((request) => {
2895
- if (isInTraffic) {
2896
- return; // We already found traffic. Continue with next request
2897
- }
2898
-
2899
- if (!request.url.match(new RegExp(url))) {
2900
- return; // url not found in this request. continue with next request
2901
- }
2902
-
2903
- // URL has matched. Now we check the parameters
2904
-
2905
- if (parameters) {
2906
- const advancedReport = allParameterValuePairsMatchExtreme(extractQueryObjects(request.url), parameters);
2907
- if (advancedReport === true) {
2908
- isInTraffic = true;
2909
- }
2910
- } else {
2911
- isInTraffic = true;
2912
- }
2913
- });
2914
-
2915
- return isInTraffic;
2916
- }
2917
-
2918
- /**
2919
- * Returns all URLs of all network requests recorded so far during execution of test scenario.
2920
- *
2921
- * @return {string} List of URLs recorded as a string, separated by new lines after each URL
2922
- * @private
2923
- */
2924
- _getTrafficDump() {
2925
- let dumpedTraffic = '';
2926
- this.requests.forEach((request) => {
2927
- dumpedTraffic += `${request.method} - ${request.url}\n`;
2928
- });
2929
- return dumpedTraffic;
2930
- }
2931
2617
  }
2932
2618
 
2933
2619
  async function proceedSee(assertType, text, context, strict = false) {
package/lib/index.js CHANGED
@@ -39,5 +39,8 @@ module.exports = {
39
39
  /** @type {typeof CodeceptJS.Locator} */
40
40
  locator: require('./locator'),
41
41
 
42
+ heal: require('./heal'),
43
+ ai: require('./ai'),
44
+
42
45
  Workers: require('./workers'),
43
46
  };
@@ -67,7 +67,6 @@ module.exports = function () {
67
67
  });
68
68
 
69
69
  event.dispatcher.on(event.step.started, (step) => {
70
- if (store.debugMode) return;
71
70
  step.startedAt = +new Date();
72
71
  step.test = currentTest;
73
72
  if (currentHook && Array.isArray(currentHook.steps)) {
@@ -78,7 +77,6 @@ module.exports = function () {
78
77
  });
79
78
 
80
79
  event.dispatcher.on(event.step.finished, (step) => {
81
- if (store.debugMode) return;
82
80
  step.finishedAt = +new Date();
83
81
  if (step.startedAt) step.duration = step.finishedAt - step.startedAt;
84
82
  debug(`Step '${step}' finished; Duration: ${step.duration || 0}ms`);
package/lib/locator.js CHANGED
@@ -1,4 +1,4 @@
1
- let cssToXPath;
1
+ const cssToXPath = require('csstoxpath');
2
2
  const { sprintf } = require('sprintf-js');
3
3
 
4
4
  const { xpathLocator } = require('./utils');
@@ -162,17 +162,8 @@ class Locator {
162
162
  * @returns {string}
163
163
  */
164
164
  toXPath(pseudoSelector = '') {
165
- const locator = `${this.value}${pseudoSelector}`;
166
- const limitation = [':nth-of-type', ':first-of-type', ':last-of-type', ':nth-last-child', ':nth-last-of-type', ':checked', ':disabled', ':enabled', ':required', ':lang', ':nth-child'];
167
-
168
- if (limitation.some(item => locator.includes(item))) {
169
- cssToXPath = require('css-to-xpath');
170
- } else {
171
- cssToXPath = require('csstoxpath');
172
- }
173
-
174
165
  if (this.isXPath()) return this.value;
175
- if (this.isCSS()) return cssToXPath(locator);
166
+ if (this.isCSS()) return cssToXPath(`${this.value}${pseudoSelector}`);
176
167
 
177
168
  throw new Error('Can\'t be converted to XPath');
178
169
  }
@@ -259,7 +250,7 @@ class Locator {
259
250
  */
260
251
  withText(text) {
261
252
  text = xpathLocator.literal(text);
262
- const xpath = sprintf('%s[%s]', this.toXPath(), `contains(., ${text})`);
253
+ const xpath = this.toXPath(`:text-contains-case(${text})`);
263
254
  return new Locator({ xpath });
264
255
  }
265
256
 
@@ -270,7 +261,7 @@ class Locator {
270
261
  */
271
262
  withTextEquals(text) {
272
263
  text = xpathLocator.literal(text);
273
- const xpath = sprintf('%s[%s]', this.toXPath(), `.= ${text}`);
264
+ const xpath = this.toXPath(`:text-case(${text})`);
274
265
  return new Locator({ xpath });
275
266
  }
276
267