codeceptjs 3.5.15 → 3.6.0

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.
@@ -36,13 +36,14 @@ const ElementNotFound = require('./errors/ElementNotFound');
36
36
  const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused');
37
37
  const Popup = require('./extras/Popup');
38
38
  const Console = require('./extras/Console');
39
- const findReact = require('./extras/React');
40
39
  const { highlightElement } = require('./scripts/highlightElement');
41
40
  const { blurElement } = require('./scripts/blurElement');
42
- const { focusElement } = require('./scripts/focusElement');
43
41
  const {
44
42
  dontSeeElementError, seeElementError, dontSeeElementInDOMError, seeElementInDOMError,
45
43
  } = require('./errors/ElementAssertion');
44
+ const {
45
+ dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics,
46
+ } = require('./network/actions');
46
47
 
47
48
  let puppeteer;
48
49
  let perfTiming;
@@ -226,6 +227,17 @@ class Puppeteer extends Helper {
226
227
  this.sessionPages = {};
227
228
  this.activeSessionName = '';
228
229
 
230
+ // for network stuff
231
+ this.requests = [];
232
+ this.recording = false;
233
+ this.recordedAtLeastOnce = false;
234
+
235
+ // for websocket messages
236
+ this.webSocketMessages = [];
237
+ this.recordingWebSocketMessages = false;
238
+ this.recordedWebSocketMessagesAtLeastOnce = false;
239
+ this.cdpSession = null;
240
+
229
241
  // override defaults with config
230
242
  this._setConfig(config);
231
243
  }
