Skip to content

Commit 0857a6c

Browse files
committed
Stuck because of 'after' events fired too late -- on hold until refactoring is finished
1 parent 4abc92b commit 0857a6c

File tree

5 files changed

+205
-68
lines changed

5 files changed

+205
-68
lines changed

features/progress_formatter.feature

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Feature: Progress formatter
2+
In order to have concise information about the execution of my features
3+
As a cucumber user
4+
I want a so-called "progress" formatter
5+
6+
Scenario: Running a one-scenario feature
7+
Given a step definition matching /^a step passes$/
8+
When I run the following feature with the "progress" formatter:
9+
"""
10+
Feature: Progress formatter on one-scenario feature
11+
Scenario: A few passing steps
12+
When a step passes
13+
Then a step passes
14+
"""
15+
Then the listener should output the following:
16+
"""
17+
..
18+
19+
1 scenario (1 passed)
20+
2 steps (2 passed)
21+
"""

features/step_definitions/cucumber_steps.js

+48-25
Original file line numberDiff line numberDiff line change
@@ -124,26 +124,8 @@ var stepDefinitions = function() {
124124
// Matching groups: none.
125125
// Multiline parameter: the feature to execute.
126126
When(/^I run the following feature:$/, function(featureSource, callback) {
127-
_listener = Cucumber.Debug.SimpleAstListener();
128-
_listener.beforeEachScenarioDo(function() {
129-
_stepDefs = [];
130-
_recordedStepParameters = [];
131-
_stepCallCount = 0;
132-
});
133-
var cucumber = Cucumber(featureSource, _getSupportCode);
134-
cucumber.attachListener(_listener);
135-
try {
136-
cucumber.start(function() {
137-
_finishedCuking = true;
138-
_featureSource = featureSource;
139-
callback();
140-
});
141-
} catch(error) {
142-
printInsideFeatureError(error);
143-
setTimeout(function() {
144-
throw(new Error("Step failed: Could not run the 'inside' feature successfully."));
145-
}, 10);
146-
};
127+
_buildListener(Cucumber.Debug.SimpleAstListener);
128+
_runFeature(featureSource, callback);
147129
});
148130

149131
// Checks that the feature previously run succeeded.
@@ -154,17 +136,13 @@ var stepDefinitions = function() {
154136
Then(/^the feature should have run successfully$/, function(callback) {
155137
if (!_finishedCuking)
156138
throw(new Error("Expected Cucumber to run the feature successfully."));
157-
158139
var actualOutput = _normalizeString(_listener.getLogs());
159140
var expectedOutput = _normalizeString(_featureSource);
160141
if (!actualOutput.match(expectedOutput))
161-
throw(new Error("Expected listener to output the feature source.\n\n<<<<<<< EXPECTED\n" +
162-
expectedOutput + "\n======= ACTUAL:\n" + actualOutput + "\n>>>>>>>"));
163-
142+
throw(UnexpectedOutputError(expectedOutput, actualOutput));
164143
callback();
165144
});
166145

167-
168146
// =======================================================
169147
// ======= Cucumber.js-specific step definitions =========
170148
// =======================================================
@@ -177,11 +155,51 @@ var stepDefinitions = function() {
177155
callback();
178156
});
179157

158+
When(/^I run the following feature with the "progress" formatter:$/, function(featureSource, callback) {
159+
_buildListener(Cucumber.Listener.ProgressFormatter);
160+
_runFeature(featureSource, callback);
161+
});
162+
163+
Then(/^the listener should output the following:$/, function(expectedOutput, callback) {
164+
var actualOutput = _listener.getLogs();
165+
var expectedOutput = expectedOutput;
166+
if (!actualOutput.match(expectedOutput))
167+
throw(UnexpectedOutputError(expectedOutput, actualOutput));
168+
callback();
169+
});
180170

181171
// =======================================================
182172
// ===================== Helpers ========================
183173
// =======================================================
184174

175+
function _runFeature(featureSource, callback) {
176+
console.log(featureSource);
177+
178+
var cucumber = Cucumber(featureSource, _getSupportCode);
179+
cucumber.attachListener(_listener);
180+
try {
181+
cucumber.start(function() {
182+
_finishedCuking = true;
183+
_featureSource = featureSource;
184+
callback();
185+
});
186+
} catch(error) {
187+
printInsideFeatureError(error);
188+
setTimeout(function() {
189+
throw(new Error("Step failed: Could not run the 'inside' feature successfully."));
190+
}, 10);
191+
};
192+
};
193+
194+
function _buildListener(listenerConstructor) {
195+
_listener = listenerConstructor();
196+
_listener.beforeEachScenarioDo(function() {
197+
_stepDefs = [];
198+
_recordedStepParameters = [];
199+
_stepCallCount = 0;
200+
});
201+
};
202+
185203
function _addStepDefinition(keyword, name, content) {
186204
var _stepName = RegExp(name);
187205
var stepDefinition;
@@ -218,6 +236,11 @@ var stepDefinitions = function() {
218236
function translateParameterOffsetToIndex(offset) {
219237
return parseInt(offset) - 1;
220238
};
239+
240+
function UnexpectedOutputError(expected, actual) {
241+
return(new Error("Expected listener output is not met.\n\n<<<<<<< EXPECTED\n" +
242+
expected + "\n======= ACTUAL:\n" + actual + "\n>>>>>>>"));
243+
};
221244
};
222245

223246
module.exports = stepDefinitions;

lib/cucumber.js

+38-43
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,9 @@ Cucumber.Ast.TreeWalker = function(features, supportCodeLibrary, listeners) {
292292
};
293293
listeners.syncForEach(function(listener) {
294294
var hearMethodName = Cucumber.Ast.TreeWalker.HEAR_METHOD_PREFIX + message;
295-
listener[hearMethodName].apply(this, parameters);
295+
var hearMethod = listener[hearMethodName];
296+
if (hearMethod)
297+
hearMethod.apply(this, parameters);
296298
});
297299
},
298300

@@ -398,7 +400,6 @@ Cucumber.SupportCode.StepDefinition = function(regexp, code) {
398400
};
399401

400402
Cucumber.Runtime = {};
401-
402403
Cucumber.Runtime.StepResult = function(status) {
403404
var self = {
404405
isSuccessful: function isSuccessful() {
@@ -408,6 +409,40 @@ Cucumber.Runtime.StepResult = function(status) {
408409
return self;
409410
};
410411

412+
Cucumber.Listener = {};
413+
Cucumber.Listener.ProgressFormatter = function() {
414+
var beforeEachScenarioUserFunctions = Cucumber.Types.Collection();
415+
var logs = "";
416+
var passingScenarios = 0;
417+
var totalScenarios = 0;
418+
419+
var self = {
420+
beforeEachScenarioDo: function beforeEachScenarioDo(userFunction) {
421+
beforeEachScenarioUserFunctions.add(userFunction);
422+
},
423+
424+
log: function log(string) {
425+
logs += string;
426+
},
427+
428+
getLogs: function getLogs() {
429+
return logs;
430+
},
431+
432+
hearStepResult: function hearStepResult(stepResult) {
433+
self.log(Cucumber.Listener.ProgressFormatter.PASSING_STEP_CHARACTER);
434+
},
435+
436+
hearAfterFeatures: function heafAfterFeatures() {
437+
self.logSummary();
438+
},
439+
440+
logSummary: TODO("logSummary()")
441+
};
442+
return self;
443+
};
444+
Cucumber.Listener.ProgressFormatter.PASSING_STEP_CHARACTER = '.';
445+
411446
Cucumber.Types = {};
412447
Cucumber.Types.Collection = function() {
413448
var items = new Array();
@@ -524,50 +559,10 @@ Cucumber.Debug.SimpleAstListener = function(options) {
524559
return indented;
525560
};
526561
};
527-
Cucumber.Debug.SgmlAstListener = function() {
528-
var self = {
529-
hearBeforeFeatures: function hearBeforeFeatures() {
530-
console.log("<features>");
531-
},
532-
533-
hearAfterFeatures: function hearAfterFeatures() {
534-
console.log("</features>");
535-
},
536-
537-
hearBeforeFeature: function hearBeforeFeature() {
538-
console.log(" <feature>");
539-
},
540-
541-
hearAfterFeature: function hearAfterFeature() {
542-
console.log(" </feature>");
543-
},
544-
545-
hearBeforeScenario: function hearBeforeScenario() {
546-
console.log(" <scenario>");
547-
},
548-
549-
hearAfterScenario: function hearAfterScenario() {
550-
console.log(" </scenario>");
551-
},
552-
553-
hearBeforeStep: function hearBeforeStep() {
554-
console.log(" <step>");
555-
},
556-
557-
hearStepResult: function hearStepResult(stepResult) {
558-
console.log(" <result success='" + (stepResult.isSuccessful() ? "true" : "false") + "'></result>");
559-
},
560-
561-
hearAfterStep: function hearAfterStep() {
562-
console.log(" </step>");
563-
}
564-
};
565-
return self;
566-
};
567562

568563
if(typeof exports != 'undefined') { module.exports = Cucumber; }
569564
if(typeof window != 'undefined') { for (var p in Cucumber) { window[p] = Cucumber[p]; } }
570565

571566
var TODO = function(description) {
572-
return function() { throw("IMPLEMENT ME: "+description) };
567+
return function() { throw("IMPLEMENT ME: " + description); };
573568
};

spec/cucumber/ast/tree_walker_spec.js

+12
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,18 @@ describe("Cucumber.Ast.TreeWalker", function() {
278278
expect(listener[hearMethod]).toHaveBeenCalledWith(parameter1, parameter2, parameter3);
279279
});
280280
});
281+
282+
it("does not tell a listener when it is not interested in that message", function() {
283+
var dumbListener = createSpy("A listener listening to nothing (it has no headXXX() method");
284+
var failed = false;
285+
listeners.push(dumbListener);
286+
try {
287+
treeWalker.broadcastMessage(message);
288+
} catch(err) {
289+
failed = true;
290+
}
291+
expect(failed).toBeFalsy();
292+
});
281293
});
282294

