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.
package/CHANGELOG.md CHANGED
@@ -1,10 +1,36 @@
1
+ ## 3.0.7
2
+
3
+ Documentation fixes:
4
+ * Remove broken link from `Nightmare helper`. See #2860 by @Arhell
5
+ * Fixed broken links in `playwright.md`. See #2848 by @johnhoodjr
6
+ * Fix mocha-multi config example. See #2881 by @rimesc
7
+ * Fix small errors in email documentation file. See #2884 by @mkrtchian
8
+ * Improve documentation for `Sharing Data Between Workers` section. See #2891 by @ngraf
9
+
10
+ Features:
11
+ * [WebDriver] Shadow DOM Support for `Webdriver`. See #2741 by @gkushang
12
+ * [Release management] Introduce the versioning automatically, it follows the semantics versioning. See #2883 by @PeterNgTr
13
+ * Adding opts into `Scenario.skip` that it would be useful for building reports. See #2867 by @AlexKo4
14
+ * Added support for attaching screenshots to [cucumberJsonReporter](https://github.com/ktryniszewski-mdsol/codeceptjs-cucumber-json-reporter) See #2888 by @fijijavis
15
+ * Supported config file for `codeceptjs shell` command. See #2895 by @PeterNgTr:
16
+
17
+ ```
18
+ npx codeceptjs shell -c foo.conf.js
19
+ ```
20
+
21
+ Bug fixes:
22
+ * [GraphQL] Use a helper-specific instance of Axios to avoid contaminating global defaults. See #2868 by @vanvoljg
23
+ * A default system color is used when passing non supported system color when using I.say(). See #2874 by @PeterNgTr
24
+ * [Playwright] Avoid the timout due to calling the click on invisible elements. See #2875 by cbayer97
25
+
26
+
1
27
  ## 3.0.6
2
28
 
3
- * [Playwright] Added `electron` as a browser to config. See #2834 by @cbayer97
29
+ * [Playwright] Added `electron` as a browser to config. See #2834 by @cbayer97
4
30
  * [Playwright] Implemented `launchPersistentContext` to be able to launch persistent remote browsers. See #2817 by @brunoqueiros. Fixes #2376.
5
31
  * Fixed printing logs and stack traces for `run-workers`. See #2857 by @haveac1gar. Fixes #2621, #2852
6
- * Emit custom messages from worker to the main thread. See #2824 by @jccguimaraes
7
- * Improved workers processes output. See #2804 by @drfiresign
32
+ * Emit custom messages from worker to the main thread. See #2824 by @jccguimaraes
33
+ * Improved workers processes output. See #2804 by @drfiresign
8
34
  * BDD. Added ability to use an array of feature files inside config in `gherkin.features`. See #2814 by @jbergeronjr
9
35
 
10
36
  ```js
@@ -13,8 +39,8 @@
13
39
  "./features/api_features/*.feature"
14
40
  ],
15
41
  ```
16
- * Added `getQueueId` to reporter to rerun a specific promise. See #2837 by @jonatask
17
- * **Added `fakerTransform` plugin** to use faker data in Gherkin scenarios. See #2854 by @adrielcodeco
42
+ * Added `getQueueId` to reporter to rerun a specific promise. See #2837 by @jonatask
43
+ * **Added `fakerTransform` plugin** to use faker data in Gherkin scenarios. See #2854 by @adrielcodeco
18
44
 
19
45
  ```feature
20
46
  Scenario Outline: ...
@@ -26,7 +52,7 @@ Scenario Outline: ...
26
52
  | productName | customer | email | anythingMore |
27
53
  | {{commerce.product}} | Dr. {{name.findName}} | {{internet.email}} | staticData |
28
54
  ```
29
- * [REST] Use class instance of axios, not the global instance, to avoid contaminating global configuration. #2846 by @vanvoljg
55
+ * [REST] Use class instance of axios, not the global instance, to avoid contaminating global configuration. #2846 by @vanvoljg
30
56
  * [Appium] Added `tunnelIdentifier` config option to provide tunnel for SauceLabs. See #2832 by @gurjeetbains
31
57
 
32
58
  ## 3.0.5
@@ -34,9 +60,9 @@ Scenario Outline: ...
34
60
 
35
61
  Features:
36
62
 
37
- * **[Official Docker image for CodeceptJS v3](https://hub.docker.com/r/codeceptjs/codeceptjs)**. New Docker image is based on official Playwright image and supports Playwright, Puppeteer, WebDriver engines. Thanks @VikentyShevyrin
63
+ * **[Official Docker image for CodeceptJS v3](https://hub.docker.com/r/codeceptjs/codeceptjs)**. New Docker image is based on official Playwright image and supports Playwright, Puppeteer, WebDriver engines. Thanks @VikentyShevyrin
38
64
  * Better support for Typescript `codecept.conf.ts` configuration files. See #2750 by @elaichenkov
39
- * Propagate more events for custom parallel script. See #2796 by @jccguimaraes
65
+ * Propagate more events for custom parallel script. See #2796 by @jccguimaraes
40
66
  * [mocha-junit-reporter] Now supports attachments, see documentation for details. See #2675 by @Shard
41
67
  * CustomLocators interface for TypeScript to extend from LocatorOrString. See #2798 by @danielrentz
42
68
  * [REST] Mask sensitive data from log messages.
package/bin/codecept.js CHANGED
@@ -27,6 +27,7 @@ program.command('shell [path]')
27
27
  .description('Interactive shell')
28
28
  .option('--verbose', 'output internal logging information')
29
29
  .option('--profile [value]', 'configuration profile to be used')
30
+ .option('-c, --config [file]', 'configuration file to be used')
30
31
  .action(require('../lib/command/interactive'));
31
32
 
32
33
  program.command('list [path]')
@@ -183,6 +183,7 @@ class Appium extends Webdriver {
183
183
  config.capabilities.browserName = config.browser || config.capabilities.browserName;
184
184
  config.capabilities.app = config.app || config.capabilities.app;
185
185
  config.capabilities.platformName = config.platform || config.capabilities.platformName;
186
+ config.capabilities.tunnelIdentifier = config.tunnelIdentifier || config.capabilities.tunnelIdentifier; // Adding the code to connect to sauce labs via sauce tunnel
186
187
  config.waitForTimeout /= 1000; // convert to seconds
187
188
 
188
189
  // [CodeceptJS compatible] transform host to hostname
@@ -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(
@@ -35,9 +35,10 @@ let defaultSelectorEnginesInitialized = false;
35
35
 
36
36
  const popupStore = new Popup();
37
37
  const consoleLogStore = new Console();
38
- const availableBrowsers = ['chromium', 'webkit', 'firefox'];
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
  *
@@ -58,7 +59,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
58
59
  * This helper should be configured in codecept.json or codecept.conf.js
59
60
  *
60
61
  * * `url`: base url of website to be tested
61
- * * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`. Default: chromium.
62
+ * * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
62
63
  * * `show`: (optional, default: false) - show browser window.
63
64
  * * `restart`: (optional, default: true) - restart browser between tests.
64
65
  * * `disableScreenshots`: (optional, default: false) - don't save screenshot on failure.
@@ -77,6 +78,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
77
78
  * * `userAgent`: (optional) user-agent string.
78
79
  * * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
79
80
  * * `chromium`: (optional) pass additional chromium options
81
+ * * `electron`: (optional) pass additional electron options
80
82
  *
81
83
  * #### Example #1: Wait for 0 network connections.
82
84
  *
@@ -121,7 +123,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
121
123
  * }
122
124
  * ```
123
125
  *
124
- * #### Example #4: Connect to remote browser by specifying [websocket endpoint](https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target)
126
+ * #### Example #4: Connect to remote browser by specifying [websocket endpoint](https://playwright.dev/docs/api/class-browsertype#browsertypeconnectparams)
125
127
  *
126
128
  * ```js
127
129
  * {
@@ -129,7 +131,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
129
131
  * Playwright: {
130
132
  * url: "http://localhost",
131
133
  * chromium: {
132
- * browserWSEndpoint: "ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a"
134
+ * browserWSEndpoint: { wsEndpoint: 'ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a' }
133
135
  * }
134
136
  * }
135
137
  * }
@@ -147,6 +149,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
147
149
  * url: "http://localhost",
148
150
  * show: true // headless mode not supported for extensions
149
151
  * chromium: {
152
+ * userDataDir: '/tmp/playwright-tmp', // necessary to launch the browser in normal mode instead of incognito,
150
153
  * args: [
151
154
  * `--disable-extensions-except=${pathToExtension}`,
152
155
  * `--load-extension=${pathToExtension}`
@@ -206,6 +209,8 @@ class Playwright extends Helper {
206
209
  this.isAuthenticated = false;
207
210
  this.sessionPages = {};
208
211
  this.activeSessionName = '';
212
+ this.isElectron = false;
213
+ this.electronSessions = [];
209
214
 
210
215
  // override defaults with config
211
216
  this._setConfig(config);
@@ -257,6 +262,8 @@ class Playwright extends Helper {
257
262
  ...this._getOptionsForBrowser(config),
258
263
  };
259
264
  this.isRemoteBrowser = !!this.playwrightOptions.browserWSEndpoint;
265
+ this.isElectron = this.options.browser === 'electron';
266
+ this.userDataDir = this.playwrightOptions.userDataDir;
260
267
  popupStore.defaultAction = this.options.defaultPopupAction;
261
268
  }
262
269
 
@@ -268,7 +275,7 @@ class Playwright extends Helper {
268
275
  },
269
276
  {
270
277
  name: 'browser',
271
- message: 'Browser in which testing will be performed. Possible options: chromium, firefox or webkit',
278
+ message: 'Browser in which testing will be performed. Possible options: chromium, firefox, webkit or electron',
272
279
  default: 'chromium',
273
280
  },
274
281
  ];
@@ -320,11 +327,21 @@ class Playwright extends Helper {
320
327
  async _after() {
321
328
  if (!this.isRunning) return;
322
329
 
330
+ if (this.isElectron) {
331
+ this.browser.close();
332
+ this.electronSessions.forEach(session => session.close());
333
+ return;
334
+ }
335
+
323
336
  // close other sessions
324
- const contexts = await this.browser.contexts();
325
- contexts.shift();
337
+ try {
338
+ const contexts = await this.browser.contexts();
339
+ contexts.shift();
326
340
 
327
- await Promise.all(contexts.map(c => c.close()));
341
+ await Promise.all(contexts.map(c => c.close()));
342
+ } catch (e) {
343
+ console.log(e);
344
+ }
328
345
 
329
346
  if (this.options.restart) {
330
347
  this.isRunning = false;
@@ -371,12 +388,22 @@ class Playwright extends Helper {
371
388
  this.debugSection('New Context', config ? JSON.stringify(config) : 'opened');
372
389
  this.activeSessionName = sessionName;
373
390
 
374
- const bc = await this.browser.newContext(config);
375
- const page = await bc.newPage();
391
+ let browserContext;
392
+ let page;
393
+ if (this.isElectron) {
394
+ const browser = await playwright._electron.launch(this.playwrightOptions);
395
+ this.electronSessions.push(browser);
396
+ browserContext = browser.context();
397
+ page = await browser.firstWindow();
398
+ } else {
399
+ browserContext = await this.browser.newContext(config);
400
+ page = await browserContext.newPage();
401
+ }
402
+
376
403
  targetCreatedHandler.call(this, page);
377
404
  this._setPage(page);
378
405
  // Create a new page inside context.
379
- return bc;
406
+ return browserContext;
380
407
  },
381
408
  stop: async () => {
382
409
  // is closed by _after
@@ -496,6 +523,7 @@ class Playwright extends Helper {
496
523
  if (!page) return;
497
524
  page.setDefaultNavigationTimeout(this.options.getPageTimeout);
498
525
  this.context = await this.page;
526
+ this.contextLocator = null;
499
527
  if (this.config.browser === 'chrome') {
500
528
  await page.bringToFront();
501
529
  }
@@ -554,15 +582,19 @@ class Playwright extends Helper {
554
582
  }
555
583
 
556
584
  async _startBrowser() {
557
- if (this.isRemoteBrowser) {
585
+ if (this.isElectron) {
586
+ this.browser = await playwright._electron.launch(this.playwrightOptions);
587
+ } else if (this.isRemoteBrowser) {
558
588
  try {
559
- this.browser = await playwright[this.options.browser].connect(this.playwrightOptions);
589
+ this.browser = await playwright[this.options.browser].connect(this.playwrightOptions.browserWSEndpoint);
560
590
  } catch (err) {
561
591
  if (err.toString().indexOf('ECONNREFUSED')) {
562
592
  throw new RemoteBrowserConnectionRefused(err);
563
593
  }
564
594
  throw err;
565
595
  }
596
+ } else if (this.userDataDir) {
597
+ this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions);
566
598
  } else {
567
599
  this.browser = await playwright[this.options.browser].launch(this.playwrightOptions);
568
600
  }
@@ -571,11 +603,22 @@ class Playwright extends Helper {
571
603
  this.browser.on('targetchanged', (target) => {
572
604
  this.debugSection('Url', target.url());
573
605
  });
574
- this.browserContext = await this.browser.newContext({ ignoreHTTPSErrors: this.options.ignoreHTTPSErrors, acceptDownloads: true, ...this.options.emulate });// Adding the HTTPSError ignore in the context so that we can ignore those errors
575
606
 
576
- const existingPages = await this.browserContext.pages();
607
+ if (this.isElectron) {
608
+ this.browserContext = this.browser.context();
609
+ } else if (this.userDataDir) {
610
+ this.browserContext = this.browser;
611
+ } else {
612
+ this.browserContext = await this.browser.newContext({ ignoreHTTPSErrors: this.options.ignoreHTTPSErrors, acceptDownloads: true, ...this.options.emulate });// Adding the HTTPSError ignore in the context so that we can ignore those errors
613
+ }
577
614
 
578
- const mainPage = existingPages[0] || await this.browserContext.newPage();
615
+ let mainPage;
616
+ if (this.isElectron) {
617
+ mainPage = await this.browser.firstWindow();
618
+ } else {
619
+ const existingPages = await this.browserContext.pages();
620
+ mainPage = existingPages[0] || await this.browserContext.newPage();
621
+ }
579
622
  targetCreatedHandler.call(this, mainPage);
580
623
 
581
624
  await this._setPage(mainPage);
@@ -584,6 +627,10 @@ class Playwright extends Helper {
584
627
  this.isRunning = true;
585
628
  }
586
629
 
630
+ _getType() {
631
+ return this.browser._type;
632
+ }
633
+
587
634
  async _stopBrowser() {
588
635
  this.withinLocator = null;
589
636
  this._setPage(null);
@@ -618,6 +665,7 @@ class Playwright extends Helper {
618
665
  const els = await this._locate(locator);
619
666
  assertElementExists(els, locator);
620
667
  this.context = els[0];
668
+ this.contextLocator = locator;
621
669
 
622
670
  this.withinLocator = new Locator(locator);
623
671
  }
@@ -625,6 +673,7 @@ class Playwright extends Helper {
625
673
  async _withinEnd() {
626
674
  this.withinLocator = null;
627
675
  this.context = await this.page;
676
+ this.contextLocator = null;
628
677
  }
629
678
 
630
679
  _extractDataFromPerformanceTiming(timing, ...dataNames) {
@@ -651,6 +700,9 @@ class Playwright extends Helper {
651
700
  * @param {string} url url path or global url.
652
701
  */
653
702
  async amOnPage(url) {
703
+ if (this.isElectron) {
704
+ throw new Error('Cannot open pages inside an Electron container');
705
+ }
654
706
  if (!(/^\w+\:\/\//.test(url))) {
655
707
  url = this.options.url + url;
656
708
  }
@@ -984,6 +1036,9 @@ class Playwright extends Helper {
984
1036
  * @param {number} [num=1]
985
1037
  */
986
1038
  async switchToNextTab(num = 1) {
1039
+ if (this.isElectron) {
1040
+ throw new Error('Cannot switch tabs inside an Electron container');
1041
+ }
987
1042
  const pages = await this.browserContext.pages();
988
1043
 
989
1044
  const index = pages.indexOf(this.page);
@@ -1007,6 +1062,9 @@ class Playwright extends Helper {
1007
1062
  * @param {number} [num=1]
1008
1063
  */
1009
1064
  async switchToPreviousTab(num = 1) {
1065
+ if (this.isElectron) {
1066
+ throw new Error('Cannot switch tabs inside an Electron container');
1067
+ }
1010
1068
  const pages = await this.browserContext.pages();
1011
1069
  const index = pages.indexOf(this.page);
1012
1070
  this.withinLocator = null;
@@ -1028,6 +1086,9 @@ class Playwright extends Helper {
1028
1086
  * ```
1029
1087
  */
1030
1088
  async closeCurrentTab() {
1089
+ if (this.isElectron) {
1090
+ throw new Error('Cannot close current tab inside an Electron container');
1091
+ }
1031
1092
  const oldPage = this.page;
1032
1093
  await this.switchToPreviousTab();
1033
1094
  await oldPage.close();
@@ -1066,6 +1127,9 @@ class Playwright extends Helper {
1066
1127
  * ```
1067
1128
  */
1068
1129
  async openNewTab(options) {
1130
+ if (this.isElectron) {
1131
+ throw new Error('Cannot open new tabs inside an Electron container');
1132
+ }
1069
1133
  await this._setPage(await this.browserContext.newPage(options));
1070
1134
  return this._waitForAction();
1071
1135
  }
@@ -2079,6 +2143,22 @@ class Playwright extends Helper {
2079
2143
  return context.evaluate.apply(context, [fn, arg]);
2080
2144
  }
2081
2145
 
2146
+ /**
2147
+ * Grab Locator if called within Context
2148
+ *
2149
+ * @param {*} locator
2150
+ */
2151
+ _contextLocator(locator) {
2152
+ locator = buildLocatorString(new Locator(locator, 'css'));
2153
+
2154
+ if (this.contextLocator) {
2155
+ const contextLocator = buildLocatorString(new Locator(this.contextLocator, 'css'));
2156
+ locator = `${contextLocator} >> ${locator}`;
2157
+ }
2158
+
2159
+ return locator;
2160
+ }
2161
+
2082
2162
  /**
2083
2163
  * Retrieves a text from an element located by CSS or XPath and returns it to test.
2084
2164
  * Resumes test execution, so **should be used inside async with `await`** operator.
@@ -2094,10 +2174,11 @@ class Playwright extends Helper {
2094
2174
  *
2095
2175
  */
2096
2176
  async grabTextFrom(locator) {
2097
- const texts = await this.grabTextFromAll(locator);
2098
- assertElementExists(texts, locator);
2099
- this.debugSection('Text', texts[0]);
2100
- return texts[0];
2177
+ locator = this._contextLocator(locator);
2178
+ const text = await this.page.textContent(locator);
2179
+ assertElementExists(text, locator);
2180
+ this.debugSection('Text', text);
2181
+ return text;
2101
2182
  }
2102
2183
 
2103
2184
  /**
@@ -2850,6 +2931,7 @@ class Playwright extends Helper {
2850
2931
 
2851
2932
  if (locator >= 0 && locator < childFrames.length) {
2852
2933
  this.context = childFrames[locator];
2934
+ this.contextLocator = locator;
2853
2935
  } else {
2854
2936
  throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath');
2855
2937
  }
@@ -2857,6 +2939,7 @@ class Playwright extends Helper {
2857
2939
  }
2858
2940
  if (!locator) {
2859
2941
  this.context = this.page;
2942
+ this.contextLocator = null;
2860
2943
  return;
2861
2944
  }
2862
2945
 
@@ -2867,8 +2950,10 @@ class Playwright extends Helper {
2867
2950
 
2868
2951
  if (contentFrame) {
2869
2952
  this.context = contentFrame;
2953
+ this.contextLocator = null;
2870
2954
  } else {
2871
2955
  this.context = els[0];
2956
+ this.contextLocator = locator;
2872
2957
  }
2873
2958
  }
2874
2959
 
@@ -3057,6 +3142,19 @@ async function findElements(matcher, locator) {
3057
3142
  return matcher.$$(buildLocatorString(locator));
3058
3143
  }
3059
3144
 
3145
+ async function getVisibleElements(elements) {
3146
+ const visibleElements = [];
3147
+ for (const element of elements) {
3148
+ if (await element.isVisible()) {
3149
+ visibleElements.push(element);
3150
+ }
3151
+ }
3152
+ if (visibleElements.length === 0) {
3153
+ return elements;
3154
+ }
3155
+ return visibleElements;
3156
+ }
3157
+
3060
3158
  async function proceedClick(locator, context = null, options = {}) {
3061
3159
  let matcher = await this._getContext();
3062
3160
  if (context) {
@@ -3076,7 +3174,8 @@ async function proceedClick(locator, context = null, options = {}) {
3076
3174
  if (options.force) {
3077
3175
  await els[0].dispatchEvent('click');
3078
3176
  } else {
3079
- await els[0].click(options);
3177
+ const element = els.length > 1 ? (await getVisibleElements(els))[0] : els[0];
3178
+ await element.click(options);
3080
3179
  }
3081
3180
  const promises = [];
3082
3181
  if (options.waitForNavigation) {
@@ -3334,11 +3433,13 @@ async function targetCreatedHandler(page) {
3334
3433
  // we are inside iframe?
3335
3434
  const frameEl = await this.context.frameElement();
3336
3435
  this.context = await frameEl.contentFrame();
3436
+ this.contextLocator = null;
3337
3437
  return;
3338
3438
  }
3339
3439
  // if context element was in iframe - keep it
3340
3440
  // if (await this.context.ownerFrame()) return;
3341
3441
  this.context = page;
3442
+ this.contextLocator = null;
3342
3443
  });
3343
3444
  });
3344
3445
  page.on('console', (msg) => {
@@ -3349,7 +3450,7 @@ async function targetCreatedHandler(page) {
3349
3450
  if (this.options.userAgent) {
3350
3451
  await page.setUserAgent(this.options.userAgent);
3351
3452
  }
3352
- if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0) {
3453
+ if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && this._getType() === 'Browser') {
3353
3454
  const dimensions = this.options.windowSize.split('x');
3354
3455
  const width = parseInt(dimensions[0], 10);
3355
3456
  const height = parseInt(dimensions[1], 10);
@@ -59,7 +59,8 @@ class REST extends Helper {
59
59
 
60
60
  this.options = { ...this.options, ...config };
61
61
  this.headers = { ...this.options.defaultHeaders };
62
- axios.defaults.headers = this.options.defaultHeaders;
62
+ this.axios = axios.create();
63
+ this.axios.defaults.headers = this.options.defaultHeaders;
63
64
  }
64
65
 
65
66
  static _checkRequirements() {
@@ -77,7 +78,7 @@ class REST extends Helper {
77
78
  */
78
79
  async _executeRequest(request) {
79
80
  const _debugRequest = { ...request };
80
- axios.defaults.timeout = request.timeout || this.options.timeout;
81
+ this.axios.defaults.timeout = request.timeout || this.options.timeout;
81
82
 
82
83
  if (this.headers && this.headers.auth) {
83
84
  request.auth = this.headers.auth;
@@ -102,7 +103,7 @@ class REST extends Helper {
102
103
 
103
104
  let response;
104
105
  try {
105
- response = await axios(request);
106
+ response = await this.axios(request);
106
107
  } catch (err) {
107
108
  if (!err.response) throw err;
108
109
  this.debugSection('Response', `Response error. Status code: ${err.response.status}`);