Permalink
Browse files

test - rework the setup to be based on cucumber/zombie, grunt spawned

  • Loading branch information...
mklabs committed Mar 25, 2012
1 parent ef99f70 commit 901149144b65ce3ed870e5c4a5c2fd444bb0dc6a
Showing with 417 additions and 8 deletions.
  1. +1 −0 .gitignore
  2. +126 −0 docs/test.md
  3. +2 −0 features/build.feature
  4. +94 −3 features/step_definitions/build.js
  5. +3 −4 features/support/{world.js → build.js}
  6. +189 −0 fixtures/grunt.js
  7. +2 −1 package.json
View
@@ -1,2 +1,3 @@
node_modules
test/fixtures/h5bp
+.test
View
@@ -0,0 +1,126 @@
+
+Testsing out JavaScript task has never been easier thanks to great,
+greta project like [Travis](http://travis-ci.org/) or [cucumberjs](https://github.com/cucumber/cucumber-js)
+
+Here we'll go through cucumberjs usage in a basic getting started guide.
+
+**add the depedency to the project**
+
+unless you'd like on a globally installed version of cucumber.
+
+ npm i cucumber -S
+
+**Add a new feature**
+
+Features are written with the [Gherkin syntax](https://github.com/cucumber/cucumber/wiki/Gherkin)
+
+ # features/build.feature
+ Feature: Build feature
+ As a user of h5bp's node build script
+ I want to write my tests as cucumber features
+ So that I can concentrate on building awesome applications
+
+ Scenario: Launching build
+ When I launch a local http server
+ Given I am on the "index.html" page
+ Then I should have a "css/style.css" css file
+
+Features in cucumber go along some support files. Support files let you
+setup the the environment in which steps will be run, and define step
+definitions.
+
+
+ // features/support/world.js
+ var zombie = require('zombie');
+ var World = function World(callback) {
+ this.browser = new zombie.Browser(); // this.browser will be available in step definitions
+
+ this.visit = function(url, callback) {
+ this.browser.visit(url, callback);
+ };
+
+ callback(); // tell Cucumber we're finished and to use 'this' as the world instance
+ };
+ exports.World = World;
+
+
+
+If you'd like further documentation on cucumberjs, you should definitely
+checkout [the project's
+readme](https://github.com/cucumber/cucumber-js#readme)
+
+## Writing a new feature
+
+*Replace `<featurename>` by the actual feature beeing tested*
+
+#### 1. feature
+
+Create a new file in `features/` named `<featurename>.feature`.
+
+Add the following:
+
+ # features/<featurename>.feature
+ Feature: <featurename> feature
+ As a user of h5bp's node build script
+ I want to write my tests as cucumber features
+ So that I can concentrate on building awesome applications
+
+ Scenario: Launching task "dom"
+ When I run "dom" with following configuration "fixtures/grunt.js"
+ And I launch a local http server
+ Given I am on the "index.html" page
+ Then I should have a "css/style.css" css file
+
+Then, try running `npm test`.
+
+Unless there is previous test errors, you should something like:
+
+ U---
+
+ 1 scenario (1 undefined)
+ 4 steps (1 undefined, 3 skipped)
+
+ You can implement step definitions for undefined steps with these snippets:
+
+ this.Then(/^I should see a "([^"]*)" css file$/, function(arg1, callback) {
+ // express the regexp above with the code you wish you had
+ callback.pending();
+ });
+
+### 2. Step definition
+
+Creates a new step definition file in `features/step_definitions` named
+`<featurename>.js`
+
+And append the following content to this new file:
+
+ var fs = require('fs'),
+ assert = require('assert'),
+ http = require('http'),
+ mime = require('mime'),
+ join = require('path').join;
+
+ module.exports = wrapper;
+
+ function wrapper() {
+ this.World = require("../support/build.js").World;
+
+ // from previous console output, copy-paste missing steps to this
+ // step definition file
+
+ this.Then(/^I should see a "([^"]*)" css file$/, function(arg1, callback) {
+ // express the regexp above with the code you wish you had
+ callback.pending();
+ });
+ }
+
+## Built-in step definition
+
+> todo
+
+* serve: When/And I launch a local http server$
+Starts a basic http server serving static files under `.test/output/
+
+* run: When/And I run ":task" with following configuration ":gruntfile"$
+Spawn grunt with the specified `:gruntfile`, to run the given `:task`.
+
View
@@ -5,5 +5,7 @@ Feature: Build feature
So that I can concentrate on building awesome applications
Scenario: Launching build
+ When I launch a local http server
+ And I run "dom" with following configuration "fixtures/grunt.js"
Given I am on the "index.html" page
Then I should have a "css/style.css" css file
@@ -1,15 +1,106 @@
+var fs = require('fs'),
+ assert = require('assert'),
+ http = require('http'),
+ mime = require('mime'),
+ path = require('path'),
+ join = path.join,
+ mkdirp = require('mkdirp'),
+ spawn = require('child_process').spawn;
module.exports = wrapper;
+// base url
+var url = function(path) { return 'http://localhost:3000/' + path; };
+
+// base test dir
+var dir = join(__dirname, '../output');
+
function wrapper() {
- this.Given(/^I am on the "([^"]*)" page$/, function(arg1, callback) {
- // express the regexp above with the code you wish you had
- callback.pending();
+ this.World = require("../support/build.js").World;
+
+ this.When(/^I launch a local http server$/, server.bind(this.Workd));
+
+ this.When(/^I run "([^"]*)" with following configuration "([^"]*)"$/, run.bind(this.World));
+
+ this.Given(/^I am on the "([^"]*)" page$/, function(page, callback) {
+ console.log(' » Visiting ', url(page));
+ this.visit(url(page), function(e, o, status, args) {
+ if(e) callback.fail(e);
+ assert.equal(status, 200);
+ callback();
+ });
});
this.Then(/^I should have a "([^"]*)" css file$/, function(arg1, callback) {
// express the regexp above with the code you wish you had
callback.pending();
});
}
+
+
+function run(task, file, cb) {
+ // copy grunt fixture file to `.test`, chdir to `.test`,
+ // run the build, check the output
+ var out = join('.test/grunt.js'),
+ base = join(__dirname, '../../.test'),
+ change = process.cwd() !== base;
+
+ mkdirp(path.dirname(out), function() {
+ console.log('copy ', file, 'to', out);
+ var rs = fs.createReadStream(file),
+ ws = fs.createWriteStream(out);
+ rs.on('error', cb.fail.bind(cb));
+ rs.on('end', function(e) {
+ if(e) return cb.fail(e);
+ change && process.chdir(base);
+ // launch grunt task
+ var grunt = gruntify([task, '-t', '../tasks', '-b', base], function(e) {
+ if(e) return cb.fail(e);
+ cb();
+ });
+ grunt.stdout.pipe(process.stdout);
+ grunt.stderr.pipe(process.stdout);
+ grunt.on('exit', function(code) {
+ console.log('Grunt exit: ', code);
+ assert.ok(!code);
+ cb();
+ });
+ });
+
+ rs.pipe(ws);
+ });
+}
+
+function server(cb) {
+ console.log('Starting http server on localhost:', 3000);
+ var srv = http.createServer(function(req, res, next) {
+ var url = req.url,
+ filepath = join(dir, url);
+
+ // index.html support
+ filepath = filepath.slice(-1) === '/' ? join(filepath, 'index.html') : filepath;
+ console.log(' » ', url);
+
+ // response
+ var rs = fs.createReadStream(filepath);
+ res.setHeader('Content-Type', mime.lookup(filepath));
+ rs.on('error', function(e) {
+ res.setHeader('Content-Type', 'text/plain');
+ res.statusCode = 404;
+ res.end('Cannot find ' + url);
+ }).pipe(res);
+ }).listen(3000, cb);
+}
+
+// spawn grunt
+function gruntify(args, takeOver, cb) {
+ if(!cb) cb = takeOver, takeOver = false;
+ console.log('Spawning grunt with following arguments');
+ console.log();
+ console.log(' grunt ' + args.join(' '));
+ console.log();
+ var o = {};
+ if(takeOver) o.customFds = [0, 1, 2], console.warn('Taking over');
+ return spawn('grunt', args, o);
+}
@@ -2,18 +2,17 @@
var zombie = require('zombie');
-exports.World = WorldConstructor;
+exports.World = Build;
+
+function Build(callback) {
-function WorldConstructor(callback) {
// this.browser will be available in step definitions
this.browser = new zombie.Browser();
this.visit = function(url, callback) {
this.browser.visit(url, callback);
};
- console.log('call');
-
callback();
}
Oops, something went wrong.

0 comments on commit 9011491

Please sign in to comment.