Cómo Y Guía Para Las Pruebas Unitarias Componentes Vue

Este artículo sirve como guía para las pruebas unitarias de los componentes de Vue.

Primero veremos por qué las pruebas unitarias son importantes para crear software mantenible y qué debe probar. Luego, detallaremos cómo:

  1. Cree y ejecute una prueba unitaria para un componente Vue
  2. Probar diferentes aspectos de un componente Vue
  3. Use simulacros para probar funciones asíncronas
  4. Verifique la cobertura de código de sus pruebas unitarias
  5. Estructure sus archivos de prueba de unidad

Dependencias :

El código fuente (junto con instrucciones de instalación detalladas) para el proyecto de la aplicación Vue Weather que se usa en este artículo se puede encontrar en GitLab: Vue Weather App .

Objetivos

Al final de este artículo, usted debería ser capaz de:

  1. Explicar por qué las pruebas unitarias son importantes.
  2. Describa lo que debe (y no debe) probar la unidad
  3. Desarrollar un conjunto de pruebas unitarias para un componente de Vue
  4. Ejecute las pruebas unitarias para un proyecto Vue
  5. Utilizar las funciones beforeEach()y afterEach()dentro de un conjunto de pruebas unitarias
  6. Escribir pruebas unitarias para probar los detalles de implementación de un componente Vue
  7. Escriba pruebas unitarias para probar los aspectos de comportamiento de un componente Vue (eventos de clic, etc.)
  8. Explicar cómo la simulación puede ayudar a simplificar las pruebas unitarias
  9. Escribir pruebas unitarias para burlarse de una biblioteca y probar funciones asincrónicas
  10. Verifique la cobertura de código de sus pruebas unitarias
  11. Desarrolle un archivo de prueba de unidad bien estructurado para probar un componente de Vue

¿Por qué prueba unitaria?

En general, las pruebas ayudan a garantizar que su aplicación funcione según lo esperado para sus usuarios finales.

Los proyectos de software con una alta cobertura de pruebas nunca son perfectos, pero es un buen indicador inicial de la calidad del software. Además, el código comprobable generalmente es un signo de una buena arquitectura de software, razón por la cual los desarrolladores avanzados tienen en cuenta las pruebas durante todo el ciclo de vida del desarrollo.

Las pruebas se pueden considerar en tres niveles:

  1. Unidad
  2. Integración
  3. De extremo a extremo

Las pruebas unitarias prueban la funcionalidad de una unidad de código individual aislada de sus dependencias. Son la primera línea de defensa contra errores e inconsistencias en su base de código. Las pruebas unitarias son una parte fundamental del proceso de desarrollo dirigido por pruebas (TDD).

Las pruebas unitarias mejoran la capacidad de mantenimiento de su código.

La capacidad de mantenimiento se refiere a realizar correcciones de errores o mejoras a su código o a otro desarrollador que necesite actualizar su código en el futuro.

Las pruebas unitarias deben combinarse con un proceso de integración continua (CI) para garantizar que sus pruebas unitarias se ejecuten constantemente, idealmente en cada confirmación en su repositorio. Un conjunto sólido de pruebas unitarias puede ser fundamental para detectar defectos de manera rápida y temprana en el proceso de desarrollo antes de que los usuarios finales los encuentren en producción.

Qué probar

¿Qué deberías probar? O, más importante aún: ¿Qué no debes probar?

Hay tres tipos de pruebas a considerar con las pruebas unitarias:

  1. Detalles de implementación : la lógica empresarial subyacente que utiliza un componente para producir un resultado basado en una entrada dada
  2. Interfaz pública/contrato de diseño : insumos específicos (o accesorios, en este caso) producen resultados específicos
  3. Efectos secundarios : "si esto, entonces aquello"; por ejemplo, cuando se hace clic en un botón, algo sucede

Dado que no puede probar todas las cosas, ¿en qué debe concentrarse?

Concéntrese en probar las entradas y salidas con las que interactuará el usuario final. ¡La experiencia que tienen los usuarios de tu producto es primordial!

  1. Entradas : datos, accesorios, interacción del usuario, métodos de ciclo de vida, almacén de datos ( Pinia / Vuex ), parámetros de ruta, cadenas de consulta
  2. Salidas : salida renderizada, eventos, resultados de datos, actualizaciones del almacén de datos (Pinia/Vuex), envíos

Al centrarse en probar las entradas/salidas de un módulo de software (por ejemplo, un componente de Vue), está probando los aspectos clave que experimentará el usuario final.

Puede haber otra lógica interna en un módulo de software que sea complejo y deba someterse a pruebas unitarias, pero es más probable que estos tipos de pruebas necesiten una actualización durante una refactorización de código.

Descripción general de la aplicación

Antes de analizar cómo realizar pruebas unitarias de los componentes de Vue, quiero brindar una breve descripción general de la aplicación Vue Weather que probaremos.

Después de clonar el repositorio, instale las dependencias y agregue la clave API.

Revise el LÉAME del proyecto para obtener más información sobre cómo crear y agregar la clave API de Open Weather.

Una vez hecho esto, la aplicación Vue Weather se puede ejecutar en su computadora local iniciando el servidor de desarrollo:

$ npm run dev

Una vez que se crea la aplicación, verá un mensaje de éxito similar a:

vite v2.9.14 dev server running at:

 > Local: http://localhost:3000/
 > Network: use `--host` to expose

 ready in 543ms.

En este punto, el servidor de desarrollo estará en funcionamiento. Puede ver la aplicación Vue navegando a http://localhost:3000 en su navegador web favorito. Cuando carga la aplicación por primera vez, no se muestran datos; solo verá un campo de entrada para ingresar la ciudad para la que le gustaría obtener el clima:

Tutorial de la aplicación Vue Weather - Paso 1

Sin ningún dato ingresado, los botones 'Buscar' y 'Borrar' están deshabilitados.

Una vez que comience a ingresar datos para una ciudad (tan pronto como se agregue el primer carácter), se habilitarán los botones 'Buscar' y 'Borrar':

Tutorial de la aplicación Vue Weather - Paso 2

Si hace clic en 'Buscar' después de ingresar una ciudad válida, se mostrarán los datos meteorológicos para esa ciudad:

Tutorial de la aplicación Vue Weather - Paso 3

En este punto, al hacer clic en el botón 'Borrar datos meteorológicos' se borrarán los datos meteorológicos:

Tutorial de la aplicación Vue Weather - Paso 4

Sin embargo, la ciudad que se ingresó permanecerá en el campo de entrada.

Si hace clic en 'Borrar' ahora, el campo de entrada se borrará y los botones 'Buscar' y 'Borrar' se desactivarán una vez más:

Tutorial de la aplicación Vue Weather - Paso 5

¿Qué sucede si ingresa una ciudad no válida? ¿Qué sucede si hace clic en 'Borrar' antes de 'Borrar datos meteorológicos'? ¿Qué otros estados de la aplicación puedes encontrar?

Pruebas unitarias en Vue

Dado que los componentes son los componentes básicos de Vue (y, en realidad, de cualquier marco SPA ), son la parte más crucial de su aplicación en su conjunto. Por lo tanto, dedique la mayor parte de su tiempo de prueba asignado a escribir pruebas unitarias que prueben los componentes de su aplicación.

Según mi experiencia con las pruebas unitarias de los componentes de Vue, descubrí que las herramientas y el marco de prueba, Vite y Vitest, satisfacen los aspectos clave de un buen entorno de prueba:

  • las pruebas son fáciles y divertidas de escribir
  • las pruebas se pueden escribir rápidamente
  • las pruebas se pueden ejecutar con un solo comando
  • las pruebas se ejecutan rápidamente

Con suerte, encontrará que la prueba unitaria de sus componentes Vue es una experiencia agradable, ya que creo que es clave para fomentar más pruebas.

Herramientas de prueba unitaria

Hay dos herramientas que vamos a utilizar para las pruebas unitarias de los componentes de Vue:

  1. Vitest - marco de prueba unitaria
  2. Vue Test Utils : biblioteca de utilidades de pruebas unitarias para Vue

Vitest es un marco de prueba de unidad que pretende ser independiente del marco, por lo que se puede usar para probar Vue, React, Svelte, Lit y ​​otros proyectos. Vitest está configurado para ejecutarse con Vite, lo que da como resultado una ejecución de prueba rápida .

Si está familiarizado con Jest, cambiar a Vitest es muy sencillo, ya que la API de Vitest es compatible con Jest.

Al escribir pruebas unitarias para un componente Vue, Vitest y Vue Test Utils brindan la siguiente funcionalidad:

engranaje

  • Herramienta de línea de comandos para ejecutar las pruebas y verificar la cobertura de la prueba
  • Interfaz de usuario para ver visualmente los resultados de las pruebas y los resultados de cobertura
  • Funciones para escribir pruebas unitarias ( it, describe)
  • Funciones para comprobar los valores esperados ( expect, toMatch, toContain, etc.)
  • burlándose ( mockResolvedValue, mockRejectedValue)
  • Configuración ( beforeEach, beforeAll) / Desmontaje ( afterEach, afterAll)

Ver utilidades de prueba

  • Componentes de montaje ( mount, shallowMount)
  • Configuración de datos de accesorios ( setProps)
  • Encontrar componentes HTML para probar ( findAll('h2'))
  • Utilidad para vaciar todas las Promesas ( flushPromises())
  • Utilidad para desencadenar eventos de clic ( trigger)
  • Utilidad para comprobar eventos emitidos ( emitted)

Vitest proporciona la funcionalidad genérica para escribir pruebas unitarias, mientras que Vue Test Utils proporciona las utilidades de prueba específicas de Vue.

Descripción general de las pruebas unitarias

Para empezar, analicemos la convención de nomenclatura para las pruebas unitarias en Vue. El archivo de prueba de la unidad debe tener el siguiente formato:

  • <ComponentName>.spec.js

Según la Guía de estilo de Vue , los nombres de los componentes deben ser varias palabras ( WeatherHeaderen lugar de solo Header) para evitar conflictos con los elementos HTML.

Por lo general, debe tener un archivo de prueba de unidad para cada componente en su proyecto Vue. Dentro de cada archivo de prueba de unidad, puede haber un conjunto de pruebas de una sola unidad o conjuntos de pruebas de varias unidades.

Los archivos de prueba de unidad deben colocarse en una subcarpeta dentro de la carpeta Componentes ( src/components/__tests__ ):

$ tree -d -L 2
.
├── node_modules
├── public
├── src
    ├── assets
    └── components
        └── __tests__

Ejecución de las pruebas

Vitest se puede usar para ejecutar las pruebas unitarias de la siguiente manera:

$ npm run test:unit

✓ src/components/__tests__/WeatherFooter.spec.js (1)
✓ src/components/__tests__/WeatherHeader.spec.js (1)
✓ src/components/__tests__/WeatherResult.spec.js (3)
✓ src/components/__tests__/WeatherBanner.spec.js (5)
✓ src/components/__tests__/WeatherSearch.spec.js (5)
✓ src/components/__tests__/App.spec.js (7)

Test Files  6 passed (6)
    Tests  22 passed (22)
     Time  2.38s (in thread 640ms, 371.13%)

Todos los comandos disponibles para ejecutar a través npmde su proyecto Vue se definen en el scriptscampo en package.json .

La configuración predeterminada para Vitest es ejecutar las pruebas en modo de observación , lo que significa que el conjunto de pruebas se volverá a ejecutar cada vez que se guarde en un archivo aplicable. Para cambiar esta configuración para que Vitest solo se ejecute una vez (sin "modo de observación"), actualice la test:unitconfiguración en package.json para incluir el runargumento:

"test:unit": "vitest run --environment jsdom",

Ejemplos

Con la aplicación Vue Weather , veamos algunos ejemplos para probar los componentes de Vue.

Ejemplo 1 - Introducción a la prueba unitaria

