Repository: TheBrainFamily/cypress-cucumber-preprocessor
Pull request #391 (2020-06-15 17:15:20)

Add an issue template in an attempt to gather info more efficiently
Subject says it all.

Too many issues are reported with little to no possibility of reproducing the problem, at least not without significant effort.


Patch:
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..8a192d0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,28 @@
+<!-- Questions and request for general support may be closed at the maintainers
+discretion. -->
+
+<!-- Issue reports that are deemed unrelated to specifically preprocessing will
+be closed. -->
+
+### Current behavior
+
+<!-- A description including screenshots, stack traces, DEBUG logs, etc. -->
+
+### Desired behavior
+
+<!-- A clear description of what you want to happen. -->
+
+### Test code to reproduce
+
+<!-- Issues without a reproducible example or not enough information will be
+closed. -->
+
+<!-- We can only attempt to debug your issue if you provide us with a minimal
+example to reproduce the problem. This should preferably be another Git
+repository to be cloned -->
+
+### Versions
+
+* **Cypress version**:
+* **Preprocessor version**:
+* **Node version**:
diff --git a/README.md b/README.md
index 4ed9950..7ac0c15 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,6 @@ You can follow the documentation below, or if you prefer to hack on a working ex
   * [Smart tagging](#smart-tagging)
 * [How to run the tests](#excluding-tests)
   * [Running tagged tests](#running-tagged-tests)
-  * [Ignoring specific scenarios using tags when executing test runner](#ignoring-specific-scenarios-using-tags-when-executing-test-runner)
   * [Output](#output)
 * [IDE support](#ide-support)
   * [Webstorm](#webstorm)
@@ -85,9 +84,8 @@ Please make use of [cosmiconfig](https://github.com/davidtheclark/cosmiconfig) t
 
 Option | Default value | Description
 ------------ | ------------- | -------------
-commonPath | `cypress/integration/common` when `nonGlobalStepDefinitions` is true <br> `cypress/support/step_definitions` when `nonGlobalStepDefinitions` is false <br> `${nonGlobalStepBaseDir}/common` when `nonGlobalStepBaseDir` is defined | Define the path to a folder containing all common step definitions of your tests. When `nonGlobalStepBaseDir` is defined this path is defined from that base location. e.g `${nonGlobalStepBaseDir}/${commonPath}`.
-nonGlobalStepDefinitions | false | If true use the Cypress Cucumber Preprocessor Style pattern for placing step definitions files. If false, we will use the "oldschool" (everything is global) Cucumber style.
-nonGlobalStepBaseDir| undefined | If defined and `nonGlobalStepDefinitions` is also true then step definition searches for folders with the features name will start from the directory provided here. The cwd is already taken into account. e.g `test/step_definitions`.
+commonPath | `cypress/integration/common` when `nonGlobalStepDefinitions` is true <br> `cypress/support/step_definitions` when `nonGlobalStepDefinitions` is false | Define the path to a folder containing all common step definitions of your tests
+nonGlobalStepDefinitions | false | If true use the Cypress Cucumber Preprocessor Style pattern for placing step definitions files. If false, we will use the "oldschool" (everything is global) Cucumber style
 stepDefinitions | `cypress/integration` when `nonGlobalStepDefinitions` is true <br> `cypress/support/step_definitions` when `nonGlobalStepDefinitions` is false | Path to the folder containing our step definitions.
 
 ## How to organize the tests
@@ -329,28 +327,8 @@ Example:
 ```
 
 Please note - we use our own cypress-tags wrapper to speed things up.
-This wrapper calls the cypress executable from local modules and if not found it falls back to the globally installed one.
 For more details and examples please take a look to the [example repo](https://github.com/TheBrainFamily/cypress-cucumber-example).
 
-### Ignoring specific scenarios using tags when executing test runner
-You can also use tags to skip or ignore specific tests/scenarios when running cypress test runner (where you don't have the abilitiy to pass parameters like in the examples above for the execution)
-
-The trick consists in adding the "env" property with the "TAGS" subproperty in the cypress.json configuration file. It would look something like this:
-
-```javascript
-{
-    "env": {
-        "TAGS": "not @ignore"
-    },
-    //rest of configuration options
-    "baseUrl": "yourBaseUrl",       
-    "ignoreTestFiles": "*.js",
-    //etc
-}
-```
-
-Then, any scenarios tagged with @ignore will be skipped when running the tests using the cypress test runner
-
 ### Limiting to a subset of feature files
 You can use a glob expression to select which feature files should be included.
 
@@ -410,14 +388,6 @@ Note, that unlike WebStorm which will correctly identify multiple implementation
 
 ## TypeScript Support
 
-### Install
-
-Install the plug-in type definitions:
-
-```shell
-npm install --save-dev @types/cypress-cucumber-preprocessor
-```
-
 ### With Webpack
 You can also use a Webpack loader to process feature files (TypeScript supported). To see how it is done please take 
 a look here: [cypress-cucumber-webpack-typescript-example](https://github.com/TheBrainFamily/cypress-cucumber-webpack-typescript-example)
diff --git a/cypress-tags.js b/cypress-tags.js
index d23055e..60445f0 100755
--- a/cypress-tags.js
+++ b/cypress-tags.js
@@ -12,44 +12,32 @@ const debug = (message, ...rest) =>
     ? console.log(`DEBUG: ${message}`, rest.length ? rest : "")
     : null;
 
-function parseArgsOrDefault(argPrefix, defaultValue) {
-  const matchedArg = process.argv
-    .slice(2)
-    .find(arg => arg.includes(`${argPrefix}=`));
-
-  // Cypress requires env vars to be passed as comma separated list
-  // otherwise it only accepts the last provided variable,
-  // the way we replace here accomodates for that.
-  const argValue = matchedArg
-    ? matchedArg.replace(new RegExp(`.*${argPrefix}=`), "").replace(/,.*/, "")
-    : "";
-
-  return argValue !== "" ? argValue : defaultValue;
-}
-
 // TODO currently we only work with feature files in cypress/integration folder.
 // It should be easy to base this on the cypress.json configuration - we are happy to take a PR
 // here if you need this functionality!
 const defaultGlob = "cypress/integration/**/*.feature";
 
-const specGlob = parseArgsOrDefault("GLOB", defaultGlob);
-debug("Found glob", specGlob);
-const envTags = parseArgsOrDefault("TAGS", "");
-debug("Found tag expression", envTags);
+const specArg = process.argv.slice(2).find(arg => arg.indexOf("GLOB=") === 0);
+
+const specGlob = specArg ? specArg.replace(/.*=/, "") : defaultGlob;
+
+if (specArg) {
+  debug("Found glob", specGlob);
+}
 
 const paths = glob.sync(specGlob);
 
 const featuresToRun = [];
 
+const found = process.argv.slice(2).find(arg => arg.indexOf("TAGS=") === 0);
+
+const envTags = found.replace(/.*=/, "");
+debug("Found tag expression", envTags);
+
 paths.forEach(featurePath => {
   const spec = `${fs.readFileSync(featurePath)}`;
   const parsedFeature = new Parser().parse(spec);
 
-  if (!parsedFeature.feature) {
-    debug(`Feature: ${featurePath} is empty`);
-    return;
-  }
-
   const featureTags = parsedFeature.feature.tags;
   const featureShouldRun = shouldProceedCurrentStep(featureTags, envTags);
   const taggedScenarioShouldRun = parsedFeature.feature.children.some(
@@ -66,20 +54,12 @@ paths.forEach(featurePath => {
   }
 });
 
-function getOsSpecificExecutable(command) {
-  return process.platform === "win32" ? `${command}.cmd` : command;
-}
-
-function getCypressExecutable() {
-  const command = getOsSpecificExecutable(`${__dirname}/../.bin/cypress`);
-  // fallback to the globally installed cypress instead
-  return fs.existsSync(command) ? command : getOsSpecificExecutable("cypress");
-}
-
 try {
   if (featuresToRun.length || envTags === "") {
     execFileSync(
-      getCypressExecutable(),
+      process.platform === "win32"
+        ? `${__dirname}/../.bin/cypress.cmd`
+        : `${__dirname}/../.bin/cypress`,
       [...process.argv.slice(2), "--spec", featuresToRun.join(",")],
       {
         stdio: [process.stdin, process.stdout, process.stderr]
diff --git a/lib/cukejson/cucumberDataCollector.js b/lib/cukejson/cucumberDataCollector.js
index 002621a..55570a3 100644
--- a/lib/cukejson/cucumberDataCollector.js
+++ b/lib/cukejson/cucumberDataCollector.js
@@ -1,5 +1,5 @@
 const { Parser } = require("gherkin");
-const statuses = require("cucumber/lib/status").default;
+const statuses = require("cucumber").Status;
 
 class CucumberDataCollector {
   constructor(uri, spec) {
@@ -72,14 +72,6 @@ class CucumberDataCollector {
           status: statuses.UNDEFINED,
           duration: this.timeTaken()
         };
-      } else if (err.constructor.name === "Pending") {
-        // cypress marks skipped mocha tests as pending
-        // https://github.com/cypress-io/cypress/issues/3092
-        // don't record this error and mark the step as skipped
-        this.stepResults[this.currentStep] = {
-          status: statuses.SKIPPED,
-          duration: this.timeTaken()
-        };
       } else {
         this.stepResults[this.currentStep] = {
           status: statuses.FAILED,
@@ -130,13 +122,9 @@ class CucumberDataCollector {
       });
     };
     this.recordScenarioResult = scenario => {
-      const allSkipped = this.areAllStepsSkipped(scenario.name);
-      const anyFailed = this.anyStepsHaveFailed(scenario.name);
-      if (allSkipped) this.runTests[scenario.name].result = statuses.SKIPPED;
-      else
-        this.runTests[scenario.name].result = anyFailed
-          ? statuses.FAILED
-          : statuses.PASSED;
+      this.runTests[scenario.name].result = this.anyStepsHaveFailed(scenario)
+        ? statuses.FAILED
+        : statuses.PASSED;
     };
 
     this.setStepToPending = step => {
@@ -150,11 +138,8 @@ class CucumberDataCollector {
       };
     };
 
-    this.areAllStepsSkipped = name =>
-      this.runTests[name].every(e => e.status === statuses.SKIPPED);
-
-    this.anyStepsHaveFailed = name =>
-      this.runTests[name].find(e => e.status === statuses.FAILED) !== undefined;
+    this.anyStepsHaveFailed = () =>
+      Object.values(this.stepResults).find(e => e.status !== statuses.PASSED);
   }
 }
 
diff --git a/lib/cukejson/generateCucumberJson.js b/lib/cukejson/generateCucumberJson.js
index ad55bc7..f77de96 100644
--- a/lib/cukejson/generateCucumberJson.js
+++ b/lib/cukejson/generateCucumberJson.js
@@ -1,7 +1,6 @@
 const { EventEmitter } = require("events");
 const { generateEvents } = require("gherkin");
-const JsonFormatter = require("cucumber/lib/formatter/json_formatter").default;
-const formatterHelpers = require("cucumber/lib/formatter/helpers");
+const { JsonFormatter, formatterHelpers } = require("cucumber");
 
 function generateCucumberJson(state) {
   let output = "";
diff --git a/lib/getConfig.js b/lib/getConfig.js
deleted file mode 100644
index e3f5ca7..0000000
--- a/lib/getConfig.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const cosmiconfig = require("cosmiconfig");
-
-let explorer;
-
-exports.getConfig = () => {
-  if (!explorer) {
-    explorer = cosmiconfig("cypress-cucumber-preprocessor", {
-      sync: true,
-      rcExtensions: true
-    });
-  }
-
-  const loaded = explorer.load();
-  return loaded && loaded.config;
-};
diff --git a/lib/getCucumberJsonConfig.js b/lib/getCucumberJsonConfig.js
index 93e9226..4d27235 100644
--- a/lib/getCucumberJsonConfig.js
+++ b/lib/getCucumberJsonConfig.js
@@ -1,10 +1,14 @@
+const cosmiconfig = require("cosmiconfig");
 const log = require("debug")("cypress:cucumber");
-const { getConfig } = require("./getConfig");
 
 exports.getCucumberJsonConfig = () => {
-  const config = getConfig();
+  const explorer = cosmiconfig("cypress-cucumber-preprocessor", { sync: true });
+  const loaded = explorer.load();
+
   const cucumberJson =
-    config && config.cucumberJson ? config.cucumberJson : { generate: false };
+    loaded && loaded.config && loaded.config.cucumberJson
+      ? loaded.config.cucumberJson
+      : { generate: false };
   log("cucumber.json", JSON.stringify(cucumberJson));
 
   return cucumberJson;
diff --git a/lib/getStepDefinitionsPaths.js b/lib/getStepDefinitionsPaths.js
index 602ea44..d35401d 100644
--- a/lib/getStepDefinitionsPaths.js
+++ b/lib/getStepDefinitionsPaths.js
@@ -1,36 +1,21 @@
-const path = require("path");
 const glob = require("glob");
-const process = require("process");
-const { getConfig } = require("./getConfig");
+const cosmiconfig = require("cosmiconfig");
 const stepDefinitionPath = require("./stepDefinitionPath.js");
 const { getStepDefinitionPathsFrom } = require("./getStepDefinitionPathsFrom");
 
 const getStepDefinitionsPaths = filePath => {
-  const appRoot = process.cwd();
   let paths = [];
-  const config = getConfig();
-  if (config && config.nonGlobalStepDefinitions) {
-    let nonGlobalPath = getStepDefinitionPathsFrom(filePath);
-    let commonPath = config.commonPath || `${stepDefinitionPath()}/common/`;
-
-    if (config.commonPath) {
-      commonPath = path.resolve(appRoot, commonPath);
-    }
-
-    if (config.nonGlobalStepBaseDir) {
-      const stepBase = `${appRoot}/${config.nonGlobalStepBaseDir}`;
-      nonGlobalPath = nonGlobalPath.replace(stepDefinitionPath(), stepBase);
-      commonPath = `${nonGlobalPath}/${config.commonPath ||
-        `${stepBase}/common/`}`;
-    }
-
-    const nonGlobalPattern = `${nonGlobalPath}/**/*.+(js|ts)`;
-
+  const explorer = cosmiconfig("cypress-cucumber-preprocessor", { sync: true });
+  const loaded = explorer.load();
+  if (loaded && loaded.config && loaded.config.nonGlobalStepDefinitions) {
+    const nonGlobalPattern = `${getStepDefinitionPathsFrom(
+      filePath
+    )}/**/*.+(js|ts)`;
+    const commonPath =
+      loaded.config.commonPath || `${stepDefinitionPath()}/common/`;
     const commonDefinitionsPattern = `${commonPath}**/*.+(js|ts)`;
-    paths = paths.concat(
-      glob.sync(nonGlobalPattern),
-      glob.sync(commonDefinitionsPattern)
-    );
+    paths = paths.concat(glob.sync(nonGlobalPattern));
+    paths = paths.concat(glob.sync(commonDefinitionsPattern));
   } else {
     const pattern = `${stepDefinitionPath()}/**/*.+(js|ts)`;
     paths = paths.concat(glob.sync(pattern));
diff --git a/lib/index.js b/lib/index.js
index 0e55ada..76ffb4e 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -37,51 +37,24 @@ const touch = filename => {
 
 let watcher;
 
-// Include our transform in Browserify options
-const wrapOptions = options => {
-  let wrappedTransform;
-  if (
-    !options.browserifyOptions ||
-    !Array.isArray(options.browserifyOptions.transform)
-  ) {
-    wrappedTransform = [transform];
-  } else if (!options.browserifyOptions.transform.includes(transform)) {
-    wrappedTransform = [transform, ...options.browserifyOptions.transform];
-  } else {
-    wrappedTransform = options.browserifyOptions.transform;
+const preprocessor = (options = browserify.defaultOptions) => async file => {
+  if (options.browserifyOptions.transform.indexOf(transform) === -1) {
+    options.browserifyOptions.transform.unshift(transform);
   }
 
-  return {
-    ...options,
-    browserifyOptions: {
-      ...(options.browserifyOptions || {}),
-      transform: wrappedTransform
+  if (file.shouldWatch) {
+    if (watcher) {
+      watcher.close();
     }
-  };
-};
-
-const preprocessor = (options = browserify.defaultOptions) => {
-  if (typeof options !== "object") {
-    throw new Error("Preprocessor options must be an object");
+    watcher = chokidar
+      .watch([`${stepDefinitionPath()}*.js`, `${stepDefinitionPath()}*.ts`], {
+        ignoreInitial: true
+      })
+      .on("all", () => {
+        touch(file.filePath);
+      });
   }
-
-  const wrappedOptions = wrapOptions(options);
-
-  return async file => {
-    if (file.shouldWatch) {
-      if (watcher) {
-        watcher.close();
-      }
-      watcher = chokidar
-        .watch([`${stepDefinitionPath()}*.js`, `${stepDefinitionPath()}*.ts`], {
-          ignoreInitial: true
-        })
-        .on("all", () => {
-          touch(file.filePath);
-        });
-    }
-    return browserify(wrappedOptions)(file);
-  };
+  return browserify(options)(file);
 };
 
 module.exports = {
diff --git a/lib/isNonGlobalStepDefinitionsMode.js b/lib/isNonGlobalStepDefinitionsMode.js
index d7a53a7..11173c5 100644
--- a/lib/isNonGlobalStepDefinitionsMode.js
+++ b/lib/isNonGlobalStepDefinitionsMode.js
@@ -1,6 +1,7 @@
-const { getConfig } = require("./getConfig");
+const cosmiconfig = require("cosmiconfig");
 
 exports.isNonGlobalStepDefinitionsMode = () => {
-  const config = getConfig();
-  return config && config.nonGlobalStepDefinitions;
+  const explorer = cosmiconfig("cypress-cucumber-preprocessor", { sync: true });
+  const loaded = explorer.load();
+  return loaded && loaded.config && loaded.config.nonGlobalStepDefinitions;
 };
diff --git a/lib/resolveStepDefinition.js b/lib/resolveStepDefinition.js
index cb60207..83ef4f3 100644
--- a/lib/resolveStepDefinition.js
+++ b/lib/resolveStepDefinition.js
@@ -18,15 +18,7 @@ class StepDefinitionRegistry {
     };
 
     this.definitions = [];
-    this.runtime = (...args) => {
-      let matcher;
-      let config;
-      let implementation;
-      if (args.length > 2) {
-        [matcher, config, implementation] = args;
-      } else {
-        [matcher, implementation] = args;
-      }
+    this.runtime = (matcher, implementation) => {
       let expression;
       if (matcher instanceof RegExp) {
         expression = new RegularExpression(
@@ -43,7 +35,6 @@ class StepDefinitionRegistry {
       this.definitions.push({
         implementation,
         expression,
-        config,
         featureName: window.currentFeatureName || "___GLOBAL_EXECUTION___"
       });
     };
@@ -187,9 +178,6 @@ function parseHookArgs(args) {
 }
 
 module.exports = {
-  resolveStepDefinition(step, featureName) {
-    return resolveStepDefinition(step, featureName);
-  },
   resolveAndRunBeforeHooks(scenarioTags, featureName) {
     return resolveAndRunHooks(beforeHookRegistry, scenarioTags, featureName);
   },
@@ -222,20 +210,20 @@ module.exports = {
     }
     throw new Error(`Step implementation missing for: ${stepText}`);
   },
-  given: (...args) => {
-    stepDefinitionRegistry.runtime(...args);
+  given: (expression, implementation) => {
+    stepDefinitionRegistry.runtime(expression, implementation);
   },
-  when: (...args) => {
-    stepDefinitionRegistry.runtime(...args);
+  when: (expression, implementation) => {
+    stepDefinitionRegistry.runtime(expression, implementation);
   },
-  then: (...args) => {
-    stepDefinitionRegistry.runtime(...args);
+  then: (expression, implementation) => {
+    stepDefinitionRegistry.runtime(expression, implementation);
   },
-  and: (...args) => {
-    stepDefinitionRegistry.runtime(...args);
+  and: (expression, implementation) => {
+    stepDefinitionRegistry.runtime(expression, implementation);
   },
-  but: (...args) => {
-    stepDefinitionRegistry.runtime(...args);
+  but: (expression, implementation) => {
+    stepDefinitionRegistry.runtime(expression, implementation);
   },
   Before: (...args) => {
     const { tags, implementation } = parseHookArgs(args);
diff --git a/lib/stepDefinitionPath.js b/lib/stepDefinitionPath.js
index fb4a790..ffa9382 100644
--- a/lib/stepDefinitionPath.js
+++ b/lib/stepDefinitionPath.js
@@ -1,11 +1,15 @@
 const path = require("path");
+const cosmiconfig = require("cosmiconfig");
 const fs = require("fs");
-const { getConfig } = require("./getConfig");
 
 module.exports = () => {
   const appRoot = process.cwd();
-  const config = getConfig();
-  if (config) {
+
+  const explorer = cosmiconfig("cypress-cucumber-preprocessor", { sync: true });
+  const loaded = explorer.load();
+  if (loaded && loaded.config) {
+    const { config, filepath } = loaded;
+
     // left for backward compability, but we need the consistency with other configuration options
     const confStepDefinitions = config.step_definitions
       ? config.step_definitions
@@ -17,7 +21,7 @@ module.exports = () => {
 
       if (!fs.existsSync(stepsPath)) {
         throw new Error(
-          `We've tried to resolve your step definitions at ${relativePath}, but that doesn't seem to exist. As of version 2.0.0 it's required to set step_definitions in your cypress-cucumber-preprocessor configuration. Look for nonGlobalStepDefinitions and add stepDefinitions right next to it. It should match your cypress configuration has set for integrationFolder. We no longer rely on getting information from that file as it was unreliable and problematic across Linux/MacOS/Windows especially since the config file could have been passed as an argument to cypress.`
+          `We've tried to resolve your step definitions at ${relativePath}, but that doesn't seem to exist. As of version 2.0.0 it's required to set step_definitions in your cypress-cucumber-preprocessor configuration. Currently your configuration is in: ${filepath}. Look for nonGlobalStepDefinitions and add stepDefinitions right next to it. It should match your cypress configuration has set for integrationFolder. We no longer rely on getting information from that file as it was unreliable and problematic across Linux/MacOS/Windows especially since the config file could have been passed as an argument to cypress.`
         );
       }
       return stepsPath;
diff --git a/package-lock.json b/package-lock.json
index d17758b..24892de 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3144,6 +3144,24 @@
       "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
       "dev": true
     },
+    "align-text": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "kind-of": "^3.0.2",
+        "longest": "^1.0.1",
+        "repeat-string": "^1.5.2"
+      }
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "dev": true
+    },
     "ansi-escapes": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
@@ -4001,6 +4019,13 @@
       "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
       "dev": true
     },
+    "camelcase": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+      "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+      "dev": true,
+      "optional": true
+    },
     "camelcase-keys": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
@@ -4050,6 +4075,17 @@
       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
       "dev": true
     },
