diff --git a/lib/sinon/assert.js b/lib/sinon/assert.js index d5058a19c..c3b285bda 100644 --- a/lib/sinon/assert.js +++ b/lib/sinon/assert.js @@ -207,6 +207,7 @@ mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %D"); mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %D"); mirrorPropAsAssertion("calledOnceWithExactly", "expected %n to be called once and with exact arguments %D"); +mirrorPropAsAssertion("calledOnceWithMatch", "expected %n to be called once and with match %D"); mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %D"); mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); diff --git a/lib/sinon/proxy.js b/lib/sinon/proxy.js index c6f94e3a5..76b10addb 100644 --- a/lib/sinon/proxy.js +++ b/lib/sinon/proxy.js @@ -176,6 +176,7 @@ delegateToCalls(proxyApi, "alwaysCalledWith", false, "calledWith"); delegateToCalls(proxyApi, "alwaysCalledWithMatch", false, "calledWithMatch"); delegateToCalls(proxyApi, "calledWithExactly", true); delegateToCalls(proxyApi, "calledOnceWithExactly", true, "calledWithExactly", false, undefined, 1); +delegateToCalls(proxyApi, "calledOnceWithMatch", true, "calledWithMatch", false, undefined, 1); delegateToCalls(proxyApi, "alwaysCalledWithExactly", false, "calledWithExactly"); delegateToCalls(proxyApi, "neverCalledWith", false, "notCalledWith", false, function() { return true; diff --git a/test/assert-test.js b/test/assert-test.js index 3f169c36f..fc433f7e3 100644 --- a/test/assert-test.js +++ b/test/assert-test.js @@ -941,6 +941,105 @@ describe("assert", function() { }); }); + describe(".calledOnceWithMatch", function() { + // eslint-disable-next-line mocha/no-setup-in-describe + requiresValidFake("calledOnceWithMatch"); + + it("fails when method fails", function() { + var object = {}; + sinonStub(this.stub, "calledOnceWithMatch").returns(false); + var stub = this.stub; + + assert.exception(function() { + sinonAssert.calledOnceWithMatch(stub, object, 1); + }); + + assert(this.stub.calledOnceWithMatch.calledOnceWithMatch(object, 1)); + assert(sinonAssert.fail.called); + }); + + it("passes when method doesn't fail", function() { + var object = {}; + sinonStub(this.stub, "calledOnceWithMatch").returns(true); + var stub = this.stub; + + refute.exception(function() { + sinonAssert.calledOnceWithMatch(stub, object, 1); + }); + + assert(this.stub.calledOnceWithMatch.calledOnceWithMatch(object, 1)); + assert.isFalse(sinonAssert.fail.called); + }); + + it("calls pass callback", function() { + this.stub("yeah"); + sinonAssert.calledOnceWithMatch(this.stub, "yeah"); + + assert(sinonAssert.pass.calledOnce); + assert(sinonAssert.pass.calledWith("calledOnceWithMatch")); + }); + + it("fails when method does not exist", function() { + assert.exception(function() { + sinonAssert.calledOnceWithMatch(); + }); + + assert(sinonAssert.fail.called); + }); + + it("fails when method is not stub", function() { + assert.exception(function() { + sinonAssert.calledOnceWithMatch(function() { + return; + }); + }); + + assert(sinonAssert.fail.called); + }); + + it("fails when method was not called", function() { + var stub = this.stub; + + assert.exception(function() { + sinonAssert.calledOnceWithMatch(stub); + }); + + assert(sinonAssert.fail.called); + }); + + it("fails when called with more than one argument", function() { + var stub = this.stub; + stub(); + + assert.exception(function() { + sinonAssert.calledOnceWithMatch(stub, 1); + }); + }); + + it("passes when method was called", function() { + var stub = this.stub; + stub(); + + refute.exception(function() { + sinonAssert.calledOnceWithMatch(stub); + }); + + assert.isFalse(sinonAssert.fail.called); + }); + + it("fails when method was called more than once", function() { + var stub = this.stub; + stub(); + stub(); + + assert.exception(function() { + sinonAssert.calledOnceWithMatch(stub); + }); + + assert(sinonAssert.fail.called); + }); + }); + describe(".neverCalledWith", function() { it("fails when method fails", function() { var object = {}; diff --git a/test/spy-test.js b/test/spy-test.js index 3bbf50bab..0ad20230a 100644 --- a/test/spy-test.js +++ b/test/spy-test.js @@ -1314,6 +1314,44 @@ describe("spy", function() { }); }); + describe(".calledOnceWithMatch", function() { + beforeEach(function() { + this.spy = createSpy(); + }); + + it("returns true for exact match", function() { + this.spy(1, 2, 3); + + assert.isTrue(this.spy.calledOnceWithMatch(1, 2, 3)); + }); + + it("returns true for partial match", function() { + this.spy(1, 2, 3); + + assert.isTrue(this.spy.calledOnceWithMatch(1, 2)); + }); + + it("returns false for exact parameters but called more then once", function() { + this.spy(1, 2, 3); + this.spy(1, 2, 3); + + assert.isFalse(this.spy.calledOnceWithMatch(1, 2, 3)); + }); + + it("return false for one mismatched call", function() { + this.spy(1, 2); + + assert.isFalse(this.spy.calledOnceWithMatch(1, 2, 3)); + }); + + it("return false for one mismatched call with some other", function() { + this.spy(1, 2, 3); + this.spy(1, 2); + + assert.isFalse(this.spy.calledOnceWithMatch(1, 2, 3)); + }); + }); + describe(".alwaysCalledWithExactly", function() { beforeEach(function() { this.spy = createSpy();