Un exemple Async
Tout d’abord, activez le support de Babel dans Jest comme indiqué dans le guide Mise en route.
Implémentons un module qui récupère les données utilisateur d'une API et retourne le nom de l'utilisateur.
import request from './request';
export function getUserName(userID) {
return request(`/users/${userID}`).then(user => user.name);
}
Dans l'implémentation ci-dessus, nous attendons du module request.js
qu'il renvoie une promesse. Nous enchaînons un appel à then
pour recevoir le nom de l'utilisateur.
Imaginez maintenant une implémentation de request.js
qui se connecte au réseau et récupère certaines données utilisateur :
const http = require('http');
export default function request(url) {
return new Promise(resolve => {
// Ceci est un exemple de requête http, par exemple pour récupérer
// des données utilisateur à partir d'une API.
// Ce module est simulé dans __mocks__/request.js
http.get({path: url}, response => {
let data = '';
response.on('data', _data => (data += _data));
response.on('end', () => resolve(data));
});
});
}
Comme nous ne voulons pas aller sur le réseau dans notre test, nous allons créer un simulateur manuel pour notre module request.js
dans le dossier __mocks__
(le dossier est sensible à la casse, __MOCKS__
ne fonctionnera pas). Il pourrait ressembler à ceci :
const users = {
4: {name: 'Mark'},
5: {name: 'Paul'},
};
export default function request(url) {
return new Promise((resolve, reject) => {
const userID = parseInt(url.substr('/users/'.length), 10);
process.nextTick(() =>
users[userID]
? resolve(users[userID])
: reject({
error: `Utilisateur avec ${userID} non trouvé.`,
}),
);
});
}
Maintenant, écrivons un test pour notre fonctionnalité asynchrone.
jest.mock('../request');
import * as user from '../user';
// L'assertion d'une promesse doit être retournée.
it('works with promises', () => {
expect.assertions(1);
return user.getUserName(4).then(data => expect(data).toBe('Mark'));
});
Nous appelons jest.mock('../request')
pour dire à Jest d'utiliser notre simulateur manuel. it
s'attend à ce que la valeur de retour soit une promesse qui va être résolue. Vous pouvez enchaîner autant de promesses que vous le souhaitez et appeler expect
à tout moment, tant que vous retournez une promesse à la fin.
.resolves
Il existe un moyen moins verbeux utilisant resolves
pour décortiquer la valeur d'une promesse remplie avec tout autre comparateur. Si la promesse est rejetée, l'assertion échouera.
it('works with resolves', () => {
expect.assertions(1);
return expect(user.getUserName(5)).resolves.toBe('Paul');
});
async
/await
L'écriture de tests utilisant la syntaxe async
/await
est également possible. Voici comment écrire les mêmes exemples que précédemment :
// async/wait peut être utilisé.
it('works with async/await', async () => {
expect.assertions(1);
const data = await user.getUserName(4);
expect(data).toBe('Mark');
});
// async/await can also be used with `.resolves`.
it('works with async/await and resolves', async () => {
expect.assertions(1);
await expect(user.getUserName(5)).resolves.toBe('Paul');
});
Pour activer async/await dans votre projet, installez @babel/preset-env
et activez la fonctionnalité dans votre fichier babel.config.js
.
Gestion des erreurs
Les erreurs peuvent être traitées en utilisant la méthode .catch
. Assurez-vous de rajouter expect.assertions
pour vérifier qu'un certain nombre d'assertions sont appelées. Sinon une promesse accomplie ne passerait pas le test :
// Tests d'erreurs asynchrones en utilisant Promise.catch.
it('teste l'erreur avec des promesses', () => {
expect.assertions(1);
return user.getUserName(2).catch(e =>
expect(e).toEqual({
error: 'Utilisateur avec 2 non trouvé.',
}),
);
});
// Ou en utilisant async/await.
it('teste l'erreur avec async/await', async () => {
expect.assertions(1);
try {
await user.getUserName(1);
} catch (e) {
expect(e).toEqual({
error: 'Utilisateur avec 1 non trouvé.',
});
}
});
.rejects
La fonction d'aide .rejects
fonctionne comme la fonction d'aide .resolves
. Si la promesse est accomplie, le test échoue automatiquement. expect.assertions(number)
n'est pas obligatoire mais recommandé pour vérifier qu'un certain nombre d'assertions sont appelées pendant un test. Il est par ailleurs facile d'oublier de return
/await
les assertions .resolves
.
// Tests d'erreurs asynchrones en utilisant `.rejects`.
it('teste l'erreur avec rejects', () => {
expect.assertions(1);
return expect(user.getUserName(3)).rejects.toEqual({
error: 'Utilisateur avec 3 non trouvé.',
});
});
// Ou en utilisant async/await avec `.rejects`.
it('teste l'erreur avec async/await et rejects', async () => {
expect.assertions(1);
await expect(user.getUserName(3)).rejects.toEqual({
error: 'Utilisateur avec 3 non trouvé.',
});
});
The code for this example is available at examples/async.
Si vous souhaitez tester les minuteurs, comme setTimeout
, jetez un coup d'œil à la documentation simulateurs de temporisation.