Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assert for an error using axios and async / await

I am trying to write a test that asserts that a specific type of error is thrown with Async / Await and axios. However, when I run my test, I get the following. Why is jest not properly rejecting my promise? Thanks!

Error: expect(received).rejects.toThrow()

Expected received Promise to reject, instead it resolved to value
{"data": "response", "status": 404}

api.js:

import axios from 'axios';
import SpecialError from './specialError.js';

const get = async () => {
  try {
    const response = await axios.get('sampleUrl', { withCredentials: true });
    return response;
  } catch (error) {
    throw new SpecialError(error);
  }
};

export default get;

specialError.js:

export default class SpecialError extends Error {
  constructor() {
    super();
    this.isSpecialError = true;
  }
}

api.test.js:

import axios from 'axios';
import get from './api';
import SpecialError from './specialError.js';

test('testing the api get method', async () => {
  axios.get.mockImplementation(() => Promise.resolve({
    data: 'response',
    status: 404,
  }));

  const expectedError = new SpecialError('foo');

  await expect(get()).rejects.toEqual(expectedError);
});
like image 277
Jimmy Avatar asked May 30 '19 23:05

Jimmy


1 Answers

axios.get is mocked to resolve to an object so get resolves to that object.

It looks like you are testing the error case, in which case axios.get should be mocked to reject:

import axios from 'axios';
import get from './code';

test('testing the api get method', async () => {
  jest.spyOn(axios, 'get').mockRejectedValue(new Error('error'));
  await expect(get()).rejects.toThrow('error');  // Success!
});

Update

OP updated the question to ask how to test for a specific kind of error.

You'll probably want to throw the error like this:

try {
  // ...
} catch (error) {
  throw new SpecialError(error.message);  // <= just use the error message
}

...and SpecialError should probably pass its args to super like this:

export default class SpecialError extends Error {
  constructor(...args) {
    super(...args);  // <= pass args to super
    this.isSpecialError = true;
  }
}

...but given those changes you can test like this:

import axios from 'axios';
import get from './api';
import SpecialError from './specialError.js';

test('testing the api get method', async () => {
  jest.spyOn(axios, 'get').mockRejectedValue(new Error('the error'));
  const promise = get();
  await expect(promise).rejects.toThrow(SpecialError);  // <= throws a SpecialError...
  await expect(promise).rejects.toThrow('the error');  // <= ...with the correct message
});

Note that testing for a particular error type and message is a bit tricky since toThrow lets you check for one or the other, but not both at the same time. You can get around this limitation by testing for each individually.

like image 111
Brian Adams Avatar answered Oct 01 '22 05:10

Brian Adams