From 19af1465e5f9cde4d5947f47f0954844dd287369 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Fri, 2 Mar 2018 13:53:19 +0000 Subject: [PATCH] Re-add assert.callOrder Lifted some private code from Sinon, as `calledInOrder` and `orderByFirstCall were made private in Sinon in https://github.com/sinonjs/sinon/pull/1506 --- .eslintrc.yaml | 2 +- lib/referee-sinon.js | 70 +++++++++++++++++++++++++++++++++++++++ lib/referee-sinon.test.js | 35 ++++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 89df783..c107f2c 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -16,7 +16,7 @@ rules: ie11/no-loop-func: warn ie11/no-weak-collections: error - max-len: [error, {code: 120, ignoreStrings: true}] + max-len: [error, {code: 120, ignoreComments: true, ignoreStrings: true}] overrides: files: '*.test.*' diff --git a/lib/referee-sinon.js b/lib/referee-sinon.js index 867b19a..0cad556 100644 --- a/lib/referee-sinon.js +++ b/lib/referee-sinon.js @@ -16,6 +16,59 @@ }(typeof self !== "undefined" ? self : this, function () { "use strict"; + // lifted from https://github.com/sinonjs/sinon/blob/f89392c419dd3825d7af7fa0d58cc6ddeabfa3a6/lib/sinon/util/core/order-by-first-call.js + // FIXME: figure out how to share this code from Sinon + // * separate repository for this function? + // * Mono repo? https://lernajs.io + function orderByFirstCall(spies) { + return spies.sort(function (a, b) { + // uuid, won't ever be equal + var aCall = a.getCall(0); + var bCall = b.getCall(0); + var aId = aCall && aCall.callId || -1; + var bId = bCall && bCall.callId || -1; + + return aId < bId ? -1 : 1; + }); + } + + // lifted from https://github.com/sinonjs/sinon/blob/f89392c419dd3825d7af7fa0d58cc6ddeabfa3a6/lib/sinon/util/core/called-in-order.js + // FIXME: figure out how to share this code from Sinon + // * separate repository for this function? + // * Mono repo? https://lernajs.io + var every = Array.prototype.every; + + function calledInOrder(spies) { + var callMap = {}; + + function hasCallsLeft(spy) { + if (callMap[spy.id] === undefined) { + callMap[spy.id] = 0; + } + + return callMap[spy.id] < spy.callCount; + } + + if (arguments.length > 1) { + spies = arguments; + } + + return every.call(spies, function checkAdjacentCalls(spy, i) { + var calledBeforeNext = true; + + if (i !== spies.length - 1) { + calledBeforeNext = spy.calledBefore(spies[i + 1]); + } + + if (hasCallsLeft(spy) && calledBeforeNext) { + callMap[spy.id] += 1; + return true; + } + + return false; + }); + } + return function (referee, sinon) { sinon.expectation.pass = function (assertion) { referee.emit("pass", assertion); @@ -80,6 +133,23 @@ return [].slice.call(arr, from); } + referee.add("callOrder", { + assert: function (spy) { + var type = Object.prototype.toString.call(spy); + var isArray = type === "[object Array]"; + var args = isArray ? spy : arguments; + verifyFakes.apply(this, args); + if (calledInOrder(args)) { return true; } + + this.expected = [].join.call(args, ", "); + this.actual = orderByFirstCall(slice(args)).join(", "); + return false; + }, + + assertMessage: "Expected ${expected} to be called in order but were called as ${actual}", + refuteMessage: "Expected ${expected} not to be called in order" + }); + function addCallCountAssertion(count) { referee.add("called" + count, { assert: function (spy) { diff --git a/lib/referee-sinon.test.js b/lib/referee-sinon.test.js index 4b00607..8c7f625 100644 --- a/lib/referee-sinon.test.js +++ b/lib/referee-sinon.test.js @@ -231,6 +231,41 @@ describe("referee-sinon", function () { }); }); + describe("callOrder", function () { + it("fails when not called with function", requiresFunction("callOrder")); + it("fails when not called with spy", requiresSpy("callOrder")); + + it("passes when called in order", function () { + var spies = [sinon.spy(), sinon.spy()]; + spies[0](); + spies[1](); + + assert.callOrder(spies[0], spies[1]); + }); + + it("passes when called in order using an array", function () { + var spies = [sinon.spy(), sinon.spy()]; + spies[0](); + spies[1](); + + assert.callOrder(spies); + }); + + it("formats message", function () { + var spies = [sinon.spy(), sinon.spy()]; + spies[1](); + spies[0](); + + try { + assert.callOrder(spies[0], spies[1]); + } catch (e) { + var message = "[assert.callOrder] Expected 0, 1 to be " + + "called in order but were called as 1, 0"; + assert.equals(e.message, message); + } + }); + }); + describe("calledOn", function () { it("fails when not called with function", requiresFunction("calledOn", {})); it("fails when not called with spy", requiresSpy("calledOn", {}));