¡Pasemos directamente a un ejemplo de un archivo de prueba de unidad en Vue! El primer archivo de prueba de unidad se encuentra en src/components/__tests__/WeatherHeader.spec.js y prueba el WeatherHeadercomponente:

import { describe, it, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import WeatherHeader from '../WeatherHeader.vue'


describe('WeatherHeader.vue Test', () => {
  it('renders message when component is created', () => {
    // render the component
    const wrapper = shallowMount(WeatherHeader, {
      propsData: {
        title: 'Vue Project'
      }
    })

    // check that the title is rendered
    expect(wrapper.text()).toMatch('Vue Project')
  })
})

Montaje

La primera línea de este archivo importa las funciones de prueba de Vitest que se utilizan en este archivo.

Si desea que la API de Vitest esté disponible globalmente (como funciona Jest), agregue test: {globals: true}la defineConfig()función en vite.config.js . Para obtener más detalles, consulte la documentación de Vitest .

La segunda línea de este archivo importa una función llamada shallowMountdesde la biblioteca Vue Test Utils. La idea de 'montaje' significa la carga de un componente individual para poder probarlo. Hay dos métodos para esto en Vue Test Utils:

  • shallowMount()- crea un wrapperpara el componente Vue, pero con componentes secundarios stubed
  • mount()- crea un wrapperpara el componente Vue, incluido el montaje de cualquier componente secundario

Dado que nuestro enfoque es probar un componente individual (el WeatherHeadercomponente), usaremos shallowMount().

shallowMount()es mejor para probar un componente individual de forma aislada, ya que los componentes secundarios se excluyen. Esta es la situación ideal para las pruebas unitarias .

Además, usar shallowMount()para probar un componente con muchos componentes secundarios puede mejorar el tiempo de ejecución de la prueba unitaria ya que no hay costo (en términos de tiempo) para renderizar los componentes secundarios.

mount()es útil cuando desea incluir la prueba del comportamiento de los componentes secundarios.

La tercera línea importa el componente de Vue que se va a probar, WeatherHeader.vue .

Describir bloques

Después de las importdeclaraciones, hay un describebloque que define un conjunto de pruebas unitarias.

Dentro de un archivo de prueba unitaria, puede haber múltiples describebloques que definen diferentes conjuntos de pruebas unitarias. De manera similar, cada describebloque puede contener múltiples pruebas unitarias, donde cada prueba unitaria está definida por un itbloque.

Pienso en esta distinción como:

  • describebloque - conjunto de pruebas unitarias
  • itbloque - función de prueba de unidad individual

Lo bueno de las pruebas unitarias con Vitest es que hay varios estímulos incorporados para agregar comentarios. Por ejemplo, el primer argumento para describedebe explicar claramente qué componente de Vue se está probando:

describe('WeatherHeader.vue Test', () => { ... })

Para cada itbloque, el primer argumento es una descripción de la función de prueba, que debe ser una breve descripción de lo que está haciendo esta prueba específica. En el ejemplo anterior, el itbloque prueba que el componente 'presenta un mensaje cuando se crea el componente'.

espera

En cuanto a la prueba unitaria real, el primer paso es montar el componente Vue para que pueda probarse:

// render the component
const wrapper = shallowMount(WeatherHeader, {
  propsData: {
    title: 'Vue Project'
  }
})

La shallowMountfunción devuelve un wrapperobjeto que contiene el componente montado y los métodos para probar ese componente. El wrapperobjeto nos permite probar todos los aspectos del HTML generado por el componente Vue y todas las propiedades (como los datos) del componente Vue.

Además, los accesorios, pasados ​​al WeatherHeadercomponente, se pasan como segundo argumento a shallowMount().

La verificación real realizada en la prueba unitaria es:

// check that the title is rendered
expect(wrapper.text()).toMatch('Vue Project')

Esta línea se usa wrapperpara verificar si el título generado por el componente es 'Vue Project'. Dado que esta verificación hace una comparación de cadenas, se recomienda usar toMatch().

Ayudantes de prueba

Si bien las comprobaciones en el archivo de prueba de la unidad para el WeatherHeadercomponente solo verifican los valores de cadena, hay [muchas opciones disponibles de Vitest para realizar comprobaciones:

  • Booleanos:
    • toBeTruthy()- comprueba que una variable/declaración es verdadera
    • toBeFalsy()- comprueba que una variable/declaración es falsa
  • Definido:
    • toBeNull()- comprueba si una variable coincide solo con nulo
    • toBeUndefined()- comprueba si una variable no está definida
    • toBeDefined()- comprueba si una variable está definida
  • Números:
    • toBeGreaterThan()- comprueba si un número es mayor que el valor especificado
    • toBeGreaterThanOrEqual()- comprueba si un número es mayor o igual que el valor especificado
    • toBeLessThan()- comprueba si un número es menor que el valor especificado
    • toBeLessThanOrEqual()- comprueba si un número es menor o igual que el valor especificado
    • toBe()y toEqual()- comprueba si un número es el mismo que el valor especificado (estas funciones son equivalentes para los números)
    • toBeCloseTo()- comprueba si un número es igual al valor especificado dentro de una pequeña tolerancia (útil para números de punto flotante)
  • Instrumentos de cuerda:
    • toMatch()- comprueba si una cadena es igual al valor especificado (¡Regex se puede usar como el valor especificado!)
  • Matrices:
    • toContain()- comprueba si una matriz contiene el valor especificado

Además, el notcalificador se puede utilizar con la mayoría de estas comprobaciones:

expect(wrapper.text()).not.toMatch('Node Project')

Para obtener una lista completa de las comprobaciones disponibles, consulte la referencia de la API de Vitest .

Ejemplo 2: prueba de las condiciones iniciales

Este ejemplo muestra cómo probar las condiciones iniciales (o estado) del WeatherResultcomponente.

Aquí hay un resumen del archivo de prueba de la unidad (definido en src/components/__tests__/WeatherResult.spec.js ):

import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { shallowMount, flushPromises } from '@vue/test-utils'
import WeatherResult from '@/components/WeatherResult.vue'


describe('WeatherResult.vue Implementation Test', () => {
  let wrapper = null

  // SETUP - run before to each unit test
  beforeEach(() => {
    // render the component
    wrapper = shallowMount(WeatherResult, {
      propsData: {
        city: '',
        weatherSummary: '',
        weatherDescription: '',
        currentTemperature: 0.0,
        lowTemperature: 0.0,
        highTemperature: 0.0
      }
    })
  })

  // TEARDOWN - run after to each unit test
  afterEach(() => {
    wrapper.unmount()
  })

  it('initializes with correct elements', () => { ... })

  it('processes valid props data', async () => { ... })

  it('emits a custom event when the Clear Weather Data button is clicked', () => { ... })
})

El archivo de prueba unitaria utiliza la shallowMount()función para renderizar el WeatherResultcomponente, ya que este componente se prueba como un componente individual de forma aislada.

Bloques beforeEach y afterEach

Dentro del conjunto de pruebas unitarias (definido dentro del describebloque), hay dos nuevas funciones definidas:

  • beforeEach()- llamado antes de la ejecución de cada prueba unitaria dentro de este conjunto de pruebas unitarias
  • afterEach()- llamado después de la ejecución de cada prueba unitaria dentro de este conjunto de pruebas unitarias

La beforeEach()función se usa para establecer un estado consistente antes de ejecutar cada prueba unitaria. Este concepto es muy importante para asegurarse de que el orden de ejecución de las pruebas unitarias no afecte los resultados de las pruebas unitarias en su conjunto.

En este ejemplo, la beforeEach()función representa el componente con un conjunto predeterminado de datos prop:

// SETUP - run before to each unit test
beforeEach(() => {
  // render the component
  wrapper = shallowMount(WeatherResult, {
    propsData: {
      city: '',
      weatherSummary: '',
      weatherDescription: '',
      currentTemperature: 0.0,
      lowTemperature: 0.0,
      highTemperature: 0.0
    }
  })
})

La afterEach()función se utiliza para limpiar cualquier procesamiento realizado durante la prueba unitaria.

En este ejemplo, la afterEach()función desmonta el wrapperutilizado durante la prueba unitaria, de modo que wrapperse puede reinicializar para la siguiente prueba unitaria en beforeEach():

// TEARDOWN - run after to each unit test
afterEach(() => {
  wrapper.unmount()
})

Si desea ejecutar código que se ejecute antes o después de que se ejecute el conjunto de pruebas unitarias general, puede usar:

beforeAll(() => {
  /* Runs before all tests */
})
afterAll(() => {
  /* Runs after all tests */
})

espera

La primera prueba unitaria comprueba las condiciones iniciales del WeatherResultcomponente:

it('initializes with correct elements', () => {
  // check that the heading text is rendered
  expect(wrapper.findAll('h2').length).toEqual(2)
  expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
  expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')

  // check that 6 fields of data for the temperature are displayed
  expect(wrapper.findAll('p').length).toEqual(6)
  expect(wrapper.findAll('p').at(0).text()).toMatch('City:')
  expect(wrapper.findAll('p').at(1).text()).toMatch('Summary:')
  expect(wrapper.findAll('p').at(2).text()).toMatch('Details:')
  expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 0° F')
  expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 0° F')
  expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 0° F')
})

Cheques:

  1. La primera sección de expects verifica que los dos encabezados (definidos como h2elementos) sean los esperados.
  2. La segunda sección de expects verifica que los seis campos de datos (definidos como pelementos) sean los esperados.

Ejemplo 3 - Accesorios de prueba

WeatherResultLa segunda prueba unitaria verifica que el componente maneje correctamente los datos válidos pasados ​​como datos prop :

it('processes valid props data', async () => {
  // Update the props passed in to the WeatherResult component
  wrapper.setProps({
    city: 'Chicago',
    weatherSummary: 'Cloudy',
    weatherDescription: 'Cloudy with a chance of rain',
    currentTemperature: 45.1,
    lowTemperature: 42.0,
    highTemperature: 47.7
  })

  // Wait until the DOM updates
  await flushPromises()

  // check that the prop data is stored as expected within the component
  expect(wrapper.vm.city).toMatch('Chicago')
  expect(wrapper.vm.weatherSummary).toMatch('Cloudy')
  expect(wrapper.vm.weatherDescription).toMatch('Cloudy with a chance of rain')
  expect(wrapper.vm.currentTemperature).toEqual(45.1)
  expect(wrapper.vm.lowTemperature).toBeCloseTo(42.0)
  expect(wrapper.vm.highTemperature).toBe(47.7)

  // check that the heading text is rendered
  expect(wrapper.findAll('h2').length).toEqual(2)
  expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
  expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')

  // check that 6 fields of data for the temperature are displayed
  expect(wrapper.findAll('p').length).toEqual(6)
  expect(wrapper.findAll('p').at(0).text()).toMatch('City: Chicago')
  expect(wrapper.findAll('p').at(1).text()).toMatch('Summary: Cloudy')
  expect(wrapper.findAll('p').at(2).text()).toMatch('Details: Cloudy with a chance of rain')
  expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 45.1° F')
  expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 47.7° F')
  expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 42° F')
})

Dado que la beforeEach()función proporciona un conjunto predeterminado de datos de utilería, necesitamos anular los datos de utilería usando la setProps()función.

Para asegurarse de que los datos de la propiedad provoquen las actualizaciones esperadas en el WeatherResult, la prueba debe esperar a que todas las actualizaciones del DOM surtan efecto:

// Wait until the DOM updates
await flushPromises()

NOTA: El uso de awaitsolo es posible si la función se define con async!

Cheques:

  1. Con los datos de accesorios actualizados, podemos verificar que los datos de accesorios se almacenaron correctamente dentro del WeatherResultcomponente al verificar los elementos de datos (usando wrapper.vm).
  2. La segunda sección de expects verifica que los dos encabezados (definidos como h2elementos) sean los esperados.
  3. El último conjunto de expects verifica que los datos prop se usen para configurar los seis campos de datos (definidos como pelementos) como se esperaba.

Ejemplo 4: prueba de la entrada del usuario (evento de clic)

La tercera prueba unitaria comprueba que clear-weather-datael componente emite el evento WeatherResultcuando el usuario hace clic en el botón 'Borrar datos meteorológicos':

it('emits a custom event when the Clear Weather Data button is clicked', () => {
  // trigger an event when the 'Clear Weather Data' button is clicked
  wrapper.findAll('button').at(0).trigger('click')

  // check that 1 occurrence of the event has been emitted
  expect(wrapper.emitted('clear-weather-data')).toBeTruthy()
  expect(wrapper.emitted('clear-weather-data').length).toBe(1)
})

Para desencadenar un evento de clic, el buttonelemento debe encontrarse en wrappery luego triggerse llama a la función para desencadenar el evento de clic.

Una vez que se hace clic en el botón, la prueba unitaria verifica que solo clear-weather-datase emita un evento personalizado (con el nombre de ).

Ejemplos burlones

Dentro del Appcomponente, cuando un usuario busca el clima de una ciudad, se realiza una llamada HTTP GET a Open Weather para recuperar los datos a través de una biblioteca de terceros llamada Axios :

const searchCity = (inputCity) => {
  // GET request for user data
  axios.get('http://api.openweathermap.org/data/2.5/weather?q=' + inputCity + '&units=imperial&APPID=' + openweathermapApiKey.value)
    .then((response) => {
      // handle success
      console.log(response)

      weatherData.value.city = response.data.name
      weatherData.value.weatherSummary = response.data.weather[0].main
      weatherData.value.weatherDescription = response.data.weather[0].description
      weatherData.value.currentTemperature = response.data.main.temp
      weatherData.value.lowTemperature = response.data.main.temp_min
      weatherData.value.highTemperature = response.data.main.temp_max
      validWeatherData.value = true
    })
    .catch((error) => {
      // handle error
      messageType.value = 'Error'
      messageToDisplay.value = 'ERROR! Unable to retrieve weather data for ' + inputCity + '!'
      console.log(error.message)
      resetData()
    })
    .finally((response) => {
      // always executed
      console.log('HTTP GET Finished!')
    })
}

Al pensar en cómo probar las llamadas HTTP GET, se me ocurren dos escenarios, cada uno de los cuales prueba el efecto secundario de la llamada API real:

  • La respuesta HTTP GET tiene éxito ( ruta feliz )
  • La respuesta HTTP GET falla ( ruta de excepción )

Al probar el código que utiliza una API externa, a menudo es más fácil no hacer la llamada real al principio reemplazando la llamada con un simulacro. Sin embargo, hay ventajas y desventajas en este enfoque.

Ventajas:

  1. Las pruebas no dependerán de una solicitud de red.
  2. No se romperán si la API se cae
  3. Correrán mucho más rápido

Contras:

  1. Deberá actualizar las pruebas cada vez que cambie el esquema de la API.
  2. Es difícil mantenerse al día con los cambios de API en una arquitectura de microservicio
  3. La simulación es un concepto difícil de comprender y puede agregar mucho desorden a sus conjuntos de pruebas.

En algún momento, debe verificar la integración completa para asegurarse de que la forma de la respuesta de la API no haya cambiado.

Dado que este artículo se centra en las pruebas unitarias, vamos a burlarnos de la biblioteca Axios.

La simulación proporciona un medio para imitar el comportamiento esperado de un módulo de software. Aunque la burla se puede usar en el código de producción (¡muy peligroso!), normalmente se usa durante el desarrollo y las pruebas.

La carga de datos desde una API externa lleva tiempo. Si bien normalmente toma menos de uno o dos segundos cargar los datos de Open Weather en esta aplicación, otras API externas pueden llevar más tiempo. Además, queremos una forma de verificar fácilmente si falla la solicitud HTTP GET. Entonces, agregaremos simulacros para especificar cómo respondería la solicitud GET.

Ejemplo 5: prueba de código asíncrono (caso exitoso)

Las pruebas unitarias para el Appcomponente se encuentran en el archivo src/components/__tests__/App.spec.js .

Para comenzar, necesitamos importla biblioteca Axios:

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount, mount, flushPromises } from '@vue/test-utils'
import App from '../../App.vue'
import axios from 'axios'

Sin embargo, no queremos usar la biblioteca Axios real como se hace en el código fuente ( App.vue ). En su lugar, queremos crear una simulación de la biblioteca de Axios para que en realidad no llamemos a la API externa:

// Mock the axios library
vi.mock("axios", () => {
  return {
    default: {
      get: vi.fn(),
    },
  };
});

Este bloque de código le dice a Vitest que se debe simular el get()método dentro de la axiosbiblioteca.

En el archivo de prueba de unidad ( src/components/__tests__/App.spec.js ), para el Appcomponente, estamos:

  1. Simulación de una solicitud HTTP GET exitosa
  2. Simulación de una solicitud HTTP GET fallida

Para comenzar, manejemos la situación nominal en la que la solicitud HTTP GET es exitosa.

describe('Implementation Test for App.vue with Successful HTTP GET', () => {
  let wrapper = null

  beforeEach(() => {
    const responseGet = { data:
      {
        name: 'Chicago',
        weather: [
          {
            main: 'Cloudy',
            description: 'Cloudy with a chance of rain'
          }
        ],
        main: {
          temp: 56.3,
          temp_min: 53.8,
          temp_max: 58.6
        }
      }
    }

    // Set the mock call to GET to return a successful GET response
    axios.get.mockResolvedValue(responseGet)

    // render the component
    wrapper = shallowMount(App)
  })

  afterEach(() => {
    axios.get.mockReset()
    wrapper.unmount()
  })

  ...

})

Bloques beforeEach y afterEach

En la beforeEach()función, establecemos la respuesta que debe ocurrir cuando axios.get()se llama. La respuesta son los datos meteorológicos preestablecidos que se parecen a los que obtenemos de Open Weather, si realmente hicimos la solicitud. La línea clave en esta sección es:

// Set the mock call to GET to return a successful GET response
axios.get.mockResolvedValue(responseGet)

Esta línea es la clave, ya que le permite a Vitest saber que debe devolver la responseGetmatriz cuando axios.get()se llama en el Appcomponente en lugar de realizar una llamada HTTP GET usando Axios.

La siguiente sección del conjunto de pruebas unitarias define la afterEach()función:

afterEach(() => {
  axios.get.mockReset()
  wrapper.unmount()
})

La afterEach()función, que se llama después de que se ejecuta cada prueba unitaria, borra el simulacro axios.get()que se creó durante la ejecución de la prueba unitaria. Este enfoque es una buena práctica para limpiar cualquier simulación después de ejecutar una prueba, de modo que cualquier prueba posterior comience desde un estado conocido.

espera

Ahora podemos definir la prueba unitaria:

it('does load the weather data when a successful HTTP GET occurs', async () => {
  wrapper.vm.searchCity('Chicago')

  // Wait until the DOM updates
  await flushPromises()

  expect(axios.get).toHaveBeenCalledTimes(1)
  expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

  // check that the user data is properly set
  expect(wrapper.vm.weatherData.city).toMatch('Chicago')
  expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
  expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
  expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
  expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
  expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
  expect(wrapper.vm.validWeatherData).toBe(true)
})

Dado que ya pasamos por los pasos para definir el simulacro y renderizar el componente (a través shallowMount()de ), esta prueba unitaria puede centrarse en realizar comprobaciones.

La prueba unitaria comienza llamando a la searchCity()función:

wrapper.vm.searchCity('Chicago')

Para garantizar que la searchCity()función provoque las actualizaciones esperadas en el Appcomponente, la prueba debe esperar a que se resuelvan todas las Promesas y que surtan efecto las actualizaciones del DOM:

// Wait until all Promises are resolved and the DOM updates
await flushPromises()

Verificamos que axios.get()se haya llamado una sola vez y que la llamada HTTP GET incluya el nombre de ciudad correcto:

expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

Para ser muy minuciosos, los datos meteorológicos también verifican la instancia del Appcomponente representado en esta prueba unitaria para asegurarse de que coincida con los datos preestablecidos devueltos por la simulación de axios.get():

// check that the user data is properly set
expect(wrapper.vm.weatherData.city).toMatch('Chicago')
expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
expect(wrapper.vm.validWeatherData).toBe(true)

Ejemplo 6: prueba de código asíncrono (caso de error)

Si bien es bueno probar cuando las cosas salen como se esperaba, también es importante verificar cómo reacciona nuestro software a las condiciones negativas. Con eso en mente, creemos un segundo conjunto de pruebas unitarias para verificar una solicitud HTTP GET fallida:

describe('Implementation Test for App.vue with Failed HTTP GET', () => { ... })

No hay ningún problema con tener varios conjuntos de pruebas de unidades dentro de un solo archivo de prueba de unidades ( .spec.js ).

Dado que los simulacros se crean en la beforeEach()función, es necesario que haya suites de prueba unitaria separadas con diferentes beforeEach()implementaciones para las respuestas HTTP GET tanto exitosas como fallidas.

Bloques beforeEach y afterEach

La beforeEach()función en este conjunto de pruebas unitarias es bastante diferente:

beforeEach(() => {
  // Set the mock call to GET to return a failed GET request
  axios.get.mockRejectedValue(new Error('BAD REQUEST'))

  // Render the component
  wrapper = shallowMount(App)
})

En lugar de configurar una respuesta para regresar de la axios.get()llamada, ahora devolvemos un objeto fallido Promisecon la respuesta 'MALA SOLICITUD'.

La afterEach()función de este conjunto de pruebas unitarias es idéntica a la del otro conjunto de pruebas unitarias:

afterEach(() => {
  axios.get.mockReset()
  wrapper.unmount()
})

espera

Aquí está la función de prueba unitaria para probar una solicitud HTTP GET fallida:

it('does not load the weather data when a failed HTTP GET occurs', async () => {
  wrapper.vm.searchCity('Chicago')

  expect(axios.get).toHaveBeenCalledTimes(1)
  expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

  // Wait until the DOM updates
  await flushPromises()

  // Check that there is no user data loaded when the GET request fails
  expect(wrapper.vm.weatherData.city).toMatch(/^$/)
  expect(wrapper.vm.weatherData.weatherSummary).toMatch(/^$/)
  expect(wrapper.vm.weatherData.weatherDescription).toMatch(/^$/)
  expect(wrapper.vm.weatherData.currentTemperature).toEqual(0)
  expect(wrapper.vm.weatherData.lowTemperature).toEqual(0)
  expect(wrapper.vm.weatherData.highTemperature).toEqual(0)
  expect(wrapper.vm.validWeatherData).toBe(false)

  // check that the banner message indicates failure
  expect(wrapper.vm.messageToDisplay).toMatch('ERROR! Unable to retrieve weather data for Chicago!')
  expect(wrapper.vm.messageType).toMatch('Error')
})

Al igual que en el conjunto de pruebas unitarias anterior, verificamos que solo axios.get()se llame a una instancia de y luego verificamos que no se hayan cargado datos meteorológicos en el Appcomponente.

Cobertura de código

Al desarrollar pruebas unitarias, puede ser bueno comprender cuánto del código fuente se prueba realmente. Este concepto se conoce como cobertura de código.

Debo dejar muy claro que tener un conjunto de pruebas unitarias que cubran el 100% del código fuente no es de ninguna manera un indicador de que el código se haya probado correctamente.

Esta métrica significa que hay muchas pruebas unitarias y se ha puesto mucho esfuerzo en desarrollar las pruebas unitarias. La calidad de las pruebas unitarias aún debe verificarse mediante la inspección del código.

El otro extremo donde se trata de un conjunto mínimo (¡o ninguno!) de pruebas unitarias es un indicador muy malo.

Vitest proporciona cobertura de código mediante el uso de la --coveragebandera.

Para ejecutar fácilmente Vitest con resultados de cobertura, me gusta incluir los siguientes elementos en la scriptsección de package.json :

{
  "name": "vue-weather-app",
  "version": "1.0.0",
  "scripts": {
    ...
    "test:unit": "vitest run --environment jsdom",
    "test:coverage": "vitest run --environment jsdom --coverage",
    "test:ui": "vitest --environment jsdom --coverage --ui"
  },
  ...
}

Cuando npm run test:unitse ejecuta, se ejecutan las pruebas unitarias:

$ npm run test:unit
...
 ✓ src/components/__tests__/WeatherBanner.spec.js (5)
 ✓ src/components/__tests__/WeatherSearch.spec.js (5)
 ✓ src/components/__tests__/WeatherFooter.spec.js (1)
 ✓ src/components/__tests__/WeatherHeader.spec.js (1)
 ✓ src/components/__tests__/WeatherResult.spec.js (3)
 ✓ src/components/__tests__/App.spec.js (7)

Test Files  6 passed (6)
     Tests  22 passed (22)
      Time  2.81s (in thread 536ms, 524.89%)

Cuando npm run test:coveragese ejecuta, se ejecutan las pruebas unitarias y se reporta la cobertura:

$ npm run test:coverage
...
Test Files  6 passed (6)
     Tests  22 passed (22)
      Time  3.38s (in thread 660ms, 512.10%)

--------------------|---------|----------|---------|---------|-------------------
File                | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files           |   99.15 |    96.55 |     100 |   99.15 |
 src                |   97.31 |    85.71 |     100 |   97.31 |
  App.vue           |   97.31 |    85.71 |     100 |   97.31 | 60-63
 src/components     |     100 |      100 |     100 |     100 |
  WeatherBanner.vue |     100 |      100 |     100 |     100 |
  WeatherFooter.vue |     100 |      100 |     100 |     100 |
  WeatherHeader.vue |     100 |      100 |     100 |     100 |
  WeatherResult.vue |     100 |      100 |     100 |     100 |
  WeatherSearch.vue |     100 |      100 |     100 |     100 |
--------------------|---------|----------|---------|---------|-------------------

Cargará los npm run test:uiresultados de la prueba y la cobertura en su navegador web predeterminado, lo que puede ser conveniente para ver dónde falta la cobertura de la prueba.

Estructura de prueba unitaria

Después de pasar por muchos archivos de prueba de unidad diferentes, recomiendo la siguiente estructura para el archivo de prueba de unidad para un componente de Vue:

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import App from '@/App.vue'  // Import Vue component to test
import axios from 'axios'    // Import libraries to mock

// Mock the axios library
vi.mock("axios", () => {
  return {
    default: {
      get: vi.fn(),
    },
  };
});


describe('Tests for the ... Component', () => {
  let wrapper = null

  beforeEach(() => {
    // set any initial data and create the mocks of libraries

    // render the component
    wrapper = shallowMount(App)
  })

  afterEach(() => {
    axios.get.mockReset()
    wrapper.unmount()
  })

  it('check successful events', () => { ... })

  it('check failure events', () => { ... })
})

Elementos clave:

  • Cada conjunto de pruebas unitarias tiene un conjunto relacionado de pruebas unitarias
  • Utilice las funciones beforeEach()y afterEach()para crear funciones de prueba unitaria independientes
  • Cree simulacros de cualquier biblioteca utilizada dentro del componente Vue que se prueba
  • Representar los componentes en la beforeEach()función y actualizar los datos de utilería dentro de las funciones de prueba unitaria
  • Utilícelo shallowMount()para mount()centrarse en probar componentes individuales

Conclusión

Este artículo proporciona una guía para las pruebas unitarias de los componentes de Vue, centrándose en:

  1. Por qué deberías escribir pruebas unitarias
  2. Lo que debe (y no debe) probar la unidad
  3. Cómo escribir pruebas unitarias

En pocas palabras, al considerar qué probar, concéntrese en probar las entradas y salidas (resultados reales), no la lógica empresarial subyacente (cómo se producen los resultados). Con esto en mente, tómese uno o dos minutos para revisar los ejemplos nuevamente, tomando nota de las entradas y salidas probadas.

Fuente:  https://testdriven.io

#vue 

What is GEEK

Buddha Community

Cómo Y Guía Para Las Pruebas Unitarias Componentes Vue

Cómo Y Guía Para Las Pruebas Unitarias Componentes Vue

Este artículo sirve como guía para las pruebas unitarias de los componentes de Vue.

Primero veremos por qué las pruebas unitarias son importantes para crear software mantenible y qué debe probar. Luego, detallaremos cómo:

  1. Cree y ejecute una prueba unitaria para un componente Vue
  2. Probar diferentes aspectos de un componente Vue
  3. Use simulacros para probar funciones asíncronas
  4. Verifique la cobertura de código de sus pruebas unitarias
  5. Estructure sus archivos de prueba de unidad

Dependencias :

El código fuente (junto con instrucciones de instalación detalladas) para el proyecto de la aplicación Vue Weather que se usa en este artículo se puede encontrar en GitLab: Vue Weather App .

Objetivos

Al final de este artículo, usted debería ser capaz de:

  1. Explicar por qué las pruebas unitarias son importantes.
  2. Describa lo que debe (y no debe) probar la unidad
  3. Desarrollar un conjunto de pruebas unitarias para un componente de Vue
  4. Ejecute las pruebas unitarias para un proyecto Vue
  5. Utilizar las funciones beforeEach()y afterEach()dentro de un conjunto de pruebas unitarias
  6. Escribir pruebas unitarias para probar los detalles de implementación de un componente Vue
  7. Escriba pruebas unitarias para probar los aspectos de comportamiento de un componente Vue (eventos de clic, etc.)
  8. Explicar cómo la simulación puede ayudar a simplificar las pruebas unitarias
  9. Escribir pruebas unitarias para burlarse de una biblioteca y probar funciones asincrónicas
  10. Verifique la cobertura de código de sus pruebas unitarias
  11. Desarrolle un archivo de prueba de unidad bien estructurado para probar un componente de Vue

¿Por qué prueba unitaria?

En general, las pruebas ayudan a garantizar que su aplicación funcione según lo esperado para sus usuarios finales.

Los proyectos de software con una alta cobertura de pruebas nunca son perfectos, pero es un buen indicador inicial de la calidad del software. Además, el código comprobable generalmente es un signo de una buena arquitectura de software, razón por la cual los desarrolladores avanzados tienen en cuenta las pruebas durante todo el ciclo de vida del desarrollo.

Las pruebas se pueden considerar en tres niveles:

  1. Unidad
  2. Integración
  3. De extremo a extremo

Las pruebas unitarias prueban la funcionalidad de una unidad de código individual aislada de sus dependencias. Son la primera línea de defensa contra errores e inconsistencias en su base de código. Las pruebas unitarias son una parte fundamental del proceso de desarrollo dirigido por pruebas (TDD).

Las pruebas unitarias mejoran la capacidad de mantenimiento de su código.

La capacidad de mantenimiento se refiere a realizar correcciones de errores o mejoras a su código o a otro desarrollador que necesite actualizar su código en el futuro.

Las pruebas unitarias deben combinarse con un proceso de integración continua (CI) para garantizar que sus pruebas unitarias se ejecuten constantemente, idealmente en cada confirmación en su repositorio. Un conjunto sólido de pruebas unitarias puede ser fundamental para detectar defectos de manera rápida y temprana en el proceso de desarrollo antes de que los usuarios finales los encuentren en producción.

Qué probar

¿Qué deberías probar? O, más importante aún: ¿Qué no debes probar?

Hay tres tipos de pruebas a considerar con las pruebas unitarias:

  1. Detalles de implementación : la lógica empresarial subyacente que utiliza un componente para producir un resultado basado en una entrada dada
  2. Interfaz pública/contrato de diseño : insumos específicos (o accesorios, en este caso) producen resultados específicos
  3. Efectos secundarios : "si esto, entonces aquello"; por ejemplo, cuando se hace clic en un botón, algo sucede

Dado que no puede probar todas las cosas, ¿en qué debe concentrarse?

Concéntrese en probar las entradas y salidas con las que interactuará el usuario final. ¡La experiencia que tienen los usuarios de tu producto es primordial!

  1. Entradas : datos, accesorios, interacción del usuario, métodos de ciclo de vida, almacén de datos ( Pinia / Vuex ), parámetros de ruta, cadenas de consulta
  2. Salidas : salida renderizada, eventos, resultados de datos, actualizaciones del almacén de datos (Pinia/Vuex), envíos

Al centrarse en probar las entradas/salidas de un módulo de software (por ejemplo, un componente de Vue), está probando los aspectos clave que experimentará el usuario final.

Puede haber otra lógica interna en un módulo de software que sea complejo y deba someterse a pruebas unitarias, pero es más probable que estos tipos de pruebas necesiten una actualización durante una refactorización de código.

Descripción general de la aplicación

Antes de analizar cómo realizar pruebas unitarias de los componentes de Vue, quiero brindar una breve descripción general de la aplicación Vue Weather que probaremos.

Después de clonar el repositorio, instale las dependencias y agregue la clave API.

Revise el LÉAME del proyecto para obtener más información sobre cómo crear y agregar la clave API de Open Weather.

Una vez hecho esto, la aplicación Vue Weather se puede ejecutar en su computadora local iniciando el servidor de desarrollo:

$ npm run dev

Una vez que se crea la aplicación, verá un mensaje de éxito similar a:

vite v2.9.14 dev server running at:

 > Local: http://localhost:3000/
 > Network: use `--host` to expose

 ready in 543ms.

En este punto, el servidor de desarrollo estará en funcionamiento. Puede ver la aplicación Vue navegando a http://localhost:3000 en su navegador web favorito. Cuando carga la aplicación por primera vez, no se muestran datos; solo verá un campo de entrada para ingresar la ciudad para la que le gustaría obtener el clima:

Tutorial de la aplicación Vue Weather - Paso 1

Sin ningún dato ingresado, los botones 'Buscar' y 'Borrar' están deshabilitados.

Una vez que comience a ingresar datos para una ciudad (tan pronto como se agregue el primer carácter), se habilitarán los botones 'Buscar' y 'Borrar':

Tutorial de la aplicación Vue Weather - Paso 2

Si hace clic en 'Buscar' después de ingresar una ciudad válida, se mostrarán los datos meteorológicos para esa ciudad:

Tutorial de la aplicación Vue Weather - Paso 3

En este punto, al hacer clic en el botón 'Borrar datos meteorológicos' se borrarán los datos meteorológicos:

Tutorial de la aplicación Vue Weather - Paso 4

Sin embargo, la ciudad que se ingresó permanecerá en el campo de entrada.

Si hace clic en 'Borrar' ahora, el campo de entrada se borrará y los botones 'Buscar' y 'Borrar' se desactivarán una vez más:

Tutorial de la aplicación Vue Weather - Paso 5

¿Qué sucede si ingresa una ciudad no válida? ¿Qué sucede si hace clic en 'Borrar' antes de 'Borrar datos meteorológicos'? ¿Qué otros estados de la aplicación puedes encontrar?

Pruebas unitarias en Vue

Dado que los componentes son los componentes básicos de Vue (y, en realidad, de cualquier marco SPA ), son la parte más crucial de su aplicación en su conjunto. Por lo tanto, dedique la mayor parte de su tiempo de prueba asignado a escribir pruebas unitarias que prueben los componentes de su aplicación.

Según mi experiencia con las pruebas unitarias de los componentes de Vue, descubrí que las herramientas y el marco de prueba, Vite y Vitest, satisfacen los aspectos clave de un buen entorno de prueba:

  • las pruebas son fáciles y divertidas de escribir
  • las pruebas se pueden escribir rápidamente
  • las pruebas se pueden ejecutar con un solo comando
  • las pruebas se ejecutan rápidamente

Con suerte, encontrará que la prueba unitaria de sus componentes Vue es una experiencia agradable, ya que creo que es clave para fomentar más pruebas.

Herramientas de prueba unitaria

Hay dos herramientas que vamos a utilizar para las pruebas unitarias de los componentes de Vue:

  1. Vitest - marco de prueba unitaria
  2. Vue Test Utils : biblioteca de utilidades de pruebas unitarias para Vue

Vitest es un marco de prueba de unidad que pretende ser independiente del marco, por lo que se puede usar para probar Vue, React, Svelte, Lit y ​​otros proyectos. Vitest está configurado para ejecutarse con Vite, lo que da como resultado una ejecución de prueba rápida .

Si está familiarizado con Jest, cambiar a Vitest es muy sencillo, ya que la API de Vitest es compatible con Jest.

Al escribir pruebas unitarias para un componente Vue, Vitest y Vue Test Utils brindan la siguiente funcionalidad:

engranaje

  • Herramienta de línea de comandos para ejecutar las pruebas y verificar la cobertura de la prueba
  • Interfaz de usuario para ver visualmente los resultados de las pruebas y los resultados de cobertura
  • Funciones para escribir pruebas unitarias ( it, describe)
  • Funciones para comprobar los valores esperados ( expect, toMatch, toContain, etc.)
  • burlándose ( mockResolvedValue, mockRejectedValue)
  • Configuración ( beforeEach, beforeAll) / Desmontaje ( afterEach, afterAll)

Ver utilidades de prueba

  • Componentes de montaje ( mount, shallowMount)
  • Configuración de datos de accesorios ( setProps)
  • Encontrar componentes HTML para probar ( findAll('h2'))
  • Utilidad para vaciar todas las Promesas ( flushPromises())
  • Utilidad para desencadenar eventos de clic ( trigger)
  • Utilidad para comprobar eventos emitidos ( emitted)

Vitest proporciona la funcionalidad genérica para escribir pruebas unitarias, mientras que Vue Test Utils proporciona las utilidades de prueba específicas de Vue.

Descripción general de las pruebas unitarias

Para empezar, analicemos la convención de nomenclatura para las pruebas unitarias en Vue. El archivo de prueba de la unidad debe tener el siguiente formato:

  • <ComponentName>.spec.js

Según la Guía de estilo de Vue , los nombres de los componentes deben ser varias palabras ( WeatherHeaderen lugar de solo Header) para evitar conflictos con los elementos HTML.

Por lo general, debe tener un archivo de prueba de unidad para cada componente en su proyecto Vue. Dentro de cada archivo de prueba de unidad, puede haber un conjunto de pruebas de una sola unidad o conjuntos de pruebas de varias unidades.

Los archivos de prueba de unidad deben colocarse en una subcarpeta dentro de la carpeta Componentes ( src/components/__tests__ ):

$ tree -d -L 2
.
├── node_modules
├── public
├── src
    ├── assets
    └── components
        └── __tests__

Ejecución de las pruebas

Vitest se puede usar para ejecutar las pruebas unitarias de la siguiente manera:

$ npm run test:unit

✓ src/components/__tests__/WeatherFooter.spec.js (1)
✓ src/components/__tests__/WeatherHeader.spec.js (1)
✓ src/components/__tests__/WeatherResult.spec.js (3)
✓ src/components/__tests__/WeatherBanner.spec.js (5)
✓ src/components/__tests__/WeatherSearch.spec.js (5)
✓ src/components/__tests__/App.spec.js (7)

Test Files  6 passed (6)
    Tests  22 passed (22)
     Time  2.38s (in thread 640ms, 371.13%)

Todos los comandos disponibles para ejecutar a través npmde su proyecto Vue se definen en el scriptscampo en package.json .

La configuración predeterminada para Vitest es ejecutar las pruebas en modo de observación , lo que significa que el conjunto de pruebas se volverá a ejecutar cada vez que se guarde en un archivo aplicable. Para cambiar esta configuración para que Vitest solo se ejecute una vez (sin "modo de observación"), actualice la test:unitconfiguración en package.json para incluir el runargumento:

"test:unit": "vitest run --environment jsdom",

Ejemplos

Con la aplicación Vue Weather , veamos algunos ejemplos para probar los componentes de Vue.

Ejemplo 1 - Introducción a la prueba unitaria

¡Pasemos directamente a un ejemplo de un archivo de prueba de unidad en Vue! El primer archivo de prueba de unidad se encuentra en src/components/__tests__/WeatherHeader.spec.js y prueba el WeatherHeadercomponente:

import { describe, it, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import WeatherHeader from '../WeatherHeader.vue'


describe('WeatherHeader.vue Test', () => {
  it('renders message when component is created', () => {
    // render the component
    const wrapper = shallowMount(WeatherHeader, {
      propsData: {
        title: 'Vue Project'
      }
    })

    // check that the title is rendered
    expect(wrapper.text()).toMatch('Vue Project')
  })
})

Montaje

La primera línea de este archivo importa las funciones de prueba de Vitest que se utilizan en este archivo.

Si desea que la API de Vitest esté disponible globalmente (como funciona Jest), agregue test: {globals: true}la defineConfig()función en vite.config.js . Para obtener más detalles, consulte la documentación de Vitest .

La segunda línea de este archivo importa una función llamada shallowMountdesde la biblioteca Vue Test Utils. La idea de 'montaje' significa la carga de un componente individual para poder probarlo. Hay dos métodos para esto en Vue Test Utils:

  • shallowMount()- crea un wrapperpara el componente Vue, pero con componentes secundarios stubed
  • mount()- crea un wrapperpara el componente Vue, incluido el montaje de cualquier componente secundario

Dado que nuestro enfoque es probar un componente individual (el WeatherHeadercomponente), usaremos shallowMount().

shallowMount()es mejor para probar un componente individual de forma aislada, ya que los componentes secundarios se excluyen. Esta es la situación ideal para las pruebas unitarias .

Además, usar shallowMount()para probar un componente con muchos componentes secundarios puede mejorar el tiempo de ejecución de la prueba unitaria ya que no hay costo (en términos de tiempo) para renderizar los componentes secundarios.

mount()es útil cuando desea incluir la prueba del comportamiento de los componentes secundarios.

La tercera línea importa el componente de Vue que se va a probar, WeatherHeader.vue .

Describir bloques

Después de las importdeclaraciones, hay un describebloque que define un conjunto de pruebas unitarias.

Dentro de un archivo de prueba unitaria, puede haber múltiples describebloques que definen diferentes conjuntos de pruebas unitarias. De manera similar, cada describebloque puede contener múltiples pruebas unitarias, donde cada prueba unitaria está definida por un itbloque.

Pienso en esta distinción como:

  • describebloque - conjunto de pruebas unitarias
  • itbloque - función de prueba de unidad individual

Lo bueno de las pruebas unitarias con Vitest es que hay varios estímulos incorporados para agregar comentarios. Por ejemplo, el primer argumento para describedebe explicar claramente qué componente de Vue se está probando:

describe('WeatherHeader.vue Test', () => { ... })

Para cada itbloque, el primer argumento es una descripción de la función de prueba, que debe ser una breve descripción de lo que está haciendo esta prueba específica. En el ejemplo anterior, el itbloque prueba que el componente 'presenta un mensaje cuando se crea el componente'.

espera

En cuanto a la prueba unitaria real, el primer paso es montar el componente Vue para que pueda probarse:

// render the component
const wrapper = shallowMount(WeatherHeader, {
  propsData: {
    title: 'Vue Project'
  }
})

La shallowMountfunción devuelve un wrapperobjeto que contiene el componente montado y los métodos para probar ese componente. El wrapperobjeto nos permite probar todos los aspectos del HTML generado por el componente Vue y todas las propiedades (como los datos) del componente Vue.

Además, los accesorios, pasados ​​al WeatherHeadercomponente, se pasan como segundo argumento a shallowMount().

La verificación real realizada en la prueba unitaria es:

// check that the title is rendered
expect(wrapper.text()).toMatch('Vue Project')

Esta línea se usa wrapperpara verificar si el título generado por el componente es 'Vue Project'. Dado que esta verificación hace una comparación de cadenas, se recomienda usar toMatch().

Ayudantes de prueba

Si bien las comprobaciones en el archivo de prueba de la unidad para el WeatherHeadercomponente solo verifican los valores de cadena, hay [muchas opciones disponibles de Vitest para realizar comprobaciones:

  • Booleanos:
    • toBeTruthy()- comprueba que una variable/declaración es verdadera
    • toBeFalsy()- comprueba que una variable/declaración es falsa
  • Definido:
    • toBeNull()- comprueba si una variable coincide solo con nulo
    • toBeUndefined()- comprueba si una variable no está definida
    • toBeDefined()- comprueba si una variable está definida
  • Números:
    • toBeGreaterThan()- comprueba si un número es mayor que el valor especificado
    • toBeGreaterThanOrEqual()- comprueba si un número es mayor o igual que el valor especificado
    • toBeLessThan()- comprueba si un número es menor que el valor especificado
    • toBeLessThanOrEqual()- comprueba si un número es menor o igual que el valor especificado
    • toBe()y toEqual()- comprueba si un número es el mismo que el valor especificado (estas funciones son equivalentes para los números)
    • toBeCloseTo()- comprueba si un número es igual al valor especificado dentro de una pequeña tolerancia (útil para números de punto flotante)
  • Instrumentos de cuerda:
    • toMatch()- comprueba si una cadena es igual al valor especificado (¡Regex se puede usar como el valor especificado!)
  • Matrices:
    • toContain()- comprueba si una matriz contiene el valor especificado

Además, el notcalificador se puede utilizar con la mayoría de estas comprobaciones:

expect(wrapper.text()).not.toMatch('Node Project')

Para obtener una lista completa de las comprobaciones disponibles, consulte la referencia de la API de Vitest .

Ejemplo 2: prueba de las condiciones iniciales

Este ejemplo muestra cómo probar las condiciones iniciales (o estado) del WeatherResultcomponente.

Aquí hay un resumen del archivo de prueba de la unidad (definido en src/components/__tests__/WeatherResult.spec.js ):

import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { shallowMount, flushPromises } from '@vue/test-utils'
import WeatherResult from '@/components/WeatherResult.vue'


describe('WeatherResult.vue Implementation Test', () => {
  let wrapper = null

  // SETUP - run before to each unit test
  beforeEach(() => {
    // render the component
    wrapper = shallowMount(WeatherResult, {
      propsData: {
        city: '',
        weatherSummary: '',
        weatherDescription: '',
        currentTemperature: 0.0,
        lowTemperature: 0.0,
        highTemperature: 0.0
      }
    })
  })

  // TEARDOWN - run after to each unit test
  afterEach(() => {
    wrapper.unmount()
  })

  it('initializes with correct elements', () => { ... })

  it('processes valid props data', async () => { ... })

  it('emits a custom event when the Clear Weather Data button is clicked', () => { ... })
})

El archivo de prueba unitaria utiliza la shallowMount()función para renderizar el WeatherResultcomponente, ya que este componente se prueba como un componente individual de forma aislada.

Bloques beforeEach y afterEach

Dentro del conjunto de pruebas unitarias (definido dentro del describebloque), hay dos nuevas funciones definidas:

  • beforeEach()- llamado antes de la ejecución de cada prueba unitaria dentro de este conjunto de pruebas unitarias
  • afterEach()- llamado después de la ejecución de cada prueba unitaria dentro de este conjunto de pruebas unitarias

La beforeEach()función se usa para establecer un estado consistente antes de ejecutar cada prueba unitaria. Este concepto es muy importante para asegurarse de que el orden de ejecución de las pruebas unitarias no afecte los resultados de las pruebas unitarias en su conjunto.

En este ejemplo, la beforeEach()función representa el componente con un conjunto predeterminado de datos prop:

// SETUP - run before to each unit test
beforeEach(() => {
  // render the component
  wrapper = shallowMount(WeatherResult, {
    propsData: {
      city: '',
      weatherSummary: '',
      weatherDescription: '',
      currentTemperature: 0.0,
      lowTemperature: 0.0,
      highTemperature: 0.0
    }
  })
})

La afterEach()función se utiliza para limpiar cualquier procesamiento realizado durante la prueba unitaria.

En este ejemplo, la afterEach()función desmonta el wrapperutilizado durante la prueba unitaria, de modo que wrapperse puede reinicializar para la siguiente prueba unitaria en beforeEach():

// TEARDOWN - run after to each unit test
afterEach(() => {
  wrapper.unmount()
})

Si desea ejecutar código que se ejecute antes o después de que se ejecute el conjunto de pruebas unitarias general, puede usar:

beforeAll(() => {
  /* Runs before all tests */
})
afterAll(() => {
  /* Runs after all tests */
})

espera

La primera prueba unitaria comprueba las condiciones iniciales del WeatherResultcomponente:

it('initializes with correct elements', () => {
  // check that the heading text is rendered
  expect(wrapper.findAll('h2').length).toEqual(2)
  expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
  expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')

  // check that 6 fields of data for the temperature are displayed
  expect(wrapper.findAll('p').length).toEqual(6)
  expect(wrapper.findAll('p').at(0).text()).toMatch('City:')
  expect(wrapper.findAll('p').at(1).text()).toMatch('Summary:')
  expect(wrapper.findAll('p').at(2).text()).toMatch('Details:')
  expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 0° F')
  expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 0° F')
  expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 0° F')
})

Cheques:

  1. La primera sección de expects verifica que los dos encabezados (definidos como h2elementos) sean los esperados.
  2. La segunda sección de expects verifica que los seis campos de datos (definidos como pelementos) sean los esperados.

Ejemplo 3 - Accesorios de prueba

WeatherResultLa segunda prueba unitaria verifica que el componente maneje correctamente los datos válidos pasados ​​como datos prop :

it('processes valid props data', async () => {
  // Update the props passed in to the WeatherResult component
  wrapper.setProps({
    city: 'Chicago',
    weatherSummary: 'Cloudy',
    weatherDescription: 'Cloudy with a chance of rain',
    currentTemperature: 45.1,
    lowTemperature: 42.0,
    highTemperature: 47.7
  })

  // Wait until the DOM updates
  await flushPromises()

  // check that the prop data is stored as expected within the component
  expect(wrapper.vm.city).toMatch('Chicago')
  expect(wrapper.vm.weatherSummary).toMatch('Cloudy')
  expect(wrapper.vm.weatherDescription).toMatch('Cloudy with a chance of rain')
  expect(wrapper.vm.currentTemperature).toEqual(45.1)
  expect(wrapper.vm.lowTemperature).toBeCloseTo(42.0)
  expect(wrapper.vm.highTemperature).toBe(47.7)

  // check that the heading text is rendered
  expect(wrapper.findAll('h2').length).toEqual(2)
  expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
  expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')

  // check that 6 fields of data for the temperature are displayed
  expect(wrapper.findAll('p').length).toEqual(6)
  expect(wrapper.findAll('p').at(0).text()).toMatch('City: Chicago')
  expect(wrapper.findAll('p').at(1).text()).toMatch('Summary: Cloudy')
  expect(wrapper.findAll('p').at(2).text()).toMatch('Details: Cloudy with a chance of rain')
  expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 45.1° F')
  expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 47.7° F')
  expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 42° F')
})

Dado que la beforeEach()función proporciona un conjunto predeterminado de datos de utilería, necesitamos anular los datos de utilería usando la setProps()función.

Para asegurarse de que los datos de la propiedad provoquen las actualizaciones esperadas en el WeatherResult, la prueba debe esperar a que todas las actualizaciones del DOM surtan efecto:

// Wait until the DOM updates
await flushPromises()

NOTA: El uso de awaitsolo es posible si la función se define con async!

Cheques:

  1. Con los datos de accesorios actualizados, podemos verificar que los datos de accesorios se almacenaron correctamente dentro del WeatherResultcomponente al verificar los elementos de datos (usando wrapper.vm).
  2. La segunda sección de expects verifica que los dos encabezados (definidos como h2elementos) sean los esperados.
  3. El último conjunto de expects verifica que los datos prop se usen para configurar los seis campos de datos (definidos como pelementos) como se esperaba.

Ejemplo 4: prueba de la entrada del usuario (evento de clic)

La tercera prueba unitaria comprueba que clear-weather-datael componente emite el evento WeatherResultcuando el usuario hace clic en el botón 'Borrar datos meteorológicos':

it('emits a custom event when the Clear Weather Data button is clicked', () => {
  // trigger an event when the 'Clear Weather Data' button is clicked
  wrapper.findAll('button').at(0).trigger('click')

  // check that 1 occurrence of the event has been emitted
  expect(wrapper.emitted('clear-weather-data')).toBeTruthy()
  expect(wrapper.emitted('clear-weather-data').length).toBe(1)
})

Para desencadenar un evento de clic, el buttonelemento debe encontrarse en wrappery luego triggerse llama a la función para desencadenar el evento de clic.

Una vez que se hace clic en el botón, la prueba unitaria verifica que solo clear-weather-datase emita un evento personalizado (con el nombre de ).

Ejemplos burlones

Dentro del Appcomponente, cuando un usuario busca el clima de una ciudad, se realiza una llamada HTTP GET a Open Weather para recuperar los datos a través de una biblioteca de terceros llamada Axios :

const searchCity = (inputCity) => {
  // GET request for user data
  axios.get('http://api.openweathermap.org/data/2.5/weather?q=' + inputCity + '&units=imperial&APPID=' + openweathermapApiKey.value)
    .then((response) => {
      // handle success
      console.log(response)

      weatherData.value.city = response.data.name
      weatherData.value.weatherSummary = response.data.weather[0].main
      weatherData.value.weatherDescription = response.data.weather[0].description
      weatherData.value.currentTemperature = response.data.main.temp
      weatherData.value.lowTemperature = response.data.main.temp_min
      weatherData.value.highTemperature = response.data.main.temp_max
      validWeatherData.value = true
    })
    .catch((error) => {
      // handle error
      messageType.value = 'Error'
      messageToDisplay.value = 'ERROR! Unable to retrieve weather data for ' + inputCity + '!'
      console.log(error.message)
      resetData()
    })
    .finally((response) => {
      // always executed
      console.log('HTTP GET Finished!')
    })
}

Al pensar en cómo probar las llamadas HTTP GET, se me ocurren dos escenarios, cada uno de los cuales prueba el efecto secundario de la llamada API real:

  • La respuesta HTTP GET tiene éxito ( ruta feliz )
  • La respuesta HTTP GET falla ( ruta de excepción )

Al probar el código que utiliza una API externa, a menudo es más fácil no hacer la llamada real al principio reemplazando la llamada con un simulacro. Sin embargo, hay ventajas y desventajas en este enfoque.

Ventajas:

  1. Las pruebas no dependerán de una solicitud de red.
  2. No se romperán si la API se cae
  3. Correrán mucho más rápido

Contras:

  1. Deberá actualizar las pruebas cada vez que cambie el esquema de la API.
  2. Es difícil mantenerse al día con los cambios de API en una arquitectura de microservicio
  3. La simulación es un concepto difícil de comprender y puede agregar mucho desorden a sus conjuntos de pruebas.

En algún momento, debe verificar la integración completa para asegurarse de que la forma de la respuesta de la API no haya cambiado.

Dado que este artículo se centra en las pruebas unitarias, vamos a burlarnos de la biblioteca Axios.

La simulación proporciona un medio para imitar el comportamiento esperado de un módulo de software. Aunque la burla se puede usar en el código de producción (¡muy peligroso!), normalmente se usa durante el desarrollo y las pruebas.

La carga de datos desde una API externa lleva tiempo. Si bien normalmente toma menos de uno o dos segundos cargar los datos de Open Weather en esta aplicación, otras API externas pueden llevar más tiempo. Además, queremos una forma de verificar fácilmente si falla la solicitud HTTP GET. Entonces, agregaremos simulacros para especificar cómo respondería la solicitud GET.

Ejemplo 5: prueba de código asíncrono (caso exitoso)

Las pruebas unitarias para el Appcomponente se encuentran en el archivo src/components/__tests__/App.spec.js .

Para comenzar, necesitamos importla biblioteca Axios:

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount, mount, flushPromises } from '@vue/test-utils'
import App from '../../App.vue'
import axios from 'axios'

Sin embargo, no queremos usar la biblioteca Axios real como se hace en el código fuente ( App.vue ). En su lugar, queremos crear una simulación de la biblioteca de Axios para que en realidad no llamemos a la API externa:

// Mock the axios library
vi.mock("axios", () => {
  return {
    default: {
      get: vi.fn(),
    },
  };
});

Este bloque de código le dice a Vitest que se debe simular el get()método dentro de la axiosbiblioteca.

En el archivo de prueba de unidad ( src/components/__tests__/App.spec.js ), para el Appcomponente, estamos:

  1. Simulación de una solicitud HTTP GET exitosa
  2. Simulación de una solicitud HTTP GET fallida

Para comenzar, manejemos la situación nominal en la que la solicitud HTTP GET es exitosa.

describe('Implementation Test for App.vue with Successful HTTP GET', () => {
  let wrapper = null

  beforeEach(() => {
    const responseGet = { data:
      {
        name: 'Chicago',
        weather: [
          {
            main: 'Cloudy',
            description: 'Cloudy with a chance of rain'
          }
        ],
        main: {
          temp: 56.3,
          temp_min: 53.8,
          temp_max: 58.6
        }
      }
    }

    // Set the mock call to GET to return a successful GET response
    axios.get.mockResolvedValue(responseGet)

    // render the component
    wrapper = shallowMount(App)
  })

  afterEach(() => {
    axios.get.mockReset()
    wrapper.unmount()
  })

  ...

})

Bloques beforeEach y afterEach

En la beforeEach()función, establecemos la respuesta que debe ocurrir cuando axios.get()se llama. La respuesta son los datos meteorológicos preestablecidos que se parecen a los que obtenemos de Open Weather, si realmente hicimos la solicitud. La línea clave en esta sección es:

// Set the mock call to GET to return a successful GET response
axios.get.mockResolvedValue(responseGet)

Esta línea es la clave, ya que le permite a Vitest saber que debe devolver la responseGetmatriz cuando axios.get()se llama en el Appcomponente en lugar de realizar una llamada HTTP GET usando Axios.

La siguiente sección del conjunto de pruebas unitarias define la afterEach()función:

afterEach(() => {
  axios.get.mockReset()
  wrapper.unmount()
})

La afterEach()función, que se llama después de que se ejecuta cada prueba unitaria, borra el simulacro axios.get()que se creó durante la ejecución de la prueba unitaria. Este enfoque es una buena práctica para limpiar cualquier simulación después de ejecutar una prueba, de modo que cualquier prueba posterior comience desde un estado conocido.

espera

Ahora podemos definir la prueba unitaria:

it('does load the weather data when a successful HTTP GET occurs', async () => {
  wrapper.vm.searchCity('Chicago')

  // Wait until the DOM updates
  await flushPromises()

  expect(axios.get).toHaveBeenCalledTimes(1)
  expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

  // check that the user data is properly set
  expect(wrapper.vm.weatherData.city).toMatch('Chicago')
  expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
  expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
  expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
  expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
  expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
  expect(wrapper.vm.validWeatherData).toBe(true)
})

Dado que ya pasamos por los pasos para definir el simulacro y renderizar el componente (a través shallowMount()de ), esta prueba unitaria puede centrarse en realizar comprobaciones.

La prueba unitaria comienza llamando a la searchCity()función:

wrapper.vm.searchCity('Chicago')

Para garantizar que la searchCity()función provoque las actualizaciones esperadas en el Appcomponente, la prueba debe esperar a que se resuelvan todas las Promesas y que surtan efecto las actualizaciones del DOM:

// Wait until all Promises are resolved and the DOM updates
await flushPromises()

Verificamos que axios.get()se haya llamado una sola vez y que la llamada HTTP GET incluya el nombre de ciudad correcto:

expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

Para ser muy minuciosos, los datos meteorológicos también verifican la instancia del Appcomponente representado en esta prueba unitaria para asegurarse de que coincida con los datos preestablecidos devueltos por la simulación de axios.get():

// check that the user data is properly set
expect(wrapper.vm.weatherData.city).toMatch('Chicago')
expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
expect(wrapper.vm.validWeatherData).toBe(true)

Ejemplo 6: prueba de código asíncrono (caso de error)

Si bien es bueno probar cuando las cosas salen como se esperaba, también es importante verificar cómo reacciona nuestro software a las condiciones negativas. Con eso en mente, creemos un segundo conjunto de pruebas unitarias para verificar una solicitud HTTP GET fallida:

describe('Implementation Test for App.vue with Failed HTTP GET', () => { ... })

No hay ningún problema con tener varios conjuntos de pruebas de unidades dentro de un solo archivo de prueba de unidades ( .spec.js ).

Dado que los simulacros se crean en la beforeEach()función, es necesario que haya suites de prueba unitaria separadas con diferentes beforeEach()implementaciones para las respuestas HTTP GET tanto exitosas como fallidas.

Bloques beforeEach y afterEach

La beforeEach()función en este conjunto de pruebas unitarias es bastante diferente:

beforeEach(() => {
  // Set the mock call to GET to return a failed GET request
  axios.get.mockRejectedValue(new Error('BAD REQUEST'))

  // Render the component
  wrapper = shallowMount(App)
})

En lugar de configurar una respuesta para regresar de la axios.get()llamada, ahora devolvemos un objeto fallido Promisecon la respuesta 'MALA SOLICITUD'.

La afterEach()función de este conjunto de pruebas unitarias es idéntica a la del otro conjunto de pruebas unitarias:

afterEach(() => {
  axios.get.mockReset()
  wrapper.unmount()
})

espera

Aquí está la función de prueba unitaria para probar una solicitud HTTP GET fallida:

it('does not load the weather data when a failed HTTP GET occurs', async () => {
  wrapper.vm.searchCity('Chicago')

  expect(axios.get).toHaveBeenCalledTimes(1)
  expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

  // Wait until the DOM updates
  await flushPromises()

  // Check that there is no user data loaded when the GET request fails
  expect(wrapper.vm.weatherData.city).toMatch(/^$/)
  expect(wrapper.vm.weatherData.weatherSummary).toMatch(/^$/)
  expect(wrapper.vm.weatherData.weatherDescription).toMatch(/^$/)
  expect(wrapper.vm.weatherData.currentTemperature).toEqual(0)
  expect(wrapper.vm.weatherData.lowTemperature).toEqual(0)
  expect(wrapper.vm.weatherData.highTemperature).toEqual(0)
  expect(wrapper.vm.validWeatherData).toBe(false)

  // check that the banner message indicates failure
  expect(wrapper.vm.messageToDisplay).toMatch('ERROR! Unable to retrieve weather data for Chicago!')
  expect(wrapper.vm.messageType).toMatch('Error')
})

Al igual que en el conjunto de pruebas unitarias anterior, verificamos que solo axios.get()se llame a una instancia de y luego verificamos que no se hayan cargado datos meteorológicos en el Appcomponente.

Cobertura de código

Al desarrollar pruebas unitarias, puede ser bueno comprender cuánto del código fuente se prueba realmente. Este concepto se conoce como cobertura de código.

Debo dejar muy claro que tener un conjunto de pruebas unitarias que cubran el 100% del código fuente no es de ninguna manera un indicador de que el código se haya probado correctamente.

Esta métrica significa que hay muchas pruebas unitarias y se ha puesto mucho esfuerzo en desarrollar las pruebas unitarias. La calidad de las pruebas unitarias aún debe verificarse mediante la inspección del código.

El otro extremo donde se trata de un conjunto mínimo (¡o ninguno!) de pruebas unitarias es un indicador muy malo.

Vitest proporciona cobertura de código mediante el uso de la --coveragebandera.

Para ejecutar fácilmente Vitest con resultados de cobertura, me gusta incluir los siguientes elementos en la scriptsección de package.json :

{
  "name": "vue-weather-app",
  "version": "1.0.0",
  "scripts": {
    ...
    "test:unit": "vitest run --environment jsdom",
    "test:coverage": "vitest run --environment jsdom --coverage",
    "test:ui": "vitest --environment jsdom --coverage --ui"
  },
  ...
}

Cuando npm run test:unitse ejecuta, se ejecutan las pruebas unitarias:

$ npm run test:unit
...
 ✓ src/components/__tests__/WeatherBanner.spec.js (5)
 ✓ src/components/__tests__/WeatherSearch.spec.js (5)
 ✓ src/components/__tests__/WeatherFooter.spec.js (1)
 ✓ src/components/__tests__/WeatherHeader.spec.js (1)
 ✓ src/components/__tests__/WeatherResult.spec.js (3)
 ✓ src/components/__tests__/App.spec.js (7)

Test Files  6 passed (6)
     Tests  22 passed (22)
      Time  2.81s (in thread 536ms, 524.89%)

Cuando npm run test:coveragese ejecuta, se ejecutan las pruebas unitarias y se reporta la cobertura:

$ npm run test:coverage
...
Test Files  6 passed (6)
     Tests  22 passed (22)
      Time  3.38s (in thread 660ms, 512.10%)

--------------------|---------|----------|---------|---------|-------------------
File                | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files           |   99.15 |    96.55 |     100 |   99.15 |
 src                |   97.31 |    85.71 |     100 |   97.31 |
  App.vue           |   97.31 |    85.71 |     100 |   97.31 | 60-63
 src/components     |     100 |      100 |     100 |     100 |
  WeatherBanner.vue |     100 |      100 |     100 |     100 |
  WeatherFooter.vue |     100 |      100 |     100 |     100 |
  WeatherHeader.vue |     100 |      100 |     100 |     100 |
  WeatherResult.vue |     100 |      100 |     100 |     100 |
  WeatherSearch.vue |     100 |      100 |     100 |     100 |
--------------------|---------|----------|---------|---------|-------------------

Cargará los npm run test:uiresultados de la prueba y la cobertura en su navegador web predeterminado, lo que puede ser conveniente para ver dónde falta la cobertura de la prueba.

Estructura de prueba unitaria

Después de pasar por muchos archivos de prueba de unidad diferentes, recomiendo la siguiente estructura para el archivo de prueba de unidad para un componente de Vue:

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import App from '@/App.vue'  // Import Vue component to test
import axios from 'axios'    // Import libraries to mock

// Mock the axios library
vi.mock("axios", () => {
  return {
    default: {
      get: vi.fn(),
    },
  };
});


describe('Tests for the ... Component', () => {
  let wrapper = null

  beforeEach(() => {
    // set any initial data and create the mocks of libraries

    // render the component
    wrapper = shallowMount(App)
  })

  afterEach(() => {
    axios.get.mockReset()
    wrapper.unmount()
  })

  it('check successful events', () => { ... })

  it('check failure events', () => { ... })
})

Elementos clave:

  • Cada conjunto de pruebas unitarias tiene un conjunto relacionado de pruebas unitarias
  • Utilice las funciones beforeEach()y afterEach()para crear funciones de prueba unitaria independientes
  • Cree simulacros de cualquier biblioteca utilizada dentro del componente Vue que se prueba
  • Representar los componentes en la beforeEach()función y actualizar los datos de utilería dentro de las funciones de prueba unitaria
  • Utilícelo shallowMount()para mount()centrarse en probar componentes individuales

Conclusión

Este artículo proporciona una guía para las pruebas unitarias de los componentes de Vue, centrándose en:

  1. Por qué deberías escribir pruebas unitarias
  2. Lo que debe (y no debe) probar la unidad
  3. Cómo escribir pruebas unitarias

En pocas palabras, al considerar qué probar, concéntrese en probar las entradas y salidas (resultados reales), no la lógica empresarial subyacente (cómo se producen los resultados). Con esto en mente, tómese uno o dos minutos para revisar los ejemplos nuevamente, tomando nota de las entradas y salidas probadas.

Fuente:  https://testdriven.io

#vue 

Luna  Mosciski

Luna Mosciski

1600583123

8 Popular Websites That Use The Vue.JS Framework

In this article, we are going to list out the most popular websites using Vue JS as their frontend framework.

Vue JS is one of those elite progressive JavaScript frameworks that has huge demand in the web development industry. Many popular websites are developed using Vue in their frontend development because of its imperative features.

This framework was created by Evan You and still it is maintained by his private team members. Vue is of course an open-source framework which is based on MVVM concept (Model-view view-Model) and used extensively in building sublime user-interfaces and also considered a prime choice for developing single-page heavy applications.

Released in February 2014, Vue JS has gained 64,828 stars on Github, making it very popular in recent times.

Evan used Angular JS on many operations while working for Google and integrated many features in Vue to cover the flaws of Angular.

“I figured, what if I could just extract the part that I really liked about Angular and build something really lightweight." - Evan You

#vuejs #vue #vue-with-laravel #vue-top-story #vue-3 #build-vue-frontend #vue-in-laravel #vue.js

Teresa  Bosco

Teresa Bosco

1598685221

Vue File Upload Using vue-dropzone Tutorial

In this tutorial, I will show you how to upload a file in Vue using vue-dropzone library. For this example, I am using Vue.js 3.0. First, we will install the Vue.js using Vue CLI, and then we install the vue-dropzone library. Then configure it, and we are ready to accept the file. DropzoneJS is an open source library that provides drag and drops file uploads with image previews. DropzoneJS is lightweight doesn’t depend on any other library (like jQuery) and is  highly customizable. The  vue-dropzone is a vue component implemented on top of Dropzone.js. Let us start Vue File Upload Using vue-dropzone Tutorial.

Dropzone.js is an open-source library providing drag-and-drop file uploads with image previews. DropzoneJS is lightweight, doesn’t depend on any other library (like jQuery), and is highly customizable.

The vue-dropzone is a vue component implemented on top of Dropzone.js.

First, install the Vue using Vue CLI.

Step 1: Install Vue.js using Vue CLI.

Go to your terminal and hit the following command.

npm install -g @vue/cli
         or
yarn global add @vue/cli

If you face any error, try running the command as an administrator.

Now, we need to generate the necessary scaffold. So type the following command.

vue create vuedropzone

It will install the scaffold.

Open the project in your favorite editor. Mine is Visual Studio Code.

cd vuedropzone
code .

Step 2: Install vue-dropzone.

I am using the Yarn package manager. So let’s install using Yarn. You can use NPM, also. It does not matter.

yarn add vue2-dropzone

or

npm install vue2-dropzone

Okay, now we need to add one css file with the above package. Now, vue cli uses css loader, so we can directly import in the src >>  main.js entry file.

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App)
}).$mount('#app')

