Search code examples
node.jstestingnode.js-tape

How do I test asynchronous function throwing error with Tape?


I'm trying to test an async function that calls an API using Tape but I don't seem to be having much luck. I've used Mocha/Chai and Jasmine before but I'm not sure how to do what I want here.

This is the function I want to test

const logicGetMovies = async (genre, page) => {

  numCheck(genre, 'genre')
  numCheck(page, 'page')
  stringCheck(process.env.API_KEY,'process.env.API_KEY')

  const url = `https://api.themoviedb.org/3/discover/movie?with_genres=${genre}&api_key=${process.env.API_KEY}&page=${page}&sort_by=vote_average.desc`

  try {
    return await axios.get(url)
  } catch (e) {
    throw new APIError(e.message)
  }
}

which relies on two helper functions that throw APIErrors (my own Error type)

const numCheck = (num, name) => {
  if (!num) throw new APIError(`${name} is missing`)
  if (typeof num !== 'number' || num <= 0) throw new APIError(`${name} must be a number greater than 0`)
}

const stringCheck = (string, name) => {
  if (!string) throw new APIError(`${name} is missing`)
  if (typeof string !== 'string') throw new APIError(`${name} must be of type string`)
}

I've tried this Tape test but it both fails and the error isn't caught

const test = require('tape')
const logic = require('../../logic')
const APIError = require('../../logic/APIError')

test('getMovies should throw error with missing genre',(t) =>{
  t.throws(logic.logicGetMovies(null,1),APIError,'genre is missing')

})

I tried changing it to async but that didn't help.

const test = require('tape')
const logic = require('../../logic')
const APIError = require('../../logic/APIError')

test('getMovies should throw error with missing genre', async (t) => {
  t.throws(logic.logicGetMovies(null, 1), APIError, 'genre is missing')
  t.end()
})

Clearly I'm lost here. Any clues or answers would be much appreciated!


Solution

  • An async function never throws an error...

    ...it returns a Promise that may reject with an error.

    So test the returned Promise to verify that it rejects with the expected error.

    You'll need to add Promise support to tape with something like tape-promise.

    Here is a simplified example:

    const tape = require('tape');
    const _test = require('tape-promise').default;
    const test = _test(tape);
    
    const func = async () => {
      throw new Error('the error');
    };
    
    test('should reject', async (t) => {
      await t.rejects(func(), Error, 'the error');  // Success!
    });