Miguel Castillo - 15 May 2020
Testing Parte 1 - Fastify desde 0
Para ejecutar el demo de testing o que puedas probar los tests que vamos a ejecutar, debes tener el proyecto final realizado en las últimas 3 lecciones ya que los tests los hacemos a partir de ahí.
Instalar Node Tap
Node Tap es una librería para realizar tests de una forma sencilla en aplicaciones Node.js, lo vamos a ejecutar como una devDependencie
así que lo instalaremos de la siguiente forma:
npm install --dev tap
Una vez instalado, dentro de nuestro archivo package.json
vamos a crear un nuevo script
llamado test
:
// Este es un fragmento de package.json, si bajaste el template podrás observar los scripts dev y build"scripts": {"dev": "parcel ./src/index.html -d ./build","build": "parcel build ./src/index.html -d ./build","test": "tap"},
Esto va a permitirno ejecutar tap con el comando npm run test
pero antes vamos a configurar nuestro servidor de pruebas.
Servidor de pruebas
Vamos a crear un nuevo archivo llamado helper.js
, en este archivo vamos a importar la función de server.js
que crea el servidor de nuestro proyecto final para aplicarle unas modificaciones:
const buildServer = require("./server.js");// En esta función vamos a recibir como parametro// la suite de test que se estará ejecutandoconst buildTestServer = async (tap) => {// Creamos un nuevo server SIN LOGGERconst server = buildServer();/*Esta línea le indicará a tap que una vez que termine de ejecutar los tests cierre el servidor Fastify para terminar el proceso de Node.js*/tap.tearDown(() => {server.close();});// Retornamos nuestro server modificadoreturn server;};// Exportamos nuestro constructor de server de pruebasmodule.exports = buildTestServer;
Fastify inject
inject
es un método que incluye la instancia de Fastify para realizar solicitudes HTTP de prueba sin tener que iniciar el servidor en un puerto HTTP con listen
.
Las propiedades que puede recibir son:
- method: Indica el método HTTP de la solicitud: GET, POST, PUT, DELETE, etc.
- url: Ruta en la cual se va a realizar la prueba, debe iniciar desde la ruta raíz
/
. - query: Objeto con los query params de prueba a enviar, los cuales se reciben en
request.query
. - payload: Objeto con el body de prueba a enviar, los cuales se reciben en
request.body
. - headers: Cabecera de la petición que queremos agregar a la prueba.
- cookies: Cookies que queremos agregar a la prueba.
Los datos los puede retornar ya sea en modo callback o en promesa:
fastify.inject({ method: "GET", url: "/" }).then((response) => {// Hacer algo con el response}).catch((err) => {// Error al hacer la solicitud});
Y los podemos utilizar en async/await
:
const response = await fastify.inject({ method: "GET", url: "/" });
Inject va a resolver la promesa con éxito aunque tu respuesta sea 400 o 500 mientras el error haya sido bien manejado de tu parte.
El valor response
que entrega inject
tiene disponible las siguientes propiedades:
- statusCode: Código HTTP que devolvió la ruta.
- headers: Cabeceras de respuesta.
- json(): Es un método el cual devuelve el formato JSON los datos de la respuesta.
Test en tap
Algunos de los tipos de tests que podemos hacer con tap son:
ok
: Indica que el valor es válido, no null, vacio o undefined
// Como primer argumento se tiene el valor a validar y como segundo un mensaje// a mostrar cuando el test haya pasado o haya falladot.ok(valor, "El valor no es vacío");
type
: Indica que el tipo de dato esperado que debe tener el valor
// Se espera que valor sea de tipo string, como tercer argumento// se envia el mensaje cuando haya pasado o fallado el testt.type(valor, "string", "El valor debe ser string");
equal
: Indica que el valor sea el esperado
// Se espera que valor sea igual a valorEsperado, como tercer argumento// se envia el mensaje cuando haya pasado o fallado el testt.equal(valor, valorEsperado, "El valor es el valorEsperado");
deepEqual
: Indica que el valor sea el esperado, este se usa para el caso de Objetos o de Arrays para validar que igual los elementos que los contienen sean iguales
// Se espera que valor sea igual a valorEsperado, como tercer argumento// se envia el mensaje cuando haya pasado o fallado el testt.deepEqual(valorArray,valorEsperado,"El valorArray y sus elementos es igual al valorEsperado");
Crear nuestro primer test
Vamos a crear una carpeta llamada test
en la raíz del proyecto final y ahi dentro un archivo llamado index.test.js
En este archivo vamos a importar nuestro server de pruebas y la librería tap:
const tap = require("tap");const buildTestServer = require("../helper");// Iniciamos la suite de tap la cual llamaremos Fastify Firebase APItap.test("Fastify Firebase API", async (subtest) => {// Obtenemos la instancia del servidor de pruebas// Como argumento le enviamos la suite de pruebasconst server = await buildTestServer(tap);// Hacemos un subtest de nuestra ruta raíz que entrega// el HTML del proyecto Reactsubtest.test("Obtener ruta raíz", async (t) => {// Con plan, le indicamos a este subtest cuantos// tests van a ejecutarset.plan(2);// Usamos la propiedad inject especial de Fastify para// realizar pruebasconst response = await server.inject({method: "GET",url: `/`,});// Validamos que la respuesta sea un código HTTP 200t.equal(response.statusCode, 200, "Respuesta / debe ser 200");// Validamos que la cabecera content-type indique que sea un HTMLt.equal(response.headers["content-type"],"text/html; charset=UTF-8","Respuesta debe ser texto html con UTF 8");});});
Ahora ejecutamos el comando:
npm run test
Deberiamos tener una respuesta parecida del resumen del test:
> tapPASS test/index.test.js 2 OK 1s🌈 SUMMARY RESULTS 🌈Suites: 1 passed, 1 of 1 completedAsserts: 2 passed, of 2Time: 4s
Tests congelados
Si observas que los tests se quedan congelados, puede ser que hayas olvidado agregar el hook onClose
que hicimos en el proyecto final para cerrar la conexión de Firebase. Recuerda que es de la siguiente forma en tu archivo server.js
:
server.addHook("onClose", (fastify, done) => {admin.app().delete().then(() => done());});/*Si eso no llega a funcionar puedes utilizar el siguiente hookaunque no es muy recomendado:server.addHook("onClose", (fastify, done) => {process.exit(0)});*/return server;