import 'vue2-dropzone/dist/vue2Dropzone.css'

If importing css is not working for you, then you need to install that CSS file manually.

Copy this vue2Dropzone.css file’s content.

Create one file inside the src  >>  assets folder, create one css file called vuedropzone.css and paste the content there.

Import this css file inside src  >>  App.vue file.

<style lang="css">
  @import './assets/vuedropzone.css';
</style>

Now, it should include in our application.

Step 3: Upload an Image.

Our primary boilerplate has one ready-made component called HelloWorld.vue inside src  >>  components folder. Now, create one more file called FileUpload.vue.

Add the following code to FileUpload.vue file.

// FileUpload.vue

<template>
  <div id="app">
    <vue-dropzone id="upload" :options="config"></vue-dropzone>
  </div>
</template>

<script>
import vueDropzone from "vue2-dropzone";

export default {
  data: () => ({
    config: {
      url: "https://appdividend.com"
    }
  }),
  components: {
    vueDropzone
  }
};
</script>

Here, our API endpoint is https://appdividend.com. It is the point where we will hit the POST route and store our image, but it is my blog’s homepage, so it will not work anyway. But let me import this file into App.vue component and see what happens.

// App.vue

<template>
  <div id="app">
    <FileUpload />
  </div>
</template>

<script>
import FileUpload from './components/FileUpload.vue'

