Tu primera experiencia con Node.js

1

¿Dónde aprender backend con Node.js actualizado?

2

Todo lo que aprenderás sobre backend con Node.js

3

¿Qué es Node.js?

4

¿Qué es Node.js y para qué sirve?

5

Diferencias entre Node.js y JavaScript

6

Resumen: Diferencias Nodejs y Javascript

7

Instalación de Node.js

8

Arquitectura orientada a eventos

9

Node.js para la web

Manejo y uso de Streams con Node.js

10

Introducción a streams

11

Readable y Writable streams

12

Duplex y Transforms streams

Uso de utilidades de Node.js

13

Sistema operativo y sistema de archivos

14

Administrar directorios y archivos

15

Consola, utilidades y debugging

16

Clusters y procesos hijos

Crea tu primer proyecto en Express.js

17

¿Qué es Express.js y para qué sirve?

18

Creando tu primer servidor con Express.js

19

Request y Response Objects

Aprende a crear un API con REST

20

Anatomía de una API Restful

21

Estructura de una película con Moockaru

22

Implementando un CRUD en Express.js

23

Métodos idempotentes del CRUD

24

Implementando una capa de servicios

Cómo conectarse con librerías externas en Express.js

25

Creación de una BD en MongoAtlas

26

Conexión a MongoAtlas una instancia de MongoDB

27

Conexión con Robot3T y MongoDB Compass a una BD

28

Implementación de las acciones de MongoDB

29

Conexión de nuestros servicios con MongoDB

Conoce como funcionan los Middleware en Express.js

30

¿Qué es un middleware? Capa de manejo de errores usando un middleware

31

Manejo de errores asíncronos y síncronos en Express

32

Capa de validación de datos usando un middleware

33

¿Qué es Joi y Boom?

34

Implementando Boom

35

Implementando Joi

36

Probar la validación de nuestros endpoints

37

Middlewares populares en Express.js

Implementa tests en Node.js

38

Creación de tests para nuestros endpoints

39

Creación de tests para nuestros servicios

40

Creación de tests para nuestras utilidades

41

Agregando un comando para coverage

42

Debugging e inspect

Despliega tu primera aplicación en Express.js

43

Considerando las mejores prácticas para el despliegue

44

Variables de entorno, CORS y HTTPS

45

¿Cómo implementar una capa de manejo de caché?

46

¿Cómo contener tu aplicación en Docker?

47

Despliegue en Now

Conclusiones

48

¿Qué aprendiste en este curso?

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Creación de tests para nuestros endpoints

38/48
Recursos

Aportes 55

Preguntas 19

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

  • mocha: nos ayuda a correr los test
  • supertest: levanta un servidor temporal
  • sinon: crea mocks para tests
  • proxyquire inyecta los mocks cuando se requieren los paquetes

La clase no estuvo muy clara. A mi parecer faltó explicar con más claridad lo relacionado con los test en javascript para poder entender más fácilmente lo que se estaba estudiando.
Este profesor sabe mucho del tema pero explica demasiado rápido y no se alcanza a entender muchas de las cosas que habla.

Investigué las documentaciones de las librerías para entender la clase y estos son mis apuntes por si les sirven.

Flujo de tests Mocha

<h1>Consideramos un test it(mensaje, function () {});</h1>


Si dentro del callback se lanza un error, el test se da por fallido y se pasa al siguiente test.

En caso de que la ejecución del callback termine sin errores entonces se pasa al siguiente test automáticamente.

Si en la ejecución del callback llamamos a una función asíncrona, debemos pasarle una función ‘done’ como parámetro (el nombre es arbitrario).

Si pasamos ese parámetro mocha sabrá que debe esperar a que la ejecutemos para pasar al siguiente test y darlo como aprobado. O en caso de que ejecutemos done(error), sabrá que debe pasar al siguiente pero dándolo como fallido.

it(mensaje, function (done) {
	setInmediate(() => done());
});

En caso de tengamos una promesa podemos simplemente retornarla y mocha esperará a que la promesa se complete, dando el test como aprobado o fallido dependiendo de si se resuelve correctamente o no.

Debemos utilizar el callback done o retornar una promesa, pero no utilizar ambos o se producirá un error.

it(mensaje, async function () {
	return Promise.resolve('hola');
});


También podemos realizar un test asíncrono y tratarlo como síncrono con async/await. En este caso, al igual que en el caso síncrono, el test depende de si la función finaliza correctamente o finaliza con un error.
⠀⠀

