From 4ca4426f1dcde49211c96c953a81f16e406bb4f1 Mon Sep 17 00:00:00 2001 From: Carl Banbury Date: Sat, 11 Apr 2015 01:15:12 +0100 Subject: [PATCH] basic setup to use global protractor and run tests --- .gitignore | 3 ++ .jshintrc | 13 +++++ Gruntfile.js | 73 ++++++++++++++++++++++++++++ LICENSE-MIT | 22 +++++++++ README.md | 89 ++++++++++++++++++++++++++++++++++ examples/basic/conf.js | 6 +++ examples/basic/gruntfile.js | 16 ++++++ examples/basic/spec.js | 9 ++++ package.json | 41 ++++++++++++++++ tasks/webdriver_protractor.js | 61 +++++++++++++++++++++++ test/expected/custom_options | 1 + test/expected/default_options | 1 + test/fixtures/123 | 1 + test/fixtures/testing | 1 + test/simple_protractor_test.js | 48 ++++++++++++++++++ 15 files changed, 385 insertions(+) create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 Gruntfile.js create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 examples/basic/conf.js create mode 100644 examples/basic/gruntfile.js create mode 100644 examples/basic/spec.js create mode 100644 package.json create mode 100644 tasks/webdriver_protractor.js create mode 100644 test/expected/custom_options create mode 100644 test/expected/default_options create mode 100644 test/fixtures/123 create mode 100644 test/fixtures/testing create mode 100644 test/simple_protractor_test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b785247 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +npm-debug.log +tmp diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..f57a8ff --- /dev/null +++ b/.jshintrc @@ -0,0 +1,13 @@ +{ + "curly": true, + "eqeqeq": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "sub": true, + "undef": true, + "boss": true, + "eqnull": true, + "node": true +} diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..ac805a7 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,73 @@ +/* + * grunt-simple-protractor + * + * + * Copyright (c) 2015 Carl Banbury + * Licensed under the MIT license. + */ + +'use strict'; + +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + jshint: { + all: [ + 'Gruntfile.js', + 'tasks/*.js', + '<%= nodeunit.tests %>' + ], + options: { + jshintrc: '.jshintrc' + } + }, + + // Before generating any new files, remove any previously-created files. + clean: { + tests: ['tmp'] + }, + + // Configuration to be run (and then tested). + simple_protractor: { + default_options: { + options: { + }, + files: { + 'tmp/default_options': ['test/fixtures/testing', 'test/fixtures/123'] + } + }, + custom_options: { + options: { + separator: ': ', + punctuation: ' !!!' + }, + files: { + 'tmp/custom_options': ['test/fixtures/testing', 'test/fixtures/123'] + } + } + }, + + // Unit tests. + nodeunit: { + tests: ['test/*_test.js'] + } + + }); + + // Actually load this plugin's task(s). + grunt.loadTasks('tasks'); + + // These plugins provide necessary tasks. + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-nodeunit'); + + // Whenever the "test" task is run, first clean the "tmp" dir, then run this + // plugin's task(s), then test the result. + grunt.registerTask('test', ['clean', 'simple_protractor', 'nodeunit']); + + // By default, lint and run all tests. + grunt.registerTask('default', ['jshint', 'test']); + +}; diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..2c3289f --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,22 @@ +Copyright (c) 2015 Carl Banbury + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bdf27f0 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# grunt-simple-protractor + +> Start webdriver manager, start a local test server and run protractor + +## Getting Started +This plugin requires Grunt `~0.4.5` + +If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: + +```shell +npm install grunt-simple-protractor --save-dev +``` + +Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: + +```js +grunt.loadNpmTasks('grunt-simple-protractor'); +``` + +## The "simple_protractor" task + +### Overview +In your project's Gruntfile, add a section named `simple_protractor` to the data object passed into `grunt.initConfig()`. + +```js +grunt.initConfig({ + simple_protractor: { + options: { + // Task-specific options go here. + }, + your_target: { + // Target-specific file lists and/or options go here. + }, + }, +}); +``` + +### Options + +#### options.separator +Type: `String` +Default value: `', '` + +A string value that is used to do something with whatever. + +#### options.punctuation +Type: `String` +Default value: `'.'` + +A string value that is used to do something else with whatever else. + +### Usage Examples + +#### Default Options +In this example, the default options are used to do something with whatever. So if the `testing` file has the content `Testing` and the `123` file had the content `1 2 3`, the generated result would be `Testing, 1 2 3.` + +```js +grunt.initConfig({ + simple_protractor: { + options: {}, + files: { + 'dest/default_options': ['src/testing', 'src/123'], + }, + }, +}); +``` + +#### Custom Options +In this example, custom options are used to do something else with whatever else. So if the `testing` file has the content `Testing` and the `123` file had the content `1 2 3`, the generated result in this case would be `Testing: 1 2 3 !!!` + +```js +grunt.initConfig({ + simple_protractor: { + options: { + separator: ': ', + punctuation: ' !!!', + }, + files: { + 'dest/default_options': ['src/testing', 'src/123'], + }, + }, +}); +``` + +## Contributing +In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). + +## Release History +_(Nothing yet)_ diff --git a/examples/basic/conf.js b/examples/basic/conf.js new file mode 100644 index 0000000..7bcf176 --- /dev/null +++ b/examples/basic/conf.js @@ -0,0 +1,6 @@ +'use strict'; + +exports.config = { + seleniumAddress: 'http://localhost:4444/wd/hub', + specs: ['spec.js'] +}; diff --git a/examples/basic/gruntfile.js b/examples/basic/gruntfile.js new file mode 100644 index 0000000..5a6efae --- /dev/null +++ b/examples/basic/gruntfile.js @@ -0,0 +1,16 @@ +'use strict'; + +module.exports = function(grunt) { + grunt.loadTasks('../../tasks'); + + grunt.initConfig({ + simple_protractor: { + options: { + configFile: 'conf.js' + }, + all: {} + } + }); + + grunt.registerTask('default', ['simple_protractor']); +}; diff --git a/examples/basic/spec.js b/examples/basic/spec.js new file mode 100644 index 0000000..ce77429 --- /dev/null +++ b/examples/basic/spec.js @@ -0,0 +1,9 @@ +'use strict'; + +describe('Protractor Demo App', function() { + it('should have a title', function() { + browser.get('http://juliemr.github.io/protractor-demo/'); + + expect(browser.getTitle()).toEqual('Super Calculator'); + }); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..570a87e --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "grunt-simple-protractor", + "description": "Start webdriver manager, start a local test server and run protractor", + "version": "0.0.1", + "homepage": "", + "author": { + "name": "Carl Banbury", + "email": "carl@banbury.ch" + }, + "repository": { + "type": "git", + "url": "null" + }, + "bugs": { + "url": "" + }, + "licenses": [ + { + "type": "MIT", + "url": "/blob/master/LICENSE-MIT" + } + ], + "engines": { + "node": ">= 0.8.0" + }, + "scripts": { + "test": "grunt test" + }, + "devDependencies": { + "grunt": "~0.4.5", + "grunt-contrib-clean": "^0.5.0", + "grunt-contrib-jshint": "^0.9.2", + "grunt-contrib-nodeunit": "^0.3.3" + }, + "peerDependencies": { + "grunt": "~0.4.5" + }, + "keywords": [ + "gruntplugin" + ] +} diff --git a/tasks/webdriver_protractor.js b/tasks/webdriver_protractor.js new file mode 100644 index 0000000..d0e0173 --- /dev/null +++ b/tasks/webdriver_protractor.js @@ -0,0 +1,61 @@ +/* +* grunt-simple-protractor +* +* +* Copyright (c) 2015 Carl Banbury +* Licensed under the MIT license. +*/ + +'use strict'; +var spawn = require('child_process').spawn; +var spawnSync = require('child_process').spawnSync; + +module.exports = function(grunt) { + grunt.registerMultiTask('simple_protractor', 'Start selenium webdriver, local server and run protractor tests', function() { + var done = this.async(); + var options = this.options({}); + + var webdriverBin = options.webdriver_bin || 'webdriver-manager'; + var protractorBin = options.protractor_bin || 'protractor'; + var configFile = options.config_file || 'conf.js'; + + var update = spawnSync(webdriverBin, ['update'], {stdio: 'pipe'}); + var webdriver = spawn(webdriverBin, ['start']); + var protractor; + var pid; + + webdriver.stderr.on('data', function(data) { + if (data.toString().search('WARN') > -1) { + return grunt.fail.warn(data.toString()); + } + + if (data.toString().search('ERROR') > -1) { + return grunt.fail.warn(data.toString()); + } + + // run protactor once the webdriver is running + if (data.toString().search('INFO - Started SocketListener') > -1) { + protractor = spawn(protractorBin, [configFile], {stdio: 'inherit'}); + + protractor.on('close', function(code) { + process.kill(webdriver.pid); + process.kill(pid); + + if (code !== 0) { + return grunt.fail.warn(data.toString()); + } + + return done(code); + }); + } + }); + + webdriver.stdout.on('data', function(data) { + + // grab the pid from log so we can cleanly exit + if (data.toString().search('seleniumProcess.pid') > -1) { + pid = +data.toString().split(': ').pop(); + } + }); + }); +}; diff --git a/test/expected/custom_options b/test/expected/custom_options new file mode 100644 index 0000000..e597128 --- /dev/null +++ b/test/expected/custom_options @@ -0,0 +1 @@ +Testing: 1 2 3 !!! \ No newline at end of file diff --git a/test/expected/default_options b/test/expected/default_options new file mode 100644 index 0000000..5f8b72f --- /dev/null +++ b/test/expected/default_options @@ -0,0 +1 @@ +Testing, 1 2 3. \ No newline at end of file diff --git a/test/fixtures/123 b/test/fixtures/123 new file mode 100644 index 0000000..703ca85 --- /dev/null +++ b/test/fixtures/123 @@ -0,0 +1 @@ +1 2 3 \ No newline at end of file diff --git a/test/fixtures/testing b/test/fixtures/testing new file mode 100644 index 0000000..0a90125 --- /dev/null +++ b/test/fixtures/testing @@ -0,0 +1 @@ +Testing \ No newline at end of file diff --git a/test/simple_protractor_test.js b/test/simple_protractor_test.js new file mode 100644 index 0000000..247514f --- /dev/null +++ b/test/simple_protractor_test.js @@ -0,0 +1,48 @@ +'use strict'; + +var grunt = require('grunt'); + +/* + ======== A Handy Little Nodeunit Reference ======== + https://github.com/caolan/nodeunit + + Test methods: + test.expect(numAssertions) + test.done() + Test assertions: + test.ok(value, [message]) + test.equal(actual, expected, [message]) + test.notEqual(actual, expected, [message]) + test.deepEqual(actual, expected, [message]) + test.notDeepEqual(actual, expected, [message]) + test.strictEqual(actual, expected, [message]) + test.notStrictEqual(actual, expected, [message]) + test.throws(block, [error], [message]) + test.doesNotThrow(block, [error], [message]) + test.ifError(value) +*/ + +exports.simple_protractor = { + setUp: function(done) { + // setup here if necessary + done(); + }, + default_options: function(test) { + test.expect(1); + + var actual = grunt.file.read('tmp/default_options'); + var expected = grunt.file.read('test/expected/default_options'); + test.equal(actual, expected, 'should describe what the default behavior is.'); + + test.done(); + }, + custom_options: function(test) { + test.expect(1); + + var actual = grunt.file.read('tmp/custom_options'); + var expected = grunt.file.read('test/expected/custom_options'); + test.equal(actual, expected, 'should describe what the custom option(s) behavior is.'); + + test.done(); + }, +};