UNPKG

@supertape/operator-stub

Version:
150 lines (102 loc) 5.38 kB
import {isStub} from '@cloudcmd/stub'; const isString = (a) => typeof a === 'string'; const getExpectedStubMessage = (fn) => `Expected stub, but received: ${fn?.toString()}`; const {stringify} = JSON; const {isArray} = Array; export const called = (operator) => (fn) => { if (!isStub(fn)) return operator.fail(getExpectedStubMessage(fn)); return operator.fail(`'t.called' is too general, looks like you need 't.calledWith' or 't.calledWithNoArgs'`); }; export const notCalled = (operator) => (fn, message = 'should not be called') => { if (!isStub(fn)) return operator.fail(getExpectedStubMessage(fn)); if (!isString(message)) return operator.fail(`'t.notCalled' expects message to be string, but received: '${stringify(message)}', looks like you need 't.notCalledWith'`); return operator.notOk(fn.called, message); }; export const calledWith = (operator) => (fn, args, message = `should be called with 'args'`) => { if (!isStub(fn)) return operator.fail(getExpectedStubMessage(fn)); if (!fn.called) return operator.fail(`Expected function to be called with arguments, but not called at all`); if (!args) return operator.fail(`You haven't provided 'args', looks like you need 't.calledWithNoArgs()'`); if (!isArray(args)) return operator.fail(`Expected 'args' to be 'array' but received: ${stringify(args)}`); const calledArgs = fn.args.at(-1); return operator.deepEqual(calledArgs, args, message); }; export const calledWithNoArgs = (operator) => (fn, message = 'should be called with no arguments') => { if (!isStub(fn)) return operator.fail(getExpectedStubMessage(fn)); if (!fn.called) return operator.fail('Expected function to be called with no arguments, but not called at all'); if (!isString(message)) return operator.fail(`'t.calledWithNoArgs' expects message to be string, but received: '${stringify(message)}', looks like you need 't.calledWith'`); const calledArgs = fn.args.at(-1); return operator.deepEqual(calledArgs, [], message); }; export const calledCount = (operator) => (fn, count, message = 'should be called') => { if (!isStub(fn)) return operator.fail(getExpectedStubMessage(fn)); return operator.equal(fn.callCount, count, message); }; export const calledOnce = (operator) => (fn, message = 'should be called once') => calledCount(operator)(fn, 1, message); export const calledTwice = (operator) => (fn, count, message = 'should be called twice') => calledCount(operator)(fn, 2, message); export const calledWithNew = (operator) => (fn, message = 'should be called with new') => { if (!isStub(fn)) return operator.fail(getExpectedStubMessage(fn)); return operator.ok(fn.calledWithNew(), message); }; const noName = ({name}) => name === 'anonymous'; export const calledBefore = (operator) => (fn1, fn2, message) => { message = message || `should call '${fn1.name}' before '${fn2.name}'`; if (!isStub(fn1)) return operator.fail(getExpectedStubMessage(fn1)); if (!isStub(fn2)) return operator.fail(getExpectedStubMessage(fn2)); if (noName(fn1) || noName(fn2)) return operator.fail(`Looks like you forget to define name of a stub, use: stub().withName('functionName')`); if (!fn1.called) return operator.fail(`Expected function '${fn1.name}' to be called before '${fn2.name}' but '${fn1.name}' not called at all`); if (!fn2.called) return operator.fail(`Expected function '${fn1.name}' to be called before '${fn2.name}' but '${fn2.name}' not called at all`); return operator.ok(fn1.calledBefore(fn2), message); }; export const calledAfter = (operator) => (fn1, fn2, message) => { message = message || `should call '${fn1.name}' after '${fn2.name}'`; if (!isStub(fn1)) return operator.fail(getExpectedStubMessage(fn1)); if (!isStub(fn2)) return operator.fail(getExpectedStubMessage(fn2)); if (noName(fn1) || noName(fn2)) return operator.fail(`Looks like you forget to define name of a stub, use: stub().withName('functionName')`); if (!fn1.called) return operator.fail(`Expected function '${fn1.name}' to be called after '${fn2.name}' but '${fn1.name}' not called at all`); if (!fn2.called) return operator.fail(`Expected function '${fn1.name}' to be called after '${fn2.name}' but '${fn2.name}' not called at all`); return operator.ok(fn1.calledAfter(fn2), message); }; export const calledInOrder = (operator) => (fns, message = 'should call in order') => { if (!isArray(fns)) return operator.fail(`Expected 'fns' to be 'array' but received: ${fns}`); let failMessage = ''; const fail = (message) => failMessage = message; const ok = (result, message) => { if (!result) failMessage = message; }; const check = calledBefore({ fail, ok, }); for (let i = 0; i < fns.length - 1; i++) { const fn1 = fns[i]; const fn2 = fns[i + 1]; check(fn1, fn2); if (failMessage) return operator.fail(failMessage); } return operator.pass(message); };