Repository: codeceptjs/CodeceptJS (js)

Issue:
els[0]._scrollIntoViewIfNeeded while upgrading Puppeteer version from 10.2.0 to 15.4.0
#### What are you trying to achieve?

Upgrade Puppeteer version from 10.2.0 to 15.4.0

#### What do you get instead?

TypeError: els[0]._scrollIntoViewIfNeeded is not a function

> Provide console output if related. Use `--verbose` mode for more details.

TypeError: els[0]._scrollIntoViewIfNeeded is not a function
    at PuppeteerHelper.scrollTo (..\node_modules\codeceptjs\lib\helper\Puppeteer.js:752:20)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at async PuppeteerHelper.scrollToElement 


```bash
# paste output here
```

> Provide test source code if related

```js
// paste test
```

### Details

* CodeceptJS version: 3.3.4
* NodeJS Version: 14
* Operating System: Windows
* puppeteer || webdriverio || testcafe version (if related) : Puppeteer version : 15.4.0
* Configuration file: package.json

  "dependencies": {
        "codeceptjs": "^3.3.4",
        <project related dependencies>
    },
    "devDependencies": {
        "puppeteer": "^15.4.0",
        <project related dependencies>
    }



```js
# paste config here
```


Pull request description:
fix(3370): els[0]._scrollIntoViewIfNeeded is broken with pupputeer > 14.4.0
## Motivation/Description of the PR
- Resolves #3370 

Applicable helpers:
- [x] Puppeteer

## Type of change
- [x] :bug: Bug fix


