From c291a07989ad85777ee33e08cced6d097e5c1ffa Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 15:22:53 +0200 Subject: [PATCH 01/28] add `promise` method --- must.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/must.js b/must.js index b61ae37..ab3494e 100644 --- a/must.js +++ b/must.js @@ -1183,6 +1183,13 @@ defineGetter(Must.prototype, "reject", function() { return Rejectable(this) }) +defineGetter(Must.prototype, "promise", function() { + this.assert( + typeof this.actual.then === "function" && typeof this.actual.catch === "function", + "be a promise (i.e., have a \'then\' and a \'catch\' function)" + ) +}) + /** * Assert a string starts with the given string. * From f7bcc4e5a5f6245fa821734bc437686df3dea1fe Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 15:23:31 +0200 Subject: [PATCH 02/28] add `promise` documentation --- must.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/must.js b/must.js index ab3494e..ff023e7 100644 --- a/must.js +++ b/must.js @@ -1183,6 +1183,34 @@ defineGetter(Must.prototype, "reject", function() { return Rejectable(this) }) +/** + * Assert that an object is a promise. + * + * The determination uses duck typing, i.e., it checks whether the object has + * a `then` and a `catch` method. + * + * There are several implementations of promises in the wild, and a promise you + * receive from a library might not be an `instanceof` _your_ `Promise` type, + * although they can work together. + * + * ```javascript + * promise.must.be.a(Promise) + * ``` + * + * might fail, while + * + * ```javascript + * promise.must.be.a.promise + * ``` + * + * might be upheld. + * + * @example + * Promise.resolve(42).must.be.a.promise() + * Promise.reject(42).must.be.a.promise() + * + * @method promise + */ defineGetter(Must.prototype, "promise", function() { this.assert( typeof this.actual.then === "function" && typeof this.actual.catch === "function", From a64f8635e6ff20c13254c192793dda27c979ed90 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 17:25:16 +0200 Subject: [PATCH 03/28] add unit test for `promise` - ok for failures, but fails for things that should pass - added an actual to error reporting --- must.js | 5 +-- test/must/promise_test.js | 72 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 test/must/promise_test.js diff --git a/must.js b/must.js index ff023e7..ab4b740 100644 --- a/must.js +++ b/must.js @@ -1213,8 +1213,9 @@ defineGetter(Must.prototype, "reject", function() { */ defineGetter(Must.prototype, "promise", function() { this.assert( - typeof this.actual.then === "function" && typeof this.actual.catch === "function", - "be a promise (i.e., have a \'then\' and a \'catch\' function)" + this.actual && typeof this.actual.then === "function" && typeof this.actual.catch === "function", + "be a promise (i.e., have a \'then\' and a \'catch\' function)", + { actual: this.actual } ) }) diff --git a/test/must/promise_test.js b/test/must/promise_test.js new file mode 100644 index 0000000..9c9a3d1 --- /dev/null +++ b/test/must/promise_test.js @@ -0,0 +1,72 @@ +var Must = require("../..") +var assert = require("./assert") + +describe("Must.prototype.promise", function() { + it("must fail given null", function () { + assert.fail(function () { Must(null).be.promise() }) + }) + + it("must fail given undefined", function () { + assert.fail(function () { Must(undefined).be.promise() }) + }) + + it("must fail given boolean primitive", function () { + assert.fail(function () { Must(true).be.promise() }) + assert.fail(function () { Must(false).be.promise() }) + }) + + it("must fail given number primitive", function () { + assert.fail(function () { Must(42).be.promise() }) + }) + + it("must fail given string primitive", function () { + assert.fail(function () { Must("").be.promise() }) + }) + + it("must fail given array", function () { + assert.fail(function () { Must([]).be.promise() }) + }) + + it("must fail given object", function () { + assert.fail(function () { Must({}).be.promise() }) + }) + + function dummy () {} + + var thenNoCatch = {then: dummy} + var catchNoThen = {catch: dummy} + var catchAndThen = {then: dummy, catch: dummy} + + it("must fail given an object with a then function, but not a catch function", function () { + assert.fail(function () { Must(thenNoCatch).be.promise() }) + }) + + it("must fail given an object with a catch function, but not a then function", function () { + assert.fail(function () { Must(catchNoThen).be.promise() }) + }) + + it("must pass given an object with a catch and a then function", function () { // NOK + assert.pass(function () { Must(catchAndThen).be.promise() }) + }) + + if (Promise) { + it("must pass given a Promise implementation, with a resolved promise", function () { // NOK + assert.pass(function () { Must(Promise.resolve(42)).be.promise() }) + }) + + it("must pass given a Promise implementation, with a rejected promise", function () { // NOK + assert.pass(function () { Must(Promise.resolve(new Error())).be.promise() }) + }) + } + + require("./_assertion_error_test")(function() { Must(catchNoThen).be.promise() }, { + actual: catchNoThen, + message: "{} must be a promise (i.e., have a \'then\' and a \'catch\' function)" + }) + + describe(".not", function() { + it("must invert the assertion", function() { + assert.fail(function() { Must(catchAndThen).not.be.promise() }) + }) + }) +}) From ece3d5cdee9ffd0c3260d19c3ce6e87448184535 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 18:04:02 +0200 Subject: [PATCH 04/28] `promise` is a function, not a property with a getter --- must.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/must.js b/must.js index ab4b740..09b20ff 100644 --- a/must.js +++ b/must.js @@ -1211,13 +1211,13 @@ defineGetter(Must.prototype, "reject", function() { * * @method promise */ -defineGetter(Must.prototype, "promise", function() { +Must.prototype.promise = function() { this.assert( this.actual && typeof this.actual.then === "function" && typeof this.actual.catch === "function", "be a promise (i.e., have a \'then\' and a \'catch\' function)", { actual: this.actual } ) -}) +} /** * Assert a string starts with the given string. From 45d510e0e3b6b4dca5b15ea509ea79699774d756 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 18:06:41 +0200 Subject: [PATCH 05/28] remove NOK warning - promise tests are green --- test/must/promise_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/must/promise_test.js b/test/must/promise_test.js index 9c9a3d1..0e2029f 100644 --- a/test/must/promise_test.js +++ b/test/must/promise_test.js @@ -45,16 +45,16 @@ describe("Must.prototype.promise", function() { assert.fail(function () { Must(catchNoThen).be.promise() }) }) - it("must pass given an object with a catch and a then function", function () { // NOK + it("must pass given an object with a catch and a then function", function () { assert.pass(function () { Must(catchAndThen).be.promise() }) }) if (Promise) { - it("must pass given a Promise implementation, with a resolved promise", function () { // NOK + it("must pass given a Promise implementation, with a resolved promise", function () { assert.pass(function () { Must(Promise.resolve(42)).be.promise() }) }) - it("must pass given a Promise implementation, with a rejected promise", function () { // NOK + it("must pass given a Promise implementation, with a rejected promise", function () { assert.pass(function () { Must(Promise.resolve(new Error())).be.promise() }) }) } From 66c5ae7485ddb9196f3c22da77300cdce236dff0 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 15:24:37 +0200 Subject: [PATCH 06/28] add nop helper function for `fulfill` and `betray` --- must.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/must.js b/must.js index 09b20ff..6fc3c32 100644 --- a/must.js +++ b/must.js @@ -1219,6 +1219,8 @@ Must.prototype.promise = function() { ) } +function nop() {} + /** * Assert a string starts with the given string. * From d3a71d1cb5f675f9199f3deb00ff5c19b089bb5b Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 15:26:04 +0200 Subject: [PATCH 07/28] add `fulfill` method --- must.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/must.js b/must.js index 6fc3c32..373ec2a 100644 --- a/must.js +++ b/must.js @@ -1221,6 +1221,16 @@ Must.prototype.promise = function() { function nop() {} +defineGetter(Must.prototype, "fulfill", function(fulfilledCondition) { + var must = this + must.promise() + return must.actual + .catch(function(err) { + must.assert(false, "resolve, but got rejected with \'" + err.message + "\'") + }) + .then(fulfilledCondition || nop) +}) + /** * Assert a string starts with the given string. * From bb5081452e16934e7d1a9f2c8b17ca1793fad110 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 15:52:09 +0200 Subject: [PATCH 08/28] add `fulfill` documentation --- must.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/must.js b/must.js index 373ec2a..0b7346e 100644 --- a/must.js +++ b/must.js @@ -1221,6 +1221,43 @@ Must.prototype.promise = function() { function nop() {} +/** + * Assert that an object is a promise (see `promise`), that eventually resolves. + * The assertion returns a promise that settles to the outcome (resolve result or + * reject error) of `fulfilledCondition`. `fulfilledCondition` is called with the + * resolution (resolve result) of the original promise when it resolves. + * If the original promise is rejected, this assertion fails, and `fulfilledCondition` + * is not called. `fulfilledCondition` is optional. + * + * This approach makes it possible to immediate express assertions about the original + * promise's resolve result. + * + * @example + * Promise.resolve(42).must.fulfill() + * Promise.resolve(42).must.fulfill(function(result) { + * result.must.be.a.number() + * result.must.be.truthy() + * return result // the resulting promise will be fulfilled + * }) + * Promise.resolve(42).must.fulfill(function(result) { + * result.must.be.a.number() + * result.must.be.truthy() + * throw result // the resulting promise will be rejected + * }) + * Promise.resolve(42).must.fulfill(function(result) { + * result.must.not.be.a.number() // fails + * result.must.be.truthy() + * return result + * }) + * Promise.reject(new Error()).must.fulfill(function(result) { // fulfill fails, callback is not executed + * result.must.not.be.a.number() + * result.must.be.truthy() + * return result + * }) + * + * @method fulfill + * @param fulfilledCondition + */ defineGetter(Must.prototype, "fulfill", function(fulfilledCondition) { var must = this must.promise() From 9e14a5fb89df49db32e5e9c109d83b4e1f2e8b69 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 18:04:46 +0200 Subject: [PATCH 09/28] `fulfill` is a function, not a property with a getter --- must.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/must.js b/must.js index 0b7346e..e125b4a 100644 --- a/must.js +++ b/must.js @@ -1258,7 +1258,7 @@ function nop() {} * @method fulfill * @param fulfilledCondition */ -defineGetter(Must.prototype, "fulfill", function(fulfilledCondition) { +Must.prototype.fulfill = function(fulfilledCondition) { var must = this must.promise() return must.actual @@ -1266,7 +1266,7 @@ defineGetter(Must.prototype, "fulfill", function(fulfilledCondition) { must.assert(false, "resolve, but got rejected with \'" + err.message + "\'") }) .then(fulfilledCondition || nop) -}) +} /** * Assert a string starts with the given string. From 592807aa5055c03d734a85fdbec4183567fbe2bf Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 15:27:18 +0200 Subject: [PATCH 10/28] add `betray` method --- must.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/must.js b/must.js index e125b4a..9e76d1d 100644 --- a/must.js +++ b/must.js @@ -1268,6 +1268,17 @@ Must.prototype.fulfill = function(fulfilledCondition) { .then(fulfilledCondition || nop) } +defineGetter(Must.prototype, "betray", function(catchCondition) { + var must = this + must.promise() + return must.actual.then( + function(result) { + must.assert(false, "reject, but got fulfilled with \'" + stringify(result) + "\'") + }, + catchCondition || nop + ) +}) + /** * Assert a string starts with the given string. * From ef3fb0f35cba326a33ddf72cae5fbefb31f13d34 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 15:53:12 +0200 Subject: [PATCH 11/28] add `betray` documentation --- must.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/must.js b/must.js index 9e76d1d..31f7c0a 100644 --- a/must.js +++ b/must.js @@ -1268,6 +1268,43 @@ Must.prototype.fulfill = function(fulfilledCondition) { .then(fulfilledCondition || nop) } +/** + * Assert that an object is a promise (see `promise`), that eventually rejects ("betrays" the promise). + * The assertion returns a promise that settles to the outcome (resolve result or + * reject error) of `catchCondition`. `catchCondition` is called with the + * error (reject result) of the original promise when it rejects. + * If the original promise is fulfilled (resolved), this assertion fails, and `catchCondition` + * is not called. `catchCondition` is optional. + * + * This approach makes it possible to immediate express assertions about the original + * promise's reject error. + * + * @example + * Promise.reject(new Error()).must.betray() + * Promise.reject(42).must.betray(function(err) { + * err.must.be.a.number() + * err.must.be.truthy() + * return result // the resulting promise will be fulfilled + * }) + * Promise.reject(42).must.betray(function(err) { + * err.must.be.a.number() + * err.must.be.truthy() + * throw result // the resulting promise will be rejected + * }) + * Promise.reject(42).must.betray(function(err) { + * err.must.not.be.a.number() // fails + * err.must.be.truthy() + * return result + * }) + * Promise.resolve(42).must.betray(function(err) { // betray fails, callback is not executed + * err.must.not.be.a.number() + * err.must.be.truthy() + * return result + * }) + * + * @method betray + * @param catchCondition + */ defineGetter(Must.prototype, "betray", function(catchCondition) { var must = this must.promise() From c06a3343175cb78eb3ac087935a658f134978558 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 18:05:27 +0200 Subject: [PATCH 12/28] `betray` is a function, not a property with a getter --- must.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/must.js b/must.js index 31f7c0a..f723aa0 100644 --- a/must.js +++ b/must.js @@ -1305,7 +1305,7 @@ Must.prototype.fulfill = function(fulfilledCondition) { * @method betray * @param catchCondition */ -defineGetter(Must.prototype, "betray", function(catchCondition) { +Must.prototype.betray = function(catchCondition) { var must = this must.promise() return must.actual.then( @@ -1314,7 +1314,7 @@ defineGetter(Must.prototype, "betray", function(catchCondition) { }, catchCondition || nop ) -}) +} /** * Assert a string starts with the given string. From 1cb2bafd95e997ffe786c78f158d14363e94eb4e Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 16:48:54 +0200 Subject: [PATCH 13/28] add new methods to TS definition Promise definition copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/es6-shim/index.d.ts --- must.d.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/must.d.ts b/must.d.ts index 2f2c2ec..561cd5b 100644 --- a/must.d.ts +++ b/must.d.ts @@ -8,6 +8,8 @@ interface Must { be: CallableMust; before(expected): Must; below(expected): Must; + betray(catchCondition?: (reason: any) => TResult | PromiseLike): Promise; + betray(catchCondition?: (reason: any) => void): Promise; between(begin, end): Must; boolean(): Must; contain(expected): Must; @@ -24,6 +26,8 @@ interface Must { false(): Must; falsy(): Must; frozen(): Must; + fulfill(fulfilledCondition?: (value?: any) => TResult | PromiseLike): Promise; + fulfill(fulfilledCondition?: (value?: any) => void): Promise; function(): Must; gt(expected: number): Must; gte(expected: number): Must; @@ -52,6 +56,7 @@ interface Must { ownProperties(properties: any): Must; ownProperty(property: string, value?): Must; permutationOf(expected: Array): Must; + promise(): Must; properties(properties: any): Must; property(property: string, value?): Must; regexp(): Must; @@ -93,4 +98,41 @@ declare global { interface Array { must: Must; } + + // copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/es6-shim/index.d.ts + interface PromiseLike { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: T) => TResult | PromiseLike, onrejected?: (reason: any) => TResult | PromiseLike): PromiseLike; + + then(onfulfilled?: (value: T) => TResult | PromiseLike, onrejected?: (reason: any) => void): PromiseLike; + } + + /** + * Represents the completion of an asynchronous operation + */ + interface Promise { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: T) => TResult | PromiseLike, onrejected?: (reason: any) => TResult | PromiseLike): Promise; + + then(onfulfilled?: (value: T) => TResult | PromiseLike, onrejected?: (reason: any) => void): Promise; + + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: (reason: any) => T | PromiseLike): Promise; + + catch(onrejected?: (reason: any) => void): Promise; + } } From 8c61412eb39c88a74bb48c3eaec0e4bfba230c4d Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 19:16:59 +0200 Subject: [PATCH 14/28] generalise failing promise tests --- test/must/_failing_promise_tests.js | 66 +++++++++++++++++++++++++++++ test/must/promise_test.js | 57 ++----------------------- 2 files changed, 69 insertions(+), 54 deletions(-) create mode 100644 test/must/_failing_promise_tests.js diff --git a/test/must/_failing_promise_tests.js b/test/must/_failing_promise_tests.js new file mode 100644 index 0000000..53bd971 --- /dev/null +++ b/test/must/_failing_promise_tests.js @@ -0,0 +1,66 @@ +var Must = require("../..") +var assert = require("./assert") +var assertionErrorTest = require("./_assertion_error_test") + +function dummy () {} + +var thenNoCatch = {then: dummy} +var catchNoThen = {catch: dummy} +var catchAndThen = {then: dummy, catch: dummy} + +module.exports = function(callToTest) { + it("must fail given null", function () { + assert.fail(function () { callToTest(Must(null)) }) + }) + + it("must fail given undefined", function () { + assert.fail(function () { callToTest(Must(undefined)) }) + }) + + it("must fail given boolean primitive", function () { + assert.fail(function () { callToTest(Must(true)) }) + assert.fail(function () { callToTest(Must(false)) }) + }) + + it("must fail given number primitive", function () { + assert.fail(function () { callToTest(Must(42)) }) + }) + + it("must fail given string primitive", function () { + assert.fail(function () { callToTest(Must("")) }) + }) + + it("must fail given array", function () { + assert.fail(function () { callToTest(Must([])) }) + }) + + it("must fail given object", function () { + assert.fail(function () { callToTest(Must({})) }) + }) + + it("must fail given an object with a then function, but not a catch function", function () { + assert.fail(function () { callToTest(Must(thenNoCatch)) }) + }) + + it("must fail given an object with a catch function, but not a then function", function () { + assert.fail(function () { callToTest(Must(catchNoThen)) }) + }) + + assertionErrorTest( + function() { callToTest(Must(catchNoThen)) }, + { + actual: catchNoThen, + message: "{} must be a promise (i.e., have a \'then\' and a \'catch\' function)" + } + ) + + describe(".not", function() { + it("must invert the assertion", function() { + assert.fail(function() { callToTest(Must(catchAndThen).not) }) + }) + }) +} + +module.exports.thenNoCatch = thenNoCatch +module.exports.catchNoThen = catchNoThen +module.exports.catchAndThen = catchAndThen diff --git a/test/must/promise_test.js b/test/must/promise_test.js index 0e2029f..2805896 100644 --- a/test/must/promise_test.js +++ b/test/must/promise_test.js @@ -1,52 +1,12 @@ var Must = require("../..") +var failingPromiseTests = require("./_failing_promise_tests") var assert = require("./assert") describe("Must.prototype.promise", function() { - it("must fail given null", function () { - assert.fail(function () { Must(null).be.promise() }) - }) - - it("must fail given undefined", function () { - assert.fail(function () { Must(undefined).be.promise() }) - }) - - it("must fail given boolean primitive", function () { - assert.fail(function () { Must(true).be.promise() }) - assert.fail(function () { Must(false).be.promise() }) - }) - - it("must fail given number primitive", function () { - assert.fail(function () { Must(42).be.promise() }) - }) - - it("must fail given string primitive", function () { - assert.fail(function () { Must("").be.promise() }) - }) - - it("must fail given array", function () { - assert.fail(function () { Must([]).be.promise() }) - }) - - it("must fail given object", function () { - assert.fail(function () { Must({}).be.promise() }) - }) - - function dummy () {} - - var thenNoCatch = {then: dummy} - var catchNoThen = {catch: dummy} - var catchAndThen = {then: dummy, catch: dummy} - - it("must fail given an object with a then function, but not a catch function", function () { - assert.fail(function () { Must(thenNoCatch).be.promise() }) - }) - - it("must fail given an object with a catch function, but not a then function", function () { - assert.fail(function () { Must(catchNoThen).be.promise() }) - }) + failingPromiseTests(function(must) { must.promise() }) it("must pass given an object with a catch and a then function", function () { - assert.pass(function () { Must(catchAndThen).be.promise() }) + assert.pass(function () { Must(failingPromiseTests.catchAndThen).be.promise() }) }) if (Promise) { @@ -58,15 +18,4 @@ describe("Must.prototype.promise", function() { assert.pass(function () { Must(Promise.resolve(new Error())).be.promise() }) }) } - - require("./_assertion_error_test")(function() { Must(catchNoThen).be.promise() }, { - actual: catchNoThen, - message: "{} must be a promise (i.e., have a \'then\' and a \'catch\' function)" - }) - - describe(".not", function() { - it("must invert the assertion", function() { - assert.fail(function() { Must(catchAndThen).not.be.promise() }) - }) - }) }) From b737286ae6ee4f62ac9202fad55831ea84c8e9df Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 19:47:52 +0200 Subject: [PATCH 15/28] fix mistake in promise_test --- test/must/promise_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/must/promise_test.js b/test/must/promise_test.js index 2805896..4aceca5 100644 --- a/test/must/promise_test.js +++ b/test/must/promise_test.js @@ -15,7 +15,7 @@ describe("Must.prototype.promise", function() { }) it("must pass given a Promise implementation, with a rejected promise", function () { - assert.pass(function () { Must(Promise.resolve(new Error())).be.promise() }) + assert.pass(function () { Must(Promise.reject(new Error())).be.promise() }) }) } }) From 3d8a5eaf795903945270c37ee679937075cef273 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 22:09:51 +0200 Subject: [PATCH 16/28] Copy Promise require from resolve test, and remove optionality of Promise tests --- test/must/promise_test.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/must/promise_test.js b/test/must/promise_test.js index 4aceca5..c43e435 100644 --- a/test/must/promise_test.js +++ b/test/must/promise_test.js @@ -1,3 +1,4 @@ +var Promise = global.Promise || require("promise") var Must = require("../..") var failingPromiseTests = require("./_failing_promise_tests") var assert = require("./assert") @@ -9,13 +10,11 @@ describe("Must.prototype.promise", function() { assert.pass(function () { Must(failingPromiseTests.catchAndThen).be.promise() }) }) - if (Promise) { - it("must pass given a Promise implementation, with a resolved promise", function () { - assert.pass(function () { Must(Promise.resolve(42)).be.promise() }) - }) + it("must pass given a Promise implementation, with a resolved promise", function () { + assert.pass(function () { Must(Promise.resolve(42)).be.promise() }) + }) - it("must pass given a Promise implementation, with a rejected promise", function () { - assert.pass(function () { Must(Promise.reject(new Error())).be.promise() }) - }) - } + it("must pass given a Promise implementation, with a rejected promise", function () { + assert.pass(function () { Must(Promise.reject(new Error())).be.promise() }) + }) }) From e6fc08536ecc2118bd2c747fe2928b321ad410b6 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 22:18:35 +0200 Subject: [PATCH 17/28] Refactor isPromise test out, and repeat a little code, to get a good stack trace for fulfill and betray --- must.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/must.js b/must.js index f723aa0..bac376a 100644 --- a/must.js +++ b/must.js @@ -1212,11 +1212,7 @@ defineGetter(Must.prototype, "reject", function() { * @method promise */ Must.prototype.promise = function() { - this.assert( - this.actual && typeof this.actual.then === "function" && typeof this.actual.catch === "function", - "be a promise (i.e., have a \'then\' and a \'catch\' function)", - { actual: this.actual } - ) + this.assert(isPromise(this.actual), isPromiseMsg, { actual: this.actual }) } function nop() {} @@ -1260,12 +1256,12 @@ function nop() {} */ Must.prototype.fulfill = function(fulfilledCondition) { var must = this - must.promise() return must.actual .catch(function(err) { must.assert(false, "resolve, but got rejected with \'" + err.message + "\'") }) .then(fulfilledCondition || nop) + must.assert(isPromise(this.actual), isPromiseMsg, {actual: this.actual}) } /** @@ -1307,13 +1303,13 @@ Must.prototype.fulfill = function(fulfilledCondition) { */ Must.prototype.betray = function(catchCondition) { var must = this - must.promise() return must.actual.then( function(result) { must.assert(false, "reject, but got fulfilled with \'" + stringify(result) + "\'") }, catchCondition || nop ) + must.assert(isPromise(this.actual), isPromiseMsg, {actual: this.actual}) } /** @@ -1418,4 +1414,10 @@ function messageFromError(err) { function isFn(fn) { return typeof fn === "function" } function isNumber(n) { return typeof n === "number" || n instanceof Number } + +var isPromiseMsg = "be a promise (i.e., have a \'then\' and a \'catch\' function)" +function isPromise(p) { + return p && typeof p.then === "function" && typeof p.catch === "function" +} + function passthrough() { return this } From 46b67fff928a891964f2f2c61a64d5ad5859eafc Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 22:20:22 +0200 Subject: [PATCH 18/28] fix a bug: make sure result of resolve or reject is propagated also when there is no condition nop is not needed --- must.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/must.js b/must.js index bac376a..cd9f548 100644 --- a/must.js +++ b/must.js @@ -1215,8 +1215,6 @@ Must.prototype.promise = function() { this.assert(isPromise(this.actual), isPromiseMsg, { actual: this.actual }) } -function nop() {} - /** * Assert that an object is a promise (see `promise`), that eventually resolves. * The assertion returns a promise that settles to the outcome (resolve result or @@ -1256,12 +1254,15 @@ function nop() {} */ Must.prototype.fulfill = function(fulfilledCondition) { var must = this - return must.actual - .catch(function(err) { - must.assert(false, "resolve, but got rejected with \'" + err.message + "\'") - }) - .then(fulfilledCondition || nop) must.assert(isPromise(this.actual), isPromiseMsg, {actual: this.actual}) + var caught = must.actual.catch(function(err) { + must.assert( + false, + "resolve, but got rejected with \'" + (err && err.message ? err.message : err) + "\'", + {actual: must.actual} + ) + }) + return fulfilledCondition ? caught.then(fulfilledCondition) : caught } /** @@ -1303,13 +1304,11 @@ Must.prototype.fulfill = function(fulfilledCondition) { */ Must.prototype.betray = function(catchCondition) { var must = this - return must.actual.then( - function(result) { - must.assert(false, "reject, but got fulfilled with \'" + stringify(result) + "\'") - }, - catchCondition || nop - ) must.assert(isPromise(this.actual), isPromiseMsg, {actual: this.actual}) + var resolved = must.actual.then(function(result) { + must.assert(false, "reject, but got fulfilled with \'" + stringify(result) + "\'") + }) + return catchCondition ? resolved.catch(catchCondition) : resolved } /** From ce39985dcc5c4d17f73ea5315bd25bc2bac267f3 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 22:21:37 +0200 Subject: [PATCH 19/28] Make clear that not is confusing in documentation (it is not being tested against either) --- must.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/must.js b/must.js index cd9f548..3a8d836 100644 --- a/must.js +++ b/must.js @@ -1226,6 +1226,9 @@ Must.prototype.promise = function() { * This approach makes it possible to immediate express assertions about the original * promise's resolve result. * + * You should not use `not` to negate `fulfill`. Things will get weird. Use `betray` + * to express that the promise should be rejected instead. + * * @example * Promise.resolve(42).must.fulfill() * Promise.resolve(42).must.fulfill(function(result) { @@ -1276,6 +1279,9 @@ Must.prototype.fulfill = function(fulfilledCondition) { * This approach makes it possible to immediate express assertions about the original * promise's reject error. * + * You should not use `not` to negate `betray`. Things will get weird. Use `fulfill` + * to express that the promise should be resolved instead. + * * @example * Promise.reject(new Error()).must.betray() * Promise.reject(42).must.betray(function(err) { From 8711db1425e8710ba35460e588370140af8dcc8c Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 22:21:59 +0200 Subject: [PATCH 20/28] Add GREEN tests for `fulfill` --- test/must/fulfill_test.js | 131 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 test/must/fulfill_test.js diff --git a/test/must/fulfill_test.js b/test/must/fulfill_test.js new file mode 100644 index 0000000..e94e85b --- /dev/null +++ b/test/must/fulfill_test.js @@ -0,0 +1,131 @@ +var Promise = global.Promise || require("promise") +var Must = require("../..") +var failingPromiseTests = require("./_failing_promise_tests") +var assert = require("./assert") + +describe("Must.prototype.fulfill", function() { + failingPromiseTests(function(must) { must.fulfill() }) + + it("must pass given a Promise that rejects, and eventually fail", function(done) { + assert.pass(function() { Must(Promise.reject(new Error())).fulfill().then(raise(done),assertThrown(done)) }) + }) + + it( + "must pass given a Promise that resolves, and eventually pass, and resolve itself", + function(done) { + assert.pass(function() { Must(Promise.resolve(42)).fulfill().then(assertStrictEqual(done, 42), raise(done)) }) + } + ) + + it( + "must pass given a Promise that resolves and a fulfilledCondition that returns, " + + "and eventually pass, and resolve to the result of the fulfilledCondition", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.resolve(42)).fulfill(function(result) { + called = true + result.must.be.a.number() + result.must.be.truthy() + return result // the resulting promise will be fulfilled + }) + .then(assertStrictEqual(done, 42, function() { return called }), raise(done)) + }) + } + ) + + it( + "must pass given a Promise that resolves and a fulfilledCondition that throws, " + + "and eventually pass, and reject to the rejection of the fulfilledCondition", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.resolve(42)).fulfill(function(result) { + called = true + result.must.be.a.number() + result.must.be.truthy() + throw result // the resulting promise will be rejected + }) + .then(raise(done), assertStrictEqual(done, 42, function() { return called })) + }) + } + ) + + it( + "must pass given a Promise that resolves and a fulfilledCondition that fails, and eventually fail", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.resolve(42)).fulfill(function(result) { + called = true + result.must.not.be.a.number() // fails + result.must.be.truthy() + return result + }) + .then(raise(done), assertThrown(done, function() { return called })) + }) + } + ) + + it( + "must pass given a Promise that rejects, and eventually fail, without calling the fulfilledCondition", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.reject(new Error('rejection'))).fulfill(function(result) { // fulfill fails, callback is not executed + called = true + result.must.not.be.a.number() // fails + result.must.be.truthy() + return result + }) + .then(raise(done), assertThrown(done, function() { return !called })) + }) + } + ) + + it("AssertionError must have all properties when it fails because of a rejection", function(done) { + var message = "rejection message" + var subject = Promise.reject(new Error(message)) + Must(subject).fulfill().then( + raise(done), + function(err) { + assert(err instanceof Must.AssertionError) + assert.deepEqual( + err, + { + actual: subject, + message: "{} must resolve, but got rejected with \'" + message + "\'" + } + ) + done() + } + ) + }) + +}) + +function assertStrictEqual(done, expected, called) { + return function(value) { + if (called) { + assert(called()) + } + assert.strictEqual(value, expected) + done() + } +} +function assertThrown(done, called) { + return function(err) { + if (called) { + assert(called()) + } + if (err instanceof Must.AssertionError) { + done() + } + else { + done(new Error("not a Must.AssertionError: " + err.message)) + } + } +} +function raise(done) { + return function() { done(new Error("Must fail")) } +} From 524f87be4e15df60783a40f54feb312474e6cff4 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 23:35:19 +0200 Subject: [PATCH 21/28] add unit tests for `betray`, with 1 particular annoying test still failing - changed implementation of betray to avoid exception cycle, and added actual to assert error --- must.js | 16 +++-- test/must/betray_test.js | 131 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 test/must/betray_test.js diff --git a/must.js b/must.js index 3a8d836..8b8655f 100644 --- a/must.js +++ b/must.js @@ -1311,10 +1311,18 @@ Must.prototype.fulfill = function(fulfilledCondition) { Must.prototype.betray = function(catchCondition) { var must = this must.assert(isPromise(this.actual), isPromiseMsg, {actual: this.actual}) - var resolved = must.actual.then(function(result) { - must.assert(false, "reject, but got fulfilled with \'" + stringify(result) + "\'") - }) - return catchCondition ? resolved.catch(catchCondition) : resolved + return must.actual.then( + function(result) { + must.assert( + false, + "reject, but got fulfilled with \'" + stringify(result) + "\'", + {actual: must.actual} + ) + }, + catchCondition + ? catchCondition + : function(err) { throw err } + ) } /** diff --git a/test/must/betray_test.js b/test/must/betray_test.js new file mode 100644 index 0000000..0d4cda8 --- /dev/null +++ b/test/must/betray_test.js @@ -0,0 +1,131 @@ +var Promise = global.Promise || require("promise") +var Must = require("../..") +var failingPromiseTests = require("./_failing_promise_tests") +var assert = require("./assert") +var stringify = require("../../lib").stringify + +describe("Must.prototype.betray", function() { + failingPromiseTests(function(must) { must.betray() }) + + it( + "must pass given a Promise that rejects, and eventually pass, and reject itself", + function(done) { + var rejection = new Error() + assert.pass( + function() { Must(Promise.reject(rejection)).betray().then(raise(done), assertStrictEqual(done, rejection)) } + ) + } + ) + + it("must pass given a Promise that resolves, and eventually fail", function(done) { + assert.pass(function() { Must(Promise.resolve(42)).betray().then(raise(done), assertThrown(done)) }) + }) + + it( + "must pass given a Promise that rejects and a catchCondition that returns, " + + "and eventually pass, and resolve to the result of the catchCondition", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.reject(42)).betray(function(result) { + called = true + result.must.be.a.number() + result.must.be.truthy() + return result // the resulting promise will be fulfilled + }).then(assertStrictEqual(done, 42, function() { return called }), raise(done)) + }) + } + ) + + it( + "must pass given a Promise that rejects and a catchCondition that throws, " + + "and eventually pass, and reject to the rejection of the catchCondition", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.reject(43).betray(function(err) { + called = true + err.must.be.a.number() + err.must.be.truthy() + throw err // the resulting promise will be rejected + }) + .then(raise(done), assertStrictEqual(done, 42, function() { return called }))) + }) + } + ) + + it( + "must pass given a Promise that rejects and a catchCondition that fails, and eventually fail", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.reject(42)).betray(function(result) { + called = true + result.must.not.be.a.number() // fails + result.must.be.truthy() + return result + }) + .then(raise(done), assertThrown(done, function() { return called })) + }) + } + ) + + it( + "must pass given a Promise that resolves, and eventually fail, without calling the catchCondition", + function(done) { + var called = false + assert.pass(function() { + Must(Promise.resolve(42)).betray(function() { // betray fails, callback is not executed + called = true + }) + .then(raise(done), assertThrown(done, function() { return !called })) + }) + } + ) + + it("AssertionError must have all properties when it fails because of a resolution", function(done) { + var resolution = 42 + var subject = Promise.resolve(resolution) + Must(subject).betray().then( + raise(done), + function(err) { + assert(err instanceof Must.AssertionError) + assert.deepEqual( + err, + { + actual: subject, + message: "{} must reject, but got fulfilled with \'" + stringify(resolution) + "\'" + } + ) + done() + } + ) + }) + +}) + +function assertStrictEqual(done, expected, called) { + return function(value) { + if (called) { + assert(called()) + } + assert.strictEqual(value, expected) + done() + } +} +function assertThrown(done, called) { + return function(err) { + if (called) { + assert(called()) + } + if (err instanceof Must.AssertionError) { + done() + } + else { + done(new Error("not a Must.AssertionError: " + err.message)) + } + } +} +function raise(done) { + return function() { done(new Error("Must fail")) } +} From 1be660134c630519f288d9d7f2d518bcf78bd4fb Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 23:35:48 +0200 Subject: [PATCH 22/28] cleanup (removing unused code) of fulfill test --- test/must/fulfill_test.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/must/fulfill_test.js b/test/must/fulfill_test.js index e94e85b..ff544d7 100644 --- a/test/must/fulfill_test.js +++ b/test/must/fulfill_test.js @@ -72,11 +72,8 @@ describe("Must.prototype.fulfill", function() { function(done) { var called = false assert.pass(function() { - Must(Promise.reject(new Error('rejection'))).fulfill(function(result) { // fulfill fails, callback is not executed + Must(Promise.reject(new Error('rejection'))).fulfill(function() { // fulfill fails, callback is not executed called = true - result.must.not.be.a.number() // fails - result.must.be.truthy() - return result }) .then(raise(done), assertThrown(done, function() { return !called })) }) From 03bb54c08334d2852171887bf993ef39aa86571e Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 23:37:46 +0200 Subject: [PATCH 23/28] marked test that has issues --- test/must/betray_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/must/betray_test.js b/test/must/betray_test.js index 0d4cda8..ac890c6 100644 --- a/test/must/betray_test.js +++ b/test/must/betray_test.js @@ -37,7 +37,7 @@ describe("Must.prototype.betray", function() { } ) - it( + it( // MUDO this test has issues "must pass given a Promise that rejects and a catchCondition that throws, " + "and eventually pass, and reject to the rejection of the catchCondition", function(done) { From 43b4ede71b44f90c40d200a4deb05ae8b517e261 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 23:41:26 +0200 Subject: [PATCH 24/28] fixed broken test the reason was a badly placed (pair of) braces --- test/must/betray_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/must/betray_test.js b/test/must/betray_test.js index ac890c6..1c2ee84 100644 --- a/test/must/betray_test.js +++ b/test/must/betray_test.js @@ -37,19 +37,19 @@ describe("Must.prototype.betray", function() { } ) - it( // MUDO this test has issues + it( "must pass given a Promise that rejects and a catchCondition that throws, " + "and eventually pass, and reject to the rejection of the catchCondition", function(done) { var called = false assert.pass(function() { - Must(Promise.reject(43).betray(function(err) { + Must(Promise.reject(42)).betray(function(err) { called = true err.must.be.a.number() err.must.be.truthy() throw err // the resulting promise will be rejected }) - .then(raise(done), assertStrictEqual(done, 42, function() { return called }))) + .then(raise(done), assertStrictEqual(done, 42, function() { return called })) }) } ) From 0117313769e0f064589001e38ed7dde7f0711ae8 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Sat, 19 Aug 2017 23:59:42 +0200 Subject: [PATCH 25/28] deal with UnhandledPromiseRejectionWarning promise now returns the promise, if it is one --- must.js | 3 ++- test/must/promise_test.js | 22 ++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/must.js b/must.js index 8b8655f..e8eac8f 100644 --- a/must.js +++ b/must.js @@ -1184,7 +1184,7 @@ defineGetter(Must.prototype, "reject", function() { }) /** - * Assert that an object is a promise. + * Assert that an object is a promise, and returns it. * * The determination uses duck typing, i.e., it checks whether the object has * a `then` and a `catch` method. @@ -1213,6 +1213,7 @@ defineGetter(Must.prototype, "reject", function() { */ Must.prototype.promise = function() { this.assert(isPromise(this.actual), isPromiseMsg, { actual: this.actual }) + return this.actual } /** diff --git a/test/must/promise_test.js b/test/must/promise_test.js index c43e435..625898b 100644 --- a/test/must/promise_test.js +++ b/test/must/promise_test.js @@ -14,7 +14,25 @@ describe("Must.prototype.promise", function() { assert.pass(function () { Must(Promise.resolve(42)).be.promise() }) }) - it("must pass given a Promise implementation, with a rejected promise", function () { - assert.pass(function () { Must(Promise.reject(new Error())).be.promise() }) + it("must pass given a Promise implementation, with a rejected promise (and passes it through)", function(done) { + var p = Promise.reject(new Error()) + assert.pass(function() { Must(p).be.promise() }) + p.catch(function() { done() }) // deal with UnhandledPromiseRejectionWarning + }) + + it("passes through a resolved promise", function() { + var p = Promise.resolve(42) + assert(Must(p).be.promise() === p) + }) + + it("passes through a rejected promise", function(done) { + var rejection = new Error() + var p = Promise.reject(rejection) + var outcome = Must(p).be.promise() + assert(outcome === p) + p.catch(function(err) { // deal with UnhandledPromiseRejectionWarning + assert(err === rejection) + done() + }) }) }) From e753a5681e826d2ad77f73b22e10233e49a3c621 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Mon, 11 Dec 2017 19:23:34 +0100 Subject: [PATCH 26/28] add Node v8 (LTS) to supported Node versions ("node" is now v9) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b41ba14..39f3a50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ node_js: - "5" - "6" - "7" + - "8" notifications: email: ["andri@dot.ee"] From a1121272ce9fa9b9dd5b10f9430183cc8bdc3ec1 Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Mon, 11 Dec 2017 20:21:15 +0100 Subject: [PATCH 27/28] fix mocha timeout with node 0.10 - we now get clear failing tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the reason for the failure is that the actual error message we expect is tested this contains a stringified version of this.actual (NOT opts.actual) - see Must.prototype.assert, `var msg = stringify(this.actual) + …` in this case, the actual is a Promise in the node 0.10 version, and only there, this is an object with strange properties `"_40", "_65", "_55", "_72"`, while in other versions of Node this is just an object with then and catch methods these properties are probably private Promise administration, that is exposed the existing Promise tests don't reveal this, because the only place where a Promise is stringified as actual in an assert call in the tests, is in the test for 'must.NOT.be.a.promise()', and there a crafted object is used, not a 'real' Promise the heart of the matter is thus the stringification of a Promise, which is nonsensical in all Node versions ('{}'), does not take into account the Node 0.10 weirdness, and is not really tested with the existing tests fixing this would require a change in Must.prototype.assert, which is a different issue --- test/must/betray_test.js | 23 ++++++++++++++--------- test/must/fulfill_test.js | 22 +++++++++++++--------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/test/must/betray_test.js b/test/must/betray_test.js index 1c2ee84..6cfc75c 100644 --- a/test/must/betray_test.js +++ b/test/must/betray_test.js @@ -89,15 +89,20 @@ describe("Must.prototype.betray", function() { Must(subject).betray().then( raise(done), function(err) { - assert(err instanceof Must.AssertionError) - assert.deepEqual( - err, - { - actual: subject, - message: "{} must reject, but got fulfilled with \'" + stringify(resolution) + "\'" - } - ) - done() + try { + assert(err instanceof Must.AssertionError) + assert.deepEqual( + err, + { + actual: subject, + message: "{} must reject, but got fulfilled with \'" + stringify(resolution) + "\'" + } + ) + done() + } + catch (assertErr) { + done(assertErr) + } } ) }) diff --git a/test/must/fulfill_test.js b/test/must/fulfill_test.js index ff544d7..89e9378 100644 --- a/test/must/fulfill_test.js +++ b/test/must/fulfill_test.js @@ -86,15 +86,19 @@ describe("Must.prototype.fulfill", function() { Must(subject).fulfill().then( raise(done), function(err) { - assert(err instanceof Must.AssertionError) - assert.deepEqual( - err, - { - actual: subject, - message: "{} must resolve, but got rejected with \'" + message + "\'" - } - ) - done() + try { + assert(err instanceof Must.AssertionError) + assert.deepEqual( + err, + { + actual: subject, + message: "{} must resolve, but got rejected with \'" + message + "\'" + } + ) + done() + } catch (assertErr) { + done(assertErr) + } } ) }) From c77e39ca9280f8a3ac2e625713ddd49eefbace9f Mon Sep 17 00:00:00 2001 From: Jan Dockx Date: Mon, 11 Dec 2017 20:31:04 +0100 Subject: [PATCH 28/28] fix the problem with Promise stringification in test in Node 0.10 by calling stringify in test, and compare literally a better representation of this.actual in Must.prototype.assert would be a better solution, but is independent of this --- test/must/betray_test.js | 2 +- test/must/fulfill_test.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/must/betray_test.js b/test/must/betray_test.js index 6cfc75c..2a5cee2 100644 --- a/test/must/betray_test.js +++ b/test/must/betray_test.js @@ -95,7 +95,7 @@ describe("Must.prototype.betray", function() { err, { actual: subject, - message: "{} must reject, but got fulfilled with \'" + stringify(resolution) + "\'" + message: stringify(subject) + " must reject, but got fulfilled with \'" + stringify(resolution) + "\'" } ) done() diff --git a/test/must/fulfill_test.js b/test/must/fulfill_test.js index 89e9378..48ad7ef 100644 --- a/test/must/fulfill_test.js +++ b/test/must/fulfill_test.js @@ -2,6 +2,7 @@ var Promise = global.Promise || require("promise") var Must = require("../..") var failingPromiseTests = require("./_failing_promise_tests") var assert = require("./assert") +var stringify = require("../../lib").stringify describe("Must.prototype.fulfill", function() { failingPromiseTests(function(must) { must.fulfill() }) @@ -92,7 +93,7 @@ describe("Must.prototype.fulfill", function() { err, { actual: subject, - message: "{} must resolve, but got rejected with \'" + message + "\'" + message: stringify(subject) + " must resolve, but got rejected with \'" + message + "\'" } ) done()