This graph shows how many times the word ______ has been mentioned throughout the history of the program.
¿Qué es TDB? TDB son las siglas de Test Driven Development y al final es una forma de desarrollo en la que tú primero haces el test y luego escribes el código.
A partir de aquí hay un montón de vertientes, hay gente que se puede volver bastante loca al respecto porque hay gente que cree que hay que hacerlo de una forma iterativa.
Por ejemplo, tú creas un test y lo que haces es que primero salga en rojo, luego salga en verde, refactorizas, rojo, verde...
El tema es que hay gente que dice, bueno, pues hay que ir paso a paso en la iteración, en el sentido de que, bueno, pues si quieres crear un endpoint, pues tú creas un test en el que primero te dé ok.
Vale, pues haces la funcionalidad para que te dé ok. Vale, pero luego es que le pases el campo tal, luego el campo tal. Eso es una vertiente.
Hay otra gente que lo que considera es que hay que hacer más el test sobre un caso de uso, una historia, por ejemplo.
En este caso tenemos el usuario cuando lo creamos con un usuario nuevo, pero queremos probar qué pasa si creamos un usuario con el mismo nombre.
Entonces, en lugar de estar iterando todo el rato, ya tenemos claro cuál es el caso de uso que queremos conseguir.
Vale, una historia que le da valor al usuario, al usuario como el que usa nuestra aplicación. Y eso es lo que vamos a probar en nuestro caso.
Ese sería una forma de trabajar. Hacemos un test que es con un caso de uso que queremos que tenga nuestra aplicación.
Hacemos primero el test, como esperamos que debería funcionar nuestra aplicación. Nos va a dar rojo porque esa funcionalidad no existe ni siquiera.
Conseguimos que nos dé verde y a partir de ahí refactorizamos. Refactorizamos ya sea cambiando funcionalidad, ya sea también mejorando nuestro código.
Pero lo que conseguimos de esta forma con esto es que siempre tenemos un loop en el que nos apoyamos en el test primero, no en la funcionalidad.
Que eso es mucho de lo que me decía mucha gente. Decía, no, yo hago la funcionalidad y ya me aseguro que funcione y no hago test ni nada.
Bueno, pues esto es lo opuesto básicamente. Es nos apoyamos en el test para la implementación y para ir diseñando como lo vamos a ir haciendo.
Es una buena práctica, no siempre se puede utilizar, pero creo que si te lo puedes permitir, en este caso yo creo que es un muy buen ejemplo.
En todos los ejemplos en lo que haces en realidad es, ¿por qué? Porque tienes un solo endpoint, se supone que no tienes IDFX y al final es muy fácil comprobar el JSON y ya está.
Que no debería ser muy complejo y sobre todo gracias a que tenemos el helper, que es para recuperar todos los usuarios que tenemos en la base de datos.
¿Qué queremos testear? ¿Qué queremos testear? Aquí habíamos testeado que funciona cuando creamos un username que es fresco.
¿Vale? Works as... No, works no. Esto debería ser creation fails with proper... Bueno, proper... Tampoco que tengamos... Es proper status code.
And message if username is already taken. ¿Vale? Si alguien ya tiene este usuario, debería fallarnos esto. ¿Vale?
Entonces, igual que habíamos hecho... Esto es asíncrono, importante. Igual que habíamos hecho aquí, ¿no? Que recuperamos los usuarios al principio, pues nada, podemos hacer lo mismo.
Vamos a recuperar los usuarios al principio. Creamos el nuevo usuario, pero ahora el nuevo usuario no es un usuario cualquiera.
Tendría que ser exactamente este, ¿no? Tendría que ser el usuario que habíamos utilizado antes. Vamos a asegurarnos que... Esto me lo copio bien.
Tiene que ser el mismo que teníamos antes. Esto lo podríamos hacer de otra forma, tener un helper, como hicimos con las notas. ¿Vale?
Pero, bueno, por ahora lo importante es que sea el mismo. No el name. Puede ser cualquiera. El password. Puede ser, pues, cualquiera.
Esto no es importante. Lo importante es que nos debería petar al intentar crear el mismo usuario.
Vamos a ver cuál es el resultado de este. Cuando en la API hacemos un post... Esto es muy parecido a lo que habíamos hecho antes, ¿verdad?
API barra users. Aquí esperamos... Enviamos primero el nuevo usuario y aquí lo que esperamos es que nos dé un error.
El error que podemos utilizar es el 400. No sé si hay uno mejor, pero a ver... Pero yo creo que es el 400, ¿no?
Bad request. Estoy pensando, a ver... No sé si... Yo creo que es... O no aceptable... O no aceptable... Conflict... Bueno, vamos a poner un 400 que al final es una... Es bastante similar.
Pero al final, si te pones a mirar, siempre te puedes volver muy loco de que encuentras... Eh... Encuentras otros tipos de status code que pueden tener más sentido.
Pero, bueno, creo que el 400 está lo suficientemente bien. ¿Vale?
Así que vamos a decirle que esperamos un 400. Y esperamos también el content type. ¿Por qué? Porque vamos a querer enviar el error.
Y vamos a ver que el error que nos está devolviendo es justamente el que esperamos. No es un error cualquiera.
En el resultado es lo que esperamos. Que el resultado tenga un body y tenga un error. Y este error contenga... Aquí podemos ir hasta donde quieras.
No sé hasta qué punto puede tener sentido esto de mirar hasta el mensaje de error. Puede ser que sí, puede ser que no. Lo que queráis.
Pueden mirar que hay un error sin mirar el mensaje. Creo que eso puede ser suficiente. Pero si no, pues que lo tengáis en cuenta.
Y luego, igual que hemos hecho antes, ¿no? Que teníamos los del principio, pues ahora vamos a mirar que no esté al final que nos ha añadido uno nuevo.
Vamos a mirar y esperamos que el users at end tenga la misma longitud que los que teníamos al principio.
No la vayamos a liar parda. Y nos ha añadido, aunque no dé un error, ¿sabes? Nos añade la base de datos de nuestro usuario.
Qué locura es esta. Entonces, esto obviamente debería explotar. Ha fallado. ¿Vale? Failed. Vamos a ver por qué.
Claro, dice esperaba un 400 y esto me ha dado un 201. O sea, lo ha creado. Que es justamente el 201 que hemos puesto antes.
Esto no es lo que queremos. Así que ahora lo que vamos a hacer es trabajar en la funcionalidad para que nos dé verde este test.
Podríamos hacer esto de un montón de formas. Un montón. O sea, podríamos ir aquí a users, buscar si ese username está pillado.
O sea, podríamos user.find username, ¿vale? Buscamos el usuario y si este user está, ¿vale? Pues entonces podríamos hacer eso.
Pero justamente existe una funcionalidad. Hay una librería en Mongoose que te hace esto.
No Mongoose en sí, sino una librería que si la tengo por aquí apuntada, que nos va a ayudar a hacer esto y nos va a evitar tener que escribir nosotros nada.
Que es esta de Mongoose Unique Validator. Vamos a probarla, a ver si funciona. Si funciona bien y si no funciona, ponlaremos a mano.
Pero bueno, si no lo podemos evitar, pues mejor. Sobre todo en el caso del backend que... Bueno, este hace dos años, ¿eh? Por eso.
Pero esto lo que nos debería permitir es indicarle qué campos queremos que sean únicos. Y todo esto lo haría por nosotros.
Lo cual me parece genial porque es una comprobación que seguramente tengas que hacer en más de un sitio.
Y si lo puedes poner en el esquema, va a hacer que no dependa de tu código. Así que aunque esta dependencia no funcionase, yo crearía algo similar para que estuviese en el esquema.
Para que fuese tu fuente de la verdad y no la implementación que tú hagas en una ruta, ¿sabes?
Así que por eso me parece una buena idea utilizar este tipo de validación. Me sorprende que Mongoose no tenga algo así.
Igual lo han puesto hace poco y ya está. Vamos a ello.
Voy a añadir aquí la dependencia con npm installs, save Mongoose unique validator. Y esto, mientras se instala, a ver, lo que nos va a permitir...
Vale, esto lo voy a eliminar. Pero bueno, para que sepáis cómo se podría llegar a hacer esto manualmente. Pero no lo vamos a hacer manualmente.
Vámonos a nuestro modelo, al de user. Y aquí lo que vamos a hacer es añadir el unique validate.
Y aquí hacemos el require de Mongoose unique validator.
Ahora, ¿cuál es el que queremos que sea único? Pues es este username. Le vamos a decir que sea... Esto es un tipo string.
Y aquí ahora le podemos decir que es unique true. Este unique validator no sé si lo tenemos que utilizar en algún sitio más.
A ver, vamos a ver. Unique validator... Vale, hay que utilizarlo como plugin.
Hemos hecho esto. Lo hemos importado. Le hemos dicho que sea único. Y ahora hay que aplicar este plugin al esquema.
Pues vamos a hacer ello. El user esquema, user esquema.apply... Ah, no. Plugin, perdón. Plugin y es el unique validator.
Y de esta forma le está dando esta funcionalidad de poder ver si realmente este campo es único.
Se podrían hacer un montón de cosas más. Se podría, por ejemplo... Ah, me imagino que esto es lo que justamente da un 400.
Bueno, pues mira, ha petado. Vamos a ver. Vale, user validation failed.
En este caso, este es el... Nos ha petado más que nada por el nombre, en realidad.
Expected username... ¿Ves? Parecía que debería ser... Expected username to unique value midu...
O sea, lo que estaba pasando aquí... User validation failed. A ver, en realidad... Es como que... Vamos a limpiar esto.
Porque más o menos pasar... O sea, el error sale, pero no sé si es que el error no es exactamente el mismo, ¿no?
¿Veis? Console error... Vale. Creation fails. Expected 400. Pero nos ha dado un 500.
O sea, lo que está dando esto no es un... No un 400, sino que está dando un 500 directamente.
Bueno, pues mira, al final ya sabemos... Claro, es que como veía tanto rojo... Digo, pero ¿cuál es el error exactamente?
Bueno. Internal server error. Hmm... No sé si se podrá cambiar, pero la verdad es que no tiene mucho sentido.
Vale, ahora esto que dice que tal... Claro, lo que podríamos hacer de todo esto, ahora que lo pienso, en realidad es ir a nuestra ruta del controller,
en el de users, y aquí, pues intentar hacer el try y tal. No sé si peta aquí, pero al final lo que podemos hacer sería algo así.
Intentamos todo esto... Y si no, aquí lo que podemos hacer es el response.status... 400... JSON... No sé si así funcionará ya.
No sé si es exactamente el cuerpo de la función. Vale, vamos a ver. Ha tenido valor undefined. Vale.
Tendríamos que ver el error. Creation fail. El error este... No nos está llegando. El error que... Claro.
Claro, porque pone .body, .error. El tema es que este console.log, o sea, este console.error, aquí tendríamos que mirar cómo es,
porque tendríamos que nosotros construir el objeto con el body y con todo esto. Me imagino yo.
O sea, tendríamos que poner aquí, por ejemplo. Creo que sería así. Error, error. Bueno, pero nos estamos acercando.
¿Ves el mensaje? Dice... Ah, es que, ¿ves? Tenemos aquí errors. Tenemos el mensaje. User validation fail.
Ese podría ser uno. Errors. Username. Kind. Unique. Message. Claro, es que queremos justamente este error.
No sé si hasta qué punto tiene sentido que busquemos en el test que contenga justamente esto.
Podríamos buscar en errors, o sea, porque ahí sí que tenemos errors.
Tendríamos body, .error, ¿vale? .error. Entonces tenemos este objeto que tenemos el message y el .error.
.error, .username, .message. A ver ahora. Ahora sí. ¡Por fin! ¡Verde! ¡Verde!
Si no me he ganado el cielo con eso, ya me dirás. Vale, ahora sí.
Es por cómo devuelve un poco el error, ¿vale? Que es un poco así... Un poco raro.
Es el tema de cómo devuelve el error. El result es la respuesta de la API .body porque como está el resultado este,
en realidad tienes ahí los headers que has utilizado, un montón de información de la respuesta, ¿vale?
El body sería el cuerpo de la respuesta. Luego dentro tienes el error, pero porque yo he creado aquí error, ¿vale?
Esto yo lo debería haber pasado directamente. De esta forma, aquí, ahora debería poder quitar el .error.
De hecho, ahora va a petar, pero ahora podría utilizar .errors porque puede haber más de un error en la validación de nuestro objeto.
Y aquí tendríamos que ver que el error que tenemos de la validación del .username en el mensaje, tenemos este.
Bueno, no me parece mal al final porque esto como quizás es justamente lo que está validando esta funcionalidad
y siempre va a tener este mensaje. Lo que puede pasar es que cambie este mensaje en la librería y nos lo reviente, por ejemplo.
Pues esto ha sido TDD. Hemos hecho una funcionalidad a través de un test y además nos ha ayudado.
Justamente he hecho un refactor después, en cuanto he terminado la funcionalidad y veía que funcionaba,
he dicho, ah, pues mira, ahora quiero .error, no sé qué. Y al final me ha ayudado a irlo afinando.
Pues podríais hacer otro checks. Podríais ir a user, decir que el username tenga una longitud mínima.
Eso ya os lo dejo también de deberes, pero esquema checks.
Bueno, hay un montón, un montón de validaciones. Si es requerido, que pueda ser uno de los diferentes valores,
que tenga una longitud de string. ¿Ves? Aquí pone the unique option is not a validator.
Mira, es lo que comenta. Así que, bueno, a tenerlo en cuenta.
Puedes utilizar algunos custom. O sea, está bastante interesante.
Ya que tenemos todo esto, vamos a seguir creciendo nuestro controlador de user router.