Idéalement on aura la possibilité de tester notre API, et pas juste des modules au sein de notre API.
C'est-à-dire, on envoie des requêtes HTTP et on évalue les réponses.
Cela veut dire qu'il faut lancer notre serveur et créer de requêtes HTTPS et recevoir des réponses. Comment faire ?
Restructurer notre serveur
Pour nos tests e2e, il faudrait pouvoir lancer et arrêter dynamiquement notre serveur (comme on a fait pour le SGBDR dans la section précédente).
On va renommer server.ts à server_manager.ts, et restructurer le fichier en deux fonctions exportées, qui lance et arrête notre serveur, et retourne une référence.
exportconstStartServer=async () => {// Récupérer le port des variables d'environnement ou préciser une valeur par défautconstPORT=process.env.PORT||5050;// Créer l'objet Expressconstapp=Express();// L'appli parse le corps du message entrant comme du jsonapp.use(json());...}exportconstStopServer=async (server:Server|undefined) => {if (!server) { return; }returnnewPromise<void>( (resolve, reject) => {server.close( (err) => {if (err) {reject(err); } else {resolve(); } } ) } ); }
server.ts sert à appeler cette fonction, ainsi que répondre aux événements du système d'exploitation concernant le fait d'arrêter ou pas.
StartServer().then( (server) => {...
Avec cette structure on peut facilement lancer un serveur à partir de nos tests.
Outil pour lancer le serveur
Nous créons un outil qui permet de lancer et arrêter le serveur dans test/utility/TestServer.ts :
Ce script lance simplement le serveur et lui garde sa référence.
Vous remarquerez la variable START_HOST. En effet, nous allons lancer le serveur seulement si cette variable est présente. Pourquoi ?
Pour nos tests locaux, nous allons affecter une valeur à START_HOST pour lancer un serveur.
A terme, nous allons compiler un artifact de notre API en forme de container Docker, qui sera lancé tout seul. On aimerait lancer nos tests e2e qui vont plutôt envoyer les requêtes à ce container. Dans ce cas, pas besoin de lancer notre serveur en local.
Du coup, nous allons ajouter quelques valeurs à notre fichier test/.env.test :
# API PORT=21011API_HOST=http://localhost:21011# TESTINGSTART_HOST=true
Cela pour indiquer qu'il faut lancer le serveur. Aussi, nous précisons le port d'écoute du serveur, ainsi que l'adresse HTTP où on peut trouver notre API.
Le test e2e
Ensuite, dans un test e2e pour un utilisateur /test/e2e/suites/User.test.ts, on peut le lancer et fermer dans les hooksbefore et after :
import axios from'axios';import chai from'chai';import chaiAsPromised from'chai-as-promised';import { describe } from'mocha';import { DB } from'../../../src/utility/DB';import { RootDB } from'../../utility/RootDB';import { TestServer } from'../../utility/TestServer';chai.use(chaiAsPromised);describe("User CRUD",function () {before(asyncfunction() {// Vider la base de données de testawaitRootDB.Reset();// Lancer le serveurawaitTestServer.Start(); });after(asyncfunction() {// Forcer la fermeture de la base de donnéesawaitDB.Close();// Arreter le serveurawaitTestServer.Stop(); });it("Create a new user",asyncfunction () {constresult=awaitaxios.post(process.env.API_HOST+'/user', { familyName:"Glass", givenName:"Kevin", email:"kevin@nguni.fr", balance:0 }, { headers: { Authorization:"Bearer INSERT HERE" } } );chai.expect(result.status).to.equal(200);chai.expect(result.data.id).to.equal(1); });it("Create the same user twice returns an error",asyncfunction () {constresponse=awaitaxios.post(process.env.API_HOST+'/user', { familyName:"Glass", givenName:"Kevin", email:"kevin@nguni.fr", balance:0 }, { headers: { Authorization:"Bearer INSERT HERE" },validateStatus: (status) => { returntrue } } );chai.expect(response.status).to.equal(400);chai.expect(response.data.structured).to.equal('sql/failed'); });});
À noter, dans chaque test, on utilise la librairie axios afin de créer et envoyer des requêtes HTTP. Il faut installer le package :
npminstall--save-devaxios
Lancer nos tests e2e
Avant de lancer le test e2e, nous allons ajouter 2 scripts à notre package.json :
Comme avant, on ajoute une qui utilise env-cmd pour charger les variables d'environnement et un autre sans.
Vous pouvez maintenant lancer les tests e2e:
npmrune2e
Avec le résultat :
User CRUD
info: API Listening on port 21011 {"tag":"exec"}
2022-09-29T16:22:36.355Z 200 POST /auth/user 8 10.573
✔ Create a new user (68ms)
error: Duplicate entry 'kevin@nguni.fr' for key 'email' {"details":{"code":400,"details":{"sqlCode":"ER_DUP_ENTRY","sqlState":"23000"},"message":"Duplicate entry 'kevin@nguni.fr' for key 'email'","path":"/auth/user","structured":"sql/failed"},"tag":"exec"}
2022-09-29T16:22:36.366Z 400 POST /auth/user 175 3.291
✔ Create the same user twice returns an error
2 passing (420ms)
Notez comment on a testé une réponse négative, et qu'un code 400 est retourné.
La suite
Nos tests sont bien en place !
On est prêt à avancer dans la configuration de Continuous Integration.