Repository: TheBrainFamily/cypress-cucumber-preprocessor (js)

Issue:
[feature request] use tags for example tables for scenarios with more example tables
When I have a scenario with more example tables with different tags:
```
Scenario Outline: Test example
  Given Step with <param1>
  When Step with <param2>
  Then Result is <result>

@smoke
Examples:
| param1 | param2 | result |
| foo    | bar    | foobar |
| 1      | 2      | 3      |

@regression
Examples:
| param1 | param2 | result |
| abc    | def    | abcdef |
| z      | y      | z      |
```
I would like to run only those examples that are tagged with specific tag, for example `@smoke`.
This is possible with pure [cucumber-js](https://github.com/cucumber/cucumber-js/blob/master/docs/cli.md#tags), do they use different [tag-expressions](https://github.com/cucumber/cucumber/tree/master/tag-expressions)?
According to cucumber [documentation](https://cucumber.io/docs/cucumber/api/#tags):
Tags can be placed above the following Gherkin elements:
- Feature
- Scenario
- Scenario Outline
- Examples

I tried to run cucumber-js and it worked, but when running cypress with cypress-cucumber-preprocessor, I get an error: `We could not detect any tests in the above file. Write some tests and re-run.`

Pull request description:
fix(tags): fix inheritance according to cucumber specs
According to cucumber tags should be inherited downwards. See
https://cucumber.io/docs/cucumber/api/#tags

fix #196

Patch:
diff --git a/README.md b/README.md
index 1bb1e54..42e84c0 100644
--- a/README.md
+++ b/README.md
@@ -391,6 +391,22 @@ You can use a glob expression to select which feature files should be included.
 
 Example:
 
+```shell
+  ./node_modules/.bin/cypress-tags run -g 'cypress/integration/**/*.feature'
+```
+
+or 
+
+```shell
+  ./node_modules/.bin/cypress-tags run --glob 'cypress/integration/**/*.feature'
+```
+
+or
+
+<span style="color:orange">*DEPRECATED*</span>
+
+This will not work if your glob pattern contains commas since Cypress expects comma delimited string of env variables.
+
 ```shell
   ./node_modules/.bin/cypress-tags run -e GLOB='cypress/integration/**/*.feature'
 ```
diff --git a/cypress-tags.js b/cypress-tags.js
index 537acce..ad610ca 100755
--- a/cypress-tags.js
+++ b/cypress-tags.js
@@ -4,6 +4,11 @@ const { Parser } = require("gherkin");
 const glob = require("glob");
 const fs = require("fs");
 const { execFileSync } = require("child_process");
+const {
+  parseArgsOrDefault,
+  stripCLIArguments,
+  getGlobArg,
+} = require("./lib/cypressTagsHelpers");
 
 const { shouldProceedCurrentStep } = require("./lib/tagsHelper");
 
@@ -13,22 +18,7 @@ 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;
-}
-
-const envGlob = parseArgsOrDefault("GLOB", false);
+const envGlob = getGlobArg();
 const envTags = parseArgsOrDefault("TAGS", "");
 
 let specGlob = envGlob || "cypress/integration/**/*.feature";
@@ -122,7 +112,7 @@ try {
   if (featuresToRun.length || envTags === "") {
     execFileSync(
       getCypressExecutable(),
-      [...process.argv.slice(2), "--spec", featuresToRun.join(",")],
+      [...stripCLIArguments(["g", "glob"]), "--spec", featuresToRun.join(",")],
       {
         stdio: [process.stdin, process.stdout, process.stderr],
       }
diff --git a/cypress/integration/BeforeAndAfterSteps.feature b/cypress/integration/BeforeAndAfterSteps.feature
index 3f6cf7f..03aad4b 100644
--- a/cypress/integration/BeforeAndAfterSteps.feature
+++ b/cypress/integration/BeforeAndAfterSteps.feature
@@ -48,3 +48,27 @@ Scenario: With multiple tags
     Given I executed empty step
     Then Tagged Before was called twice
     And Untagged Before was called once
+
+Scenario Outline: With tagged Before only on one of the examples
+  Then Tagged Before was <result>
+
+  @withTaggedBefore
+  Examples:
+  | result      |
+  | called once |
+
+  Examples:
+    | result     |
+    | not called |
+
+@withTaggedBefore
+Scenario Outline: With tagged Before on scenario outline with multiple examples
+    Then Tagged Before was <result>
+
+    Examples:
+      | result      |
+      | called once |
+
+    Examples:
+      | result      |
+      | called once |
\ No newline at end of file
diff --git a/cypress/integration/TagsImplementationWithEnvSetExamplesLevel.feature b/cypress/integration/TagsImplementationWithEnvSetExamplesLevel.feature
new file mode 100644
index 0000000..4e9dd30
--- /dev/null
+++ b/cypress/integration/TagsImplementationWithEnvSetExamplesLevel.feature
@@ -0,0 +1,18 @@
+Feature: Tags Implementation with environmental variables set only at examples level
+
+  As a cucumber cypress plugin which handles Tags
+  I want to allow people set any tags via CLI
+  And run only tests selected even if they are tagged only at examples level
+
+  Scenario Outline: This scenario should run only 1 example
+    Given '@test-tag' is in current TAGS environmental variable
+    Then this <result>
+
+    @test-tag
+    Examples:
+      | result     |
+      | should run |
+
+    Examples:
+      | result         |
+      | should not run |
\ No newline at end of file
diff --git a/lib/cypressTagsHelpers.js b/lib/cypressTagsHelpers.js
new file mode 100644
index 0000000..b112e78
--- /dev/null
+++ b/lib/cypressTagsHelpers.js
@@ -0,0 +1,59 @@
+const minimist = require("minimist");
+const dargs = require("dargs");
+
+const minimistConfig = {
+  alias: { g: "glob" },
+  string: ["g"],
+};
+
+function stripCLIArguments(argsToRemove = []) {
+  const command = process.argv[2];
+  const userOptions = process.argv.slice(3);
+
+  const minimistArgs = minimist(userOptions);
+  const argsAndAliasesToExclude =
+    argsToRemove.length > 0
+      ? Object.entries(minimistConfig.alias)
+          .map(([key, value]) => [key, value].flat())
+          .filter((aliasedOption) =>
+            aliasedOption.some((option) => argsToRemove.includes(option))
+          )
+          .flat()
+      : [];
+
+  return [
+    command,
+    ...dargs(minimistArgs, {
+      excludes: [...new Set([...argsAndAliasesToExclude, ...argsToRemove])],
+      useEquals: false,
+    }),
+  ];
+}
+/**
+ * Users will be expected to pass args by --glob/-g to avoid issues related to commas in those parameters.
+ */
+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;
+}
+
+function getGlobArg() {
+  const args = minimist(process.argv.slice(2), minimistConfig);
+  return args.g || parseArgsOrDefault("GLOB", false);
+}
+
+module.exports = {
+  stripCLIArguments,
+  parseArgsOrDefault,
+  getGlobArg,
+};
diff --git a/lib/getStepDefinitionsPaths.js b/lib/getStepDefinitionsPaths.js
index 813894f..c39b1ef 100644
--- a/lib/getStepDefinitionsPaths.js
+++ b/lib/getStepDefinitionsPaths.js
@@ -14,7 +14,7 @@ const getStepDefinitionsPaths = (filePath) => {
     let commonPath = config.commonPath || `${stepDefinitionPath()}/common/`;
 
     if (config.commonPath) {
-      commonPath = path.resolve(appRoot, commonPath);
+      commonPath = `${path.resolve(appRoot, commonPath)}/`;
     }
 
     if (config.nonGlobalStepBaseDir) {
diff --git a/manual-releases.md b/manual-releases.md
index 3bceb32..e1e77e6 100644
--- a/manual-releases.md
+++ b/manual-releases.md
@@ -41,4 +41,4 @@ change is to release a new patch version.
 Reference: #<the number of a relevant pull request, issue, or commit>
 ```
 
-The number of times we've had to do a manual release is: 5
+The number of times we've had to do a manual release is: 6
diff --git a/package-lock.json b/package-lock.json
index 0f71747..51746f6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3645,22 +3645,93 @@
       "dev": true
     },
     "chokidar": {
-      "version": "2.1.8",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
-      "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
-      "requires": {
-        "anymatch": "^2.0.0",
-        "async-each": "^1.0.1",
-        "braces": "^2.3.2",
-        "fsevents": "^1.2.7",
-        "glob-parent": "^3.1.0",
-        "inherits": "^2.0.3",
-        "is-binary-path": "^1.0.0",
-        "is-glob": "^4.0.0",
-        "normalize-path": "^3.0.0",
-        "path-is-absolute": "^1.0.0",
-        "readdirp": "^2.2.1",
-        "upath": "^1.1.1"
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
+      "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
+      "requires": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "fsevents": "~2.3.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "dependencies": {
+        "anymatch": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+          "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+          "requires": {
+            "normalize-path": "^3.0.0",
+            "picomatch": "^2.0.4"
+          }
+        },
+        "binary-extensions": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+          "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
+        },
+        "braces": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+          "requires": {
+            "fill-range": "^7.0.1"
+          }
+        },
+        "fill-range": {
+          "version": "7.0.1",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+          "requires": {
+            "to-regex-range": "^5.0.1"
+          }
+        },
+        "fsevents": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+          "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+          "optional": true
+        },
+        "glob-parent": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+          "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+          "requires": {
+            "is-glob": "^4.0.1"
+          }
+        },
+        "is-binary-path": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+          "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+          "requires": {
+            "binary-extensions": "^2.0.0"
+          }
+        },
+        "is-number": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+        },
+        "readdirp": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+          "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+          "requires": {
+            "picomatch": "^2.2.1"
+          }
+        },
+        "to-regex-range": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+          "requires": {
+            "is-number": "^7.0.0"
+          }
+        }
       }
     },
     "ci-info": {
@@ -4638,6 +4709,11 @@
         "type": "^1.0.1"
       }
     },
+    "dargs": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
+      "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg=="
+    },
     "dash-ast": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz",
@@ -6463,7 +6539,8 @@
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
       "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "handlebars": {
       "version": "4.7.6",
@@ -7392,6 +7469,7 @@
       "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
       "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
       "dev": true,
+      "optional": true,
       "requires": {
         "is-docker": "^2.0.0"
       }
@@ -10681,6 +10759,7 @@
       "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz",
       "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==",
       "dev": true,
+      "optional": true,
       "requires": {
         "growly": "^1.3.0",
         "is-wsl": "^2.2.0",
@@ -10695,6 +10774,7 @@
           "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
           "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
           "dev": true,
+          "optional": true,
           "requires": {
             "lru-cache": "^6.0.0"
           }
@@ -10703,13 +10783,15 @@
           "version": "8.3.2",
           "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
           "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
-          "dev": true
+          "dev": true,
+          "optional": true
         },
         "which": {
           "version": "2.0.2",
           "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
           "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
           "dev": true,
+          "optional": true,
           "requires": {
             "isexe": "^2.0.0"
           }
@@ -14689,8 +14771,7 @@
     "picomatch": {
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
-      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
-      "dev": true
+      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
     },
     "pify": {
       "version": "2.3.0",
@@ -15826,7 +15907,8 @@
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
       "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "signal-exit": {
       "version": "3.0.3",
diff --git a/package.json b/package.json
index d1b4e00..c370757 100644
--- a/package.json
+++ b/package.json
@@ -45,11 +45,12 @@
   "dependencies": {
     "@cypress/browserify-preprocessor": "^3.0.1",
     "chai": "^4.2.0",
-    "chokidar": "2.1.8",
+    "chokidar": "3.5.2",
     "cosmiconfig": "^4.0.0",
     "cucumber": "^4.2.1",
     "cucumber-expressions": "^6.0.1",
     "cucumber-tag-expressions": "^1.1.1",
+    "dargs": "^7.0.0",
     "debug": "^3.0.1",
     "gherkin": "^5.1.0",
     "glob": "^7.1.2",


Test patch:
diff --git a/lib/createTestFromScenario.js b/lib/createTestFromScenario.js
index 23dc228..64d0129 100644
--- a/lib/createTestFromScenario.js
+++ b/lib/createTestFromScenario.js
@@ -7,6 +7,7 @@ const {
   resolveAndRunAfterHooks,
 } = require("./resolveStepDefinition");
 const { generateCucumberJson } = require("./cukejson/generateCucumberJson");
+const { shouldProceedCurrentStep, getEnvTags } = require("./tagsHelper");
 
 const replaceParameterTags = (rowData, text) =>
   Object.keys(rowData).reduce(
@@ -108,9 +109,13 @@ const createTestFromScenarios = (
 
   allScenarios.forEach((section) => {
     if (section.examples) {
+      const hasEnvTags = !!getEnvTags();
       section.examples.forEach((example) => {
         const exampleValues = [];
         const exampleLocations = [];
+        const shouldRunExamples =
+          !hasEnvTags ||
+          shouldProceedCurrentStep(example.tags.concat(section.tags));
 
         example.tableBody.forEach((row, rowIndex) => {
           exampleLocations[rowIndex] = row.location;
@@ -138,6 +143,9 @@ const createTestFromScenarios = (
 
           const scenarioExample = {
             ...section,
+            // tags on scenario's should be inherited by examples (https://cucumber.io/docs/cucumber/api/#tags)
+            tags: example.tags.concat(section.tags),
+            shouldRun: shouldRunExamples,
             name: uniqueScenarioName,
             example: exampleLocations[index],
           };
diff --git a/lib/createTestsFromFeature.js b/lib/createTestsFromFeature.js
index d80ad49..2ecb7cf 100644
--- a/lib/createTestsFromFeature.js
+++ b/lib/createTestsFromFeature.js
@@ -17,6 +17,12 @@ const createTestsFromFeature = (filePath, spec) => {
     (section) => section.type !== "Background"
   );
 
+  // tags on features should be inherited by scenario's (https://cucumber.io/docs/cucumber/api/#tags)
+  allScenarios.forEach((section) => {
+    // eslint-disable-next-line no-param-reassign
+    section.tags = section.tags.concat(featureTags);
+  });
+
   const scenariosToRun = allScenarios.filter((section) => {
     let shouldRun;
     // only just run focused if no env tags set
@@ -24,9 +30,7 @@ const createTestsFromFeature = (filePath, spec) => {
     if (!hasEnvTags && anyFocused) {
       shouldRun = section.tags.find((t) => t.name === "@focus");
     } else {
-      shouldRun =
-        !hasEnvTags ||
-        shouldProceedCurrentStep(section.tags.concat(featureTags)); // Concat handles inheritance of tags from feature
+      shouldRun = !hasEnvTags || shouldProceedCurrentStep(section.tags);
     }
     return shouldRun;
   });
diff --git a/lib/cypressTagsHelpers.test.js b/lib/cypressTagsHelpers.test.js
new file mode 100644
index 0000000..60313de
--- /dev/null
+++ b/lib/cypressTagsHelpers.test.js
@@ -0,0 +1,82 @@
+const { stripCLIArguments, getGlobArg } = require("./cypressTagsHelpers");
+
+const processArgv = process.argv;
+
+describe("stripCLIArguments function should return correct args array", () => {
+  beforeEach(() => {
+    process.argv = ["path/to/node", "path/to/file", "run"];
+  });
+
+  test("when only target option is present", () => {
+    process.argv.push(...["-g", "cypress/integration/**/*.feature"]);
+    expect(stripCLIArguments(["g"])).to.eql(["run"]);
+  });
+
+  test("when target option is a word", () => {
+    process.argv.push(...["--glob", "cypress/integration/**/*.feature"]);
+    expect(stripCLIArguments(["glob"])).to.eql(["run"]);
+  });
+
+  test("when option doesn't have a value tied to it", () => {
+    process.argv.push(...["-g"]);
+    expect(stripCLIArguments(["g"])).to.eql(["run"]);
+  });
+
+  test("when there are multiple options but only one is target for removal", () => {
+    process.argv.push(...["-g", "-t"]);
+    expect(stripCLIArguments(["g"])).to.eql(["run", "-t"]);
+  });
+
+  test("when there are multiple options to remove", () => {
+    process.argv.push(...["-g", "-t", "cypress tags string"]);
+    expect(stripCLIArguments(["g", "t"])).to.eql(["run"]);
+  });
+
+  test("when option is coupled with other ones like -tg", () => {
+    process.argv.push(...["-tg", "cypress/integration/**/*.feature"]);
+    expect(stripCLIArguments(["t"])).to.eql([
+      "run",
+      "-g",
+      "cypress/integration/**/*.feature",
+    ]);
+  });
+
+  test("when option is coupled with other ones like -gt where t has a value", () => {
+    process.argv.push(...["-gt", "cypress tags string"]);
+    expect(stripCLIArguments(["t"])).to.eql(["run", "-g"]);
+  });
+
+  afterEach(() => {
+    process.argv = processArgv;
+  });
+});
+
+describe("getGlobArg function should return", () => {
+  beforeEach(() => {
+    process.argv = ["path/to/node", "path/to/file", "run"];
+  });
+
+  test("glob pattern when using -g or --glob option", () => {
+    process.argv.push(...["-g", "cypress/integration/**/*.feature"]);
+    expect(getGlobArg()).to.equal("cypress/integration/**/*.feature");
+  });
+
+  test("glob pattern containing commas when using -g option", () => {
+    process.argv.push(...["-g", "cypress/integration/**/1,2*.feature"]);
+    expect(getGlobArg()).to.equal("cypress/integration/**/1,2*.feature");
+  });
+
+  test("glob pattern containing braced sections when using -g option", () => {
+    process.argv.push(...["-g", "cypress/integration/**/{1,2}*.feature"]);
+    expect(getGlobArg()).to.equal("cypress/integration/**/{1,2}*.feature");
+  });
+
+  test("glob pattern when using env variables GLOB=", () => {
+    process.argv.push(...["-e", "GLOB=cypress/integration/**/*.feature"]);
+    expect(getGlobArg()).to.equal("cypress/integration/**/*.feature");
+  });
+
+  afterEach(() => {
+    process.argv = processArgv;
+  });
+});
diff --git a/lib/getStepDefinitionsPaths.test.js b/lib/getStepDefinitionsPaths.test.js
index 3706400..d51411b 100644
--- a/lib/getStepDefinitionsPaths.test.js
+++ b/lib/getStepDefinitionsPaths.test.js
@@ -1,3 +1,4 @@
+// file.only
 /* eslint-disable global-require */
 jest.mock("./stepDefinitionPath.js", () => () => "stepDefinitionPath");
 jest.mock("glob", () => ({
@@ -28,16 +29,7 @@ describe("getStepDefinitionsPaths", () => {
   });
 
   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");
+    jest.spyOn(process, "cwd").mockImplementation(() => "/cwd/");
 
     getConfig.mockReturnValue({
       nonGlobalStepDefinitions: true,
@@ -47,7 +39,7 @@ describe("getStepDefinitionsPaths", () => {
     const { getStepDefinitionsPaths } = require("./getStepDefinitionsPaths");
 
     const actual = getStepDefinitionsPaths("/path");
-    const expected = "./cwd/myPath/**/*.+(js|ts|tsx)";
+    const expected = "/cwd/myPath/**/*.+(js|ts|tsx)";
     expect(actual).to.include(expected);
   });
   it("should return the default non global step definition pattern", () => {