58 lines
1.2 KiB
TypeScript
58 lines
1.2 KiB
TypeScript
|
const MOCK_SYMBOL = Symbol.for("@MOCK");
|
||
|
|
||
|
export type MockCall = {
|
||
|
args: any[];
|
||
|
returned?: any;
|
||
|
thrown?: any;
|
||
|
timestamp: number;
|
||
|
returns: boolean;
|
||
|
throws: boolean;
|
||
|
};
|
||
|
|
||
|
export function fn(...stubs: Function[]) {
|
||
|
const calls: MockCall[] = [];
|
||
|
|
||
|
const f = (...args: any[]) => {
|
||
|
const stub = stubs.length === 1
|
||
|
? // keep reusing the first
|
||
|
stubs[0]
|
||
|
: // pick the exact mock for the current call
|
||
|
stubs[calls.length];
|
||
|
|
||
|
try {
|
||
|
const returned = stub ? stub(...args) : undefined;
|
||
|
calls.push({
|
||
|
args,
|
||
|
returned,
|
||
|
timestamp: Date.now(),
|
||
|
returns: true,
|
||
|
throws: false,
|
||
|
});
|
||
|
return returned;
|
||
|
} catch (err) {
|
||
|
calls.push({
|
||
|
args,
|
||
|
timestamp: Date.now(),
|
||
|
returns: false,
|
||
|
thrown: err,
|
||
|
throws: true,
|
||
|
});
|
||
|
throw err;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Object.defineProperty(f, MOCK_SYMBOL, {
|
||
|
value: { calls },
|
||
|
writable: false,
|
||
|
});
|
||
|
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
export function calls(f: Function): MockCall[] {
|
||
|
const mockInfo = (f as any)[MOCK_SYMBOL];
|
||
|
if (!mockInfo) throw new Error("callCount only available on mock functions");
|
||
|
|
||
|
return [...mockInfo.calls];
|
||
|
}
|