Skip to content

Commit

Permalink
Scenario outline fixes
Browse files Browse the repository at this point in the history
This pull request fixes the following issues:

- #177 Empty Scenario Outline still calls Before and After hooks
- #180 Execution order of scenarios and scenario outlines in a feature
- #185 Before/After hooks on Scenario Outline called incorrectly
- #217 Scenario Outlines with multiple Examples sections only executing the very last Examples
- #224 Issue with tables in feature in version 0.4.2
  • Loading branch information
simondean authored and jbpros committed Sep 5, 2014
1 parent 74923bc commit 4f6bcc4
Show file tree
Hide file tree
Showing 18 changed files with 896 additions and 320 deletions.
556 changes: 507 additions & 49 deletions features/json_formatter.feature

Large diffs are not rendered by default.

60 changes: 16 additions & 44 deletions lib/cucumber/ast/assembler.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
var Assembler = function (features, filter) {
var currentFeature, currentScenarioOrBackground, currentStep, suggestedFeature;
var currentFeature, currentFeatureElement, currentStep, suggestedFeature;
var stashedTags = [];

var self = {
setCurrentFeature: function setCurrentFeature(feature) {
currentFeature = feature;
self.setCurrentScenarioOrBackground(undefined);
self.setCurrentFeatureElement(undefined);
},

getCurrentFeature: function getCurrentFeature() {
return currentFeature;
},

setCurrentScenarioOrBackground: function setCurrentScenarioOrBackground(scenarioOrBackground) {
currentScenarioOrBackground = scenarioOrBackground;
setCurrentFeatureElement: function setCurrentFeatureElement(featureElement) {
currentFeatureElement = featureElement;
self.setCurrentStep(undefined);
},

getCurrentScenarioOrBackground: function getCurrentScenarioOrBackground() {
return currentScenarioOrBackground;
getCurrentFeatureElement: function getCurrentFeatureElement() {
return currentFeatureElement;
},

setCurrentStep: function setCurrentStep(step) {
Expand All @@ -42,7 +42,7 @@ var Assembler = function (features, filter) {
applyCurrentFeatureTagsToElement: function applyCurrentFeatureTagsToElement(element) {
var currentFeature = self.getCurrentFeature();
var featureTags = currentFeature.getTags();
element.addInheritedtags(featureTags);
element.addInheritedTags(featureTags);
},

applyStashedTagsToElement: function applyStashedTagsToElement(element) {
Expand All @@ -51,9 +51,9 @@ var Assembler = function (features, filter) {
},

insertBackground: function insertBackground(background) {
self.setCurrentScenarioOrBackground(background);
self.setCurrentFeatureElement(background);
var currentFeature = self.getCurrentFeature();
currentFeature.addBackground(background);
currentFeature.setBackground(background);
},

insertDataTableRow: function insertDataTableRow(dataTableRow) {
Expand All @@ -76,61 +76,33 @@ var Assembler = function (features, filter) {
insertScenario: function insertScenario(scenario) {
self.applyCurrentFeatureTagsToElement(scenario);
self.applyStashedTagsToElement(scenario);
self.setCurrentScenarioOrBackground(scenario);
if (filter.isElementEnrolled(scenario)) {
var currentFeature = self.getCurrentFeature();
currentFeature.addFeatureElement(scenario);
}
},

insertOutlineScenario: function insertOutlineScenario(scenario, tags) {
self.applyCurrentFeatureTagsToElement(scenario);
scenario.addTags(tags);
self.setCurrentScenarioOrBackground(scenario);
self.setCurrentFeatureElement(scenario);
if (filter.isElementEnrolled(scenario)) {
var currentFeature = self.getCurrentFeature();
currentFeature.addFeatureElement(scenario);
}
},

insertExamples: function insertExamples(examples) {
var currentScenarioOrBackground = self.getCurrentScenarioOrBackground();
if (currentScenarioOrBackground.payloadType == 'scenarioOutline')
currentScenarioOrBackground.setExamples(examples);
else
var currentFeatureElement = self.getCurrentFeatureElement();
if (!currentFeatureElement.isScenarioOutline())
throw new Error("Examples are allowed inside scenario outlines only");
currentFeatureElement.addExamples(examples);
self.setCurrentStep(examples);
},

insertStep: function insertStep(step) {
self.setCurrentStep(step);
var currentScenarioOrBackground = self.getCurrentScenarioOrBackground();
currentScenarioOrBackground.addStep(step);
var currentFeatureElement = self.getCurrentFeatureElement();
currentFeatureElement.addStep(step);
},

insertTag: function insertTag(tag) {
self.stashTag(tag);
},

convertScenarioOutlineToScenarios: function convertScenarioOutlineToScenarios(scenario){
var subScenarios = scenario.buildScenarios();
var subScenarioTags = scenario.getTags();
subScenarios.syncForEach(function (scenario) {
self.insertOutlineScenario(scenario, subScenarioTags);
});
},

convertScenarioOutlinesToScenarios: function convertScenarioOutlinesToScenarios(){
var currentFeature = self.getCurrentFeature();
var scenarios = currentFeature.getFeatureElements();

scenarios.syncForEach(function(scenario){
self.convertScenarioOutlineToScenarios(scenario);
});
},

finish: function finish() {
self.convertScenarioOutlinesToScenarios();
self.getCurrentFeature().convertScenarioOutlinesToScenarios();
self.tryEnrollingSuggestedFeature();
},

Expand Down
2 changes: 1 addition & 1 deletion lib/cucumber/ast/data_table.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var DataTable = function() {

raw: function raw(){
rawRows = [];
rowsCollection.syncForEach(function(row, index) {
rowsCollection.syncForEach(function(row) {
rawRows.push(row.raw());
});
return rawRows;
Expand Down
27 changes: 24 additions & 3 deletions lib/cucumber/ast/feature.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var Feature = function(keyword, name, description, uri, line) {
return line;
},

addBackground: function addBackground(newBackground) {
setBackground: function setBackground(newBackground) {
background = newBackground;
},

Expand All @@ -43,9 +43,30 @@ var Feature = function(keyword, name, description, uri, line) {
featureElement.setBackground(background);
featureElements.add(featureElement);
},

insertFeatureElement: function insertFeatureElement(index, featureElement) {
var background = self.getBackground();
featureElement.setBackground(background);
featureElements.insert(index, featureElement);
},

convertScenarioOutlinesToScenarios: function convertScenarioOutlinesToScenarios() {
featureElements.syncForEach(function(featureElement) {
if (featureElement.isScenarioOutline()) {
self.convertScenarioOutlineToScenarios(featureElement);
}
});
},

getFeatureElements: function getFeatureElements(){
return featureElements;
convertScenarioOutlineToScenarios: function convertScenarioOutlineToScenarios(scenarioOutline) {
var scenarios = scenarioOutline.buildScenarios();
var scenarioOutlineIndex = featureElements.indexOf(scenarioOutline);
featureElements.removeAtIndex(scenarioOutlineIndex);
var scenarioOutlineTags = scenarioOutline.getTags();
scenarios.syncForEach(function (scenario, index) {
scenario.addTags(scenarioOutlineTags);
self.insertFeatureElement(scenarioOutlineIndex + index, scenario);
});
},

getLastFeatureElement: function getLastFeatureElement() {
Expand Down
10 changes: 4 additions & 6 deletions lib/cucumber/ast/scenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ var Scenario = function(keyword, name, description, uri, line) {
var tags = [];

var self = {
payloadType: 'scenario',
isScenarioOutline: function isScenarioOutline() {
return false;
},

setBackground: function setBackground(newBackground) {
background = newBackground;
},

buildScenarios: function buildScenarios() {
return Cucumber.Type.Collection();
},

getKeyword: function getKeyword() {
return keyword;
},
Expand Down Expand Up @@ -63,7 +61,7 @@ var Scenario = function(keyword, name, description, uri, line) {
tags = tags.concat(newTags);
},

addInheritedtags: function addInheritedtags(newTags) {
addInheritedTags: function addInheritedTags(newTags) {
inheritedTags = tags.concat(newTags);
},

Expand Down
36 changes: 16 additions & 20 deletions lib/cucumber/ast/scenario_outline.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,38 @@
var ScenarioOutline = function (keyword, name, description, uri, line) {
var Cucumber = require('../../cucumber');
var self = Cucumber.Ast.Scenario(keyword, name, description, uri, line);
var examples = [];
var examplesCollection = Cucumber.Type.Collection();

self.payloadType = 'scenarioOutline';
self.isScenarioOutline = function () {
return true;
};

self.setExamples = function (newExamples) {
examples = newExamples;
self.addExamples = function (examples) {
examplesCollection.add(examples);
};

function buildScenario(row) {
var newSteps = self.applyExampleRow(row.example, self.getSteps());
function buildScenario(example) {
var newSteps = self.applyExampleRow(example, self.getSteps());
var subScenario = Cucumber.Ast.Scenario(keyword, name, description, uri, line);
subScenario.setSteps(newSteps);
return subScenario;
}

self.buildScenarios = function () {
var rows = examples.getDataTable().getRows();
var firstRow = rows.shift().raw();

rows.syncForEach(function (row, index) {
row.example = {};
row.id = index;
for (var i = 0, ii = firstRow.length; i < ii; i++) {
row.example[firstRow[i]] = row.raw()[i];
}
});

var scenarios = Cucumber.Type.Collection();
rows.syncForEach(function (row) {
scenarios.add(buildScenario(row));

examplesCollection.syncForEach(function(examples) {
var exampleHashes = examples.getDataTable().hashes();
exampleHashes.forEach(function(exampleHash) {
scenarios.add(buildScenario(exampleHash));
});
});

return scenarios;
};

self.getExamples = function () {
return examples;
return examplesCollection;
};

self.applyExampleRow = function (example, steps) {
Expand Down
2 changes: 1 addition & 1 deletion lib/cucumber/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ var Parser = function(featureSources, astFilter) {
handleExamples: function handleExamples(keyword, name, description, line) {
var examples = Cucumber.Ast.Examples(keyword, name, description, line);
astAssembler.insertExamples(examples);
},
}
};
return self;
};
Expand Down
6 changes: 2 additions & 4 deletions lib/cucumber/runtime/ast_tree_walker.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,11 @@ var AstTreeWalker = function(features, supportCodeLibrary, listeners) {
supportCodeLibrary.instantiateNewWorld(function(world) {
self.setWorld(world);
self.witnessNewScenario(scenario);
var payload = {};
payload[scenario.payloadType] = scenario;
self.createBeforeAndAfterStepsForAroundHooks(scenario);
self.createBeforeStepsForBeforeHooks(scenario);
self.createAfterStepsForAfterHooks(scenario);
var event = AstTreeWalker.Event(AstTreeWalker[scenario.payloadType.toUpperCase() + '_EVENT_NAME'], payload);
var payload = { scenario: scenario };
var event = AstTreeWalker.Event(AstTreeWalker.SCENARIO_EVENT_NAME, payload);
self.broadcastEventAroundUserFunction(
event,
function(callback) {
Expand Down Expand Up @@ -293,7 +292,6 @@ AstTreeWalker.FEATURES_EVENT_NAME = 'Features';
AstTreeWalker.FEATURE_EVENT_NAME = 'Feature';
AstTreeWalker.BACKGROUND_EVENT_NAME = 'Background';
AstTreeWalker.SCENARIO_EVENT_NAME = 'Scenario';
AstTreeWalker.SCENARIO_OUTLINE_EVENT_NAME = 'ScenarioOutline';
AstTreeWalker.STEP_EVENT_NAME = 'Step';
AstTreeWalker.STEP_RESULT_EVENT_NAME = 'StepResult';
AstTreeWalker.ROW_EVENT_NAME = 'ExampleRow';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
var _ = require('underscore');
var stepDefinitionSnippetBuilderSyntax = require('./step_definition_snippet_builder_syntax');
_.str = require('underscore.string');

var StepDefinitionSnippetBuilder = function (step, syntax) {
Expand Down
16 changes: 16 additions & 0 deletions lib/cucumber/type/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ var Collection = function () {
items.push(item);
},

insert: function insert(index, item) {
items.splice(index, 0, item);
},

removeAtIndex: function removeAtIndex(index) {
items.splice(index, 1);
},

unshift: function unshift(item) {
items.unshift(item);
},
Expand All @@ -17,6 +25,14 @@ var Collection = function () {
items.length = 0;
},

indexOf: function indexOf(item) {
return items.indexOf(item);
},

getAtIndex: function getAtIndex(index) {
return items[index];
},

getLast: function getLast() {
return items[items.length - 1];
},
Expand Down
Loading

0 comments on commit 4f6bcc4

Please sign in to comment.