@@ -2078,7 +2090,6 @@ class Puppeteer extends Helper {
2078
2090
  async waitNumberOfVisibleElements(locator, num, sec) {
2079
2091
  const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2080
2092
  locator = new Locator(locator, 'css');
2081
- await this.context;
2082
2093
  let waiter;
2083
2094
  const context = await this._getContext();
2084
2095
  if (locator.isCSS()) {
@@ -2459,6 +2470,214 @@ class Puppeteer extends Helper {
2459
2470
  if (prop) return rect[prop];
2460
2471
  return rect;
2461
2472
  }
2473
+
2474
+ /**
2475
+ * Mocks network request using [`Request Interception`](https://pptr.dev/next/guides/request-interception)
2476
+ *
2477
+ * ```js
2478
+ * I.mockRoute(/(\.png$)|(\.jpg$)/, route => route.abort());
2479
+ * ```
2480
+ * This method allows intercepting and mocking requests & responses. [Learn more about it](https://pptr.dev/next/guides/request-interception)
2481
+ *
2482
+ * @param {string|RegExp} [url] URL, regex or pattern for to match URL
2483
+ * @param {function} [handler] a function to process request
2484
+ */
2485
+ async mockRoute(url, handler) {
2486
+ await this.page.setRequestInterception(true);
2487
+
2488
+ this.page.on('request', interceptedRequest => {
2489
+ if (interceptedRequest.url().match(url)) {
2490
+ // @ts-ignore
2491
+ handler(interceptedRequest);
2492
+ } else {
2493
+ interceptedRequest.continue();
2494
+ }
2495
+ });
2496
+ }
2497
+
2498
+ /**
2499
+ * Stops network mocking created by `mockRoute`.
2500
+ *
2501
+ * ```js
2502
+ * I.stopMockingRoute(/(\.png$)|(\.jpg$)/);
2503
+ * ```
2504
+ *
2505
+ * @param {string|RegExp} [url] URL, regex or pattern for to match URL
2506
+ */
2507
+ async stopMockingRoute(url) {
2508
+ await this.page.setRequestInterception(true);
2509
+
2510
+ this.page.off('request');
2511
+
2512
+ // Resume normal request handling for the given URL
2513
+ this.page.on('request', interceptedRequest => {
2514
+ if (interceptedRequest.url().includes(url)) {
2515
+ interceptedRequest.continue();
2516
+ } else {
2517
+ interceptedRequest.continue();
2518
+ }
2519
+ });
2520
+ }
2521
+
2522
+ /**
2523
+ *
2524
+ * {{> flushNetworkTraffics }}
2525
+ */
2526
+ flushNetworkTraffics() {
2527
+ flushNetworkTraffics.call(this);
2528
+ }
2529
+
2530
+ /**
2531
+ *
2532
+ * {{> stopRecordingTraffic }}
2533
+ */
2534
+ stopRecordingTraffic() {
2535
+ stopRecordingTraffic.call(this);
2536
+ }
2537
+
2538
+ /**
2539
+ * {{> startRecordingTraffic }}
2540
+ *
2541
+ */
2542
+ async startRecordingTraffic() {
2543
+ this.flushNetworkTraffics();
2544
+ this.recording = true;
2545
+ this.recordedAtLeastOnce = true;
2546
+
2547
+ await this.page.setRequestInterception(true);
2548
+
2549
+ this.page.on('request', (request) => {
2550
+ const information = {
2551
+ url: request.url(),
2552
+ method: request.method(),
2553
+ requestHeaders: request.headers(),
2554
+ requestPostData: request.postData(),
2555
+ response: request.response(),
2556
+ };
2557
+
2558
+ this.debugSection('REQUEST: ', JSON.stringify(information));
2559
+
2560
+ if (typeof information.requestPostData === 'object') {
2561
+ information.requestPostData = JSON.parse(information.requestPostData);
2562
+ }
2563
+ request.continue();
2564
+ this.requests.push(information);
2565
+ });
2566
+ }
2567
+
2568
+ /**
2569
+ *
2570
+ * {{> grabRecordedNetworkTraffics }}
2571
+ */
2572
+ async grabRecordedNetworkTraffics() {
2573
+ return grabRecordedNetworkTraffics.call(this);
2574
+ }
2575
+
2576
+ /**
2577
+ *
2578
+ * {{> seeTraffic }}
2579
+ */
2580
+ async seeTraffic({
2581
+ name, url, parameters, requestPostData, timeout = 10,
2582
+ }) {
2583
+ await seeTraffic.call(this, ...arguments);
2584
+ }
2585
+
2586
+ /**
2587
+ *
2588
+ * {{> dontSeeTraffic }}
2589
+ *
2590
+ */
2591
+ dontSeeTraffic({ name, url }) {
2592
+ dontSeeTraffic.call(this, ...arguments);
2593
+ }
2594
+
2595
+ async getNewCDPSession() {
2596
+ const client = await this.page.target().createCDPSession();
2597
+ return client;
2598
+ }
2599
+
2600
+ /**
2601
+ * {{> startRecordingWebSocketMessages }}
2602
+ */
2603
+ async startRecordingWebSocketMessages() {
2604
+ this.flushWebSocketMessages();
2605
+ this.recordingWebSocketMessages = true;
2606
+ this.recordedWebSocketMessagesAtLeastOnce = true;
2607
+
2608
+ this.cdpSession = await this.getNewCDPSession();
2609
+ await this.cdpSession.send('Network.enable');
2610
+ await this.cdpSession.send('Page.enable');
2611
+
2612
+ this.cdpSession.on(
2613
+ 'Network.webSocketFrameReceived',
2614
+ (payload) => {
2615
+ this._logWebsocketMessages(this._getWebSocketLog('RECEIVED', payload));
2616
+ },
2617
+ );
2618
+
2619
+ this.cdpSession.on(
2620
+ 'Network.webSocketFrameSent',
2621
+ (payload) => {
2622
+ this._logWebsocketMessages(this._getWebSocketLog('SENT', payload));
2623
+ },
2624
+ );
2625
+
2626
+ this.cdpSession.on(
2627
+ 'Network.webSocketFrameError',
2628
+ (payload) => {
2629
+ this._logWebsocketMessages(this._getWebSocketLog('ERROR', payload));
2630
+ },
2631
+ );
2632
+ }
2633
+
2634
+ /**
2635
+ * {{> stopRecordingWebSocketMessages }}
2636
+ */
2637
+ async stopRecordingWebSocketMessages() {
2638
+ await this.cdpSession.send('Network.disable');
2639
+ await this.cdpSession.send('Page.disable');
2640
+ this.page.removeAllListeners('Network');
2641
+ this.recordingWebSocketMessages = false;
2642
+ }
2643
+
2644
+ /**
2645
+ * Grab the recording WS messages
2646
+ *
2647
+ * @return { Array<any>|undefined }
2648
+ *
2649
+ */
2650
+ grabWebSocketMessages() {
2651
+ if (!this.recordingWebSocketMessages) {
2652
+ if (!this.recordedWebSocketMessagesAtLeastOnce) {
2653
+ throw new Error('Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.');
2654
+ }
2655
+ }
2656
+ return this.webSocketMessages;
2657
+ }
2658
+
2659
+ /**
2660
+ * Resets all recorded WS messages.
2661
+ */
2662
+ flushWebSocketMessages() {
2663
+ this.webSocketMessages = [];
2664
+ }
2665
+
2666
+ _getWebSocketMessage(payload) {
2667
+ if (payload.errorMessage) {
2668
+ return payload.errorMessage;
2669
+ }
2670
+
2671
+ return payload.response.payloadData;
2672
+ }
2673
+
2674
+ _getWebSocketLog(prefix, payload) {
2675
+ return `${prefix} ID: ${payload.requestId} TIMESTAMP: ${payload.timestamp} (${new Date().toISOString()})\n\n${this._getWebSocketMessage(payload)}\n\n`;
2676
+ }
2677
+
2678
+ _logWebsocketMessages(message) {
2679
+ this.webSocketMessages += message;
2680
+ }
2462
2681
  }
2463
2682
 
2464
2683
  module.exports = Puppeteer;
@@ -2,10 +2,8 @@ let webdriverio;
2
2
 
3
3
  const assert = require('assert');
4
4
  const path = require('path');
5
- const fs = require('fs');
6
5
 
7
6
  const Helper = require('@codeceptjs/helper');
8
- const crypto = require('crypto');
9
7
  const promiseRetry = require('promise-retry');
10
8
  const stringIncludes = require('../assert/include').includes;
11
9
  const { urlEquals, equals } = require('../assert/equal');
@@ -30,13 +28,14 @@ const ElementNotFound = require('./errors/ElementNotFound');
30
28
  const ConnectionRefused = require('./errors/ConnectionRefused');
31
29
  const Locator = require('../locator');
32
30
  const { highlightElement } = require('./scripts/highlightElement');
33
- const store = require('../store');
34
31
  const { focusElement } = require('./scripts/focusElement');
35
32
  const { blurElement } = require('./scripts/blurElement');
36
33
  const {
37
34
  dontSeeElementError, seeElementError, seeElementInDOMError, dontSeeElementInDOMError,
38
35
  } = require('./errors/ElementAssertion');
39
- const { allParameterValuePairsMatchExtreme, extractQueryObjects, createAdvancedTestResults } = require('./networkTraffics/utils');
36
+ const {
37
+ dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics,
38
+ } = require('./network/actions');
40
39
 
41
40
  const SHADOW = 'shadow';
42
41
  const webRoot = 'body';
@@ -2758,42 +2757,7 @@ class WebDriver extends Helper {
2758
2757
  console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2759
2758
  return;
2760
2759
  }
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);
2760
+ return grabRecordedNetworkTraffics.call(this);
2797
2761
  }
