Skip to content
Browse files

Add around hooks (#32)

  • Loading branch information...
1 parent e02b0b4 commit 2bc9537ef837b9ef3d5dc000223245790f75fb4c @jbpros jbpros committed Feb 23, 2012
2 features/cucumber-tck
@@ -1 +1 @@
-Subproject commit 7b5b642774561ddb25ff9c88269245a51917cd27
+Subproject commit 80eaf4d64e0545c504353c47e214219c65b81b9c
View
14 features/step_definitions/cucumber_js_mappings.rb
@@ -138,12 +138,24 @@ def write_world_function
def write_passing_hook hook_type
provide_cycle_logging_facilities
define_hook = hook_type.capitalize
- append_support_code <<-EOF
+ if hook_type == "around"
+ append_support_code <<-EOF
+this.#{define_hook}(function(runScenario) {
+ this.logCycleEvent('#{hook_type}-pre');
+ runScenario(function(callback) {
+ this.logCycleEvent('#{hook_type}-post');
+ callback();
+ });
+});
+EOF
+ else
+ append_support_code <<-EOF
this.#{define_hook}(function(callback) {
this.logCycleEvent('#{hook_type}');
callback();
});
EOF
+ end
end
def write_scenario options = {}
View
25 features/step_definitions/cucumber_steps.js
@@ -27,6 +27,17 @@ var cucumberSteps = function() {
callback();
});
+ Given(/^a passing around hook$/, function(callback) {
+ this.stepDefinitions += "this.Around(function(runScenario) {\
+ world.logCycleEvent('around-pre');\
+ runScenario(function(callback) {\
+ world.logCycleEvent('around-post');\
+ callback();\
+ });\
+});\n";
+ callback();
+ });
+
Given(/^the step "([^"]*)" has a failing mapping$/, function(stepName, callback) {
this.stepDefinitions += "Given(/^" + stepName + "$/, function(callback) {\
world.touchStep(\"" + stepName + "\");\
@@ -240,9 +251,19 @@ callback();\
Then(/^the (before|after) hook is fired (?:before|after) the scenario$/, function(hookType, callback) {
if (hookType == 'before')
- this.assertCycleSequence(hookType, 'step');
+ this.assertCycleSequence(hookType, 'step 1');
else
- this.assertCycleSequence('step', hookType);
+ this.assertCycleSequence('step 1', hookType);
+ callback();
+ });
+
+ Then(/^the around hook fires around the scenario$/, function(callback) {
+ this.assertCycleSequence('around-pre', 'step 1', 'around-post');
+ callback();
+ });
+
+ Then(/^the around hook is fired around the other hooks$/, function(callback) {
+ this.assertCycleSequence('around-pre', 'before', 'step 1', 'after', 'around-post');
callback();
});
View
2 features/step_definitions/cucumber_world.js
@@ -49,7 +49,7 @@ proto.runFeatureWithSupportCodeSource = function runFeatureWithSupportCodeSource
proto.runAScenario = function runAScenario(callback) {
this.addScenario("", "Given a step");
this.stepDefinitions += "Given(/^a step$/, function(callback) {\
- world.logCycleEvent('step');\
+ world.logCycleEvent('step 1');\
callback();\
});";
this.runFeature({}, callback);
View
21 lib/cucumber/runtime/ast_tree_walker.js
@@ -43,10 +43,11 @@ var AstTreeWalker = function(features, supportCodeLibrary, listeners) {
supportCodeLibrary.instantiateNewWorld(function(world) {
self.setWorld(world);
self.witnessNewScenario();
- var payload = { scenario: scenario };
- var event = AstTreeWalker.Event(AstTreeWalker.SCENARIO_EVENT_NAME, payload);
- var hookedUpScenarioVisit = self.hookUpFunction(
- function(callback) { scenario.acceptVisitor(self, callback); }
+ var payload = { scenario: scenario };
+ var event = AstTreeWalker.Event(AstTreeWalker.SCENARIO_EVENT_NAME, payload);
+ var hookedUpScenarioVisit = supportCodeLibrary.hookUpFunctionWithWorld(
+ function(callback) { scenario.acceptVisitor(self, callback); },
+ world
);
self.broadcastEventAroundUserFunction(
event,
@@ -111,18 +112,6 @@ var AstTreeWalker = function(features, supportCodeLibrary, listeners) {
);
},
- hookUpFunction: function hookUpFunction(hookedUpFunction) {
- return function(callback) {
- supportCodeLibrary.triggerBeforeHooks(self.getWorld(), function() {
- hookedUpFunction(function() {
- supportCodeLibrary.triggerAfterHooks(self.getWorld(), function() {
- callback();
- });
- });
- });
- }
- },
-
lookupStepDefinitionByName: function lookupStepDefinitionByName(stepName) {
return supportCodeLibrary.lookupStepDefinitionByName(stepName);
},
View
28 lib/cucumber/support_code/library.js
@@ -2,9 +2,8 @@ var Library = function(supportCodeDefinition) {
var MISSING_WORLD_INSTANCE_ERROR = "World constructor called back without World instance.";
var Cucumber = require('../../cucumber');
- var beforeHooks = Cucumber.Type.Collection();
- var afterHooks = Cucumber.Type.Collection();
var stepDefinitions = Cucumber.Type.Collection();
+ var hooker = Cucumber.SupportCode.Library.Hooker();
var worldConstructor = Cucumber.SupportCode.WorldConstructor();
var self = {
@@ -24,26 +23,21 @@ var Library = function(supportCodeDefinition) {
return (stepDefinition != undefined);
},
- defineBeforeHook: function defineBeforeHook(code) {
- var beforeHook = Cucumber.SupportCode.Hook(code);
- beforeHooks.add(beforeHook);
+ hookUpFunctionWithWorld: function hookUpFunctionWithWorld(userFunction, world) {
+ var hookedUpFunction = hooker.hookUpFunctionWithWorld(userFunction, world);
+ return hookedUpFunction;
},
- triggerBeforeHooks: function(world, callback) {
- beforeHooks.forEach(function(beforeHook, callback) {
- beforeHook.invoke(world, callback);
- }, callback);
+ defineAroundHook: function defineAroundHook(code) {
+ hooker.addAroundHookCode(code);
},
- defineAfterHook: function defineAfterHook(code) {
- var afterHook = Cucumber.SupportCode.Hook(code);
- afterHooks.unshift(afterHook);
+ defineBeforeHook: function defineBeforeHook(code) {
+ hooker.addBeforeHookCode(code);
},
- triggerAfterHooks: function(world, callback) {
- afterHooks.forEach(function(afterHook, callback) {
- afterHook.invoke(world, callback);
- }, callback);
+ defineAfterHook: function defineAfterHook(code) {
+ hooker.addAfterHookCode(code);
},
defineStep: function defineStep(name, code) {
@@ -64,6 +58,7 @@ var Library = function(supportCodeDefinition) {
};
var supportCodeHelper = {
+ Around : self.defineAroundHook,
Before : self.defineBeforeHook,
After : self.defineAfterHook,
Given : self.defineStep,
@@ -77,4 +72,5 @@ var Library = function(supportCodeDefinition) {
return self;
};
+Library.Hooker = require('./library/hooker');
module.exports = Library;
View
76 lib/cucumber/support_code/library/hooker.js
@@ -0,0 +1,76 @@
+var Hooker = function() {
+ var Cucumber = require('../../../cucumber');
+
+ var aroundHooks = Cucumber.Type.Collection();
+ var beforeHooks = Cucumber.Type.Collection();
+ var afterHooks = Cucumber.Type.Collection();
+
+ var self = {
+ addAroundHookCode: function addAroundHookCode(code) {
+ var aroundHook = Cucumber.SupportCode.Hook(code);
+ aroundHooks.add(aroundHook);
+ },
+
+ addBeforeHookCode: function addBeforeHookCode(code) {
+ var beforeHook = Cucumber.SupportCode.Hook(code);
+ beforeHooks.add(beforeHook);
+ },
+
+ addAfterHookCode: function addAfterHookCode(code) {
+ var afterHook = Cucumber.SupportCode.Hook(code);
+ afterHooks.unshift(afterHook);
+ },
+
+ hookUpFunctionWithWorld: function hookUpFunctionWithWorld(userFunction, world) {
+ var hookedUpFunction = function(callback) {
+ var postScenarioAroundHookCallbacks = Cucumber.Type.Collection();
+ aroundHooks.forEach(callPreScenarioAroundHook, callBeforeHooks);
+
+ function callPreScenarioAroundHook(aroundHook, preScenarioAroundHookCallback) {
+ aroundHook.invoke(world, function(postScenarioAroundHookCallback) {
+ postScenarioAroundHookCallbacks.unshift(postScenarioAroundHookCallback);
+ preScenarioAroundHookCallback();
+ });
+ }
+
+ function callBeforeHooks() {
+ self.triggerBeforeHooks(world, callUserFunction);
+ }
+
+ function callUserFunction() {
+ userFunction(callAfterHooks);
+ }
+
+ function callAfterHooks() {
+ self.triggerAfterHooks(world, callPostScenarioAroundHooks);
+ }
+
+ function callPostScenarioAroundHooks() {
+ postScenarioAroundHookCallbacks.forEach(
+ callPostScenarioAroundHook,
+ callback
+ );
+ }
+
+ function callPostScenarioAroundHook(postScenarioAroundHookCallback, callback) {
+ postScenarioAroundHookCallback.call(world, callback);
+ }
+ };
+ return hookedUpFunction;
+ },
+
+ triggerBeforeHooks: function triggerBeforeHooks(world, callback) {
+ beforeHooks.forEach(function(beforeHook, callback) {
+ beforeHook.invoke(world, callback);
+ }, callback);
+ },
+
+ triggerAfterHooks: function triggerAfterHooks(world, callback) {
+ afterHooks.forEach(function(afterHook, callback) {
+ afterHook.invoke(world, callback);
+ }, callback);
+ }
+ };
+ return self;
+};
+module.exports = Hooker;
View
3 lib/cucumber/type/collection.js
@@ -21,7 +21,8 @@ var Collection = function() {
});
};
iterate();
- }
+ },
+ length: function length() { return items.length; }
};
return self;
};
View
36 spec/cucumber/runtime/ast_tree_walker_spec.js
@@ -162,10 +162,9 @@ describe("Cucumber.Runtime.AstTreeWalker", function() {
describe("visitScenario()", function() {
var scenario, callback;
- var world;
beforeEach(function() {
- scenario = createSpyWithStubs("Scenario AST element", {acceptVisitor: null});
+ scenario = createSpyWithStubs("scenario");
callback = createSpy("Callback");
spyOnStub(supportCodeLibrary, 'instantiateNewWorld');
});
@@ -177,21 +176,22 @@ describe("Cucumber.Runtime.AstTreeWalker", function() {
});
describe("on world instantiation completion", function() {
- var worldInstantiationCompletionCallback, world, event, payload, hookedUpFunction;
+ var worldInstantiationCompletionCallback;
+ var world, event, payload;
+ var hookedUpScenarioVisit;
beforeEach(function() {
- world = createSpy("world instance");
treeWalker.visitScenario(scenario, callback);
worldInstantiationCompletionCallback = supportCodeLibrary.instantiateNewWorld.mostRecentCall.args[0];
-
- event = createSpy("Event");
- payload = {scenario: scenario};
- scenarioVisitWithHooks = createSpy("scenario visit with hooks");
- spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
- spyOn(treeWalker, 'broadcastEventAroundUserFunction');
+ world = createSpy("world instance");
+ event = createSpy("scenario visit event");
+ hookedUpScenarioVisit = createSpy("hooked up scenario visit");
+ payload = {scenario: scenario};
spyOn(treeWalker, 'setWorld');
spyOn(treeWalker, 'witnessNewScenario');
- spyOn(treeWalker, 'hookUpFunction').andReturn(scenarioVisitWithHooks);
+ spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
+ spyOnStub(supportCodeLibrary, 'hookUpFunctionWithWorld').andReturn(hookedUpScenarioVisit);
+ spyOn(treeWalker, 'broadcastEventAroundUserFunction');
});
it("sets the new World instance", function() {
@@ -211,28 +211,30 @@ describe("Cucumber.Runtime.AstTreeWalker", function() {
it("hooks up a function", function() {
worldInstantiationCompletionCallback(world);
- expect(treeWalker.hookUpFunction).toHaveBeenCalled();
- expect(treeWalker.hookUpFunction).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ expect(supportCodeLibrary.hookUpFunctionWithWorld).toHaveBeenCalled();
+ expect(supportCodeLibrary.hookUpFunctionWithWorld).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ expect(supportCodeLibrary.hookUpFunctionWithWorld).toHaveBeenCalledWithValueAsNthParameter(world, 2);
});
describe("hooked up function", function() {
var hookedUpFunction, hookedUpFunctionCallback;
beforeEach(function() {
- hookedUpFunctionCallback = createSpy("hooked up function callback");
worldInstantiationCompletionCallback(world);
- hookedUpFunction = treeWalker.hookUpFunction.mostRecentCall.args[0];
+ hookedUpFunction = supportCodeLibrary.hookUpFunctionWithWorld.mostRecentCall.args[0];
+ hookedUpFunctionCallback = createSpy("hooked up function callback");
+ spyOnStub(scenario, 'acceptVisitor');
});
- it("tells the scenario to accept the tree walker itself as a visitor", function() {
+ it("instructs the scenario to accept the tree walker as a visitor", function() {
hookedUpFunction(hookedUpFunctionCallback);
expect(scenario.acceptVisitor).toHaveBeenCalledWith(treeWalker, hookedUpFunctionCallback);
});
});
it("broadcasts the visit of the scenario", function() {
worldInstantiationCompletionCallback(world);
- expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalledWith(event, scenarioVisitWithHooks, callback);
+ expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalledWith(event, hookedUpScenarioVisit, callback);
});
});
});
View
309 spec/cucumber/support_code/library/hooker_spec.js
@@ -0,0 +1,309 @@
+require('../../../support/spec_helper');
+
+describe("Cucumber.SupportCode.Library.Hooker", function() {
+ var Cucumber = requireLib('cucumber');
+ var hooker, aroundHooks, beforeHooks, afterHooks;
+
+ beforeEach(function() {
+ aroundHooks = createSpy("around hook collection");
+ beforeHooks = createSpy("before hook collection");
+ afterHooks = createSpy("after hook collection");
+ spyOn(Cucumber.Type, 'Collection').andReturnSeveral([aroundHooks, beforeHooks, afterHooks]);
+ hooker = Cucumber.SupportCode.Library.Hooker();
+ });
+
+ describe("constructor", function() {
+ it("creates collections of around, before and after hooks", function() {
+ expect(Cucumber.Type.Collection).toHaveBeenCalled();
+ expect(Cucumber.Type.Collection.callCount).toBe(3);
+ });
+ });
+
+ describe("addAroundHookCode", function() {
+ var aroundHook, code;
+
+ beforeEach(function() {
+ code = createSpy("around code");
+ aroundHook = createSpy("around hook");
+ spyOn(Cucumber.SupportCode, "Hook").andReturn(aroundHook);
+ spyOnStub(aroundHooks, "add");
+ });
+
+ it("creates an around hook with the code", function() {
+ hooker.addAroundHookCode(code);
+ expect(Cucumber.SupportCode.Hook).toHaveBeenCalledWith(code);
+ });
+
+ it("unshifts the around hook to the around hook collection", function() {
+ hooker.addAroundHookCode(code);
+ expect(aroundHooks.add).toHaveBeenCalledWith(aroundHook);
+ });
+ });
+
+ describe("addBeforeHookCode", function() {
+ var beforeHook, code;
+
+ beforeEach(function() {
+ code = createSpy("before code");
+ beforeHook = createSpy("before hook");
+ spyOn(Cucumber.SupportCode, "Hook").andReturn(beforeHook);
+ spyOnStub(beforeHooks, "add");
+ });
+
+ it("creates a before hook with the code", function() {
+ hooker.addBeforeHookCode(code);
+ expect(Cucumber.SupportCode.Hook).toHaveBeenCalledWith(code);
+ });
+
+ it("adds the before hook to the before hook collection", function() {
+ hooker.addBeforeHookCode(code);
+ expect(beforeHooks.add).toHaveBeenCalledWith(beforeHook);
+ });
+ });
+
+ describe("addAfterHookCode", function() {
+ var afterHook, code;
+
+ beforeEach(function() {
+ code = createSpy("after code");
+ afterHook = createSpy("after hook");
+ spyOn(Cucumber.SupportCode, "Hook").andReturn(afterHook);
+ spyOnStub(afterHooks, "unshift");
+ });
+
+ it("creates a after hook with the code", function() {
+ hooker.addAfterHookCode(code);
+ expect(Cucumber.SupportCode.Hook).toHaveBeenCalledWith(code);
+ });
+
+ it("prepends the after hook to the after hook collection", function() {
+ hooker.addAfterHookCode(code);
+ expect(afterHooks.unshift).toHaveBeenCalledWith(afterHook);
+ });
+ });
+
+ describe("hookUpFunctionWithWorld()", function() {
+ var userFunction, world;
+
+ beforeEach(function() {
+ userFunction = createSpy("user function");
+ world = createSpy("world instance");
+ });
+
+ it("returns a function", function() {
+ expect(hooker.hookUpFunctionWithWorld(userFunction, world)).toBeAFunction();
+ });
+
+ describe("returned function", function() {
+ var returnedFunction, callback, postScenarioAroundHookCallbacks;
+
+ beforeEach(function() {
+ returnedFunction = hooker.hookUpFunctionWithWorld(userFunction, world);
+ callback = createSpy("callback");
+ postScenarioAroundHookCallbacks = createSpy("post-scenario around hook callbacks");
+ spyOnStub(aroundHooks, 'forEach');
+ Cucumber.Type.Collection.reset();
+ Cucumber.Type.Collection.andReturn(postScenarioAroundHookCallbacks);
+ });
+
+ it("instantiates a collection for the post-scenario around hook callbacks", function() {
+ returnedFunction(callback);
+ expect(Cucumber.Type.Collection).toHaveBeenCalled();
+ });
+
+ it("iterates over the around hooks", function() {
+ returnedFunction(callback);
+ expect(aroundHooks.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ expect(aroundHooks.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(2);
+ });
+
+ describe("for each around hook", function() {
+ var aroundHookIteration, aroundHook, iterationCallback;
+
+ beforeEach(function() {
+ aroundHook = createSpyWithStubs("around hook", {invoke: null});
+ iterationCallback = createSpy("iteration callback");
+ returnedFunction(callback);
+ aroundHookIteration = aroundHooks.forEach.mostRecentCall.args[0];
+ });
+
+ it("invokes the around hook with the world instance", function() {
+ aroundHookIteration(aroundHook, iterationCallback);
+ expect(aroundHook.invoke).toHaveBeenCalled();
+ expect(aroundHook.invoke).toHaveBeenCalledWithValueAsNthParameter(world, 1);
+ expect(aroundHook.invoke).toHaveBeenCalledWithAFunctionAsNthParameter(2);
+ });
+
+ describe("on around hook invocation completion", function() {
+ var invocationCompletionCallback, postScenarioAroundHookCallback;
+
+ beforeEach(function() {
+ aroundHookIteration(aroundHook, iterationCallback);
+ invocationCompletionCallback = aroundHook.invoke.mostRecentCall.args[1];
+ postScenarioAroundHookCallback = createSpy("post-scenario around hook callback");
+ spyOnStub(postScenarioAroundHookCallbacks, 'unshift');
+ });
+
+ it("prepends the returned post-scenario hook callback to the post-scenario hook callback collection", function() {
+ invocationCompletionCallback(postScenarioAroundHookCallback);
+ expect(postScenarioAroundHookCallbacks.unshift).toHaveBeenCalledWith(postScenarioAroundHookCallback);
+ });
+
+ it("calls back", function() {
+ invocationCompletionCallback(postScenarioAroundHookCallback);
+ expect(iterationCallback).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("on around hook look completion", function() {
+ var aroundHooksLoopCallback;
+
+ beforeEach(function() {
+ returnedFunction(callback);
+ aroundHooksLoopCallback = aroundHooks.forEach.mostRecentCall.args[1];
+ spyOn(hooker, 'triggerBeforeHooks');
+ });
+
+ it("triggers the before hooks", function() {
+ aroundHooksLoopCallback();
+ expect(hooker.triggerBeforeHooks).toHaveBeenCalled();
+ expect(hooker.triggerBeforeHooks).toHaveBeenCalledWithValueAsNthParameter(world, 1);
+ expect(hooker.triggerBeforeHooks).toHaveBeenCalledWithAFunctionAsNthParameter(2);
+ });
+
+ describe("on before hooks completion", function() {
+ var beforeHooksCompletionCallback;
+
+ beforeEach(function() {
+ aroundHooksLoopCallback();
+ beforeHooksCompletionCallback = hooker.triggerBeforeHooks.mostRecentCall.args[1];
+ });
+
+ it("calls the user function", function() {
+ beforeHooksCompletionCallback();
+ expect(userFunction).toHaveBeenCalled();
+ expect(userFunction).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ });
+
+ describe("on user function completion", function() {
+ var userFunctionCallback;
+
+ beforeEach(function() {
+ beforeHooksCompletionCallback();
+ userFunctionCallback = userFunction.mostRecentCall.args[0];
+ spyOn(hooker, 'triggerAfterHooks');
+ });
+
+ it("triggers the after hooks", function() {
+ userFunctionCallback();
+ expect(hooker.triggerAfterHooks).toHaveBeenCalled();
+ expect(hooker.triggerAfterHooks).toHaveBeenCalledWithValueAsNthParameter(world, 1);
+ expect(hooker.triggerAfterHooks).toHaveBeenCalledWithAFunctionAsNthParameter(2);
+ });
+
+ describe("on after hooks completion", function() {
+ var afterHooksCompletionCallback;
+
+ beforeEach(function() {
+ userFunctionCallback();
+ afterHooksCompletionCallback = hooker.triggerAfterHooks.mostRecentCall.args[1];
+ spyOnStub(postScenarioAroundHookCallbacks, 'forEach');
+ });
+
+ it("iterates over the post-scenario around hook callbacks", function() {
+ afterHooksCompletionCallback();
+ expect(postScenarioAroundHookCallbacks.forEach).toHaveBeenCalled();
+ expect(postScenarioAroundHookCallbacks.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ expect(postScenarioAroundHookCallbacks.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
+ });
+
+ describe("for each post-scenario around hook", function() {
+ var postScenarioAroundHookIteration, postScenarioAroundHookCallback, postScenarioAroundHookIterationCallback;
+
+ beforeEach(function() {
+ afterHooksCompletionCallback();
+ postScenarioAroundHookIteration = postScenarioAroundHookCallbacks.forEach.mostRecentCall.args[0];
+ postScenarioAroundHookCallback = createSpy("post-scenario around hook callback");
+ postScenarioAroundHookIterationCallback = createSpy("post-scenario around hook iteration callback");
+ });
+
+ it("calls the post-scenario around hook callback", function() {
+ postScenarioAroundHookIteration(postScenarioAroundHookCallback, postScenarioAroundHookIterationCallback);
+ expect(postScenarioAroundHookCallback).toHaveBeenCalledWith(postScenarioAroundHookIterationCallback);
+ expect(postScenarioAroundHookCallback.mostRecentCall.object).toBe(world);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+
+ describe("triggerBeforeHooks", function() {
+ var world, callback;
+
+ beforeEach(function() {
+ world = createSpy("world");
+ callback = createSpy("callback");
+ spyOnStub(beforeHooks, 'forEach');
+ });
+
+ it("iterates over the before hooks", function() {
+ hooker.triggerBeforeHooks(world, callback);
+ expect(beforeHooks.forEach).toHaveBeenCalled();
+ expect(beforeHooks.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ expect(beforeHooks.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
+ });
+
+ describe("for each before hook", function() {
+ var beforeHook, forEachBeforeHookFunction, forEachBeforeHookFunctionCallback;
+
+ beforeEach(function() {
+ hooker.triggerBeforeHooks(world, callback);
+ forEachBeforeHookFunction = beforeHooks.forEach.mostRecentCall.args[0];
+ forEachBeforeHookFunctionCallback = createSpy("for each before hook iteration callback");
+ beforeHook = createSpyWithStubs("before hook", {invoke: null});
+ });
+
+ it("invokes the hook", function() {
+ forEachBeforeHookFunction(beforeHook, forEachBeforeHookFunctionCallback);
+ expect(beforeHook.invoke).toHaveBeenCalledWith(world, forEachBeforeHookFunctionCallback);
+ });
+ });
+ });
+
+ describe("triggerAfterHooks", function() {
+ var world, callback;
+
+ beforeEach(function() {
+ world = createSpy("world");
+ callback = createSpy("callback");
+ spyOnStub(afterHooks, 'forEach');
+ });
+
+ it("iterates over the after hooks", function() {
+ hooker.triggerAfterHooks(world, callback);
+ expect(afterHooks.forEach).toHaveBeenCalled();
+ expect(afterHooks.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ expect(afterHooks.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
+ });
+
+ describe("for each after hook", function() {
+ var afterHook, forEachAfterHookFunction, forEachAfterHookFunctionCallback;
+
+ beforeEach(function() {
+ hooker.triggerAfterHooks(world, callback);
+ forEachAfterHookFunction = afterHooks.forEach.mostRecentCall.args[0];
+ forEachAfterHookFunctionCallback = createSpy("for each after hook iteration callback");
+ afterHook = createSpyWithStubs("after hook", {invoke: null});
+ });
+
+ it("invokes the hook", function() {
+ forEachAfterHookFunction(afterHook, forEachAfterHookFunctionCallback);
+ expect(afterHook.invoke).toHaveBeenCalledWith(world, forEachAfterHookFunctionCallback);
+ });
+ });
+ });
+});
View
135 spec/cucumber/support_code/library_spec.js
@@ -2,33 +2,33 @@ require('../../support/spec_helper');
describe("Cucumber.SupportCode.Library", function() {
var Cucumber = requireLib('cucumber');
- var library, rawSupportCode;
- var beforeHookCollection;
- var afterHookCollection;
+ var library, rawSupportCode, hooker;
var stepDefinitionCollection;
var worldConstructor;
- var spiesDuringSupportCodeDefinitionExecution = {};
beforeEach(function() {
- rawSupportCode = createSpy("Raw support code");
- beforeHookCollection = createSpy("before hook collection");
- afterHookCollection = createSpy("after hook collection");
+ rawSupportCode = createSpy("Raw support code");
stepDefinitionCollection = [
createSpyWithStubs("First step definition", {matchesStepName:false}),
createSpyWithStubs("Second step definition", {matchesStepName:false}),
createSpyWithStubs("Third step definition", {matchesStepName:false})
];
+ hooker = createSpyWithStubs("hooker");
worldConstructor = createSpy("world constructor");
spyOnStub(stepDefinitionCollection, 'syncForEach').andCallFake(function(cb) { stepDefinitionCollection.forEach(cb); });
- spyOn(Cucumber.Type, 'Collection').andReturnSeveral([beforeHookCollection, afterHookCollection, stepDefinitionCollection]);
+ spyOn(Cucumber.Type, 'Collection').andReturn(stepDefinitionCollection);
+ spyOn(Cucumber.SupportCode.Library, 'Hooker').andReturn(hooker);
spyOn(Cucumber.SupportCode, 'WorldConstructor').andReturn(worldConstructor);
library = Cucumber.SupportCode.Library(rawSupportCode);
});
describe("constructor", function() {
- it("creates collecitons of before hooks, after hooks and step definitions", function() {
+ it("creates a collection of step definitions", function() {
expect(Cucumber.Type.Collection).toHaveBeenCalled();
- expect(Cucumber.Type.Collection.callCount).toBe(3);
+ });
+
+ it("instantiates a hooker", function() {
+ expect(Cucumber.SupportCode.Library.Hooker).toHaveBeenCalled();
});
it("executes the raw support code", function() {
@@ -50,6 +50,11 @@ describe("Cucumber.SupportCode.Library", function() {
supportCodeHelper = rawSupportCode.mostRecentCall.object;
});
+ it("exposes a method to define Around hooks", function() {
+ expect(supportCodeHelper.Around).toBeAFunction();
+ expect(supportCodeHelper.Around).toBe(library.defineAroundHook);
+ });
+
it("exposes a method to define Before hooks", function() {
expect(supportCodeHelper.Before).toBeAFunction();
expect(supportCodeHelper.Before).toBe(library.defineBeforeHook);
@@ -144,111 +149,65 @@ describe("Cucumber.SupportCode.Library", function() {
});
});
- describe("defineBeforeHook", function() {
- var beforeHook, code;
+ describe("hookUpFunctionWithWorld", function() {
+ var userFunction, world, hookedUpFunction;
beforeEach(function() {
- code = createSpy("before code");
- beforeHook = createSpy("before hook");
- spyOn(Cucumber.SupportCode, "Hook").andReturn(beforeHook);
- spyOnStub(beforeHookCollection, "add");
+ userFunction = createSpy("user function");
+ hookedUpFunction = createSpy("hooked up function");
+ world = createSpy("world instance");
+ spyOnStub(hooker, 'hookUpFunctionWithWorld').andReturn(hookedUpFunction);
});
- it("creates a before hook with the code", function() {
- library.defineBeforeHook(code);
- expect(Cucumber.SupportCode.Hook).toHaveBeenCalledWith(code);
+ it("hooks up the function with the world instance", function() {
+ library.hookUpFunctionWithWorld(userFunction, world);
+ expect(hooker.hookUpFunctionWithWorld).toHaveBeenCalledWith(userFunction, world);
});
- it("adds the before hook to the before hooks collection", function() {
- library.defineBeforeHook(code);
- expect(beforeHookCollection.add).toHaveBeenCalledWith(beforeHook);
+ it("returns the hooked up function", function() {
+ expect(library.hookUpFunctionWithWorld(userFunction, world)).toBe(hookedUpFunction);
});
});
- describe("triggerBeforeHooks", function() {
- var world, callback;
+ describe("defineAroundHook", function() {
+ var code;
beforeEach(function() {
- world = createSpy("world");
- callback = createSpy("callback");
- spyOnStub(beforeHookCollection, 'forEach');
+ code = createSpy("hook code");
+ spyOnStub(hooker, 'addAroundHookCode');
});
- it("iterates over the before hooks", function() {
- library.triggerBeforeHooks(world, callback);
- expect(beforeHookCollection.forEach).toHaveBeenCalled();
- expect(beforeHookCollection.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
- expect(beforeHookCollection.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
- });
-
- describe("for each before hook", function() {
- var beforeHook, forEachBeforeHookFunction, forEachBeforeHookFunctionCallback;
-
- beforeEach(function() {
- library.triggerBeforeHooks(world, callback);
- forEachBeforeHookFunction = beforeHookCollection.forEach.mostRecentCall.args[0];
- forEachBeforeHookFunctionCallback = createSpy("for each before hook iteration callback");
- beforeHook = createSpyWithStubs("before hook", {invoke: null});
- });
-
- it("invokes the hook", function() {
- forEachBeforeHookFunction(beforeHook, forEachBeforeHookFunctionCallback);
- expect(beforeHook.invoke).toHaveBeenCalledWith(world, forEachBeforeHookFunctionCallback);
- });
+ it("instructs the hooker to use the code as an around hook", function() {
+ library.defineAroundHook(code);
+ expect(hooker.addAroundHookCode).toHaveBeenCalledWith(code);
});
});
- describe("defineAfterHook", function() {
- var afterHook, code;
+ describe("defineBeforeHook", function() {
+ var code;
beforeEach(function() {
- code = createSpy("after code");
- afterHook = createSpy("after hook");
- spyOn(Cucumber.SupportCode, "Hook").andReturn(afterHook);
- spyOnStub(afterHookCollection, "unshift");
- });
-
- it("creates a after hook with the code", function() {
- library.defineAfterHook(code);
- expect(Cucumber.SupportCode.Hook).toHaveBeenCalledWith(code);
+ code = createSpy("hook code");
+ spyOnStub(hooker, 'addBeforeHookCode');
});
- it("adds the after hook to the after hooks collection", function() {
- library.defineAfterHook(code);
- expect(afterHookCollection.unshift).toHaveBeenCalledWith(afterHook);
+ it("instructs the hooker to use the code as an before hook", function() {
+ library.defineBeforeHook(code);
+ expect(hooker.addBeforeHookCode).toHaveBeenCalledWith(code);
});
});
- describe("triggerAfterHooks", function() {
- var world, callback;
+ describe("defineAfterHook", function() {
+ var code;
beforeEach(function() {
- world = createSpy("world");
- callback = createSpy("callback");
- spyOnStub(afterHookCollection, 'forEach');
+ code = createSpy("hook code");
+ spyOnStub(hooker, 'addAfterHookCode');
});
- it("iterates over the after hooks", function() {
- library.triggerAfterHooks(world, callback);
- expect(afterHookCollection.forEach).toHaveBeenCalled();
- expect(afterHookCollection.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
- expect(afterHookCollection.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
- });
-
- describe("for each after hook", function() {
- var afterHook, forEachAfterHookFunction, forEachAfterHookFunctionCallback;
-
- beforeEach(function() {
- library.triggerAfterHooks(world, callback);
- forEachAfterHookFunction = afterHookCollection.forEach.mostRecentCall.args[0];
- forEachAfterHookFunctionCallback = createSpy("for each after hook iteration callback");
- afterHook = createSpyWithStubs("after hook", {invoke: null});
- });
-
- it("invokes the hook", function() {
- forEachAfterHookFunction(afterHook, forEachAfterHookFunctionCallback);
- expect(afterHook.invoke).toHaveBeenCalledWith(world, forEachAfterHookFunctionCallback);
- });
+ it("instructs the hooker to use the code as an after hook", function() {
+ library.defineAfterHook(code);
+ expect(hooker.addAfterHookCode).toHaveBeenCalledWith(code);
});
});

0 comments on commit 2bc9537

Please sign in to comment.
Something went wrong with that request. Please try again.