Repository: Codeception/CodeceptJS (js)

Issue:
Helper _init() hook is called twice after upgrade to 1.1.7
#### What are you trying to achieve?
Initialize a helper.
#### What do you get instead?
Helper _init() hook is called twice, once before bootstrap and again after. Before upgrading it was only called once, before bootstrap. This change broke our suite initialization that relied on this particular sequence.
### Details

* CodeceptJS version: 1.1.7
* NodeJS Version: 8.2.1
* Operating System: MacOS 10.12.6
* WebDriverIO
* Configuration file:

```js
exports.config = {
  bootstrap,
  name: '...',
  mocha: {},
  tests: './{,+(bin|core|features|app_modules)/**/tests/acceptance/}*.acctests.js',
  output: './acceptanceScreenshots',
  timeout: 20000,
  // custom settings.
  customSettings: {
  ...
  },
  helpers: {
    WebDriverIO: {
      url: appUrl,
      browser: 'chrome',
      windowSize: '1024x1000',
      restart: false,
      keepCookies: false,
      manualStart: true
    },
    FileSystem: {},
    REST: {
      endpoint: apiUrl,
      resetHeaders: true,
    },
    ApiDataFactory: {
      endpoint: apiUrl,
      cleanup: true,
      factories: {
      ...
      },
      REST: {
        resetHeaders: true
      }
    },
    AppHelper: {
      require: './app_modules/acceptanceTest/appHelper.js'
    },
   ...
  },
  include: {
    // Misc app components/pages
   ...
  }
```
Thank you.

Pull request:
Removed double call to Helper._init
fixes #1036

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5fac5453..d4fe9eae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,7 @@ locate('//table')
 * Added `event.test.finished` which fires synchronously for both failed and passed tests.
 * [WebDriverIO][Protractor][Nightmare][Puppeteer] Full page screenshots on failure disabled by default. See [issue #1600](https://github.com/Codeception/CodeceptJS/issues/1060). You can enabled them with `fullPageScreenshots: true`, however they may work unstable in Selenium.
 * `within` blocks can return values. See [updated documentation](https://codecept.io/basics/#within).
+* Removed doublt call to `_init` in helpers. Fixes issue [#1036](https://github.com/Codeception/CodeceptJS/issues/1036)
 * Added scenario and feature configuration via fluent API:
 
 ```js
diff --git a/bin/codecept.js b/bin/codecept.js
index 93b47a3e..bd612db2 100755
--- a/bin/codecept.js
+++ b/bin/codecept.js
@@ -3,10 +3,18 @@ const program = require('commander');
 const path = require('path');
 const Config = require('../lib/config');
 const Codecept = require('../lib/codecept');
-const print = require('../lib/output');
+const { print, error } = require('../lib/output');
 const fileExists = require('../lib/utils').fileExists;
 const fs = require('fs');
 
+if (process.versions.node && process.versions.node.split('.') && process.versions.node.split('.')[0] < 8) {
+  error('NodeJS >= 8 is required to run.');
+  print();
+  print('Please upgrade your NodeJS engine');
+  print(`Current NodeJS version: ${process.version}`);
+  process.exit(1);
+}
+
 program.command('init [path]')
   .description('Creates dummy config in current dir or [path]')
   .action(require('../lib/command/init'));
diff --git a/lib/command/init.js b/lib/command/init.js
index 5828b140..55899239 100644
--- a/lib/command/init.js
+++ b/lib/command/init.js
@@ -165,6 +165,10 @@ module.exports = function (initPath) {
         success(`Steps file created at ${stepFile}`);
       }
 
+      if (!result.helpers.length) {
+        error('Warning: No helpers were selected, please add them manually by editing config');
+      }
+
       fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
       success(`Config created at ${configFile}`);
 
diff --git a/lib/listener/helpers.js b/lib/listener/helpers.js
index dd2bf971..1a3e7806 100644
--- a/lib/listener/helpers.js
+++ b/lib/listener/helpers.js
@@ -22,10 +22,6 @@ module.exports = function () {
     });
   };
 
-  event.dispatcher.on(event.all.before, () => {
-    runHelpersHook('_init');
-  });
-
   event.dispatcher.on(event.suite.before, (suite) => {
     runAsyncHelpersHook('_beforeSuite', suite, true);
   });


Test patch:
diff --git a/test/data/helper.js b/test/data/helper.js
index 5cc650b5..c426266e 100644
--- a/test/data/helper.js
+++ b/test/data/helper.js
@@ -5,6 +5,10 @@ class MyHelper extends Helper {
     return 'hello world';
   }
 
+  _init() {
+    console.log('Helper: I\'m initialized');
+  }
+
   _beforeSuite() {
     console.log('Helper: I\'m simple BeforeSuite hook');
   }
diff --git a/test/runner/codecept_test.js b/test/runner/codecept_test.js
index b0478307..a34f66d0 100644
--- a/test/runner/codecept_test.js
+++ b/test/runner/codecept_test.js
@@ -98,7 +98,12 @@ describe('CodeceptJS Runner', () => {
     exec(codecept_run_config('codecept.testhooks.json'), (err, stdout) => {
       const lines = stdout.match(/\S.+/g);
 
+      const uniqueLines = lines.filter((v, i, a) => a.indexOf(v) === i);
+
+      expect(uniqueLines.length).to.eql(lines.length, `No duplicates in output +${lines} \n\n -${uniqueLines}`);
+
       expect(lines).to.include.members([
+        'Helper: I\'m initialized',
         'Helper: I\'m simple BeforeSuite hook',
         'Test: I\'m simple BeforeSuite hook',
         'Test: I\'m generator BeforeSuite hook',
@@ -116,6 +121,7 @@ describe('CodeceptJS Runner', () => {
         'Test: I\'m async/await AfterSuite hook',
         'Helper: I\'m simple AfterSuite hook',
       ]);
+
       stdout.should.include('OK  | 1 passed');
       assert(!err);
       done();