2798
2762
 
2799
2763
  /**
@@ -2809,47 +2773,7 @@ class WebDriver extends Helper {
2809
2773
  console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2810
2774
  return;
2811
2775
  }
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
- }
2776
+ await seeTraffic.call(this, ...arguments);
2853
2777
  }
2854
2778
 
2855
2779
  /**
@@ -2864,69 +2788,7 @@ class WebDriver extends Helper {
2864
2788
  console.log('* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration');
2865
2789
  return;
2866
2790
  }
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;
2791
+ dontSeeTraffic.call(this, ...arguments);
2930
2792
  }
2931
2793
  }
2932
2794
 
@@ -20,6 +20,11 @@ async function findVue(matcher, locator) {
20
20
  return matcher.locator(_locator).all();
21
21
  }
22
22
 
23
+ async function findByPlaywrightLocator(matcher, locator) {
24
+ if (locator && locator.toString().includes(process.env.testIdAttribute)) return matcher.getByTestId(locator.pw.value.split('=')[1]);
25
+ return matcher.locator(locator.pw).all();
26
+ }
27
+
23
28
  function propBuilder(props) {
24
29
  let _props = '';
25
30
 
@@ -35,4 +40,4 @@ function propBuilder(props) {
35
40
  return _props;
36
41
  }
37
42
 
38
- module.exports = { findReact, findVue };
43
+ module.exports = { findReact, findVue, findByPlaywrightLocator };
@@ -0,0 +1,123 @@
1
+ const assert = require('assert');
2
+ const { isInTraffic, createAdvancedTestResults, getTrafficDump } = require('./utils');
3
+
4
+ function dontSeeTraffic({ name, url }) {
5
+ if (!this.recordedAtLeastOnce) {
6
+ throw new Error('Failure in test automation. You use "I.dontSeeTraffic", but "I.startRecordingTraffic" was never called before.');
7
+ }
8
+
9
+ if (!name) {
10
+ throw new Error('Missing required key "name" in object given to "I.dontSeeTraffic".');
11
+ }
12
+
13
+ if (!url) {
14
+ throw new Error('Missing required key "url" in object given to "I.dontSeeTraffic".');
15
+ }
16
+
17
+ if (isInTraffic.call(this, url)) {
18
+ assert.fail(`Traffic with name "${name}" (URL: "${url}') found, but was not expected to be found.`);
19
+ }
20
+ }
21
+
22
+ async function seeTraffic({
23
+ name, url, parameters, requestPostData, timeout = 10,
24
+ }) {
25
+ if (!name) {
26
+ throw new Error('Missing required key "name" in object given to "I.seeTraffic".');
27
+ }
28
+
29
+ if (!url) {
30
+ throw new Error('Missing required key "url" in object given to "I.seeTraffic".');
31
+ }
32
+
33
+ if (!this.recording || !this.recordedAtLeastOnce) {
34
+ throw new Error('Failure in test automation. You use "I.seeTraffic", but "I.startRecordingTraffic" was never called before.');
35
+ }
36
+
37
+ for (let i = 0; i <= timeout * 2; i++) {
38
+ const found = isInTraffic.call(this, url, parameters);
39
+ if (found) {
40
+ return true;
41
+ }
42
+ await new Promise((done) => {
43
+ setTimeout(done, 1000);
44
+ });
45
+ }
46
+
47
+ // check request post data
48
+ if (requestPostData && isInTraffic.call(this, url)) {
49
+ const advancedTestResults = createAdvancedTestResults(url, requestPostData, this.requests);
50
+
51
+ assert.equal(advancedTestResults, true, `Traffic named "${name}" found correct URL ${url}, BUT the post data did not match:\n ${advancedTestResults}`);
52
+ } else if (parameters && isInTraffic.call(this, url)) {
53
+ const advancedTestResults = createAdvancedTestResults(url, parameters, this.requests);
54
+
55
+ assert.fail(
56
+ `Traffic named "${name}" found correct URL ${url}, BUT the query parameters did not match:\n`
57
+ + `${advancedTestResults}`,
58
+ );
59
+ } else {
60
+ assert.fail(
61
+ `Traffic named "${name}" not found in recorded traffic within ${timeout} seconds.\n`
62
+ + `Expected url: ${url}.\n`
63
+ + `Recorded traffic:\n${getTrafficDump.call(this)}`,
64
+ );
65
+ }
66
+ }
67
+
68
+ async function grabRecordedNetworkTraffics() {
69
+ if (!this.recording || !this.recordedAtLeastOnce) {
70
+ throw new Error('Failure in test automation. You use "I.grabRecordedNetworkTraffics", but "I.startRecordingTraffic" was never called before.');
71
+ }
72
+
73
+ const promises = this.requests.map(async (request) => {
74
+ const resp = await request.response;
75
+
76
+ if (!resp) {
77
+ return {
78
+ url: '',
79
+ response: {
80
+ status: '',
81
+ statusText: '',
82
+ body: '',
83
+ },
84
+ };
85
+ }
86
+
87
+ let body;
88
+ try {
89
+ // There's no 'body' for some requests (redirect etc...)
90
+ body = JSON.parse((await resp.body()).toString());
91
+ } catch (e) {
92
+ // only interested in JSON, not HTML responses.
93
+ }
94
+
95
+ return {
96
+ url: resp.url(),
97
+ response: {
98
+ status: resp.status(),
99
+ statusText: resp.statusText(),
100
+ body,
101
+ },
102
+ };
103
+ });
104
+ return Promise.all(promises);
105
+ }
106
+
107
+ function stopRecordingTraffic() {
108
+ // @ts-ignore
109
+ this.page.removeAllListeners('request');
110
+ this.recording = false;
111
+ }
112
+
113
+ function flushNetworkTraffics() {
114
+ this.requests = [];
115
+ }
116
+
117
+ module.exports = {
118
+ dontSeeTraffic,
119
+ seeTraffic,
120
+ grabRecordedNetworkTraffics,
121
+ stopRecordingTraffic,
122
+ flushNetworkTraffics,
123
+ };
@@ -129,9 +129,59 @@ const allRequestPostDataValuePairsMatchExtreme = (RequestPostDataObject, advance
129
129
  return success ? true : littleReport;
130
130
  };
131
131
 
132
+ /**
133
+ * Returns all URLs of all network requests recorded so far during execution of test scenario.
134
+ *
135
+ * @return {string} List of URLs recorded as a string, separated by new lines after each URL
136
+ * @private
137
+ */
138
+ function getTrafficDump() {
139
+ let dumpedTraffic = '';
140
+ this.requests.forEach((request) => {
141
+ dumpedTraffic += `${request.method} - ${request.url}\n`;
142
+ });
143
+ return dumpedTraffic;
144
+ }
145
+
146
+ /**
147
+ * Checks if URL with parameters is part of network traffic. Returns true or false. Internal method for this helper.
148
+ *
149
+ * @param url URL to look for.
150
+ * @param [parameters] Parameters that this URL needs to contain
151
+ * @return {boolean} Whether or not URL with parameters is part of network traffic.
152
+ * @private
153
+ */
154
+ function isInTraffic(url, parameters) {
155
+ let isInTraffic = false;
156
+ this.requests.forEach((request) => {
157
+ if (isInTraffic) {
158
+ return; // We already found traffic. Continue with next request
159
+ }
160
+
161
+ if (!request.url.match(new RegExp(url))) {
162
+ return; // url not found in this request. continue with next request
163
+ }
164
+
165
+ // URL has matched. Now we check the parameters
166
+
167
+ if (parameters) {
168
+ const advancedReport = allParameterValuePairsMatchExtreme(extractQueryObjects(request.url), parameters);
169
+ if (advancedReport === true) {
170
+ isInTraffic = true;
171
+ }
172
+ } else {
173
+ isInTraffic = true;
174
+ }
175
+ });
176
+
177
+ return isInTraffic;
178
+ }
179
+
132
180
  module.exports = {
133
181
  createAdvancedTestResults,
134
182
  extractQueryObjects,
135
183
  allParameterValuePairsMatchExtreme,
136
184
  allRequestPostDataValuePairsMatchExtreme,
185
+ getTrafficDump,
186
+ isInTraffic,
137
187
  };
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`);