Test del Codice Asincrono
Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →
In JavaScript è comune che il codice venga eseguito in modo asincrono. Quando hai del codice che viene eseguito in modo asincrono, Jest deve sapere quando il codice sottoposto a test ha completato l'esecuzione, prima di poter passare a un altro test. Jest offre diversi modi per gestire questa situazione.
Promise
Restituisci una promise dal tuo test e Jest attenderà che questa promise venga risolta. Se la promise viene rifiutata, il test fallirà.
Ad esempio, supponiamo che fetchData restituisca una promise che dovrebbe risolversi con la stringa 'peanut butter'. Potremmo testarla con:
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
Async/Await
In alternativa, puoi usare async e await nei tuoi test. Per scrivere un test asincrono, utilizza la keyword async davanti alla funzione passata a test. Ad esempio, lo stesso scenario con fetchData può essere testato con:
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (error) {
expect(error).toMatch('error');
}
});
Puoi combinare async e await con .resolves o .rejects.
test('the data is peanut butter', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
await expect(fetchData()).rejects.toMatch('error');
});
In questi casi, async e await sono essenzialmente zucchero sintattico per la stessa logica utilizzata nell'esempio con le promise.
Assicurati di restituire (o await) la promise - se ometti l'istruzione return/await, il test completerà prima che la promise restituita da fetchData venga risolta o rifiutata.
Se ti aspetti che una promise venga rifiutata, utilizza il metodo .catch. Assicurati di aggiungere expect.assertions per verificare che venga chiamato un certo numero di asserzioni. Altrimenti, una promise soddisfatta non farebbe fallire il test.
test('the fetch fails with an error', () => {
expect.assertions(1);
return fetchData().catch(error => expect(error).toMatch('error'));
});
Callback
Se non utilizzi le promise, puoi usare le callback. Ad esempio, supponiamo che fetchData, invece di restituire una promise, si aspetti una callback, cioè recuperi alcuni dati e chiami callback(null, data) al completamento. Vuoi verificare che i dati restituiti siano la stringa 'peanut butter'.
Per impostazione predefinita, i test di Jest si completano quando raggiungono la fine della loro esecuzione. Ciò significa che questo test non funzionerà come previsto:
// Don't do this!
test('the data is peanut butter', () => {
function callback(error, data) {
if (error) {
throw error;
}
expect(data).toBe('peanut butter');
}
fetchData(callback);
});
Il problema è che il test completerà non appena fetchData termina, senza mai chiamare la callback.
Esiste una forma alternativa di test che risolve questo problema. Invece di inserire il test in una funzione senza argomenti, utilizza un singolo argomento chiamato done. Jest attenderà che venga chiamata la callback done prima di terminare il test.
test('the data is peanut butter', done => {
function callback(error, data) {
if (error) {
done(error);
return;
}
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchData(callback);
});
Se done() non viene mai chiamata, il test fallirà (con errore di timeout), che è esattamente il comportamento desiderato.
Se l'istruzione expect fallisce, genera un errore e done() non viene chiamata. Se vogliamo vedere nel log del test perché è fallito, dobbiamo racchiudere expect in un blocco try e passare l'errore nel blocco catch a done. Altrimenti, otterremo un errore di timeout opaco che non mostra quale valore è stato ricevuto da expect(data).
Jest genererà un errore se alla stessa funzione di test viene passata una callback done() e restituisce una promise. Questa precauzione evita memory leak nei test.
.resolves / .rejects
Puoi anche utilizzare il matcher .resolves nella tua istruzione expect, e Jest attenderà che la promise venga risolta. Se la promise viene rifiutata, il test fallirà automaticamente.
test('the data is peanut butter', () => {
return expect(fetchData()).resolves.toBe('peanut butter');
});
Assicurati di restituire l'asserzione—se ometti questa istruzione return, il test completerà prima che la promise restituita da fetchData venga risolta e then() abbia la possibilità di eseguire la callback.
Se ti aspetti che una promise venga rifiutata, utilizza il matcher .rejects. Funziona in modo analogo al matcher .resolves. Se la promise viene soddisfatta, il test fallirà automaticamente.
test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toMatch('error');
});
Nessuna di queste modalità è particolarmente superiore alle altre, e puoi combinarle liberamente nello stesso progetto o persino in un singolo file. Dipende esclusivamente da quale stile ritieni renda i tuoi test più semplici.