2024-01-01 21:11:32 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2024-04-10 02:43:44 +00:00
|
|
|
// This module is browser compatible.
|
2023-11-21 14:52:38 +00:00
|
|
|
// Copyright 2019 Allain Lalonde. All rights reserved. ISC License.
|
|
|
|
// deno-lint-ignore-file no-explicit-any ban-types
|
|
|
|
|
2024-05-23 11:20:11 +00:00
|
|
|
/**
|
|
|
|
* This module contains a function to mock functions for testing and assertions.
|
|
|
|
*
|
|
|
|
* ```ts
|
|
|
|
* import { fn, expect } from "@std/expect";
|
|
|
|
*
|
|
|
|
* Deno.test("example", () => {
|
|
|
|
* const mockFn = fn((a: number, b: number) => a + b);
|
|
|
|
* const result = mockFn(1, 2);
|
|
|
|
* expect(result).toEqual(3);
|
|
|
|
* expect(mockFn).toHaveBeenCalledWith(1, 2);
|
|
|
|
* expect(mockFn).toHaveBeenCalledTimes(1);
|
|
|
|
* });
|
|
|
|
* ```
|
2024-07-22 03:17:47 +00:00
|
|
|
*
|
|
|
|
* @module
|
2024-05-23 11:20:11 +00:00
|
|
|
*/
|
|
|
|
|
2024-02-27 21:57:25 +00:00
|
|
|
import { MOCK_SYMBOL, type MockCall } from "./_mock_util.ts";
|
2023-11-21 14:52:38 +00:00
|
|
|
|
2024-05-23 11:20:11 +00:00
|
|
|
/**
|
|
|
|
* Creates a mock function that can be used for testing and assertions.
|
|
|
|
*
|
2024-07-22 03:17:47 +00:00
|
|
|
* @param stubs Functions to be used as stubs for different calls.
|
2024-05-23 11:20:11 +00:00
|
|
|
* @returns A mock function that keeps track of calls and returns values based on the provided stubs.
|
|
|
|
*
|
2024-06-03 04:10:27 +00:00
|
|
|
* @example Usage
|
|
|
|
* ```ts no-assert
|
2024-05-23 11:20:11 +00:00
|
|
|
* import { fn, expect } from "@std/expect";
|
|
|
|
*
|
|
|
|
* Deno.test("example", () => {
|
|
|
|
* const mockFn = fn(
|
|
|
|
* (a: number, b: number) => a + b,
|
|
|
|
* (a: number, b: number) => a - b
|
|
|
|
* );
|
|
|
|
* const result = mockFn(1, 2);
|
|
|
|
* expect(result).toEqual(3);
|
|
|
|
* expect(mockFn).toHaveBeenCalledWith(1, 2);
|
|
|
|
* expect(mockFn).toHaveBeenCalledTimes(1);
|
|
|
|
*
|
|
|
|
* const result2 = mockFn(3, 2);
|
|
|
|
* expect(result2).toEqual(1);
|
|
|
|
* expect(mockFn).toHaveBeenCalledWith(3, 2);
|
|
|
|
* expect(mockFn).toHaveBeenCalledTimes(2);
|
|
|
|
* });
|
|
|
|
* ```
|
|
|
|
*/
|
2023-12-19 00:26:13 +00:00
|
|
|
export function fn(...stubs: Function[]): Function {
|
2023-11-21 14:52:38 +00:00
|
|
|
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;
|
|
|
|
}
|