javascript - Kan du skriva asynkrona test som förväntar sig att kasta ett undantag?
Jag skriver ett asynkront test som förväntar sig att den asynkrona funktionen kastar ett undantag på det här sättet:
it("expects to have failed", async () => {
let getBadResults = async () => {
await failingAsyncTest()
}
expect(await getBadResults()).toThrow()
})
Men jest misslyckas bara istället för att klara testet:
FAIL src/failing-test.spec.js
● expects to have failed
Failed: I should fail!
Om jag skriver om testet så att det ser ut så här:
expect(async () => {
await failingAsyncTest()
}).toThrow()
Jag får detta fel istället för ett godkänt test:
expect(function).toThrow(undefined)
Expected the function to throw an error.
But it didn't throw anything.
Svar #1
Du kan testa din asynkrona funktion så här:
it('should test async errors', async () => {
await expect(failingAsyncTest())
.rejects
.toThrow('I should fail');
});
Strängen ''I should fail'' kommer att matcha vilken del som helst av det fel som kastas.
Svar #2
Jag skulle vilja bara tillägga detta och säga att funktionen du testar måste kasta ett faktiskt Error-objekt throw new Error(...). Jest verkar inte känna igen om du bara kastar ett uttryck som throw 'Ett fel uppstod!'.
Svar #3
await expect(async () => {
await someAsyncFunction(someParams);
}).rejects.toThrowError("Some error message");
Vi måste kapsla in koden i en funktion för att fånga felet. Här förväntar vi oss att felmeddelandet som kastas från someAsyncFunction ska vara lika med "Some error message". Vi kan också kalla på undantagshanteraren
await expect(async () => {
await someAsyncFunction(someParams);
}).rejects.toThrowError(new InvalidArgumentError("Some error message"));
Läs mer https://jestjs.io/docs/expect#tothrowerror
Svar #4
Anpassad felklass
Användningen av rejects.toThrow kommer inte att fungera för dig. Istället kan du kombinera rejects-metoden med toBeInstanceOf-matchern för att matcha det anpassade fel som har kastats.
Exempel
it("should test async errors", async () => {
await expect(asyncFunctionWithCustomError()).rejects.toBeInstanceOf(
CustomError
)
})
Svar #5
Om du vill testa att en asynkron funktion INTE kastar:
it('async function does not throw', async () => {
await expect(hopefullyDoesntThrow()).resolves.not.toThrow();
});
Ovanstående test kommer att gå igenom oavsett vilket värde som returneras, även om det är undefined.
Tänk på att om en async-funktion kastar ett fel, så kommer det egentligen tillbaka som en Promise Rejection i Node, inte ett fel (därför, om du inte har try/catch-block kommer du att få en UnhandledPromiseRejectionWarning, något annorlunda än ett fel). Så, som andra har sagt, det är därför du använder antingen:
.rejectsoch.resolvesmetoder, eller entry/catch-block inom dina tester.
Referens: https://jestjs.io/docs/asynchronous#asyncawait
Svar #6
För att kunna göra många testförhållanden utan att behöva lösa löftet varje gång, fungerar detta också:
it('throws an error when it is not possible to create an user', async () => {
const throwingFunction = () => createUser(createUserPayload)
// This is what prevents the test to succeed when the promise is resolved and not rejected
expect.assertions(3)
await throwingFunction().catch(error => {
expect(error).toBeInstanceOf(Error)
expect(error.message).toMatch(new RegExp('Could not create user'))
expect(error).toMatchObject({
details: new RegExp('Invalid payload provided'),
})
})
})