Patch:
diff --git a/docs/community-helpers.md b/docs/community-helpers.md
index ef758229..4c56ab8c 100644
--- a/docs/community-helpers.md
+++ b/docs/community-helpers.md
@@ -37,6 +37,7 @@ Please **add your own** by editing this page.
 * [codeceptjs-rphelper](https://github.com/reportportal/agent-js-codecept) is a CodeceptJS helper which can publish tests results on ReportPortal after execution.
 * [codeceptjs-xray-helper](https://www.npmjs.com/package/codeceptjs-xray-helper) is a CodeceptJS helper which can publish tests results on [XRAY](https://confluence.xpand-it.com/display/XRAYCLOUD/Import+Execution+Results+-+REST).
 * [codeceptjs-slack-reporter](https://www.npmjs.com/package/codeceptjs-slack-reporter) Get a Slack notification when one or more scenarios fail.
+* [codeceptjs-tesults](https://www.npmjs.com/package/codeceptjs-tesults) Report test results data from CodeceptJS to Tesults with this plugin.
 
 ## Page Object Code Generator
 * [codeceptjs-CodeGenerator](https://github.com/senthillkumar/CodeCeptJS-PageObject) is a CodeceptJS custom wrapper which can create page class with action methods from the page object file(JSON) and project setup(Folder Structure).
diff --git a/docs/reports.md b/docs/reports.md
index 4fb98a19..36a9524b 100644
--- a/docs/reports.md
+++ b/docs/reports.md
@@ -435,3 +435,14 @@ npm i codeceptjs-testrail --save
 
 Now there is new feature, add the configuration to test run of test plan
 ![Attachemnt for failed case](http://g.recordit.co/uQLvQUq7cT.gif)
+
+
+## Tesults
+
+Submit test results data from CodeceptJS to [Tesults](https://www.tesults.com) easily with the [codeceptjs-tesults](https://www.npmjs.com/package/codeceptjs-tesults) plugin. Test results data is submitted automatically after a test run completes.
+
+```sh
+npm i codeceptjs-tesults --save
+```
+
+Once installed, follow the [quick and easy integration instructions](https://www.tesults.com/docs/codeceptjs) to get setup in no time.
diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js
index f818d51f..660a348f 100644
--- a/lib/helper/Puppeteer.js
+++ b/lib/helper/Puppeteer.js
@@ -192,7 +192,6 @@ class Puppeteer extends Helper {
     super(config);
 
     puppeteer = requireWithFallback('puppeteer', 'puppeteer-core');
-
     // set defaults
     this.isRemoteBrowser = false;
     this.isRunning = false;
@@ -372,22 +371,22 @@ class Puppeteer extends Helper {
   }
 
   /**
-  * Use Puppeteer API inside a test.
-  *
-  * First argument is a description of an action.
-  * Second argument is async function that gets this helper as parameter.
-  *
-  * { [`page`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page), [`browser`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser) } from Puppeteer API are available.
-  *
-  * ```js
-  * I.usePuppeteerTo('emulate offline mode', async ({ page }) {
-  *   await page.setOfflineMode(true);
-  * });
-  * ```
-  *
-  * @param {string} description used to show in logs.
-  * @param {function} fn async function that is executed with Puppeteer as argument
-  */
+   * Use Puppeteer API inside a test.
+   *
+   * First argument is a description of an action.
+   * Second argument is async function that gets this helper as parameter.
+   *
+   * { [`page`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page), [`browser`](https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser) } from Puppeteer API are available.
+   *
+   * ```js
+   * I.usePuppeteerTo('emulate offline mode', async ({ page }) {
+   *   await page.setOfflineMode(true);
+   * });
+   * ```
+   *
+   * @param {string} description used to show in logs.
+   * @param {function} fn async function that is executed with Puppeteer as argument
+   */
   usePuppeteerTo(description, fn) {
     return this._useTo(...arguments);
   }
@@ -749,7 +748,8 @@ class Puppeteer extends Helper {
     if (locator) {
       const els = await this._locate(locator);
       assertElementExists(els, locator, 'Element');
-      await els[0]._scrollIntoViewIfNeeded();
+      const el = els[0];
+      await el.evaluate((el) => el.scrollIntoView());
       const elementCoordinates = await getClickablePoint(els[0]);
       await this.executeScript((x, y) => window.scrollBy(x, y), elementCoordinates.x + offsetX, elementCoordinates.y + offsetY);
     } else {
@@ -1069,7 +1069,12 @@ class Puppeteer extends Helper {
       fs.mkdirSync(downloadPath, '0777');
     }
     fsExtra.emptyDirSync(downloadPath);
-    return this.page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath });
+
+    try {
+      return this.page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath });
+    } catch (e) {
+      return this.page._client().send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath });
+    }
   }
 
   /**
diff --git a/lib/helper/WebDriver.js b/lib/helper/WebDriver.js
index f7d91946..8e783d89 100644
--- a/lib/helper/WebDriver.js
+++ b/lib/helper/WebDriver.js
@@ -567,6 +567,9 @@ class WebDriver extends Helper {
       });
     }
 
+    if (this.browser.capabilities && this.browser.capabilities.platformName) {
+      this.browser.capabilities.platformName = this.browser.capabilities.platformName.toLowerCase();
+    }
     return this.browser;
   }
 
diff --git a/lib/utils.js b/lib/utils.js
index 75ea0c0a..31904cc9 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -33,12 +33,7 @@ const isAsyncFunction = module.exports.isAsyncFunction = function (fn) {
 };
 
 module.exports.fileExists = function (filePath) {
-  try {
-    fs.statSync(filePath);
-  } catch (err) {
-    if (err.code === 'ENOENT') return false;
-  }
-  return true;
+  return fs.existsSync(filePath);
 };
 
 module.exports.isFile = function (filePath) {
diff --git a/package.json b/package.json
index 73974b87..679cccab 100644
--- a/package.json
+++ b/package.json
@@ -90,7 +90,7 @@
     "uuid": "^8.3.2"
   },
   "devDependencies": {
-    "@codeceptjs/detox-helper": "^1.0.2",    
+    "@codeceptjs/detox-helper": "^1.0.2",
     "@codeceptjs/mock-request": "^0.3.1",
     "@faker-js/faker": "^5.5.3",
     "@pollyjs/adapter-puppeteer": "^5.1.0",


Test patch:
diff --git a/test/unit/utils_test.js b/test/unit/utils_test.js
index 90c08480..a9e17d33 100644
--- a/test/unit/utils_test.js
+++ b/test/unit/utils_test.js
@@ -7,8 +7,9 @@ const utils = require('../../lib/utils');
 
 describe('utils', () => {
   describe('#fileExists', () => {
-    it('exists', () => expect(utils.fileExists(__filename)));
-    it('not exists', () => expect(!utils.fileExists('not_utils.js')));
+    it('exists', () => expect(utils.fileExists(__filename)).to.be.true);
+    it('not exists', () => expect(utils.fileExists('not_utils.js')).to.be.false);
+    it('not exists if file used as directory', () => expect(utils.fileExists(`${__filename}/not_utils.js`)).to.be.false);
   });
   /* eslint-disable no-unused-vars */
   describe('#getParamNames', () => {