export default {
  name: 'app',
  components: {
    FileUpload
  }
}
</script>

<style lang="css">
  @import './assets/vuedropzone.css';
</style>

Now, start the development server using the following command. It will open up URL: http://localhost:8080.

npm run serve

Now, after uploading the image, we can see that the image upload is failed due to the wrong POST request endpoint.

Step 4: Create Laravel API for the endpoint.

Install the Laravel.

After that, we configure the database in the .env file and use MySQL database.

We need to create one model and migration file to store the image. So let us install the following command inside the Laravel project.

php artisan make:model Image -m

It will create both the Image model and create_images_table.php migrations file.

Now, open the migrations file and add the schema to it.

// create_images_table.php

public function up()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->increments('id');
            $table->string('image_name');
            $table->timestamps();
        });
    }

Now, migrate the database table using the following command.

php artisan migrate

It creates the table in the database.

Now, we need to add a laravel-cors package to prevent cross-site-allow-origin errors. Go to the Laravel root and enter the following command to install it.

composer require barryvdh/laravel-cors

Configure it in the config  >>  app.php file.

Barryvdh\Cors\ServiceProvider::class,

Add the middleware inside app >>  Http  >>  Kernel.php file.

// Kernel.php

protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
        \Barryvdh\Cors\HandleCors::class,
];

