cucumber
Version:
The official JavaScript implementation of Cucumber.
1,328 lines (1,075 loc) • 56.9 kB
JavaScript
var domain = require('domain');
require('../../support/spec_helper');
describe("Cucumber.Runtime.AstTreeWalker", function () {
var Cucumber = requireLib('cucumber');
var beforeStepCollection, afterStepCollection, attachmentCollection, emptyHook;
var walkDomain;
var treeWalker, features, supportCodeLibrary, listeners, supportListeners;
beforeEach(function () {
features = createSpyWithStubs("Features AST element", {acceptVisitor: null});
supportCodeLibrary = createSpy("Support code library");
listeners = [createSpy("First listener"), createSpy("Second listener")];
supportListeners = [createSpy("First support listener"), createSpy("Second support listener")];
walkDomain = createSpy("walk domain");
spyOnStub(listeners, 'syncForEach').andCallFake(function (cb) { listeners.forEach(cb); });
spyOnStub(supportListeners, 'syncForEach').andCallFake(function (cb) { supportListeners.forEach(cb); });
spyOnStub(supportCodeLibrary, 'getListeners').andReturn(supportListeners);
beforeStepCollection = createSpyWithStubs("before step collection", {add: undefined, unshift: undefined, clear: undefined, forEach: undefined});
afterStepCollection = createSpyWithStubs("after step collection", {add: undefined, unshift: undefined, clear: undefined, forEach: undefined});
attachmentCollection = createSpyWithStubs("attachment collection", {add: undefined, unshift: undefined, clear: undefined, forEach: undefined});
emptyHook = createSpy("empty hook");
spyOn(Cucumber.Type, 'Collection').andReturnSeveral([beforeStepCollection, afterStepCollection, attachmentCollection]);
spyOn(Cucumber.SupportCode, "Hook").andReturn(emptyHook);
spyOn(domain, 'create').andReturn(walkDomain);
treeWalker = Cucumber.Runtime.AstTreeWalker(features, supportCodeLibrary, listeners);
});
it("creates a domain", function () {
expect(domain.create).toHaveBeenCalled();
});
describe("walk()", function () {
var callback;
beforeEach(function () {
callback = createSpy("Callback");
spyOn(treeWalker, 'visitFeatures');
});
describe("when the walk domain can be entered", function () {
beforeEach(function () {
spyOnStub(walkDomain, 'enter');
});
it("enters the domain", function () {
treeWalker.walk(callback);
expect(walkDomain.enter).toHaveBeenCalled();
});
});
it("visits all features with a callback", function () {
treeWalker.walk(callback);
expect(treeWalker.visitFeatures).
toHaveBeenCalledWithValueAsNthParameter(features, 1);
expect(treeWalker.visitFeatures).
toHaveBeenCalledWithAFunctionAsNthParameter(2);
});
describe("features visit callback", function () {
var featuresVisitCallback, featuresResult;
beforeEach(function () {
treeWalker.walk(callback);
featuresVisitCallback = treeWalker.visitFeatures.mostRecentCall.args[1];
featuresResult = createSpy("result of all features");
spyOn(treeWalker, 'didAllFeaturesSucceed').andReturn(featuresResult);
});
describe("when the walk domain can be exited", function () {
beforeEach(function () {
spyOnStub(walkDomain, 'exit');
});
it("exits the domain", function () {
featuresVisitCallback();
expect(walkDomain.exit).toHaveBeenCalled();
});
});
it("checks whether all features were successful", function () {
featuresVisitCallback();
expect(treeWalker.didAllFeaturesSucceed).toHaveBeenCalled();
});
it("calls back with the result of the features", function () {
featuresVisitCallback();
expect(callback).toHaveBeenCalledWith(featuresResult);
});
});
});
describe("visitFeatures()", function () {
var callback, event, payload;
beforeEach(function () {
callback = createSpy("Callback");
event = createSpy("Event");
payload = {features: features};
spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
spyOn(treeWalker, 'broadcastEventAroundUserFunction');
});
it("creates a new event about the features' visit", function () {
treeWalker.visitFeatures(features, callback);
expect(Cucumber.Runtime.AstTreeWalker.Event).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.FEATURES_EVENT_NAME, payload);
});
it("broadcasts the visit of the features", function () {
treeWalker.visitFeatures(features, callback);
expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalled();
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithValueAsNthParameter(event, 1);
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithAFunctionAsNthParameter(2);
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithValueAsNthParameter(callback, 3);
});
describe("user function", function () {
var userFunction, userFunctionCallback;
beforeEach(function () {
userFunctionCallback = createSpy("User function callback");
treeWalker.visitFeatures(features, callback);
userFunction = treeWalker.broadcastEventAroundUserFunction.mostRecentCall.args[1];
});
it("visits the features, passing it the received callback", function () {
userFunction (userFunctionCallback);
expect(features.acceptVisitor).toHaveBeenCalledWith(treeWalker, userFunctionCallback);
});
});
});
describe("visitFeature()", function () {
var feature, callback, event, payload;
beforeEach(function () {
feature = createSpyWithStubs("Feature AST element", {acceptVisitor: null});
callback = createSpy("Callback");
event = createSpy("Event");
payload = {feature: feature};
spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
spyOn(treeWalker, 'broadcastEventAroundUserFunction');
});
it("creates a new event about the feature' visit", function () {
treeWalker.visitFeature(feature, callback);
expect(Cucumber.Runtime.AstTreeWalker.Event).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.FEATURE_EVENT_NAME, payload);
});
it("broadcasts the visit of the feature", function () {
treeWalker.visitFeature(feature, callback);
expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalled();
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithValueAsNthParameter(event, 1);
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithAFunctionAsNthParameter(2);
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithValueAsNthParameter(callback, 3);
});
describe("user function", function () {
var userFunction, userFunctionCallback;
beforeEach(function () {
userFunctionCallback = createSpy("User function callback");
treeWalker.visitFeature(feature, callback);
userFunction = treeWalker.broadcastEventAroundUserFunction.mostRecentCall.args[1];
});
it("visits the feature, passing it the received callback", function () {
userFunction (userFunctionCallback);
expect(feature.acceptVisitor).toHaveBeenCalledWith(treeWalker, userFunctionCallback);
});
});
});
describe("visitBackground()", function () {
var background, scenario, callback, event, payload;
beforeEach(function () {
scenario = createSpyWithStubs('background AST element');
callback = createSpy('callback');
event = createSpy('event');
payload = {background: background};
spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
spyOn(treeWalker, 'broadcastEvent');
});
it("creates a new event about the background", function () {
treeWalker.visitBackground(background, callback);
expect(Cucumber.Runtime.AstTreeWalker.Event).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.BACKGROUND_EVENT_NAME, payload);
});
it("broadcasts the visit of the background", function () {
treeWalker.visitBackground(background, callback);
expect(treeWalker.broadcastEvent).toHaveBeenCalledWith(event, callback);
});
});
describe("visitScenario()", function () {
var scenario, callback;
beforeEach(function () {
scenario = createSpyObj("scenario",['mock']);
callback = createSpy("Callback");
spyOnStub(supportCodeLibrary, 'instantiateNewWorld');
});
it("instantiates a new World instance asynchronously", function () {
treeWalker.visitScenario(scenario, callback);
expect(supportCodeLibrary.instantiateNewWorld).toHaveBeenCalled();
expect(supportCodeLibrary.instantiateNewWorld).toHaveBeenCalledWithAFunctionAsNthParameter(1);
});
describe("on world instantiation completion", function () {
var worldInstantiationCompletionCallback;
var world, event, payload;
var hookedUpScenarioVisit;
beforeEach(function () {
treeWalker.visitScenario(scenario, callback);
worldInstantiationCompletionCallback = supportCodeLibrary.instantiateNewWorld.mostRecentCall.args[0];
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, 'createBeforeAndAfterStepsForAroundHooks');
spyOn(treeWalker, 'createBeforeStepsForBeforeHooks');
spyOn(treeWalker, 'createAfterStepsForAfterHooks');
spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
spyOnStub(supportCodeLibrary, 'hookUpFunction').andReturn(hookedUpScenarioVisit);
spyOn(treeWalker, 'broadcastEventAroundUserFunction');
});
it("sets the new World instance", function () {
worldInstantiationCompletionCallback(world);
expect(treeWalker.setWorld).toHaveBeenCalledWith(world);
});
it("witnesses a new scenario", function () {
worldInstantiationCompletionCallback(world);
expect(treeWalker.witnessNewScenario).toHaveBeenCalledWith(scenario);
});
it("creates before and after steps for around hooks", function () {
worldInstantiationCompletionCallback(world);
expect(treeWalker.createBeforeAndAfterStepsForAroundHooks).toHaveBeenCalledWith(scenario);
});
it("creates before steps for before hooks", function () {
worldInstantiationCompletionCallback(world);
expect(treeWalker.createBeforeStepsForBeforeHooks).toHaveBeenCalledWith(scenario);
});
it("creates after steps for after hooks", function () {
worldInstantiationCompletionCallback(world);
expect(treeWalker.createAfterStepsForAfterHooks).toHaveBeenCalledWith(scenario);
});
it("creates a new event about the scenario", function () {
worldInstantiationCompletionCallback(world);
expect(Cucumber.Runtime.AstTreeWalker.Event).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.SCENARIO_EVENT_NAME, payload);
});
it("broadcasts the visit of the scenario", function () {
worldInstantiationCompletionCallback(world);
expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalled();
expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalledWithValueAsNthParameter(event, 1);
expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalledWithAFunctionAsNthParameter(2);
expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalledWithValueAsNthParameter(callback, 3);
});
describe("on broadcast of the visit of the scenario", function () {
var userFunction, userFunctionCallback;
beforeEach(function () {
worldInstantiationCompletionCallback(world);
userFunction = treeWalker.broadcastEventAroundUserFunction.mostRecentCall.args[1];
userFunctionCallback = createSpy("user function callback");
spyOn(treeWalker, 'visitBeforeSteps');
userFunction (userFunctionCallback);
});
it("visits the before steps", function () {
expect(treeWalker.visitBeforeSteps).toHaveBeenCalled();
});
describe("after visiting the before steps", function () {
beforeEach(function () {
spyOnStub(scenario, 'acceptVisitor');
var visitBeforeStepsCallback = treeWalker.visitBeforeSteps.mostRecentCall.args[0];
visitBeforeStepsCallback();
});
it("instructs the scenario to accept the tree walker as a visitor", function () {
expect(scenario.acceptVisitor).toHaveBeenCalled();
expect(scenario.acceptVisitor).toHaveBeenCalledWithValueAsNthParameter(treeWalker, 1);
});
describe("after visiting the scenario", function () {
beforeEach(function () {
spyOn(treeWalker, 'visitAfterSteps');
var acceptVisitorCallback = scenario.acceptVisitor.mostRecentCall.args[1];
acceptVisitorCallback();
});
it("visits the after steps", function () {
expect(treeWalker.visitAfterSteps).toHaveBeenCalled();
});
describe("after visiting the after steps", function () {
beforeEach(function () {
var visitAfterStepsCallback = treeWalker.visitAfterSteps.mostRecentCall.args[0];
visitAfterStepsCallback();
});
it("calls back", function () {
expect(userFunctionCallback).toHaveBeenCalled();
});
});
});
});
});
});
});
describe("createBeforeAndAfterStepsForAroundHooks()", function () {
var scenario, aroundHooks;
beforeEach(function () {
scenario = createSpy("scenario");
aroundHooks = createSpy("around hooks");
spyOnStub(aroundHooks, "syncForEach");
spyOnStub(supportCodeLibrary, 'lookupAroundHooksByScenario').andReturn(aroundHooks);
treeWalker.createBeforeAndAfterStepsForAroundHooks(scenario);
});
it("looks up around hooks by scenario", function () {
expect(supportCodeLibrary.lookupAroundHooksByScenario).toHaveBeenCalledWith(scenario);
});
it("iterates over the around hooks", function () {
expect(aroundHooks.syncForEach).toHaveBeenCalled();
expect(aroundHooks.syncForEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
});
describe("for each around hook", function () {
var aroundHook, beforeStep, afterStep;
beforeEach(function () {
aroundHook = createSpyWithStubs("around hook", {setAfterStep: undefined});
beforeStep = createSpyWithStubs("before step", {setHook: undefined});
afterStep = createSpyWithStubs("after step", {setHook: undefined});
var syncForEachCallback = aroundHooks.syncForEach.mostRecentCall.args[0];
spyOn(Cucumber.Ast, "HookStep").andReturnSeveral([beforeStep, afterStep]);
syncForEachCallback(aroundHook);
});
it("creates a before step and an after step", function () {
expect(Cucumber.Ast.HookStep).toHaveBeenCalledNTimes(2);
expect(Cucumber.Ast.HookStep.calls[0].args).toEqual([Cucumber.Runtime.AstTreeWalker.AROUND_STEP_KEYWORD]);
expect(Cucumber.Ast.HookStep.calls[1].args).toEqual([Cucumber.Runtime.AstTreeWalker.AROUND_STEP_KEYWORD]);
});
it("sets the around hook as the before step's hook", function () {
expect(beforeStep.setHook).toHaveBeenCalledWith(aroundHook);
});
it("adds the before step to the before step collection", function () {
expect(beforeStepCollection.add).toHaveBeenCalledWith(beforeStep);
});
it("sets the empty hook as the after step's hook", function () {
expect(afterStep.setHook).toHaveBeenCalledWith(emptyHook);
});
it("adds the after step to the end of the after step collection", function () {
expect(afterStepCollection.unshift).toHaveBeenCalledWith(afterStep);
});
it("sets the after step as the around hook's after step", function () {
expect(aroundHook.setAfterStep).toHaveBeenCalledWith(afterStep);
});
});
});
describe("createBeforeStepsForBeforeHooks()", function () {
var scenario, beforeHooks;
beforeEach(function () {
scenario = createSpy("scenario");
beforeHooks = createSpy("before hooks");
spyOnStub(beforeHooks, "syncForEach");
spyOnStub(supportCodeLibrary, 'lookupBeforeHooksByScenario').andReturn(beforeHooks);
treeWalker.createBeforeStepsForBeforeHooks(scenario);
});
it("looks up before hooks by scenario", function () {
expect(supportCodeLibrary.lookupBeforeHooksByScenario).toHaveBeenCalledWith(scenario);
});
it("iterates over the before hooks", function () {
expect(beforeHooks.syncForEach).toHaveBeenCalled();
expect(beforeHooks.syncForEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
});
describe("for each before hook", function () {
var beforeHook, beforeStep;
beforeEach(function () {
beforeHook = createSpyWithStubs("before hook");
beforeStep = createSpyWithStubs("before step", {setHook: undefined});
var syncForEachCallback = beforeHooks.syncForEach.mostRecentCall.args[0];
spyOn(Cucumber.Ast, "HookStep").andReturn(beforeStep);
syncForEachCallback(beforeHook);
});
it("creates a before step", function () {
expect(Cucumber.Ast.HookStep).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.BEFORE_STEP_KEYWORD);
});
it("sets the before hook as the before step's hook", function () {
expect(beforeStep.setHook).toHaveBeenCalledWith(beforeHook);
});
it("adds the before step to the before step collection", function () {
expect(beforeStepCollection.add).toHaveBeenCalledWith(beforeStep);
});
});
});
describe("createAfterStepsForAfterHooks()", function () {
var scenario, afterHooks;
beforeEach(function () {
scenario = createSpy("scenario");
afterHooks = createSpy("after hooks");
spyOnStub(afterHooks, "syncForEach");
spyOnStub(supportCodeLibrary, 'lookupAfterHooksByScenario').andReturn(afterHooks);
treeWalker.createAfterStepsForAfterHooks(scenario);
});
it("looks up after hooks by scenario", function () {
expect(supportCodeLibrary.lookupAfterHooksByScenario).toHaveBeenCalledWith(scenario);
});
it("iterates over the after hooks", function () {
expect(afterHooks.syncForEach).toHaveBeenCalled();
expect(afterHooks.syncForEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
});
describe("for each after hook", function () {
var afterHook, afterStep;
beforeEach(function () {
afterHook = createSpyWithStubs("after hook");
afterStep = createSpyWithStubs("after step", {setHook: undefined});
var syncForEachCallback = afterHooks.syncForEach.mostRecentCall.args[0];
spyOn(Cucumber.Ast, "HookStep").andReturn(afterStep);
syncForEachCallback(afterHook);
});
it("creates a after step", function () {
expect(Cucumber.Ast.HookStep).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.AFTER_STEP_KEYWORD);
});
it("sets the after hook as the after step's hook", function () {
expect(afterStep.setHook).toHaveBeenCalledWith(afterHook);
});
it("adds the after step to the end of the after step collection", function () {
expect(afterStepCollection.unshift).toHaveBeenCalledWith(afterStep);
});
});
});
describe("visitBeforeSteps()", function () {
var callback;
beforeEach(function () {
callback = createSpy("callback");
treeWalker.visitBeforeSteps(callback);
});
it("iterates over the before steps", function () {
expect(beforeStepCollection.forEach).toHaveBeenCalled();
expect(beforeStepCollection.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
});
describe("for each before step", function () {
var beforeStep, callback;
beforeEach(function () {
beforeStep = createSpyWithStubs("before step", {acceptVisitor: undefined});
callback = createSpyWithStubs("callback");
spyOn(treeWalker, 'witnessHook');
var userFunction = beforeStepCollection.forEach.mostRecentCall.args[0];
userFunction (beforeStep, callback);
});
it("witnesses a hook", function () {
expect(treeWalker.witnessHook).toHaveBeenCalled();
});
it("instructs the before step to accept the tree walker as a visitor", function () {
expect(beforeStep.acceptVisitor).toHaveBeenCalled();
expect(beforeStep.acceptVisitor).toHaveBeenCalledWithValueAsNthParameter(treeWalker, 1);
expect(beforeStep.acceptVisitor).toHaveBeenCalledWithAFunctionAsNthParameter(2);
});
});
describe("when it has finished iterating over the before steps", function () {
beforeEach(function () {
var forEachCallback = beforeStepCollection.forEach.mostRecentCall.args[1];
forEachCallback();
});
it("calls back", function () {
expect(callback).toHaveBeenCalled();
});
});
});
describe("visitAfterSteps()", function () {
var callback;
beforeEach(function () {
callback = createSpy("callback");
treeWalker.visitAfterSteps(callback);
});
it("iterates over the after steps", function () {
expect(afterStepCollection.forEach).toHaveBeenCalled();
expect(afterStepCollection.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
});
describe("for each after step", function () {
var afterStep, callback;
beforeEach(function () {
afterStep = createSpyWithStubs("after step", {acceptVisitor: undefined});
callback = createSpyWithStubs("callback");
spyOn(treeWalker, 'witnessHook');
var userFunction = afterStepCollection.forEach.mostRecentCall.args[0];
userFunction (afterStep, callback);
});
it("witnesses a hook", function () {
expect(treeWalker.witnessHook).toHaveBeenCalled();
});
it("instructs the before step to accept the tree walker as a visitor", function () {
expect(afterStep.acceptVisitor).toHaveBeenCalled();
expect(afterStep.acceptVisitor).toHaveBeenCalledWithValueAsNthParameter(treeWalker, 1);
expect(afterStep.acceptVisitor).toHaveBeenCalledWithAFunctionAsNthParameter(2);
});
});
describe("when it has finished iterating over the after steps", function () {
beforeEach(function () {
var forEachCallback = afterStepCollection.forEach.mostRecentCall.args[1];
forEachCallback();
});
it("calls back", function () {
expect(callback).toHaveBeenCalled();
});
});
});
describe("visitStep()", function () {
var step, callback, event, payload, sequence;
beforeEach(function () {
step = createSpy("step");
callback = createSpy("callback");
event = createSpy("Event");
payload = {step: step};
spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
sequence = [];
spyOn(treeWalker, 'witnessNewStep').andCallFake(function () {
sequence.push('witnessNewStep');
});
spyOn(treeWalker, 'broadcastEventAroundUserFunction').andCallFake(function () {
sequence.push('broadcastEventAroundUserFunction');
});
});
it("witnesses a new step", function () {
treeWalker.visitStep(step, callback);
expect(treeWalker.witnessNewStep).toHaveBeenCalled();
});
it("witnesses a new step before broadcasting the step", function () {
treeWalker.visitStep(step, callback);
expect(sequence).toEqual(['witnessNewStep', 'broadcastEventAroundUserFunction']);
});
it("creates a new event about the step to be processed", function () {
treeWalker.visitStep(step, callback);
expect(Cucumber.Runtime.AstTreeWalker.Event).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.STEP_EVENT_NAME, payload);
});
it("broadcasts the step", function () {
treeWalker.visitStep(step, callback);
expect(treeWalker.broadcastEventAroundUserFunction).toHaveBeenCalled();
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithValueAsNthParameter(event, 1);
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithAFunctionAsNthParameter(2);
expect(treeWalker.broadcastEventAroundUserFunction).
toHaveBeenCalledWithValueAsNthParameter(callback, 3);
});
describe("user function", function () {
var userFunction, userFunctionCallback;
beforeEach(function () {
treeWalker.visitStep(step, callback);
userFunction = treeWalker.broadcastEventAroundUserFunction.mostRecentCall.args[1];
userFunctionCallback = createSpy("user function callback");
spyOn(treeWalker, 'processStep');
});
it("processes the step", function () {
userFunction (userFunctionCallback);
expect(treeWalker.processStep).toHaveBeenCalledWith(step, userFunctionCallback);
});
});
});
describe("visitStepResult()", function () {
var stepResult, callback, event, payload;
beforeEach(function () {
stepResult = createSpyWithStubs("Step result", {isFailed: undefined, isPending: undefined, getFailureException: null});
callback = createSpy("Callback");
event = createSpy("Event");
payload = {stepResult: stepResult};
spyOn(treeWalker, 'broadcastEvent');
spyOn(treeWalker, 'witnessFailedStep');
spyOn(Cucumber.Runtime.AstTreeWalker, 'Event').andReturn(event);
});
it("creates a new event about the step result", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(Cucumber.Runtime.AstTreeWalker.Event).toHaveBeenCalledWith(Cucumber.Runtime.AstTreeWalker.STEP_RESULT_EVENT_NAME, payload);
});
it("broadcasts the visit of the step result and the step result itself", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(treeWalker.broadcastEvent).toHaveBeenCalledWith(event, callback);
});
it("checks whether the step failed or not", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(stepResult.isFailed).toHaveBeenCalled();
});
describe("when the step failed", function () {
beforeEach(function () {
stepResult.isFailed.andReturn(true);
});
it("witnesses a failed step", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(treeWalker.witnessFailedStep).toHaveBeenCalledWith(stepResult.getFailureException());
});
});
describe("when the step did not fail", function () {
beforeEach(function () {
stepResult.isFailed.andReturn(false);
spyOn(treeWalker, 'witnessPendingStep');
});
it("does not witness a failed step", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(treeWalker.witnessFailedStep).not.toHaveBeenCalled();
});
it("checks whether the step was pending or not", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(stepResult.isPending).toHaveBeenCalled();
});
describe("when the step was pending", function () {
beforeEach(function () {
stepResult.isPending.andReturn(true);
});
it("witnesses a pending step", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(treeWalker.witnessPendingStep).toHaveBeenCalled();
});
});
describe("when the step was not pending", function () {
beforeEach(function () {
stepResult.isPending.andReturn(false);
});
it("does not witness a pending step", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(treeWalker.witnessPendingStep).not.toHaveBeenCalled();
});
});
});
it("does not call back by itself", function () {
treeWalker.visitStepResult(stepResult, callback);
expect(callback).not.toHaveBeenCalled();
});
});
describe("broadcastEventAroundUserFunction ()", function () {
var event, userFunction, callback;
var userFunctionWrapper;
beforeEach(function () {
event = createSpy("Event");
userFunction = createSpy("User function");
callback = createSpy("Callback");
userFunctionWrapper = createSpy("User function wrapper");
spyOn(treeWalker, 'wrapUserFunctionAndAfterEventBroadcast').andReturn(userFunctionWrapper);
spyOn(treeWalker, 'broadcastBeforeEvent');
});
it("wraps the user function and after event broadcast together", function () {
treeWalker.broadcastEventAroundUserFunction (event, userFunction, callback);
expect(treeWalker.wrapUserFunctionAndAfterEventBroadcast).toHaveBeenCalledWith(userFunction, event, callback);
});
it("broadcasts a before event with the user function and after event broadcast wrapper as callback", function () {
treeWalker.broadcastEventAroundUserFunction (event, userFunction, callback);
expect(treeWalker.broadcastBeforeEvent).toHaveBeenCalledWith(event, userFunctionWrapper);
});
});
describe("wrapUserFunctionAndAfterEventBroadcast()", function () {
var userFunction, event, callback;
var broadcastAfterEventWrapper;
beforeEach(function () {
userFunction = createSpy("User function");
event = createSpy("Event");
callback = createSpy("Callback");
broadcastAfterEventWrapper = createSpy("After event broadcast wrapper");
spyOn(treeWalker, 'wrapAfterEventBroadcast').andReturn(broadcastAfterEventWrapper);
});
it("wraps the after event broadcast to use as a callback", function () {
treeWalker.wrapUserFunctionAndAfterEventBroadcast(userFunction, event, callback);
expect(treeWalker.wrapAfterEventBroadcast).toHaveBeenCalledWith(event, callback);
});
it("returns a wrapper function", function () {
var returned = treeWalker.wrapUserFunctionAndAfterEventBroadcast(userFunction, event, callback);
expect(returned).toBeAFunction ();
});
describe("returned wrapper function", function () {
var wrapper;
beforeEach(function () {
wrapper = treeWalker.wrapUserFunctionAndAfterEventBroadcast(userFunction, event, callback);
});
it("calls the user function with the after event broadcast wrapper", function () {
wrapper();
expect(userFunction).toHaveBeenCalledWith(broadcastAfterEventWrapper);
});
});
});
describe("wrapAfterEventBroadcast()", function () {
var event, callback;
beforeEach(function () {
event = createSpy("Event");
callback = createSpy("Callback");
});
it("returns a function", function () {
var returned = treeWalker.wrapAfterEventBroadcast(event, callback);
expect(returned).toBeAFunction ();
});
describe("returned wrapper function", function () {
var wrapper;
beforeEach(function () {
wrapper = treeWalker.wrapAfterEventBroadcast(event, callback);
spyOn(treeWalker, 'broadcastAfterEvent');
});
it("broadcasts an after event with the received callback as callback", function () {
wrapper();
expect(treeWalker.broadcastAfterEvent).toHaveBeenCalledWith(event, callback);
});
});
});
describe("broadcastBeforeEvent()", function () {
var event, callback, preEvent;
beforeEach(function () {
preEvent = createSpy("Pre-event (before)");
event = createSpyWithStubs("Event", { replicateAsPreEvent: preEvent });
callback = createSpy("Callback");
spyOn(treeWalker, 'broadcastEvent');
});
it("asks the event to replicate itself as a before event", function () {
treeWalker.broadcastBeforeEvent(event, callback);
expect(event.replicateAsPreEvent).toHaveBeenCalled();
});
it("broadcasts the pre event with the call back", function () {
treeWalker.broadcastBeforeEvent(event, callback);
expect(treeWalker.broadcastEvent).toHaveBeenCalledWith(preEvent, callback);
});
});
describe("broadcastAfterEvent()", function () {
var event, callback, postEvent;
beforeEach(function () {
postEvent = createSpy("Post-event (after)");
event = createSpyWithStubs("Event", { replicateAsPostEvent: postEvent });
callback = createSpy("Callback");
spyOn(treeWalker, 'broadcastEvent');
});
it("asks the event to replicate itself as a after event", function () {
treeWalker.broadcastAfterEvent(event, callback);
expect(event.replicateAsPostEvent).toHaveBeenCalled();
});
it("broadcasts the post event with the call back", function () {
treeWalker.broadcastAfterEvent(event, callback);
expect(treeWalker.broadcastEvent).toHaveBeenCalledWith(postEvent, callback);
});
});
describe("broadcastEvent()", function () {
var event, callback;
beforeEach(function () {
event = createSpy("Event");
callback = createSpy("Callback");
spyOnListeners(listeners);
spyOnListeners(supportListeners);
});
function spyOnListeners(listeners) {
spyOn(listeners, 'forEach').andCallFake(function () {
var callback = listeners.forEach.mostRecentCall.args[1];
callback();
});
}
it("iterates over the listeners", function () {
treeWalker.broadcastEvent(event, callback);
assertListenerCollectionCalled(listeners.forEach);
assertListenerCollectionCalled(supportListeners.forEach);
expect(supportListeners.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
});
function assertListenerCollectionCalled(forEachSpy) {
expect(forEachSpy).toHaveBeenCalled();
expect(forEachSpy).toHaveBeenCalledWithAFunctionAsNthParameter(1);
}
describe("for each listener", function () {
var userFunction, listener, forEachCallback;
beforeEach(function () {
listener = createSpyWithStubs("Listener", {hear:null});
forEachCallback = createSpy("forEach() callback");
treeWalker.broadcastEvent(event, callback);
userFunction = listeners.forEach.mostRecentCall.args[0];
});
it("tells the listener about the event and calls back when finished", function () {
userFunction (listener, forEachCallback);
expect(listener.hear).toHaveBeenCalledWith(event, forEachCallback);
});
});
});
describe("getWorld() [setWorld()]", function () {
var world;
beforeEach(function () {
world = createSpy("world instance");
});
it("returns the World instance set with setWorld()", function () {
treeWalker.setWorld(world);
expect(treeWalker.getWorld()).toBe(world);
});
});
describe("lookupStepDefinitionByName()", function () {
var stepName, stepDefinition;
beforeEach(function () {
stepName = createSpy("Step name");
stepDefinition = createSpy("Step definition");
spyOnStub(supportCodeLibrary, 'lookupStepDefinitionByName').andReturn(stepDefinition);
});
it("asks the support code library for the step definition", function () {
treeWalker.lookupStepDefinitionByName(stepName);
expect(supportCodeLibrary.lookupStepDefinitionByName).toHaveBeenCalledWith(stepName);
});
it("returns the step definition returned by the library", function () {
expect(treeWalker.lookupStepDefinitionByName(stepName)).toBe(stepDefinition);
});
});
describe("isStepUndefined()", function () {
var step, stepName;
beforeEach(function () {
stepName = createSpy("name of the step");
step = createSpyWithStubs("step", {getName: stepName});
spyOnStub(supportCodeLibrary, 'isStepDefinitionNameDefined');
});
it("gets the name of the step", function () {
treeWalker.isStepUndefined(step);
expect(step.getName).toHaveBeenCalled();
});
it("asks the support code library whether a step definition is defined for that name", function () {
treeWalker.isStepUndefined(step);
expect(supportCodeLibrary.isStepDefinitionNameDefined).toHaveBeenCalledWith(stepName);
});
describe("when the step definition is defined", function () {
beforeEach(function () {
supportCodeLibrary.isStepDefinitionNameDefined.andReturn(true);
});
it("returns false", function () {
expect(treeWalker.isStepUndefined(step)).toBeFalsy();
});
});
describe("when the step definition is undefined", function () {
beforeEach(function () {
supportCodeLibrary.isStepDefinitionNameDefined.andReturn(false);
});
it("returns true", function () {
expect(treeWalker.isStepUndefined(step)).toBeTruthy();
});
});
});
describe("didAllFeaturesSucceed()", function () {
describe("when strict mode is off", function () {
it("returns true when no failure was encountered", function () {
expect(treeWalker.didAllFeaturesSucceed()).toBeTruthy();
});
it("returns false when a failed step was encountered", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.didAllFeaturesSucceed()).toBeFalsy();
});
it("returns true when a pending step was encountered", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.didAllFeaturesSucceed()).toBeTruthy();
});
it("returns true when an undefined step was encountered", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.didAllFeaturesSucceed()).toBeTruthy();
});
});
describe("when strict mode is on", function () {
beforeEach(function () {
var isStrictMode = true;
treeWalker = Cucumber.Runtime.AstTreeWalker(features, supportCodeLibrary, listeners, isStrictMode);
});
it("returns true when no failure was encountered", function () {
expect(treeWalker.didAllFeaturesSucceed()).toBeTruthy();
});
it("returns false when a failed step was encountered", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.didAllFeaturesSucceed()).toBeFalsy();
});
it("returns false when a pending step was encountered", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.didAllFeaturesSucceed()).toBeFalsy();
});
it("returns false when an undefined step was encountered", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.didAllFeaturesSucceed()).toBeFalsy();
});
});
});
describe("isScenarioSuccessful()", function () {
beforeEach(function () {
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
});
it("returns true when no failed, pending or undefined step was encountered", function () {
expect(treeWalker.isScenarioSuccessful()).toBeTruthy();
});
it("returns false when a pending step was encountered", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.isScenarioSuccessful()).toBeFalsy();
});
it("returns false when a undefined step was encountered", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.isScenarioSuccessful()).toBeFalsy();
});
it("returns false when a failed step was encountered", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.isScenarioSuccessful()).toBeFalsy();
});
it("still returns true when a pending step was encountered but not in the current scenario", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.isScenarioSuccessful()).toBeFalsy();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isScenarioSuccessful()).toBeTruthy();
});
it("still returns true when a undefined step was encountered but not in the current scenario", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.isScenarioSuccessful()).toBeFalsy();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isScenarioSuccessful()).toBeTruthy();
});
it("still returns true when a failing step was encountered but not in the current scenario", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.isScenarioSuccessful()).toBeFalsy();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isScenarioSuccessful()).toBeTruthy();
});
});
describe("isScenarioFailed()", function () {
beforeEach(function () {
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
});
it("returns false when no failed step was encountered", function () {
expect(treeWalker.isScenarioFailed()).toBeFalsy();
});
it("still returns false when a pending step was encountered", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.isScenarioFailed()).toBeFalsy();
});
it("still returns false when a undefined step was encountered", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.isScenarioFailed()).toBeFalsy();
});
it("returns true when a failed step was encountered", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.isScenarioFailed()).toBeTruthy();
});
it("still returns false when a failing step was encountered but not in the current scenario", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.isScenarioFailed()).toBeTruthy();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isScenarioFailed()).toBeFalsy();
});
});
describe("isScenarioPending()", function () {
beforeEach(function () {
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
});
it("returns false when no pending step was encountered", function () {
expect(treeWalker.isScenarioPending()).toBeFalsy();
});
it("returns true when a pending step was encountered", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.isScenarioPending()).toBeTruthy();
});
it("still returns false when a undefined step was encountered", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.isScenarioPending()).toBeFalsy();
});
it("still returns false when a failed step was encountered", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.isScenarioPending()).toBeFalsy();
});
it("still returns false when a pending step was encountered but not in the current scenario", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.isScenarioPending()).toBeTruthy();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isScenarioPending()).toBeFalsy();
});
});
describe("isScenarioUndefined()", function () {
beforeEach(function () {
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
});
it("returns false when no undefined step was encountered", function () {
expect(treeWalker.isScenarioUndefined()).toBeFalsy();
});
it("still returns false when a pending step was encountered", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.isScenarioUndefined()).toBeFalsy();
});
it("returns true when a undefined step was encountered", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.isScenarioUndefined()).toBeTruthy();
});
it("still returns false when a failed step was encountered", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.isScenarioUndefined()).toBeFalsy();
});
it("still returns false when a undefined step was encountered but not in the current scenario", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.isScenarioUndefined()).toBeTruthy();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isScenarioUndefined()).toBeFalsy();
});
});
describe("attach()", function () {
var data, mimeType, attachment;
beforeEach(function () {
data = createSpy("data");
mimeType = createSpy("mimeType");
attachment = createSpy("attachment");
spyOn(Cucumber.Runtime, 'Attachment').andReturn(attachment);
treeWalker.attach(data, mimeType);
});
it("creates an attachment", function () {
expect(Cucumber.Runtime.Attachment).toHaveBeenCalledWith({mimeType: mimeType, data: data});
});
it("adds the attachment to the collection", function () {
expect(attachmentCollection.add).toHaveBeenCalledWith(attachment);
});
});
describe("getAttachments()", function () {
var returnValue;
beforeEach(function () {
returnValue = treeWalker.getAttachments();
});
it("returns the attachments", function () {
expect(returnValue).toBe(attachmentCollection);
});
});
describe("witnessNewStep()", function () {
beforeEach(function () {
treeWalker.witnessNewStep();
});
it("clears the attachments", function () {
expect(attachmentCollection.clear).toHaveBeenCalled();
});
});
describe("witnessNewScenario()", function () {
var scenario, apiScenario;
beforeEach(function () {
scenario = createSpy("scenario");
apiScenario = createSpy("API scenario");
spyOn(Cucumber.Api, 'Scenario').andReturn(apiScenario);
treeWalker.witnessNewScenario(scenario);
});
it("creates an API scenario", function () {
expect(Cucumber.Api.Scenario).toHaveBeenCalledWith(treeWalker, scenario);
});
it("clears the before step collection", function () {
expect(beforeStepCollection.clear).toHaveBeenCalled();
});
it("clears the after step collection", function () {
expect(afterStepCollection.clear).toHaveBeenCalled();
});
});
describe("getScenario()", function () {
var scenario, apiScenario, returnValue;
describe("when a new scenario is visited", function () {
beforeEach(function () {
scenario = createSpy("scenario");
apiScenario = createSpy("API scenario");
spyOn(Cucumber.Api, 'Scenario').andReturn(apiScenario);
treeWalker.witnessNewScenario(scenario);
returnValue = treeWalker.getScenario();
});
it("returns the API scenario", function () {
expect(returnValue).toBe(apiScenario);
});
});
});
describe("getDomain()", function () {
it("returns the walk domain", function () {
expect(treeWalker.getDomain()).toBe(walkDomain);
});
});
describe("isSkippingSteps() [witnessFailedSteps(), witnessPendingSteps(), witnessUndefinedStep(), witnessNewScenario()]", function () {
beforeEach(function () {
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
});
it("returns false when no failed, pending or undefined steps were encountered", function () {
expect(treeWalker.isSkippingSteps()).toBeFalsy();
});
it("returns true when a failed step was encountered", function () {
treeWalker.witnessFailedStep();
expect(treeWalker.isSkippingSteps()).toBeTruthy();
});
it("returns true when a pending step was encountered", function () {
treeWalker.witnessPendingStep();
expect(treeWalker.isSkippingSteps()).toBeTruthy();
});
it("returns true when a undefined step was encountered", function () {
treeWalker.witnessUndefinedStep();
expect(treeWalker.isSkippingSteps()).toBeTruthy();
});
it("returns false when a failed step was encountered but not in the current scenario", function () {
treeWalker.witnessFailedStep();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isSkippingSteps()).toBeFalsy();
});
it("returns false when a pending step was encountered but not in the current scenario", function () {
treeWalker.witnessPendingStep();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isSkippingSteps()).toBeFalsy();
});
it("returns false when a undefined step was encountered but not in the current scenario", function () {
treeWalker.witnessUndefinedStep();
var scenario = createSpy("scenario");
treeWalker.witnessNewScenario(scenario);
expect(treeWalker.isSkippingSteps()).toBeFalsy();
});
});
describe("processStep()", function () {
var step, callback;
beforeEach(function () {
step = createSpy("step");
callback = createSpy("callback");