Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add throwsArg(index) to stubs #1319

Merged
merged 4 commits into from
May 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/_releases/v1.17.6/stubs.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ Causes the stub to throw an exception of the provided type.

Causes the stub to throw the provided exception object.

#### `stub.throwsArg(index);`

Causes the stub to throw the argument exception at the provided index. Throws a `TypeError` if called with fewer than `index` arguments.

`stub.throwsArg(0);` causes the stub to throw the first argument exception.


#### `stub.callsArg(index);`

Expand Down
10 changes: 10 additions & 0 deletions lib/sinon/behavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ var proto = {
this.exception ||
typeof this.returnArgAt === "number" ||
this.returnThis ||
typeof this.throwArgAt === "number" ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test.

this.fakeFn ||
this.returnValueDefined);
},
Expand All @@ -126,6 +127,15 @@ var proto = {
return args[this.returnArgAt];
} else if (this.returnThis) {
return context;
} else if (typeof this.throwArgAt === "number") {
if (args.length < this.throwArgAt) {
throw new TypeError(
"throwArgs failed: " + this.throwArgAt
+ " arguments required but only " + args.length
+ " present"
);
}
throw args[this.throwArgAt];
} else if (this.fakeFn) {
return this.fakeFn.apply(context, args);
} else if (this.resolve) {
Expand Down
12 changes: 12 additions & 0 deletions lib/sinon/call.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ var callProto = {
this.args[pos].apply(thisValue, args);
},

throwArg: function (pos) {
if (pos > this.args.length) {
throw new TypeError(
"Not enough arguments: " + pos
+ " required but only " + this.args.length
+ " present"
);
}

throw this.args[pos];
},

"yield": function () {
this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
},
Expand Down
8 changes: 8 additions & 0 deletions lib/sinon/default-behaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ module.exports = {
fake.returnArgAt = pos;
},

throwsArg: function throwsArg(fake, pos) {
if (typeof pos !== "number") {
throw new TypeError("argument index is not number");
}

fake.throwArgAt = pos;
},

returnsThis: function returnsThis(fake) {
fake.returnThis = true;
},
Expand Down
3 changes: 3 additions & 0 deletions lib/sinon/spy.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ delegateToCalls("callArgOn", false, "callArgOnWith", function () {
throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
});
spyApi.callArgOnWith = spyApi.callArgOn;
delegateToCalls("throwArg", false, "throwArg", function () {
throw new Error(this.toString() + " cannot throw arg since it was not yet invoked.");
});
delegateToCalls("yield", false, "yield", function () {
throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
});
Expand Down
1 change: 1 addition & 0 deletions lib/sinon/stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ var proto = {

delete this.returnValue;
delete this.returnArgAt;
delete this.throwArgAt;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test.

delete this.fakeFn;
this.returnThis = false;

Expand Down
54 changes: 54 additions & 0 deletions test/spy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2294,6 +2294,59 @@ describe("spy", function () {
});
});

describe(".throwArg", function () {
it("should be a function", function () {
var spy = createSpy();

assert.isFunction(spy.throwArg);
});

it("should throw if spy hasn't been called", function () {
var spy = createSpy();

assert.exception(
function () {
spy.throwArg(0);
},
function (error) {
return error.message === "spy cannot throw arg since it was not yet invoked.";
}
);
});

it("should throw if there aren't enough arguments in the previous spy call", function () {
var spy = createSpy();

spy("only", "four", "arguments", "here");

assert.exception(
function () {
spy.throwArg(7);
},
function (error) {
return error.message === "Not enough arguments: 7 required but only 4 present";
}
);
});

it("should throw specified argument", function () {
var spy = createSpy();
var expectedError = new TypeError("catpants");

spy(true, false, null, expectedError, "meh");
assert.exception(
function () {
spy.throwArg(3);
},
function (error) {
return error instanceof TypeError
&& error.message === expectedError.message
;
}
);
});
});

describe(".reset", function () {
it("return same object", function () {
var spy = createSpy();
Expand Down Expand Up @@ -2328,3 +2381,4 @@ describe("spy", function () {
});
});
});

78 changes: 78 additions & 0 deletions test/stub-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,84 @@ describe("stub", function () {
});
});

describe(".throwsArg", function () {
it("throws argument at specified index", function () {
var stub = createStub.create();
stub.throwsArg(0);
var expectedError = new Error("The expected error message");

assert.exception(function () {
stub(expectedError);
}, function (err) {
return err.message === expectedError.message;
});
});

it("returns stub", function () {
var stub = createStub.create();

assert.same(stub.throwsArg(0), stub);
});

it("throws TypeError if no index is specified", function () {
var stub = createStub.create();

assert.exception(function () {
stub.throwsArg();
}, "TypeError");
});

it("should throw without enough arguments", function () {
var stub = createStub.create();
stub.throwsArg(3);

assert.exception(
function () {
stub("only", "two arguments");
},
function (error) {
return error instanceof TypeError
&& error.message ===
"throwArgs failed: 3 arguments required but only 2 present"
;
}
);

});

it("should work with call-based behavior", function () {
var stub = createStub.create();
var expectedError = new Error("catpants");

stub.returns(1);
stub.onSecondCall().throwsArg(1);

refute.exception(function () {
assert.equals(1, stub(null, expectedError));
});

assert.exception(
function () {
stub(null, expectedError);
},
function (error) {
return error.message === expectedError.message;
}
);
});

it("should be reset by .resetBeahvior", function () {
var stub = createStub.create();

stub.throwsArg(0);
stub.resetBehavior();

refute.exception(function () {
stub(new Error("catpants"));
});
});
});

describe(".returnsThis", function () {
it("stub returns this", function () {
var instance = {};
Expand Down