Step 5: Define the API route and method to store the image.

First, create an ImageController.php file using the following command.

php artisan make:controller ImageController

Define the store method. Also, create one images folder inside the public directory because we will store an image inside it.

Right now, I have written the store function that handles one image at a time. So do not upload multiple photos at a time; otherwise, it will break.

// ImageController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Image;

class ImageController extends Controller
{
    public function store(Request $request)
    {
       if($request->file('file'))
       {
          $image = $request->file('file');
          $name = time().$image->getClientOriginalName();
          $image->move(public_path().'/images/', $name); 
        }

       $image= new Image();
       $image->image_name = $name;
       $image->save();

       return response()->json(['success' => 'You have successfully uploaded an image'], 200);
     }
}

Go to the routes   >>  api.php file and add the following route.

// api.php

Route::post('image', 'ImageController@store');

Step 6: Edit FileUpload.vue component.

We need to add the correct Post request API endpoint in FileUpload.vue component.

// FileUpload.vue

<template>
  <div id="app">
    <vue-dropzone id="drop1" :options="config" @vdropzone-complete="afterComplete"></vue-dropzone>
  </div>
</template>

<script>
import vueDropzone from "vue2-dropzone";

export default {
  data: () => ({
    config: {
      url: "http://localhost:8000/api/image",
      
    }
  }),
  components: {
    vueDropzone
  },
  methods: {
    afterComplete(file) {
      console.log(file);
    }
  }
};
</script>

