Jest: async/wait toThrow funktioniert nicht

Erstellt am 15. Sept. 2016  ·  21Kommentare  ·  Quelle: facebook/jest

nächster Test

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

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

schlägt fehl und fängt Fehler nicht richtig ab (ich verwende die neueste Version von Jest)

Hilfreichster Kommentar

Anstatt von

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

das funktioniert:

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

Ja, die Syntax ist umständlich...

Alle 21 Kommentare

Ja, dies wird derzeit nicht unterstützt. Siehe https://github.com/facebook/jest/issues/1377

Anstatt von

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

das funktioniert:

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

Ja, die Syntax ist umständlich...

Sie können auch schreiben:

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

Folgendes hat bei mir auch funktioniert:

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

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

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

Hinzufügen zur Liste der Problemumgehungen.
Wenn Sie wie ich einen bestimmten Fehlertyp abfangen möchten und sich nicht um die Nachricht kümmern:

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

Sollte auch funktionieren

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

ist das, was ich tue.

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]

Sie müssen es aufrufen, um ihm das eigentliche Versprechen zu geben

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

Sollte auch funktionieren

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

kann arbeiten

Ausführung

  • Witz: 23.4.2
  • ts-scherz: 23.1.2

Ich weiß, es braucht ein Versprechen, aber der Fall, den Sie anbieten, ist es nicht :)

Hi ! Möglicherweise mache ich etwas falsch, aber ich habe immer noch ein Problem mit benutzerdefinierten Fehlern in asynchronen Aufrufen. Folgendes berücksichtigen:

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

dann schlägt der Test mit folgender Ausgabe fehl:

Erwartet, dass die Funktion einen Fehler des Typs ausgibt:
"CustomErrorType"
Aber es warf nichts.

Der Test schlägt also fehl - obwohl er perfekt funktioniert, wenn die geworfene Klasse Error . Wenn ich versuche, Error mit . zu verlängern
```javascript
Klasse CustomErrorType erweitert Error {}
````

dann ist der fehler

Erwartet, dass die Funktion einen Fehler des Typs ausgibt:
"CustomErrorType"
Stattdessen warf es:
Fehler

Irgendein Hinweis auf etwas, was in diesem Beispiel nicht stimmt? Ich benutze Scherz 23.4.2.

@Marchelune Wenn Sie class CustomErrorType extends Error {} schreiben, haben Sie keine neue Klasse definiert. Wenn Sie CustomErrorType einen Body geben, auch nur einen Konstruktor, der nichts anderes tut, als super() aufzurufen, wird es funktionieren.

Für den Fall, dass jemand etwas anderes als die Fehlerklasse der Instanz wirft und Schwierigkeiten hat, Ratschläge aus diesem Thread zu verwenden (wie ich es getan habe).
toThrow() prüft, welcher Wert die Instanz der Error-Klasse ist, und wenn nicht, wird throw nicht erkannt. Dies war aus den Dokumenten und dem gesunden Menschenverstand nicht ersichtlich.
Dies wird fehlschlagen, obwohl es eindeutig wirft:

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

aber das wird funktionieren (nicht sicher, ob es einen besseren Weg gibt):

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

@Karabur Tippfehler toBeThruthy sollte toBeTruthy

Hier ist ein expliziter Test, der sicherstellt, dass er definitiv kaputt geht, wenn er NICHT auslöst und mit einem bestimmten Fehler übereinstimmt.

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

Hallo @SimenB.
Wenn ich das habe und es funktioniert.

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

InternalServerErrorException wird mit einem Objekt ausgelöst....

Wie kann ich auch Eigenschaften für den geworfenen Fehler geltend machen? Zum Beispiel:

  • Ausnahme.Nachricht = 'FEHLER'
  • Ausnahme.status = '500'

Hier ist ein expliziter Test, der sicherstellt, dass er definitiv kaputt geht, wenn er NICHT auslöst und mit einem bestimmten Fehler übereinstimmt.

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

        done();
    });

Das Problem dabei ist, dass Ihr Test bestanden wird, wenn der Code nie Fehler aufweist.

Dieser Test würde also nicht wirklich viel Wert bieten, da die erwarteten Ergebnisse variieren, je nachdem, ob der getestete Code einen Fehler aufweist oder nicht.

Tests sollten einen negativen Flow oder einen positiven Flow haben und wir sollten nur das testen, was zum Testen benötigt wird. Diese Art von Zufälligkeit ist nicht die größte.

Hey @David-Tennant

Danke für den Hinweis. Ich arbeitete damals an einer Promise<notVoid> Methode. Mir wurde klar, dass ich keine gemeinsame Lösung habe, die auch für Promise<void> gültig ist. Ich habe meine Antwort mit einem Kommentar aktualisiert, der besagt, dass ich Annahmen gemacht habe. Beim Flow stimme ich dir zu.

Danke 💨

Hallo @futuredayv 👋

Hey @David-Tennant

Danke für den Hinweis. Ich arbeitete damals an einer Promise<notVoid> Methode. Mir wurde klar, dass ich keine gemeinsame Lösung habe, die auch für Promise<void> gültig ist. Ich habe meine Antwort mit einem Kommentar aktualisiert, der besagt, dass ich Annahmen gemacht habe. Beim Flow stimme ich dir zu.

Danke 💨

Das Problem ist, dass Ihr Test immer noch bestanden wird, wenn der Test void zurückgibt. Was sollte ein Bug sein, oder?
Der Aufruf von done() bedeutet "Mein Test wurde wie erwartet bestanden und ich bin bereit, mit meinem nächsten Test fortzufahren."

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

Sie sind sich nicht sicher, was die Lösung für Ihren Anwendungsfall wäre. Aber ich würde damit beginnen, done() im then aufzurufen oder vielleicht einen Fehler im "dann" auszulösen, um sicherzustellen, dass der Test fehlschlägt.

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

Für den Fall, dass jemand etwas anderes als die Fehlerklasse der Instanz wirft und Schwierigkeiten hat, Ratschläge aus diesem Thread zu verwenden (wie ich es getan habe).
toThrow() prüft, welcher Wert die Instanz der Error-Klasse ist, und wenn nicht, wird throw nicht erkannt. Dies war aus den Dokumenten und dem gesunden Menschenverstand nicht ersichtlich.
Dies wird fehlschlagen, obwohl es eindeutig wirft:

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

aber das wird funktionieren (nicht sicher, ob es einen besseren Weg gibt):

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

Ein etwas besserer Weg ist toBeDefined() anstelle von toBeTruthy() :
async function f() {throw 'aa'} const res = await expect(f()).rejects.toBeTruthy()`

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

samzhang111 picture samzhang111  ·  3Kommentare

nsand picture nsand  ·  3Kommentare

mmcgahan picture mmcgahan  ·  3Kommentare

hramos picture hramos  ·  3Kommentare

jardakotesovec picture jardakotesovec  ·  3Kommentare