From 7094a7dee427803920cefaeca10deea9439ee68b Mon Sep 17 00:00:00 2001 From: Tim Haines Date: Tue, 26 Jun 2012 15:56:11 +0100 Subject: [PATCH 1/2] Integration with Angular Creates angular "describe" blocks for features and scenarios and "it" blocks for steps. Also, now always tells cucumber that the step passed (rather than allowing the client to do so), as we hand off execution of the steps to Angular. --- lib/cucumber/ast/scenario.js | 19 +++++++++++++++---- lib/cucumber/runtime/ast_tree_walker.js | 6 ++++++ lib/cucumber/support_code/library.js | 1 + lib/cucumber/support_code/step_definition.js | 19 ++++++++++++++++--- .../step_definition_snippet_builder.js | 6 +++--- 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/lib/cucumber/ast/scenario.js b/lib/cucumber/ast/scenario.js index 373799aeb..69a1d3f75 100644 --- a/lib/cucumber/ast/scenario.js +++ b/lib/cucumber/ast/scenario.js @@ -48,10 +48,21 @@ var Scenario = function(keyword, name, description, line) { return tags; }, - acceptVisitor: function acceptVisitor(visitor, callback) { - self.instructVisitorToVisitBackgroundSteps(visitor, function() { - self.instructVisitorToVisitScenarioSteps(visitor, callback); - }); + acceptVisitor: function acceptVisitor(visitor, callback) { + // Create an angular describe block for the current scenario + describeStart(self.getKeyword() + ': ' + self.getName(), function(endDescribeCallback) { + // Visit each of the background steps + self.instructVisitorToVisitBackgroundSteps(visitor, function() { + // Visit each of the scenario steps + self.instructVisitorToVisitScenarioSteps(visitor, function() { + // Close the describe block + endDescribeCallback(); + // Tell cucumber we've finished - we'll let angular deal with any errors in the step. + callback(); + }); + }); + }, + self.getDescription()); }, instructVisitorToVisitBackgroundSteps: function instructVisitorToVisitBackgroundSteps(visitor, callback) { diff --git a/lib/cucumber/runtime/ast_tree_walker.js b/lib/cucumber/runtime/ast_tree_walker.js index 4da776fd7..cc52859e0 100644 --- a/lib/cucumber/runtime/ast_tree_walker.js +++ b/lib/cucumber/runtime/ast_tree_walker.js @@ -157,6 +157,12 @@ var AstTreeWalker = function(features, supportCodeLibrary, listeners) { processStep: function processStep(step, callback) { if (self.isStepUndefined(step)) { + // Tell angular that we couldn't find the step definition and give some example code + var snippetBuilder = Cucumber.SupportCode.StepDefinitionSnippetBuilder(step); + var snippet = snippetBuilder.buildSnippet(); + it(step.getKeyword() + ': ' + step.getName(), function () { throw ('Error: Step definition could not be found.\n\nExpected a step definition similar to the following:\n\n' + snippet); }); + + // Continue with the cucumber code self.witnessUndefinedStep(); self.skipUndefinedStep(step, callback); } else if (self.isSkippingSteps()) { diff --git a/lib/cucumber/support_code/library.js b/lib/cucumber/support_code/library.js index 501e627b5..2f56453c5 100644 --- a/lib/cucumber/support_code/library.js +++ b/lib/cucumber/support_code/library.js @@ -66,6 +66,7 @@ var Library = function(supportCodeDefinition) { Given : self.defineStep, When : self.defineStep, Then : self.defineStep, + And : self.defineStep, defineStep : self.defineStep, World : worldConstructor }; diff --git a/lib/cucumber/support_code/step_definition.js b/lib/cucumber/support_code/step_definition.js index aa0ca5b0a..064c29f14 100644 --- a/lib/cucumber/support_code/step_definition.js +++ b/lib/cucumber/support_code/step_definition.js @@ -44,12 +44,20 @@ var StepDefinition = function(pattern, code) { callback(failedStepResult); }; - var parameters = self.buildInvocationParameters(step, codeCallback); + // Previous version of the code had codeCallback as a parameter, but we'll exclude this and call it ourselves. + var parameters = self.buildInvocationParameters(step, null); var handleException = self.buildExceptionHandlerToCodeCallback(codeCallback); Cucumber.Util.Exception.registerUncaughtExceptionHandler(handleException); try { - code.apply(world, parameters); + // Create an angular callback. Angular just executes the function, so we wrap it here so we can include any parameters. + var angularCallback = function() { code.apply(this, parameters); }; + + // Create an Angular scenario runner 'it' block + it(step.getKeyword() + ': ' + step.getName(), angularCallback); + + // Make the callback immediately as angular will actually run the tests, so we just tell Cucumber everything worked fine and let it continue + codeCallback(); } catch (exception) { handleException(exception); } @@ -64,7 +72,12 @@ var StepDefinition = function(pattern, code) { var attachmentContents = step.getAttachmentContents(); parameters.push(attachmentContents); } - parameters.push(callback); + + // If a callback exists, then include it, won't be required for angular integration. + if (!!callback) { + parameters.push(callback); + } + return parameters; }, diff --git a/lib/cucumber/support_code/step_definition_snippet_builder.js b/lib/cucumber/support_code/step_definition_snippet_builder.js index a6f1a7179..755cd9701 100644 --- a/lib/cucumber/support_code/step_definition_snippet_builder.js +++ b/lib/cucumber/support_code/step_definition_snippet_builder.js @@ -87,10 +87,10 @@ var StepDefinitionSnippetBuilder = function(step) { StepDefinitionSnippetBuilder.STEP_DEFINITION_START = 'this.'; StepDefinitionSnippetBuilder.STEP_DEFINITION_INNER1 = '('; StepDefinitionSnippetBuilder.STEP_DEFINITION_INNER2 = ', function('; -StepDefinitionSnippetBuilder.STEP_DEFINITION_END = ") {\n // express the regexp above with the code you wish you had\n callback.pending();\n});\n"; +StepDefinitionSnippetBuilder.STEP_DEFINITION_END = ") {\n // express the regexp above with the equivalent angular DSL code\n throw ('Error: Step not implemented');\n});\n"; StepDefinitionSnippetBuilder.STEP_DEFINITION_DOC_STRING = 'string'; StepDefinitionSnippetBuilder.STEP_DEFINITION_DATA_TABLE = 'table'; -StepDefinitionSnippetBuilder.STEP_DEFINITION_CALLBACK = 'callback'; +StepDefinitionSnippetBuilder.STEP_DEFINITION_CALLBACK = ''; StepDefinitionSnippetBuilder.PATTERN_START = '/^'; StepDefinitionSnippetBuilder.PATTERN_END = '$/'; StepDefinitionSnippetBuilder.CONTEXT_STEP_DEFINITION_FUNCTION_NAME = 'Given'; @@ -101,4 +101,4 @@ StepDefinitionSnippetBuilder.NUMBER_MATCHING_GROUP = '(\\d+)'; StepDefinitionSnippetBuilder.QUOTED_STRING_PATTERN = /"[^"]*"/gi; StepDefinitionSnippetBuilder.QUOTED_STRING_MATCHING_GROUP = '"([^"]*)"'; StepDefinitionSnippetBuilder.FUNCTION_PARAMETER_SEPARATOR = ', '; -module.exports = StepDefinitionSnippetBuilder; +module.exports = StepDefinitionSnippetBuilder; \ No newline at end of file From d4e3ddf242a3f4f2ae69db69e71a3b277240aaa7 Mon Sep 17 00:00:00 2001 From: Tim Haines Date: Tue, 26 Jun 2012 15:56:53 +0100 Subject: [PATCH 2/2] Integration with Angular Missed from previous check in. Create an Angular "describe" block for each Cucumber feature. --- lib/cucumber/ast/feature.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/cucumber/ast/feature.js b/lib/cucumber/ast/feature.js index a9ebec68d..2502c8410 100644 --- a/lib/cucumber/ast/feature.js +++ b/lib/cucumber/ast/feature.js @@ -52,10 +52,20 @@ var Feature = function(keyword, name, description, line) { return tags; }, - acceptVisitor: function acceptVisitor(visitor, callback) { - self.instructVisitorToVisitBackground(visitor, function() { - self.instructVisitorToVisitScenarios(visitor, callback); - }); + acceptVisitor: function acceptVisitor(visitor, callback) { + // Create an angular describe block + describeStart(self.getKeyword() + ': ' + self.getName(),function(endDescribeCallback) { + // Call each cucumber background and all scenarios + self.instructVisitorToVisitBackground(visitor, function() { + self.instructVisitorToVisitScenarios(visitor, function() { + // When background and scenarios have completed, close the describe block + endDescribeCallback(); + // Tell cucumber we've finished with the feature - we'll let angular deal with any errors. + callback(); + }); + }); + }, + self.getDescription()); }, instructVisitorToVisitBackground: function instructVisitorToVisitBackground(visitor, callback) {