it(mensaje, async function () {
	const promesa = Promise.resolve('hola');

	await promesa;
});


Como no envolvemos el await en un try/catch, este lanzará un error en caso de que la promesa sea rechazada, por lo tento el test pasará fallido.

Testing de endpoints HTTP


Para esto utilizamos una librería llamada supertest, la cual sirve para testear servidores HTTP NODE.js, nos permite envíar solicitudes HTTP de tipo GET, POST, PATCH, PUT, y DELETE, y recibir la respuesta.

supertest nos provee una función a la que le debemos pasar nuestra app express como parámetro (con sus rutas establecidas), y nos retornará un objeto por el cual podemos relizar solicitudes y validaciones.

const createRequester = require('supertest');
const request = createRequester(app);

request
    .get('/user')
    .expect('Content-Type', /json/)
    .expect('Content-Length', '15')
    .expect(200)
    .end(function(err, res) {
        if (err) throw err;
    });


Si estamos en un test mocha, podemos pasar el done a la función end.

request
    .get('/user')
    .expect(200)
    .end(done);


De esta manera, si hay un error mocha recibirá un done con el error y el test fallará, y si no hay error, no fallará porque done no recibirá un error. End recibe un error first callback.

Si no usamos la función end, los expect lanzarán errores en el segundo parámetro y podemos capturarlos de la siguiente manera…

request
    .get('/user')
    .expect(200, done);


Para leer la respuesta podemos usar un then

request
    .get('/user')
    .then(response => {
        assert(response.body.email, '[email protected]');
    });

Les recomiendo jest para los test unitarios, tanto en el front como en el back

Aprendí muy poco en esta clase.
.
Voy a leer los comentarios, y ver de nuevo la clase.
.
De aquí salgo aprendiendo-
.
VUAAAAAAAAAAMOS

Al ejecutar el script de test me dio un error porque faltaba setear la variable NODE_ENV

“test”: “set NODE_ENV=development && mocha --exit”

No olviden en test-server hacer uso del parse de express para formato json, el no hacerlo puede generarle error, en su defectoque la prueba falle.

const express = require('express')
const supertest = require('supertest')

function testServer(route){
    const app = express()
    app.use(express.json())
    route(app)
    return supertest(app)
}

module.exports = testServer

Algo que me di cuenta, es que es super importante que al hacer el deepEqual asegurarse que los datos que estan comparando sean exactamente iguales. En este caso tanto la data como el mensaje que se reciben.
Me estaba dando errores porque en el mensaje que retornaba de las rutas era diferente al que comparaba en el test. Me salía este error:

.
Así que hay que estar muy pendientes con este tipo de errores.

¿Alguien sabe por qué esto funciona

En ‘routes/movies.js’

const MovieService = require('../services/MovieService')

En ‘test/routes.movies.test.js’

const route = proxyquire('../routes/movies', {
        '../services/MovieService': MoviesServiceMock
})

Pero esto no:

En ‘routes/movies.js’

const { MovieService } = require('../services/')

En ‘test/routes.movies.test.js’

const route = proxyquire('../routes/movies', {
        '../services/': { MovieService: MoviesServiceMock }
})

?

Si alguno tuvo problemas con el deepEqual, es porque la función está deprecada, la correcta es :


assert.deepStrictEqual(res.body, {
                    data: moviesMock,
                    message: 'movies listed',
                });

Implementar test en Node.js 🧪

Las dependencias que instalaremos solo se usarán en modo de desarrollo cuales son

  • mocha: nos ayuda a correr los test
  • supertest : no ayuda a levantar un sevidor temporal
  • sinon: nos ayuda a hacer mocks
  • proyquiere: nos ayuda a inyectar los mocks

El objetivo de esto es probar unicamente las rutas, no nos conectaremos a nuestros servicios como mongoDB si no que lo haremos a nuestros Mocks

Crearemos el archivo donde haremos los test

Importamos las dependencias que nos ayudarán

const assert = require('assert');
const proxyquire = require('proxyquire');

Importamos el creador de sevidores temporales y los mocks

const { moviesMock, MoviesServiceMock } = require('../utils/mocks/movies.js');
const testServer = require('../utils/testServer');
  • El testServer se le tiene que pasar una funcion con las rutas

Esta funcion reemplazará el requiere del servicio de mongo por el de Mock que importamos

