Repository: Codeception/CodeceptJS
Pull request #2044 (2019-11-22 13:16:02)

improve the codeceptjs info
## Motivation/Description of the PR

Applicable helpers:

- [ ] Webdriver
- [ ] Puppeteer
- [ ] Nightmare
- [ ] REST
- [ ] Appium
- [ ] Protractor
- [ ] TestCafe

This gives more info when using `npx codeceptjs info`

```sh
$npx codeceptjs info

 Environment information:-

codeceptVersion:  "2.3.0"
nodeInfo:  10.15.0
osInfo:  macOS Mojave 10.14.6
cpuInfo:  (8) x64 Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
chromeInfo:  78.0.3904.108
edgeInfo:  N/A
firefoxInfo:  65.0.1
safariInfo:  13.0.4
helpers:  {
 "WebDriver": {
  "url": "https://www.amazon.de",
  "browser": "chrome",
  "desiredCapabilities": {
   "chromeOptions": {
    "args": [
     "--headless",
     "--disable-gpu",
     "--window-size=1440,700"
    ]
   }
  },
  "windowSize": "1440x700"
 }
}
plugins:  "You don't have any enabled plugins"
***************************************

If you have questions ask them in our Slack: shorturl.at/cuKU8
    
Or ask them on our discussion board: https://codecept.discourse.group/
    
If you found a bug, an improvements, you can report it to GitHub issues: https://github.com/Codeception/CodeceptJS/issues
```


## Type of change

- [ ] Breaking changes
- [ ] New functionality
- [ ] Bug fix
- [ ] Documentation changes/updates
- [ ] Hot fix
- [ ] Markdown files fix - not related to source code

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] Tests have been added
- [ ] Documentation has been added (Run `robo docs`)
- [x] Lint checking (Run `npm run lint`)
- [x] Local tests are passed (Run `npm test`)


Patch:
diff --git a/bin/codecept.js b/bin/codecept.js
index 6b7bb691..a1b14fe9 100755
--- a/bin/codecept.js
+++ b/bin/codecept.js
@@ -1,5 +1,4 @@
 #!/usr/bin/env node
-const envinfo = require('envinfo');
 const program = require('commander');
 const Codecept = require('../lib/codecept');
 const { print, error } = require('../lib/output');
@@ -156,19 +155,10 @@ program.command('run-multiple [suites...]')
 
   .action(require('../lib/command/run-multiple'));
 
-program.command('info')
+program.command('info [path]')
   .description('Print debugging information concerning the local environment')
-  .action(() => {
-    console.log('\n Environment information:-\n');
-    envinfo
-      .run({
-        System: ['OS', 'CPU'],
-        Binaries: ['Node', 'Yarn', 'npm'],
-        Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
-        npmGlobalPackages: ['codeceptjs'],
-      })
-      .then(console.log);
-  });
+  .option('-c, --config', 'your config file path')
+  .action(require('../lib/command/info'));
 
 program.command('dry-run [test]')
   .description('Prints step-by-step scenario for a test without actually running it')
diff --git a/docs/basics.md b/docs/basics.md
index b49f9a90..b23291d0 100644
--- a/docs/basics.md
+++ b/docs/basics.md
@@ -3,7 +3,7 @@ id: basics
 title: Basics
 ---
 
