Tester les formulaires
Nous avons vu à l'étape précédente comment générer un code de base pour un test. Entre autres, il s'agissait d'un test pour un formulaire.
Revoici la version de base.
test('Il est possible de créer un projet', async ({ page }) => {
await page.goto('http://localhost:4200/projets');
await page.getByRole('link', { name: 'Nouveau projet' }).click();
await page.getByRole('textbox', { name: 'Nom' }).click();
await page.getByRole('textbox', { name: 'Nom' }).fill('Un projet');
await page.getByRole('textbox', { name: 'Nom' }).press('Tab');
await page.getByRole('textbox', { name: 'Description' }).fill('Une description');
await page.getByRole('button', { name: 'Soumettre' }).click();
});
Évidemment, on peut modifier l'URL complète afin de la remplacer par un chemin relatif puisque notre configuration contient déjà l'URL de base.
test('Il est possible de créer un projet', async ({ page }) => {
await page.goto('/projets');
await page.getByRole('link', { name: 'Nouveau projet' }).click();
await page.getByRole('textbox', { name: 'Nom' }).click();
await page.getByRole('textbox', { name: 'Nom' }).fill('Un projet');
await page.getByRole('textbox', { name: 'Nom' }).press('Tab');
await page.getByRole('textbox', { name: 'Description' }).fill('Une description');
await page.getByRole('button', { name: 'Soumettre' }).click();
});
Intercepter la requête POST, vérifier son contenu et retourner une réponse
Lorsque le formulaire est envoyé, on veut vérifier le contenu de la requête. On voudra aussi vérifier que l'utilisateur est redirigé.
- On peut utiliser le même principe que précédemment pour intercepter les requêtes, à l'aide de
page.route, mais en vérifiant que la requête est de typePOSTtest('il doit être possible de créer un projet', async ({ page }) => {
await page.route('http://localhost:3000/projets', (route) => {
if (route.request().method() === 'POST') {
}
});
//... - Obtenir les données du
POSTet vérifier que ces dernières correspondent à celles du formulaire.test('il doit être possible de créer un projet', async ({ page }) => {
await page.route('http://localhost:3000/projets', (route) => {
if (route.request().method() === 'POST') {
const postData = route.request().postDataJSON();
/**
* Vérifier que les données du formulaire correspondent
* à l'objet de requête attendu.
*/
expect(postData).toEqual({
nom: 'Un projet',
description: 'Une description',
});
//... - Retourner une réponse de succès ou non selon le scénario de test
test('il doit être possible de créer un projet', async ({ page }) => {
await page.route('http://localhost:3000/projets', (route) => {
if (route.request().method() === 'POST') {
const postData = route.request().postDataJSON();
/**
* Vérifier que les données du formulaire correspondent
* à l'objet de requête attendu.
*/
expect(postData).toEqual({
nom: 'Un projet',
description: 'Une description',
});
/**
* Retourner une réponse de succès
*/
route.fulfill({
status: 200,
});
}
});
//...
Vérifier un événement de navigation
Pour attendre qu'une page navigue vers une autre, on peut spécifiquement attendre pour l'URL en question et ensuite vérifier que l'URL a bien changé.
test('il doit être possible de créer un projet', async ({ page }) => {
await page.route('http://localhost:3000/projets', (route) => {
if (route.request().method() === 'POST') {
const postData = route.request().postDataJSON();
/**
* Vérifier que les données du formulaire correspondent
* à l'objet de requête attendu.
*/
expect(postData).toEqual({
nom: 'Un projet',
description: 'Une description',
});
/**
* Retourner une réponse de succès
*/
route.fulfill({
status: 200,
});
}
});
await page.goto('http://localhost:4200/projets/creer');
await page.getByPlaceholder('Nom').click();
await page.getByPlaceholder('Nom').fill('Un projet');
await page.getByPlaceholder('Nom').press('Tab');
await page.getByPlaceholder('Description').fill('Une description');
await page.getByRole('button', { name: 'Soumettre' }).click();
await page.waitForURL('http://localhost:4200/projets')
expect(page.url()).toBe('http://localhost:4200/projets');
})
Tests de cas limites ou invalides
Un bon test ne fait pas que tester les scénarios souhaités, il teste aussi les scénarios qui pourraient mener à des erreurs en s'assurant que ces erreurs sont bien gérées.
Par exemple, pour le test du formulaire, on pourrait vouloir tester que:
- Le bouton
soumettren'a aucun effet si le formulaire n'est pas valide - Des messages de validation sont affichés dans le cas où certains champs ne sont pas correctement renseignés.
Tester qu'un appel (ex.: POST) n'est pas effectué
Pour tester qu'un appel n'est pas effectué, on peut utiliser une valeur booléenne à false par défaut, mais qui serait true dans le cas où une requête POST est effectuée. Il suffirait ensuite de tester à la fin du test que la valeur est bien false.
Par exemple dans le cas où on ferait un test vérifiant que si je n'entre pas de valeur pour "nom" dans le formulaire, le formulaire n'est pas envoyé (pas de POST).
test('Il ne devrait pas être possible de créer un projet sans nom', async ({ page }) => {
let postCalled = false;
// Intercepte la requête POST vers l'URL désirée
await page.route('http://localhost:3000/projets', (route) => {
if (route.request().method() === 'POST') {
postCalled = true; // Une requête POST a été effectuée
}
route.continue(); // Continuer la requête si c'est le cas
});
// LE RESTE DU TEST
// ...
// Vérifier si la variable est bien false
expect(postCalled).toBe(false);
})
Tester les messages d'erreur
Pour tester l'affichage d'un message d'erreur au niveau du formulaire, on peut utiliser page.locator afin de cibler l'élément .invalid-feedback) et vérifier le contenu.
const erreurValidation = await page.locator('#projetNom ~ .invalid-feedback').textContent();
expect(erreurValidation).toBeTruthy();
#projetNomest leiddu input qui est vide#projetNom ~ .invalid-feedbackest un sélecteur CSS qui cible la classe.invalid-feedbackétant au même niveau que#projetNom. Voir https://developer.mozilla.org/en-US/docs/Web/CSS/Subsequent-sibling_combinator.