¿Cómo hacer correctamente un error de lanzamiento simulado en Jest?

4 minutos de lectura

avatar de usuario
el garçon

Estoy probando mi API GraphQL usando Jest.

Estoy usando un traje de prueba separado para cada consulta/mutación

Tengo 2 pruebas (cada una en un traje de prueba separado) donde me burlo de una función (a saber, Meteor’s callMethod) que se utiliza en mutaciones.

  it('should throw error if email not found', async () => {
    callMethod
      .mockReturnValue(new Error('User not found [403]'))
      .mockName('callMethod');

    const query = FORGOT_PASSWORD_MUTATION;
    const params = { email: 'user@example.com' };

    const result = await simulateQuery({ query, params });

    console.log(result);

    // test logic
    expect(callMethod).toBeCalledWith({}, 'forgotPassword', {
      email: 'user@example.com',
    });

    // test resolvers
  });

Cuando yo console.log(result) yo obtengo

{ data: { forgotPassword: true } }

Este comportamiento no es lo que quiero porque en .mockReturnValue Lanzo un error y por lo tanto espero result tener un objeto de error

Antes de esta prueba, sin embargo, se ejecuta otra

 it('should throw an error if wrong credentials were provided', async () => {
    callMethod
      .mockReturnValue(new Error('cannot login'))
      .mockName('callMethod');

Y funciona bien, se lanza el error.

Supongo que el problema es que el simulacro no se reinicia después de que finaliza la prueba. En mi jest.conf.js tengo clearMocks: true

Cada traje de prueba está en un archivo separado, y me burlo de las funciones antes de las pruebas como esta:

import simulateQuery from '../../../helpers/simulate-query';

import callMethod from '../../../../imports/api/users/functions/auth/helpers/call-accounts-method';

import LOGIN_WITH_PASSWORD_MUTATION from './mutations/login-with-password';

jest.mock(
  '../../../../imports/api/users/functions/auth/helpers/call-accounts-method'
);

describe('loginWithPassword mutation', function() {
...

ACTUALIZAR

Cuando sustituí .mockReturnValue con .mockImplementation todo salió como se esperaba:

callMethod.mockImplementation(() => {
  throw new Error('User not found');
});

Pero eso no explica por qué en otra prueba .mockReturnValue funciona bien…

  • Parece que tu simulacro es regresando un objeto de error, no lanzamiento eso. Sin ver su código que está probando, solo puedo compartir la experiencia que tuve. Olvidé burlarme de una función llamada en mi mutación, lo que provocó que se arrojara un error sin querer. ¿Quizás te está pasando algo similar?

    – Rhuarc13

    14 mayo 2018 a las 13:54

avatar de usuario
eduardomoroni

Cambio .mockReturnValue con .mockImplementation:

    yourMockInstance.mockImplementation(() => {
      throw new Error();
    });

por si quieres afirmar

   test('the fetch fails with an error', () => {
     return expect(fetchData()).rejects.toMatch('error');
   });

Si es una promesa también puedes .rechazar www.jestjs.io/docs/en/asynchronous#resolves–rejects

  • Frío. ¿Cómo manejarlo y hacer y afirmar?

    – Dmitro

    19 de febrero de 2021 a las 23:00

  • arroja el error pero luego la prueba falla porque ha arrojado un error. ¿cómo afirmamos?

    – schlingel

    7 de marzo a las 7:36

avatar de usuario
cara boquiabierta

Para promesas, puede usar https://jestjs.io/docs/mock-function-api#mockfnmockrejectedvaluevalue

test('async test', async () => {
  const asyncMock = jest.fn().mockRejectedValue(new Error('Async error'));

  await asyncMock(); // throws "Async error"
});

Para probar si se arrojó un error o no, puede usar https://eloquentcode.com/expect-a-function-to-throw-an-exception-in-bromea

const func = () => {
  throw new Error('my error')
}
it('should throw an error', () => {
    expect(func).toThrow()
})

  • También necesitaría probar y atrapar en su espera, de lo contrario, no se afirmaría correctamente. ¿Puede mejorar su respuesta o responder si me falta algo?

    – Desarrollador MG

    24 de noviembre de 2021 a las 16:57

  • @MGDeveloper no necesitamos try-catch durante las pruebas unitarias y usando toThrow() (jestjs.io/docs/expect#tothrowerror). Si intenta eso en sus pruebas, debería funcionar. También puede probar aquí: codesandbox.io/s/jest-playground-forked-euewe?file=/src/… (aunque el contenido de la caja de arena es transitorio). Edité la terminología de “manejo” a “prueba” si eso era confuso

    – cara boquiabierta

    27 de noviembre de 2021 a las 3:42


avatar de usuario
chico angular

Para Angular + broma:

import { throwError } from 'rxjs';

yourMockInstance.mockImplementation(() => {
  return throwError(new Error('my error message'));
});

  • Técnicamente esto no es un throw en el sentido puro de JS. Está configurando el simulacro para devolver un objeto observable RXJS que emite inmediatamente una notificación de error. Aún así, tal vez sea útil para que la gente lo vea aquí. La respuesta aceptada ciertamente voluntad hacer un simulacro arrojar un error. En todos los casos.

    – Zach Lysobey

    16 sep 2020 a las 21:57


  • solo regresando throw Error debería ser suficiente: yourMockInstance.mockImplementation(() => throwError('my error message'));

    – manzapanza

    30 abr 2021 a las 21:42

  • realmente usando mockReturnValue es suficiente: mockInstance.mockReturnValue(throwError(() => new Error('my error message')))

    – RcoderNY

    19 de junio a las 5:41

¿Ha sido útil esta solución?