mirror of
https://github.com/FlipsideCrypto/DefinitelyTyped.git
synced 2026-02-06 19:07:08 +00:00
Merge pull request #33201 from felixfbecker/sinon-spy
Infer parameter and return types for sinon.spy()
This commit is contained in:
commit
87e8022082
101
types/sinon/ts3.1/index.d.ts
vendored
101
types/sinon/ts3.1/index.d.ts
vendored
@ -145,7 +145,32 @@ declare namespace Sinon {
|
||||
calledAfter(call: SinonSpyCall): boolean;
|
||||
}
|
||||
|
||||
interface SinonSpy<TArgs extends any[] = any[], TReturnValue = any>
|
||||
/**
|
||||
* A test spy is a function that records arguments, return value,
|
||||
* the value of this and exception thrown (if any) for all its calls.
|
||||
*/
|
||||
interface SinonSpy<TArgs extends any[] = any[], TReturnValue = any> extends SinonInspectable<TArgs, TReturnValue> {
|
||||
// Methods
|
||||
(...args: TArgs): TReturnValue;
|
||||
|
||||
/**
|
||||
* Creates a spy that only records calls when the received arguments match those passed to withArgs.
|
||||
* This is useful to be more expressive in your assertions, where you can access the spy with the same call.
|
||||
* @param args Expected args
|
||||
*/
|
||||
withArgs(...args: MatchArguments<TArgs>): SinonSpy<TArgs, TReturnValue>;
|
||||
|
||||
/**
|
||||
* Set the displayName of the spy or stub.
|
||||
* @param name
|
||||
*/
|
||||
named(name: string): SinonSpy<TArgs, TReturnValue>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The part of the spy API that allows inspecting the calls made on a spy.
|
||||
*/
|
||||
interface SinonInspectable<TArgs extends any[] = any[], TReturnValue = any>
|
||||
extends Pick<
|
||||
SinonSpyCallApi<TArgs, TReturnValue>,
|
||||
Exclude<keyof SinonSpyCallApi<TArgs, TReturnValue>, 'args'>
|
||||
@ -209,9 +234,6 @@ declare namespace Sinon {
|
||||
* If the call did not explicitly return a value, the value at the call’s location in .returnValues will be undefined.
|
||||
*/
|
||||
returnValues: TReturnValue[];
|
||||
|
||||
// Methods
|
||||
(...args: any[]): any;
|
||||
/**
|
||||
* Returns true if the spy was called before @param anotherSpy
|
||||
* @param anotherSpy
|
||||
@ -232,12 +254,6 @@ declare namespace Sinon {
|
||||
* @param anotherSpy
|
||||
*/
|
||||
calledImmediatelyAfter(anotherSpy: SinonSpy): boolean;
|
||||
/**
|
||||
* Creates a spy that only records calls when the received arguments match those passed to withArgs.
|
||||
* This is useful to be more expressive in your assertions, where you can access the spy with the same call.
|
||||
* @param args Expected args
|
||||
*/
|
||||
withArgs(...args: MatchArguments<TArgs>): SinonSpy<TArgs, TReturnValue>;
|
||||
/**
|
||||
* Returns true if the spy was always called with @param obj as this.
|
||||
* @param obj
|
||||
@ -292,11 +308,6 @@ declare namespace Sinon {
|
||||
* Returns an Array with all callbacks return values in the order they were called, if no error is thrown.
|
||||
*/
|
||||
invokeCallback(...args: TArgs): void;
|
||||
/**
|
||||
* Set the displayName of the spy or stub.
|
||||
* @param name
|
||||
*/
|
||||
named(name: string): SinonSpy<TArgs, TReturnValue>;
|
||||
/**
|
||||
* Returns the nth call.
|
||||
* Accessing individual calls helps with more detailed behavior verification when the spy is called more than once.
|
||||
@ -338,7 +349,7 @@ declare namespace Sinon {
|
||||
/**
|
||||
* Spies on the provided function
|
||||
*/
|
||||
(func: Function): SinonSpy;
|
||||
<F extends (...args: any[]) => any>(func: F): SinonSpy<Parameters<F>, ReturnType<F>>;
|
||||
/**
|
||||
* Creates a spy for object.method and replaces the original method with the spy.
|
||||
* An exception is thrown if the property is not already a function.
|
||||
@ -1155,129 +1166,129 @@ declare namespace Sinon {
|
||||
* Passes if spy was never called
|
||||
* @param spy
|
||||
*/
|
||||
notCalled(spy: SinonSpy): void;
|
||||
notCalled(spy: SinonInspectable): void;
|
||||
/**
|
||||
* Passes if spy was called at least once.
|
||||
*/
|
||||
called(spy: SinonSpy): void;
|
||||
called(spy: SinonInspectable): void;
|
||||
/**
|
||||
* Passes if spy was called once and only once.
|
||||
*/
|
||||
calledOnce(spy: SinonSpy): void;
|
||||
calledOnce(spy: SinonInspectable): void;
|
||||
/**
|
||||
* Passes if spy was called exactly twice.
|
||||
*/
|
||||
calledTwice(spy: SinonSpy): void;
|
||||
calledTwice(spy: SinonInspectable): void;
|
||||
/**
|
||||
* Passes if spy was called exactly three times.
|
||||
*/
|
||||
calledThrice(spy: SinonSpy): void;
|
||||
calledThrice(spy: SinonInspectable): void;
|
||||
/**
|
||||
* Passes if spy was called exactly num times.
|
||||
*/
|
||||
callCount(spy: SinonSpy, count: number): void;
|
||||
callCount(spy: SinonInspectable, count: number): void;
|
||||
/**
|
||||
* Passes if provided spies were called in the specified order.
|
||||
* @param spies
|
||||
*/
|
||||
callOrder(...spies: SinonSpy[]): void;
|
||||
callOrder(...spies: SinonInspectable[]): void;
|
||||
/**
|
||||
* Passes if spy was ever called with obj as its this value.
|
||||
* It’s possible to assert on a dedicated spy call: sinon.assert.calledOn(spy.firstCall, arg1, arg2, ...);.
|
||||
*/
|
||||
calledOn(spyOrSpyCall: SinonSpy | SinonSpyCall, obj: any): void;
|
||||
calledOn(spyOrSpyCall: SinonInspectable | SinonSpyCall, obj: any): void;
|
||||
/**
|
||||
* Passes if spy was always called with obj as its this value.
|
||||
*/
|
||||
alwaysCalledOn(spy: SinonSpy, obj: any): void;
|
||||
alwaysCalledOn(spy: SinonInspectable, obj: any): void;
|
||||
/**
|
||||
* Passes if spy was called with the provided arguments.
|
||||
* It’s possible to assert on a dedicated spy call: sinon.assert.calledWith(spy.firstCall, arg1, arg2, ...);.
|
||||
* @param spyOrSpyCall
|
||||
* @param args
|
||||
*/
|
||||
calledWith(spyOrSpyCall: SinonSpy | SinonSpyCall, ...args: any[]): void;
|
||||
calledWith<TArgs extends any[]>(spyOrSpyCall: SinonInspectable<TArgs> | SinonSpyCall<TArgs>, ...args: MatchArguments<TArgs>): void;
|
||||
/**
|
||||
* Passes if spy was always called with the provided arguments.
|
||||
* @param spy
|
||||
* @param args
|
||||
*/
|
||||
alwaysCalledWith(spy: SinonSpy, ...args: any[]): void;
|
||||
alwaysCalledWith<TArgs extends any[]>(spy: SinonInspectable<TArgs>, ...args: MatchArguments<TArgs>): void;
|
||||
/**
|
||||
* Passes if spy was never called with the provided arguments.
|
||||
* @param spy
|
||||
* @param args
|
||||
*/
|
||||
neverCalledWith(spy: SinonSpy, ...args: any[]): void;
|
||||
neverCalledWith<TArgs extends any[]>(spy: SinonInspectable<TArgs>, ...args: MatchArguments<TArgs>): void;
|
||||
/**
|
||||
* Passes if spy was called with the provided arguments and no others.
|
||||
* It’s possible to assert on a dedicated spy call: sinon.assert.calledWithExactly(spy.getCall(1), arg1, arg2, ...);.
|
||||
* @param spyOrSpyCall
|
||||
* @param args
|
||||
*/
|
||||
calledWithExactly(
|
||||
spyOrSpyCall: SinonSpy | SinonSpyCall,
|
||||
...args: any[]
|
||||
calledWithExactly<TArgs extends any[]>(
|
||||
spyOrSpyCall: SinonInspectable<TArgs> | SinonSpyCall<TArgs>,
|
||||
...args: MatchArguments<TArgs>
|
||||
): void;
|
||||
/**
|
||||
* Passes if spy was always called with the provided arguments and no others.
|
||||
*/
|
||||
alwaysCalledWithExactly(spy: SinonSpy, ...args: any[]): void;
|
||||
alwaysCalledWithExactly<TArgs extends any[]>(spy: SinonInspectable<TArgs>, ...args: MatchArguments<TArgs>): void;
|
||||
/**
|
||||
* Passes if spy was called with matching arguments.
|
||||
* This behaves the same way as sinon.assert.calledWith(spy, sinon.match(arg1), sinon.match(arg2), ...).
|
||||
* It’s possible to assert on a dedicated spy call: sinon.assert.calledWithMatch(spy.secondCall, arg1, arg2, ...);.
|
||||
*/
|
||||
calledWithMatch(
|
||||
spyOrSpyCall: SinonSpy | SinonSpyCall,
|
||||
...args: any[]
|
||||
calledWithMatch<TArgs extends any[]>(
|
||||
spyOrSpyCall: SinonInspectable<TArgs> | SinonSpyCall<TArgs>,
|
||||
...args: TArgs
|
||||
): void;
|
||||
/**
|
||||
* Passes if spy was always called with matching arguments.
|
||||
* This behaves the same way as sinon.assert.alwaysCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...).
|
||||
*/
|
||||
alwaysCalledWithMatch(spy: SinonSpy, ...args: any[]): void;
|
||||
alwaysCalledWithMatch<TArgs extends any[]>(spy: SinonInspectable<TArgs>, ...args: TArgs): void;
|
||||
/**
|
||||
* Passes if spy was never called with matching arguments.
|
||||
* This behaves the same way as sinon.assert.neverCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...).
|
||||
* @param spy
|
||||
* @param args
|
||||
*/
|
||||
neverCalledWithMatch(spy: SinonSpy, ...args: any[]): void;
|
||||
neverCalledWithMatch<TArgs extends any[]>(spy: SinonInspectable<TArgs>, ...args: TArgs): void;
|
||||
/**
|
||||
* Passes if spy was called with the new operator.
|
||||
* It’s possible to assert on a dedicated spy call: sinon.assert.calledWithNew(spy.secondCall, arg1, arg2, ...);.
|
||||
* @param spyOrSpyCall
|
||||
*/
|
||||
calledWithNew(spyOrSpyCall: SinonSpy | SinonSpyCall): void;
|
||||
calledWithNew(spyOrSpyCall: SinonInspectable | SinonSpyCall): void;
|
||||
/**
|
||||
* Passes if spy threw any exception.
|
||||
*/
|
||||
threw(spyOrSpyCall: SinonSpy | SinonSpyCall): void;
|
||||
threw(spyOrSpyCall: SinonInspectable | SinonSpyCall): void;
|
||||
/**
|
||||
* Passes if spy threw the given exception.
|
||||
* The exception is an actual object.
|
||||
* It’s possible to assert on a dedicated spy call: sinon.assert.threw(spy.thirdCall, exception);.
|
||||
*/
|
||||
threw(spyOrSpyCall: SinonSpy | SinonSpyCall, exception: string): void;
|
||||
threw(spyOrSpyCall: SinonInspectable | SinonSpyCall, exception: string): void;
|
||||
/**
|
||||
* Passes if spy threw the given exception.
|
||||
* The exception is a String denoting its type.
|
||||
* It’s possible to assert on a dedicated spy call: sinon.assert.threw(spy.thirdCall, exception);.
|
||||
*/
|
||||
threw(spyOrSpyCall: SinonSpy | SinonSpyCall, exception: any): void;
|
||||
threw(spyOrSpyCall: SinonInspectable | SinonSpyCall, exception: any): void;
|
||||
/**
|
||||
* Like threw, only required for all calls to the spy.
|
||||
*/
|
||||
alwaysThrew(spy: SinonSpy): void;
|
||||
alwaysThrew(spy: SinonInspectable): void;
|
||||
/**
|
||||
* Like threw, only required for all calls to the spy.
|
||||
*/
|
||||
alwaysThrew(spy: SinonSpy, exception: string): void;
|
||||
alwaysThrew(spy: SinonInspectable, exception: string): void;
|
||||
/**
|
||||
* Like threw, only required for all calls to the spy.
|
||||
*/
|
||||
alwaysThrew(spy: SinonSpy, exception: any): void;
|
||||
alwaysThrew(spy: SinonInspectable, exception: any): void;
|
||||
/**
|
||||
* Uses sinon.match to test if the arguments can be considered a match.
|
||||
*/
|
||||
@ -1714,7 +1725,7 @@ declare namespace Sinon {
|
||||
createStubInstance<TType>(
|
||||
constructor: StubbableType<TType>,
|
||||
overrides?: { [K in keyof TType]?:
|
||||
SinonStubbedMember<TType[K]> | TType[K] extends (...args: any[]) => infer R ? R : TType[K] }
|
||||
SinonStubbedMember<TType[K]> | (TType[K] extends (...args: any[]) => infer R ? R : TType[K]) }
|
||||
): SinonStubbedInstance<TType>;
|
||||
}
|
||||
|
||||
|
||||
@ -83,14 +83,17 @@ function testSandbox() {
|
||||
const privateFooStubbedInstance = sb.createStubInstance(PrivateFoo);
|
||||
stubInstance.foo.calledWith('foo', 1);
|
||||
privateFooStubbedInstance.foo.calledWith();
|
||||
const clsFoo: sinon.SinonStub = stubInstance.foo;
|
||||
const privateFooFoo: sinon.SinonStub = privateFooStubbedInstance.foo;
|
||||
const clsFoo: sinon.SinonStub<[string, number], number> = stubInstance.foo;
|
||||
const privateFooFoo: sinon.SinonStub<[], void> = privateFooStubbedInstance.foo;
|
||||
const clsBar: number = stubInstance.bar;
|
||||
const privateFooBar: number = privateFooStubbedInstance.bar;
|
||||
sb.createStubInstance(cls, {
|
||||
foo: (arg1: string, arg2: number) => 2,
|
||||
foo: sinon.stub<[string, number], number>().returns(1),
|
||||
bar: 1
|
||||
});
|
||||
sb.createStubInstance(cls, {
|
||||
foo: 1, // used as return value
|
||||
});
|
||||
}
|
||||
|
||||
function testFakeServer() {
|
||||
@ -291,6 +294,50 @@ function testAssert() {
|
||||
sinon.assert.expose(obj);
|
||||
sinon.assert.expose(obj, { prefix: 'blah' });
|
||||
sinon.assert.expose(obj, { includeFail: true });
|
||||
|
||||
const typedSpy = sinon.spy((arg1: string, arg2: boolean) => 123);
|
||||
sinon.assert.notCalled(typedSpy);
|
||||
sinon.assert.called(typedSpy);
|
||||
sinon.assert.calledOnce(typedSpy);
|
||||
sinon.assert.calledTwice(typedSpy);
|
||||
sinon.assert.calledThrice(typedSpy);
|
||||
sinon.assert.callCount(typedSpy, 3);
|
||||
sinon.assert.callOrder(typedSpy, spyTwo);
|
||||
sinon.assert.calledOn(typedSpy, obj);
|
||||
sinon.assert.calledOn(typedSpy.firstCall, obj);
|
||||
sinon.assert.alwaysCalledOn(typedSpy, obj);
|
||||
sinon.assert.alwaysCalledWith(typedSpy, 'a', 'b', 'c'); // $ExpectError
|
||||
sinon.assert.alwaysCalledWith(typedSpy, 'a', true);
|
||||
sinon.assert.neverCalledWith(typedSpy, 'a', false);
|
||||
sinon.assert.neverCalledWith(typedSpy, 'a', 'b'); // $ExpectError
|
||||
sinon.assert.calledWithExactly(typedSpy, 'a', true);
|
||||
sinon.assert.calledWithExactly(typedSpy, 'a', 'b'); // $ExpectError
|
||||
sinon.assert.alwaysCalledWithExactly(typedSpy, 'a', true);
|
||||
sinon.assert.alwaysCalledWithExactly(typedSpy, 'a', 1); // $ExpectError
|
||||
sinon.assert.calledWithMatch(typedSpy, 'a', true);
|
||||
sinon.assert.calledWithMatch(typedSpy.firstCall, 'a', true);
|
||||
sinon.assert.calledWithMatch(typedSpy.firstCall, 'a', 2); // $ExpectError
|
||||
sinon.assert.alwaysCalledWithMatch(typedSpy, 'a', true);
|
||||
sinon.assert.alwaysCalledWithMatch(typedSpy, 'a', 2); // $ExpectError
|
||||
sinon.assert.neverCalledWithMatch(typedSpy, 'a', true);
|
||||
sinon.assert.neverCalledWithMatch(typedSpy, 'a', 2); // $ExpectError
|
||||
sinon.assert.calledWithNew(typedSpy);
|
||||
sinon.assert.calledWithNew(typedSpy.firstCall);
|
||||
sinon.assert.threw(typedSpy);
|
||||
sinon.assert.threw(typedSpy.firstCall);
|
||||
sinon.assert.threw(typedSpy, 'foo error');
|
||||
sinon.assert.threw(typedSpy.firstCall, 'foo error');
|
||||
sinon.assert.threw(typedSpy, new Error('foo'));
|
||||
sinon.assert.threw(typedSpy.firstCall, new Error('foo'));
|
||||
sinon.assert.alwaysThrew(typedSpy);
|
||||
sinon.assert.alwaysThrew(typedSpy, 'foo error');
|
||||
sinon.assert.alwaysThrew(typedSpy, new Error('foo'));
|
||||
sinon.assert.match('a', 'b');
|
||||
sinon.assert.match(1, 1 + 1);
|
||||
sinon.assert.match({ a: 1 }, { b: 2, c: 'abc' });
|
||||
sinon.assert.expose(obj);
|
||||
sinon.assert.expose(obj, { prefix: 'blah' });
|
||||
sinon.assert.expose(obj, { includeFail: true });
|
||||
}
|
||||
|
||||
function testTypedSpy() {
|
||||
@ -329,7 +376,7 @@ function testTypedSpy() {
|
||||
}
|
||||
|
||||
function testSpy() {
|
||||
const fn = () => { };
|
||||
let fn = (arg: string, arg2: number): boolean => true;
|
||||
const obj = class {
|
||||
foo() { }
|
||||
set bar(val: number) { }
|
||||
@ -337,12 +384,11 @@ function testSpy() {
|
||||
};
|
||||
const instance = new obj();
|
||||
|
||||
let spy = sinon.spy();
|
||||
const spy = sinon.spy(); // $ExpectType SinonSpy<any[], any>
|
||||
const spyTwo = sinon.spy().named('spyTwo');
|
||||
|
||||
spy = sinon.spy(fn);
|
||||
spy = sinon.spy(instance, 'foo');
|
||||
spy = sinon.spy(instance, 'bar', ['set', 'get']);
|
||||
const methodSpy = sinon.spy(instance, 'foo');
|
||||
const methodSpy2 = sinon.spy(instance, 'bar', ['set', 'get']);
|
||||
|
||||
let count = 0;
|
||||
count = spy.callCount;
|
||||
@ -360,7 +406,12 @@ function testSpy() {
|
||||
arr = spy.exceptions;
|
||||
arr = spy.returnValues;
|
||||
|
||||
spy('a', 'b');
|
||||
const fnSpy = sinon.spy(fn); // $ExpectType SinonSpy<[string, number], boolean>
|
||||
fn = fnSpy; // Should be assignable to original function
|
||||
fnSpy('a', 1); // $ExpectType boolean
|
||||
fnSpy.args; // $ExpectType [string, number][]
|
||||
fnSpy.returnValues; // $ExpectType boolean[]
|
||||
|
||||
spy(1, 2);
|
||||
spy(true);
|
||||
|
||||
@ -424,14 +475,13 @@ function testSpy() {
|
||||
|
||||
function testStub() {
|
||||
const obj = class {
|
||||
foo() { }
|
||||
foo(arg: string): number { return 1; }
|
||||
promiseFunc() { return Promise.resolve('foo'); }
|
||||
promiseLikeFunc() { return Promise.resolve('foo') as PromiseLike<string>; }
|
||||
};
|
||||
const instance = new obj();
|
||||
|
||||
let stub = sinon.stub();
|
||||
stub = sinon.stub(instance, 'foo').named('namedStub');
|
||||
const stub = sinon.stub();
|
||||
|
||||
const spy: sinon.SinonSpy = stub;
|
||||
|
||||
@ -492,6 +542,25 @@ function testStub() {
|
||||
stub.yieldsToAsync('foo', 'a', 2);
|
||||
stub.yieldsToOnAsync('foo', instance, 'a', 2);
|
||||
stub.withArgs('a', 2).returns(true);
|
||||
|
||||
// Type-safe stubs
|
||||
const stub2 = sinon.stub(instance, 'foo').named('namedStub');
|
||||
instance.foo = stub2; // Should be assignable to original
|
||||
stub2.returns(true); // $ExpectError
|
||||
stub2.returns(5);
|
||||
stub2.returns('foo'); // $ExpectError
|
||||
stub2.callsFake((arg: string) => 1);
|
||||
stub2.callsFake((arg: number) => 1); // $ExpectError
|
||||
stub2.callsFake((arg: string) => 'a'); // $ExpectError
|
||||
stub2.onCall(1).returns(2);
|
||||
stub2.withArgs('a', 2).returns('true'); // $ExpectError
|
||||
stub2.withArgs('a').returns(1);
|
||||
stub2.withArgs('a').returns('a'); // $ExpectError
|
||||
|
||||
const pStub = sinon.stub(instance, 'promiseFunc');
|
||||
pStub.resolves();
|
||||
pStub.resolves('foo');
|
||||
pStub.resolves(1); // $ExpectError
|
||||
}
|
||||
|
||||
function testTypedStub() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user