-CodeceptJS is a modern end to end testing framework with a special BDD-style syntax. The test is written as a linear scenario of user's action on a site.
+CodeceptJS is a modern end to end testing framework with a special BDD-style syntax. The tests are written as a linear scenario of the user's action on a site.
 
 ```js
 Feature('CodeceptJS demo');
@@ -16,21 +16,21 @@ Scenario('check Welcome page on site', (I) => {
 
 Tests are expected to be written in **ECMAScript 7**.
 
-Each test is described inside a `Scenario` function with `I` object passed into it.
-I object is an **actor**, an abstraction for a testing user. I is a proxy object for currently enabled **Helpers**.
+Each test is described inside a `Scenario` function with the `I` object passed into it.
+The `I` object is an **actor**, an abstraction for a testing user. The `I` is a proxy object for currently enabled **Helpers**.
 
 ## Architecture
 
-CodeceptJS bypasses execution commands to helpers. Depending on helper enabled your tests will be executed differently. If you need cross-browser support you should choose Selenium-based WebDriver or Protractor, if you are interested in speed - use Chrome-based Puppeteer, or Electron-based Nightmare. Those engines can run tests in window mode or headlessly and doesn't require additional tools to be installed.
+CodeceptJS bypasses execution commands to helpers. Depending on the helper enabled, your tests will be executed differently. If you need cross-browser support you should choose Selenium-based WebDriver or TestCafé. If you are interested in speed - you should use Chrome-based Puppeteer.
 
-Here is the diagram of CodeceptJS architecture
+The following is a diagram of the CodeceptJS architecture:
 
 ![architecture](https://codecept.io/img/architecture.svg)
 
-All helpers share the same API so it's easy to migrate tests from one backend to other.
-However, because of difference in backends and their limitations, they are not guaranteed to be compatible with each other. For instance, you can't set request headers in WebDriver or Protractor, but you can do so in Puppteer or Nightmare.
+All helpers share the same API, so it's easy to migrate tests from one backend to another.
+However, because of the difference in backends and their limitations, they are not guaranteed to be compatible with each other. For instance, you can't set request headers in WebDriver or Protractor, but you can do so in Puppteer or Nightmare.
 
-**Pick one helper, as it defines how tests are executed.** If requirements change it's easy to migrate to another, but don't use few helpers of same kind at once.
+**Pick one helper, as it defines how tests are executed.** If requirements change it's easy to migrate to another.
 
 ---
 
@@ -44,13 +44,13 @@ Refer to following guides to more information on:
 
 > ℹ Depending on a helper selected a list of available actions may change.
 
-To list all available commands for current configuration run `codeceptjs list`
+To list all available commands for the current configuration run `codeceptjs list`
 or enable [auto-completion by generating TypeScript definitions](#intellisense).
 
 
 ## Writing Tests
 
-Tests are written from a user's perspective. There is an actor (represented as `I`) which contains actions taken from helpers. A test is written as a sequence of actions performed by actor:
+Tests are written from a user's perspective. There is an actor (represented as `I`) which contains actions taken from helpers. A test is written as a sequence of actions performed by an actor:
 
 ```js
 I.amOnPage('/');
@@ -61,9 +61,9 @@ I.see('Please Login', 'h1');
 
 ### Opening a Page
 
-A test should usually start with navigating browser to the website.
+A test should usually start by navigating the browser to a website.
 
-Start a test by opening a page. Use `I.amOnPage()` command for this:
+Start a test by opening a page. Use the `I.amOnPage()` command for this:
 
 ```js
 // When "http://site.com" is url in config
@@ -72,9 +72,9 @@ I.amOnPage('/about'); // -> opens http://site.com/about
 I.amOnPage('https://google.com'); // -> https://google.com
 ```
 
-When URL doesn't start with a protocol (http:// or https://) it is considered to be a relative URL and appended to URL which was initially set in the config.
+When an URL doesn't start with a protocol (http:// or https://) it is considered to be a relative URL and will be appended to the URL which was initially set-up in the config.
 
-> It is recommended to use relative URLs and keep base URL in config file, so you could easily switch between development, staging, and production environments.
+> It is recommended to use a relative URL and keep the base URL in the config file, so you can easily switch between development, stage, and production environments.
 
 
 ### Locating Element
@@ -87,7 +87,7 @@ I.seeElement('//button[contains(., "press me")]'); // button
 ```
 
 By default CodeceptJS tries to guess the locator type.
-In order to specify exact locator type you can pass an object called **strict locator**.
+In order to specify the exact locator type you can pass an object called **strict locator**.
 
 ```js
 I.seeElement({css: 'div.user'});
@@ -105,7 +105,7 @@ I.seeElement({id: 'users'});
 I.seeElement({react: 'user-profile', props: {name: 'davert'}});
 ```
 
-In [mobile testing](http://codecept.io/mobile/#locating-elements) you can use `~` to specify accessibility id to locate an element. In web application you can locate element by their `aria-label` value.
+In [mobile testing](http://codecept.io/mobile/#locating-elements) you can use `~` to specify the accessibility id to locate an element. In web application you can locate elements by their `aria-label` value.
 
 ```js
 // locate element by [aria-label] attribute in web
@@ -119,23 +119,23 @@ I.seeElement('~username');
 
 CodeceptJS provides a flexible syntax to specify an element to click.
 
-By default CodeceptJS tries to find button or link with exact text on it
+By default CodeceptJS tries to find the button or link with the exact text on it
 
 ```js
 // search for link or button
 I.click('Login');
 ```
 
-If none found, CodeceptJS tries to find link or button containing that text. In case an image is clickable its `alt` attribute will be checked for text inclusion. Form buttons will also be searched by name.
+If none was found, CodeceptJS tries to find a link or button containing that text. In case an image is clickable its `alt` attribute will be checked for text inclusion. Form buttons will also be searched by name.
 
-To narrow down the results you can specify a context in second parameter.
+To narrow down the results you can specify a context in the second parameter.
 
 ```js
 I.click('Login', '.nav'); // search only in .nav
 I.click('Login', {css: 'footer'}); // search only in footer
 ```
 
