logo

midudev


Transcribed podcasts: 167
Time transcribed: 5d 15h 37m 28s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

En la clase de hoy vamos a ver Testing End-to-End y lo vamos a hacer utilizando Cypress, lo que sería ahora mismo el framework o la utilizada para hacer Testing End-to-End más utilizada del momento.
Y no es para menos, tiene algunas características que lo hacen bastante especial y las vamos a repasar.
Los cuatro tipos de test. Ahora, para hacerlos End-to-End, porque la integración, unitarios y estáticos, estáticos no hemos visto de tipos, que lo veremos con TypeScript, pero sí el linter no deja de ser un Testing estático.
Entonces, ¿cómo vamos a hacer los de End-to-End? Se podría hacer de un montón de maneras. Antiguamente se hacía una cosa que se llamaba Selenium, que no estaba mal, era un webdriver, pero no es exactamente lo que hoy en día se lleva.
¿Por qué? Porque Selenium da muchísimos problemas a la hora de levantar lo que sería todo el entorno para poder probar los tests y todo esto.
Y encima, los tests como tal no se ejecutaban realmente en el navegador, sino que se hacía algo de ejecutar el código en el navegador, ver si eso había funcionado, pero fuera del navegador.
Entonces, desde hace unos años apareció una nueva librería o utilidad que se llama Cypress.
Cypress es, seguramente hoy en día, la opción más utilizada para hacer Testing End-to-End en las aplicaciones.
¿Y por qué? Primero, porque utiliza Chrome, que es seguramente el navegador más usado, y por lo tanto ya interesa que puedas hacer estos tests End-to-End en el navegador más usado.
Porque claro, en los End-to-End tienes que levantar un navegador y hacerte pasar por un usuario.
Así que Chrome, que es bastante rápido, es bastante seguro, es bastante fiable, es la elección idónea.
También se pueden ejecutar los tests con Firefox y creo que ahora, obviamente, con Edge.
No se pueden ejecutar, por ejemplo, Internet Explorer 11, porque no tiene las, digamos, la biblioteca no está preparada para utilizar Cypress con eso.
Pero bueno, lo importante es que se pueden utilizar los navegadores más modernos, los que nos interesan, y tienen algunas características que realmente en su momento, ahora poco a poco van saliendo más, lo hacen único.
¿Vale? Y son estas de aquí.
La primera es el Time Travel. Esto lo vamos a ver al principio.
Y es que puedes ver cada uno de los pasos que está haciendo el test y ver cómo se ha ido renderizando la página y por qué no ha funcionado, o si ha funcionado, qué es lo que ha hecho en cada paso y todo esto.
Luego, la forma de depurar este código. Vais a ver que es muy visual y esto va a hacer que sea súper sencillo.
Luego también tenemos Real Time Reloads. Esto es que cada vez que vas haciendo cambios se van ejecutando los tests súper rápido y vamos a poder ver cómo se pone en verde o en rojo según vamos cambiando los tests.
Y luego que, bueno, esto es que está esperando siempre que tengamos un nuevo comando, que vamos ejecutando los nuevos tests y todo esto.
Esto serían un poco las características mejores de Cypress. Y estas las que vamos a utilizar en nuestra aplicación de notas.
¿Vale? Yo creo que lo mejor para ver Cypress es que finalmente lo utilicemos en nuestro proyecto y es lo que vamos a ver.
Voy a cerrar esa fría y no se pone todo abierto por ahí.
Muy bien. Importante. Muy importante.
Como hemos dicho, para poder hacer un test end to end tenemos que tener la aplicación levantada. Esto es diferente a como son los tests unitarios y los tests de integración, que puedes no levantar la aplicación.
Así que hay que tener en cuenta que vamos a necesitar levantar la API y levantar la app para que puedan correr estos tests.
Por ahora vamos a nuestra aplicación de React, la que teníamos de las notas, y lo que voy a hacer es instalar Cypress.
Vamos a poner Cypress menos de mayúscula, que esto es de desarrollo, una dependencia de desarrollo.
¿Vale? Espero que no me dé problemas, ¿vale?
Porque como tengo el procesador este de Apple, el Silicon, sé que había antes algunos problemas de compatibilidad con este procesador.
Puede ser que cuando ejecute los tests, igual el stream se corte un poco, petardé, ten paciencia, intentaré que no sea muy doloroso, pero que sepas que puede ocurrir para que lo tengas controlado.
¿Vale?
Entonces, ahora que ya he instalado Cypress, lo primero que voy a hacer, ya sabéis que a mí lo que me gusta mucho es trabajar con los scripts.
¿Vale?
Con los scripts. ¿Qué tipo de scripts?
Vale, pues con estos, ¿no? Del package.json.
Así que voy a añadir uno, que le vamos a poner cypress.open.
Para, en lugar de utilizar directamente el comando de Cypress, lo vamos a hacer así, con un script.
En lugar de poner .barra node modules, .bin, Cypress, no sé qué, vamos a poder ejecutar este script de aquí.
Vale, pues guardo los cambios y ya npm run cypress open.
Vamos a ver si esto funciona bien.
Cuando he ejecutado Cypress, ahora vamos a ver si esto funciona.
Bueno, veo que va lento porque debe estar con una versión antigua.
Ahora me confirmáis y peta el Steam mientras esto está cargando.
Vale, no files found.
Vale, esto, esto.
Vale, pues sí que están aquí los files found.
A ver, Cypress integrations está aquí.
¿Por qué me dice?
Ah, porque se han borrado.
Se han borrado estos, estos, vale.
¿Sabéis qué puede pasar?
Que antes lo he instalado.
Bueno, vamos a hacer, a ver, voy a eliminar el node modules y voy a empezar desde, voy a hacer una instalación limpia para asegurarme de que lo instala todo.
Vale.
Y voy a eliminar el cypress este, este y este.
Al menos este.
Voy a dejar el del package.json.
Vale, he puesto la versión de Cypress, me la he puesto por aquí.
Perfecto.
Pues vamos a hacer un npm install para empezar desde cero y que me está de todas las dependencias seguro.
Porque igual lo que hace Cypress al principio es que te pone una estructura de directorios por defecto cuando se instala.
Vale.
Entonces, a lo mejor ha encontrado que sí que está la dependencia y ha dicho, ah, ya tiene la dependencia, pues no voy a hacer nada.
Además de eso, Cypress lo que hace es debería descargarte el binario de Chrome.
A veces se utiliza el que ya tienes instalado, pero puede ser que te instale otro.
Vale.
Si por cualquier motivo veis que te está instalando un Chrome, que sepas que es normal.
Porque a lo mejor la versión que utilizan no es exactamente la que tienes instalada en tu ordenador.
Por ahora, ¿qué?
¿No está petando el stream?
¿Se escucha bien?
¿O va petando?
Ahora me comentáis, ¿vale?
Los installs suele petar un poco.
Vale.
Entonces, vamos a ejecutar ahora sí el comando de npm run.
Todo bien.
Un poquillo.
Bueno.
npm run cypress open.
Vamos a ver ahora.
Vale.
Este es cypress open.
Ahora debería ejecutarnos, ahora sí que debería crearnos estas carpetas que teníamos por aquí.
A ver si lo hace.
Ahora sí.
¿Vale?
Ahora sí que lo ha encontrado porque justamente me ha creado toda la estructura de carpetas.
Como veis, me ha creado un archivo, bueno, un directorio cypress y un archivo cypress.json.
El cypress.json está vacío y aquí lo que podríamos poner es un montón de opciones, pero en la clase de hoy no lo vamos a utilizar, así que os podéis olvidar de él.
Bueno, en cypress el directorio nos ha dejado un montón de cosas, fixtures, integrations, plugins, support, nos ha dejado un montón de cosas.
Nosotros nos fijaremos en esta clase, porque solo es una clase que vamos a poder hacer solo una, en integration y comandos.
¿Vale?
Pero cypress tiene un montón de funcionalidades, las fixtures, los plugins, pero la integración, que es donde van los tests y los comandos, yo diría que es lo más importante para empezar.
¿Vale?
Así que vamos a empezar por ahí.
Luego, también cuando he ejecutado este comando, aparte de crearme todos estos archivos, habrás visto que tengo esto de cypress aquí y me ha abierto esto.
¿Vale?
Pues esto, aquí tengo todos los tests que ya me ha detectado de integración.
Podría ejecutar este run 19 integration specs, aquí seleccionar en qué navegador ejecutarlo, vamos a poner Chrome por ahora, y le voy a dar a run, a ver qué hace.
¿Vale?
Ahora pone el run, y me abre un navegador de Chrome, que si te fijas no es el mismo que tenía, es más oscurito, y ahora se va a poner aquí a ejecutar los tests.
Además de forma visual, lo cual es súper interesante.
Es un navegador real, y vamos a poder ver paso a paso cómo se están ejecutando cada uno de los tests.
Ahora los está cargando, ¿vale?
Está diciendo, tus tests están cargando.
Normalmente tarda menos, pero yo creo que es porque está utilizando un binario que no está optimizado para mi versión de Mac.
¿Vale?
Ahora vemos aquí el type, puede ser a veces pet alguno, ¿vale?
Aunque sean los de ejemplo, a veces pasa, pero ¿veis?
Ahora están pasando.
¿Veis?
Esta sería la página en la que estamos testeando estos de ejemplo.
Estos son de ejemplo ahora mismo, solo para que veamos cómo funciona.
¿Vale?
Los va pasando y conforme va haciendo cada uno de los pasos, ¿verdad?
¿Veis?
Se ve aquí visualmente cómo está haciendo cada cosa.
Pues los va haciendo un check, y dentro de cada uno dice, vale, ahora estoy haciendo esto, ahora estoy haciendo el otro.
Lo mejor de esto, los puedes parar, ¿vale?
Podríamos pararlos, de hecho los vamos a parar, ¿vale?
Los he parado, pero yo ahora aquí, donde tengo todos los specs, bueno, ha petado porque hace un timeout, porque lo he parado y tal, ¿eh?
Pero estaba funcionando correctamente.
Podemos entrar a uno de estos, ¿vale?
Por ejemplo, actions, este type.
Esto no os preocupéis si ahora no entendéis, porque cuando hagamos lo nuestro lo vamos a revisar de nuevo y lo vamos a volver a entender.
Pero le voy a dar este, action type.
Y dice, vale, type into a domain, DOM element.
Y aquí podemos ver cada uno de los pasos que ha hecho este test.
Este es el time travel que decíamos al principio, ¿vale?
Mira, ¿ves?
Test body.
Entonces, yo voy a get, me pongo encima y puedes ver aquí a la derecha, vas a ver qué ha ido haciendo, que puedes ir viendo las cosas que ha ido haciendo, ¿vale?
Lo que ha ido recuperando, por ejemplo, esto era un get.
Luego ha hecho type fake arroba email y en el siguiente paso, ¿veis?
Ya está ahí.
Ya está ahí.
Entonces, aquí puedes ver súper fácil.
Puedes ver súper fácil dónde se ha quedado, qué problema ha tenido.
Si hubiera petado, si hubiera petado, hubiéramos visto en qué punto ha petado y podemos ver en cada punto qué es lo que ha hecho visualmente en el otro sitio.
O sea, súper potente, súper potente.
Esto lo vamos a ver después.
Por ahora lo voy a cerrar porque no son los test que a nosotros nos interesa.
Podríamos estar mirando los test, los de prueba todo el rato, pero no es lo interesante.
Por ahora, ya tenemos nuestra aplicación por aquí.
Vamos a levantarla.
¿Vale?
NPM run.
Y teníamos el NPM run.
NPM start.
Vamos a levantar nuestra aplicación de React, la de notas.
Ahora debería aparecer aquí nuestra aplicación de notas.
Perfecto.
Ahora, vamos a levantar también la de la API.
Pero hay que tener en cuenta una cosa con la API porque ahora la que queremos, queremos levantar la API, pero la queremos levantar en modo test.
Si te acuerdas cuando hacíamos los test, añadimos las variables de entorno y había una en modo test justamente para que cuando era un test no grabase los datos en la base de datos, la de producción, sino una de test.
Y en este caso queremos hacer lo mismo.
Pues lo que vamos a hacer en este proyecto de la API, vamos al packet.json y lo que hacemos aquí, igual que tenemos este test, vamos a hacer, por ejemplo, como le podemos llamar a esto, start test.
Esto sería para levantar nuestra aplicación, nuestra API, pero en modo test.
Así que vamos a poner aquí node.env.test y el puerto lo vamos a dejar como estamos, node.index.js.
Por ahora vamos a dejarlo así.
De esta forma vamos a levantar nuestra API también en modo test.
Así que en pin run, start, test.
Y esto nos debería dejar en el puerto, creo que era el 3001, si no recuerdo mal.
A ver si ya aparece aquí, nos lo chiva.
Ya tenemos en el puerto 3001 y con la base de datos conectada.
Pero esta es la base de datos conectada, pero la de test.
Ya tenemos la aplicación levantada y el test.
De hecho, si vamos a nuestra aplicación y refresco, estoy viendo aquí la base de datos de test.
Si queréis, la tengo por aquí abierta, os la voy a enseñar rápidamente.
Qué de cosas hemos hecho en estas clases, ¿eh?
Es increíble.
Hemos hecho MongoDB, Node, React, JavaScript.
O sea, hemos hecho de todo.
Vale.
Veis, aquí tengo lo que sería la base de datos de producción y la de test.
Y la de test tengo nodes y users, que serían las dos colecciones que estamos trabajando.
Y en notas tengo esto, aprendiendo full stack con mi dudev, no sé qué.
Y esto es lo que veo aquí.
O sea, que está apuntando correctamente a la de test.
Importante asegurarse porque ya veréis más adelante que vamos a necesitar asegurarnos que esto va a ser así y que no la liamos.
Ahora que ya tenemos nuestra aplicación aquí funcionando y que he visto, vale, me he dejado el MongoDB por aquí abierto
para que luego, por si tengo algún problema, lo pueda encontrar fácil.
Ahora que tenemos todo esto abierto, ya tenemos la app y la API, vamos a crear nuestro primer test.
Voy a borrar directamente la carpeta de examples y voy a crear aquí mi primer test.
Vamos a trabajar con un solo test, bueno, un solo archivo de test, porque al final va a ser la aplicación de notas,
pero luego más adelante, si tú quieres, lo puedes ir separando y tal.
Lo importante, aquí he creado el nombre como nodeapp.spec.js, porque así es como lo va a encontrar automáticamente.
Así que así es como le hemos puesto el nombre ya.
Voy a cerrar esto también y vamos a empezar.
¿Cómo se puede empezar un test?
Esto lo vimos ya en Jest, vamos a poner un describe.
Cypress por debajo no utiliza Jest, utiliza mocha, que es algo muy parecido a Jest, pero tiene algunas diferencias.
Al final, si miras la documentación de Cypress, no vas a tener ningún problema.
Vamos a describir esto como que esto es el nodeapp.
Vamos a poner que esto tiene una función y luego, pues nada, vamos a empezar a decirle a listar los test que queremos hacer.
El primer test que tenemos que hacer es uno de los test que se llama, le suelen llamar smoke test o le puedes llamar un test mínimo de viabilidad de tu aplicación, que básicamente es que el front page puede ser abierto.
Esto quiere decir que puedes visitar la página y que la página funciona.
Esto, que parece una chorrada, muchas veces no se hace así, sino que lo que se utiliza es un health check.
Esto quiere decir que alguien visita tu página solo para ver que realmente se está mostrando.
Pero este tipo de prueba que puede parecer una tontería te puede salvar de muchos problemas.
Por ejemplo, haces un cambio, rompes la aplicación, no haces nada, no la chequeas ni manualmente y esto te podría decir, ostras, es que no soy capaz de renderizar la aplicación.
¿Cómo lo vamos a ver?
Pues vamos a utilizar CY, que esto es de Cypress, ¿vale?
Ya veréis que esto es un objeto o una instancia de Cypress que tiene un montón de métodos y entre ellos tendríamos este, visit.
Este es uno de los más típicos y es el que vas a tener que utilizar siempre porque le vamos a decir, vamos a controlar el navegador.
Vamos a decirle, oye, navegador, visita esta página y le vamos a decir HTTP localhost 3000, ¿vale?
Porque aquí, en localhost 3000, es donde tenemos justamente la aplicación que acabamos de levantar.
Así que primero esto. Esto luego lo arreglamos, ¿vale?
Esto ya veréis que ahora se está quejando, ¿no? Nuestros test estáticos, pero tiene solución.
Lo siguiente, una vez que la hayamos visitado, lo que le vamos a decir es, vale, ahora comprueba qué contiene
y vamos a ver qué podríamos decir que nuestra aplicación al menos se renderiza para comprobar.
Bueno, pues podríamos buscar este, notes, este texto de notes, ¿vale?
Así que vamos a hacer eso. Contains, notes. Vamos, uy, notes. He pegado otra cosa ahí.
Vamos a ver si contiene notas. Básicamente eso es lo que vamos a hacer por ahora.
Así que ahora vamos a ejecutar los tests que teníamos por aquí de Cypress.
Bien, run, Cypress, open. Tarda un poquito en iniciarse.
Como veis, los tests de integración, no, los de Entwine, son costosos.
O sea, claro, levantar un navegador, una instancia de un navegador, cuesta.
Así que son más lentos, pero claro, son más potentes.
Vale, ¿veis? Ya ha encontrado el mío. Pues le vamos a dar a run, one integration test.
Está abriendo en Chrome 89. Esto es lo mismo que hemos visto antes.
Ahora vamos a ver si visita la página que le hemos dicho, que debe ser la de notas que tenemos levantada.
¿Vale? Front page ahora la está ejecutando. Perfecto. Bueno, está haciendo otra... Vale.
Ha pasado correctamente, ha visitado la página y ha encontrado esto genial.
El poder ver paso a paso, ¿ves? Aquí estoy, contents notes.
Y le estoy aquí encima y me está indicando al otro lado dónde lo ha encontrado.
Esto es que no os podéis imaginar cuánto tiempo os va a arreglar esto.
Vale, esto puede parecer un poco una tontería, pero además veis que ha ido como paso a paso.
También te indica aquí las requests, las fetch.
En este caso, para recuperar las notas, como lo ha hecho más tarde,
así también puedes ver temas de asincronía, si tienes algún problema asíncrono, ¿no?
De que tú des por sentado que tengas un texto y en realidad es que eso lo estás haciendo más tarde.
Por eso lo puedes ver fácilmente aquí.
Vale, esto pues está bien, pero siempre que os he dicho, siempre que os he dicho en las clases,
que tenemos que ver que los tests están en rojo.
A ver, aquí podríamos hacer, por un lado, copiarlo y ya está.
Guardar los cambios, volver aquí.
Y ves, ya se ha añadido automáticamente.
No he hecho nada mal, no he vuelto a ejecutar ningún comando.
Y ya me dicen, vale, se puede abrir la página.
Yo he abierto la página, pero cuando he intentado entrar esto,
fíjate, ha esperado durante 4 segundos, esto lo espera por defecto,
esto se puede configurar por si necesitan más tiempo o lo que sea,
pero ha esperado por defecto 4 segundos intentando encontrar el WTF este, ¿vale?
Este string de aquí, pero no lo ha encontrado y por lo tanto, pues ha petado.
Así que ya sabemos que nuestro primer test para encontrar el notes,
aunque puede parecer una tontería, al menos nos está diciendo que nuestra aplicación se está renderizando.
A partir de aquí, podríamos empezar a escalar, ¿no?
¿Qué es lo primero que yo creo que podríamos, pues, chequear ahora?
Podríamos mirar el show login.
Como veis, aquí, para crear una nota, podríamos darle a show login y luego crear aquí la nota, ¿no?
Así que vamos a ver si esto lo podemos hacer con un test,
de darle clic y hacernos pasar por un usuario que está haciendo justamente todos estos pasos, ¿no?
De visitar la página, darle clic y ver cómo está haciendo.
Y vamos a ver cómo se le da un clic, justamente.
Así que vamos a copiarnos este, este test por aquí.
En lugar de front page can be opened, le podemos llamar login form can be opened,
porque al final también lo tenemos que abrir.
Tenemos que volver a poner esto del CI visit, porque cada test se supone que debería ser un test totalmente nuevo.
Así que vamos a hacer esto.
Y en lugar de hacer el contains, lo que podemos buscar es que el elemento que contiene el show login,
que justamente, bueno, ahora porque justo me lo he...
Vale, pero es esto, ¿veis?
Aquí el botón show login.
Cuando hacemos el punto contains, esto lo que va a hacer es recuperar ese elemento
y lo que podemos hacer es encadenar una acción que queremos hacer sobre el elemento que encuentre.
Vamos a hacer un clic.
Con esto deberíamos ver justamente que al menos hace clic.
O sea que podemos encontrar ese elemento, que le hacemos clic y ya está.
Vamos a ver.
Vamos a ver por aquí.
Aquí, si hacemos los pasos, podemos ver que ha encontrado el elemento, le ha hecho clic, le ha hecho clic, ¡pum!
Y además fíjate, está bien porque lo que hace es que te enseña dónde ha hecho clic y luego qué pasa cuando hace el clic.
O sea que es genial.
Vale.
Primera iteración, primera refactorización.
Aquí todavía falta, ¿eh?
O sea, ya iremos mejorando nuestros test.
Pero lo primero que ya veo es que cada vez que voy a un test tengo que hacer lo de visitar el localhost.
Esto es un poco de...
¿no?
O sea, porque tenemos que repetir esto todo el rato.
Esto también lo vimos en una clase anterior.
Tenemos la posibilidad de utilizar un before each.
El before each lo que nos va a decir es, vale, antes de cada test tienes que hacer una función.
Por lo que le vamos a decir es que visite la página, que tiene todo el sentido del mundo, ¿no?
Porque si todas van a necesitar visitar la página desde cero, cada test debe ser como totalmente empezando desde cero.
Lo que vamos a hacer es, vale, antes de cada uno visita la página localhost 3000.
Vamos a guardar los cambios, a ver si esto funciona sin problemas.
Bueno, no sé ni siquiera si le ha dado tiempo a esto.
Vamos a hacer raro el test.
¿Vale?
Ahora, para asegurarnos, ves que ahora en el before each ha hecho el visit y luego se está ejecutando el test y tal.
Esto ha sido una pequeña refactorización.
Pero vamos a hacer más en condiciones el login, ¿vale?
Porque yo lo he dejado así, que, vale, puede estar abierto.
Esto significa que está el botón y tal.
Pero yo creo que lo interesante realmente sería ver que el usuario puede iniciar sesión, ¿no?
Que realmente va más allá, que le hacemos clic, sí, pero que puede poner su nombre y cuando le dé clic.
Esto ya sería un test de integración realmente.
El usuario entra a la página, le da un botón, se pone a rellenar un formulario, le da clic e inicia sesión.
Eso ya es un end to end.
¿Por qué?
Porque ya no solo es la parte frontal, sino que además va a comprobar también que el backend, sea el que sea, está funcionando como se espera.
Y que luego el frontend se actualiza con esa respuesta correcta.
Así que, vale.
Por ahora ya hemos visto cómo podemos controlar, recuperar este botón de show login.
Hasta aquí bien.
Ahora lo que tenemos que hacer es recuperar el elemento.
Si miramos un poco lo que tenemos que hacer es ir aquí al...
Bueno, esto ahora porque está con la sesión iniciada, ¿vale?
Pero una vez que inicie, que le demos al botón, tenemos aquí el username y el password, ¿no?
Y luego tendremos que darle aquí a login.
Pues vamos a ello.
Vamos a ver cómo recuperamos este input y este input.
Vamos a hacerlo.
Para eso vamos a utilizar cain y luego punto.
Y aquí utilizamos para recuperar un elemento.
En lugar de decir, recuperamos un elemento que contenga un texto, lo que vamos a hacer es utilizar el get.
¿Por qué?
Porque utilizamos un selector.
Vamos a utilizar un selector.
Así que, recupérame el elemento, el input y luego podemos utilizar un pseudo selector, que se le llama.
Igual que tenemos el hover, ¿vale?
Que es un pseudo selector.
Podemos utilizar uno que es first, para decirle, vale, recupérame el primer input que encuentres.
Porque el primer input, si miramos aquí, si miramos aquí, el primer input es este, el username.
Así que aquí ya podríamos poner type y aquí por ahora voy a poner miduD.
Y lo mismo para el siguiente.
Input y vamos a poner por ahora que es el last.
Vamos a ver si esto funciona porque estoy pensando en algo, pero por ahora lo voy a dejar así.
Y veremos si da algún problema y lo que sea.
La miduPassword.
No me acuerdo cómo hicimos esto.
Igual tengo que crear un usuario, porque el usuario tiene que estar creado en la base de datos de testing.
Esto también lo arreglaremos, para ver cómo lo hacemos mejor y tal.
Por ahora voy a guardar los cambios y vamos a ver qué hace esto.
Vale, ¿veis?
¿Veis que no lo ha rellenado?
Vale, ha funcionado, pero porque todavía tampoco está haciendo ningún test.
Pero lo importante es que lo ha rellenado, ¿vale?
Ha rellenado con los datos que yo le he puesto.
Ahí creo que hay otra forma de hacer esto, que es con otro comando que se puede encadenar, lo digo por si te gusta más, que puede ser así.
Porque el get al final lo que hace es recuperar todos los elementos que tengan este selector.
Claro, si le pones first solo encuentra uno, pero si pones input va a encontrar todos.
Y luego puedes utilizar este método first para recuperar solo el primero que ha encontrado.
Voy a probar y además así pues probaré, ¿vale?
Pues esto también funcionaría.
Esto es de la API, este first y este last, esto es de la API de Cypress.
Esto está en la documentación.
Así que podéis utilizar cualquiera de los dos, el que prefiráis.
Obviamente, esto puede ser un poco problemático, ¿vale?
¿Por qué puede ser un poco problemático?
Porque lo que podemos encontrarnos, por lo que sea, es que tengamos otro input, ¿no?
Este test se va a romper súper fácil.
Porque si en algún momento, imagínate, se pone un buscador aquí arriba.
Pues el primer input que encontraría sería ese, o sea que sería un poquito problemático.
Cosas que se pueden hacer para solucionar esto.
A ver, podríamos ir donde está justamente el login form y tenemos diferentes opciones.
Una puede ser esta, recuperar a partir del name podríamos, o con el placeholder también podríamos recuperarlo.
Al final el selector que pongáis aquí es el que vosotros queráis.
O sea, podéis utilizar, por ejemplo, yo creo que esto debería funcionar.
Vamos a probarlo.
Pero imaginemos que tenemos claro que el placeholder este es único, ¿vale?
Ya no necesitamos el first, ¿vale?
Y como os dije en la anterior clase, utilizar playholders y cosas así puede tener bastante sentido, ¿vale?
Porque al final, aunque sí que es verdad que podríamos recuperar, que esto también lo vimos en la clase anterior,
las traducciones por si cambian las traducciones en nuestra aplicación,
al menos es algo que difícilmente vaya a cambiar.
Y si cambia, a veces puede ser que sea más un problema realmente que tiene la aplicación.
¿Veis?
Esto parece que ha funcionado bien.
Recuperando el placeholder, pues ha recuperado este username.
¿Qué no os gusta el placeholder?
Bueno, podemos ir haciendo diferentes cosas.
Podríamos recuperar el form, poner aquí un data, ¿cómo lo pondríamos?
DataTestID.
Y aquí poner un DataTestID.
A partir de este, recuperar el primer input y el segundo.
Hay diferentes estrategias aquí, ¿vale?
No las voy a hacer todas porque si no podría estarme aquí hasta mañana.
Otra podría ser, yo no soy muy fan de esta, poner aquí una ID.
Y poner aquí login for username.
Al menos algo descriptivo, ¿vale?
No pongáis aquí username porque las IDs tienen que ser únicas en todo el documento.
Y claro, si ponéis esto, pues esto es muy fácil que se utilice en otro sitio.
Así que al menos login for user, en contra de más contexto le deis a la ID, pues mejor.
Yo no soy muy fan porque creo que si se puede evitar, mejor.
Sobre todo cuando estás poniendo una ID, no porque lo necesite el usuario, sino para tu test.
Todo lo que pongas para tu test, si lo puedes evitar, mejor.
Si al final lo tienes que hacer, pues lo haces y ya está.
Pero bueno, esto sería un poco para recuperar.
Pero a ver, que esto todavía nos queda.
Porque yo he dicho, bueno, el login for can be open no sería, ¿eh?
Sería el user can login.
¿Vale?
Que puede hacer login.
No solo que se pueda abrir, sino que puede hacer login.
Ahora, pues un paso más, ¿no?
Lo siguiente que necesitamos sería recuperar este botón, el del login.
Aquí tenemos un problema.
Mira, si yo pongo contains login y hago el clic sobre esto.
Aquí, como está buscando este...
Bueno, lo puedo hacer porque, de hecho, esto es bastante interesante verlo, ¿no?
Claro.
No va a petar porque por ahora no hace nada.
Bueno, sí, sí que va a petar, claro.
Porque el tema es que está viendo que no está...
Bueno, aquí dice que...
Claro.
Porque el primero que ha encontrado ya no está visible, que es el show login que teníamos antes.
¿Veis que ya no está el show login?
Que es el primero que justamente estábamos encontrando aquí.
Claro, como estoy utilizando el texto, claro, login ya no lo encuentra.
Pues aquí un poco lo mismo.
Podríamos ponerle una ID, lo que sea.
Bueno, en este caso vamos a ponerle una ID para que login form, login button.
¿Vale?
Vamos a poner la ID.
Pero yo creo que una forma que podría ser interesante, si al final necesitas ID, sería hacer esto.
¿Vale?
El tener aquí login form con el data test ID, es verdad que eso lo estamos haciendo no para el test,
pero al menos de esta forma podrías este formulario ya controlarlo siempre que necesites en tu test.
¿Vale?
Pero bueno, yo os doy las estrategias y al final podéis utilizar la que prefiráis.
Vale, pues para recuperar esto, pues ahora que tenemos aquí un selector, saco con el selector.
Al menos eso, no pongáis button ni login, sino que darle el máximo contexto posible.
Y ahora sí, hacemos el click.
Una vez que hacemos este click, cuando realmente el usuario se inicia sesión, es capaz de crear una nota.
No lo vamos a hacer, pero ¿qué es lo que yo esperaría?
Cuando el usuario ha iniciado sesión, le sale el node form y le sale este título, por ejemplo, create a new node.
Esto, si miramos aquí, no está por ningún sitio.
Entonces, podríamos buscar, por ejemplo, contains, create a new node.
Y así veríamos si realmente nos está pasando o no el test.
Habría otras formas de hacerlo, por ejemplo, de nuevo, estrategias.
Seguramente yo no miraría un texto, porque una nota podría tener este texto y entonces pasaría el test.
Sería bastante peligroso.
Quizás lo mejor sería ver si está el formulario.
De hecho, este node form, que tenemos aquí el formulario, ¿no?
Pues ponerle aquí el data test ID.
O, por ejemplo, lo que hemos visto esto, ¿no?
El playholder.
Pues podríamos hacer un playholder buscando este input.
A ver si realmente está este input ahora.
O no está.
Vamos a dejarlo así por ahora.
A ver qué.
A ver si funciona.
Vale.
Ground credentials.
Genial.
Esto significa, por un lado, que nos va a petar el test y, por otro lado, que este usuario no está generado en la base de datos de testing para crear este usuario, ¿vale?
Que va a ser nuestro usuario de pruebas.
Luego veremos que esto lo vamos a ir iterando.
Lo vamos a ir iterando.
¿Por qué?
Porque no es buena práctica el hecho de que yo tenga que ir manualmente a mi API a crear un usuario de pruebas.
No tiene sentido.
Y vamos a ver más adelante cómo lo podemos hacer mejor.
Cómo lo mejoramos.
Así que no os preocupéis que todo va iterando.
Vamos a ir a request.
Vamos a ir a create user.
Porque además el usuario todavía no se puede crear en la UI.
Vale.
Aquí tenemos el test 0, 0.
Vamos a poner midu dev.
La midu password.
Voy a guardar esto.
Send request.
¿Vale?
Nos ha creado el usuario.
Además, bueno, esta es la idea y tal.
Por ahora voy a dejar así.
La midu password.
Perfecto.
Cierro esto.
Y, vale, midu dev.
La midu password.
Vamos a ver si ahora esto funciona.
En realidad, lo que he hecho es crear el usuario y ya está.
Pues, vale.
Ya funciona.
Ahora, ha hecho los mismos pasos que antes, pero ahora sí que está el usuario en la base de datos.
Ya os digo, esto no es buena práctica, pero lo vamos a cambiar más adelante.
¿Por qué no es buena práctica?
Porque esto depende de algo colateral que no estamos controlando en el test, ¿vale?
Es un efecto colateral que no estamos controlando en el test y eso no está bien.
Siempre tenemos que controlarlo en los test, ya sea en el before each, crear en la base de datos lo que necesitemos y tal.
Pero lo importante es que funciona el test por ahora, luego recuperaremos un poco el trabajo este que hemos hecho aquí, a ver cómo lo hacemos mejor.
Pero si no os importa, a mí al menos me está molestando un poco tanto rojo.
Yo cuando veo mucho rojo es que me pongo nervioso.
Entonces vamos a arreglar todo este rojo.
Una forma muy fácil y muy rápida de hacer esto sería poner aquí global, ci y bang, ya está, fuera.
Adiós, chao.
Error.
¿Esto por qué?
Porque esto en realidad se está quejando, de lo que se queja es que ci no está definido.
Entonces lo que le podemos indicar al linter es que en realidad esto es global, es una variable global,
y que por lo tanto no está definida porque le viene con el contexto global.
Igual que Windows es global y no está esperando que esté definido en el archivo.
Pero no es la mejor forma de hacerlo.
La mejor forma de hacerlo es instalar, en este caso, a ver si me puedo poner aquí.
Perfecto.
A nuestra aplicación vamos a instalarle un plugin que es slint plugin cypress y lo ponemos en modo desarrollo.
Lo vamos a guardar como dev dependencies.
Lo vamos a instalar.
¿Por qué es interesante el plugin?
Bueno, porque además de arreglarnos esto, también nos va a avisar de posibles errores estáticos
que podemos cometer cuando escribamos los tests.
Por ejemplo, cuando intentamos guardar en una variable algo y nos va a decir,
oye, no, es que esto devuelve undefined, pues deberías hacerlo de otra forma, cosas así.
O cuando intentas encadenar cosas que no deberían y te avisa.
Así que creo que es mejor.
En mi caso, yo estoy utilizando aquí, estoy extendiendo aquí React App.
Vale, no pasa nada.
Hay diferentes formas de hacerlo.
Si estás utilizando React App, pues React App.
Si estás utilizando standard, pues standard, lo que sea.
Al final, lo que necesitamos es decirle, por un lado, el plugin que queremos utilizar.
Así que le decimos, en plugins, esto sería la lista de plugins, le decimos que tiene que cargar cypress.
Voy a guardar los cambios.
A ver si con esto es suficiente.
No es suficiente.
Falta una cosita más.
Y es que, además, le tenemos que decir el environment.
Y en el environment se le puede pasar un objeto y le decimos aquí cypress barra globals y le decimos que esto es true.
Así que, en el environment tiene que tener en cuenta que tenemos las globales de cypress.
Y las tenemos a true.
A ver si ahora.
Ahora sí.
Esto es que, claro, en este caso, React App ya tenía las globales, ya tenía describe, before each, it, after each y lo que sea.
Pero si no lo hubiera tenido, seguramente eso también saldría en rojo.
Y en este cypress globals nos hubiera ayudado también en esto.
Así que es interesante tenerlo porque no controlamos exactamente todas las variables globales que realmente tiene cypress y que necesitamos que nos controle.
Vale, pues hasta aquí bien.
Voy a leeros un rato, va.
A ver qué me contáis.
¿Cómo estáis?
¿Cómo estáis?
¿Cómo os encontráis?
Voy a ver.
¡Buah!
¿Cuánta gente se ha suscrito aquí en un momento?
¿Pero esto qué es?
¿Cómo estáis, hombre?
A ver.
Crispis.
Crispis AG se ha suscrito con Prime.
Gracias.
Gaut Gasala se ha suscrito durante un mes en el nivel 1.
Gracias también.
Muchas gracias.
Esteban, también a ti.
Hace 21 minutos.
A ver, a ver que todo lo que habéis comentado...
A ver, todo lo que habéis comentado no, pero...
Esto queda subido en mi canal de YouTube.
Podéis entrar como midu.tube.
Entráis directos a mi canal de YouTube donde se guardan todas las clases del full stack.
Sí, como habéis visto no hay que importar nada.
Para Cypress ya está todo disponible.
No hay que importar absolutamente nada, ¿vale?
También quedan en Twitch, pero en YouTube además los subo cortados.
Corto trozos que vea que a lo mejor no tiene sentido o lo que sea.
También se mide el coverage del código.
Se puede medir sin ningún problema.
El 3001 es el puerto que estábamos utilizando.
Y cómo simula su login con user y password.
Eso lo hemos visto.
Se puede cerrar el navegador y ver si guardan nuestro token en local storage.
Se puede cerrar y se puede limpiar el local storage sin problema.
Sería mejor poner un name a los elementos.
De hecho, había en el login, tienen name.
Sí que tienen name.
Los otros no.
El name puede ser interesante, pero también puede ser peligroso.
A ver, tanto el placeholder como el name puede ser igual de peligroso.
A mí el name me gusta.
No me desagrada.
También podría ser el name.
El name me parece también una buena opción.
Todo lo que sea, intentar evitar no crear algo para el test, ya estaría bien.
Con clases de CSS, nah.
¿Por qué?
Porque las clases de CSS al final también se romperían y están más pensadas para estilar.
Por ejemplo, poner una clase, a ver, caso peor no está mal.
Tampoco pasa nada.
O sea, quiero decir, hay que priorizar entre uno, etiquetas que ya tienes por el marcado de tu página
y luego irías bajando.
Yo clases evitaría, yo utilizaría antes aquí un data test ID y pondría login form
y tiraría de este hacia los de abajo.
Por ejemplo, una vez que ya tienes esto, pues puedes hacer un cget.
Bueno, aquí porque no tengo Cypress, ¿no?
Pero yo haría algo así.
Data test ID, login form.
Y a partir de aquí ya puedes tirar del input first, por ejemplo.
¿Que esto también se puede romper?
Hombre, sí, pero ya mucho menos.
O puedes tirar del name, ¿no?
Input y aquí, pues del name, que es bastante...
Esto ya me empieza a gustar más, ¿vale?
Esto, algo así.
Y esto, pues ya sabrías que este es el login form y tal.
Bueno, ya os digo, o sea, es que depende...
¿Por qué no os quiero decir, haced esto, ¿vale?
¿Por qué no os lo quiero decir?
Porque es que depende muchas veces de cómo de grande es tu aplicación,
cómo va a crecer tu aplicación.
Creo que esta podría ser una buena forma para una aplicación media grande
o que vaya a crecer, ¿vale?
Y me parece que escala moderadamente bien.
Algo así, ¿no?
Decer el input, utilizando el name.
¿Ves? El name no lo hemos tenido que crear.
Solo creando un data test ID para todo el componente
y entonces luego ir chipeando con el selector.
Esto me parece bien.
Así que, ¿qué más?
¿Qué más, qué más?
Al final, esto es data test ID, que esto se puede borrar con Babel,
pero aún así, aún así, aunque se borre con Babel,
no los pongáis en todos los sitios.
O sea, lo que no tiene sentido es que hagáis esto.
Data test ID.
Esto, que lo he visto en un montón de sitios, esto no tiene sentido.
Login form, username.
Esto.
¿Por qué?
Porque estáis empezando a escribir un montón de código
para un cliente que no existe, que ahora es vuestro test.
Y esto, además, también lo tenéis que mantener.
Aunque luego se borre en producción, que lo tenéis que borrar en producción.
Hay un plugin de Babel que lo hace, ¿vale?
Pero que lo tengáis en cuenta.
Si lo tenéis que hacer, que lo hagáis lo menos posible.
Lo menos posible.
Es verdad que Cypress recomienda esto, que utilicéis esto,
pero por otro lado, React Testing Library lo que recomienda es la accesibilidad.
Y luego, este sería como el último caso.
Yo estoy súper, súper alineado con React Testing Library.
Si podéis, primero, tirar de cosas de accesibilidad o de marcado de vuestra aplicación,
hacerlo, porque te da más sentido.
¿Vale?
Que no llegáis, entonces ya utilizáis esto.
Por delante de las clases.
O sea, primero esto, yo no utilizaría.
Es que clases intentaría no utilizar nunca.
Si no llega la accesibilidad y el marcado, tiraría de esto.
¿Por qué React Testing Library habla de esto?
Porque te dice, vale, el form este no lo puedes recuperar de ninguna forma.
Vale, pues utiliza esto.
Pero a partir de que tienes esto, ya puedes empezar a tirar de marcado accesible
y del marcado que ya tienes.
Entonces, tiras ya de esto.
Ahí es donde yo creo que está, en el equilibrio está la cosa, ¿vale?
Ahí está la cosa.
Y no se puede utilizar aquí el GetByRoll y tal, ¿vale?
Vale.
¿Ves?
En mi empresa hace año y medio, aquí dice Yedinikoto.
¿Ves?
Lo de Data Test.
A ver, esto es una discusión súper enorme.
Y al final habría que ver vuestro código y tal, ¿eh?
Pero lo que os digo, lo que os digo un montón es que yo lo evitaría al máximo
y solo lo usaría donde tenga sentido, ¿vale?
Si lo ponéis en todos vuestros elementos, es que lo he visto y es una verdadera locura.
Además, luego se quedan Data Test ID que ya no se utilizan.
O sea, fatal.
Fatal.
Y quedan en el código que tienes que mantener.
Vale.
Vale.
Tú, tú, tú.
Yo creo que el font debería tener una ID.
Y luego los campos por el name.
Ya que no creo que una app tenga que tener dos font para hacer lo mismo.
Es verdad que no debería haber dos font.
Pero bueno, sí que pueden tener IDs que colisionen.
Hay que tener cuidado con las IDs.
Oye, Sergio, muchas gracias por regalar una suscripción.
Se le ha llegado a TheRolleshark.
Qué grande.
Fantástico.
Bueno, va.
Seguimos.
Seguimos, que si no, no terminamos nunca.
Y además con el Data Test ID podemos estar aquí horas y horas y horas.
Ahora que ya tenemos todo esto, lo que vamos a...
Ya está iniciando sesión el usuario, ¿verdad?
Genial.
Pues lo que vamos a hacer es probar de crear una nota.
Vamos a hacer crear una nueva nota cuando el usuario ya ha iniciado sesión.
Vamos a ver aquí.
Con el Note App voy a hacer esto más pequeñito.
Tenemos el User Can Login.
Pues este User Can Login lo que vamos a hacer es describe.
Y voy a decir, vale, cuando el usuario ya ha iniciado sesión,
pues vamos a hacer aquí otra cosita, ¿vale?
¿Qué es lo que vamos a hacer?
Vale, pues lo que vamos a hacer es que una nueva nota puede ser quedada.
Y aquí nos vamos a encontrar los mismos problemas del Data Test ID y todo esto.
Bueno, veremos cómo lo hacemos, ¿vale?
A new Note can be created.
Vale, vale.
Entonces, antes de poder crear, ¿sabes?
Para iniciar sesión, ¿qué tenemos que hacer?
Pues primero tenemos que iniciar la sesión.
Bueno, pues vamos a copiar todo esto y luego lo arreglaremos.
Vamos a hacer un before each, ¿vale?
Y antes de intentar iniciar crear una nota,
lo que vamos a hacer es hacer todos los pasos que hemos hecho antes justamente para iniciar sesión.
Así que vamos a hacer esto.
Esto ya veréis que es una mala práctica porque Cypress ya nos dice,
oye, no dupliques tu test, ¿no?
No lo hagas dos veces y luego veremos cómo lo podemos arreglar.
¿Cómo creamos una nueva nota?
Bueno, aquí ya como vamos un poco, ya vamos sabiendo,
vemos que tenemos aquí un Show Create Note,
pues es el que tendríamos justamente que clicar.
Pues vamos a hacer esto, punto, clic.
Tendríamos que clicar esto.
Ahora, otra vez lo mismo, ¿no?
Lo del input.
Y aquí podríamos poner cuál sería la nota que queremos crear.
Pues a note created by Cypress.
Vamos a poner esto.
Esto ya os digo que es problemático,
pero ahora lo arreglaremos de alguna forma.
Ahora, c.contains.
Lo vamos a hacer por contains,
pero lo podemos hacer, ¿veis?
Tenemos el botón de save,
pues vamos a hacer el save.
Le vamos a dar un clic
y luego vamos a ver realmente que esta nota aparece, ¿no?
Porque cuando creamos una nota debería aparecer por aquí.
Así que vamos a añadirla a note.
Esto debería estar por aquí.
Ahora, si esto os molesta,
pues podríamos poner note content por aquí.
Lo hacemos así
y ya podréis hacer por un lado el type
y luego la comparación, ¿vale?
Para ver si lo contiene.
¿Ok?
Esto podríamos llevarlo a otro nivel,
¿vale?
Esto es, de nuevo, ¿no?
Estamos mirando el texto,
lo cual es un poco raro
porque esto podría dar un falso positivo
cuando la lista de elementos
ya tenía anteriormente esto.
Entonces tendríamos que ver
que realmente es el último
para realmente verificar
qué es el que se ha añadido, por ejemplo.
Pero bueno, ya más o menos.
Lo que quiero no es justamente deciros
cómo lo tenéis que hacer,
sino veros y daros las herramientas
de cómo más o menos vamos a ir iterando esto
y cómo vamos subiendo cada vez un escalón
de hacerlo mejor y mejor y mejor, ¿vale?
Igualmente es que también estamos
siguiendo la guía de Full Stack Open
y van por aquí los tiros.
Bueno, esto no va a funcionar, ¿eh?
No va a funcionar justamente
porque el click este nos dice un elemento
que no es visible, no sé qué, bla, bla, bla.
Y es justamente por lo mismo, ¿no?
Ah, bueno, este, es que este content,
create a new node,
esto es el before each, a ver.
Vale, vamos a ver aquí
por qué no encuentra el
show create node,
show create node.
Create a new node.
Esto es show,
es que no es, es show create node.
¿Vale?
Vale.
Vale.
Ahora.
Uy.
Vale.
Ahora dice que sí, que ha funcionado.
Vale, sí que lo ha hecho bien.
Y aquí justamente se puede ver
cómo ha creado la nota.
Igualmente este input,
que sí que funciona,
tenemos un poco el mismo problema
que antes.
A mí, una vez viendo esto,
que estamos mucho con inputs y tal,
yo lo que haría justamente
es lo que os decía.
Tener un data test ID,
a lo mejor para los formularios.
Alguien decía que le gustaba tener
que los formularios tengan ID,
pues lo utilizáis.
Y a partir de ese data test ID
o de esa ID,
pues empezáis a tirar de aquí.
¿Por qué?
Porque si no este input,
por ejemplo,
podría ser problemático
y os podría petar
y no funcionaría.
Ya estamos viendo un poco
que vamos a necesitar
controlar la base de datos.
Porque estamos creando
estos tests y estos tests.
Ahora, si yo vuelvo a ejecutar
este test y este test peta,
es lo que os digo,
en la lista de elementos
ya estaría esta nota creada
y ya pasaría
sin necesidad de que funcionase.
Hombre,
y esto no está bien, ¿vale?
Así que tenemos que controlar
de alguna forma
que lo que está en la base de datos
es realmente lo que necesitamos
para nuestro testing.
Para hacer esto,
vamos a ir a la API.
Vamos a tocar un poquito de API.
Ya hacía tiempo
que no hacíamos API.
Y vamos a crear
una ruta especial.
De nuevo,
de esto,
hay 10.000 millones de estrategias.
Y esta,
sin ser la más fiable
o la más tranquila,
o la que te podrías quedar
más tranquilo,
sí que creo
que no está nada mal.
Y en muchos test en tu end,
esto te puede ayudar
justamente a limpiar
la base de datos y tal.
De hecho,
en muchas empresas,
a veces el implementar esto
les cuesta un montón.
Así que cuanto antes lo hagas
y tengas una forma
de hacer esto
o de que la base de datos
la puedas limpiar
cuando tú quieras,
mucho mejor.
La que sea de testing,
no la de producción.
De hecho,
en las de producción
puedes tener controles
para evitar justamente
que hagas ciertos comandos,
para evitar
que te pete
una cosa esta.
¿Qué es lo que voy a hacer?
¿Qué es lo que busco hacer?
Básicamente,
lo que voy a hacer
es tener,
vale,
esto era en mayúscula,
vale,
que ya nos acordamos
en una de las clases
del problema que tuvimos.
Lo que voy a hacer
es tener un nuevo endpoint
que lo que va a hacer
es poder limpiar
toda la base de datos,
tanto de las notas
de los usuarios.
Así que,
en el router,
no os lo estoy explicando esto
porque ya lo hemos hecho
un montón de veces
en las clases anteriores.
Pero estamos haciendo
un nuevo endpoint
donde vamos a tener
la request
en la response
y aquí vamos a llamar
al node,
esto es asíncrono,
así que node
delete many
con un objeto vacío
porque las vamos a eliminar
todas las notas
y los usuarios
igual delete many.
Esto nos va a ayudar
a limpiar la base de datos
para nuestros test
y vamos a hacer
un response
punto status
204
porque al final
es un no content
y terminaríamos aquí.
Hasta aquí bien,
¿no?
Tendríamos un nuevo controlador
que es el de testing.
Ahora bien,
¿cómo podemos...?
Esto no lo podemos poner aquí
en nuestra API
de forma libre.
Ah, bueno, sí,
fantástico,
tenemos un nuevo endpoint
que lo llame quien quiera.
No, no puede ser, ¿vale?
Lo que tenemos que hacer
es controlarlo mejor.
Como os digo,
hay muchas formas
de controlar esto
para evitar justamente
que pueda cualquiera
llamar a este endpoint
y puedes incluso
proteger tu base de datos
para que no puedas hacer
ciertas operaciones
si no tienes ciertos roles
o permisos.
Una cosa sencilla
que se puede hacer
en este caso,
que estamos haciendo aquí
este app.use,
no sé qué,
no sé cuánto,
lo que podemos hacer
es hacer esto.
Esto sería
API testing,
por ejemplo.
Aquí importaríamos
el que hemos hecho
el controlador este
de testing,
así que teníamos
el testing router.
¿Vale?
Testing router,
vamos a importarlo
aquí arriba.
voy a cerrar esto
por aquí.
Testing router,
require,
the controllers,
testing,
vale.
Ahora que tenemos
el testing router,
vamos por aquí,
sería barra
API tal,
pero esto
lo tendría
todo el mundo
accesible
y no queremos
que sea accesible
para todo el mundo.
Una cosa que podemos
hacer es mirar
el node.env
y solo permitir
que cuando el node.env
sea test,
entonces
que tengamos
disponible
esta ruta.
¿Vale?
Esta podría ser
una forma,
hay,
esto porque nosotros
lo estamos controlando
todo de esta forma,
pero hay veces
que esto lo puedes
incluso hacer
de una mejor forma
si controlas tú
la base de datos
y poder llamar
o que solo
la máquina
que ejecuta los test
pueda tener
la posibilidad
de hacer esto.
Hay un montón
de formas de hacerlo
para evitarte esto.
¿Vale?
Levantar la base de datos
también en local,
por ejemplo,
para no tener que hacer esto
y que lo puedas
controlar de otra forma,
hay un montón de formas,
pero en este caso
lo vamos a hacer así.
De hecho,
una cosa que también
puedes hacer
aprovechando el require
que normalmente
se hacen aquí arriba,
lo podríamos poner aquí
para que solo
se haga el require
si el node.env
es test
y así,
bueno,
tampoco es que sea
más seguro,
pero al menos
solo lo vamos a requerir
cuando realmente
lo necesitamos.
¿Vale?
Entonces,
ahora tenemos esto,
voy a tener que resetear
nuestra API,
no sé,
ese type error
que tenía por ahí.
¡Ostras!
Me he cargado algo.
Requires a my work function
but I've got an object.
A ver qué he hecho.
Ah,
porque no he hecho
el módulo,
no he hecho el exports,
a ver,
users,
claro,
es que no he hecho,
no he exportado esto,
¿no?
Esto sería el router,
le podemos llamar
testingrouter,
testingrouter,
module.export,
testingrouter,
ahora,
ahí estás,
vale,
vamos a ver si ahora funcionas.
Vale,
ahora está en 3001,
perfecto.
Vamos a cambiar nuestros tests
para que utilice
esta funcionalidad,
¿vale?
Vamos a ello.
¿Por qué?
Porque,
como os decía,
esta nota,
por ejemplo,
la creamos
y ya no tiene sentido
que esto lo haga.
Lo que vamos a hacer
es que antes de hacer
cada uno de ellos,
lo que vamos a querer
es justamente
que limpie la API.
Así que,
lo primero que haremos,
antes de nada,
vamos a hacer
un ci.request.
Esto lo que va a hacer
es una petición
del tipo
que nosotros le digamos,
en nuestro caso
le vamos a decir
que es post,
porque lo hemos hecho así,
que el endpoint
solo se puede hacer un post
y le decimos la ruta
donde tiene que hacerlo.
En este caso,
localhost,
3001,
API,
testing,
creo que era reset,
si no me equivoco.
Vamos a mirarlo un momento.
Reset,
¿vale?
Reset.
Esto sería
la request.
Perfecto.
Hace la request,
limpia la base de datos
y ya lo tendríamos.
Ahora,
por otro lado,
vamos a crear un usuario.
¿Por qué?
Porque este usuario
que teníamos por aquí
es lo que os decía.
O sea,
no tiene sentido
que ya esté creado
este usuario.
Así que vamos a crearlo
desde el principio.
Vamos a poner que tiene
como nombre Miguel.
Vamos a ponerle,
creo que a username
y password.
Y el password
le vamos a poner
la midu password,
¿vale?
Así que,
de esta forma,
ya este usuario
nos vamos a asegurar
que sí que funciona.
Que sí que va a estar
en la base de datos,
pese a que lo borremos todo,
porque lo vamos a crear
manualmente.
¿Cómo se crea en un usuario?
Porque, claro,
el usuario,
si os acordáis,
no lo podemos crear
de la interfaz.
Igualmente,
tiene sentido
que utilicemos la API
para crear el usuario
directamente.
Porque si no,
vamos a volver a hacer
lo mismo que os he comentado
antes, ¿no?
De testear,
de hacer los pasos
en la UI
cuando eso debería
tener un test propio.
Y lo que estaríamos haciendo
es duplicar el test.
Y no tiene sentido.
Así que,
tenemos la request,
el post,
para hacer el reset,
creamos el usuario,
creo que es username.
Si no,
lo podemos mirar rápidamente
aquí en la request.
Create user,
username,
name,
password.
De hecho,
es que me podría haber copiado este.
Me podría haber copiado este,
justamente.
Pero bueno.
Y aquí lo mismo,
pues hacemos la request,
con post,
HTTP,
localhost,
3001,
API,
creo que era users
o users.
Y lo que hay que pasarle
también es el objeto.
Así que,
el tercer parámetro,
mira,
de hecho,
creo que el tercer parámetro
sea la configuración.
Al final,
el request este que veis aquí,
está utilizando por detrás axios.
Así que,
si sabéis utilizar axios,
os vais a encontrar
que tiene cosas muy similares
a la hora de pasarle parámetros
y cosas así.
En este caso,
le podemos pasar directamente
el JSON
y esto se lo va a pasar
y debería funcionar correctamente
sin ningún problema.
¿Vale?
De esta forma,
vamos a guardar los cambios,
a ver si funciona todo lo que hemos hecho.
Parece que el login,
parece que sí.
Vale.
Pues esto,
ha tenido que ejecutar,
como veis,
ya ha llamado al 204
de la API Reset,
o sea,
que ha reseteado
toda nuestra base de datos
y luego ha creado
un nuevo usuario.
Pues perfecto,
esto ha funcionado bien.
Aquí,
no tenéis que preocuparos
de que haya una race condition
porque justamente
lo que hace Cypress
con estos comandos
es encolarlos
y son totalmente asíncronos,
pero aunque tú no veas
una sync aquí,
lo que hace internamente
es esperarlos.
¿Vale?
Entonces,
no te asustes de ver
esta request
que no se está esperando ni nada
y ya hacemos esto
que parece que va a haber
una race condition
de a ver cuál termina antes
porque al final
lo que haces es
esta petición
va a esperarla
y luego hará la siguiente.
Entonces,
no te preocupes
por un tema de race condition
que no va a pasar nada.
Ya funcionan nuestros test.
Ahora tiene bastante más sentido
que lo que estábamos haciendo antes.
Así que vamos a ver
de cambiar la importancia.
Bueno,
lo de cambiar la importancia,
esto sé que es una cosa
que no funcionaba en la UI.
Entonces,
lo podríamos hacer,
podríamos hacer el test
y podría dejarlo como deberes
por si queréis arreglar el test.
Esa podría ser una de ellas
que podríamos hacer.
Por ahora me lo voy a saltar
y vamos a hacer
el de contraseña incorrecta
y todo esto
para ver
y luego si nos da tiempo
haremos el de
el de cambiarle la importancia
a una nota.
¿Vale?
Así que vamos con el de
la contraseña incorrecta.
Para contraseña incorrecta,
¿qué podemos hacer?
Pues un poco lo mismo, ¿no?
Aquí,
login fails,
with ground password.
¿Y qué va a ser interesante
de esto?
A ver,
lo que os quiero enseñar en esto
es una forma
en la que podéis
hacer el expect
de los test.
No solo
como lo hemos hecho hasta aquí, ¿no?
Que al final está haciendo click,
que contenga,
a ver si realmente
se contiene un elemento,
si existe o no existe.
Y vais a ver
que hay una forma
mucho más interesante
de hacer test con Cypress.
Entonces,
vamos a ver
el ejemplo
de fallar el test
y que busque realmente
si tiene en algún sitio
el error de ground credentials
que hemos visto antes, ¿no?
¿Qué tenemos que hacer?
Pues, a ver,
es muy parecido
a lo que estamos haciendo aquí.
Solo que,
en lugar de poner, pues,
midu def
y la midu password y tal,
pues aquí deberíamos poner
password incorrecta,
por ejemplo, ¿no?
Esto debería ser
muy similar.
Ahora,
deberíamos buscar
realmente
que tenemos
los ground credentials.
Vamos,
voy a poner por ahora,
voy a poner aquí
lo que sea,
a ver si peta,
que debería petar
y vamos a ver.
Vale,
ground credentials, ¿vale?
Pero veis que
no está encontrando
este texto
y por lo tanto
peta después de 4 segundos.
Esto como es un poco
coñazo
el hecho de que
es un poco molesto
que se ponga a ejecutar
todos los test.
Entonces,
aquí también podéis utilizar
el punto only,
que esto lo vimos también
en una clase anterior
que os comenté,
solo para ejecutar un test.
Entonces,
vamos a poner solo
el punto only aquí
para que solo nos ejecute.
¿Veis?
Ahora solo ejecuta este test,
solo está ejecutando
uno en concreto.
Así nos podemos enfocar
en ese y no que se ejecuten
todos porque es un poco molesto.
Así que,
vamos a ejecutar este.
Ahora,
vamos a buscar
el ground credentials,
a ver si esto existe
y efectivamente
tendría que existir
porque lo acabo de ver.
Ground credentials.
Vale, sí,
verde.
Es que digo,
pensaba que estaba esperando.
Verde,
perfecto.
¿Qué pasa?
Que aparte de esto,
se puede hacer
de otra forma
el hecho de buscar
si realmente contienes algo.
Vamos a hacer algo.
El ground credentials
está en nuestro componente
notification,
que es este de aquí.
ya teníamos un class name
que es error.
Ya os he dicho
que no soy muy fan
de utilizar class name,
pero bueno,
por ahora,
ya que está el class name
y para que veáis
que se puede utilizar
el class name si queréis,
pues hacer el get
con el error
y aquí tendréis el contains
con el ground credentials.
Esto sería una forma
de hacer el check,
ver si justamente el error
contiene ground credentials,
me miraría el texto,
funcionaría,
perfecto.
Hay otra forma
de hacer este tipo
de comprobación
que creo que muchas veces
tiene más sentido
y es bastante más explícito
y además te permite,
como veremos ahora,
encadenar cosas
que eso está bastante genial.
Por ejemplo,
le podemos decir
el .c.getError,
este elemento error,
debería contener
y ahora le decimos
el ground credentials.
¿Vale?
Si ahora quito esto,
esto sería otra forma,
lo puedes hacer en una línea,
eso soy yo que ya
me estoy adelantando.
Puedes hacer getError,
debería contener
ground credentials.
Entonces guardando los cambios,
ahora esto,
pues funciona correctamente
y además se lo pone en verde.
Además fíjate
que es bastante más interesante,
que te dice assert,
o sea ya,
es un poco más explícito
y esto la verdad
es que ayuda
en el tema del testing.
Vale,
lo mejor de esto
es que aquí
lo podéis mirar
en la documentación
porque tiene un montón,
pero hay alguno
que es muy, muy, muy interesante
como por ejemplo
mirar si tiene,
esto debería hacer un shoot
y aquí puedes mirar
si tiene CSS
y entonces puedes mirar
que tenga unas propiedades
en concreto.
Si miramos
el ground credentials,
este de aquí,
además,
no os lo he comentado antes,
pero podéis pinear
un estado,
¿vale?
Imagínate que quieres
entrar en este,
pues le puedes dar un clic
y entonces se queda,
se queda como está
la UI en ese momento.
Eso es brutal.
Vale,
pues este ground credentials
que tenemos aquí,
¿veis que tiene unos estilos
en concreto?
A ver,
normalmente hacer testing
sobre estilos
no es,
o yo no lo recomendaría
o no me parece muy interesante,
¿vale?
¿Por qué?
Porque realmente los estilos
lo que va a hacer normalmente
es cambiar,
o sea,
no tiene mucho sentido
pensar que iba a poder mirar
ahí los estilos,
igual se puede,
pero no,
hacer logout aquí,
login.
Entonces,
una cosa que puedes hacer
si te interesa
es mirar el tema
de los estilos.
Con el container
lo puedes encadenar,
yo os quería enseñar
lo de encadenar,
pero bueno,
así podemos mirar.
Ay,
es que solo dura
un momento.
Bueno,
si no,
color red,
por ejemplo,
color red y font size,
half 6,
aquí le puedo decir
que el color sea,
creo que con red
debería funcionar,
si no,
vamos a probar aquí,
half 6,
y aquí le podemos decir
border style,
podemos decir,
creo que era solid,
¿no?
Lo mejor de todo
es que lo puedes encadenar.
Dices,
este elemento
debería contener esto,
debería tener CSS este,
debería,
y puedes concatenarlo,
y al final,
al encadenarlo
queda mucho más claro.
Y si miramos un poco los tests,
aquí,
vamos a ver si pasan,
vale,
el error,
se ha quedado ahí
con el error.
Bueno,
ha pesado uno,
pero otro no.
Bueno,
porque el valor,
esto es una de las razones
por las que no me gusta mucho el,
ves,
yo tengo el CSS red
y aquí me está diciendo
que tiene RGB 255,
porque realmente ese es el que tiene computado,
y el que está computando es este.
A ver,
yo no testearía CSS,
a no ser que sea algo súper importante.
Lo que os quería enseñar
es que podéis encadenar los checks
y justamente os salen aquí,
¿vale?
Y si falla uno de ellos,
os diría justamente el que ha fallado.
Y todo esto visualmente,
lo cual lo hace bastante potente.
Y que fíjate que tienes hasta la posibilidad
de mirar el CSS.
No es lo más útil del mundo.
A veces pueden mirar,
¿no?
Si, por ejemplo,
ya te digo,
si es importante realmente tener una negrita.
Un ejemplo de una cosa
que en mi empresa miramos,
¿no?
Nosotros tenemos productos destacados
y muchas veces,
muchos clientes se nos han quejado
de que pese a que pagan el producto,
no le aparece con unos estilos en concreto
que llaman la atención.
Claro,
para nosotros es un tema de negocio
súper importante
y tiene bastante sentido
que hagamos a veces un end to end
porque se tiene que hacer
unos cuantos pasos
para justamente ver eso,
¿no?
Y lo tenemos ahí
para evitar que esto no vuelva a ocurrir
porque a una vez
ha sido un fallo nuestro.
Así que,
para que lo sepas,
cuándo te puede ayudar
este hub CSS.
Es un ejemplo un poco tonto,
pero a nosotros nos ayuda.
Vale,
vale.
Dicho esto,
tenemos esto del show login
que os quería comentar antes,
¿vale?
Una mala práctica
que estamos haciendo aquí.
Voy a quitar el only.
Una mala práctica
que estamos haciendo aquí
mirando nuestros test,
si te fijas,
voy a poner esto,
voy a hacerlo todo más pequeñito
porque creo que se repite solo aquí,
¿vale?
Creo que Cypress lo comenta
su documentación
y tiene todo el sentido del mundo,
¿vale?
Porque si miras este test,
este test que estamos haciendo aquí,
es exactamente lo mismo
que estamos haciendo aquí.
Esto es una mala práctica
porque realmente estamos testeando aquí
y tenemos el test repetido
para aprovecharnos
de lo que está haciendo aquí,
¿no?
Estamos como forzando la navegación
de decir,
vale,
ahora que sé que se puede hacer login,
hago aquí el login
y además copio todo y tal.
Siempre que puedas,
siempre que puedas
y a veces no es fácil,
pero siempre que puedas,
evita esto.
Esto hay que evitarlo.
Entonces,
claro,
me preguntarás,
vale,
pero entonces esto,
¿cómo lo hago?
Bueno,
pues cuando vas a utilizar
un before each
y cosas así,
excepto algunas veces
que tiene sentido
que pues navegues
y hagas algunas cosas,
este tipo de cosas
hay que buscar la posibilidad
de hacerlo directamente
con la API
en lugar de hacer esto,
¿vale?
Porque al final
lo que estás haciendo
es volver a testear algo
que has testeado anteriormente.
En este caso,
si nos acordamos
para nosotros
hacer un login del usuario,
pues tenemos que hacer
una request,
tendríamos que hacer
http
barra barra localhost
barra 3001
esto,
barra app
y barra login,
perdón,
aquí tendríamos
el objeto
de la configuración
que le tenemos que pasar,
tendríamos el username
y tendríamos por otro lado
el password,
¿no?
El username,
aquí lo tenemos,
es midudev,
pues le ponemos aquí
midudev,
tenemos el password
y tendríamos
la midu password,
¿vale?
Esto sería el objeto
que le queremos pasar
para hacer login.
Ahora,
esto nos devuelve
cierta información.
No se puede utilizar fácilmente
una singa wait
en este caso,
así que hay que utilizarlo
como una promesa,
pero la request
al final devuelve una promesa
y podemos recuperar
la respuesta,
así que tendríamos
la response aquí.
¿Qué es lo que nos devolvía
la información de la API?
Espero que te hayas estudiado
súper bien,
pero esto es lo que nos devolvía
era el token
que necesitábamos justamente
para estar logados.
Si miramos
cómo lo hacíamos,
lo guardamos
en el local storage,
¿verdad?
Y esto
es lo que nos estaba diciendo
si un usuario
realmente estaba logado
o no,
si había
iniciado la sesión
o no.
Aquí,
este window
local storage
set item
con esto.
Pues lo que podemos hacer
justamente
en esta response
nosotros
podemos utilizar
el local storage.
Podemos hacer
local storage
punto set item
porque al final
tienes que acordarte
que los tests
se están ejecutando
en el navegador.
Esto es algo
que es bastante diferente
a cómo funciona
Selenium
que hay que hacerlo,
se puede llegar a hacer,
pero no es tan sencillo.
Así que
lo mismo que estamos haciendo
aquí con el window
punto local storage
y tal,
lo podemos hacer aquí.
Esto lo vamos a poner así,
local storage
punto set item,
vamos a guardar
la información esta,
este response
que nos ha llegado
lo vamos a poder guardar aquí,
solo que hay que tener en cuenta
pues igual que en Axios,
que la respuesta
no tiene directamente
el cuerpo
de la respuesta,
sino que tenéis que acceder
a la propiedad
body.
así que response
punto body
y esto debería tener
ya nuestra funcionalidad.
Este before each
que teníamos por aquí,
en principio
esto debería funcionar,
esto lo podemos eliminar
porque ya no tiene sentido.
Esto al final
lo que está haciendo
es simularlo
de otra forma
sin pasar realmente
por tanto
por la UI,
¿vale?
Estamos evitando
pasar la UI
y esto
lo hace bastante
más interesante
porque imagínate
por lo que fuese
que peta este test
porque has cambiado
un playholder.
Imagínate
que claro
al cambiar
todo este playholder
en lugar de petar este test
no solo peta este test
sino que peta este
y todos estos,
todos los que estuviesen
aquí dentro.
Claro,
el ruido
que te genera eso
es mucho mayor
que solo si te peta este
porque has cambiado
un playholder
por lo que sea.
Así que por eso
es buena práctica
hacer este tipo de cosas.
Saltarte a la UI
cuando quieres hacer
esto de
crear un usuario
o por ejemplo
iniciar una sesión
si lo puedes evitar
y puedes hacer esto
mejor que mejor
¿vale?
Vamos a ver si esto funciona
que no lo hemos probado
vamos a ver
¿vale?
Parece que
funciona
funciona correctamente
de hecho esto lo hemos hecho
en el
when log in
¿no?
Ah no, pues mira
no funciona
Peted, find, show, create
no sé qué
bueno, vamos a ver
lo que ha pasado
y ya está
vamos paso a paso
vamos aquí
esto es el before each
esto tiene otro
before each
que esto lo que hace
es el login
pero este login
si levantamos
las
si abrimos
las herramientas
de desarrollo
creo que nos dicen
nos debería decir
en la consola
vamos a poner por aquí
ostras
en la request
creo que nos da
la información
de cómo ha ido
y qué ha hecho
y tal
¿ves?
esta es la que hemos enviado
con mi dev
password
no sé qué
atendemos el body
bueno pues aquí estamos
Miguel
el token
el mi dev
vale
pues esto
ah
vale
claro
yo he iniciado sesión
pero como tal
no estoy volviendo
a renderizar la aplicación
lo que debería hacer
con esto
una vez que ha hecho esto
es volver a visitar la web
¿no?
porque de esta forma
sí que
claro
como no lo estoy haciendo
en la UI
la UI no está respondiendo
pero sí que puedo guardar
el local storage
y volver a acceder
a la aplicación
porque de esta forma
sí que debería tener
ahora sí el token
correcto
o sea debería tener
el local storage
eso lo verá bien
desde el principio
y de esta forma
debería
debería funcionar
uy
me ha dado un 401
ahí que no está autorizado
ah por el
ground credentials
vale es normal
pero ahora sí que ha funcionado
¿vale?
es en este
a new node can be created
vale
pues ahora ya estaría
¿qué pasa?
que esto de iniciar sesión
a ver es súper útil
esto de
de usar
o sea
de iniciar sesión
es brutal
es súper útil
tenerlo aquí
imagínate que ahora
en otro sitio
me gustaría utilizar esto
pues claro
es un poco
rollo
el tener que volver
a copiar esto
para utilizar
y reutilizar
este tipo de código
en otro sitio
lo que tienes que hacer
es crear un comando
de cypress
¿vale?
en cypress puedes crear
tantos comandos
como quieras
los puedes añadir
y ahora verás
cómo los puedes utilizar
es súper sencillo
súper potente
aunque yo tengo que decir
que a mí
hay una cosa
que no me gusta
de cypress
que os la comentaré después
pero bueno
luego os la comento
por ahora vamos a hacer
el comando
¿cómo se hace un comando?
para hacer un comando
vamos a ir a la carpeta
support
vamos a commands
y veréis que aquí
ya tenía como un montón
de comandos
y tal
estos comandos
bueno
están todos comentados
hay algunos que pueden ser
interesantes
bueno ya
fíjate que hay uno
que pone
cypress commands
add login
bueno
¿por qué?
porque es súper típico
un comando de hacer login
entre ustedes
en tu en
súper típico
así que vamos a eliminarlo todo
y vamos a hacerlo paso a paso
primero
cypress
punto
una vez que tenemos cypress
commands
y le decimos
añádeme un comando
y le decimos el comando
que tiene que añadir
en este caso
le vamos a llamar login
los parámetros
que vamos a poder pasarle
a este comando
por un lado username
y por otro password
ahora
voy a cerrar esto
para que salga bien
ahora ¿qué es lo que hace
este comando?
pues es lo que acabamos de hacer
básicamente
el comando va a hacer
todo esto
todo esto
¿vale?
con el visit incluido
porque el visit es importante
justamente para
como que haya iniciado
la sesión el usuario
para como
no sé
simularlo
de alguna forma
así que username
password
esto se lo vamos a pasar
por parámetro
así que
bueno
puedo dejar como estaba
lo demás
debería ser exactamente igual
¿vale?
así que
esto
ya lo podemos eliminar
y ahora
¿cómo le podemos decir
que quiero que utilices
justamente este comando?
pues muy sencillo
le tenemos que hacer
cy
punto
y el comando
login
que es el comando
que nosotros hemos creado
de esta forma
tú puedes tener tantos comandos
como quieras
que los puedes utilizar aquí
para reutilizarlos
tantas veces como quieras
y cuando quieras
¿vale?
ahora hay que pasarle
los parámetros que espera
username
¿vale?
miodef
password
creo que da
la midu password
no me acuerdo si era este
pero si no es esta
ahora lo descubriremos
ahora si guardo los cambios
pues esto
debería funcionar bien
y si no
pues lo volveremos a revisar
a ver qué pasa
¿vale?
ha funcionado correctamente
si miro una nueva nota
que se ha creado
pues esto
deberíamos tener por aquí
claro
no aparece
que esté utilizando
el comando
pero
justamente está haciendo
los mismos pasos
que estaba haciendo antes
así que perfecto
¿vale?
esto por aquí
vamos a ver
¿qué más tenemos por aquí?
a ver
una cosa que
que al menos quería comentar
es el tema de utilizar
el as
a ver cómo os puedo comentar esto
¿con qué ejemplo os puedo comentar esto?
cuando creamos notas
cuando
para crear diferentes notas
a ver
¿cómo lo hacemos?
la nueva nota
bueno
vamos a empezar
vamos a empezar el tema
del
el de cambiar la importancia
de una nota
y ya está
así de esta forma
si vemos que peta
a lo mejor nos ayuda
justamente a arreglar
lo que falta nos hace
¿por qué?
porque cuando estamos aquí
y hacemos login
bueno ahora no funciona
el login este
porque no sé cuál es
a ver
midu dev
la midu password
login
se supone que
le debería poder
dar aquí a un botón
¿ves?
esto peta
por beta saber
qué motivo
porque no terminamos
nunca de hacer
esta funcionalidad
la podríamos revisar
a ver qué pasa
pero vamos a hacer un test
de lo que nosotros
esperamos que pase
y así
que nos ayude
a arreglarlo
¿vale?
así estar ahí
todo el rato
haciendo watch
hasta que por fin
lo arreglemos
y miraremos
cuál es el problema
para hacer esto
lo primero que vamos a mirar
es que importan
esto era false
importan
no era true
el por defecto
vamos a ver dónde
se añade una nota
creo que eran servicios
notes
¿vale?
cuando creamos una nota
estamos pasando
el new object
aquí
aquí
punto create
note object
add note
se estaba añadiendo
la nota
claro
no se le estaba pasando
ni siquiera
cuál era el
si le importan
era por defecto
o lo que sea
¿no?
create
pensaba que teníamos
un create note
por ahí
pero ya veo que no
note object
entonces
cuando tenemos
el note object
a ver
note form
add note
y el importan
era un random
esto es lo que estamos haciendo
estamos haciendo un random aquí
y algunos salían que sí
y otros que no
vamos a hacer que sean todos false
¿vale?
que cuando creemos una nota
siempre sea false
y así podremos crear
esto
lo hacemos para
para probar al test
¿vale?
que se creen false
y entonces
que le podamos cambiar
justamente la
la importancia
¿no?
y a esto debería
hacer una llamada
a la API
ver que realmente
cambia visualmente
y cosas así
así que
vamos a nuestro test
por aquí
login fails
¿vale?
cuando un usuario
ha iniciado sesión
puede crear una nueva nota
y también
debería
no sé si poner
no sé si ponerlo dentro
o sea
podríamos poner
describir otra
¿no?
que sea
esto ¿no?
que una nota existe
y cuando una nota existe
pues entonces hacemos
antes de la nota
que esto también
lo deberíamos hacer
con la API
pero antes de la nota
podríamos hacer
que contiene
¿no?
porque esto es
que haya iniciado sesión
que ya ha podido crear
una nueva nota
pues antes del before each
este
podríamos hacer justamente
esto que acabamos de hacer
que nos cree una nota
que haga un post
para crear la nota
para hacer eso
pues
hacemos una request
con el post
http
localhost
3001
API
notes
y aquí deberíamos pasarle
la nota
¿no?
que le queremos pasar
claro
aquí hay un tema interesante
vale
mira esto es interesante
si queríamos
si nos gustaría
probar esto
¿cuál es el problema
que nos podemos encontrar aquí?
que el objeto
que le tenemos que pasar
es un poquito más complejo
no vamos a poder hacerlo así
¿por qué?
porque cuando creamos
una nota en la API
fíjate
cuando creamos una nota
vale
create post note
tenemos que pasarle
header de authorization
entonces claro
hay que pasarle una cabecera
no es tan fácil
como decirle post
no sé qué
no sé cuánto
así que esto
lo vamos a tener que transformar
le vamos a decir
que el method
es post
básicamente le vamos a pasar
un objeto
con toda la información
de todo lo que debería hacer
es un método post
la url
a la que tienes que ir
creo que esto lo tenía
no lo tenía pegado
localhost 3000
API
notes
vale
esta sería la url
el método ya lo tenemos
le tenemos que pasar el body
que el body
podríamos poner
content important
vamos a poner que esto es false
y el contenido que sea
a note created from cypress
esto ahora lo vamos a extraer a un comando
para que lo puedas utilizar como tú quieras
aparte del body
le tenemos que decir los headers
que aquí es donde está lo importante
los headers de donde los saca
authorization
a ver si lo escribo bien
que como lo escriba mal
luego cualquiera lo encuentra
authorization
vale
vale
aquí tendríamos el header
y aquí tendríamos que pasarle
el token de autorización
para poder hacer
estas requests
¿de dónde sacamos esto?
pues esto
lo deberíamos poder sacar
de local storage
local storage
get item
porque justamente
en el comando de login
lo estábamos guardando
en local storage
como aquí se supone
que ya está el usuario
con la sesión iniciada
porque tenemos aquí el test
o en login
antes se loguea y tal
esto lo deberíamos tener disponible
o sea que debería ser capaz
de recuperar del local storage
esta información
entiendo que esto
en el log not app user
esto al final
lo que se guarda aquí
es todo
si recuerdo mal
todo el usuario
por lo tanto
lo que vamos a hacer aquí
sería json.parse
vamos a parsear
todo lo que tenemos
en local storage
y lo único que vamos a recuperar
sería el token
porque en local storage
hemos guardado un objeto
pero en local storage
solo se puede guardar un string
así que lo parseamos
para recuperar el objeto
y accedemos a la propiedad token
tela
solo para esto
esto sería la request
entiendo que ya no deberíamos tener nada
podríamos hacer de nuevo
hacer la request
y para ver
en la UI
reflejados los cambios
pues deberíamos hacer
de nuevo el visit
este
uy
30.001 o no
porque deberíamos ver
de alguna forma
que la nota se ha creado
o sea creamos la nota
y refrescamos la página
para ver el cambio
porque como no usamos la UI
la UI no tiene ni idea
de que eso está pasando
en la base de datos
así que tiramos de
de base de API
hacemos esto
y ya estaría
vale
entonces
ahora
podríamos hacer
que se puede cambiar
cuando una nota existe
puede ser
it can be made important
vale
vamos a ver
si podemos hacerla importante
ahora
ahora
que sabemos
la nota
que estábamos creando aquí
la podríamos buscar
podríamos decir
vale
pues esta nota
que me estás diciendo
que es importante
tendría que ser tal
a ver
pues si contains
a note
tal
vale
como puedo buscar
porque esto es interesante
esto lo que me busca
es el elemento
que tiene este texto
vale
porque justamente
lo estoy creando aquí
y sé que lo va a tener
el tema
es que una vez
que tú encuentras
un elemento
te devuelve ese elemento
y después
puedes seguir buscando
esto es un poco parecido
a lo que os estaba comentando
al principio de la clase
tú puedes decir
data test ID
buscar ese
y a partir de ese
buscar el resto
de selectores
de elementos
y tal
con el contains
puedes hacer lo mismo
tú puedes decir
vale
búscame el texto
el elemento
que contiene
este texto
vale
que será una nota
si vamos al componente
de las notas
veis aquí en Lee
tenemos este elemento
que aquí es donde
estará el texto
cuando nos devuelva
el elemento
será este elemento
y podremos buscar
justamente
el botón
que debería tener
el label
de make important
vale
debería
vamos a verlo
make important
esto debe
al menos esto
debería funcionar
y si no
lo revisamos
ahí
debería haber puesto
no Lee
porque ahora
ves
los va a hacer
todos
vale
no le ha gustado
http
localhost
because you are
attending to visit
that is
of a different
what
entonces lo he puesto
localhost
que ha pasado aquí
que ha pasado
que ha pasado ahí
he puesto en https
ah
es que es 3000
es que he puesto 3001
vale
eso es interesante
no puedes ponerte
a visitar
las páginas
que te dé la gana
ya sabes
sino que tiene que ser
justamente la misma
que en la que estás
funcionando
vale
vamos por aquí
ahí el only
lo voy a poner
lo voy a poner ahora
al menos estas
venga
vale
fíjate todas las cosas
que hacemos ya antes
vale
bueno
ha funcionado correctamente
si vamos viendo los pasos
un poco
y vamos viendo la UI
pues podemos ver
que al final
me aparece el botón
de make important
ahora lo que me faltaría
es darle un clic
y tal
pero una cosa
que te quiero explicar
aquí
porque creo que es
bastante interesante
y es bastante potente
a la hora de trabajar
con esto
es el hecho
de que
bueno
primero vamos a arreglar
esto
de los commands
vamos a poner
otro comando
commands
create node
que le podamos pasar
esto
esto no es así
esto es add
y aquí le ponemos
el nombre
create node
aquí le ponemos
el content
y el
como era
important
a ver
important
content
important
vale
y ahora esto
lo que va a hacer aquí dentro
es todo lo que hacemos aquí
esto es súper interesante
hacerlo
porque de esta forma
ahora podemos crear notas
tantas veces como queramos
donde queramos
y ya está
solo que vamos a quitar esto
para que no sea siempre el mismo
sino que sea el que le pasemos
por parámetro
ahora este create node
lo vamos a utilizar aquí
create node
y le vamos a pasar
justamente
este objeto de aquí
porque es lo que espera
como parámetro
vale
ahora borramos esto
y ya está
se me ha quedado eso ahí
vamos a ponerlo aquí
con un salto
para que se entienda mejor
vale
imagínate
que pasa con esto
que pasa con esto
que imagínate que yo creo aquí
más de una nota
vamos a crear más de una nota
this is the
this is the first
note
this is the second note
y
this is the third
note
vale
vamos a crear tres notas
las tres con
importan a false
y tal
vale
entonces lo que podemos hacer
para justamente
buscar
imaginemos
que quiero
solo ver
que es la segunda nota
vale
hago esto
hasta aquí
pero el tema de esto
es que cuando
lo que quiero comprobar
aunque ahora me va a petar
porque ya sabemos que no funciona
es vale
voy a buscar este elemento
que es la segunda nota
que contenga
make important
y le voy a hacer click
vale
esto debería petar
porque no funciona correctamente
pero
claro
una vez que haga click
me gustaría volver a recuperar
la misma
o sea
me gustaría volver aquí otra vez
pero ver que contiene otra cosa
que sería
make not
make not important
vale
quiero ver que realmente
ahora tiene otra cosa
diferente
vale
o sea que me gustaría
revisar que realmente
ha hecho ese cambio
que
se pueda
bueno en este caso es
make important
make can be made important
exacto
o sea
make important
le hacemos importante
y me gustaría ver que el texto
ha cambiado
y tal
si te fijas aquí
lo que estamos haciendo un poco
es volver a repetir
otra vez
el mismo
lo mismo
o sea
estamos recuperando el mismo
y es un poco
que se puede hacer en este caso
a ver
en este caso
se podría
aquí
esto es una de las cosas
que yo decía que no me gustaba
de cypress
porque
mucha gente
cuando ve cypress
y con razón
se cree que es javascript
o sea
que yo podría hacer algo así
¿no?
guardar aquí la
second note
que esto es algo
que sí que vas a hacer
en react testing library
un montón
y guardar esto
así
entonces
en lugar de repetir
otra vez
guardar en una constante esto
así ¿no?
y decir bueno
pues al menos
ahora
tengo esto funcionando correctamente
tengo el second note
que contiene esto
y ahora luego
que contenga esto
al menos
tengo una forma más sencilla
de hacerlo
pero esto no funciona
esto no funciona
no funciona
porque esto
aunque no lo parezca
esto es un método
que es asíncrono
y esto lo que te devuelve
es undefined
o sea
esto no devuelve nada
esto lo que hace
Cypress
es encolar
todos estos comandos
y lo hace
de una forma síncrona
y tal
es un poco rollo
así que como no puedes
depender de que esto sea
javascript de verdad
ya te dan
una funcionalidad
justamente
para que puedas
reutilizar un elemento
de forma sencilla
lo que puedes hacer es
vale
cuando tengas este elemento
me voy a referir a él
como
y le puedes decir
como te quieres referir ahí
the note
la nota
por ejemplo
entonces
una vez que tengas esto
puedes decir
ci
punto get
y puedes utilizar
con un arroba
justamente el selector
que has indicado
puedes decirle
vale
la nota
y esto
al menos sería una forma
de reutilizar
este tipo de selectores
habría otra
otra forma de hacerlo
porque al final
como os decía
esto es una promesa
puedes hacer un punto den
y aquí
pues podrías hacer
pero
ya
empieza a quitarle
un poco de la magia
que tiene Cypress
de que
aparezca
que es código
síncrono
que va de arriba abajo
que se puede leer
muy fácilmente
así que
esta sería la forma
de
yo creo
más interesante
de hacerlo
se lee un poco raro
no lo voy a negar
de que se pone al final
pero al menos
te permite reutilizarlo
y esto puede ser muy útil
cuando tienes un montón
de elementos
y tienes que
revisar más de una vez
si ha cambiado
de alguna forma
si miramos esto
vamos a ver
it can be made important
vale veo que funciona
vamos a ver
igual
ostras
mira
si que funciona
pues si
si que funciona
igual
cuando
mira
es que
igual cuando
lo he hecho antes
algo
el important y tal
a lo mejor estaba
algo de la API
y no teníamos algo aquí
pero si si
aquí si que funciona
pues nos ha dicho esto
que
a ver
make it not important
vamos a ir a la
borrela
si si
de hecho
y si refresco
pues si funciona
perfectamente
igual es que teníamos
algo de testing
antes
y nos ha limpiado
correctamente
pero mira
justamente genial
con el test
nos hemos asegurado
ves esto es
porque es importante
no depender
de tener
la base de datos
de una forma
no controlada
de que si tenga un usuario
de que la nota
esté creada de una forma
al final lo que queremos
es justamente esto
lo que queremos
es no depender
de algo externo
sino que tú digas
oye voy a borrar esto
lo voy a crear desde cero
sé que contenido hay
y tal
así que mira
de esta forma
ahora sabemos
que funciona
correctamente
súper importante
el tema este
vale
no se puede guardar
una variable
como si esto fuese
javascript y tal
yo ojalá algún día llegue
porque es una cosa
que me gusta bastante
de react testing library
al final no tienes que aprender
tanto de cómo funciona
cypress una vez más
sino que realmente
dices bueno
es javascript
pues ya utilizo y tal
pero cypress
hace mucha magia
por detrás
justamente para simplificarte
el código
o sea tiene sentido
porque lo hace
porque tú todo lo que
estás viendo aquí
todo lo que ves
parece síncrono
pero aquí
todo esto ya te digo
que no es síncrono
esto está haciendo
esperando a un elemento
del DOM
haciendo timeouts
todo esto es asíncrono
los están colando
entonces no funciona
como esperas
que lo tengas en cuenta
¿vale?
luego os quería comentar
dos cositas más
una
como podéis ver
estamos ejecutando
los test aquí
pero esto
esto es muy visual
y está muy bien
cuando estamos depurando
los test
si queréis ejecutar
los test
en la línea de comandos
básicamente
vamos a añadir
otro
vamos a poner por aquí
vamos a añadir
otro en el package
json
otro script
¿vale?
vamos a añadir otro script
que le podemos llamar
a ver tenemos
cypress open
podemos llamarle test
en tu end
que además tiene sentido
estos test en tu end
los utilizaremos
más adelante
en una clase
así que lo utilizaremos
cuando veamos
continuous integration
y continuous deployment
para utilizarlos
en la línea de comandos
y que no te levante
el navegador
sino que lo ponga
en modo headless
que se llama
sin cabeza
clasca
que le corta la cabeza
sin cabeza
se utiliza el cypress run
¿vale?
que sea headless
lo que significa
es que no va a tener
la interfaz gráfica
esto tiene un montón
de ventajas
y una de ellas
por supuesto
es la memoria
del proceso
que necesita
aunque sigue necesitando
mucho
no es tanto
y además
es que hay sistemas
por ejemplo
en linux
o en algunos
continuous integration
que no tienen
interfaz gráfica
y por lo tanto
no pueden ejecutar
chrome
con interfaz gráfica
la forma de ejecutar
los headless
lo que hace
es que puedas ejecutar
chrome
que aunque no se vea
y tal
sí que funcione
aunque no tenga
una forma visual
de hacerlo
¿vale?
pero sí que se esté
renderizando
de alguna forma
todo ese contenido
y puedas acceder
a toda la API
de chrome
por eso lo hace
tan interesante
el tema de headless
y aparte de que es
un poco más rápido
de hecho vamos a probarlo
a ver
esto
esto
esto que es
esto es el
estos cypress
lo vamos a cerrar
así que vamos a hacer
mpn run
test end to end
cypress run
vamos a ver si
pasan aquí
creo que he dejado
un only por ahí
¿no?
puede ser
¿no?
¿lo he quitado?
sí lo he dejado
bueno
lo voy a dejar
y ahora lo quito
a ver qué
a ver qué
pero ya
ya se nota
que los test end to end
tardan más
que los de integración
o sea
tienen un poquito más
de
les cuesta un poco más
de arrancar
consumen más recursos
les cuesta más
¿ves?
ha tardado
cuatro
pasados
ningún problema
pero mira
en total
siete segundos
nos ha hecho un vídeo
a ver si
que esto es otra
de las funcionalidades
súper interesantes
que tiene
que tiene
cypress
lo que os he enseñado
hoy
en esta horita
es solo
una punta del iceberg
mirad
ah mira
ah
ahora sí
ves ha grabado un vídeo
y todo
pasando los test
brutal
esto te lo puedes
llevar a cypress
te tiene un dashboard
donde lo puedes
también
lo puedes ver
todas las ejecuciones
que has tenido
dónde ha fallado
o sea
es brutal
ahí tiene una parte
que es gratuita
aunque al final
si lo realmente
lo utilizas
bastante es de pago
pero te hace un vídeo
automático
o sea
es genial
o te puedes hacer fotos
también
lo malo es que
esto ocupa espacio
no mucho
pero bueno
lo que puedes hacer
en continuous integration
es que te lo envíe
si ha fallado
que te lo envíe a slack
o te lo envíe a algún sitio
lo podríamos ver
en algún directo
si os gustaría verlo
lo podemos mirar
porque es una cosa
que no es muy difícil
y que creo que
que da bastante
da bastante juego
vamos a pasarlos todos
a ver cuánto tardan
vale
vamos a pasarlos todos
así como el cypress run
no sé si el cypress run
me parece a mí
que por defecto
creo que
que sí que por defecto
es
es headless
de hecho veis
que pone aquí browser
y pone electron
porque no está utilizando chrome
sino que está utilizando electron
que al final utiliza el motor de chrome
pero bueno
es interesante
esto puede ser problemático a veces
hay que tenerlo en cuenta
pero veis que pone aquí headless
esto es que no tiene la interfaz gráfica
bueno
han pasado todos
pero
tardan 12 segundos
claro
comparado con los otros test
pues hay que tener en cuenta
que hay
hay un coste mayor
y van escalando
van escalando
se pueden ejecutar de forma
en paralelo
por ejemplo
podríamos ejecutar test en paralelo
para que
en lugar de 12
pues a lo mejor tarde 4
ya os digo que cuanto más tienes
más importante es paralelizarlo
paralelizarlo
no es difícil
pero la forma más fácil
es medio de pago
no es de pago
pero cypress no te lo deja hacer muy fácil
solo para que lo tengáis en cuenta
vale
y para antes de que os pongáis a tope aquí con cypress
porque estoy seguro que os ha debido encantar la clase
si no ahora os leeré en el chat
que tengáis en cuenta una cosa
vale
a la hora de hacer debug
o de depurar vuestros test
vamos a ejecutar una vez más cypress
pero con la forma la otra
con
ay
he puesto run
vale
con la otra
porque esto es verdad que es un
no es raro
pero hay mucha gente que a lo mejor no espera que funcione
de la forma que lo hace
vale
a ver
vamos a ejecutar los test
vamos aquí a integration
note aquí
claro
hay gente
o al menos
a lo mejor esto ha cambiado
pero esto antes no funcionaba así
no funciona con un debug y ya está
lo primero que tienes que hacer
para que te funcione en el debug
aunque ya os digo que el debug
tal cual ese creo que no funciona
es que tienes que tener las herramientas
de desarrollo abiertas por supuesto
si no
no funciona
vale
así que lo primero
herramientas de desarrollo
y luego
si ves si yo
ahora
vamos a ver
igual si lo ha hecho
pero al menos antes no
no funcionaba
vamos a verlo
run credentials
no sé qué
no
no
no ha parado
no
no
ah sí
ha parado
vale
ha parado
pero ya en un momento
en el que a lo mejor
bueno en este caso parece que sí
pero
qué pasa
qué pasa con esto
este tipo de debugger
vale
este tipo de debugger no funciona correctamente
sí que para
pero
no funciona correctamente
porque a lo mejor no para en el punto en el que tú te esperas
o a lo mejor no ha hecho nada de nada de lo que estás viendo
¿por qué?
por lo que decía ¿no?
porque los comandos que tú ves aquí
son totalmente asíncronos
y al encolarlos
a lo mejor tú crees que ha hecho ciertos pasos
y no ha hecho nada
o sea
si yo pongo aquí un debugger
aquí en medio ¿no?
que espero que sea justo después del click
pues este debugger no está haciendo realmente
lo que tú crees que está haciendo
porque no es síncrono este código ¿vale?
entonces el debugger
a lo mejor no ha hecho nada
y paraliza el proceso
para hacer esto
y de hecho tenía aquí la URL apuntada para revisarlo
hay que utilizar otro comando
que justamente es de
es de Cypress ¿vale?
no se puede utilizar el debugger normal y corriente
al final este debugger
hace lo que esperas
pero tienes que utilizar este debugger de Cypress
¿vale?
mira ves
yo he puesto este debugger
que lo he puesto
bueno ahora porque
bueno lo había puesto aquí
con este contains
pero este contains todavía aquí no se ha ejecutado
¿vale?
¿por qué?
porque esto es asíncrono
se lo ha saltado
vale pues aquí tienes el debugger
no fíes de este debugger
tenéis que utilizar
el de Cypress ¿vale?
si queréis que justamente
se paralice el debugger
ahí tenéis que poner
ci.debug
esto lo he visto un montón de veces
de que sea un problema
de que la gente se vuelve muy loca
y con razón
porque bueno
tiene estas cosillas
que las tenéis que saber
porque si no
no
bueno
también es cierto una cosa
que muy poco
mira ahora sí ¿veis?
que se ha parado como en medio
se ha parado en este punto
en lugar de pararse
¿ves?
es como ahora tiene más sentido
es el debugger
el mismo
pero el de Cypress
cierto es
que Cypress
es tan potente
a la hora de ver
paso a paso tu test
que no tienes
muchas veces
por qué tirar del debugger
pero las pocas veces
que lo tienes que hacer
que sepas
que tienes que utilizar este
muy bien
no