Now, save the file and try to upload an image. If everything is okay, then you will be able to save the image on the Laravel web server as well as save the name in the database as well.

You can also verify on the server side by checking the database entry and the images folder in which we have saved the image.

Step 7: More vue-dropzone configuration.

The only required options are url, but there are many more you can use.

For example, let’s say you want:

  • A maximum of 4 files
  • 2 MB max file size
  • Sent in chunks of 500 bytes
  • Set a custom thumbnail size of 150px
  • Make the uploaded items cancelable and removable (by default, they’re not)
export default {
  data: () => ({
    dropOptions: {
      url: "https://httpbin.org/post",
      maxFilesize: 5, // MB
      maxFiles: 5,
      chunking: true,
      chunkSize: 400, // Bytes
      thumbnailWidth: 100, // px
      thumbnailHeight: 100,
      addRemoveLinks: true
    }
  })
  // ...
}

Happy Coding !!!

Originally published at https://appdividend.com 

#vue #vue-dropzone #vue.js #dropzone.js #dropzonejs #vue cli

Como exportar banco de dados de EML para o formato PST?

O usuário agora pode converter seus arquivos EML para o formato PST apenas instalando este conversor em seu PC. O conversor EML para PST converte seus dados com total precisão, sem prejudicar os dados a qualquer custo. O aplicativo é confiável e fácil de usar.

