mirror of
https://github.com/nodejs/node.git
synced 2026-10-29 02:35:20 +08:00
Add t.assert.called(), t.assert.callCount(), t.assert.nthCalledWith() and t.assert.lastCalledWith() for asserting on mock function calls. Assisted-by: Claude Signed-off-by: Guilherme Araújo <arauujogui@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66476 Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: James M Snell <jasnell@gmail.com>
156 lines
3.5 KiB
JavaScript
156 lines
3.5 KiB
JavaScript
'use strict';
|
|
const {
|
|
SafeMap,
|
|
} = primordials;
|
|
const {
|
|
codes: {
|
|
ERR_INVALID_ARG_TYPE,
|
|
},
|
|
} = require('internal/errors');
|
|
const {
|
|
validateFunction,
|
|
validateInteger,
|
|
validateString,
|
|
} = require('internal/validators');
|
|
const { isDeepStrictEqual } = require('internal/util/comparisons');
|
|
const assert = require('assert');
|
|
const { AssertionError } = assert;
|
|
const methodsToCopy = [
|
|
'deepEqual',
|
|
'deepStrictEqual',
|
|
'doesNotMatch',
|
|
'doesNotReject',
|
|
'doesNotThrow',
|
|
'equal',
|
|
'fail',
|
|
'ifError',
|
|
'match',
|
|
'notDeepEqual',
|
|
'notDeepStrictEqual',
|
|
'notEqual',
|
|
'notStrictEqual',
|
|
'partialDeepStrictEqual',
|
|
'rejects',
|
|
'strictEqual',
|
|
'throws',
|
|
];
|
|
let assertMap;
|
|
|
|
function getMockContext(fn) {
|
|
const { MockFunctionContext } = require('internal/test_runner/mock/mock');
|
|
const ctx = fn?.mock;
|
|
|
|
if (!(ctx instanceof MockFunctionContext)) {
|
|
throw new ERR_INVALID_ARG_TYPE('fn', 'mock function', fn);
|
|
}
|
|
|
|
return ctx;
|
|
}
|
|
|
|
function called(fn, message) {
|
|
const count = getMockContext(fn).callCount();
|
|
|
|
if (count === 0) {
|
|
throw new AssertionError({
|
|
__proto__: null,
|
|
message: message ?? 'Expected mock function to have been called',
|
|
actual: count,
|
|
operator: 'called',
|
|
stackStartFn: called,
|
|
});
|
|
}
|
|
}
|
|
|
|
function callCount(fn, times, message) {
|
|
validateInteger(times, 'times', 0);
|
|
const count = getMockContext(fn).callCount();
|
|
|
|
if (count !== times) {
|
|
throw new AssertionError({
|
|
__proto__: null,
|
|
message: message ??
|
|
`Expected mock function to have been called ${times} times, but it was called ${count} times`,
|
|
actual: count,
|
|
expected: times,
|
|
operator: 'callCount',
|
|
stackStartFn: callCount,
|
|
});
|
|
}
|
|
}
|
|
|
|
function assertCalledWithAt(fn, n, args, stackStartFn) {
|
|
const calls = getMockContext(fn).calls;
|
|
|
|
if (n > calls.length) {
|
|
throw new AssertionError({
|
|
__proto__: null,
|
|
message: `Expected mock function to have been called at least ${n} times, ` +
|
|
`but it was called ${calls.length} times`,
|
|
actual: calls.length,
|
|
expected: n,
|
|
operator: stackStartFn.name,
|
|
stackStartFn,
|
|
});
|
|
}
|
|
|
|
const actual = calls[n - 1].arguments;
|
|
|
|
if (!isDeepStrictEqual(actual, args)) {
|
|
throw new AssertionError({
|
|
__proto__: null,
|
|
message: `Expected call ${n} of mock function to have been called with:`,
|
|
actual,
|
|
expected: args,
|
|
operator: 'deepStrictEqual',
|
|
stackStartFn,
|
|
});
|
|
}
|
|
}
|
|
|
|
function nthCalledWith(fn, n, ...args) {
|
|
validateInteger(n, 'n', 1);
|
|
assertCalledWithAt(fn, n, args, nthCalledWith);
|
|
}
|
|
|
|
function lastCalledWith(fn, ...args) {
|
|
const count = getMockContext(fn).callCount();
|
|
|
|
if (count === 0) {
|
|
throw new AssertionError({
|
|
__proto__: null,
|
|
message: 'Expected mock function to have been called',
|
|
actual: count,
|
|
operator: 'lastCalledWith',
|
|
stackStartFn: lastCalledWith,
|
|
});
|
|
}
|
|
|
|
assertCalledWithAt(fn, count, args, lastCalledWith);
|
|
}
|
|
|
|
function getAssertionMap() {
|
|
if (assertMap === undefined) {
|
|
assertMap = new SafeMap();
|
|
|
|
for (let i = 0; i < methodsToCopy.length; i++) {
|
|
assertMap.set(methodsToCopy[i], assert[methodsToCopy[i]]);
|
|
}
|
|
|
|
assertMap.set('called', called);
|
|
assertMap.set('callCount', callCount);
|
|
assertMap.set('lastCalledWith', lastCalledWith);
|
|
assertMap.set('nthCalledWith', nthCalledWith);
|
|
}
|
|
|
|
return assertMap;
|
|
}
|
|
|
|
function register(name, fn) {
|
|
validateString(name, 'name');
|
|
validateFunction(fn, 'fn');
|
|
const map = getAssertionMap();
|
|
map.set(name, fn);
|
|
}
|
|
|
|
module.exports = { getAssertionMap, register };
|