Análisis profundo de Mirage JS: uso de Mirage JS y Cypress para pruebas de interfaz de usuario (Parte 4)

 

 

 

  • SmashingConf Friburgo 2024
  • Accesibilidad para diseñadores, con Stéphanie Walter

  • Índice
    1. Lea partes anteriores de la serie:
  • Introducción a las pruebas de UI
  • Nuestra primera prueba de interfaz de usuario
  • Evitar varios servidores Mirage
  • Entorno de prueba
  • Pruebas AAA
  • Probemos errores
  • Probar la página de detalles del producto
  • Terminando
  • En esta parte final de la serie Mirage JS Deep Dive, pondremos todo lo que hemos aprendido en la serie anterior en cómo realizar pruebas de UI con Mirage JS.

     

    Una de mis citas favoritas sobre pruebas de software proviene de la documentación de Flutter. Dice:

    “¿Cómo puede asegurarse de que su aplicación siga funcionando a medida que agrega más funciones o cambia la funcionalidad existente? Escribiendo exámenes”.

    En ese sentido, esta última parte de la serie Mirage JS Deep Dive se centrará en el uso de Mirage para probar su aplicación front-end de JavaScript.

    Nota : este artículo asume un entorno Cypress . Cypress es un marco de prueba para pruebas de interfaz de usuario. Sin embargo, puede transferir el conocimiento aquí a cualquier entorno o marco de prueba de UI que utilice.

    Lea partes anteriores de la serie:

    • Parte 1 : Comprensión de los modelos y asociaciones de Mirage JS
    • Parte 2 : Comprensión de las fábricas, accesorios y serializadores
    • Parte 3 : Comprender el momento, la respuesta y la transferencia

    Introducción a las pruebas de UI

    La prueba de interfaz de usuario o interfaz de usuario es una forma de prueba de aceptación realizada para verificar los flujos de usuarios de su aplicación front-end. El énfasis de este tipo de pruebas de software está en el usuario final, es decir, la persona real que interactuará con su aplicación web en una variedad de dispositivos que van desde computadoras de escritorio, portátiles hasta dispositivos móviles. Estos usuarios interactuarían con su aplicación utilizando dispositivos de entrada como un teclado, un mouse o pantallas táctiles. Por lo tanto, las pruebas de UI están escritas para imitar la interacción del usuario con su aplicación lo más fielmente posible.

     

    Tomemos como ejemplo un sitio web de comercio electrónico. Un escenario típico de prueba de UI sería:

    • El usuario puede ver la lista de productos cuando visita la página de inicio.

    Otros escenarios de prueba de UI podrían ser:

    • El usuario puede ver el nombre de un producto en la página de detalles del producto.
    • El usuario puede hacer clic en el botón “añadir al carrito”.
    • El usuario puede realizar el pago.

    Captas la idea ¿cierto?

    Al realizar pruebas de UI, dependerá principalmente de los estados de back-end, es decir, ¿devolvió los productos o fue un error? El papel que desempeña Mirage en esto es hacer que esos estados del servidor estén disponibles para que usted pueda modificarlos según sea necesario. Entonces, en lugar de realizar una solicitud real a su servidor de producción en sus pruebas de UI, realiza la solicitud al servidor simulado de Mirage.

    Durante el resto de este artículo, realizaremos pruebas de interfaz de usuario en una interfaz de usuario de aplicación web de comercio electrónico ficticia. Entonces empecemos.

    Nuestra primera prueba de interfaz de usuario

    Como se indicó anteriormente, este artículo asume un entorno Cypress. Cypress hace que probar la interfaz de usuario en la web sea rápido y sencillo. Puede simular clics y navegación y puede visitar rutas mediante programación en su aplicación. Consulte los documentos para obtener más información sobre Cypress.

    Entonces, suponiendo que Cypress y Mirage estén disponibles para nosotros, comencemos definiendo una función de proxy para su solicitud de API. Podemos hacerlo en el support/index.jsarchivo de nuestra configuración de Cypress. Simplemente pegue el siguiente código en:

    // cypress/support/index.jsCypress.on("window:before:load", (win) = { win.handleFromCypress = function (request) { return fetch(request.url, { method: request.method, headers: request.requestHeaders, body: request.requestBody, }).then((res) = { let content = res.headers.map["content-type"] === "application/json" ? res.json() : res.text() return new Promise((resolve) = { content.then((body) = resolve([res.status, res.headers, body])) }) }) }})

    Luego, en el archivo de arranque de su aplicación ( main.jspara Vue, index.jspara React), usaremos Mirage para enviar las solicitudes API de su aplicación a la handleFromCypressfunción solo cuando Cypress se esté ejecutando. Aquí está el código para eso:

    import { Server, Response } from "miragejs"if (window.Cypress) { new Server({ environment: "test", routes() { let methods = ["get", "put", "patch", "post", "delete"] methods.forEach((method) = { this[method]("/*", async (schema, request) = { let [status, headers, body] = await window.handleFromCypress(request) return new Response(status, headers, body) }) }) }, })}

    Con esa configuración, cada vez que se ejecuta Cypress, su aplicación sabe que debe usar Mirage como servidor simulado para todas las solicitudes de API.

     

    Sigamos escribiendo algunas pruebas de UI. Comenzaremos probando nuestra página de inicio para ver si se muestran 5 productos . Para hacer esto en Cypress, necesitamos crear un homepage.test.jsarchivo en la testscarpeta en la raíz del directorio de su proyecto. A continuación, le diremos a Cypress que haga lo siguiente:

    • Visite la página de inicio, es decir, /ruta
    • Luego afirma si tiene li elementos con la clase de producty también verifica si son 5 en números.

    Aquí está el código:

    // homepage.test.jsit('shows the products', () = { cy.visit('/'); cy.get('li.product').should('have.length', 5);});

    Es posible que haya adivinado que esta prueba fallaría porque no tenemos un servidor de producción que devuelva 5 productos a nuestra aplicación de front-end. ¿Asi que que hacemos? ¡Nos burlamos del servidor en Mirage! Si incorporamos Mirage, puede interceptar todas las llamadas de red en nuestras pruebas. Hagamos esto a continuación e iniciemos el servidor Mirage antes de cada prueba en la beforeEachfunción y también apagémoslo en la afterEachfunción. Cypress proporciona las funciones beforeEachy y se pusieron a disposición para que pueda ejecutar código antes y después de cada ejecución de prueba en su conjunto de pruebas, de ahí el nombre. afterEachEntonces veamos el código para esto:

    // homepage.test.jsimport { Server } from "miragejs"let serverbeforeEach(() = { server = new Server()})afterEach(() = { server.shutdown()})it("shows the products", function () { cy.visit("/") cy.get("li.product").should("have.length", 5)})

    Bien, estamos llegando a alguna parte; Hemos importado el servidor de Mirage y lo estamos iniciando y apagándolo en beforeEachfunciones afterEachrespectivamente. Vayamos a burlarnos de nuestro recurso de producto.

    // homepage.test.jsimport { Server, Model } from 'miragejs';let server;beforeEach(() = { server = new Server({ models: { product: Model, }, routes() { this.namespace = 'api'; this.get('products', ({ products }, request) = { return products.all(); }); }, });});afterEach(() = { server.shutdown();});it('shows the products', function() { cy.visit('/'); cy.get('li.product').should('have.length', 5);});

    Nota : siempre puedes echar un vistazo a las partes anteriores de esta serie si no comprendes los fragmentos de Mirage del fragmento de código anterior.

    • Parte 1 : Comprensión de los modelos y asociaciones de Mirage JS
    • Parte 2 : Comprensión de las fábricas, accesorios y serializadores
    • Parte 3 : Comprender el momento, la respuesta y la transferencia

    Bien, hemos comenzado a desarrollar nuestra instancia de servidor creando el modelo de producto y también creando el controlador de ruta para la /api/productsruta. Sin embargo, si ejecutamos nuestras pruebas, fallará porque todavía no tenemos ningún producto en la base de datos de Mirage.

     

    Completemos la base de datos de Mirage con algunos productos. Para hacer esto, podríamos haber usado el create()método en nuestra instancia de servidor, pero crear 5 productos a mano parece bastante tedioso. Debería haber una mejor manera.

    Ah, sí, lo hay. Utilicemos fábricas (como se explica en la segunda parte de esta serie). Necesitaremos crear nuestra fábrica de productos así:

    // homepage.test.jsimport { Server, Model, Factory } from 'miragejs';let server;beforeEach(() = { server = new Server({ models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}` } }) }, routes() { this.namespace = 'api'; this.get('products', ({ products }, request) = { return products.all(); }); }, });});afterEach(() = { server.shutdown();});it('shows the products', function() { cy.visit('/'); cy.get('li.product').should('have.length', 5);});

    Luego, finalmente, usaremos createList()para crear rápidamente los 5 productos que nuestra prueba debe pasar.

    Hagámoslo:

    // homepage.test.jsimport { Server, Model, Factory } from 'miragejs';let server;beforeEach(() = { server = new Server({ models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}` } }) }, routes() { this.namespace = 'api'; this.get('products', ({ products }, request) = { return products.all(); }); }, });});afterEach(() = { server.shutdown();});it('shows the products', function() { server.createList("product", 5) cy.visit('/'); cy.get('li.product').should('have.length', 5);});

    Entonces, cuando ejecutamos nuestra prueba, ¡pasa! Comprar Pintura

    Nota : Después de cada prueba, el servidor de Mirage se apaga y se reinicia, por lo que nada de este estado se filtrará entre las pruebas.

    Evitar varios servidores Mirage

    Si ha seguido esta serie, se habrá dado cuenta de que estábamos usando Mirage en desarrollo para interceptar nuestras solicitudes de red; Teníamos un server.jsarchivo en la raíz de nuestra aplicación donde configuramos Mirage. En el espíritu de DRY (No te repitas), creo que sería bueno utilizar esa instancia del servidor en lugar de tener dos instancias separadas de Mirage tanto para el desarrollo como para las pruebas. Para hacer esto (en caso de que aún no tenga un server.jsarchivo), simplemente cree uno en el directorio src de su proyecto .

    Nota : Su estructura será diferente si está utilizando un marco de JavaScript, pero la idea general es configurar el archivo server.js en la raíz src de su proyecto.

    Entonces, con esta nueva estructura, exportaremos una función server.jsque es responsable de crear nuestra instancia del servidor Mirage. Vamos a hacer eso:

    // src/server.jsexport function makeServer() { /* Mirage code goes here */}

    Completemos la implementación de la makeServerfunción eliminando el servidor Mirage JS que creamos homepage.test.jsy agregándolo al makeServercuerpo de la función:

     

    import { Server, Model, Factory } from 'miragejs';export function makeServer() { let server = new Server({ models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}`; }, }), }, routes() { this.namespace = 'api'; this.get('/products', ({ products }) = { return products.all(); }); }, seeds(server) { server.createList('product', 5); }, }); return server;}

    Ahora todo lo que tienes que hacer es importar makeServeren tu prueba. Usar una única instancia de Mirage Server es más limpio; De esta manera, no es necesario mantener dos instancias de servidor para los entornos de desarrollo y prueba.

    Después de importar la makeServerfunción, nuestra prueba ahora debería verse así:

    import { makeServer } from '/path/to/server';let server;beforeEach(() = { server = makeServer();});afterEach(() = { server.shutdown();});it('shows the products', function() { server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);});

    Ahora tenemos un servidor Mirage central que nos sirve tanto en el desarrollo como en las pruebas. También puede utilizar la makeServerfunción para iniciar Mirage en desarrollo (consulte la primera parte de esta serie).

    Su código Mirage no debería llegar a producción. Por lo tanto, dependiendo de la configuración de su compilación, solo necesitará iniciar Mirage durante el modo de desarrollo.

    Nota : Lea mi artículo sobre cómo configurar API Mocking con Mirage y Vue.js para ver cómo lo hice en Vue para que pueda replicarlo en cualquier marco de interfaz de usuario que utilice.

    Entorno de prueba

    Mirage tiene dos entornos: desarrollo (predeterminado) y prueba . En el modo de desarrollo, el servidor Mirage tendrá un tiempo de respuesta predeterminado de 400 ms (que puede personalizar. Consulte el tercer artículo de esta serie para eso), registra todas las respuestas del servidor en la consola y carga las semillas de desarrollo.

    Sin embargo, en el entorno de prueba, tenemos:

    • 0 retrasos para mantener nuestras pruebas rápidas
    • Mirage suprime todos los registros para no contaminar sus registros de CI
    • Mirage también ignorará la seeds()función para que sus datos iniciales puedan usarse únicamente para el desarrollo pero no se filtren en sus pruebas. Esto ayuda a mantener sus pruebas deterministas.

    Actualicemos nuestro makeServerpara que podamos aprovechar el entorno de prueba. Para hacer eso, haremos que acepte un objeto con la opción de entorno (lo estableceremos de manera predeterminada en desarrollo y lo anularemos en nuestra prueba). Nuestro server.jsahora debería verse así:

    // src/server.jsimport { Server, Model, Factory } from 'miragejs';export function makeServer({ environment = 'development' } = {}) { let server = new Server({ environment, models: { product: Model, }, factories: { product: Factory.extend({ name(i) { return `Product ${i}`; }, }), }, routes() { this.namespace = 'api'; this.get('/products', ({ products }) = { return products.all(); }); }, seeds(server) { server.createList('product', 5); }, }); return server;}

    También tenga en cuenta que estamos pasando la opción de entorno a la instancia del servidor Mirage utilizando la abreviatura de propiedad ES6 . Ahora que esto está implementado, actualicemos nuestra prueba para anular el valor del entorno a probar. Nuestra prueba ahora se ve así:

     

    import { makeServer } from '/path/to/server';let server;beforeEach(() = { server = makeServer({ environment: 'test' });});afterEach(() = { server.shutdown();});it('shows the products', function() { server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);});

    Pruebas AAA

    Mirage fomenta un estándar de prueba llamado enfoque de prueba triple A o AAA. Esto significa Organizar , Actuar y Afirmar . Ya puedes ver esta estructura en nuestra prueba anterior:

    it("shows all the products", function () { // ARRANGE server.createList("product", 5) // ACT cy.visit("/") // ASSERT cy.get("li.product").should("have.length", 5)})

    Es posible que necesites romper este patrón, pero 9 de cada 10 veces debería funcionar bien para tus pruebas.

    Probemos errores

    Hasta ahora, hemos probado nuestra página de inicio para ver si tiene 5 productos; sin embargo, ¿qué pasa si el servidor no funciona o si algo salió mal al buscar los productos? No necesitamos esperar a que el servidor esté inactivo para trabajar en cómo se vería nuestra interfaz de usuario en tal caso. Simplemente podemos simular ese escenario con Mirage.

    Devolvemos un 500 (error del servidor) cuando el usuario está en la página de inicio. Como hemos visto en un artículo anterior, para personalizar las respuestas de Mirage hacemos uso de la clase Response. Importémoslo y escribamos nuestra prueba.

    homepage.test.jsimport { Response } from "miragejs"it('shows an error when fetching products fails', function() { server.get('/products', () = { return new Response( 500, {}, { error: "Can’t fetch products at this time" } ); }); cy.visit('/'); cy.get('div.error').should('contain', "Can’t fetch products at this time");});

    ¡Qué mundo de flexibilidad! Simplemente anulamos la respuesta que devolvería Mirage para probar cómo se mostraría nuestra interfaz de usuario si no se pudieran recuperar los productos. Nuestro homepage.test.jsarchivo general ahora se vería así:

    // homepage.test.jsimport { Response } from 'miragejs';import { makeServer } from 'path/to/server';let server;beforeEach(() = { server = makeServer({ environment: 'test' });});afterEach(() = { server.shutdown();});it('shows the products', function() { server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);});it('shows an error when fetching products fails', function() { server.get('/products', () = { return new Response( 500, {}, { error: "Can’t fetch products at this time" } ); }); cy.visit('/'); cy.get('div.error').should('contain', "Can’t fetch products at this time");});

    Tenga en cuenta que la modificación que le hicimos al /api/productscontrolador solo se encuentra en nuestra prueba. Eso significa que funciona como definimos previamente cuando estás en modo de desarrollo.

     

    Entonces, cuando ejecutemos nuestras pruebas, ambas deberían pasar.

    Nota : Creo que vale la pena señalar que los elementos que estamos consultando en Cypress deberían existir en su interfaz de usuario. Cypress no crea elementos HTML por usted.

    Probar la página de detalles del producto

    Finalmente, probemos la interfaz de usuario de la página de detalles del producto. Entonces esto es lo que estamos probando:

    • El usuario puede ver el nombre del producto en la página de detalles del producto.

    Hagámoslo. Primero, creamos una nueva prueba para probar este flujo de usuarios.

    Aquí está la prueba:

    it("shows the product’s name on the detail route", function() { let product = this.server.create('product', { name: 'Korg Piano', }); cy.visit(`/${product.id}`); cy.get('h1').should('contain', 'Korg Piano');});

    Finalmente deberías homepage.test.jslucir así.

    // homepage.test.jsimport { Response } from 'miragejs';import { makeServer } from 'path/to/server;let server;beforeEach(() = { server = makeServer({ environment: 'test' });});afterEach(() = { server.shutdown();});it('shows the products', function() { console.log(server); server.createList('product', 5); cy.visit('/'); cy.get('li.product').should('have.length', 5);});it('shows an error when fetching products fails', function() { server.get('/products', () = { return new Response( 500, {}, { error: "Can’t fetch products at this time" } ); }); cy.visit('/'); cy.get('div.error').should('contain', "Can’t fetch products at this time");});it("shows the product’s name on the detail route", function() { let product = server.create('product', { name: 'Korg Piano', }); cy.visit(`/${product.id}`); cy.get('h1').should('contain', 'Korg Piano');});

    Cuando ejecute sus pruebas, las tres deberían pasar.

    Terminando

    Ha sido divertido mostrarles el interior de Mirage JS en esta serie. Espero que haya estado mejor equipado para comenzar a tener una mejor experiencia de desarrollo front-end utilizando Mirage para simular su servidor back-end. También espero que utilice el conocimiento de este artículo para escribir más pruebas de aceptación/UI/de un extremo a otro para sus aplicaciones front-end.

    • Parte 1 : Comprensión de los modelos y asociaciones de Mirage JS
    • Parte 2 : Comprensión de las fábricas, accesorios y serializadores
    • Parte 3 : Comprender el momento, la respuesta y la transferencia
    • Parte 4: Uso de Mirage JS y Cypress para pruebas de UI

    (ra, il)Explora más en

    • interfaz de usuario
    • API
    • Pruebas
    • javascript





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Análisis profundo de Mirage JS: uso de Mirage JS y Cypress para pruebas de interfaz de usuario (Parte 4)

    Análisis profundo de Mirage JS: uso de Mirage JS y Cypress para pruebas de interfaz de usuario (Parte 4)

    SmashingConf Friburgo 2024 Accesibilidad para diseñadores, con Stéphanie Walter Índice Lea partes anter

    programar

    es

    https://aprendeprogramando.es/static/images/programar-analisis-profundo-de-mirage-js-uso-de-mirage-js-y-cypress-para-pruebas-de-interfaz-de-usuario-parte-4-1039-0.jpg

    2024-05-21

     

    Análisis profundo de Mirage JS: uso de Mirage JS y Cypress para pruebas de interfaz de usuario (Parte 4)
    Análisis profundo de Mirage JS: uso de Mirage JS y Cypress para pruebas de interfaz de usuario (Parte 4)

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20