Pourquoi Tester React avec Cypress ?
Tester React avec Cypress est une pratique cruciale pour les développeurs modernes, en particulier ceux travaillant sur des applications front-end complexes. Un développement quotidien sans tests unitaires ou d'intégration serait risqué et inefficace. Les tests aident à identifier rapidement et facilement les bugs, facilitent la maintenance du code et permettent une meilleure collaboration entre les équipes.
Un cas d'usage concret est le développement de fonctionnalités dynamiques nécessitant des états complexes. Par exemple, lorsqu'un utilisateur ajoute un nouvel article à son panier dans une application e-commerce, il est crucial de s'assurer que l'article est bien ajouté et que les quantités sont correctement gérées, même après plusieurs opérations.
Prerequis
- Connaissances en React, JSX et JavaScript ES6+
- Node.js v14.x ou supérieur
- npm (Node Package Manager)
- Cypress 7.x ou supérieur
Installation des outils
Pour installer les dépendances nécessaires, exécutez les commandes suivantes dans votre terminal :
## Installer Node.js si ce n'est pas déjà fait
## https://nodejs.org/en/download/
## Créer un nouveau projet React
npx create-react-app cypress-test-app
cd cypress-test-app
## Installer Cypress
npm install cypress --save-dev
Concepts fondamentaux
1. Cypress
Cypress est un framework d'automatisation de tests end-to-end pour les applications web. Il permet de simuler des interactions utilisateur et de vérifier l'état de l'application.
// Installer Cypress
npm install cypress --save-dev
// Lancer Cypress
npx cypress open
2. Fixtures
Les fixtures sont des fichiers JSON utilisés pour stocker des données qui peuvent être utilisées dans les tests.
Fixture (cypress/fixtures/users.json) :
[
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
},
{
"id": 2,
"name": "Jane Doe",
"email": "jane@example.com"
}
]
Test (cypress/integration/users_spec.js) :
describe('Users', () => {
it('should display the correct user name', () => {
cy.fixture('users').then(users => {
users.forEach(user => {
cy.visit('/user/' + user.id)
cy.get('.username').should('contain', user.name)
})
})
})
})
3. Commands
Les commands sont des fonctions personnalisées qui peuvent être utilisées dans les tests.
Command (cypress/support/commands.js) :
Cypress.Commands.add('login', (email, password) => {
cy.visit('/login')
cy.get('#email').type(email)
cy.get('#password').type(password)
cy.get('#submit').click()
})
Test (cypress/integration/login_spec.js) :
describe('Login', () => {
it('should log in successfully', () => {
cy.login('john@example.com', 'password123')
cy.url().should('contain', '/dashboard')
})
})
Mise en pratique : projet fil rouge
Nous allons créer un mini-projet complet et réaliste, un gestionnaire de tâches simple.
Structure du projet :
cypress-test-app/
├── public/
│ └── index.html
├── src/
│ ├── App.js
│ ├── TaskList.js
│ ├── AddTaskForm.js
│ ├── index.js
│ ├── logo.svg
│ ├── reportWebVitals.js
│ └── setupTests.js
├── cypress/
│ ├── fixtures/
│ ├── integration/
│ │ ├── tasks_spec.js
│ ├── plugins/
│ ├── support/
│ │ ├── commands.js
│ │ └── index.js
│ └── videos/
├── package.json
└── README.md
1. Création des composants
AddTaskForm.js :
import React, { useState } from 'react';
const AddTaskForm = ({ onAddTask }) => {
const [taskText, setTaskText] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (taskText.trim()) {
onAddTask(taskText);
setTaskText('');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={taskText}
onChange={(e) => setTaskText(e.target.value)}
placeholder="Ajouter une tâche..."
/>
<button type="submit">Ajouter</button>
</form>
);
};
export default AddTaskForm;
TaskList.js :
import React from 'react';
const TaskList = ({ tasks, onRemoveTask }) => {
return (
<ul>
{tasks.map((task) => (
<li key={task.id}>
{task.text}
<button onClick={() => onRemoveTask(task.id)}>Supprimer</button>
</li>
))}
</ul>
);
};
export default TaskList;
App.js :
import React, { useState } from 'react';
import AddTaskForm from './AddTaskForm';
import TaskList from './TaskList';
const App = () => {
const [tasks, setTasks] = useState([]);
const addTask = (text) => {
const newTask = {
id: Date.now(),
text
};
setTasks([...tasks, newTask]);
};
const removeTask = (id) => {
setTasks(tasks.filter((task) => task.id !== id));
};
return (
<div>
<h1>Gestionnaire de Tâches</h1>
<AddTaskForm onAddTask={addTask} />
<TaskList tasks={tasks} onRemoveTask={removeTask} />
</div>
);
};
export default App;
2. Configuration de Cypress
Command (cypress/support/commands.js) :
Cypress.Commands.add('addTask', (taskText) => {
cy.get('#add-task-form input').type(taskText);
cy.get('#add-task-form button').click();
})
Test (cypress/integration/tasks_spec.js) :
describe('Tasks', () => {
it('should add a task successfully', () => {
cy.visit('/');
cy.addTask('Faire les courses');
cy.contains('Faire les courses').should('be.visible');
});
it('should remove a task successfully', () => {
cy.visit('/');
cy.addTask('Faire la lessive');
cy.get('.task button').click();
cy.contains('Faire la lessive').should('not.exist');
});
});
3. Lancer les tests
Pour exécuter les tests, utilisez la commande suivante :
npx cypress open
Cela ouvrira l'interface de Cypress et vous permettra d'exécuter les tests.
Erreurs frequentes et debugging
1. Erreur : cy.get ne trouve pas l'élément
Code incorrect :
cy.get('.non-existent-class').click();
Code correct :
cy.get('.non-existent-class').should('exist').click();
2. Erreur : cy.contains ne trouve pas le texte
Code incorrect :
cy.contains('Task does not exist');
Code correct :
cy.contains('Task does not exist', { matchCase: false });
3. Erreur : cy.request retourne un statut non autorisé
Code incorrect :
cy.request({
method: 'POST',
url: '/api/tasks',
body: { text: 'New Task' }
});
Code correct :
cy.request({
method: 'POST',
url: '/api/tasks',
body: { text: 'New Task' },
headers: {
Authorization: 'Bearer ' + Cypress.env('token')
}
});
Pour aller plus loin
Tests Asynchrones : Apprenez à traiter les opérations asynchrones avec Cypress.
Page Objects : Structurez vos tests en utilisant des objets de page pour améliorer la lisibilité et la maintenabilité.
Plugins : Explorez les plugins Cypress pour ajouter des fonctionnalités supplémentaires.
Défi pratique
Créez un mini-projet de gestionnaire de contacts en utilisant React et Cypress. Assurez-vous d'inclure des tests pour les principales fonctionnalités, telles que l'ajout et la suppression de contacts.
Bonne chance avec votre projet !