Permalink
Browse files

Adds an optional BDD testing idiom.

The 'whiskey' package now exports a 'bdd' symbol which can be required to enable BDD-style tests:

var bdd = require('whiskey').bdd.init(exports);

This wraps the exports object of the test module and translates the BDD tests into whiskey tests
so they run normally.

The one adaptation of the BDD idiom for whiskey is that test suite and spec functions being passed
to describe() and it() need to accept a function parameter, respectively it() and expect() - this
is to support the whiskey behavior of injecting (test, assert) into each test individually.
  • Loading branch information...
1 parent 66bb309 commit 69c474a01816967261de2190440e913112f6ea27 @robert-chiniquy committed May 29, 2012
Showing with 238 additions and 0 deletions.
  1. +3 −0 CHANGES.md
  2. +12 −0 README.md
  3. +39 −0 example/test-bdd-failures.js
  4. +69 −0 example/test-bdd.js
  5. +1 −0 index.js
  6. +97 −0 lib/bdd.js
  7. +17 −0 test/run.sh
View
@@ -1,6 +1,9 @@
Changes
=======
+* Add an optional, minimal BDD idiom implementation.
+ [Robert Chiniquy]
+
* Send the SIGKILL signal instead of SIGTERM when killing child processes managed by the process runner.
[Robert Chiniquy]
View
@@ -123,6 +123,18 @@ exports['test_two_equals_one'] = function(test, assert) {
}
```
+A simple example using the optional BDD module:
+``` javascript
+var bdd = require('whiskey').bdd.init(exports);
+var describe = bdd.describe;
+
+describe('the bdd module', function(it) {
+ it('supports it(), expect(), and toEqual()', function(expect) {
+ expect(true).toEqual(true);
+ });
+});
+```
+
For more examples please check the `example/` folder.
# Build status
@@ -0,0 +1,39 @@
+/*
+ * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * Cloudkick licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var bdd = require('../lib/bdd').init(exports);
+var describe = bdd.describe;
+
+describe('the bdd expect()', function(it) {
+
+ it('correctly fails toBeNull()', function(expect) {
+ expect("not null").toBeNull();
+ });
+
+ it('correctly fails toBeDefined()', function(expect) {
+ expect(undefined).toBeDefined();
+ });
+
+ it('correctly fails toBeUndefined()', function(expect) {
+ expect(true).toBeUndefined();
+ });
+
+ it('correctly fails toMatch()', function(expect) {
+ expect('fish').toMatch(/not a fish/);
+ });
+
+});
View
@@ -0,0 +1,69 @@
+/*
+ * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * Cloudkick licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var bdd = require('../lib/bdd').init(exports);
+var describe = bdd.describe;
+var beforeEach = bdd.beforeEach;
+
+var wasBeforeEachCalled = false;
+
+beforeEach(function() {
+ wasBeforeEachCalled = true;
+});
+
+describe('the bdd module', function(it) {
+
+ it('supports it(), expect(), and toEqual()', function(expect) {
+ expect(true).toEqual(true);
+ });
+
+ it('supports beforeEach()', function(expect) {
+ expect(wasBeforeEachCalled).toEqual(true);
+ });
+
+ it('supports async tests', function(expect, callback) {
+ var called = false;
+ setTimeout(function() {
+ called = true;
+ }, 1);
+ setTimeout(function() {
+ expect(called).toEqual(true);
+ callback();
+ }, 3);
+ });
+
+});
+
+describe('the bdd expect()', function(it) {
+
+ it('handles toBeNull()', function(expect) {
+ expect(null).toBeNull();
+ });
+
+ it('handles toBeDefined()', function(expect) {
+ expect(true).toBeDefined();
+ });
+
+ it('handles toBeUndefined()', function(expect) {
+ expect(undefined).toBeUndefined();
+ });
+
+ it('handles toMatch()', function(expect) {
+ expect('fish').toMatch(/is/);
+ });
+
+});
View
@@ -15,5 +15,6 @@
* limitations under the License.
*/
+exports.bdd = require('./lib/bdd.js');
exports.run = require('./lib/run.js').run;
exports.installCoverageHandler = require('./lib/coverage').installCoverageHandler;
View
@@ -0,0 +1,97 @@
+/*
+ * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * Cloudkick licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var sprintf = require('sprintf').sprintf;
+
+function Expect(actual) {
+ this._actual = actual;
+}
+
+/**
+ * @param {Object} imports The foreign exports object to add bdd tests to
+ * @returns {Object} bdd A collection of test functions
+ */
+exports.init = function(imports) {
+ var bdd = {
+ '_suiteSetup': function() {}
+ };
+
+ /** @param {Function} setup function to call before each suite */
+ bdd.beforeEach = function(setup) {
+ bdd._suiteSetup = setup;
+ };
+
+ /** @description creates a test suite
+ * @param {string} title
+ * @param {Function} suite
+ */
+ bdd.describe = function(title, suite) {
+
+ /** @description it() is the equivalent of a exports['test blah'] in the whiskey idiom.
+ * This function, when called, adds a whiskey test to the imports object.
+ * @param {string} name
+ * @param {Function} spec(expect, callback)
+ */
+ function it(name, spec) {
+ var whiskeyName = sprintf("test %s %s", title, name);
+
+ function expect(actual) {
+ return new Expect(actual);
+ }
+
+ /** @description Re-binds the Expect test methods using the newly-injected assert.
+ * @param {object} test the test object injected by whiskey
+ * @param {object} assert the assert object injected by whiskey
+ */
+ imports[whiskeyName] = function(test, assert) {
+
+ // make the whiskey test and assert objects available to bdd tests
+ bdd.test = test;
+ bdd.assert = assert;
+
+ /** @description maps an assert method to a bdd matcher
+ * @param {string} assertion the name of a whiskey assert method
+ * @param {string} bddName the name of the equivalent expect method
+ */
+ function translateMatcher(assertion, bddName) {
+ Expect.prototype[bddName] = function() {
+ assert[assertion].bind(this, this._actual).apply(this, arguments);
+ }
+ }
+
+ // This must be done each time a test is created,
+ // as test and assert are injected in each test function.
+ translateMatcher('equal', 'toEqual');
+ translateMatcher('isNull', 'toBeNull');
+ translateMatcher('isDefined', 'toBeDefined');
+ translateMatcher('isUndefined', 'toBeUndefined');
+ translateMatcher('match', 'toMatch');
+
+ spec(expect, test.finish);
+ if (spec.length === 1) {
+ // if spec isn't expecting test.finish as an async callback, call it directly
+ test.finish();
+ }
+ }
+ }
+
+ bdd._suiteSetup();
+ suite(it);
+ };
+
+ return bdd;
+}
View
@@ -268,6 +268,23 @@ if [ $? -ne 0 ]; then
exit 1
fi
+"${CWD}/bin/whiskey" --timeout 1000 \
+--tests "${CWD}/example/test-bdd.js"
+
+if [ $? -ne 0 ]; then
+ echo "BDD test didn't exit with zero exit code."
+ exit 1
+fi
+
+"${CWD}/bin/whiskey" --timeout 1000 \
+--tests "${CWD}/example/test-bdd-failures.js"
+
+if [ $? -ne 4 ]; then
+ echo "BDD failure test didn't fail as expected."
+ exit 1
+fi
+
+
echo ""
echo "* * * Whiskey test suite PASSED. * * *"
exit 0

0 comments on commit 69c474a

Please sign in to comment.