Repository: TheBrainFamily/cypress-cucumber-preprocessor
Pull request #142 (2019-02-08 17:27:24)

Scenario outline and data tables
This PR fixes https://github.com/TheBrainFamily/cypress-cucumber-preprocessor/issues/137.
@lgandecki could you have a look, if this might do already.
Thanks in advance!

lgandecki: I think this is good, thanks :) 

Patch:
diff --git a/cypress/integration/ScenarioOutline.feature b/cypress/integration/ScenarioOutline.feature
index 25bb46a..6140805 100644
--- a/cypress/integration/ScenarioOutline.feature
+++ b/cypress/integration/ScenarioOutline.feature
@@ -18,7 +18,19 @@ Feature: Being a plugin handling Scenario Outline
     Then I should get "<juice>"
 
     Examples:
-      | fruit      | juice               |
-      | apple      | apple juice         |
-      | pineapple  | pineapple juice     |
-      | strawberry | strawberry juice    |
+      | fruit      | juice            |
+      | apple      | apple juice      |
+      | pineapple  | pineapple juice  |
+      | strawberry | strawberry juice |
+
+  Scenario Outline: A calculation
+    When I enter <first> and <second>
+    Then I see following result table
+      | first   | second   | result   |
+      | <first> | <second> | <result> |
+
+    Examples:
+      | first | second | result |
+      | 1     | 2      | 3      |
+      | 3     | 4      | 7      |
+      | 5     | 6      | 11     |
\ No newline at end of file
diff --git a/cypress/support/step_definitions/scenario_outline_data_table.js b/cypress/support/step_definitions/scenario_outline_data_table.js
new file mode 100644
index 0000000..b1c2c1b
--- /dev/null
+++ b/cypress/support/step_definitions/scenario_outline_data_table.js
@@ -0,0 +1,15 @@
+/* global then, when */
+
+let sum = { first: 0, second: 0, result: 0 };
+
+when("I enter {int} and {int}", (a, b) => {
+  sum = { first: a, second: b, result: a + b };
+});
+
+then("I see following result table", dataTable => {
+  dataTable.hashes().forEach(row => {
+    expect(sum.first).to.equal(parseInt(row.first, 10));
+    expect(sum.second).to.equal(parseInt(row.second, 10));
+    expect(sum.result).to.equal(parseInt(row.result, 10));
+  });
+});
diff --git a/lib/resolveStepDefinition.js b/lib/resolveStepDefinition.js
index c065364..35f44a8 100644
--- a/lib/resolveStepDefinition.js
+++ b/lib/resolveStepDefinition.js
@@ -50,24 +50,47 @@ function resolveStepDefinition(step) {
 
 module.exports = {
   // eslint-disable-next-line func-names
-  resolveAndRunStepDefinition(step) {
+  resolveAndRunStepDefinition(step, replaceParameterTags, exampleRowData) {
+    const modifiedStep = step;
     const { expression, implementation } = resolveStepDefinition(step);
     if (expression && implementation) {
       let argument;
-      if (step.argument) {
-        if (step.argument.type === "DataTable") {
-          argument = new DataTable(step.argument);
-        } else if (step.argument.type === "DocString") {
-          argument = step.argument.content;
+      if (modifiedStep.argument) {
+        if (modifiedStep.argument.type === "DataTable") {
+          if (exampleRowData) {
+            if (!modifiedStep.argument.templateRows) {
+              modifiedStep.argument.templateRows = modifiedStep.argument.rows;
+            }
+            const scenarioDataTableRows = modifiedStep.argument.templateRows.map(
+              tr => {
+                if (tr && tr.type === "TableRow") {
+                  const cells = {
+                    cells: tr.cells.map(c => {
+                      const value = {
+                        value: replaceParameterTags(exampleRowData, c.value)
+                      };
+                      return Object.assign({}, c, value);
+                    })
+                  };
+                  return Object.assign({}, tr, cells);
+                }
+                return tr;
+              }
+            );
+            modifiedStep.argument.rows = scenarioDataTableRows;
+          }
+          argument = new DataTable(modifiedStep.argument);
+        } else if (modifiedStep.argument.type === "DocString") {
+          argument = modifiedStep.argument.content;
         }
       }
       return implementation.call(
         this,
-        ...expression.match(step.text).map(match => match.getValue()),
+        ...expression.match(modifiedStep.text).map(match => match.getValue()),
         argument
       );
     }
-    throw new Error(`Step implementation missing for: ${step.text}`);
+    throw new Error(`Step implementation missing for: ${modifiedStep.text}`);
   },
   given: (expression, implementation) => {
     stepDefinitionRegistry.runtime(expression, implementation);
diff --git a/package.json b/package.json
index aae3891..7ca1706 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
   "main": "lib/index.js",
   "scripts": {
     "test": "eslint . && jest && cypress run",
+    "test:debug": "jest && DEBUG=cypress:* cypress open\n",
     "fixStyle": "eslint . --fix",
     "semantic-release": "semantic-release"
   },


Test patch:
diff --git a/lib/createTestFromScenario.js b/lib/createTestFromScenario.js
index 4731bdf..2fe13bc 100644
--- a/lib/createTestFromScenario.js
+++ b/lib/createTestFromScenario.js
@@ -1,17 +1,22 @@
 /* eslint-disable prefer-template */
 const { resolveAndRunStepDefinition } = require("./resolveStepDefinition");
 
-const stepTest = function(stepDetails) {
-  cy.log(`${stepDetails.keyword} ${stepDetails.text}`);
-  resolveAndRunStepDefinition.call(this, stepDetails);
-};
-
 const replaceParameterTags = (rowData, text) =>
   Object.keys(rowData).reduce(
     (value, key) => value.replace(`<${key}>`, rowData[key]),
     text
   );
 
+const stepTest = function(stepDetails, exampleRowData) {
+  cy.log(`${stepDetails.keyword} ${stepDetails.text}`);
+  resolveAndRunStepDefinition.call(
+    this,
+    stepDetails,
+    replaceParameterTags,
+    exampleRowData
+  );
+};
+
 const createTestFromScenario = (scenario, backgroundSection) => {
   if (scenario.examples) {
     scenario.examples.forEach(example => {
@@ -39,7 +44,7 @@ const createTestFromScenario = (scenario, backgroundSection) => {
             const newStep = Object.assign({}, step);
             newStep.text = replaceParameterTags(rowData, newStep.text);
 
-            stepTest.call(this, newStep);
+            stepTest.call(this, newStep, rowData);
           });
         });
       });
diff --git a/lib/resolveStepDefinition.test.js b/lib/resolveStepDefinition.test.js
index 226ff3d..4f1a9a1 100644
--- a/lib/resolveStepDefinition.test.js
+++ b/lib/resolveStepDefinition.test.js
@@ -30,6 +30,7 @@ const readAndParseFeatureFile = featureFilePath => {
 describe("Scenario Outline", () => {
   require("../cypress/support/step_definitions/scenario_outline_integer");
   require("../cypress/support/step_definitions/scenario_outline_string");
+  require("../cypress/support/step_definitions/scenario_outline_data_table");
 
   createTestsFromFeature(
     readAndParseFeatureFile("./cypress/integration/ScenarioOutline.feature")