title: How to spy on an async function using Jest?
body: <p>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:</p>
  <pre><code>exports.consumeRecords = async (consumerFunction, records) =&gt; {
  
      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 ..
  }
  </code></pre>
  <p>My tests for the above code look like this:</p>
  <pre><code>describe('FUNCTION: consumeRecords', () =&gt; {
      let logSpy, mockAsyncConsumerFunction
      beforeEach(()=&gt; {
          mockAsyncConsumerFunction = async (recordBody) =&gt; `${recordBody} - resolved consumer`
          logSpy = jest.spyOn(console, 'log').mockImplementation(() =&gt; null)
      })
          test('throws error when missing consumerFunction argument', async () =&gt; {
              await expect(async () =&gt; await utils.consumeRecords({})).rejects.toThrow(`Missing required argument, consumerFunction,`)
          })
          test('throws error when consumerFunction is not a function', async () =&gt; {
              await expect(async () =&gt; await utils.consumeRecords({ consumerFunction: 123 })).rejects.toThrow(`Argument, consumerFunction, is not of type 'function'`)
          })
          test('throws error when consumerFunction is not async function', async () =&gt; {
              let syncFunction = () =&gt; console.log()
              await expect(async () =&gt; await utils.consumeRecords({ consumerFunction: syncFunction })).rejects.toThrow(`Argument, consumerFunction, is not a async function`)
          })
      afterEach(() =&gt; {
          jest.clearAllMocks()
      })
      afterAll(() =&gt; {
          jest.restoreAllMocks()
      })
  })
  </code></pre>
  <p>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:</p>
  <pre><code>mockAsyncConsumerFunction = async (recordBody) =&gt; `${recordBody} - resolved consumer`
  mockAsyncConsumerFunctionSpy = jest.fn(mockAsyncConsumerFunction)
  </code></pre>
  <p>and then the standard assertions using the <code>.mocks</code> object on the <code>jest.fn</code>, like this:</p>
  <pre><code>test('calls consumer function correctly', async () =&gt; {
      await utils.consumeRecords({ consumerFunction: mockAsyncConsumerFunctionSpy, records: [{ body: JSON.stringify({fake:111}) },{ body: JSON.stringify({fake:222}) }], taskNameString: &quot;Apply image overlays&quot; })
      expect(mockAsyncConsumerFunctionSpy).toHaveBeenCalledWith({fake:111})
  })
  </code></pre>
  <p>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:</p>
  <pre><code>FUNCTION: consumeRecords › calls consumer function correct number of
   times
  
      Argument, consumerFunction, is not a async function in consumeRecords function.
  </code></pre>
  <p>How can I make a mock/spy function in Jest that reads as an async function?</p>