Jest: async / await toThrow не работает

Созданный на 15 сент. 2016  ·  21Комментарии  ·  Источник: facebook/jest

следующий тест

async function check() {
  throw new Error('Test');
}

expect(async () => 
  await check()
).toThrow();

потерпит неудачу и не поймает ошибку должным образом (я использую последнюю версию jest)

Самый полезный комментарий

Вместо того

expect(async () => await check()).toThrow()
// Jest error: "Expected the function to throw an error. But it didn't throw anything."

это работает:

expect(check()).rejects.toEqual(new Error('Test'))

Да уж, синтаксис неудобный ...

Все 21 Комментарий

Да, в настоящее время это не поддерживается. См. Https://github.com/facebook/jest/issues/1377

Вместо того

expect(async () => await check()).toThrow()
// Jest error: "Expected the function to throw an error. But it didn't throw anything."

это работает:

expect(check()).rejects.toEqual(new Error('Test'))

Да уж, синтаксис неудобный ...

Вы также можете написать:

let error;
try {
  await check();
} catch (e) {
  error = e;
}
expect(error).toEqual(new Error('Test'));

Для меня также сработало следующее:

async function check() {
  throw new Error('Test');
}

expect(check()).rejects.toEqual(new Error('Test'))

См. Https://facebook.github.io/jest/docs/en/tutorial-async.html#rejects

Добавление в список обходных путей.
Если вы, как я, хотите поймать конкретный тип ошибки и не заботитесь о сообщении:

async function check() {
  throw new SomeSpecificError('Whatever');
}

await check()
  .then(() => {
    throw new Error('Should go to .catch, not enter .then');
  })
  .catch((err) => {
    expect(err).toBeInstanceOf(SomeSpecificError);
  });
await expect(check).rejects.toThrow(SomeSpecificError);

Тоже должно работать

await expect(check).rejects.toThrow(/DUPLICATES_DETECTED/);

это то, что я делаю.

async function check() {
  throw new Error("Test");
}
await expect(check).rejects.toThrow(Error);
expect(received).rejects.toThrow()

received value must be a Promise.
Received:
 function: [Function check]

Вам нужно вызвать его, чтобы дать ему настоящее обещание

async function check() {
  throw new Error("Test");
}
await expect(check()).rejects.toThrow(Error);

Тоже должно работать

it(`some test`, async () => {
  async function check() {
    try {
      return Promise.reject(await asyncMethod());
    } catch (error) {
      throw new Error("test");
    }
  }
  await expect(check()).rejects.toThrow(Error);
});

может работать

версия

  • шутка: 23.4.2
  • ts-jest: 23.1.2

Я знаю, что для этого нужно обещание, но случай, который вы предлагаете, нет :)

Привет ! Возможно, я делаю что-то не так, но у меня все еще есть проблема с пользовательскими ошибками в асинхронных вызовах. Учтите следующее:

class CustomErrorType {}
// ...
test('check throws custom error', async () => {            
    async function check() {
        throw new CustomErrorType();
    }
    await expect(check()).rejects.toThrow(CustomErrorType);
});

тогда тест завершится ошибкой со следующим выводом:

Ожидается, что функция выдаст ошибку типа:
"CustomErrorType"
Но ничего не выкинуло.

Таким образом, тест не проходит - хотя он отлично работает, когда выбранный класс Error . Когда я пытаюсь продлить Error с помощью
`` javascript
class CustomErrorType расширяет Error {}
`` ''

тогда ошибка

Ожидается, что функция выдаст ошибку типа:
"CustomErrorType"
Вместо этого он бросил:
Ошибка

Есть какие-нибудь подсказки о том, что не так в этом образце? Я использую шутку 23.4.2.

@Marchelune Когда вы пишете class CustomErrorType extends Error {} вы фактически не определили новый класс. Если вы дадите CustomErrorType тело, даже просто конструктор, который ничего не делает, кроме вызова super (), он будет работать.

В случае, если кто-то выбрасывает что-то отличное от класса ошибки экземпляра и изо всех сил пытается использовать совет из этого потока (как я).
toThrow() проверит, какое выброшенное значение является экземпляром класса Error, и если это не так, throw не будет обнаружен. Это не было очевидно из документации и здравого смысла.
Это не удастся, даже если оно явно выбрасывает:

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toThrow()`

но это сработает (не уверен, есть ли лучший способ):

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toBeTruthy()`

