En este capítulo vamos a ver cómo escribir pruebas automatizadas para tus aplicaciones de Express. Vamos a ver cómo crear pruebas para las rutas y pruebas de sistema (que incluyen desde la interacción en el navegador hasta la base de datos).
Probando las rutas
Asumiendo que ya has incluído Express, el primer paso es incluir las librerías que vamos a utilizar para hacer las pruebas: Jest, Supertest y Superagent:
# npm
$ npm install jest supertest superagent --save-dev
El siguiente paso es separar la aplicación del servidor. Por ejemplo, la aplicación puede estar en app.js:
Y en server.js requerimos app.js y prendemos el servidor:
constapp=require('./app');app.listen(3000,()=>console.log('Listening on port 3000!'));
De esa forma vamos a importar app.js para realizar las pruebas de nuestras rutas.
En el archivo app.test.js escribe las pruebas:
constrequest=require('supertest');constapp=require('./app');describe('/',()=>{test('GET responds with success code',async()=>{constresponse=awaitrequest(app).get('/');expect(response.statusCode).toBe(200);});});
Revisa que tu package.json tenga configurado el script de pruebas con la opción --forceExit:
Y ejecuta las pruebas con el siguiente comando:
MongoDB
Si estás utilizando MongoDB utiliza una variable de entorno en la aplicación para pasarle la URL de conexión:
Modifica package.json para que la prueba se ejecute con otra base de datos:
Nota: No olvides cambiar <dev-db-name> y <test-db-name> con los nombres de tu base de datos de desarrollo y pruebas respectivamente.
Y en la prueba agrega lo siguiente:
En la primera línea estamos requiriendo Mongoose (esto lo debes agregar con los demás require).
En la línea 3 agregamos un beforeEach con una función que se va a ejecutar antes de cada prueba y que va a limpiar todas las colecciones de la base de datos.
En la línea 11 agregamos un afterAll con una función que se va a ejecutar después de todas las pruebas y que va a desconectarse de Mongoose.
Autenticación
Para probar rutas que requieren autenticación podemos crear un método de ayuda que realiza la autenticación antes de ejecutar el resto de nuestra prueba. Por ejemplo, en una prueba podemos tener el siguiente código:
En la línea 13 creamos un método signIn que se va a encargar de autenticar al usuario haciendo POST a /login. Después tenemos dos pruebas, una que verifica que el usuario sea redirigido a /login si no está autenticado y otra que permita el acceso si está autenticado.
Pruebas de sistema
Las pruebas de sistema se utilizan para probar la interacción desde el navegador hasta la base de datos. Son el tipo de pruebas más completas, aunque también las más lentas.
"scripts": {
"test": "MONGODB_URI=mongodb://localhost:27017/<test-db-name> jest --forceExit"
},
const mongoose = require("mongoose");
beforeEach(async () => {
// antes de cada prueba limpiamos todas las colecciones para iniciar con una
// base de datos en blanco
for (var i in mongoose.connection.collections) {
await mongoose.connection.collections[i].remove({});
}
});
afterAll(async () => {
await mongoose.disconnect();
});
const request = require('supertest');
const mongoose = require("mongoose");
const User = require("./User");
const app = require('./app');
// Esto soluciona un issue de Jest con las cookies en Superagent. Ver
// https://github.com/facebook/jest/issues/2549
request.agent.prototype._saveCookies = function(res) {
const cookies = res.headers['set-cookie'];
if (cookies) this.jar.setCookies(cookies[0].split(","));
};
const signIn = async (credentials) => {
const agent = request.agent(app);
await agent.post('/login')
.type("form")
.send(credentials);
return agent;
}
describe("GET /private", () => {
test("redirects to login if not authenticated", async () => {
const response = await request(app).get('/polls');
expect(response.statusCode).toBe(302);
expect(response.headers.location).toBe("/login");
});
test("responds with success code if authenticated", async () => {
const credentials = { email: "pedro@gmail.com", password: "test1234" };
const user = await User.create(credentials);
const agent = await signIn(credentials);
const response = await agent.get("/private");
expect(response.statusCode).toBe(200);
});
});