283295
describe("lookupStepDefinitionByName()", function() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
require('../../support/spec_helper');
2+
3+
describe("Cucumber.Listener.ProgressFormatter", function() {
4+
var Cucumber = require('cucumber');
5+
var listener, beforeEachScenarioUserFunctions;
6+
7+
beforeEach(function() {
8+
beforeEachScenarioUserFunctions = createSpy("User Functions to call before each scenario");
9+
spyOn(Cucumber.Types, 'Collection').andReturn(beforeEachScenarioUserFunctions);
10+
listener = Cucumber.Listener.ProgressFormatter();
11+
});
12+
13+
describe("constructor", function() {
14+
it("creates a new collection to store user functions to call before each scenario", function() {
15+
expect(Cucumber.Types.Collection).toHaveBeenCalled();
16+
});
17+
});
18+
19+
describe("beforeEachScenarioDo()", function() {
20+
beforeEach(function() {
21+
spyOnStub(beforeEachScenarioUserFunctions, 'add');
22+
});
23+
24+
it("adds the user function to the collection of 'before each scenario' user functions", function() {
25+
var userFunction = createSpy("A user function to call before each scenario");
26+
listener.beforeEachScenarioDo(userFunction);
27+
expect(beforeEachScenarioUserFunctions.add).toHaveBeenCalledWith(userFunction);
28+
});
29+
});
30+
31+
describe("log()", function() {
32+
it("records logged strings", function() {
33+
var logged = "this was logged";
34+
var alsoLogged = "this was also logged";
35+
var loggedBuffer = logged + alsoLogged;
36+
listener.log(logged);
37+
listener.log(alsoLogged);
38+
expect(listener.getLogs()).toBe(loggedBuffer);
39+
});
40+
});
41+
42+
describe("getLogs()", function() {
43+
it("returns the logged buffer", function() {
44+
var logged = "this was logged";
45+
var alsoLogged = "this was also logged";
46+
var loggedBuffer = logged + alsoLogged;
47+
listener.log(logged);
48+
listener.log(alsoLogged);
49+
expect(listener.getLogs()).toBe(loggedBuffer);
50+
});
51+
52+
it("returns an empty string when the listener did not log anything yet", function() {
53+
expect(listener.getLogs()).toBe("");
54+
});
55+
});
56+
57+
describe("hearStepResult", function() {
58+
var stepResult;
59+
60+
beforeEach(function() {
61+
spyOn(listener, 'log');
62+
stepResult = createSpy("AST step result");
63+
});
64+
65+
describe("when the step has passed", function() {
66+
it("logs the passing step character if the step succeeded", function() {
67+
listener.hearStepResult(stepResult);
68+
expect(listener.log).toHaveBeenCalledWith(Cucumber.Listener.ProgressFormatter.PASSING_STEP_CHARACTER);
69+
});
70+
});
71+
});
72+
73+
describe("hearAfterFeatures()", function() {
74+
var features;
75+
76+
beforeEach(function() {
77+
features = createSpy("Features AST element");
78+
spyOn(listener, "logSummary");
79+
});
80+
81+
it("displays a summary", function() {
82+
listener.hearAfterFeatures(features);
83+
expect(listener.logSummary).toHaveBeenCalled();
84+
});
85+
});
86+
});

0 commit comments

Comments
 (0)