-> To skip guessing locator type pass in a strict locator. A locator starting with '#' or '.' is considered to be CSS. Locator starting with '//' or './/' is considered to be XPath.
+> To skip guessing the locator type, pass in a strict locator - A locator starting with '#' or '.' is considered to be CSS. Locators starting with '//' or './/' are considered to be XPath.
 
 You are not limited to buttons and links. Any element can be found by passing in valid CSS or XPath:
 
@@ -148,7 +148,7 @@ I.click('//dev[@test-id="myid"]');
 
 ### Filling Fields
 
-Clicking the links is not what takes the most time during testing a web site. If your site consists only of links you can skip test automation. The most routine waste of time goes into the testing of forms. CodeceptJS provides several ways of doing that.
+Clicking the links is not what takes the most time during testing a web site. If your site consists only of links you can skip test automation. The most waste of time goes into the testing of forms. CodeceptJS provides several ways of doing that.
 
 Let's submit this sample form for a test:
 
@@ -167,7 +167,7 @@ Let's submit this sample form for a test:
 </form>
 ```
 
-We need to fill in all those fields and click "Update" button. CodeceptJS matches form elements by their label, name, or by CSS or XPath locators.
+We need to fill in all those fields and click the "Update" button. CodeceptJS matches form elements by their label, name, or by CSS or XPath locators.
 
 ```js
 // we are using label to match user_name field
@@ -192,7 +192,7 @@ I.selectOption('#user_gender','m');
 I.click('submitButton', '#update_form');
 ```
 
-To fill in sensitive data use `secret` function:
+To fill in sensitive data use the `secret` function:
 
 ```js
 I.fillField('password', secret('123456'));
@@ -200,8 +200,8 @@ I.fillField('password', secret('123456'));
 
 ### Assertions
 
-In order to verify the expected behavior of a web application, a content should be checked.
-CodeceptJS provides built-in assertions for that. They start with `see` (or `dontSee`) prefix.
+In order to verify the expected behavior of a web application, it's content should be checked.
+CodeceptJS provides built-in assertions for that. They start with a `see` (or `dontSee`) prefix.
 
 The most general and common assertion is `see`, which checks visilibility of a text on a page:
 
@@ -214,7 +214,7 @@ I.see('Hello', '.msg');
 I.dontSee('Bye');
 ```
 
-You should provide a text as first argument and optionally a locator to search for a text in a context.
+You should provide a text as first argument and, optionally, a locator to search for a text in a context.
 
 You can check that specific element exists (or not) on a page, as it was described in [Locating Element](#locating-element) section.
 
@@ -231,12 +231,12 @@ I.seeInField('user[name]', 'Miles');
 I.seeInTitle('My Website');
 ```
 
-To see all possible assertions see the helper's reference.
+To see all possible assertions, check the helper's reference.
 
 ### Grabbing
 
-Sometimes you need to retrieve a data from a page to use it in next steps of a scenario.
-Imagine, application generates a password and you want to ensure that user can login using this password.
+Sometimes you need to retrieve data from a page to use it in the following steps of a scenario.
+Imagine the application generates a password, and you want to ensure that user can login using this password.
 
 ```js
 Scenario('login with generated password', async (I) => {
@@ -251,7 +251,7 @@ Scenario('login with generated password', async (I) => {
 });
 ```
 
-`grabTextFrom` action is used here to retrieve text from an element. All actions starting with `grab` prefix are expected to return data. In order to synchronize this step with a scenario you should pause test execution with `await` keyword of ES6. To make it work your test should be written inside a async function (notice `async` in its definition).
+The `grabTextFrom` action is used to retrieve the text from an element. All actions starting with the `grab` prefix are expected to return data. In order to synchronize this step with a scenario you should pause the test execution with the `await` keyword of ES6. To make it work, your test should be written inside a async function (notice `async` in its definition).
 
 ```js
 Scenario('use page title', async (I) => {
@@ -263,9 +263,9 @@ Scenario('use page title', async (I) => {
 
 ### Waiting
 
-In modern web applications rendering is happen on client side.
+In modern web applications, rendering is done on the client-side.
 Sometimes that may cause delays. A test may fail while trying to click an element which has not appeared on a page yet.
-To handle this cases `wait*` methods introduced.
+To handle these cases, the `wait*` methods has been introduced.
 
 ```js
 I.waitForElement('#agree_button', 30); // secs
