Permalink
Browse files

Finish Cucumber.js example (fixes #8)

The example test suite is now in `examples/cucumber`. Run it like so:
    make cucumber.js
  • Loading branch information...
1 parent ea2ef55 commit 41fd5b961947222b549a80b8e785bafd946238a2 @lawnsea lawnsea committed Aug 30, 2012
View
16 Makefile
@@ -7,11 +7,13 @@ NODE_MODULES = $(PWD)/node_modules
# XXX: below may be a bit too clever
PID_FILE := $(PWD)/$(shell echo ".test-server-pid.$$RANDOM")
-test:
+fixture-server:
@cd tests/fixtures ; \
$(NODE_MODULES)/.bin/http-server -s -p $(TEST_PORT) & \
echo "$$!" > $(PID_FILE) ; \
cd $(PWD)
+
+test: fixture-server
@$(NODE_MODULES)/.bin/mocha tests/test --recursive \
--globals define \
--timeout $(TEST_TIMEOUT) --slow $(TEST_SLOW) \
@@ -20,4 +22,14 @@ test:
kill -9 `cat $(PID_FILE)` ; rm $(PID_FILE) ; \
exit $$STATUS
-.PHONY: test
+cucumber.js: fixture-server
+ @TEST_PORT=$(TEST_PORT) $(NODE_MODULES)/.bin/cucumber.js \
+ -f pretty \
+ examples/cucumber/features \
+ --require examples/cucumber/features/steps \
+ --require examples/cucumber/features/support ; \
+ STATUS=$$? ; \
+ kill -9 `cat $(PID_FILE)` ; rm $(PID_FILE) ; \
+ exit $$STATUS
+
+.PHONY: test fixture-server cucumber.js
View
14 README.md
@@ -62,15 +62,21 @@ var spooky = new Spooky({
});
```
-A minimal example can be found in `examples`.
+A minimal example can be found in the repo under `examples`. Run it like this:
``` shell
$ node examples/hello.js
```
-See `tests/util/hooks.js` for an example of how to use SpookyJS with [Mocha](http://visionmedia.github.com/mocha).
+A small example [Cucumber.js](https://github.com/cucumber/cucumber-js/) test suite can be found in the repo under `examples/cucumber`. To run the suite:
-See `tests/features/` for an example using SpookyJS with Cucumber.js.
+``` shell
+$ make cucumber.js
+```
+
+You may change the port that the fixture server runs on by setting the `TEST_PORT` make parameter.
+
+See the tests for an example of how to use SpookyJS with [Mocha](http://visionmedia.github.com/mocha).
## Development
@@ -82,7 +88,7 @@ SpookyJS includes a suite of unit tests, driven by [Mocha](http://visionmedia.gi
$ make test
```
-The following parameters are supported (defaults are in parentheses):
+The following make parameters are supported (defaults are in parentheses):
* `TEST_REPORTER` the [Mocha reporter](http://visionmedia.github.com/mocha/#reporters) to use (dot)
* `TEST_PORT` the port to run the fixture web server on (8080)
View
20 examples/cucumber/features/navigation.feature
@@ -0,0 +1,20 @@
+Feature: Navigation
+ As a SpookyJS user
+ I would like to use the navigation API
+
+ Scenario: Back
+ Given I go to "/1.html"
+ And I go to "/2.html"
+ And I go to "/3.html"
+ When I go back
+ Then I should be on "2\.html"
+ And run
+
+ Scenario: Forward
+ Given I go to "/1.html"
+ And I go to "/2.html"
+ And I go to "/3.html"
+ And I go back
+ When I go forward
+ Then I should be on "3\.html"
+ And run
View
38 examples/cucumber/features/steps/navigation.js
@@ -0,0 +1,38 @@
+module.exports = function () {
+ this.World = require('../support/world.js').World;
+
+ function go(url, callback) {
+ this.spooky.thenOpen(this.baseUrl + url);
+ callback();
+ }
+
+ function goBack(callback) {
+ this.spooky.back();
+ callback();
+ }
+
+ function goForward(callback) {
+ this.spooky.forward();
+ callback();
+ }
+
+ this.Given('I go to "$url"', go);
+ this.When('I go to "$url"', go);
+
+ this.Given('I go back', goBack);
+ this.When('I go back', goBack);
+
+ this.Given('I go forward', goForward);
+ this.When('I go forward', goForward);
+
+ this.Then('I should be on "$url"', function shouldBeOn(url, callback) {
+ this.spooky.then([{
+ url: url
+ }, function () {
+ this.echo(this.getCurrentUrl());
+ this.test.assertUrlMatch(new RegExp(url));
+ }]);
+ callback();
+ });
+};
+
View
23 examples/cucumber/features/steps/run.js
@@ -0,0 +1,23 @@
+module.exports = function () {
+ this.World = require('../support/world.js').World;
+
+ this.Then('run', function (callback) {
+ var world = this;
+
+ this.spooky.then(function () {
+ this.emit('tests.complete', this.test.testResults);
+ });
+
+ this.spooky.once('tests.complete', (function (results) {
+ if (results.failed) {
+ callback.fail(results.failures.map(function (failure) {
+ return 'Failed: ' + failure.message;
+ }).join('\n'));
+ } else {
+ callback();
+ }
+ }).bind(this));
+
+ this.spooky.run();
+ });
+};
View
5 tests/features/support/before.js → examples/cucumber/features/support/hooks.js
@@ -3,4 +3,9 @@ module.exports = function () {
this.spooky.start();
callback();
});
+
+ this.After(function (callback) {
+ this.spooky.destroy();
+ callback();
+ });
};
View
82 examples/cucumber/features/support/world.js
@@ -0,0 +1,82 @@
+var util = require('util');
+var Spooky = require('../../../../lib/spooky');
+
+var World = function World(callback) {
+ var spooky;
+ var world = this;
+
+ this.baseUrl = 'http://localhost:' + process.env.TEST_PORT;
+
+ try {
+ spooky = world.spooky = new Spooky({
+ casper: {
+ verbose: true,
+ logLevel: 'debug'
+ },
+ child: {
+ port: 8081,
+ spooky_lib: './node_modules',
+ script: './lib/bootstrap.js'
+ }
+ }, onCreated);
+ } catch (e) {
+ console.dir(e)
+ console.trace('Spooky.listen failed');
+ }
+
+ //spooky.debug = true;
+
+ // track errors
+ spooky.errors = [];
+ spooky.on('error', function (error) {
+ error = error.data ? error.data : error;
+ spooky.errors.push(error);
+ if (spooky.debug) {
+ console.error('spooky error', util.inspect(error));
+ }
+ });
+
+ spooky.console = [];
+ spooky.on('console', function (line) {
+ spooky.console.push(line);
+ if (spooky.debug) {
+ console.log(line);
+ }
+ });
+
+ spooky.on('log', function (entry) {
+ if (!spooky.debug) { return; }
+ var message = entry.message;
+ var event = (message.event || '').toLowerCase();
+
+ if (event === 'request') {
+ console.log('%s: %s %s',
+ spooky.options.port, message.method, message.request.url);
+ console.log(' Headers: %s',
+ util.inspect(message.request.headers));
+ console.log(' Payload: %s',
+ util.inspect(JSON.parse(message.request.post)));
+ } else if (event === 'response') {
+ console.log('%s: %s %s',
+ spooky.options.port, message.code,
+ util.inspect(JSON.parse(message.body)));
+ } else {
+ console.log(spooky.options.port + ':');
+ console.dir(entry);
+ }
+ });
+
+ function onCreated(err, error, response) {
+ if (err) {
+ throw err;
+ } else if (error) {
+ console.dir(error);
+ throw new Error('Failed to initialize context.spooky: ' +
+ error.code + ' - ' + error.message);
+ }
+
+ callback(world);
+ }
+};
+
+module.exports.World = World;
View
38 examples/cucumber/steps/navigation.js
@@ -0,0 +1,38 @@
+module.exports = function () {
+ var expect = require('expect.js');
+ this.World = require('../support/world.js').World;
+
+ this.Given('I go to "$path"', function (path, callback) {
+ this.spooky.thenOpen(this.testUrl + path);
+ callback();
+ });
+
+ this.Given('I go back', function (callback) {
+ this.spooky.back();
+ callback();
+ });
+
+ this.Given('I go forward', function (callback) {
+ this.spooky.forward();
+ callback();
+ });
+
+ this.When('I go back', function (callback) {
+ this.spooky.back();
+ callback();
+ });
+
+ this.When('I go forward', function (callback) {
+ this.spooky.forward();
+ callback();
+ });
+
+ this.Then('I should be on "$path"', function (path, callback) {
+ this.spooky.then([{
+ url: this.testUrl + path
+ }, function () {
+ this.test.assert(this.getCurrentUrl() === url);
+ }]);
+ callback();
+ });
+};
View
15 tests/features/errors.feature
@@ -1,15 +0,0 @@
-Feature: Error handling and propogation
- As a user of spooky
- I want to be notified when an error occurs locally or remotely
- So that I can fix it
-
- # Setup phase
-
- Scenario: Invalid argument to remote method
- When I call "then" with "not a function, bro"
- Then Spooky should raise an error
-
- Scenario: Error during remote method execution
- When I call "then" with "function () { throw new Error('OHNOES'); }"
- And I run spooky
- Then Spooky should raise an error
View
9 tests/features/steps/call.js
@@ -1,9 +0,0 @@
-module.exports = function () {
- this.World = require('../support/world.js').World;
-
- this.When('I call "$method" with "$args"', function (method, args, callback) {
- args = args.split(',');
- this.spooky[method].apply(this.spooky, args);
- callback();
- });
-};
View
24 tests/features/steps/errors.js
@@ -1,24 +0,0 @@
-module.exports = function () {
- var expect = require('expect.js');
- this.World = require('../support/world.js').World;
-
- this.When('I pass a string to a method expecting a function',
- function (callback) {
- this.spooky.then('not a function');
- callback();
- });
-
- this.Then('Spooky should raise an error', function (callback) {
- var world = this;
-
- if (this.errors.length < 1) {
- this.spooky.on('error', function (e) {
- expect(world.errors.length).to.be(1);
- callback();
- });
- } else {
- expect(this.errors.length).to.be(1);
- callback();
- }
- });
-};
View
8 tests/features/steps/run.js
@@ -1,8 +0,0 @@
-module.exports = function () {
- this.World = require('../support/world.js').World;
-
- this.When('I run spooky', function (callback) {
- this.spooky.run();
- callback();
- });
-};
View
101 tests/features/support/world.js
@@ -1,101 +0,0 @@
-var util = require('util');
-var casper;
-
-var World = function World(callback) {
- var Spooky = this.Spooky = require('../../../lib/spooky');
- var world = this;
- var spooky;
-
- this.testUrl = 'http://spookytests:8888';
-
-
- this.errors = [];
- if (!casper) {
- try {
- casper = Spooky.listen({
- port: 8081,
- script: 'lib/bootstrap.js',
- spooky_lib: './node_modules',
- }, onReady);
- } catch (e) {
- console.dir(e)
- console.trace('Spooky.listen failed');
- }
-
- //casper.debug = true;
-
- // track errors
- casper.errors = [];
- casper.on('error', function (error) {
- casper.errors.push(error);
- if (casper.debug) {
- console.error('casper error', util.inspect(error));
- }
- });
-
- casper.console = [];
- casper.on('console', function (line) {
- casper.console.push(line);
- if (casper.debug) {
- console.log(line);
- }
- });
-
- casper.on('log', function (entry) {
- if (!casper.debug) { return; }
- var message = entry.message;
- var event = (message.event || '').toLowerCase();
-
- if (event === 'request') {
- console.log('%s: %s %s',
- casper.options.port, message.method, message.request.url);
- console.log(' Headers: %s',
- util.inspect(message.request.headers));
- console.log(' Payload: %s',
- util.inspect(JSON.parse(message.request.post)));
- } else if (event === 'response') {
- console.log('%s: %s %s',
- casper.options.port, message.code,
- util.inspect(JSON.parse(message.body)));
- } else {
- console.log(casper.options.port + ':');
- console.dir(entry);
- }
- });
- } else {
- onReady();
- }
-
- function onReady(err) {
- if (err) {
- throw err;
- }
- world.spooky = spooky = Spooky.create({
- port: 8081,
- casper: !casper.debug ? {} : {
- verbose: true,
- logLevel: 'debug'
- }
- }, onCreated);
- }
-
- function onCreated(err, error, response) {
- if (err) {
- throw err;
- } else if (error) {
- console.dir(error);
- throw new Error('Failed to initialize spooky: ' +
- error.code + ' - ' + error.message);
- }
-
- world.spooky.on('error', function (error) {
- world.errors.push(error);
- if (casper.debug) {
- console.error('spooky error', util.inspect(error));
- }
- });
- callback(world);
- }
-};
-
-module.exports.World = World;

0 comments on commit 41fd5b9

Please sign in to comment.