+    "center-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "align-text": "^0.1.3",
+        "lazy-cache": "^1.0.3"
+      }
+    },
     "chai": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
@@ -4511,6 +4547,27 @@
       "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
       "dev": true
     },
+    "cliui": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+      "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "center-align": "^0.1.1",
+        "right-align": "^0.1.1",
+        "wordwrap": "0.0.2"
+      },
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.2",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+          "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
     "co": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -7503,7 +7560,8 @@
         "ansi-regex": {
           "version": "2.1.1",
           "resolved": false,
-          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+          "optional": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -7524,12 +7582,14 @@
         "balanced-match": {
           "version": "1.0.0",
           "resolved": false,
-          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+          "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "resolved": false,
           "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -7544,17 +7604,20 @@
         "code-point-at": {
           "version": "1.1.0",
           "resolved": false,
-          "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+          "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+          "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "resolved": false,
-          "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+          "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+          "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "resolved": false,
-          "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+          "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+          "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -7671,7 +7734,8 @@
         "inherits": {
           "version": "2.0.3",
           "resolved": false,
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "optional": true
         },
         "ini": {
           "version": "1.3.5",
@@ -7683,6 +7747,7 @@
           "version": "1.0.0",
           "resolved": false,
           "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -7697,6 +7762,7 @@
           "version": "3.0.4",
           "resolved": false,
           "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -7704,12 +7770,14 @@
         "minimist": {
           "version": "0.0.8",
           "resolved": false,
-          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+          "optional": true
         },
         "minipass": {
           "version": "2.2.4",
           "resolved": false,
           "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
+          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.1",
             "yallist": "^3.0.0"
@@ -7728,6 +7796,7 @@
           "version": "0.5.1",
           "resolved": false,
           "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -7808,7 +7877,8 @@
         "number-is-nan": {
           "version": "1.0.1",
           "resolved": false,
-          "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+          "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+          "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -7820,6 +7890,7 @@
           "version": "1.4.0",
           "resolved": false,
           "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -7905,7 +7976,8 @@
         "safe-buffer": {
           "version": "5.1.1",
           "resolved": false,
-          "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+          "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+          "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -7941,6 +8013,7 @@
           "version": "1.0.2",
           "resolved": false,
           "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -7960,6 +8033,7 @@
           "version": "3.0.1",
           "resolved": false,
           "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -8003,12 +8077,14 @@
         "wrappy": {
           "version": "1.0.2",
           "resolved": false,
-          "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+          "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+          "optional": true
         },
         "yallist": {
           "version": "3.0.2",
           "resolved": false,
-          "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
+          "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
+          "optional": true
         }
       }
     },
@@ -8212,39 +8288,30 @@
       "dev": true
     },
     "handlebars": {
-      "version": "4.7.3",
-      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.3.tgz",
-      "integrity": "sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg==",
+      "version": "4.0.11",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
+      "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
       "dev": true,
       "requires": {
-        "neo-async": "^2.6.0",
+        "async": "^1.4.0",
         "optimist": "^0.6.1",
-        "source-map": "^0.6.1",
-        "uglify-js": "^3.1.4"
+        "source-map": "^0.4.4",
+        "uglify-js": "^2.6"
       },
       "dependencies": {
-        "commander": {
-          "version": "2.20.3",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-          "dev": true,
-          "optional": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+        "async": {
+          "version": "1.5.2",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+          "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
           "dev": true
         },
-        "uglify-js": {
-          "version": "3.7.7",
-          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.7.tgz",
-          "integrity": "sha512-FeSU+hi7ULYy6mn8PKio/tXsdSXN35lm4KgV2asx00kzrLU9Pi3oAslcJT70Jdj7PHX29gGUPOT6+lXGBbemhA==",
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
           "dev": true,
-          "optional": true,
           "requires": {
-            "commander": "~2.20.3",
-            "source-map": "~0.6.1"
+            "amdefine": ">=0.0.4"
           }
         }
       }
@@ -9485,17 +9552,34 @@
         "commander": {
           "version": "2.20.0",
           "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
-          "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
+          "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
+          "dev": true,
+          "optional": true
+        },
+        "handlebars": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
+          "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
+          "dev": true,
+          "requires": {
+            "neo-async": "^2.6.0",
+            "optimist": "^0.6.1",
+            "source-map": "^0.6.1",
+            "uglify-js": "^3.1.4"
+          }
         },
         "source-map": {
           "version": "0.6.1",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
         },
         "uglify-js": {
           "version": "3.6.0",
           "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
           "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
+          "dev": true,
+          "optional": true,
           "requires": {
             "commander": "~2.20.0",
             "source-map": "~0.6.1"
@@ -10372,7 +10456,8 @@
               "version": "2.1.1",
               "resolved": false,
               "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "aproba": {
               "version": "1.2.0",
@@ -10396,13 +10481,15 @@
               "version": "1.0.0",
               "resolved": false,
               "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "brace-expansion": {
               "version": "1.1.11",
               "resolved": false,
               "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
               "dev": true,
+              "optional": true,
               "requires": {
                 "balanced-match": "^1.0.0",
                 "concat-map": "0.0.1"
@@ -10419,19 +10506,22 @@
               "version": "1.1.0",
               "resolved": false,
               "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "concat-map": {
               "version": "0.0.1",
               "resolved": false,
               "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "console-control-strings": {
               "version": "1.1.0",
               "resolved": false,
               "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "core-util-is": {
               "version": "1.0.2",
@@ -10562,7 +10652,8 @@
               "version": "2.0.3",
               "resolved": false,
               "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "ini": {
               "version": "1.3.5",
@@ -10576,6 +10667,7 @@
               "resolved": false,
               "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
               "dev": true,
+              "optional": true,
               "requires": {
                 "number-is-nan": "^1.0.0"
               }
@@ -10592,6 +10684,7 @@
               "resolved": false,
               "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
               "dev": true,
+              "optional": true,
               "requires": {
                 "brace-expansion": "^1.1.7"
               }
@@ -10600,13 +10693,15 @@
               "version": "0.0.8",
               "resolved": false,
               "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "minipass": {
               "version": "2.3.5",
               "resolved": false,
               "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
               "dev": true,
+              "optional": true,
               "requires": {
                 "safe-buffer": "^5.1.2",
                 "yallist": "^3.0.0"
@@ -10627,6 +10722,7 @@
               "resolved": false,
               "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
               "dev": true,
+              "optional": true,
               "requires": {
                 "minimist": "0.0.8"
               }
@@ -10715,7 +10811,8 @@
               "version": "1.0.1",
               "resolved": false,
               "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "object-assign": {
               "version": "4.1.1",
@@ -10729,6 +10826,7 @@
               "resolved": false,
               "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
               "dev": true,
+              "optional": true,
               "requires": {
                 "wrappy": "1"
               }
@@ -10824,7 +10922,8 @@
               "version": "5.1.2",
               "resolved": false,
               "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "safer-buffer": {
               "version": "2.1.2",
@@ -10866,6 +10965,7 @@
               "resolved": false,
               "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
               "dev": true,
+              "optional": true,
               "requires": {
                 "code-point-at": "^1.0.0",
                 "is-fullwidth-code-point": "^1.0.0",
@@ -10887,6 +10987,7 @@
               "resolved": false,
               "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
               "dev": true,
+              "optional": true,
               "requires": {
                 "ansi-regex": "^2.0.0"
               }
@@ -10935,13 +11036,15 @@
               "version": "1.0.2",
               "resolved": false,
               "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-              "dev": true
+              "dev": true,
+              "optional": true
             },
             "yallist": {
               "version": "3.0.3",
               "resolved": false,
               "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
-              "dev": true
+              "dev": true,
+              "optional": true
             }
           }
         },
@@ -12220,6 +12323,13 @@
       "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=",
       "dev": true
     },
+    "lazy-cache": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+      "dev": true,
+      "optional": true
+    },
     "left-pad": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
@@ -13065,6 +13175,13 @@
         "cli-cursor": "^1.0.2"
       }
     },
+    "longest": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+      "dev": true,
+      "optional": true
+    },
     "loose-envify": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -13407,9 +13524,9 @@
       }
     },
     "minimist": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.3.tgz",
