Add support for promise-returning tests #202

Closed
wants to merge 1 commit into
from
@@ -229,6 +229,106 @@ describe("jasmine spec running", function () {
expect(yet_another_spec.results().getItems()[0].passed()).toEqual(false);
});
+ it("should run asynchronus tests that return fulfilling promises", function () {
+ var done, spec;
+ runs(function () {
+ env.describe('promise test', function () {
+ spec = env.it('should resolve', function () {
+ return {
+ then: function (resolve, reject) {
+ setTimeout(function() {
+ resolve();
+ done = true;
+ }, 0);
+ }
+ }
+ });
+ });
+ env.execute();
+ });
+ waitsFor(function () {
+ return done;
+ });
+ runs(function () {
+ expect(spec.resolved).toBe(true);
+ expect(spec.results().getItems().length).toEqual(0);
+ });
+ });
+
+ it("should run asynchronus tests that return rejecting promises", function () {
+ var done, spec;
+ runs(function () {
+ env.describe('promise test', function () {
+ spec = env.it('should reject', function () {
+ return {
+ then: function (resolve, reject) {
+ setTimeout(function() {
+ reject(new Error("I should not be."));
+ done = true;
+ }, 0);
+ }
+ }
+ });
+ });
+ env.execute();
+ });
+ waitsFor(function () {
+ return done;
+ });
+ runs(function () {
+ expect(spec.rejected).toBe(true);
+ expect(spec.results().getItems().length).toEqual(1);
+ expect(spec.results().getItems()[0].passed()).toEqual(false);
+ expect(spec.results().getItems()[0].message).toEqual('Error: I should not be.');
+ });
+ });
+
+ it("should run asynchronus tests that return fulfilling promises with unexpected values", function () {
+ var done, spec;
+ runs(function () {
+ env.describe('promise test', function () {
+ spec = env.it('should resolve', function () {
+ return {
+ then: function (resolve, reject) {
+ setTimeout(function() {
+ resolve('I should not be.');
+ done = true;
+ }, 0);
+ }
+ }
+ });
+ });
+ spec.execute();
+ });
+ waitsFor(function () {
+ return done;
+ });
+ runs(function () {
+ expect(spec.results().getItems().length).toEqual(1);
+ expect(spec.results().getItems()[0].passed()).toEqual(false);
+ expect(spec.results().getItems()[0].message).toEqual('Error: Promise fulfilled with unexpected value: I should not be.');
+ });
+ });
+
+ it("should run asynchronus tests that return promises that throw errors", function () {
+ var done, spec;
+ runs(function () {
+ env.describe('promise test', function () {
+ spec = env.it('should resolve', function () {
+ return {
+ then: function (resolve, reject) {
+ throw new Error("I should not be.");
+ }
+ }
+ });
+ });
+ spec.execute();
+ expect(spec.results().getItems().length).toEqual(1);
+ expect(spec.results().getItems()[0].passed()).toEqual(false);
+ expect(spec.results().getItems()[0].message).toEqual("Error: I should not be.");
+ });
+ });
+
it("testAsyncSpecsWithMockSuite", function () {
var bar = 0;
var another_spec;
View
@@ -1,6 +1,10 @@
/**
* Blocks are functions with executable code that make up a spec.
*
+ * A block function may return a "thenable" promise, in which case the
+ * test completes when the promise is resolved and fails if the promise
+ * fails or if it succeeds with an unexpected value.
+ *
* @constructor
* @param {jasmine.Env} env
* @param {Function} func
@@ -12,11 +16,49 @@ jasmine.Block = function(env, func, spec) {
this.spec = spec;
};
-jasmine.Block.prototype.execute = function(onComplete) {
+jasmine.Block.prototype.execute = function(onComplete) {
+ var spec = this.spec;
+ var result;
try {
- this.func.apply(this.spec);
- } catch (e) {
- this.spec.fail(e);
+ result = this.func.apply(spec);
+ } catch (error) {
+ spec.fail(error);
+ }
+ if (typeof result === 'undefined') {
+ // blocks that do not return promises complete immediately
+ onComplete();
+ } else if (typeof result !== 'object' || typeof result.then !== 'function') {
+ // if a block returns anything, it must return a promise as defined by
+ // CommonJS/A
+ spec.fail(new Error('`it` block returns non-promise: ' + result));
+ onComplete();
+ } else {
+ // Throwing an error from an attempt to use a returned promise fails
+ // the block
+ try {
+ result.then(function (value) {
+ // fulfillment
+ spec.resolved = true; // for verification;
+ // test block promises must fulfill to undefined. it is typical
+ // to pipe the final promise of a test to make note of an expected
+ // value and return no value
+ if (value !== undefined) {
+ spec.fail(new Error('Promise fulfilled with unexpected value: ' + value));
+ }
+ onComplete();
+ }, function (error) {
+ // rejection
+ spec.rejected = true; // for verification
+ if (!error || !('stack' in error)) {
+ spec.fail(new Error(error));
+ }
+ spec.fail(error);
+ onComplete();
+ });
+ } catch (error) {
+ spec.fail(error);
+ onComplete();
+ }
}
- onComplete();
};
+