From ddb8584a59343284904676ef6d8db5c1c996b900 Mon Sep 17 00:00:00 2001 From: Matt Fritz Date: Fri, 13 Nov 2015 15:31:45 -0700 Subject: [PATCH] chore(cucumber): Remove cucumber from internal implementation --- docs/frameworks.md | 25 ++-- docs/infrastructure.md | 2 +- docs/jasmine-upgrade.md | 2 +- docs/referenceConf.js | 6 +- lib/cli.js | 2 +- lib/configParser.js | 13 -- lib/frameworks/README.md | 10 +- lib/frameworks/cucumber.js | 189 --------------------------- lib/runner.js | 2 - package.json | 1 - scripts/test.js | 2 - scripts/test/test_util.js | 2 +- spec/cucumber/lib.feature | 15 --- spec/cucumber/stepDefinitions.js | 41 ------ spec/cucumberConf.js | 23 ---- spec/plugins/cucumberPostTestConf.js | 1 - spec/plugins/features/simple.feature | 3 - spec/plugins/postTestConfTemplate.js | 3 +- spec/unit/config_test.js | 12 -- 19 files changed, 29 insertions(+), 325 deletions(-) delete mode 100644 lib/frameworks/cucumber.js delete mode 100644 spec/cucumber/lib.feature delete mode 100644 spec/cucumber/stepDefinitions.js delete mode 100644 spec/cucumberConf.js delete mode 100644 spec/plugins/cucumberPostTestConf.js delete mode 100644 spec/plugins/features/simple.feature diff --git a/docs/frameworks.md b/docs/frameworks.md index cd4679dba..b00679b9d 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -1,7 +1,7 @@ Choosing a Framework ==================== -Protractor supports three behavior driven development (BDD) test frameworks: Jasmine, Mocha, and Cucumber. These frameworks are based on JavaScript and Node.js and provide the syntax, scaffolding, and reporting tools you will use to write and manage your tests. +Protractor supports two behavior driven development (BDD) test frameworks out of the box: Jasmine and Mocha. These frameworks are based on JavaScript and Node.js and provide the syntax, scaffolding, and reporting tools you will use to write and manage your tests. Using Jasmine @@ -58,28 +58,35 @@ For a full example, see Protractor’s own test: [/spec/mocha/lib_spec.js](/spec Using Cucumber -------------- -_Note: Limited support for Cucumber is available as of January 2015. Support for Cucumber in Protractor is maintained by the community, so bug fixes may be slow. For more information, see the [Cucumber GitHub site](https://github.com/cucumber/cucumber-js)._ +_Note: Cucumber is no longer included by default as of version `3.0`. You can integrate Cucumber with Protractor with the `custom` framework option. For more information, see the [Protractor Cucumber Framework site](https://github.com/mattfritz/protractor-cucumber-framework) or the [Cucumber GitHub site](https://github.com/cucumber/cucumber-js)._ If you would like to use the Cucumber test framework, download the dependencies with npm. Cucumber should be installed in the same place as Protractor - so if protractor was installed globally, install Cucumber with -g. ``` npm install -g cucumber +npm install --save-dev protractor-cucumber-framework ``` -Set the 'framework' property to cucumber, either by adding `framework: 'cucumber'` to the [config file](../spec/cucumberConf.js) or by adding `--framework=cucumber` to the command line. +Set the 'framework' property to custom by adding `framework: 'custom'` and `frameworkPath: 'protractor-cucumber-framework'` to the [config file](../spec/cucumberConf.js) Options for Cucumber such as 'format' can be given in the config file with cucumberOpts: ```js -cucumberOpts: { - format: "summary" -} +exports.config = { + // set to "custom" instead of cucumber. + framework: 'custom', + + // path relative to the current config file + frameworkPath: 'protractor-cucumber-framework' + + // relevant cucumber command line options + cucumberOpts: { + format: "summary" + } +}; ``` -For a full example, see Protractor’s own test: [/spec/cucumber/lib.feature](/spec/cucumber/lib.feature). - - Using a Custom Framework ------------------------ diff --git a/docs/infrastructure.md b/docs/infrastructure.md index 4c1a64212..3e83300ca 100644 --- a/docs/infrastructure.md +++ b/docs/infrastructure.md @@ -2,7 +2,7 @@ How It Works ============ -Protractor is an end-to-end test framework for AngularJS applications. Protractor is a Node.js program that supports the Jasmine, Mocha, and Cucumber test frameworks. +Protractor is an end-to-end test framework for AngularJS applications. Protractor is a Node.js program that supports the Jasmine and Mocha test frameworks. Selenium is a browser automation framework. Selenium includes the Selenium Server, the WebDriver APIs, and the WebDriver browser drivers. diff --git a/docs/jasmine-upgrade.md b/docs/jasmine-upgrade.md index f683d79b6..c4df4c9dc 100644 --- a/docs/jasmine-upgrade.md +++ b/docs/jasmine-upgrade.md @@ -9,7 +9,7 @@ Specify that you want to use jasmine2.x: ```javascript exports.config = { - // Specify you want to use jasmine 2.x as you would with mocha and cucumber. Note, 'jasmine' by default will use the latest jasmine framework. + // Specify you want to use jasmine 2.x as you would with mocha. Note, 'jasmine' by default will use the latest jasmine framework. framework: 'jasmine' }; diff --git a/docs/referenceConf.js b/docs/referenceConf.js index 64d130846..04548b936 100644 --- a/docs/referenceConf.js +++ b/docs/referenceConf.js @@ -279,7 +279,7 @@ exports.config = { // --------------------------------------------------------------------------- // Test framework to use. This may be one of: - // jasmine, cucumber, mocha or custom. + // jasmine, mocha or custom. // // When the framework is set to "custom" you'll need to additionally // set frameworkPath with the path relative to the config file or absolute @@ -289,7 +289,7 @@ exports.config = { // to comply with the interface details of your custom implementation. // // Jasmine is fully supported as test and assertion frameworks. - // Mocha and Cucumber have limited support. You will need to include your + // Mocha has limited support. You will need to include your // own assertion framework (such as Chai) if working with Mocha. framework: 'jasmine', @@ -319,7 +319,7 @@ exports.config = { reporter: 'list' }, - // Options to be passed to Cucumber. + // Options to be passed to Cucumber (when set up as a custom framework). cucumberOpts: { // Require files before executing the features. require: 'cucumber/stepDefinitions.js', diff --git a/lib/cli.js b/lib/cli.js index 05ee94f75..6a2ac66c7 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -48,7 +48,7 @@ var optimist = require('optimist'). describe('verbose', 'Print full spec names'). describe('stackTrace', 'Print stack trace on error'). describe('params', 'Param object to be passed to the tests'). - describe('framework', 'Test framework to use: jasmine, cucumber or mocha'). + describe('framework', 'Test framework to use: jasmine, mocha, or custom'). describe('resultJsonOutputFile', 'Path to save JSON test result'). describe('troubleshoot', 'Turn on troubleshooting output'). describe('elementExplorer', 'Interactively test Protractor commands'). diff --git a/lib/configParser.js b/lib/configParser.js index f03e1cd42..5d0ed8e2e 100644 --- a/lib/configParser.js +++ b/lib/configParser.js @@ -34,7 +34,6 @@ var ConfigParser = function() { defaultTimeoutInterval: (30 * 1000) }, seleniumArgs: [], - cucumberOpts: {}, mochaOpts: { ui: 'bdd', reporter: 'list' @@ -95,16 +94,7 @@ ConfigParser.resolveFilePatterns = if (patterns) { for (var i = 0; i < patterns.length; ++i) { - // Cucumber allows running a spec given a line number. See - // https://github.com/angular/protractor/issues/2413 - // TODO: when we deprecated node < v0.12 switch to using path.parse as in - // d6aebbad6e9b191fef141472887637ee4318438e var fileName = patterns[i]; - var lineNumber = /:\d+$/.exec(fileName); - if (lineNumber) { - fileName = fileName.slice(0, lineNumber.index); - lineNumber = lineNumber[0].slice(1); - } var matches = glob.sync(fileName, {cwd: cwd}); if (!matches.length && !opt_omitWarnings) { @@ -112,9 +102,6 @@ ConfigParser.resolveFilePatterns = } for (var j = 0; j < matches.length; ++j) { var resolvedPath = path.resolve(cwd, matches[j]); - if (lineNumber) { - resolvedPath += ':' + lineNumber; - } resolvedFiles.push(resolvedPath); } } diff --git a/lib/frameworks/README.md b/lib/frameworks/README.md index 49a28179b..7db48c1df 100644 --- a/lib/frameworks/README.md +++ b/lib/frameworks/README.md @@ -29,7 +29,7 @@ Requirements - `runner.getConfig().onComplete` must be called when tests are finished. - - The returned promise must be resolved when tests are finished and it should return a results object. This object must have a `failedCount` property and optionally a `specResults` + - The returned promise must be resolved when tests are finished and it should return a results object. This object must have a `failedCount` property and optionally a `specResults` object of the following structure: ``` specResults = [{ @@ -37,7 +37,7 @@ Requirements assertions: [{ passed: boolean, errorMsg: string, - stackTrace: string + stackTrace: string }], duration: integer }] @@ -46,14 +46,14 @@ Requirements Custom Frameworks ----------------- -If you have created/adapted a custom framework and want it added to -Protractor core please send a PR so it can evaluated for addition as an +If you have created/adapted a custom framework and want it added to +Protractor core please send a PR so it can evaluated for addition as an official supported framework. In the meantime you can instruct Protractor to use your own framework via the config file: ```js exports.config = { - // set to "custom" instead of jasmine/mocha/cucumber. + // set to "custom" instead of jasmine/mocha framework: 'custom', // path relative to the current config file frameworkPath: './frameworks/my_custom_jasmine.js', diff --git a/lib/frameworks/cucumber.js b/lib/frameworks/cucumber.js deleted file mode 100644 index f8dde2398..000000000 --- a/lib/frameworks/cucumber.js +++ /dev/null @@ -1,189 +0,0 @@ -var ConfigParser = require('../configParser'), - q = require('q'); - -/** - * Execute the Runner's test cases through Cucumber. - * - * @param {Runner} runner The current Protractor Runner. - * @param {Array} specs Array of Directory Path Strings. - * @return {q.Promise} Promise resolved with the test results - */ -exports.run = function(runner, specs) { - // TODO - add the event interface for cucumber. - var Cucumber = require('cucumber'), - execOptions = ['node', 'node_modules/.bin/cucumber-js'], - cucumberResolvedRequire; - - // Set up exec options for Cucumber - execOptions = execOptions.concat(specs); - if (runner.getConfig().cucumberOpts) { - - // Process Cucumber Require param - if (runner.getConfig().cucumberOpts.require) { - // TODO - this should move into the launcher. - cucumberResolvedRequire = - ConfigParser.resolveFilePatterns( - runner.getConfig().cucumberOpts.require, - false, - runner.getConfig().configDir); - if (cucumberResolvedRequire && cucumberResolvedRequire.length) { - execOptions = cucumberResolvedRequire.reduce(function(a, fn) { - return a.concat('-r', fn); - }, execOptions); - } - } - - // Process Cucumber Tag param - if (Array.isArray(runner.getConfig().cucumberOpts.tags)) { - for (var i in runner.getConfig().cucumberOpts.tags) { - var tags = runner.getConfig().cucumberOpts.tags[i]; - execOptions.push('-t'); - execOptions.push(tags); - } - } else if (runner.getConfig().cucumberOpts.tags) { - execOptions.push('-t'); - execOptions.push(runner.getConfig().cucumberOpts.tags); - } - - // Process Cucumber Format param - if (Array.isArray(runner.getConfig().cucumberOpts.format)) { - runner.getConfig().cucumberOpts.format.forEach(function (format) { - execOptions.push('-f'); - execOptions.push(format); - }); - } else if (runner.getConfig().cucumberOpts.format) { - execOptions.push('-f'); - execOptions.push(runner.getConfig().cucumberOpts.format); - } - - // Process Cucumber 'coffee' param - if (runner.getConfig().cucumberOpts.coffee) { - execOptions.push('--coffee'); - } - - // Process Cucumber 'no-snippets' param - if (runner.getConfig().cucumberOpts.noSnippets) { - execOptions.push('--no-snippets'); - } - - // Process Cucumber 'dry-run' param - if (runner.getConfig().cucumberOpts.dryRun) { - execOptions.push('-d'); - } - } - global.cucumber = Cucumber.Cli(execOptions); - - var testResult = []; - var stepResults = { - description: null, - assertions: [], - duration: 0 - }; - var scenarioFailed = false; - - var failedCount = 0; - // Add a listener into cucumber so that protractor can find out which - // steps passed/failed - var addResultListener = function(formatter) { - var feature = { getName: function() { return ''; } }; - var originalHandleBeforeFeatureEvent = formatter.handleBeforeFeatureEvent; - formatter.handleBeforeFeatureEvent = function(event, callback) { - feature = event.getPayloadItem('feature'); - if (typeof originalHandleBeforeFeatureEvent == 'function') { - originalHandleBeforeFeatureEvent.apply(formatter, arguments); - } else { - callback(); - } - }; - var originalHandleAfterScenarioEvent = formatter.handleAfterScenarioEvent; - formatter.handleAfterScenarioEvent = function(event, callback) { - var scenarioInfo = { - name: event.getPayloadItem('scenario').getName(), - category: feature.getName() - }; - stepResults.description = scenarioInfo.name; - if (scenarioFailed) { - ++failedCount; - runner.emit('testFail', scenarioInfo); - } else { - runner.emit('testPass', scenarioInfo); - } - - testResult.push(stepResults); - stepResults = { - description: null, - assertions: [], - duration: 0 - }; - scenarioFailed = false; - - if (originalHandleAfterScenarioEvent - && typeof(originalHandleAfterScenarioEvent) === 'function') { - originalHandleAfterScenarioEvent(event, callback); - } else { - callback(); - } - }; - - var originalHandleStepResultEvent = formatter.handleStepResultEvent; - formatter.handleStepResultEvent = function(event, callback) { - var stepResult = event.getPayloadItem('stepResult'); - var isStepFailed = stepResult.isFailed ? - stepResult.isFailed() : - stepResult.getStatus() === Cucumber.Status.FAILED; - var isStepSuccessful = stepResult.isSuccessful ? - stepResult.isSuccessful() : - stepResult.getStatus() === Cucumber.Status.PASSED; - - if (isStepSuccessful) { - stepResults.assertions.push({ - passed: true - }); - stepResults.duration += stepResult.getDuration(); - } else if (isStepFailed) { - scenarioFailed = true; - var failureMessage = stepResult.getFailureException(); - stepResults.assertions.push({ - passed: false, - errorMsg: failureMessage.message, - stackTrace: failureMessage.stack - }); - stepResults.duration += stepResult.getDuration(); - } - - if (originalHandleStepResultEvent - && typeof(originalHandleStepResultEvent) === 'function') { - originalHandleStepResultEvent(event, callback); - } else { - callback(); - } - }; - }; - - return runner.runTestPreparer().then(function() { - return q.promise(function(resolve, reject) { - var cucumberConf = Cucumber.Cli.Configuration(execOptions); - var runtime = Cucumber.Runtime(cucumberConf); - var formatters = cucumberConf.getFormatter ? - [cucumberConf.getFormatter()] : - cucumberConf.getFormatters(); - - addResultListener(formatters[0]); - formatters.forEach(runtime.attachListener.bind(runtime)); - - runtime.start(function() { - try { - if (runner.getConfig().onComplete) { - runner.getConfig().onComplete(); - } - resolve({ - failedCount: failedCount, - specResults: testResult - }); - } catch (err) { - reject(err); - } - }); - }); - }); -}; diff --git a/lib/runner.js b/lib/runner.js index 0965689f0..eeb99a579 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -295,8 +295,6 @@ Runner.prototype.run = function() { frameworkPath = './frameworks/jasmine.js'; } else if (self.config_.framework === 'mocha') { frameworkPath = './frameworks/mocha.js'; - } else if (self.config_.framework === 'cucumber') { - frameworkPath = './frameworks/cucumber.js'; } else if (self.config_.framework === 'debugprint') { // Private framework. Do not use. frameworkPath = './frameworks/debugprint.js'; diff --git a/package.json b/package.json index ed2ed0665..7d5e99d1e 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "chai-as-promised": "~5.1.0", "jshint": "2.5.0", "mocha": "2.3.3", - "cucumber": "~0.8.0", "express": "~3.3.4", "rimraf": "~2.2.6" }, diff --git a/scripts/test.js b/scripts/test.js index 3ae550d6b..fb88ae97d 100755 --- a/scripts/test.js +++ b/scripts/test.js @@ -14,7 +14,6 @@ var passingTests = [ 'node lib/cli.js spec/onPreparePromiseConf.js', 'node lib/cli.js spec/onPreparePromiseFileConf.js', 'node lib/cli.js spec/mochaConf.js', - 'node lib/cli.js spec/cucumberConf.js', 'node lib/cli.js spec/withLoginConf.js', 'node lib/cli.js spec/suitesConf.js --suite okmany', 'node lib/cli.js spec/suitesConf.js --suite okspec', @@ -23,7 +22,6 @@ var passingTests = [ 'node lib/cli.js spec/plugins/multiPluginConf.js', 'node lib/cli.js spec/plugins/jasminePostTestConf.js', 'node lib/cli.js spec/plugins/mochaPostTestConf.js', - 'node lib/cli.js spec/plugins/cucumberPostTestConf.js', 'node lib/cli.js spec/plugins/browserGetSyncedConf.js', 'node lib/cli.js spec/plugins/browserGetUnsyncedConf.js', 'node lib/cli.js spec/plugins/waitForAngularConf.js', diff --git a/scripts/test/test_util.js b/scripts/test/test_util.js index b9f6e3417..93bd39d05 100644 --- a/scripts/test/test_util.js +++ b/scripts/test/test_util.js @@ -192,7 +192,7 @@ var CommandlineTest = function(command) { * exitCode, test durations, expected errors, and expected stackTrace * Note, this will work with any commandline tests, but only if it supports * the flag '--resultJsonOutputFile', unless only exitCode is being tested. - * For now, this means protractor tests (jasmine/mocha/cucumber). + * For now, this means protractor tests (jasmine/mocha). */ exports.Executor = function() { var tests = []; diff --git a/spec/cucumber/lib.feature b/spec/cucumber/lib.feature deleted file mode 100644 index bdd005738..000000000 --- a/spec/cucumber/lib.feature +++ /dev/null @@ -1,15 +0,0 @@ -Feature: Running Cucumber with Protractor - As a user of Protractor - I should be able to use Cucumber - to run my E2E tests - - @dev - Scenario: Running Cucumber with Protractor - Given I run Cucumber with Protractor - Then it should still do normal tests - Then it should expose the correct global variables - - @dev - Scenario: Wrapping WebDriver - Given I go on "index.html" - Then the title should equal "My AngularJS App" diff --git a/spec/cucumber/stepDefinitions.js b/spec/cucumber/stepDefinitions.js deleted file mode 100644 index 0d8374b1c..000000000 --- a/spec/cucumber/stepDefinitions.js +++ /dev/null @@ -1,41 +0,0 @@ -// Use the external Chai As Promised to deal with resolving promises in -// expectations. -var chai = require('chai'); -var chaiAsPromised = require('chai-as-promised'); -chai.use(chaiAsPromised); - -var expect = chai.expect; - -// Chai expect().to.exist syntax makes default jshint unhappy. -// jshint expr:true - -module.exports = function() { - - this.Given(/^I run Cucumber with Protractor$/, function(next) { - next(); - }); - - this.Given(/^I go on(?: the website)? "([^"]*)"$/, function(url, next) { - browser.get(url); - next(); - }); - - this.Then(/^it should still do normal tests$/, function(next) { - expect(true).to.equal(true); - next(); - }); - - this.Then(/^it should expose the correct global variables$/, function(next) { - expect(protractor).to.exist; - expect(browser).to.exist; - expect(by).to.exist; - expect(element).to.exist; - expect($).to.exist; - next(); - }); - - this.Then(/the title should equal "([^"]*)"$/, function(text, next) { - expect(browser.getTitle()).to.eventually.equal(text).and.notify(next); - }); - -}; diff --git a/spec/cucumberConf.js b/spec/cucumberConf.js deleted file mode 100644 index cbf1ab40e..000000000 --- a/spec/cucumberConf.js +++ /dev/null @@ -1,23 +0,0 @@ -var env = require('./environment.js'); - -// A small suite to make sure the cucumber framework works. -exports.config = { - seleniumAddress: env.seleniumAddress, - - framework: 'cucumber', - - // Spec patterns are relative to this directory. - specs: [ - 'cucumber/*.feature' - ], - - capabilities: env.capabilities, - - baseUrl: env.baseUrl, - - cucumberOpts: { - require: 'cucumber/stepDefinitions.js', - tags: '@dev', - format: 'pretty' - } -}; diff --git a/spec/plugins/cucumberPostTestConf.js b/spec/plugins/cucumberPostTestConf.js deleted file mode 100644 index 5eeb8e435..000000000 --- a/spec/plugins/cucumberPostTestConf.js +++ /dev/null @@ -1 +0,0 @@ -exports.config = require('./postTestConfTemplate')('cucumber'); diff --git a/spec/plugins/features/simple.feature b/spec/plugins/features/simple.feature deleted file mode 100644 index fbd070a69..000000000 --- a/spec/plugins/features/simple.feature +++ /dev/null @@ -1,3 +0,0 @@ -Feature: category - This is spec does nothing - Scenario: name diff --git a/spec/plugins/postTestConfTemplate.js b/spec/plugins/postTestConfTemplate.js index 4d37410f7..8a39db240 100644 --- a/spec/plugins/postTestConfTemplate.js +++ b/spec/plugins/postTestConfTemplate.js @@ -7,8 +7,7 @@ module.exports = function(framework) { framework: framework, specs: [ - framework != 'cucumber' ? 'specs/simple_spec.js' : - 'features/simple.feature' + 'specs/simple_spec.js' ], capabilities: env.capabilities, diff --git a/spec/unit/config_test.js b/spec/unit/config_test.js index 9a51a704e..15c655657 100644 --- a/spec/unit/config_test.js +++ b/spec/unit/config_test.js @@ -62,17 +62,5 @@ describe('the config parser', function() { expect(specs[0].indexOf(path.normalize('unit/data/fakespecA.js'))).not.toEqual(-1); expect(specs[1].indexOf(path.normalize('unit/data/fakespecB.js'))).not.toEqual(-1); }); - - it('should allow for line numbers in file paths', function() { - spyOn(process, 'cwd').and.returnValue(__dirname + '/'); - var toAdd = { - specs: ['data/fakespecA.js:32', 'data/fakespecB.js'] - }; - var config = new ConfigParser().addConfig(toAdd).getConfig(); - var specs = ConfigParser.resolveFilePatterns(config.specs); - expect(specs.length).toEqual(2); - expect(specs[0].indexOf(path.normalize('unit/data/fakespecA.js:32'))).not.toEqual(-1); - expect(specs[1]).toMatch(/unit\/data\/fakespecB.js$/); - }); }); });