UNPKG

cucumber

Version:

The official JavaScript implementation of Cucumber.

240 lines (199 loc) 8.09 kB
var World = function(callback) { this.touchedSteps = []; this.featureSource = ""; this.stepDefinitions = ""; this.runOutput = ""; this.cycleEvents = ""; this.stepCount = 0; this.runSucceeded = false; World.mostRecentInstance = this; callback(this); }; var proto = World.prototype; proto.runFeature = function runFeature(options, callback) { var supportCode; var supportCodeSource = "supportCode = function() {\n var Given = When = Then = this.defineStep;\n" + " var Around = this.Around, Before = this.Before, After = this.After;\n" + this.stepDefinitions + "};\n"; var world = this; eval(supportCodeSource); this.runFeatureWithSupportCodeSource(supportCode, options, callback); } proto.runFeatureWithSupportCodeSource = function runFeatureWithSupportCodeSource(supportCode, options, callback) { var world = this; var Cucumber = require('../../lib/cucumber'); options = options || {}; var tags = options['tags'] || []; var cucumber = Cucumber(this.featureSource, supportCode, {tags: tags}); var formatter = Cucumber.Listener.ProgressFormatter({logToConsole: false}); cucumber.attachListener(formatter); try { cucumber.start(function(succeeded) { world.runSucceeded = succeeded; world.runOutput = formatter.getLogs(); Cucumber.Debug.notice(world.runOutput, 'cucumber output', 5); callback(); }); } catch(e) { world.runOutput += e.toString(); Cucumber.Debug.notice(world.runOutput, 'cucumber output', 5); callback(); } } proto.runAScenario = function runAScenario(callback) { this.addScenario("", "Given a step"); this.stepDefinitions += "Given(/^a step$/, function(callback) {\ world.logCycleEvent('step 1');\ callback();\ });"; this.runFeature({}, callback); } proto.logCycleEvent = function logCycleEvent(event) { this.cycleEvents += " -> " + event; } proto.touchStep = function touchStep(string) { this.touchedSteps.push(string); } proto.isStepTouched = function isStepTouched(pattern) { return (this.touchedSteps.indexOf(pattern) >= 0); } proto.addScenario = function addScenario(name, contents, options) { options = options || {}; var tags = options['tags'] || []; var tagString = (tags.length > 0 ? tags.join(" ") + "\n" : ""); var scenarioName = tagString + "Scenario: " + name; this.createEmptyFeature(); this.featureSource += this.indentCode(scenarioName, 1); this.featureSource += this.indentCode(contents, 2); }; proto.addPassingScenarioWithTags = function addPassingScenarioWithTags(tags) { tags = Array.prototype.slice.call(arguments, 0); var stepName = this.makeNumberedStepName(); var scenarioName = "A scenario tagged with " + tags.join(', '); var step = "Given " + stepName + "\n"; this.addScenario(scenarioName, step, {tags: tags}); this.stepDefinitions += "Given(/^" + stepName + "$/, function(callback) {\ world.logCycleEvent('" + stepName + "');\ callback();\ });\n"; }; proto.addPassingScenarioWithoutTags = function addPassingScenarioWithoutTags() { this.addPassingScenarioWithTags(); }; proto.createEmptyFeature = function createEmptyFeature(options) { options = options || {}; tags = options['tags'] || []; if (!this.emptyFeatureReady) { if (tags.length > 0) this.featureSource += tags.join(' ') + "\n"; this.featureSource += "Feature: A feature\n\n"; this.emptyFeatureReady = true; } }; proto.makeNumberedStepName = function makeNumberedStepName(index) { var index = index || (++this.stepCount); var stepName = "step " + index; return stepName; } proto.assertPassedFeature = function assertPassedFeature() { this.assertNoPartialOutput("failed", this.runOutput); this.assertSuccess(); } proto.assertPassedScenario = function assertPassedScenario() { this.assertPartialOutput("1 scenario (1 passed)", this.runOutput); this.assertSuccess(); } proto.assertFailedScenario = function assertFailedScenario() { this.assertPartialOutput("1 scenario (1 failed)", this.runOutput); this.assertFailure(); } proto.assertPendingScenario = function assertPendingScenario() { this.assertPartialOutput("1 scenario (1 pending)", this.runOutput); this.assertSuccess(); } proto.assertUndefinedScenario = function assertUndefinedScenario() { this.assertPartialOutput("1 scenario (1 undefined)", this.runOutput); this.assertSuccess(); } proto.assertScenarioReportedAsFailing = function assertScenarioReportedAsFailing(scenarioName) { this.assertPartialOutput("# Scenario: " + scenarioName, this.runOutput); this.assertFailure(); } proto.assertScenarioNotReportedAsFailing = function assertScenarioNotReportedAsFailing(scenarioName) { this.assertNoPartialOutput("# Scenario: " + scenarioName, this.runOutput); } proto.assertPassedStep = function assertPassedStep(stepName) { if (!this.isStepTouched(stepName)) throw(new Error("Expected step \"" + stepName + "\" to have passed.")); } proto.assertSkippedStep = function assertSkippedStep(stepName) { if (this.isStepTouched(stepName)) throw(new Error("Expected step \"" + stepName + "\" to have been skipped.")); } proto.assertSuccess = function assertSuccess() { if (!this.runSucceeded) throw(new Error("Expected Cucumber to succeed but it failed.")); } proto.assertFailure = function assertFailure() { if (this.runSucceeded) throw(new Error("Expected Cucumber to fail but it succeeded.")); } proto.assertFailureMessage = function assertFailureMessage(message) { this.assertPartialOutput(message, this.runOutput); this.assertFailure(); } proto.assertPartialOutput = function assertPartialOutput(expected, actual) { if (actual.indexOf(expected) < 0) throw(new Error("Expected:\n\"" + actual + "\"\nto match:\n\"" + expected + "\"")); } proto.assertNoPartialOutput = function assertNoPartialOutput(expected, actual) { if (actual.indexOf(expected) >= 0) throw(new Error("Expected:\n\"" + actual + "\"\nnot to match:\n\"" + expected + "\"")); } proto.assertEqual = function assertRawDataTable(expected, actual) { var expectedJSON = JSON.stringify(expected); var actualJSON = JSON.stringify(actual); if (actualJSON != expectedJSON) throw(new Error("Expected:\n\"" + actualJSON + "\"\nto match:\n\"" + expectedJSON + "\"")); } proto.assertExecutedNumberedScenarios = function assertExecutedNumberedScenarios() { var self = this; var scenarioIndexes = Array.prototype.slice.apply(arguments); var stepNames = []; scenarioIndexes.forEach(function(scenarioIndex) { var stepName = self.makeNumberedStepName(scenarioIndex); stepNames.push(stepName); }); this.assertCompleteCycleSequence.apply(this, stepNames); } proto.assertCycleSequence = function assertCycleSequence() { var events = Array.prototype.slice.apply(arguments); var partialSequence = ' -> ' + events.join(' -> '); if (this.cycleEvents.indexOf(partialSequence) < 0) throw(new Error("Expected cycle sequence \"" + this.cycleEvents + "\" to contain \"" + partialSequence + "\"")); } proto.assertCompleteCycleSequence = function assertCompleteCycleSequence() { var events = Array.prototype.slice.apply(arguments); var sequence = ' -> ' + events.join(' -> '); if (this.cycleEvents != sequence) throw(new Error("Expected cycle sequence \"" + this.cycleEvents + "\" to be \"" + sequence + "\"")); } proto.assertCycleSequenceExcluding = function assertCycleSequenceExcluding() { var self = this; var events = Array.prototype.slice.apply(arguments); events.forEach(function(event) { if (self.cycleEvents.indexOf(event) >= 0) throw(new Error("Expected cycle sequence \"" + self.cycleEvents + "\" not to contain \"" + event + "\"")); }); } proto.indentCode = function indentCode(code, levels) { var indented = ''; var lines = code.split("\n"); levels = levels || 1; lines.forEach(function(line) { var indent = (line == "" ? "" : Array(levels + 1).join(" ")); indented += indent + line + "\n"; }); return indented; }; exports.World = World;