A conversão de alta velocidade e a taxa de precisão de 100% proporcionam uma economia de tempo aos usuários. Além disso, uma versão demo também está disponível para todos os usuários verem o funcionamento do software.

Por que usar o conversor EML para PST

Converter o arquivo EML para o formato PST vai demorar muito se for feito manualmente, mas pode ser feito em alta velocidade usando o conversor EML para PST. Portanto, antes de qualquer conhecimento adicional, vamos primeiro saber sobre o conversor de EML para PST.

  • O aplicativo é executado sem problemas em todos os sistemas operacionais Windows.
  • O aplicativo pode converter os arquivos em massa.
  • Os dados podem ser salvos automaticamente pelo conversor.
  • A conversão é feita em alta velocidade.
  • O resultado obtido após a conversão é 100% preciso.
  • Para utilizar o aplicativo o usuário não necessita de suporte técnico ou assistência.
  • Os usuários podem salvar o arquivo em qualquer local de sua escolha.
  • Uma versão demo gratuita está disponível para verificar as pastas.

Um atributo chave do conversor EML para PST

O conversor de EML para PST possui muitos dos recursos que o tornam um conversor único e confiável. Portanto, a seguir estão alguns dos recursos deste conversor inteligente:

1. Fornece apenas conversão específica
O aplicativo converte apenas arquivos EML específicos para o formato PST, o que é saudável. O conversor é compatível com todas as versões do Windows.

