Skip to content

Commit

Permalink
Merge pull request kriskowal#599
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal committed Nov 10, 2014
2 parents 077efa7 + d86a65b commit 21a64d3
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ q.min.js
.coverage_data/
.coverage_debug/
cover_html/

# IntelliJ IDEA project files
.idea
*.iml
24 changes: 24 additions & 0 deletions q.js
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,30 @@ Promise.prototype.then = function (fulfilled, rejected, progressed) {
return deferred.promise;
};

Q.tap = function (promise, callback) {
return Q(promise).tap(callback);
};

/**
* Works almost like "finally", but not called for rejections.
* Original resolution value is passed through callback unaffected.
* Callback may return a promise that will be awaited for.
* @param {Function} callback
* @returns {Q.Promise}
* @example
* doSomething()
* .then(...)
* .tap(console.log)
* .then(...);
*/
Promise.prototype.tap = function (callback) {
callback = Q(callback);

return this.then(function (value) {
return callback.fcall(value).thenResolve(value);
});
};

/**
* Registers an observer on a promise.
*
Expand Down
94 changes: 94 additions & 0 deletions spec/q-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,100 @@ describe("fin", function () {

});

// Almost like "fin"
describe("tap", function () {
var exception1 = new Error("boo!");

describe("when the promise is fulfilled", function () {
it("should call the callback", function () {
var called = false;
return Q("foo")
.tap(function () {
called = true;
})
.then(function () {
expect(called).toBe(true);
});
});

it("should fulfill with the original value", function () {
return Q("foo")
.tap(function () {
return "bar";
})
.then(function (result) {
expect(result).toBe("foo");
});
});

describe("when the callback returns a promise", function () {
describe("that is fulfilled", function () {
it("should fulfill with the original reason after that promise resolves", function () {
var promise = Q.delay(250);

return Q("foo")
.tap(function () {
return promise;
})
.then(function (result) {
expect(Q.isPending(promise)).toBe(false);
expect(result).toBe("foo");
});
});
});

describe("that is rejected", function () {
it("should reject with this new rejection reason", function () {
return Q("foo")
.tap(function () {
return Q.reject(exception1);
})
.then(function () {
expect(false).toBe(true);
},
function (exception) {
expect(exception).toBe(exception1);
});
});
});

});

describe("when the callback throws an exception", function () {
it("should reject with this new exception", function () {
return Q("foo")
.tap(function () {
throw exception1;
})
.then(function () {
expect(false).toBe(true);
},
function (exception) {
expect(exception).toBe(exception1);
});
});
});

});

describe("when the promise is rejected", function () {
it("should not call the callback", function () {
var called = false;

return Q.reject(exception1)
.tap(function () {
called = true;
})
.then(function () {
expect(called).toBe(false);
}, function () {
expect(called).toBe(false);
});
});
});
});


describe("done", function () {
describe("when the promise is fulfilled", function () {
describe("and the callback does not throw", function () {
Expand Down

0 comments on commit 21a64d3

Please sign in to comment.