Jest: async/ wait toThrow ne fonctionne pas

Créé le 15 sept. 2016  ·  21Commentaires  ·  Source: facebook/jest

prochain essai

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

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

échouera et ne détectera pas correctement les erreurs (j'utilise la dernière version de jest)

Commentaire le plus utile

À la place de

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

cela marche:

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

Oui la syntaxe est maladroite...

Tous les 21 commentaires

Oui, ce n'est pas pris en charge actuellement. Voir https://github.com/facebook/jest/issues/1377

À la place de

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

cela marche:

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

Oui la syntaxe est maladroite...

Vous pouvez également écrire :

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

Les éléments suivants ont également fonctionné pour moi :

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

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

Voir : https://facebook.github.io/jest/docs/en/tutorial-async.html#rejects

Ajout à la liste des solutions de contournement.
Si, comme moi, vous voulez détecter un type d'erreur spécifique et ne vous souciez pas du message :

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);

Devrait fonctionner aussi

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

est ce que je fais.

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]

Vous devez l'invoquer pour lui donner la promesse réelle

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

Devrait fonctionner aussi

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);
});

peut marcher

version

  • blague : 23.4.2
  • ts-blague : 23.1.2

Je sais qu'il faut une promesse, mais le cas que vous proposez ne l'est pas :)

Salut ! Je fais peut-être quelque chose de mal, mais j'ai toujours un problème avec les erreurs personnalisées dans les appels asynchrones. Considérer ce qui suit:

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

alors le test échoue avec la sortie suivante :

Attendu que la fonction renvoie une erreur de type :
"CustomErrorType"
Mais ça n'a rien jeté.

Le test échoue donc - alors qu'il fonctionne parfaitement lorsque la classe lancée est Error . Lorsque j'essaie d'étendre Error avec
```javascript
la classe CustomErrorType étend l'erreur {}
````

alors l'erreur est

Attendu que la fonction renvoie une erreur de type :
"CustomErrorType"
Au lieu de cela, il a lancé:
Erreur

Un indice sur quelque chose qui ne va pas dans cet échantillon? J'utilise jest 23.4.2.

@Marchelune Lorsque vous écrivez class CustomErrorType extends Error {} vous n'avez pas réellement défini de nouvelle classe. Si vous donnez à CustomErrorType un corps, même juste un constructeur qui ne fait rien d'autre qu'appeler super(), cela fonctionnera.

Au cas où quelqu'un lancerait quelque chose de différent de la classe d'erreur d'instance et aurait du mal à utiliser les conseils de ce fil (comme je l'ai fait).
toThrow() vérifiera quelle valeur levée est l'instance de la classe Error, et si ce n'est pas le cas, throw ne sera pas détecté. Ce n'était pas évident d'après la doc et le bon sens.
Cela échouera, même si cela renvoie clairement :

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

mais cela fonctionnera (je ne sais pas s'il existe un meilleur moyen):

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

@Karabur faute toBeThruthy frappe toBeTruthy

Voici un test explicite qui garantit qu'il se brisera définitivement s'il ne lance PAS et ne correspond pas à une erreur spécifique.

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();
    });

Salut @SimenB.
Si j'ai ça et que ça marche.

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

InternalServerErrorException est levée avec un objet....

Comment puis-je également affirmer des propriétés sur l'erreur levée? Par exemple:

  • exception.message = 'ERREUR'
  • exception.status = '500'

Voici un test explicite qui garantit qu'il se brisera définitivement s'il ne lance PAS et ne correspond pas à une erreur spécifique.

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

        done();
    });

Le problème à ce sujet est que votre test réussira si le code n'a jamais d'erreurs.

Donc, ce test n'offrirait pas vraiment beaucoup de valeur car ses résultats attendus varient selon que le code qu'il teste comporte une erreur ou non.

Les tests doivent avoir un flux négatif ou un flux positif et nous ne devons tester que ce qui est nécessaire pour tester. Ce genre d'aléatoire n'est pas le plus grand.

Salut @David-Tennant

Merci de l'avoir signalé. Je travaillais sur une méthode Promise<notVoid> à l'époque. J'ai réalisé que je ne partageais pas de solution commune qui soit également valable pour Promise<void> . J'ai mis à jour ma réponse avec un commentaire disant que j'ai fait des hypothèses. Je suis d'accord avec toi pour le débit.

Merci

Salut @futuredayv

Salut @David-Tennant

Merci de l'avoir signalé. Je travaillais sur une méthode Promise<notVoid> à l'époque. J'ai réalisé que je ne partageais pas de solution commune qui soit également valable pour Promise<void> . J'ai mis à jour ma réponse avec un commentaire disant que j'ai fait des hypothèses. Je suis d'accord avec toi pour le débit.

Merci

Le problème est que votre test réussira toujours si le test retourne void. Qu'est-ce qui devrait être un bug, n'est-ce pas ?
Appeler done() signifie "Mon test a réussi comme prévu et je suis prêt à passer à mon prochain test"

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();
    });

Je ne sais pas quelle serait la solution pour votre cas d'utilisation. Mais je commencerais par ne pas appeler done() dans le then ou peut-être lancer une erreur dans le "then" pour m'assurer que le test échoue,

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();
    });

Au cas où quelqu'un lancerait quelque chose de différent de la classe d'erreur d'instance et aurait du mal à utiliser les conseils de ce fil (comme je l'ai fait).
toThrow() vérifiera quelle valeur levée est l'instance de la classe Error, et si ce n'est pas le cas, throw ne sera pas détecté. Ce n'était pas évident d'après la doc et le bon sens.
Cela échouera, même si cela renvoie clairement :

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

mais cela fonctionnera (je ne sais pas s'il existe un meilleur moyen):

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

Une façon légèrement meilleure est d'utiliser toBeDefined() au lieu de toBeTruthy() :
async function f() {throw 'aa'} const res = await expect(f()).rejects.toBeTruthy()`

Cette page vous a été utile?
0 / 5 - 0 notes