describe('routes - movies', function() {
  const route = proxyquire('../routes/movies', {
    '../services/movies': MoviesServiceMock
  });
// una vez realizado el cambio proxiquery nos 
// nos devuelve el mismo archivo pero con las 
// modificaciones, y esto lo podemos guardar 
// en una variable

Una vez el mock inyectado se lo pasamos a supertes que hará un servidor temporal

const request = testServer(route);

Creamos una prueba pero en vez de inyectar algo hará un unit test, le pasamos el nombre del test y la función a ejecutar

El done quiere fucionaría como un next, es decir termina aquí

describe('GET /movies', function() {
    it('should respond with status 200', function(done) {
      request.get('/api/movies').expect(200, done);
    });

it( una descripción de lo que deberia dar, funcion a ejecutar

it('should respond with status 200', function

La función no es mas que un servidor temporal con el archivo modificado, dentro de este haremos un

routes.get(ruta a probar, expect(status esperado, done))

request.get('/api/movies').expect(200, done);

Ahora usaremos el .end que recibe una función que tiene el resultado de la petición y si hay algun error,

.end((err, res) => {
        assert.deepEqual(res.body, {
          data: moviesMock,
          message: 'movies listed'
        });

usaremos assert.deepEqual(valor 1, valor 2) cual comparará los datos

instalar: npm i -D mocha supertest sinon proxyquire

creo que falta mas detalles sobre el tema de test, debería ser un modulo completo.

Si modificaron alguna parte del código con anterioridad y ahora tienen problemas con MOCHA, este código les puede ayudar.

require('dotenv').config();

const config = {
	dev: (process.env.NODE_ENV || '').trim() !== 'production',
	port: process.env.PORT || 3000,
	cors: process.env.CORS,
	dbUser: process.env.DB_USER,
	dbPass: process.env.DB_PASSWORD,
	dbHost: process.env.DB_HOST,
	dbName: process.env.DB_NAME,
};

module.exports = {
	config,
};

he encontrado esta informacion acerca de los
tes
ya que mas adelante podrias no entender nada.

Y si encuentras mi comentario en el siguiente video, me das un corazonsito ❤️

Siempre es bueno escribir las cosas [email protected] [email protected]… pero a veces es más fácil con un simple copy/paste:

npm i -D mocha supertest sinon proxyquire

😃

cuando vayan a crear los ‘servicios’ de mock, asegúrense que las funciones tenga el mismo nombre que del servicio original (osea, si en su capa de servicio para obtener peliculas es getAll, en el mock coloquenlo igual), dure media hora con un error por culpa de una ‘s’ 😃

y realmente la consola no es que ayudo mucho para solucionar el error, ya que me daba a entender que el error estaba en el archivo de test en si, y no en el mock xd

Me da el siguiente error ! 😢😢😭😭
![](

me demore pero es satisfactorio cuando entiendes y a la vez el codigo corre. ahora si a dormir ZzzZZ

Tal y como todo proxy sirve para interceptar procesos, proxyquire sirve para interceptar un módulo (require).

const route = proxyquire('../routes/movies', {
    '../services/movies': MoviesServiceMock,
  });

El primer parámetro representa la ruta del archivo donde pensamos interceptar el módulo (require) Ej.: ‘…/routes/movies’.

El segundo parámetro son pares “llave-valor” en los cuales, respectivamente, cada llave representa el módulo que se quiere interceptar (Ej.: ‘…/services/movies’), y cada valor representa el módulo (Ej.: MoviesServiceMock) por el cual se va a reemplazar el (módulo de la llave) que se está interceptando.

Utilizando lo que tenemos hasta ahora quedaría algo como esto:

const route = proxyquire('../routes/movies', {
    '../services/movies': require('../utils/mocks/movies').MoviesServiceMock,
  });

o más a fondo:

// en el archivo routes/movies.js quedaría algo así

const MoviesService = require('../services/movies');
const { MoviesServiceMock } = require('../services/mocks/movies')
const MoviesService = MoviesServiceMock;

// o sea sobrescribiendo el contenido del primer "MoviesService"

Espero no haber confundido más a nadie 🤣

Para los que quieran profundizar un poco más sobre testing, les recomiendo que lean sobre Jest.

El proxyquire me genera error :
const route = proxyquire(’…/controllers/routes.js’, {
’…/services/Animals’ : Animals
})
TypeError: route is not a function

Si por alguna razón estás usando Typescript en lugar de javascript como yo, este comando te resumirá horas de búsqueda 😅

   "scripts": {
        "test": "mocha -r ts-node/register 'tests/**/*.ts'"
    },

Ayuda!!! Por fa!
Hola a todos, he intentado corregir los test para que me funcionen y no me ha sido posible:

Siendo el script de test:
“test”: “SET NODE_ENV=development& mocha --exit”

Esto me sale en consola:





$ npm run test

[email protected] test D:\platzi-backend-node-implementando-una-capa-de-servicios\movies-api
SET NODE_ENV=development& mocha --exit

Error: No test files found: "test"
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] test: SET NODE_ENV=development& mocha --exit
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Daniel\AppData\Roaming\npm-cache_logs\2020-07-15T14_43_35_626Z-debug.log


Realmente no veo nada adicional en el log que refiere el error del arranque.

alguien de dio este error.

npm i -D mocha supertest sinon proxyquire

Con mocha 9 se obtiene el error

Error: Not supported
    at formattedImport

Para solucionar el problema de manera temporal se debe de utilizar la versión mas antigua, ejemplo “mocha”: “^6.1.4”, con eso, el se puede continuar con la clase.

todo un gigachad hecho y derecho!

El test nos sirve para ver la calidad y futuro de nuestra app.

npm i -D mocha supertest sinon proxyquire

No entendi como se relacionan las rutas de MoviesServiceMock, cuando hacemos el test con describe, por ejemplo para seleccionar la ruta con getMovie pasando un ID

El test me ayudó a descubrir que mi message decia ‘movie listed’ en vez de ‘movies listed’, un error simple que tal vez nunca me hubiera dado cuenta sin el test. Súper cool la herramienta

npm i -D mocha supertest sinon proxyquire

El video esta incompleto, hay archivos que Guillermo no explica como por ejemplo utils/mocks/mongoLib.js y otros dos archivos que estan en la carpeta de test, tampoco explica el buildMessage.js en la carpeta de utils.
Clase muy incompleta -.-

Los test no tienen en cuenta el validationSchema que hace parte de la ruta.

Excelente, no tenía en mente la importancia de los test de prueba y como muchos siempre los omito, pero creo que de hoy en adelante será necesario realizarlos en mi código.

proxiquire

Instalando dependencias

Creando test server para pruebas

Creando test server para pruebas

Compañeros ayuda!! … Me arroja “Type: request.get is not a function” del routes.movies.test.js… Pero parece que soy el único 😦

Creo que no fue muy clara la clase, me costó bastante seguirle el hilo. Aun así logré completarla y entender que los test son importantes pero me gustaría que hubiera sido mejor explicada.

A mi me daba error porque en el config/index.js en la constante config había añadido un .trim() al final de NODE_ENV para solucionar un problema de una clase.

Quité este .trim() y anduvo bien, pero no creo que sea una solución completa.
Si a alguien le pasó lo mismo, lo invito a compartir su solucion!

Así estaba mi codigo:

const config = { 
    dev: process.env.NODE_ENV.trim() !== 'production',
    port: process.env.PORT || 3000,
    // etc
}

Me daba el siguiente TypeError:

TypeError: Cannot read property 'trim' of undefined
    at Object.<anonymous> (F:\Atom\Platzi\BackendNodeJS\moviesAPI\config\index.js:4:31)

Sacando el .trim() queda así:

const config = { 
    dev: process.env.NODE_ENV !== 'production',
    port: process.env.PORT || 3000,
    // etc
}

Y pasa efectivamente los test. De nuevo, si alguien tiene una mejor solución, lo invito a compartirla!

Buenas.
Alguien ha logrado hacer los test para el post, put y delete.
Me encuentro con el problema de que si intento hacer un post, el createMovie, le da igual el contenido aunque este el validator en medio, puedo hacer un post sin enviar nada, y me devuelve un 200, puedo romper cualqueir cosa que el 200 vuelve =(

Los test nos garantizan tener un código de buena calidad y si en el futuro hay cambios no se va a romper nuestro código.

Hola a todos, tengo una pregunta que quisiera pudieran aclararme, ¿Cuál es el sentido de hacer pruebas con mocks? al ver la este video pienso que no se esta llegando al endpoint a realizar al request, si no estamos haciendo el mockup, entonces ya se que voy a resolver, y si alguien cambia la funcionalidad del endpoint, la prueba seguiría pasando probablemente porque no modificaran el mock, creo que estoy confundido, pueden ayudarme a salir de esta duda?

Definitivamente hace falta un curso de testing para Node jaja me pareció bastante compleja esta clase. Incluso los cursos te testing de Platzi son con Jest o Cypress entonces tenemos poca información sobre mocha y creo que a muchos nos serviría un curso específicamente de “testing para Node”

Si tienen este error al momento de correr el test.

Les explico porque…


Este fue mi error…

  1. En lugar de decir movies listed’ decía **‘Moies Listed’*, esto pasa porque utiliza el método estricto, tiene que ser igual en cuanto a tipo y dato.
  2. El método que utiliza @Guillermo Rodas hoy en dia se encuentra despreciado por las nuevas versiones de node.

Entonces… Hice lo siguiente

  1. Importe de manera estricta los datos
const assert = require('assert').strict;
  1. Hice unas modificaciones pertinentes para esto.
it('Should respond with the list of movies', function (done) {
			request.get('/api/movies').end((err, res) => {
				assert.deepStrictEqual(res.body, {
					data: moviesMock,
					message: 'movies listed',
				});
				done();
			});
		});
  • mocha: nos ayuda a correr los test

  • supertest: levanta un servidor temporal

  • sinon: crea mocks para tests

  • proxyquire inyecta los mocks cuando se requieren los paquetes

🌸🌟🌞



::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Los Test****: Son una buena manera de poder asegurarse que nuestro codigo tiene calidad y que si en el futuro hay cambios no se vaya a romper nuestro codigo.

Hola les traigo lo que dijo el profe pero escrito

/** Verifica que tanto se parecen dos datos  */
const assert = require('assert')

/** Cada require elegimos si obtenemos el paquete real o los mocks  */
const proxyquire = require('proxyquire')

/** Mocks de la base de datos y los servicios */
const {   
  moviesMock,
  MoviesServiceMock
} = require('../utils/mocks/movies')

/** Servidor de tests */
const testServer = require('../utils/testServer')

/** describe imprime en consola y corre la funcion siguiente*/
describe('route - movies', function() {

  /** 
   * proxyquire toma el archivo del checkpoint 'routes/movies.js'
   * para probar que las peticiones esten funcionando correctamente.
   * Y para verificar que la respuesta es retornada de la manera que queremos
   * se implantan el MovieServiceMock en el lugar donde se requiere la ruta de los servicios
  */
  const route = proxyquire('../routes/movies', {

    /** intercambia services/movies por la clase MoviesServiceMock  */
    '../services/movies': MoviesServiceMock
  })

  /** Crea un servidor de prueba que maneje esta ruta declarada */
  const request = testServer(route)

  /** describe imprime en consola y llama al callback */
  describe('GET /movies', function() {

    /** 
     * Prueba: imprime este mensaje y corre el callback
     * request corre el servidor de pruebas generando una peticion get
     * que va a la ruta expuesta, y el metodo expect
     * declara esperar un status 200 y mediante done terminamos la prueba
     */
    it('should respond with status 2000', function(done) {
      request.get('/api/movies').expect(200, done)
    })

    /**
     * Prueba: hace una peticion get a la ruta y verifica el contenido
     * request.get accede a la ruta, .end maneja la respuesta y el error
     * pero solamente vamos a evaluar la respuesta,
     * asset es un modulo core de node que nos permite evaluar el tipo y contenido de valores y variables
     * en este caso verificamos res.body sea estrictamente igual a lo que enviamos como segundo parametro
     * y finaliza la prueba con done
     */
    it('should respond with the list of movies', function(done) {
      request.get('/api/movies').end((err, res) => {
        assert.deepEqual(res.body, {
          data: moviesMock,
          message: 'movies listed'
        })
        done()
      })
    })
  })
})

si proxyquire retorna un objeto, se tiene un error de tipo

TypeError: route is not a function

por lo que me toco sacar la funcion que espera testServer de esta forma, no creo sea la mejor pero me sirvió

const {moviesApi: route} = proxyquire('../routes/movies.js', {
    '../services/movies': MoviesServiceMock
  });

espero les sirva

El término ‘mocha’ no se reconoce como nombre de un cmdlet, función, archivo de script o programa ejecutable.

Alguien le ha salido ese error? he comprobado que si tengo instalado el mocha y tmb lo tengo en el package.json