@@ -273,17 +273,17 @@ I.waitForElement('#agree_button', 30); // secs
 I.click('#agree_button');
 ```
 
-> ℹ See [helpers reference](https://codecept.io/reference) for a complete list of all available commands for a helper you use.
+> ℹ See [helpers reference](https://codecept.io/reference) for a complete list of all available commands for the helper you use.
 
 ## How It Works
 
 Tests are written in a synchronous way. This improves the readability and maintainability of tests.
-While writing tests you should not think about promises. You should focus on the test scenario.
+While writing tests you should not think about promises, and instead should focus on the test scenario.
 
-However, behind the scenes **all actions are wrapped in promises** inside of the `I` object.
-[Global promise](https://github.com/Codeception/CodeceptJS/blob/master/lib/recorder.js) chain is initialized before each test and all `I.*` calls will be appended to it as well as setup and teardown.
+However, behind the scenes **all actions are wrapped in promises**, inside of the `I` object.
+[Global promise](https://github.com/Codeception/CodeceptJS/blob/master/lib/recorder.js) chain is initialized before each test and all `I.*` calls will be appended to it, as well as setup and teardown.
 
-If you want to get information from a running test you can use `await` inside **async function** and special methods of helpers started with `grab` prefix.
+If you want to get information from a running test you can use `await` inside the **async function**, and utilize special methods of helpers started with the `grab` prefix.
 
 ```js
 Scenario('try grabbers', async (I) => {
@@ -301,23 +301,23 @@ assert.equal(title, 'CodeceptJS');
 
 ## Running Tests
 
-To launch tests use `run` command. To execute tests in [multiple browsers](https://codecept.io/advanced/#multiple-browsers-execution) or [multiple threads](https://codecept.io/advanced/#parallel-execution) use `run-multiple`.
+To launch tests use the `run` command, and to execute tests in [multiple browsers](https://codecept.io/advanced/#multiple-browsers-execution) or [multiple threads](https://codecept.io/advanced/#parallel-execution) use the `run-multiple` command.
 
 ### Level of Detail
 
-To see step-by-step output of running tests, add `--steps` flag:
+To see the step-by-step output of running tests, add the `--steps` flag:
 
 ```
 npx codeceptjs run --steps
 ```
 
-To see more detailed output add `--debug` flag:
+To see a more detailed output add the `--debug` flag:
 
 ```
 npx codeceptjs run --debug
 ```
 
-To see very detailed output system use `--verbose` flag:
+To see very detailed output informations use the `--verbose` flag:
 
 ```
 npx codeceptjs run --verbose
@@ -325,7 +325,7 @@ npx codeceptjs run --verbose
 
 ### Filter
 
-A single test file can be executed if you provide a relative path to such file:
+A single test file can be executed if you provide a relative path to such a file:
 
 ```
 npx codeceptjs run github_test.js
@@ -335,9 +335,9 @@ npx codeceptjs run github_test.js
 npx codeceptjs run admin/login_test.js
 ```
 
-To filter a test by name use `--grep` parameter. Which will execute all tests with names matching the regex pattern.
+To filter a test by name use the `--grep` parameter, which will execute all tests with names matching the regex pattern.
 
-To run all tests with `slow` word in it
+To run all tests with the `slow` word in it:
 
 ```
 npx codeceptjs run --grep "slow"
@@ -350,18 +350,18 @@ It is recommended to [filter tests by tags](https://codecept.io/advanced/#tags).
 
 ### Parallel Run
 
-Since CodeceptJS 2.3 you can run tests in parallel by using NodeJS workers. This feature requires NodeJS >= 11.6. Use `run-workers` command with the number of workers (threads) to split tests.
+Since CodeceptJS 2.3, you can run tests in parallel by using NodeJS workers. This feature requires NodeJS >= 11.6. Use `run-workers` command with the number of workers (threads) to split tests.
 
 ```
 npx codeceptjs run-workers 3
 ```
 
-Tests are split by scenarios, not by files. Results are aggregated and shown in the main process.
+Tests are split by scenarios, not by files. Results are aggregated and shown up in the main process.
 
 ## Configuration
 
-Configuration is set in `codecept.conf.js` file which was created during `init` process.
-Inside config file you can enable and configure helpers, plugins, set bootstrap and teardown scripts.
+Configuration is set in the `codecept.conf.js` file which was created during the `init` process.
+Inside the config file you can enable and configure helpers and plugins, and set bootstrap and teardown scripts.
 
 ```js
 exports.config = {
@@ -379,15 +379,15 @@ exports.config = {
 
 > ▶ See complete [configuration reference](https://codecept.io/configuration).
 
-You can have multiple configuration files for a one project. In this case specify a config file to be used with `-c` when running.
+You can have multiple configuration files for a the same project, in this case you can specify a config file to be used with `-c` when running.
 
 ```
 npx codeceptjs run -c codecept.ci.conf.js
 ```
 
-Tuning configuration for helpers like WebDriver, Puppeteer can be hard, as it requires good understanding of how those technologies work. Use [`@codeceptjs/configure`](https://github.com/codecept-js/configure) package with common configuration recipes.
+Tuning configuration for helpers like WebDriver, Puppeteer can be hard, as it requires good understanding of how these technologies work. Use the [`@codeceptjs/configure`](https://github.com/codecept-js/configure) package with common configuration recipes.
 
-For instance, you can set window size or toggle headless mode no matter of which helpers are actually used.
+For instance, you can set the window size or toggle headless mode, no matter of which helpers are actually used.
 
 ```js
 const { setHeadlessWhen, setWindowSize } = require('@codeceptjs/configure');
@@ -407,7 +407,7 @@ exports.config = {
 ## Debug
 
 CodeceptJS allows to write and debug tests on the fly while keeping your browser opened.
-By using interactive shell you can stop execution at any point and type in CodeceptJS commands.
+By using the interactive shell you can stop execution at any point and type in any CodeceptJS commands.
 
 This is especially useful while writing a new scratch. After opening a page call `pause()` to start interacting with a page:
 
@@ -422,7 +422,7 @@ Try to perform your scenario step by step. Then copy succesful commands and inse
 
 Test execution can be paused in any place of a test with `pause()` call.
 
-This launches interactive console where you can call actions of `I` object.
+This launches the interactive console where you can call any action from the `I` object.
 
 ```
  Interactive shell started
@@ -434,21 +434,21 @@ This launches interactive console where you can call actions of `I` object.
 
 ```
 
-Type in different actions to try them, copy valid successful ones to test, update the test file.
+Type in different actions to try them, copy and paste successful ones into the test file.
 
 Press `ENTER` to resume test execution.
 
-To **debug test step-by-step** type press Enter. The next step will be executed and interactive shell will be shown again.
+To **debug test step-by-step** press Enter, the next step will be executed and interactive shell will be shown again.
 
-To see all available commands press TAB two times to see list of all actions included in I.
+To see all available commands, press TAB two times to see list of all actions included in the `I` object.
 
-If a test is failing you can prevent browser from closing by putting `pause()` command into `After()` hook. This is very helpful to debug failing tests. This way you can keep the same session and try different actions on a page to get the idea what went wrong.
+If a test is failing you can prevent the browser from closing by putting the `pause()` command into an `After()` hook. This is very helpful to debug failing tests. This way you can keep the same session and try different actions on a page to get an idea about what went wrong.
 
 ```js
 After(pause);
 ```
 
-Interactive shell can be started outside the test context by running
+The interactive shell can be started outside of test context by running
 
 ```bash
 codeceptjs shell
@@ -468,20 +468,20 @@ To see how the test was executed, use [stepByStepReport Plugin](https://codecept
 
 ### Retry Step
 
-If you have a step which often fails you can retry execution for this single step.
-Use `retry()` function before an action to ask CodeceptJS to retry this step on failure:
+If you have a step which often fails, you can retry execution for this single step.
+Use the `retry()` function before an action to ask CodeceptJS to retry it on failure:
 
 ```js
 I.retry().see('Welcome');
 ```
 
-If you'd like to retry step more than once pass the amount as parameter:
+If you'd like to retry a step more than once, pass the amount as a parameter:
 
 ```js
 I.retry(3).see('Welcome');
 ```
 
-Additional options can be provided to retry so you can set the additional options (defined in [promise-retry](https://www.npmjs.com/package/promise-retry) library).
+Additional options can be provided to `retry`, so you can set the additional options (defined in [promise-retry](https://www.npmjs.com/package/promise-retry) library).
 
 
 ```js
@@ -498,7 +498,7 @@ I.retry({
 }).seeElement('#user');
 ```
 
-Pass a function to `when` option to retry only when error matches the expected one.
+Pass a function to the `when` option to retry only when an error matches the expected one.
 
 ### Auto Retry
 
@@ -506,10 +506,10 @@ You can auto-retry a failed step by enabling [retryFailedStep Plugin](https://co
 
 ### Retry Scenario
 
-When you need to rerun a scenario a few times just add the `retries` option added to the `Scenario` declaration.
+When you need to rerun scenarios a few times, add the `retries` option to the `Scenario` declaration.
 
-CodeceptJS implements retries the same way [Mocha does](https://mochajs.org#retry-tests).
-You can set number of a retries for a feature:
+CodeceptJS implements retries the same way [Mocha does](https://mochajs.org#retry-tests);
+You can set the number of a retries for a feature:
 
 ```js
 Scenario('Really complex', (I) => {
@@ -525,19 +525,19 @@ Unlike retry step, there is no `when` condition supported for retries on a scena
 
 ### Retry Feature
 
-To set this option for all scenarios in a file, add retry to a feature:
+To set this option for all scenarios in a file, add `retry` to a feature:
 
 ```js
 Feature('Complex JS Stuff').retry(3);
 ```
 
 Every Scenario inside this feature will be rerun 3 times.
-You can make an exception for a specific scenario by passing `retries` option to a Scenario.
+You can make an exception for a specific scenario by passing the `retries` option to a Scenario.
 
 
 ## Before
 
-Common preparation steps like opening a web page, logging in a user, can be placed in `Before` or `Background` hook:
+Common preparation steps like opening a web page or logging in a user, can be placed in the `Before` or `Background` hooks:
 
 ```js
 Feature('CodeceptJS Demonstration');
@@ -561,9 +561,9 @@ Same as `Before` you can use `After` to run teardown for each scenario.
 
 ## BeforeSuite
 
-If you need to run complex setup before all tests and teardown this afterwards you can use `BeforeSuite` and `AfterSuite`
-functions. `BeforeSuite` and `AfterSuite` have access to `I` object, but `BeforeSuite/AfterSuite` don't have an access to the browser because it's not running at this moment.
-You can use them to execute handlers that will setup your environment. `BeforeSuite/AfterSuite` will work  only for a file where it was declared (so you can declare different setups for files)
+If you need to run complex a setup before all tests and have to teardown this afterwards, you can use the `BeforeSuite` and `AfterSuite` functions.
+`BeforeSuite` and `AfterSuite` have access to the `I` object, but `BeforeSuite/AfterSuite` don't have any access to the browser, because it's not running at this moment.
+You can use them to execute handlers that will setup your environment. `BeforeSuite/AfterSuite` will work only for the file it was declared in (so you can declare different setups for files)
 
 ```js
 BeforeSuite((I) => {
@@ -576,11 +576,11 @@ AfterSuite((I) => {
 });
 ```
 
-[Here are some ideas](https://github.com/Codeception/CodeceptJS/pull/231#issuecomment-249554933) where to use BeforeSuite hooks.
+[Here are some ideas](https://github.com/Codeception/CodeceptJS/pull/231#issuecomment-249554933) on where to use BeforeSuite hooks.
 
 ## Within
 
-To specify the exact area on a page where actions can be performed you can use `within` function.
+To specify the exact area on a page where actions can be performed you can use the `within` function.
 Everything executed in its context will be narrowed to context specified by locator:
 
 Usage: `within('section', ()=>{})`
@@ -596,7 +596,7 @@ within('.js-signup-form', () => {
 I.see('There were problems creating your account.');
 ```
 
-`within` can also work with IFrames. Special `frame` locator is required to locate the iframe and get into its context.
+`within` can also work with IFrames. A special `frame` locator is required to locate the iframe and get into its context.
 
 See example:
 
@@ -606,7 +606,7 @@ within({frame: "#editor"}, () => {
 });
 ```
 
-Nested IFrames can be set by passing array *(WebDriver, Nightmare & Puppeteer only)*:
+Nested IFrames can be set by passing an array *(WebDriver, Nightmare & Puppeteer only)*:
 
 ```js
 within({frame: [".content", "#editor"]}, () => {
@@ -614,11 +614,11 @@ within({frame: [".content", "#editor"]}, () => {
 });
 ```
 
-When running steps inside a within block will be shown with a shift:
+When running steps inside, a within block will be shown with a shift:
 
 ![within](https://codecept.io/img/within.png)
 
-Within can return a value which can be used in a scenario:
+Within can return a value, which can be used in a scenario:
 
 ```js
 // inside async function
@@ -630,8 +630,8 @@ I.fillField('Description', val);
 
 ## Comments
 
-There is a simple way to add additional comments to your test scenario.
-Use `say` command to print information to screen:
+There is a simple way to add additional comments to your test scenario:
+Use the `say` command to print information to screen:
 
 ```js
 I.say('I am going to publish post');
@@ -639,7 +639,7 @@ I.say('I enter title and body');
 I.say('I expect post is visible on site');
 ```
 
-Use second parameter to pass in color value (ASCII).
+Use the second parameter to pass in a color value (ASCII).
 
 ```js
 I.say('This is red', 'red'); //red is used
@@ -652,15 +652,15 @@ I.say('This is by default'); //cyan is used
 
 ![](/img/edit.gif)
 
-To get autocompletion when working with CodeceptJS use  Visual Studio Code or other IDE that supports TypeScript Definitions.
+To get autocompletion when working with CodeceptJS, use Visual Studio Code or another IDE that supports TypeScript Definitions.
 
-Generate step definitions with
+Generate step definitions with:
 
 ```sh
 npx codeceptjs def
 ```
 
-Create `jsconfig.json` in your project root directory unless it is already there.
+Create a file called `jsconfig.json` in your project root directory, unless you already have one.
 
 ```jsconfig.json
 {
@@ -676,7 +676,7 @@ to get method autocompletion while writing tests.
 
 ## Multiple Sessions
 
-CodeceptJS allows to run several browser sessions inside a test. This can be useful for testing communication between users inside a system, for instance in chats. To open another browser use `session()` function as shown in example:
+CodeceptJS allows to run several browser sessions inside a test. This can be useful for testing communication between users inside a chat or other systems. To open another browser use the `session()` function as shown in the example:
 
 ```js
 Scenario('test app', (I) => {
@@ -702,9 +702,9 @@ Scenario('test app', (I) => {
 });
 ```
 
-`session` function expects a first parameter to be a name of a session. You can switch back to session by using the same name.
+The `session` function expects the first parameter to be the name of the session. You can switch back to this session by using the same name.
 
-You can override config for session by passing second parameter:
+You can override the configuration for the session by passing a second parameter:
 
 ```js
 session('john', { browser: 'firefox' } , () => {
@@ -713,7 +713,7 @@ session('john', { browser: 'firefox' } , () => {
 });
 ```
 
-or just start session without switching to it. Call `session` passing only its name:
+or just start the session without switching to it. Call `session` passing only its name:
 
 ```js
 Scenario('test', (I) => {
@@ -730,7 +730,7 @@ Scenario('test', (I) => {
   });
 }
 ```
-`session` can return value which can be used in scenario:
+`session` can return a value which can be used in a scenario:
 
 ```js
 // inside async function
@@ -741,15 +741,15 @@ const val = await session('john', () => {
 I.fillField('Description', val);
 ```
 
-Function passed into session can use `I`, page objects, and any objects declared for the scenario.
+Functions passed into a session can use the `I` object, page objects, and any other objects declared for the scenario.
 This function can also be declared as async (but doesn't work as generator).
 
-Also, you can use `within` inside a session but you can't call session from inside `within`.
+Also, you can use `within` inside a session, but you can't call session from inside `within`.
 
 
 ## Skipping
 
-Like in Mocha you can use `x` and `only` to skip tests or making a single test to run.
+Like in Mocha you can use `x` and `only` to skip tests or to run a single test.
 
 * `xScenario` - skips current test
 * `Scenario.only` - executes only the current test
diff --git a/lib/command/definitions.js b/lib/command/definitions.js
index 577ea4fb..b3035d4f 100644
--- a/lib/command/definitions.js
+++ b/lib/command/definitions.js
@@ -93,7 +93,9 @@ function getPath(originalPath, targetFolderPath, testsPath) {
   else if (parsedPath.ext === '.ts') parsedPath.base = parsedPath.name;
 
   if (!parsedPath.dir.startsWith('.')) return path.join(parsedPath.dir, parsedPath.base);
-  return path.relative(targetFolderPath, path.join(testsPath, parsedPath.dir, parsedPath.base));
+  const relativePath = path.relative(targetFolderPath, path.join(testsPath, parsedPath.dir, parsedPath.base));
+
+  return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
 }
 
 /**
diff --git a/lib/command/info.js b/lib/command/info.js
new file mode 100644
index 00000000..8b997b3d
--- /dev/null
+++ b/lib/command/info.js
@@ -0,0 +1,39 @@
+const getConfig = require('./utils').getConfig;
+const getTestRoot = require('./utils').getTestRoot;
+const Codecept = require('../codecept');
+const output = require('../output');
+const envinfo = require('envinfo');
+
+module.exports = async function (path) {
+  const testsPath = getTestRoot(path);
+  const config = getConfig(testsPath);
+  const codecept = new Codecept(config, {});
+  codecept.init(testsPath);
+
+  output.print('\n Environment information:-\n');
+  const info = {};
+  info.codeceptVersion = Codecept.version();
+  info.nodeInfo = await envinfo.helpers.getNodeInfo();
+  info.osInfo = await envinfo.helpers.getOSInfo();
+  info.cpuInfo = await envinfo.helpers.getCPUInfo();
+  info.chromeInfo = await envinfo.helpers.getChromeInfo();
+  info.edgeInfo = await envinfo.helpers.getEdgeInfo();
+  info.firefoxInfo = await envinfo.helpers.getFirefoxInfo();
+  info.safariInfo = await envinfo.helpers.getSafariInfo();
+  const { helpers, plugins } = config;
+  info.helpers = helpers || "You don't use any helpers";
+  info.plugins = plugins || "You don't have any enabled plugins";
+
+  for (const [key, value] of Object.entries(info)) {
+    if (Array.isArray(value)) {
+      output.print(`${key}:  ${value[1]}`);
+    } else {
+      output.print(`${key}:  ${JSON.stringify(value, null, ' ')}`);
+    }
+  }
+  output.print('***************************************');
+  output.print('If you have questions ask them in our Slack: shorturl.at/cuKU8');
+  output.print('Or ask them on our discussion board: https://codecept.discourse.group/');
+  output.print('Please copy environment info when you report issues on GitHub: https://github.com/Codeception/CodeceptJS/issues');
+  output.print('***************************************');
+};
diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js
index 5e2785cc..e43b03d8 100644
--- a/lib/helper/Puppeteer.js
+++ b/lib/helper/Puppeteer.js
@@ -248,9 +248,13 @@ class Puppeteer extends Helper {
       this.debugSection('Session', 'cleaning cookies and localStorage');
       await this.clearCookie();
     }
-    await this.executeScript('localStorage.clear();').catch((err) => {
-      if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err;
-    });
+    const currentUrl = await this.grabCurrentUrl();
+
+    if (currentUrl.startsWith('http')) {
+      await this.executeScript('localStorage.clear();').catch((err) => {
+        if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err;
+      });
+    }
     await this.closeOtherTabs();
     return this.browser;
   }


Test patch:
diff --git a/test/data/sandbox/configs/definitions/codecept.inject.po.json b/test/data/sandbox/configs/definitions/codecept.inject.po.json
index 56e15c2e..9ee4bd17 100644
--- a/test/data/sandbox/configs/definitions/codecept.inject.po.json
+++ b/test/data/sandbox/configs/definitions/codecept.inject.po.json
@@ -8,7 +8,8 @@
   "include": {
     "I": "../../support/custom_steps.js",
     "MyPage": "../../support/my_page.js",
-    "SecondPage": "../../support/second_page.js"
+    "SecondPage": "../../support/second_page.js",
+    "CurrentPage": "./po/custom_steps.js"
   },
   "bootstrap": false,
   "mocha": {},
diff --git a/test/data/sandbox/configs/definitions/po/custom_steps.js b/test/data/sandbox/configs/definitions/po/custom_steps.js
new file mode 100644
index 00000000..fcf5ee29
--- /dev/null
+++ b/test/data/sandbox/configs/definitions/po/custom_steps.js
@@ -0,0 +1,9 @@
+// Need for testing pages
+module.exports = () => {
+  return actor({
+    openDir() {
+      this.amInPath('.');
+    },
+  });
+};
+
diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js
index da5d3894..765914c6 100644
--- a/test/helper/Puppeteer_test.js
+++ b/test/helper/Puppeteer_test.js
@@ -50,6 +50,19 @@ describe('Puppeteer', function () {
     return I._after();
   });
 
+  describe('Session', () => {
+    it('should not fail for localStorage.clear() on about:blank', async () => {
+      I.options.restart = false;
+      return I.page.goto('about:blank')
+        .then(() => I._after())
+        .then(() => { I.options.restart = true; })
+        .catch((e) => {
+          I.options.restart = true;
+          throw new Error(e);
+        });
+    });
+  });
+
   describe('open page : #amOnPage', () => {
     it('should open main page of configured site', async () => {
       await I.amOnPage('/');
diff --git a/test/runner/definitions_test.js b/test/runner/definitions_test.js
index 38546052..0e4d1866 100644
--- a/test/runner/definitions_test.js
+++ b/test/runner/definitions_test.js
@@ -74,6 +74,21 @@ describe('Definitions', function () {
     });
   });
 
+  it('def should create definition file with correct page def', (done) => {
+    exec(`${runner} def --config ${codecept_dir}/codecept.inject.po.json`, (err, stdout) => {
+      stdout.should.include('Definitions were generated in steps.d.ts');
+      const types = typesFrom(`${codecept_dir}/steps.d.ts`);
+      types.should.be.valid;
+
+      const definitionFile = types.getSourceFileOrThrow(`${codecept_dir}/steps.d.ts`);
+      const extend = definitionFile.getFullText();
+
+      extend.should.include("type CurrentPage = typeof import('./po/custom_steps.js');");
+      assert(!err);
+      done();
+    });
+  });
+
   it('def should create definition file given a config file', (done) => {
     exec(`${runner} def --config ${codecept_dir}/../../codecept.ddt.json`, (err, stdout, stderr) => {
       stdout.should.include('Definitions were generated in steps.d.ts');