@Karabur опечатка toBeThruthy должно быть toBeTruthy

Вот явный тест, который гарантирует, что он обязательно сломается, если он НЕ выдаст и не соответствует конкретной ошибке.

yourCoolAsyncMethod('yeah it is')
    .then(ok => { // Presumes not a Promise<void>
        expect(ok).toBeUndefined();
        done();
    })
    .catch(bad => {
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

Привет @SimenB.
Если у меня есть это, и он работает.

async function check() {
    // do something
}
await expect(check()).rejects.toThrow(InternalServerErrorException);

InternalServerErrorException выбрасывается с объектом ....

Как я могу также утверждать свойства при появлении ошибки? Например:

  • exception.message = 'ОШИБКА'
  • exception.status = '500'

Вот явный тест, который гарантирует, что он обязательно сломается, если он НЕ выдаст и не соответствует конкретной ошибке.

yourCoolAsyncMethod('yeah it is')
    .then(ok => {
        expect(ok).toBeUndefined();
        done();
    })
    .catch(bad => {
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

Проблема в том, что ваш тест пройдет успешно, если в коде нет ошибок.

Таким образом, этот тест не представляет особой ценности, поскольку его ожидаемые результаты зависят от того, содержит ли тестируемый код ошибку или нет.

Тесты должны иметь отрицательный или положительный поток, и мы должны тестировать только то, что необходимо для тестирования. Такая случайность не самая лучшая.

Привет, Дэвид-Теннант

Спасибо, что указали на это. В то время я работал над методом Promise<notVoid> . Я понял, что у меня нет общего решения, которое также подходит для Promise<void> . Я обновил свой ответ, добавив комментарий, в котором говорится, что я сделал предположения. Я согласен с вами насчет потока.

Спасибо 💨

Привет @futuredayv 👋

Привет, Дэвид-Теннант

Спасибо, что указали на это. В то время я работал над методом Promise<notVoid> . Я понял, что у меня нет общего решения, которое также подходит для Promise<void> . Я обновил свой ответ, добавив комментарий, в котором говорится, что я сделал предположения. Я согласен с вами насчет потока.

Спасибо 💨

Проблема в том, что ваш тест все равно пройдет, если он вернет недействительность. Что должно быть ошибкой?
Вызов done() означает: «Мой тест прошел ожидаемым образом, и я готов перейти к следующему тесту».

yourCoolAsyncMethod('yeah it is')
     // -- Lets say your method does not throw, and returns void instead
    .then(ok => { // Presumes not a Promise<void>
        expect(ok).toBeUndefined(); // -- At this point if it was void, this would pass
        done(); // -- Then your test would end and the catch would not be reached
        // -- Now you have unknown behavior passing a test where it's suppose to catch a fail
    })
    .catch(bad => {
        // -- This block does not run because done() is called above
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

Не уверен, какое решение будет для вашего варианта использования. Но я бы начал с того, что не называл done() в then или, возможно, выдавал ошибку в "then", чтобы убедиться, что тест не прошел,

yourCoolAsyncMethod('yeah it is')
    .then(ok => throw new Error("This block of code should not be reached")
    .catch(bad => {
        expect(bad).toBeDefined();
        expect(bad).toMatchInlineSnapshot(
            `Specifically serious error!`
        );

        done();
    });

В случае, если кто-то выбрасывает что-то отличное от класса ошибки экземпляра и изо всех сил пытается использовать совет из этого потока (как я).
toThrow() проверит, какое выброшенное значение является экземпляром класса Error, и если это не так, throw не будет обнаружен. Это не было очевидно из документации и здравого смысла.
Это не удастся, даже если оно явно выбрасывает:

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toThrow()`

но это сработает (не уверен, есть ли лучший способ):

async function f() {throw 'aa'}
const res = await expect(f()).rejects.toBeTruthy()`

Немного лучший способ - использовать toBeDefined() вместо toBeTruthy() :
async function f() {throw 'aa'} const res = await expect(f()).rejects.toBeTruthy()`

Была ли эта страница полезной?
0 / 5 - 0 рейтинги