The function I'm looking to test receives a async function as an argument. In my argument validation I verify that it exists, is a function, and is an async function like so:
exports.consumeRecords = async (consumerFunction, records) => {
if (!consumerFunction) {
throw new Error(`Missing required argument, consumerFunction, in consumeRecords function`)
}
if (typeof consumerFunction !== 'function') {
throw new Error(`Argument, consumerFunction, is not of type 'function' in consumeRecords function. Type found: ${typeof consumerFunction}`)
}
if (args.consumerFunction.then instanceof Promise) {
throw new Error(`Argument, consumerFunction, is not a async function in consumeRecords function.`)
}
await consumerFunction(records)
// ... blah blah ..
}
My tests for the above code look like this:
describe('FUNCTION: consumeRecords', () => {
let logSpy, mockAsyncConsumerFunction
beforeEach(()=> {
mockAsyncConsumerFunction = async (recordBody) => `${recordBody} - resolved consumer`
logSpy = jest.spyOn(console, 'log').mockImplementation(() => null)
})
test('throws error when missing consumerFunction argument', async () => {
await expect(async () => await utils.consumeRecords({})).rejects.toThrow(`Missing required argument, consumerFunction,`)
})
test('throws error when consumerFunction is not a function', async () => {
await expect(async () => await utils.consumeRecords({ consumerFunction: 123 })).rejects.toThrow(`Argument, consumerFunction, is not of type 'function'`)
})
test('throws error when consumerFunction is not async function', async () => {
let syncFunction = () => console.log()
await expect(async () => await utils.consumeRecords({ consumerFunction: syncFunction })).rejects.toThrow(`Argument, consumerFunction, is not a async function`)
})
afterEach(() => {
jest.clearAllMocks()
})
afterAll(() => {
jest.restoreAllMocks()
})
})
Now, I'd like to test if consumerFunction gets called by spying on the mock, so I'm trying to do this at the top of my test:
mockAsyncConsumerFunction = async (recordBody) => `${recordBody} - resolved consumer`
mockAsyncConsumerFunctionSpy = jest.fn(mockAsyncConsumerFunction)
and then the standard assertions using the .mocks
object on the jest.fn
, like this:
test('calls consumer function correctly', async () => {
await utils.consumeRecords({ consumerFunction: mockAsyncConsumerFunctionSpy, records: [{ body: JSON.stringify({fake:111}) },{ body: JSON.stringify({fake:222}) }], taskNameString: "Apply image overlays" })
expect(mockAsyncConsumerFunctionSpy).toHaveBeenCalledWith({fake:111})
})
Unfortunately, after doing this, my test fails because it's no longer seen as an async function and thus my input validation fails, giving me:
FUNCTION: consumeRecords › calls consumer function correct number of
times
Argument, consumerFunction, is not a async function in consumeRecords function.
How can I make a mock/spy function in Jest that reads as an async function?