cucumber
Version:
The official JavaScript implementation of Cucumber.
364 lines (310 loc) • 12.7 kB
JavaScript
var domain = require('domain');
function AstTreeWalker(features, supportCodeLibrary, listeners, strictMode, dryRun) {
var Cucumber = require('../../cucumber');
var world;
var allFeaturesSucceeded = true;
var emptyHook = Cucumber.SupportCode.Hook(function (callback) { callback(); }, {});
var beforeSteps = Cucumber.Type.Collection();
var afterSteps = Cucumber.Type.Collection();
var attachments = Cucumber.Type.Collection();
var apiScenario, scenarioSuccessful, scenarioFailed, scenarioPending, scenarioUndefined, scenarioSkipped,scenarioFailureException;
var walkDomain = domain.create();
walkDomain.id = 'domain-' + Date.now();
var self = {
walk: function walk(callback) {
if (walkDomain.enter)
walkDomain.enter();
self.visitFeatures(features, function () {
if (walkDomain.exit)
walkDomain.exit();
var featuresResult = self.didAllFeaturesSucceed();
callback(featuresResult);
});
},
visitFeatures: function visitFeatures(features, callback) {
var payload = { features: features };
var event = AstTreeWalker.Event(AstTreeWalker.FEATURES_EVENT_NAME, payload);
self.broadcastEventAroundUserFunction(
event,
function (callback) { features.acceptVisitor(self, callback); },
callback
);
},
visitFeature: function visitFeature(feature, callback) {
var payload = { feature: feature };
var event = AstTreeWalker.Event(AstTreeWalker.FEATURE_EVENT_NAME, payload);
self.broadcastEventAroundUserFunction(
event,
function (callback) { feature.acceptVisitor(self, callback); },
callback
);
},
visitBackground: function visitBackground(background, callback) {
var payload = { background: background };
var event = AstTreeWalker.Event(AstTreeWalker.BACKGROUND_EVENT_NAME, payload);
self.broadcastEvent(event, callback);
},
visitScenario: function visitScenario(scenario, callback) {
supportCodeLibrary.instantiateNewWorld(function (world) {
self.setWorld(world);
self.witnessNewScenario(scenario);
self.createBeforeAndAfterStepsForAroundHooks(scenario);
self.createBeforeStepsForBeforeHooks(scenario);
self.createAfterStepsForAfterHooks(scenario);
var payload = { scenario: scenario };
var event = AstTreeWalker.Event(AstTreeWalker.SCENARIO_EVENT_NAME, payload);
self.broadcastEventAroundUserFunction (
event,
function (callback) {
self.visitBeforeSteps(function () {
scenario.acceptVisitor(self, function () {
self.visitAfterSteps(callback);
});
});
},
callback
);
});
},
createBeforeAndAfterStepsForAroundHooks: function createBeforeAndAfterStepsForAroundHooks(scenario) {
var aroundHooks = supportCodeLibrary.lookupAroundHooksByScenario(scenario);
aroundHooks.syncForEach(function (aroundHook) {
var beforeStep = Cucumber.Ast.HookStep(AstTreeWalker.AROUND_STEP_KEYWORD);
beforeStep.setHook(aroundHook);
beforeSteps.add(beforeStep);
var afterStep = Cucumber.Ast.HookStep(AstTreeWalker.AROUND_STEP_KEYWORD);
afterStep.setHook(emptyHook);
afterSteps.unshift(afterStep);
aroundHook.setAfterStep(afterStep);
});
},
createBeforeStepsForBeforeHooks: function createBeforeStepsForBeforeHooks(scenario) {
var beforeHooks = supportCodeLibrary.lookupBeforeHooksByScenario(scenario);
beforeHooks.syncForEach(function (beforeHook) {
var beforeStep = Cucumber.Ast.HookStep(AstTreeWalker.BEFORE_STEP_KEYWORD);
beforeStep.setHook(beforeHook);
beforeSteps.add(beforeStep);
});
},
createAfterStepsForAfterHooks: function createAfterStepsForAfterHooks(scenario) {
var afterHooks = supportCodeLibrary.lookupAfterHooksByScenario(scenario);
afterHooks.syncForEach(function (afterHook) {
var afterStep = Cucumber.Ast.HookStep(AstTreeWalker.AFTER_STEP_KEYWORD);
afterStep.setHook(afterHook);
afterSteps.unshift(afterStep);
});
},
visitBeforeSteps: function visitBeforeSteps(callback) {
beforeSteps.forEach(function (beforeStep, callback) {
self.witnessHook();
beforeStep.acceptVisitor(self, callback);
}, callback);
},
visitAfterSteps: function visitAfterSteps(callback) {
afterSteps.forEach(function (afterStep, callback) {
self.witnessHook();
afterStep.acceptVisitor(self, callback);
}, callback);
},
visitStep: function visitStep(step, callback) {
self.witnessNewStep();
var payload = { step: step };
var event = AstTreeWalker.Event(AstTreeWalker.STEP_EVENT_NAME, payload);
self.broadcastEventAroundUserFunction (
event,
function (callback) {
self.processStep(step, callback);
},
callback
);
},
visitStepResult: function visitStepResult(stepResult, callback) {
if (stepResult.isFailed())
self.witnessFailedStep(stepResult.getFailureException());
else if (stepResult.isPending())
self.witnessPendingStep();
var payload = { stepResult: stepResult };
var event = AstTreeWalker.Event(AstTreeWalker.STEP_RESULT_EVENT_NAME, payload);
self.broadcastEvent(event, callback);
},
broadcastEventAroundUserFunction: function broadcastEventAroundUserFunction (event, userFunction, callback) {
var userFunctionWrapper = self.wrapUserFunctionAndAfterEventBroadcast(userFunction, event, callback);
self.broadcastBeforeEvent(event, userFunctionWrapper);
},
wrapUserFunctionAndAfterEventBroadcast: function wrapUserFunctionAndAfterEventBroadcast(userFunction, event, callback) {
var callAfterEventBroadcast = self.wrapAfterEventBroadcast(event, callback);
return function callUserFunctionAndBroadcastAfterEvent() {
userFunction (callAfterEventBroadcast);
};
},
wrapAfterEventBroadcast: function wrapAfterEventBroadcast(event, callback) {
return function () { self.broadcastAfterEvent(event, callback); };
},
broadcastBeforeEvent: function broadcastBeforeEvent(event, callback) {
var preEvent = event.replicateAsPreEvent();
self.broadcastEvent(preEvent, callback);
},
broadcastAfterEvent: function broadcastAfterEvent(event, callback) {
var postEvent = event.replicateAsPostEvent();
self.broadcastEvent(postEvent, callback);
},
broadcastEvent: function broadcastEvent(event, callback) {
function onRuntimeListenersComplete() {
var listeners = supportCodeLibrary.getListeners();
broadcastToListeners(listeners, callback);
}
function broadcastToListeners(listeners, callback) {
listeners.forEach(
function (listener, callback) { listener.hear(event, callback); },
callback
);
}
broadcastToListeners(listeners, onRuntimeListenersComplete);
},
lookupStepDefinitionByName: function lookupStepDefinitionByName(stepName) {
return supportCodeLibrary.lookupStepDefinitionByName(stepName);
},
setWorld: function setWorld(newWorld) {
world = newWorld;
},
getWorld: function getWorld() {
return world;
},
isStepUndefined: function isStepUndefined(step) {
var stepName = step.getName();
return !supportCodeLibrary.isStepDefinitionNameDefined(stepName);
},
didAllFeaturesSucceed: function didAllFeaturesSucceed() {
return allFeaturesSucceeded;
},
isScenarioSuccessful: function isScenarioSuccessful() {
return scenarioSuccessful;
},
isScenarioFailed: function isScenarioFailed() {
return scenarioFailed;
},
isScenarioPending: function isScenarioPending() {
return scenarioPending;
},
isScenarioUndefined: function isScenarioUndefined() {
return scenarioUndefined;
},
isScenarioSkipped: function isScenarioSkipped() {
return scenarioSkipped;
},
getFailureException: function getFailureException() {
return scenarioFailureException;
},
attach: function attach(data, mimeType) {
attachments.add(Cucumber.Runtime.Attachment({mimeType: mimeType, data: data}));
},
getAttachments: function getAttachments() {
return attachments;
},
witnessHook: function witnessHook() {
attachments.clear();
},
witnessNewStep: function witnessNewStep() {
attachments.clear();
},
witnessFailedStep: function witnessFailedStep(failureException) {
allFeaturesSucceeded = false;
scenarioSuccessful = false;
scenarioFailed = true;
scenarioFailureException = failureException;
},
witnessPendingStep: function witnessPendingStep() {
if (strictMode) {
allFeaturesSucceeded = false;
}
scenarioSuccessful = false;
scenarioPending = true;
},
witnessUndefinedStep: function witnessUndefinedStep() {
if (strictMode) {
allFeaturesSucceeded = false;
}
scenarioSuccessful = false;
scenarioUndefined = true;
},
witnessSkippedStep: function witnessSkippedStep() {
if (scenarioSuccessful) {
scenarioSuccessful = false;
scenarioSkipped = true;
}
},
witnessNewScenario: function witnessNewScenario(scenario) {
apiScenario = Cucumber.Api.Scenario(self, scenario);
scenarioSuccessful = true;
scenarioFailed = false;
scenarioPending = false;
scenarioUndefined = false;
scenarioSkipped = false;
scenarioFailureException = null;
beforeSteps.clear();
afterSteps.clear();
},
processDryRunStep: function processDryRunStep(step, callback) {
if (strictMode && self.isStepUndefined(step)) {
self.witnessUndefinedStep();
self.skipUndefinedStep(step, callback);
} else {
self.witnessSkippedStep();
self.skipStep(step, callback);
}
},
getScenario: function getScenario() {
return apiScenario;
},
getDomain: function getDomain() {
return walkDomain;
},
isSkippingSteps: function isSkippingSteps() {
return !scenarioSuccessful;
},
processStep: function processStep(step, callback) {
if (dryRun) {
self.processDryRunStep(step, callback);
} else if (self.isStepUndefined(step)) {
self.witnessUndefinedStep();
self.skipUndefinedStep(step, callback);
} else if (self.isSkippingSteps()) {
self.skipStep(step, callback);
} else {
self.executeStep(step, callback);
}
},
executeStep: function executeStep(step, callback) {
step.acceptVisitor(self, callback);
},
skipStep: function skipStep(step, callback) {
var skippedStepResult = Cucumber.Runtime.SkippedStepResult({step: step});
var payload = { stepResult: skippedStepResult };
var event = AstTreeWalker.Event(AstTreeWalker.STEP_RESULT_EVENT_NAME, payload);
self.broadcastEvent(event, callback);
},
skipUndefinedStep: function skipUndefinedStep(step, callback) {
var undefinedStepResult = Cucumber.Runtime.UndefinedStepResult({step: step});
var payload = { stepResult: undefinedStepResult };
var event = AstTreeWalker.Event(AstTreeWalker.STEP_RESULT_EVENT_NAME, payload);
self.broadcastEvent(event, callback);
}
};
return self;
}
AstTreeWalker.FEATURES_EVENT_NAME = 'Features';
AstTreeWalker.FEATURE_EVENT_NAME = 'Feature';
AstTreeWalker.BACKGROUND_EVENT_NAME = 'Background';
AstTreeWalker.SCENARIO_EVENT_NAME = 'Scenario';
AstTreeWalker.STEP_EVENT_NAME = 'Step';
AstTreeWalker.STEP_RESULT_EVENT_NAME = 'StepResult';
AstTreeWalker.ROW_EVENT_NAME = 'ExampleRow';
AstTreeWalker.BEFORE_EVENT_NAME_PREFIX = 'Before';
AstTreeWalker.AFTER_EVENT_NAME_PREFIX = 'After';
AstTreeWalker.NON_EVENT_LEADING_PARAMETERS_COUNT = 0;
AstTreeWalker.NON_EVENT_TRAILING_PARAMETERS_COUNT = 2;
AstTreeWalker.AROUND_STEP_KEYWORD = 'Around ';
AstTreeWalker.BEFORE_STEP_KEYWORD = 'Before ';
AstTreeWalker.AFTER_STEP_KEYWORD = 'After ';
AstTreeWalker.Event = require('./ast_tree_walker/event');
module.exports = AstTreeWalker;