UNPKG

cucumber-for-jenkins

Version:

The unofficial JavaScript implementation of Cucumber.

425 lines (357 loc) 15.3 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(); }; 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.runFeatures = function runFeatures(options, callback) { this.runFeaturesWithSupportCodeSource(this.features, function() {}, options, callback); }; proto.runFeatureWithSupportCodeSource = function runFeatureWithSupportCodeSource(supportCode, options, callback) { this.runFeaturesWithSupportCodeSource(this.featureSource, supportCode, options, callback); }; proto.runFeaturesWithSupportCodeSource = function runFeaturesWithSupportCodeSource(features, supportCode, options, callback) { var world = this; var Cucumber = require('../../lib/cucumber'); options = options || {}; var tags = options['tags'] || []; var cucumber = Cucumber(features, 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.runAScenarioCallingMapping = function runAScenarioCallingMapping(callback) { this.addScenario("", "Given " + this.mappingName); this.runFeature({}, callback); }; proto.runAScenarioCallingMappingWithParameters = function runAScenarioCallingMappingWithParameters(callback) { this.expectedMappingArguments = [5, "fresh cucumbers"]; this.addScenario("", 'Given a mapping with ' + this.expectedMappingArguments[0] + ' "' + this.expectedMappingArguments[1] + '"'); this.runFeature({}, callback); }; proto.runAScenarioCallingMappingWithMultipleParameters = function runAScenarioCallingMappingWithMultipleParameters(callback) { this.expectedMappingArguments = [5, "fresh cucumbers", 2, 'pickled gherkins']; this.addScenario("", 'Given a mapping with ' + this.expectedMappingArguments[0] + ' ' + this.expectedMappingArguments[2] + ' "' + this.expectedMappingArguments[1] + '" "' + this.expectedMappingArguments[3] + '"'); this.runFeature({}, callback); }; proto.runAScenarioCallingWorldFunction = function runAScenarioCallingWorldFunction(callback) { this.addScenario("", "Given a step"); this.stepDefinitions += "Given(/^a step$/, function(callback) {\ world.logCycleEvent('step 1');\ this.someFunction();\ 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.addStringBasedPatternMapping = function addStringBasedPatternMapping() { this.mappingName = "/a string-based mapping with fancy characters |\\ ^*-{(})+[a].?"; this.stepDefinitions += "Given('/a string-based mapping with fancy characters |\\\\ ^*-{(})+[a].?', function(callback) {\ world.logCycleEvent('/a string-based mapping with fancy characters |\\\\ ^*-{(})+[a].?');\ callback();\ });"; }; proto.addStringBasedPatternMappingWithParameters = function addStringBasedPatternMappingWithParameters() { this.mappingName = "a string-based mapping"; this.stepDefinitions += "Given('a mapping with $word_param \"$multi_word_param\"', function(p1, p2, callback) {\ world.logCycleEvent('a string-based mapping');\ world.actualMappingArguments = [p1, p2];\ callback();\ });"; }; proto.addStringBasedPatternMappingWithMultipleParameters = function addStringBasedPatternMappingWithMultipleParameters() { this.mappingName = "a string-based mapping with multiple parameters"; this.stepDefinitions += "Given('a mapping with $word_param_a $word_param_b \"$multi_word_param_a\" \"$multi_word_param_b\"', function(p1, p2, p3, p4, callback) {\ world.logCycleEvent('a string-based mapping with multiple parameters');\ world.actualMappingArguments = [p1, p2, p3, p4];\ callback();\ });"; }; 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.addBeforeHook = function (callback) { this._addHook({ type: "before" }, callback); }; proto.addAfterHook = function (callback) { this._addHook({ type: "after" }, callback); }; proto.addAroundHook = function (callback) { this._addAroundHook(callback); }; proto.addAroundHookWithTags = function (tags, callback) { this._addAroundHook({ tags: tags, logEvent: "hook" }, callback); }; proto.addUntaggedHook = function (callback) { this._addHook({ type: "before", logEvent: "hook" }, callback); }; proto.addHookWithTags = function (tags, callback) { this._addHook({ type: "before", logEvent: "hook", tags: tags }, callback); }; proto._addHook = function (options, callback) { if (!callback) { callback = options; options = {}; } var type = "before"; var tags = ""; if (options.type) type = options.type; if (!options.logEvent) options.logEvent = type; if (options.tags) tags = '"' + options.tags + '", '; var defineHook = (type == 'before' ? 'Before' : 'After'); this.stepDefinitions += defineHook + "(" + tags + "function(scenario, callback) {\ world.logCycleEvent('" + options.logEvent + "');\ callback();\ });\n"; callback(); }; proto._addAroundHook = function (options, callback) { if (!callback) { callback = options; options = {}; } var tags = ""; var logEvent = "around"; if (options.tags) tags = '"' + options.tags + '", '; if (options.logEvent) logEvent = options.logEvent; this.stepDefinitions += "Around(" + tags + "function(scenario, runScenario) {\ world.logCycleEvent('" + logEvent + "-pre');\ runScenario(function(scenario, callback) {\ world.logCycleEvent('" + logEvent + "-post');\ callback();\ });\ });\n"; callback(); }; proto.addFailingMapping = function (stepName, options, callback) { this.stepDefinitions += this._generateFailingMapping(stepName, options); callback(); }; proto._generateMapping = function (stepName, body) { return "\ Given(/^" + stepName + "$/, function(callback) {\ world.touchStep(\"" + stepName + "\");\n" + body + "\ });\ "; }; proto._generateFailingMapping = function (stepName, options) { var message = "I was supposed to fail."; if (options.message) message = options.message; var body = "throw(new Error('" + message + "'));"; return this._generateMapping(stepName, body); }; 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.addPassingStepDefinitionWithName = function (name, callback) { this.stepDefinitions += "Given(/^" + name + "$/, function(callback) {\ world.touchStep(\"" + name + "\");\ callback();\ });\n"; callback(); }; 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.assertPassedFeatures = function assertPassedFeatures() { this.assertNoPartialOutput("failed", this.runOutput); this.assertPartialOutput("3 scenarios ("+this.color.format("passed","3 passed")+")", this.runOutput); this.assertSuccess(); }; proto.assertPassedScenario = function assertPassedScenario() { this.assertPartialOutput("1 scenario ("+this.color.format("passed","1 passed")+")", this.runOutput); this.assertSuccess(); }; proto.assertFailedScenario = function assertFailedScenario() { this.assertPartialOutput("1 scenario ("+this.color.format("failed","1 failed")+")", this.runOutput); this.assertFailure(); }; proto.assertPendingScenario = function assertPendingScenario() { this.assertPartialOutput("1 scenario ("+this.color.format("pending","1 pending")+")", this.runOutput); this.assertSuccess(); }; proto.assertUndefinedScenario = function assertUndefinedScenario() { this.assertPartialOutput("1 scenario ("+this.color.format("undefined", "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.assertPassedMapping = function assertPassedMapping() { this.assertCycleSequence(this.mappingName); }; proto.assertPassedMappingWithArguments = function assertPassedMappingWithArguments() { this.assertPassedMapping(); if (this.actualMappingArguments.length != this.expectedMappingArguments.length || this.actualMappingArguments[0] != this.expectedMappingArguments[0] || this.actualMappingArguments[1] != this.expectedMappingArguments[1]) throw(new Error("Expected arguments to be passed to mapping.")); }; proto.assertPassedMappingWithMultipleArguments = function assertPassedMappingWithMultipleArguments() { this.assertPassedMapping(); if (this.actualMappingArguments.length != this.expectedMappingArguments.length || this.actualMappingArguments[0] != this.expectedMappingArguments[0] || this.actualMappingArguments[1] != this.expectedMappingArguments[1] || this.actualMappingArguments[2] != this.expectedMappingArguments[2] || this.actualMappingArguments[3] != this.expectedMappingArguments[3]) throw(new Error("Expected arguments to be passed to mapping.")); }; 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.assertTrue = function assertTrue(value) { if (!value) throw(new Error("Expected:\n\"" + value + "\"\n to be true")); }; 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; }; proto.color = require('../../lib/cucumber/util/colors'); exports.World = World;