-      "integrity": "sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw=="
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
     },
     "minimist-options": {
       "version": "3.0.2",
@@ -18327,6 +18444,16 @@
       "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
       "dev": true
     },
+    "right-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "align-text": "^0.1.1"
+      }
+    },
     "right-pad": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz",
@@ -20295,6 +20422,40 @@
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
       "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
     },
+    "uglify-js": {
+      "version": "2.8.29",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+      "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "source-map": "~0.5.1",
+        "uglify-to-browserify": "~1.0.0",
+        "yargs": "~3.10.0"
+      },
+      "dependencies": {
+        "yargs": {
+          "version": "3.10.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+          "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "camelcase": "^1.0.2",
+            "cliui": "^2.1.0",
+            "decamelize": "^1.0.0",
+            "window-size": "0.1.0"
+          }
+        }
+      }
+    },
+    "uglify-to-browserify": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+      "dev": true,
+      "optional": true
+    },
     "umd": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz",
@@ -20625,7 +20786,8 @@
             },
             "ansi-regex": {
               "version": "2.1.1",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "aproba": {
               "version": "1.2.0",
@@ -20643,11 +20805,13 @@
             },
             "balanced-match": {
               "version": "1.0.0",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "brace-expansion": {
               "version": "1.1.11",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "balanced-match": "^1.0.0",
                 "concat-map": "0.0.1"
@@ -20660,15 +20824,18 @@
             },
             "code-point-at": {
               "version": "1.1.0",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "concat-map": {
               "version": "0.0.1",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "console-control-strings": {
               "version": "1.1.0",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "core-util-is": {
               "version": "1.0.2",
@@ -20771,7 +20938,8 @@
             },
             "inherits": {
               "version": "2.0.3",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "ini": {
               "version": "1.3.5",
@@ -20781,6 +20949,7 @@
             "is-fullwidth-code-point": {
               "version": "1.0.0",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "number-is-nan": "^1.0.0"
               }
@@ -20793,17 +20962,20 @@
             "minimatch": {
               "version": "3.0.4",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "brace-expansion": "^1.1.7"
               }
             },
             "minimist": {
               "version": "0.0.8",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "minipass": {
               "version": "2.3.5",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "safe-buffer": "^5.1.2",
                 "yallist": "^3.0.0"
@@ -20820,6 +20992,7 @@
             "mkdirp": {
               "version": "0.5.1",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "minimist": "0.0.8"
               }
@@ -20892,7 +21065,8 @@
             },
             "number-is-nan": {
               "version": "1.0.1",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "object-assign": {
               "version": "4.1.1",
@@ -20902,6 +21076,7 @@
             "once": {
               "version": "1.4.0",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "wrappy": "1"
               }
@@ -20977,7 +21152,8 @@
             },
             "safe-buffer": {
               "version": "5.1.2",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "safer-buffer": {
               "version": "2.1.2",
@@ -21007,6 +21183,7 @@
             "string-width": {
               "version": "1.0.2",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "code-point-at": "^1.0.0",
                 "is-fullwidth-code-point": "^1.0.0",
@@ -21024,6 +21201,7 @@
             "strip-ansi": {
               "version": "3.0.1",
               "bundled": true,
+              "optional": true,
               "requires": {
                 "ansi-regex": "^2.0.0"
               }
@@ -21062,11 +21240,13 @@
             },
             "wrappy": {
               "version": "1.0.2",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "yallist": {
               "version": "3.0.3",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             }
           }
         },
@@ -21156,6 +21336,13 @@
       "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
       "dev": true
     },
+    "window-size": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+      "dev": true,
+      "optional": true
+    },
     "windows-release": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.1.0.tgz",
diff --git a/steps/index.d.ts b/steps/index.d.ts
deleted file mode 100644
index 6ba7f82..0000000
--- a/steps/index.d.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-export function given(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function when(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function then(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function and(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function but(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function given(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function when(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function then(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function and(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function but(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function defineStep(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function defineParameterType(): void;
-
-// Aliased versions of the above funcs.
-export function Given(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function When(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function Then(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function And(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function But(
-  expression: RegExp | string,
-  implementation: (...args: any[]) => void
-): void;
-export function Given(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function When(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function Then(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function And(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function But(
-  expression: RegExp | string,
-  config: { timeout?: number },
-  implementation: (...args: any[]) => void
-): void;
-export function Before(
-  optionsOrImplementation: object | ((...args: any[]) => void),
-  implementation?: (...args: any[]) => void
-): void;
-export function After(
-  optionsOrImplementation: object | ((...args: any[]) => void),
-  implementation?: (...args: any[]) => void
-): void;


Test patch:
diff --git a/lib/createTestFromScenario.js b/lib/createTestFromScenario.js
index 0be1e41..6086a4a 100644
--- a/lib/createTestFromScenario.js
+++ b/lib/createTestFromScenario.js
@@ -1,7 +1,6 @@
 /* eslint-disable prefer-template */
-const statuses = require("cucumber/lib/status").default;
+const statuses = require("cucumber").Status;
 const {
-  resolveStepDefinition,
   resolveAndRunStepDefinition,
   resolveAndRunBeforeHooks,
   resolveAndRunAfterHooks
@@ -16,13 +15,8 @@ const replaceParameterTags = (rowData, text) =>
 
 // eslint-disable-next-line func-names
 const stepTest = function(state, stepDetails, exampleRowData) {
-  const step = resolveStepDefinition.call(
-    this,
-    stepDetails,
-    state.feature.name
-  );
   cy.then(() => state.onStartStep(stepDetails))
-    .then((step && step.config) || {}, () =>
+    .then(() =>
       resolveAndRunStepDefinition.call(
         this,
         stepDetails,
@@ -39,42 +33,22 @@ const runTest = (scenario, stepsToRun, rowData) => {
     Object.assign({}, step, { index })
   );
 
-  // should we actually run this scenario
-  // or just mark it as skipped
-  if (scenario.shouldRun) {
-    // eslint-disable-next-line func-names
-    it(scenario.name, function() {
-      const state = window.testState;
-      return cy
-        .then(() => state.onStartScenario(scenario, indexedSteps))
-        .then(() =>
-          resolveAndRunBeforeHooks.call(this, scenario.tags, state.feature.name)
-        )
-        .then(() =>
-          indexedSteps.forEach(step =>
-            stepTest.call(this, state, step, rowData)
-          )
-        )
-        .then(() =>
-          resolveAndRunAfterHooks.call(this, scenario.tags, state.feature.name)
-        )
-        .then(() => state.onFinishScenario(scenario));
-    });
-  } else {
-    // eslint-disable-next-line func-names,prefer-arrow-callback
-    it(scenario.name, function() {
-      // register this scenario with the cucumber data collector
-      // but don't run it
-      // Tell mocha this is a skipped test so it also shows correctly in Cypress
-      const state = window.testState;
-      cy.then(() => state.onStartScenario(scenario, indexedSteps))
-        .then(() => state.onFinishScenario(scenario))
-        // eslint-disable-next-line func-names
-        .then(function() {
-          return this.skip();
-        });
-    });
-  }
+  // eslint-disable-next-line func-names
+  it(scenario.name, function() {
+    const state = window.testState;
+    return cy
+      .then(() => state.onStartScenario(scenario, indexedSteps))
+      .then(() =>
+        resolveAndRunBeforeHooks.call(this, scenario.tags, state.feature.name)
+      )
+      .then(() =>
+        indexedSteps.forEach(step => stepTest.call(this, state, step, rowData))
+      )
+      .then(() =>
+        resolveAndRunAfterHooks.call(this, scenario.tags, state.feature.name)
+      )
+      .then(() => state.onFinishScenario(scenario));
+  });
 };
 
 const cleanupFilename = s => s.split(".")[0];
@@ -90,7 +64,7 @@ const writeCucumberJsonFile = json => {
 };
 
 const createTestFromScenarios = (
-  allScenarios,
+  scenariosToRun,
   backgroundSection,
   testState
 ) => {
@@ -113,7 +87,7 @@ const createTestFromScenarios = (
     Cypress.on("fail", failHandler);
   });
 
-  allScenarios.forEach(section => {
+  scenariosToRun.forEach(section => {
     if (section.examples) {
       section.examples.forEach(example => {
         const exampleValues = [];
diff --git a/lib/createTestsFromFeature.js b/lib/createTestsFromFeature.js
index caa4272..a5bc69a 100644
--- a/lib/createTestsFromFeature.js
+++ b/lib/createTestsFromFeature.js
@@ -6,37 +6,58 @@ const createTestsFromFeature = (filePath, spec) => {
   const testState = new CucumberDataCollector(filePath, spec);
   const featureTags = testState.feature.tags;
   const hasEnvTags = !!getEnvTags();
-  const anyFocused =
-    testState.feature.children.filter(
-      section => section.tags && section.tags.find(t => t.name === "@focus")
-    ).length > 0;
-  const backgroundSection = testState.feature.children.find(
-    section => section.type === "Background"
-  );
-  const allScenarios = testState.feature.children.filter(
-    section => section.type !== "Background"
+  const sectionsWithTags = testState.feature.children.filter(
+    section => section.tags && section.tags.length
   );
 
-  const scenariosToRun = allScenarios.filter(section => {
-    let shouldRun;
-    // only just run focused if no env tags set
-    // https://github.com/TheBrainFamily/cypress-cucumber-example#smart-tagging
-    if (!hasEnvTags && anyFocused) {
-      shouldRun = section.tags.find(t => t.name === "@focus");
+  const sectionsWithTagsExist = sectionsWithTags.length > 0;
+
+  let everythingShouldRun = false;
+  let featureShouldRun = false;
+  let taggedScenarioShouldRun = false;
+  let anyFocused = false;
+  if (hasEnvTags) {
+    featureShouldRun = shouldProceedCurrentStep(featureTags);
+    taggedScenarioShouldRun = testState.feature.children.some(
+      section =>
+        section.tags &&
+        section.tags.length &&
+        shouldProceedCurrentStep(section.tags.concat(featureTags))
+    );
+  } else if (!sectionsWithTagsExist) {
+    everythingShouldRun = true;
+  } else {
+    anyFocused = sectionsWithTags.some(section =>
+      section.tags.find(t => t.name === "@focus")
+    );
+    if (anyFocused) {
+      taggedScenarioShouldRun = true;
     } else {
-      shouldRun =
-        !hasEnvTags ||
-        shouldProceedCurrentStep(section.tags.concat(featureTags)); // Concat handles inheritance of tags from feature
+      everythingShouldRun = true;
     }
-    return shouldRun;
-  });
-  // create tests for all the scenarios
-  // but flag only the ones that should be run
-  scenariosToRun.forEach(section => {
-    // eslint-disable-next-line no-param-reassign
-    section.shouldRun = true;
-  });
-  createTestFromScenarios(allScenarios, backgroundSection, testState);
+  }
+
+  // eslint-disable-next-line prefer-arrow-callback
+  if (everythingShouldRun || featureShouldRun || taggedScenarioShouldRun) {
+    const backgroundSection = testState.feature.children.find(
+      section => section.type === "Background"
+    );
+    const otherSections = testState.feature.children.filter(
+      section => section.type !== "Background"
+    );
+    const scenariosToRun = otherSections.filter(section => {
+      let shouldRun;
+      if (anyFocused) {
+        shouldRun = section.tags.find(t => t.name === "@focus");
+      } else {
+        shouldRun =
+          everythingShouldRun ||
+          shouldProceedCurrentStep(section.tags.concat(featureTags)); // Concat handles inheritance of tags from feature
+      }
+      return shouldRun;
+    });
+    createTestFromScenarios(scenariosToRun, backgroundSection, testState);
+  }
 };
 
 module.exports = {
diff --git a/lib/cukejson/cucumberDataCollector.test.js b/lib/cukejson/cucumberDataCollector.test.js
index 7f68f64..272f837 100644
--- a/lib/cukejson/cucumberDataCollector.test.js
+++ b/lib/cukejson/cucumberDataCollector.test.js
@@ -1,5 +1,5 @@
 const fs = require("fs");
-const statuses = require("cucumber/lib/status").default;
+const statuses = require("cucumber").Status;
 const { CucumberDataCollector } = require("./cucumberDataCollector");
 const { generateCucumberJson } = require("./generateCucumberJson");
 
diff --git a/lib/getStepDefinitionsPaths.test.js b/lib/getStepDefinitionsPaths.test.js
index 4c65a43..34c3e70 100644
--- a/lib/getStepDefinitionsPaths.test.js
+++ b/lib/getStepDefinitionsPaths.test.js
@@ -1,4 +1,3 @@
-/* eslint-disable global-require */
 jest.mock("./stepDefinitionPath.js", () => () => "stepDefinitionPath");
 jest.mock("glob", () => ({
   sync(pattern) {
@@ -6,76 +5,40 @@ jest.mock("glob", () => ({
   }
 }));
 
-let getConfig;
-
 describe("getStepDefinitionsPaths", () => {
-  beforeEach(() => {
-    jest.resetModules();
-    ({ getConfig } = require("./getConfig"));
-    jest.unmock("path");
-    jest.mock("./getConfig");
-  });
   it("should return the default common folder", () => {
-    getConfig.mockReturnValue({
-      nonGlobalStepDefinitions: true
-    });
-
+    jest.resetModules();
+    jest.mock("cosmiconfig", () => () => ({
+      load: () => ({
+        config: {
+          nonGlobalStepDefinitions: true
+        }
+      })
+    }));
+    // eslint-disable-next-line global-require
     const { getStepDefinitionsPaths } = require("./getStepDefinitionsPaths");
 
     const actual = getStepDefinitionsPaths("/path");
     const expected = "stepDefinitionPath/common/**/*.+(js|ts)";
-    expect(actual).to.include(expected);
-  });
-
-  it("should return the common folder defined by the developer", () => {
-    jest.mock("path", () => ({
-      resolve(appRoot, commonPath) {
-        return `./${appRoot}/${commonPath}`;
-      },
-      extname() {
-        return ".js";
-      }
-    }));
-
-    jest.spyOn(process, "cwd").mockImplementation(() => "cwd");
 
-    getConfig.mockReturnValue({
-      nonGlobalStepDefinitions: true,
-      commonPath: "myPath/"
-    });
-
-    const { getStepDefinitionsPaths } = require("./getStepDefinitionsPaths");
-
-    const actual = getStepDefinitionsPaths("/path");
-    const expected = "./cwd/myPath/**/*.+(js|ts)";
     expect(actual).to.include(expected);
   });
-  it("should return the default non global step definition pattern", () => {
-    getConfig.mockReturnValue({
-      nonGlobalStepDefinitions: true
-    });
+  it("should return the common folder defined by the developper", () => {
+    jest.resetModules();
+    jest.mock("cosmiconfig", () => () => ({
+      load: () => ({
+        config: {
+          nonGlobalStepDefinitions: true,
+          commonPath: "myPath/"
+        }
+      })
+    }));
     // eslint-disable-next-line global-require
     const { getStepDefinitionsPaths } = require("./getStepDefinitionsPaths");
-    const path = "stepDefinitionPath/test.feature";
-    const actual = getStepDefinitionsPaths(path);
-    const expected = "stepDefinitionPath/test/**/*.+(js|ts)";
 
-    expect(actual).to.include(expected);
-  });
-
-  it("should return the overriden non global step definition pattern if nonGlobalStepBaseDir is defined", () => {
-    jest.spyOn(process, "cwd").mockImplementation(() => "cwd");
-    getConfig.mockReturnValue({
-      nonGlobalStepDefinitions: true,
-      nonGlobalStepBaseDir: "nonGlobalStepBaseDir"
-    });
-    // eslint-disable-next-line global-require
-    const { getStepDefinitionsPaths } = require("./getStepDefinitionsPaths");
-    const path = "stepDefinitionPath/test.feature";
-    const actual = getStepDefinitionsPaths(path);
-    const expected = "cwd/nonGlobalStepBaseDir/test/**/*.+(js|ts)";
+    const actual = getStepDefinitionsPaths("/path");
+    const expected = "myPath/**/*.+(js|ts)";
 
     expect(actual).to.include(expected);
-    expect(actual).to.not.include("stepDefinitionPath/test/**/*.+(js|ts)");
   });
 });
diff --git a/lib/index.test.js b/lib/index.test.js
deleted file mode 100644
index e5d8013..0000000
--- a/lib/index.test.js
+++ /dev/null
@@ -1,98 +0,0 @@
-const browserify = require("@cypress/browserify-preprocessor");
-const { default: preprocessor, transform } = require(".");
-
-jest.mock("@cypress/browserify-preprocessor");
-const { defaultOptions } = jest.requireActual(
-  "@cypress/browserify-preprocessor"
-);
-
-describe("Preprocessor", () => {
-  beforeEach(() => {
-    browserify.defaultOptions = defaultOptions;
-    browserify.mockReturnValue(() => {});
-  });
-
-  afterEach(() => {
-    browserify.mockClear();
-  });
-
-  it("should use Cypress browserify options by default", async () => {
-    await preprocessor()({ shouldWatch: false });
-
-    global.jestExpect(browserify).toHaveBeenCalledWith({
-      ...defaultOptions,
-      browserifyOptions: {
-        ...defaultOptions.browserifyOptions,
-        transform: [transform, ...defaultOptions.browserifyOptions.transform]
-      }
-    });
-  });
-
-  it("should add transform when other transforms are defined in options", async () => {
-    await preprocessor({
-      browserifyOptions: {
-        transform: ["babelify"]
-      }
-    })({ shouldWatch: false });
-
-    global.jestExpect(browserify).toHaveBeenCalledWith({
-      browserifyOptions: {
-        transform: [transform, "babelify"]
-      }
-    });
-  });
-
-  it("should preserve transforms in options when our transform is already included", async () => {
-    const options = {
-      browserifyOptions: {
-        extensions: ["js", "ts"],
-        plugins: [["tsify"]],
-        transform: ["aliasify", transform, "babelify"]
-      }
-    };
-
-    await preprocessor(options)({ shouldWatch: false });
-
-    global.jestExpect(browserify).toHaveBeenCalledWith(options);
-  });
-
-  it("should add our transform when no other transforms are defined in options", async () => {
-    const options = {
-      browserifyOptions: {
-        extensions: ["js", "ts"],
-        plugins: [["tsify"]]
-      }
-    };
-
-    await preprocessor(options)({ shouldWatch: false });
-
-    global.jestExpect(browserify).toHaveBeenCalledWith({
-      ...options,
-      browserifyOptions: {
-        ...options.browserifyOptions,
-        transform: [transform]
-      }
-    });
-  });
-
-  it("should add our transform when browserifyOptions property is not passed to options", async () => {
-    const options = { unsupported: true };
-
-    await preprocessor(options)({ shouldWatch: false });
-
-    global.jestExpect(browserify).toHaveBeenCalledWith({
-      ...options,
-      browserifyOptions: {
-        transform: [transform]
-      }
-    });
-  });
-
-  it("should fail gracefully when options is not an object", () => {
-    const err = new Error("Preprocessor options must be an object");
-
-    global.jestExpect(() => preprocessor("options")).toThrow(err);
-    global.jestExpect(() => preprocessor(1)).toThrow(err);
-    global.jestExpect(() => preprocessor(false)).toThrow(err);
-  });
-});
diff --git a/lib/stepDefinitionPath.test.js b/lib/stepDefinitionPath.test.js
index f88cd5c..f4402a0 100644
--- a/lib/stepDefinitionPath.test.js
+++ b/lib/stepDefinitionPath.test.js
@@ -1,46 +1,66 @@
 const fs = require("fs");
-const { getConfig } = require("./getConfig");
-const stepDefinitionPath = require("./stepDefinitionPath");
+const cosmiconfig = require("cosmiconfig");
+const stepDefinitionPath = require("./stepDefinitionPath.js");
 
-jest.mock("./getConfig");
 jest.mock("fs", () => ({
   existsSync: jest.fn()
 }));
 
+jest.mock("cosmiconfig");
+
 const defaultNonGlobalStepDefinitionsPath = "cypress/integration";
 
 describe("load path from step definitions", () => {
   beforeEach(() => {
-    getConfig.mockReset();
+    cosmiconfig.mockReset();
     fs.existsSync.mockReset();
   });
 
   test("Should throw an error if nonGlobalStepDefinitions and stepDefinitions are not set and the default is wrong", () => {
-    getConfig.mockReturnValue({
-      nonGlobalStepDefinitions: true
+    const COMICONFIG_FILEPATH = "package.json";
+    const loadMock = jest.fn().mockReturnValue({
+      config: {
+        nonGlobalStepDefinitions: true
+      },
+      filepath: COMICONFIG_FILEPATH
+    });
+    cosmiconfig.mockReturnValue({
+      load: loadMock
     });
     fs.existsSync.mockReturnValue(false);
 
-    const errorMessage = `We've tried to resolve your step definitions at ${defaultNonGlobalStepDefinitionsPath}, but that doesn't seem to exist. As of version 2.0.0 it's required to set step_definitions in your cypress-cucumber-preprocessor configuration. Look for nonGlobalStepDefinitions and add stepDefinitions right next to it. It should match your cypress configuration has set for integrationFolder. We no longer rely on getting information from that file as it was unreliable and problematic across Linux/MacOS/Windows especially since the config file could have been passed as an argument to cypress.`;
+    const errorMessage = `We've tried to resolve your step definitions at ${defaultNonGlobalStepDefinitionsPath}, but that doesn't seem to exist. As of version 2.0.0 it's required to set step_definitions in your cypress-cucumber-preprocessor configuration. Currently your configuration is in: ${COMICONFIG_FILEPATH}. Look for nonGlobalStepDefinitions and add stepDefinitions right next to it. It should match your cypress configuration has set for integrationFolder. We no longer rely on getting information from that file as it was unreliable and problematic across Linux/MacOS/Windows especially since the config file could have been passed as an argument to cypress.`;
     expect(stepDefinitionPath).throw(errorMessage);
   });
 
   test("Should throw an error if nonGlobalStepDefinitions and stepDefinitions are set but the folder doesn't exist", () => {
+    const COMICONFIG_FILEPATH = "package.json";
     const stepDefinitions = "cypress/stepDefinitions";
-    getConfig.mockReturnValue({
-      nonGlobalStepDefinitions: true,
-      stepDefinitions
+    const loadMock = jest.fn().mockReturnValue({
+      config: {
+        nonGlobalStepDefinitions: true,
+        stepDefinitions
+      },
+      filepath: COMICONFIG_FILEPATH
+    });
+    cosmiconfig.mockReturnValue({
+      load: loadMock
     });
     fs.existsSync.mockReturnValue(false);
 
-    const errorMessage = `We've tried to resolve your step definitions at ${stepDefinitions}, but that doesn't seem to exist. As of version 2.0.0 it's required to set step_definitions in your cypress-cucumber-preprocessor configuration. Look for nonGlobalStepDefinitions and add stepDefinitions right next to it. It should match your cypress configuration has set for integrationFolder. We no longer rely on getting information from that file as it was unreliable and problematic across Linux/MacOS/Windows especially since the config file could have been passed as an argument to cypress.`;
+    const errorMessage = `We've tried to resolve your step definitions at ${stepDefinitions}, but that doesn't seem to exist. As of version 2.0.0 it's required to set step_definitions in your cypress-cucumber-preprocessor configuration. Currently your configuration is in: ${COMICONFIG_FILEPATH}. Look for nonGlobalStepDefinitions and add stepDefinitions right next to it. It should match your cypress configuration has set for integrationFolder. We no longer rely on getting information from that file as it was unreliable and problematic across Linux/MacOS/Windows especially since the config file could have been passed as an argument to cypress.`;
     expect(stepDefinitionPath).throw(errorMessage);
   });
 
   test("should use the default stepDefinitions path for nonGlobalStepDefinitions", () => {
     const appRoot = process.cwd();
-    getConfig.mockReturnValue({
-      nonGlobalStepDefinitions: true
+    const loadMock = jest.fn().mockReturnValue({
+      config: {
+        nonGlobalStepDefinitions: true
+      }
+    });
+    cosmiconfig.mockReturnValue({
+      load: loadMock
     });
     fs.existsSync.mockReturnValue(true);
 
@@ -51,9 +71,16 @@ describe("load path from step definitions", () => {
 
   test("should use the stepDefinitions path for nonGlobalStepDefinitions", () => {
     const appRoot = process.cwd();
-    getConfig.mockReturnValue({
-      step_definitions: "./e2e/support/step-definitions"
+    const loadMock = jest.fn().mockReturnValue({
+      config: {
+        stepDefinitions: "./e2e/support/step-definitions",
+        nonGlobalStepDefinitions: true
+      }
+    });
+    cosmiconfig.mockReturnValue({
+      load: loadMock
     });
+    fs.existsSync.mockReturnValue(true);
 
     expect(stepDefinitionPath()).to.equal(
       `${appRoot}/e2e/support/step-definitions`
@@ -62,9 +89,15 @@ describe("load path from step definitions", () => {
 
   test("should use the stepDefinitions path", () => {
     const appRoot = process.cwd();
-    getConfig.mockReturnValue({
-      step_definitions: "./e2e/support/step-definitions"
+    const loadMock = jest.fn().mockReturnValue({
+      config: {
+        stepDefinitions: "./e2e/support/step-definitions"
+      }
     });
+    cosmiconfig.mockReturnValue({
+      load: loadMock
+    });
+    fs.existsSync.mockReturnValue(true);
 
     expect(stepDefinitionPath()).to.equal(
       `${appRoot}/e2e/support/step-definitions`
@@ -73,6 +106,10 @@ describe("load path from step definitions", () => {
 
   test("should return default path if stepDefinition are not configured and nonGlobalStepDefinitions are not set", () => {
     const appRoot = process.cwd();
+    cosmiconfig.mockReturnValue({
+      load: jest.fn()
+    });
+
     expect(stepDefinitionPath()).to.equal(
       `${appRoot}/cypress/support/step_definitions`
     );
@@ -80,9 +117,15 @@ describe("load path from step definitions", () => {
 
   test("should allow the backward compatible use of step_definitions in cosmiconfig", () => {
     const appRoot = process.cwd();
-    getConfig.mockReturnValue({
-      step_definitions: "./e2e/support/step-definitions"
+    const loadMock = jest.fn().mockReturnValue({
+      config: {
+        step_definitions: "./e2e/support/step-definitions"
+      }
+    });
+    cosmiconfig.mockReturnValue({
+      load: loadMock
     });
+    fs.existsSync.mockReturnValue(true);
 
     expect(stepDefinitionPath()).to.equal(
       `${appRoot}/e2e/support/step-definitions`
diff --git a/lib/testHelpers/setupTestFramework.js b/lib/testHelpers/setupTestFramework.js
index c14b32d..a636dbb 100644
--- a/lib/testHelpers/setupTestFramework.js
+++ b/lib/testHelpers/setupTestFramework.js
@@ -3,7 +3,6 @@ global.expect = require("chai").expect;
 
 global.before = jest.fn();
 global.after = jest.fn();
-global.skip = jest.fn();
 
 window.Cypress = {
   env: jest.fn(),
@@ -25,18 +24,9 @@ const {
   After
 } = require("../resolveStepDefinition");
 
-const mockedThen = (funcOrConfig, func) => {
-  if (typeof funcOrConfig === "object") {
-    func();
-  } else {
-    funcOrConfig();
-  }
-  return { then: mockedThen };
-};
-
 const mockedPromise = func => {
   func();
-  return { then: mockedThen };
+  return { then: mockedPromise };
 };
 
 window.defineParameterType = defineParameterType;
@@ -56,6 +46,6 @@ window.cy = {
   startStep: mockedPromise,
   finishStep: mockedPromise,
   finishTest: mockedPromise,
-  then: mockedThen,
+  then: mockedPromise,
   end: mockedPromise
 };