2. Suporta conversão em massa
Este aplicativo inteligente pode converter arquivos EML em formato PST em massa. Todos os arquivos convertidos são salvos em uma pasta PST e formam um arquivo forte do Outlook.

3. Conversão de dados saudáveis
O aplicativo converte apenas os arquivos que não estão corrompidos. Portanto, o resultado é 100% preciso com perda zero de dados. Portanto, o resultado atende às expectativas do usuário.

4. Salvamento automático de dados
Os usuários podem salvar os dados em qualquer local ou usar a opção padrão. Portanto, o usuário pode salvar automaticamente seus dados convertidos. Portanto, o usuário acha fácil salvar os dados.

5. Mantém os dados na ordem hierárquica
O aplicativo mantém os dados na ordem hierárquica e a originalidade dos dados também é mantida durante todo o processo de conversão.

Palavras Finais

Os usuários agora podem converter os arquivos EML em PST usando este conversor. O aplicativo está pronto para funcionar em várias versões do Windows sem nenhum obstáculo. Os usuários podem usar a versão demo gratuita antes de usar o aplicativo.

Mais informações:- https://www.datavare.com/pt/conversor-eml-para-pst.html

#conversor eml para pst #eml para pst exportador #eml para pst importador #importar eml para pst #converter eml para pst #exportar eml para pst

joe biden

1616476521

Conversor OLM para PST para converter ou exportar Mac OLM para Outlook PST

O usuário agora pode converter seus arquivos OLM para o formato do Outlook sem instalar o MS Outlook facilmente, instalando o OLM para PST Converter. O conversor é capaz de converter seus arquivos OLM, incluindo e-mails, notas, contatos e muitos outros arquivos em uma velocidade rápida e sem erros. O aplicativo fornece uma conversão perfeita. Além disso, ele gera uma visualização enquanto você seleciona os arquivos OLM para conversão, isso é feito para você verificar se os arquivos selecionados estão íntegros e não corrompidos. Além disso, você pode converter quantos arquivos desejar.

Será mais fácil para cada usuário converter seus arquivos OLM para o formato Outlook, pois o aplicativo oferece a seus usuários a conversão de quantos arquivos OLM desejarem, sem qualquer obrigação. Nenhuma perda de dados é feita por este aplicativo. Além disso, você pode usar este aplicativo notável em qualquer versão do seu aplicativo Windows. Não há restrição quanto ao tamanho ou número de arquivos a serem escolhidos para a tarefa de conversão. Você tem permissão para converter vários arquivos OLM de uma só vez com este aplicativo incrível.

Quais são as etapas para converter arquivos OLM para o formato PST?

Existem alguns passos a serem seguidos por cada usuário para a conversão perfeita de seus arquivos OLM para o formato PST do Outlook. Abaixo estão as etapas para converter seus arquivos OLM para o formato do Outlook. Siga esses passos:

Etapa 1- Baixe o aplicativo em seu aplicativo do Windows.
Etapa 2 - Agora, inicie o aplicativo.
Etapa 3- Selecione os arquivos OLM que você precisa converter.
Etapa 4 - Visualize os arquivos OLM selecionados.
Etapa 5 - Escolha o destino onde deseja salvar seus arquivos OLM convertidos.
Etapa 6 - Clique no botão “Converter agora”.

Assim que você clicar no botão “converter agora”, o conversor converterá seus arquivos OLM para o formato Outlook.

Além disso, o aplicativo também fornece um instantâneo dessas etapas para que nenhum usuário encontre qualquer tipo de obstáculo ao converter seus arquivos OLM.

Recursos do aplicativo que vão te impressionar!

O aplicativo é muito favorável e, portanto, fornece muitos recursos para os usuários realizarem a tarefa de conversão. Abaixo estão os recursos da ferramenta Conversor OLM para PST:

Converter todos os dados
O aplicativo é versátil e, portanto, é capaz de converter todos os seus arquivos OLM. Porém, os arquivos corrompidos ou que apresentam qualquer outro tipo de problema não são convertidos. Isso é feito para fornecer a você um resultado de conversão saudável de seus arquivos OLM.

Conversão sem erros
Não importa quantos arquivos você escolheu para conversão ou qual é o tamanho do arquivo OLM, o conversor irá converter todos os seus arquivos OLM de uma maneira perfeita. Além disso, não compromete com o tempo, o que significa que mesmo vários arquivos são mantidos para conversão, o resultado convertido será fornecido a você o mais rápido possível em apenas alguns minutos.

Visualização selecionada
Os arquivos que você selecionou são os únicos que são visualizados pelo aplicativo. A visualização dos arquivos é concedida aos usuários para que possam verificar se os arquivos selecionados estão corrompidos ou não.

Grande compatibilidade
Este aplicativo avançado tem grande compatibilidade, o aplicativo é compatível com qualquer sistema operacional Mac e Windows. Os arquivos OLM de qualquer versão do Mac são suportados pelo aplicativo.

Fácil de lidar
O aplicativo fornece uma GUI inteligente e uma interface de usuário amigável, portanto, o aplicativo é fácil de manusear. O usuário sem nenhuma habilidade proficiente também pode usar o aplicativo e converter seus arquivos OLM para o formato PST do Outlook.

Verificação dos arquivos
Os arquivos selecionados e os arquivos OLM convertidos são verificados corretamente para detectar se há algum tipo de dano causado.

Declaração final

O Datavare Conversor OLM para PST é uma maneira inteligente de converter todos os seus arquivos OLM para o formato PST do Outlook, pois o aplicativo não apenas converte seus arquivos, mas também detecta se há algum tipo de arquivo corrompido. Além disso, o aplicativo é altamente compatível e aceita arquivos OLM de qualquer versão do Mac, podendo ser utilizado em qualquer uma das versões do Windows.

Os usuários podem usar a versão demo disponível antes de comprar a versão licenciada deste aplicativo.

Mais informações:- https://www.datavare.com/software/olm-to-pst-converter.html

#olm para pst exportador #exportador olm para pst #importar olm para pst #converter olm para pst #importador olm para pst #conversor olm para pst