I am considering the following breaking change. Please let me know what you think. TL;DR version:
promiseFor(2 + 2).should.eventually.be.ok.then(done, done)
would no longer work, to be replaced by
promiseFor(2 + 2).should.eventually.be.ok.callback(done)
== The problem ==
When building 1.0, I was concerned with supporting the `.then(done, done)` style for frameworks like Mocha, wherein you are given a single `done` callback to signal the end of an async test. If you pass it nothing, it assumes the test passed; otherwise, the test fails. The idea is that `done` is somewhat like a Node.js callback.
Thus, when running the following code:
promiseFor(2 + 2).should.eventually.be.ok.then(done, done);
while `be` returns an assertion-promise [1] for 42, `ok` actually returns a promise for `undefined`, since otherwise `done` would be called with 42 and assume an error occurred.
This forces an unfortunate situation. The most visible consequence is that you cannot chain assertions. That is,
promiseFor(2 + 2).should.eventually.be.ok.and.equal(4).then(done, done);
does not work, since `ok` ends the chaining and must return a promise fulfilled with `undefined`, so by the time `equal` gets called, it doesn’t have anything to test `4` against.
The other problem is that the way in which this is coded [2] is rather fragile, as I need to manually categorize asserters into "end of chain" or "still chaining." Currently this is done by saying that all function asserters (e.g. `equal`, `include`, `keys`) are "end of chain," as well as a small whitelist of property-asserters (viz. `arguments`, `empty`, `exist`, `false`, `ok`, and `true`). All others are assumed to be "still chaining." This is not only future-unfriendly, it is also plugin-unfriendly.
[1]: that is, a promise that has all of the asserters, like `ok`, `equal`, etc., tacked onto it
[2]:
https://github.com/domenic/chai-as-promised/blob/71e23309cae82b367c86a2eb29725122ba5323fc/lib/chai-as-promised.js#L24-28
== The proposed solution ==
Chai as Promised would no longer take pains to fulfill assertion-promises with `undefined`. That is,
promiseFor(2 + 2).should.eventually.be.ok.then(done, done);
would now throw up, since `4` would be passed to `done`. The naïve solution is then
promiseFor(2 + 2).should.eventually.be.ok.then(function () { done(); }, done);
But of course I would then just augment assertion-promises with a new capstone method to do this for you, e.g.
promiseFor(2 + 2).should.eventually.be.ok.end(done) // kind of conflicts with Q
promiseFor(2 + 2).should.eventually.be.ok.callback(done) // probably my favorite?
promiseFor(2 + 2).should.eventually.be.ok.cb(done)
promiseFor(2 + 2).should.eventually.be.ok.makeSureToInform(done) // mostly kidding
promiseFor(2 + 2).should.eventually.be.ok.whyDoesntHeJustAcceptMochaPullRequestNumber329(done) // definitely kidding [3]
What do you think?
[3]:
https://github.com/visionmedia/mocha/pull/329