Video Summary and Transcription
Hola, estoy agradecido de que hayas elegido ver mi masterclass. Gracias. La semana pasada, tuve que ejecutar algunas pruebas unitarias mientras codificaba. El rendimiento empresarial puede ser impresionante. Tiene características muy interesantes y destacadas. Estos conjuntos de pruebas son excesivamente complejos. Es fácil encontrarse solucionando problemas durante horas. VTest tiene casi 200 opciones de configuración. Al explicar cómo funcionan las cosas, podemos responder preguntas sobre el uso de runners de terceros complejos frente al runner incorporado de node.js. Entender mejor ayuda a evitar obstáculos, solucionar problemas más rápido e identificar oportunidades para configurar las cosas mejor. La capa CLI realiza la validación y entrega a la clase VTest. Busca archivos de prueba, los ejecuta de manera eficiente utilizando un grupo de trabajadores y asegura la aislamiento para prevenir problemas con el estado sucio. VTest utiliza la biblioteca piscina para facilitar el trabajo con múltiples trabajadores y mejorar el rendimiento. Los trabajadores se preparan configurando los globals correctos, inicializando snapshots, decidiendo el archivo del runner de pruebas y comenzando la recolección de cobertura. Cada trabajador ejecuta todas las pruebas en un archivo y envía un mensaje RPC cuando ha terminado. La decisión de reutilizar o crear un nuevo trabajador se determina por la opción de configuración de aislamiento. Considera distribuir las pruebas entre más archivos para utilizar completamente la máquina. Elige entre proceso, hilo o VM como tipo de trabajador. En términos de aislamiento, puedes elegir entre usar un proceso, un hilo o una VM. El proceso es el más pesado en términos de costo de rendimiento, mientras que el hilo es más ligero. El rendimiento de la VM depende de aspectos más lentos conocidos como el acceso a globals. El proceso es la opción clásica para la estabilidad, pero el hilo tiene limitaciones y problemas conocidos. La VM tiene problemas de informes con fugas de memoria. Los resultados de las pruebas de referencia mostraron que usar múltiples procesos fue un 50% mejor para aplicaciones del mundo real, pero para pruebas unitarias, un proceso fue diez veces más rápido. El hilo fue ligeramente más rápido que el proceso, y la VM fue más lenta. El precio del aislamiento con tipos de trabajadores de proceso fue de aproximadamente tres minutos. Sin aislamiento, las pruebas duraron solo dos minutos, mucho más rápido, pero con algunas fallas. Los hilos mostraron resultados similares con algunas fallas. El riesgo de lidiar con problemas de pruebas aumenta sin aislamiento. Por defecto, las pruebas se ejecutan secuencialmente dentro de los trabajadores, pero puedes configurarlas para que se ejecuten en paralelo usando la palabra clave 'concurrent'. Sin embargo, las pruebas aún se ejecutan secuencialmente a pesar de especificar 'concurrent'. La concurrencia en VTest se basa en promesas y requiere trabajo asíncrono. Las pruebas unitarias se ejecutan secuencialmente y la concurrencia no tiene aislamiento. El mocking en una prueba afecta a otras pruebas que se ejecutan simultáneamente. Al elegir configuraciones de trabajadores, depende del contexto. La concurrencia en el archivo es mejor evitarla, y se recomienda el tipo de trabajador de proceso como predeterminado. El aislamiento es crucial en pruebas de integración pero no es obligatorio en pruebas unitarias. Dentro del trabajador, se maneja un archivo TypeScript, y pueden ocurrir fallas al hacer mocking de funciones. El mocking no funciona en el trabajador. El trabajador maneja archivos TypeScript y los transpila usando el servidor Vite. El servidor Vite reemplaza las importaciones y eleva el mocking. Vite introduce un nuevo cargador de módulos en el tiempo de ejecución. Vite elevó el mock a la primera línea en el código de transformación para hacerlo antes de la importación. Además, Vite cambia los mocks a importaciones dinámicas, asegurando que el mocking funcione. Vite intercepta llamadas a funciones a nivel de importación de archivo, pero no puede interceptar llamadas entre funciones en el mismo archivo. Mover la función dos a un archivo diferente o usar una exportación de objeto puede resolver este problema. La función uno llama a la función dos en el mismo contexto de objeto. Usa Spy para reemplazar funciones dentro del objeto. Vite ofrece una gama de plugins para diferentes funcionalidades. Puedes solucionar problemas de importación personalizando el tiempo de ejecución de Vite. El servidor Vite maneja la resolución de dependencias y la transformación. Considera usar el runner de pruebas incorporado o mockup para pruebas a pequeña escala. Obtén una mejor experiencia de pruebas con el tiempo de ejecución personalizado de Vite.
1. Introducción a VTest
Hola, estoy agradecido de que hayas elegido ver mi charla. Gracias. La semana pasada, tuve que ejecutar algunas pruebas unitarias mientras codificaba. El rendimiento empresarial puede ser increíble. Tiene características muy interesantes y sobresalientes. Estos conjuntos de pruebas son excesivamente complejos.
Hola, estoy agradecido de que hayas elegido ver mi charla. Gracias.
La semana pasada, tuve que ejecutar algunas pruebas unitarias mientras codificaba. Y cada vez que cambiaba algo en el código, la prueba se ejecutaba en la segunda pantalla. Tenía 200 pruebas, y se ejecutaban en 170 milisegundos. Wow. Eso fue tan increíblemente rápido. Como, podría parpadear y perderme la ejecución. El rendimiento empresarial puede ser increíble.
Ahora, no se trata solo de rendimiento. También tiene características muy interesantes y sobresalientes. Como, ¿sabías que puedes escribir una prueba con la misma sintaxis pero solo recibir alertas cuando tienes una regresión de rendimiento? Otro ejemplo, puedes ejecutar pruebas que harán verificación de tipos en tiempo de compilación y muchas otras características inusuales, hermosas, útiles. Pero todas estas maravillas tienen un precio. Estos conjuntos de pruebas son excesivamente complejos. Es muy fácil encontrarte solucionando problemas durante horas, por ejemplo, ¿por qué funcionó este walking? Y también tomar la decisión arquitectónica incorrecta debido a un conocimiento ineficiente sobre lo que está sucediendo allí dentro. Para darte un ejemplo, VTest tiene casi 200 configuraciones opciones. Puedes pasar días leyendo y tratando de entender todas tus opciones para comparar los runners de prueba integrados de node.js como solo 19.
2. Explorando la Ejecución de VTest
Al explicar cómo funcionan las cosas, podemos responder preguntas sobre el uso de runners de terceros complejos frente al runner integrado de node.js. Entender mejor ayuda a evitar trampas, solucionar problemas más rápido e identificar oportunidades para configurar las cosas mejor. Nuestro viaje con VTest comienza cuando alguien escribe el comando para ejecutar pruebas. La capa CLI realiza la validación y pasa a la clase VTest. Busca archivos de prueba, los ejecuta de manera eficiente utilizando un grupo de trabajadores y asegura la aislamiento para prevenir problemas con el estado sucio.
Esta es mi esperanza hoy. Al explicar a ustedes cómo funcionan las cosas, podemos responder preguntas como si deberías usar estos runners de terceros complejos o usar uno más simple como el runner integrado de node.js. Y también al entender mejor, espero que puedas evitar trampas comunes, solucionar problemas más rápido, y también identificar oportunidades para configurar las cosas mejor y obtener más características de ello.
¿Listo para sumergirte en este agujero de conejo conmigo? Genial. Justo antes de eso, soy Emily Goldberg. Soy consultora de backend y pruebas. Trabajo con más de 50 empresas en todo el mundo, grandes nombres y startups en un garaje escribiendo pruebas simples de frontend y backend. Intento resumir todo el conocimiento y las prácticas que aprendí en mi repositorio de GitHub que en total fue visitado por más de 135,000 personas. Si quieres aprender más sobre cómo probar cosas avanzadas de backend modernas, entonces sé mi invitado en testjavascript.com.
Así que nuestro viaje comienza cuando alguien escribe VTest. El comando VTest para comenzar a ejecutar pruebas proporciona este patrón de globos para encontrar todos los archivos que comienzan con este prefijo. Y lo primero que sucede es que la capa CLI de VTest es activada, realiza principalmente una validación simple. Y luego se pasa a la gran clase VTest. Esta es una especie de clase Dios que tiene la referencia a la medida de los servicios. Y está orquestando este flujo. Para empezar, hará todo tipo de cosas casuales como instalar dependencias alrededor de la configuración global. Luego llamará a una clase de globos que buscará todos los archivos de prueba que coincidan con este patrón. Y el resultado de esto es, obviamente, una lista de archivos de TypeScript para ejecutar.
Ahora, VTest necesita ejecutar todos estos archivos. Naivamente, puede ejecutarlos todos uno por uno secuencialmente. Pero si cada uno toma un segundo, en total durará tres segundos. Y esto es un desperdicio en una máquina de múltiples núcleos. Otros problemas a tener en cuenta son la aislamiento. Cada archivo de prueba podría dejar rastros si todos se ejecutan en el mismo entorno de Node.js. Y por rastros, me refiero a cosas como cambiar variables de entorno, burlas, la caché de módulos, grupos de conexiones, y más. Luego, cuando se ejecute la siguiente prueba, podría enfrentar todos estos, todo este estado sucio y enfrentar problemas.
Así que VTest quiere hacerlo mejor. Y la forma en que funciona es tomando estos archivos y utilizando un grupo de trabajadores. Bajo el capó, utiliza una biblioteca llamada piscina, una futura que fue creada por Matteo Colina y James Nell. Y piscina facilita el trabajo con múltiples trabajadores. Te permite elegir si es un proceso o un hilo, y también permite reutilizar trabajadores existentes para un mejor rendimiento.
3. Preparando Trabajadores y Tomando Decisiones
Los trabajadores se preparan configurando los globals correctos, inicializando snapshots, decidiendo el archivo del runner de pruebas y comenzando la recolección de cobertura. Cada trabajador ejecuta todas las pruebas en un archivo y envía un mensaje RPC cuando ha terminado. La decisión de reutilizar o crear un nuevo trabajador se determina por la opción de configuración de aislamiento. Considera distribuir las pruebas entre más archivos para utilizar completamente la máquina. Elige entre proceso, hilo o VM como tipo de trabajador.
Una vez que los trabajadores están listos, antes de ejecutar las pruebas, necesitan prepararse. Esta es la fase de preparación, que incluye cosas como que puedes elegir el entorno de pruebas. Puede ser front-end, back-end. Así que VTest necesita establecer los globals correctos y luego inicializar los snapshots, todos los datos de snapshot, decidir sobre el archivo del runner de pruebas, comenzar la recolección de cobertura, y más. Luego estamos listos.
El grupo toma el primer archivo y lo envía al trabajador número uno. El segundo al trabajador número dos. Obviamente, en tiempo real, tendremos más trabajadores que dos, pero intentaré simplificarlo aquí. Cada trabajador ahora ejecuta todas las pruebas en el archivo. Profundizaremos en esta sección pronto, y luego han terminado. Envían de vuelta un mensaje RPC. Hemos terminado. Ahora necesitamos procesar el tercer archivo, el archivo número tres.
Así que aquí tenemos una decisión que tomar. ¿Deberíamos reutilizar este trabajador o crear uno nuevo? Esto se determina por la opción de configuración. En VTest, se llama aislamiento. Si eliges verdadero para aislar, entonces lo que hará el grupo es crear el trabajador número tres, uno nuevo, que manejará el siguiente archivo, el archivo número tres. Alternativamente, si especificas aislamiento falso, reutilizará el trabajador número uno. Saltará el tiempo que lleva instanciar un nuevo trabajador y simplemente lo reutilizará. Hay una cosa que podemos aprender de este modelo. Si tienes un número muy reducido de archivos de prueba, como dos o tres, es bastante común en microservicios, y tienes un brillante nuevo M4 Apple Silicon, entonces es como conducir un Ferrari en un carril con mucho tráfico. Estás utilizando una porción muy, muy pequeña de tu máquina. En otras palabras, el número de archivos es el límite superior de paralelización que VTest y Jest pueden hacer por ti. Así que es algo a considerar y distribuir tus pruebas entre más archivos. La siguiente decisión a tomar es ¿qué tipo de trabajador necesitas? ¿Proceso, un hilo, o una VM?
Ahora, sabes qué son un proceso y un hilo, pero ¿qué es una VM? Cada vez que usas el navegador Chrome, con el motor V8, por supuesto, y estás usando nuevas pestañas, cada pestaña obtiene su propio entorno de sandbox para separar la memoria y el almacenamiento. Esta característica se llama contexto V8. Node.js envuelve esto en un modelo que se llama VM que te permite ejecutar un archivo JavaScript en un entorno completamente aislado y en sandbox. Lo que VTest y Jest permiten es ejecutar cada archivo de prueba en el mismo entorno V8, sin necesidad de crear un nuevo trabajador, pero en un contexto diferente. Bueno, de esta manera logramos un aislamiento completo. Eventualmente, tenemos tres opciones para elegir de.
4. Choosing the Right Worker Type
En términos de aislamiento, puedes elegir entre usar un proceso, un hilo o una VM. El proceso es el más pesado en términos de costo de rendimiento, mientras que el hilo es más ligero. El rendimiento de la VM depende de aspectos más lentos conocidos, como el acceso a globals. El proceso es la opción clásica por estabilidad, pero el hilo tiene limitaciones y problemas conocidos. La VM tiene problemas de informes con fugas de memoria. Los resultados de las pruebas de referencia mostraron que usar múltiples procesos era un 50% mejor para aplicaciones del mundo real, pero para pruebas unitarias, un proceso era diez veces más rápido. El hilo fue ligeramente más rápido que el proceso, y la VM fue más lenta. El costo de aislamiento con tipos de trabajadores de proceso fue de aproximadamente tres minutos.
Tomemos una decisión reflexiva. ¿Deberías usar un proceso, un hilo o una VM? En términos de aislamiento, al usar un proceso, si deseas aislar tu archivo de prueba, tienes que crear un nuevo proceso cada vez. Lo mismo ocurre con el hilo, pero con la VM, no tienes que hacerlo. Puedes reutilizar el mismo trabajador, pero solo crear un nuevo contexto V8. En términos de rendimiento, el costo de rendimiento. El proceso es el más pesado. Esperarás, pagarás mucho más por instanciar uno nuevo todo el tiempo. El hilo es un poco más ligero. En la VM, depende. Depende de cosas que se sabe que son más lentas al usar la VM, como acceder a globals. ¿Qué pasa con la estabilidad? ¿Qué tan segura es esta opción? Bueno, el proceso es la opción clásica para todos porque así es como funciona tu código de producción. Tienes un nuevo proceso fresco que sostiene tu framework. Sin embargo, el hilo tiene más limitaciones que problemas conocidos. Solo un ejemplo, hay errores conocidos en nuestra industria, como Prisma y Bcrypt, que se asume que dejan uno en un proceso. Pero una vez que estás ejecutando múltiples hilos, hay problemas y limitaciones conocidos relacionados con esto. Además, la VM tiene muchos problemas de informes sobre fugas de memoria. Busca los problemas de Jest, y encontrarás al menos docenas de problemas abiertos sobre fugas de memoria al usar la VM. Así que, eventualmente, el rendimiento es un gran factor en esta decisión, y no puedes tomar una decisión reflexiva sin algunas pruebas de referencia. Así que, creé algunas para ti. Usando una aplicación del mundo real, intencionalmente usando NestJS, que es un framework más pesado, 400 archivos de código, 300 pruebas de integración con base de datos. Y estos fueron mis hallazgos. La primera pregunta fue sobre, ¿el paralelismo realmente aporta algún valor? La primera pregunta que intenté responder fue, ¿la paralelización aporta algún valor? No fue fácil, por cierto, porque cuando lo ejecuté con una aplicación Playground, no vi ningún beneficio notable al ejecutar cosas en paralelo. Pero cuando ejecuté esto con sistemas del mundo real, lo que noté es que ejecutar con múltiples procesos era como un 50% mejor, lo cual tiene sentido, dado que tienes todas estas partes móviles. Sin embargo, con pruebas unitarias, lo que observé es que un proceso era diez veces más rápido que múltiples, porque obviamente el tiempo que lleva obtener, instanciar un nuevo trabajador es por sí mismo más largo que ejecutar todas las pruebas. La siguiente prueba de referencia es sobre qué tipo de trabajador es más rápido. Así que, cuando ejecuté un proceso, 300 pruebas con el sitio de proceso, duró aproximadamente tres minutos. El hilo fue solo diez segundos más rápido, y la VM fue en realidad más lenta. Y esto está documentado en muchos lugares que ciertas cosas en la VM son en realidad más lentas, mientras que se pretendía que fueran más rápidas. La siguiente prueba de referencia es sobre el costo de aislamiento. ¿Cuánto te costaría más aislar entre sitios de prueba? Así que, con tipos de trabajadores de proceso, y con aislamiento, duró alrededor de tres minutos.
5. Understanding Test Isolation and Concurrency
Sin aislamiento, las pruebas duraron solo dos minutos, mucho más rápido, pero con algunos fallos. Los hilos mostraron resultados similares con algunos fallos. El riesgo de lidiar con problemas de pruebas aumenta sin aislamiento. Por defecto, las pruebas se ejecutan secuencialmente dentro de los trabajadores, pero puedes configurarlas para que se ejecuten en paralelo usando la palabra clave 'concurrent'. Sin embargo, las pruebas aún se ejecutan secuencialmente a pesar de especificar 'concurrent'. La concurrencia en VTest se basa en promesas y requiere trabajo asíncrono. Las pruebas unitarias se ejecutan secuencialmente y la concurrencia no tiene aislamiento. El mocking en una prueba afecta a otras pruebas que se ejecutan simultáneamente.
Sin aislamiento, sin embargo, duró solo dos minutos, mucho más rápido. Pero hubo algunos fallos. Con hilos, los mismos números, pero nuevamente, pocos fallos. Podría probablemente arreglar los fallos, supongo, pero como puedes ver, hay más riesgos y más posibilidades de que tengas que lidiar con problemas de pruebas.
Para obtener la imagen completa, también necesitas entender lo siguiente. Por defecto, dentro de los trabajadores, las pruebas se ejecutan secuencialmente, así. Pero puedes configurar esto. Si especificas la palabra clave concurrent aquí, entonces la prueba se ejecutará, según la documentación que hicimos conmigo. Usa concurrent para ejecutarlas en paralelo.
Así que, verifiqué esto. Y como puedes ver, tenemos múltiples pruebas aquí. Cada una escribe en el registro, su número. Y probé esto con muchas más pruebas. Y cuando las ejecuté, esperaba ver en el registro algún orden aleatorio de entradas de registro. Pero de hecho, lo que obtuve es que la prueba en realidad se ejecuta en secuencia. Así que, miré el código fuente de VTest, y vi esto. Esa es la función principal que ejecuta las pruebas. Y luego, como puedes ver, la función run test está envuelta por la función limitMaxConcurrency que intentará establecer el número de concurrencia con el que se ejecutan las pruebas.
Y cuando hago doble clic dentro, puedes ver que esta función en realidad devuelve una promesa. Y esta promesa se resuelve con la siguiente lógica. Si el conteo, el número de pruebas en ejecución, es menor que el máximo permitido, que puedes configurar, entonces se resuelve. La prueba ahora está permitida para ejecutarse. Pero si ya alcanzamos el límite, entonces se coloca en cola, se espera, y se ejecutará nuevamente más tarde. Y lo que aprendimos de esto es que esta concurrencia se basa en promesas. Es como ejecutar la prueba en PromiseAlt. Así que, se basa en la concurrencia de Node.
6. Understanding Worker Model and Code Failures
La concurrencia en VTest no tiene aislamiento y puede afectar a otras pruebas que se ejecutan simultáneamente. Al elegir configuraciones de trabajadores, depende del contexto. La concurrencia en el mismo archivo es mejor evitarla, y se recomienda el tipo de trabajador de proceso como predeterminado. El aislamiento es crucial en las pruebas de integración, pero no es obligatorio en las pruebas unitarias. Dentro del trabajador, se maneja un archivo TypeScript, y pueden ocurrir fallos al simular funciones.
Así que, se basa en la concurrencia de Node.js que exige que estés haciendo algún trabajo asíncrono. Con la prueba unitaria, no lo harás. Así que, si estás ejecutando una prueba unitaria, en realidad será secuencial. Y no solo esto, también la concurrencia no tiene aislamiento en absoluto. Cuando ejecutas múltiples pruebas en el mismo espacio de memoria, si estás haciendo mocking en una prueba, se aplicará y afectará a otras pruebas que se ejecuten al mismo tiempo.
Ahora entiendes el modelo del trabajador. ¿Qué configuración deberías elegir? Depende. Pero intentaré sugerir algunas reglas generales. En cuanto a la concurrencia en el mismo archivo, creo que quieres evitarla por defecto por todas las razones que se mencionaron, como la falta de aislamiento, etc. ¿Qué pasa con los tipos de trabajadores? ¿Cuál debería ser el predeterminado? Sugiero proceso. Porque es el objeto más seguro y la penalización de rendimiento no es tan alta. ¿Qué pasa con el aislamiento? Bueno, en las pruebas de integración, hay tantas partes móviles que no comenzar desde un estado limpio tiene altas probabilidades de enfrentar algunos problemas relacionados. Así que, sugiero que es un buen predeterminado. Pero en las pruebas unitarias que se ejecutan tan rápido, la penalización de rendimiento de iniciar un nuevo proceso o cierto código es mayor. Y es mucho más fácil, de hecho, asegurar un entorno sin estado en las pruebas unitarias. Así que, creo que el aislamiento no es una opción obligatoria en las pruebas unitarias.
Lo que hemos visto hasta ahora es cómo VTest gestiona todos sus trabajadores. Pero, ¿qué está sucediendo dentro del trabajador? Esto es interesante, no menos. Así que, lo que sucede es que un trabajador recibe un archivo TypeScript para manejar. Y antes de mostrarte cómo lo maneja, quiero mostrarte algunos fallos de código. Y luego, al entender los internos, podremos explicar estos fallos y solucionarlos. Pero lo que tenemos aquí es un código muy simple para probar. Function1 llama a function2 que imprime la verdadera function2. Fácil y simple. Ahora, la prueba de esto comienza con un mocking. Intentamos simular este código y hacer que function2 devuelva una cadena diferente, no function2. Así que, una vez que llamamos a function1, bajo el capó llama a function2 y debería devolver no una real, sino más bien la función simulada function2. Esto debería funcionar. Esto está perfectamente bien. Sin embargo, en realidad, falla.
7. Understanding Worker Handling and Transpilation
El mocking no funciona en el trabajador. El trabajador maneja archivos TypeScript y los transpila utilizando el servidor Vite. El servidor Vite reemplaza las importaciones y eleva el mocking. El código transformado reemplaza las declaraciones de importación con funciones de importación de Vite.
Obtenemos la salida real, la incorrecta, la verdadera function2 en lugar de hacer mocking. En otras palabras, el mocking aquí no funcionó. ¿Pero por qué? Intentemos entender. Así que, el trabajador está a punto de manejar este archivo TypeScript. Lo primero que hace es buscar a través de todos los archivos del mocking y anota todo el mocking que encuentra estáticamente en los archivos. Crea una clase mocker que sostiene un registro, solo un diccionario. Y cualquier vez que se da cuenta de un mock, como en nuestro caso, recuerda, solo anotó lo que encontró un mock en la prueba por uno que se aplica al código uno. Y estos son los sustitutos. Recuerda este registro porque volverá muy pronto a nuestra historia.
Ahora, dado que quiere ejecutar todos estos archivos, y no puede porque es TypeScript, necesita transpilarlo primero, ¿verdad? Así que, pensé que llamaría a algún tipo de TSC o SWC, cualquier tipo de compilador. Pero lo que encontré en el código era un poco diferente. La función transform request es responsable de esto. Y noté que se llama algo que se llama servidor. Esa es una dependencia de NPM de terceros para el servidor Vite. Así que, si no estás familiarizado con ello, el servidor Vite proviene del mundo del front end. Es una herramienta que se especializa en empaquetar, transpilar y transformar código. Y tiene sentido usarlo aquí porque Vitest es un proyecto hermano de Vite. Y lo que necesitamos hacer es transpilar. Y el servidor Vite hará en realidad tres cosas. Dos son interesantes. La primera es transpilar, obviamente, pero también reemplazará las importaciones y elevará el mocking.
Veamos qué significa eso. Para establecer una transformación, podemos usar una herramienta muy agradable que Vitest empaqueta, la herramienta AUI que te muestra todo el gráfico de módulos. Es una forma valiosa para hacer benchmarking y analizar cómo maneja tus archivos. Y una vez que haces clic en algún archivo fuente, obtendrás una vista que te muestra la fuente a la izquierda y el código transformado a la derecha. Ahora, necesito tu atención porque cosas muy interesantes y inusuales están sucediendo aquí. La primera cosa que podrías notar es que tenemos una declaración de importación a la izquierda. Se reemplazan con funciones de importación de Vite. Ahora, este es un movimiento audaz porque la importación es parte de JavaScript.
8. Vite's Customized Runtimes and Module Loader
Vite introduce un nuevo cargador de módulos en el tiempo de ejecución.
Es parte del tiempo de ejecución. Y Vite personalizó los tiempos de ejecución e introdujo un nuevo cargador de módulos, que es algo de lo que hay que estar al tanto. ¿Por qué lo hace? Lo entenderemos muy pronto.
9. Vite's Mocking Transformations and Test Failures
Vite elevó el mock a la primera línea en el código de transformación para hacerlo antes de la importación. Además, Vite cambia los mocks a importaciones dinámicas, asegurando que el mocking funcione. Vite intercepta las llamadas a funciones a nivel de importación de archivos, pero no puede interceptar llamadas entre funciones en el mismo archivo. Mover la función dos a un archivo diferente o usar una exportación de objeto puede resolver este problema.
Esta no es la única transformación. Mira aquí, intentamos hacer un mock de la función número dos y cambiarla antes de que nuestro código la importara y usara la real, pero la importación ya había ocurrido, así que es demasiado tarde. Por esta razón, como puedes ver, dado que ocurre en la línea número ocho en el código fuente, Vite la elevó y la puso en la primera línea en el código de transformación para hacerla antes de la importación.
Sin embargo, esto no es suficiente porque las declaraciones de importación siempre ocurren primero. Se analizan estáticamente antes del tiempo de ejecución. Así que lo que Vite hace además es que cada vez que nota un mock, lo cambiará a una importación dinámica. Mira aquí, el await. Ahora, tenemos el mock primero y luego secuencialmente la importación del código. Y ahora el mocking debería funcionar. Así es como Vite transformó el archivo y lo devuelve a un JS al worker para procesarlo. Ahora el worker puede ejecutar el archivo.
Así que está a punto de ejecutar el archivo de prueba uno que llama al código uno. Pero debido a que se hace utilizando la importación de Vite, puede buscar en el registro de mocks y notar, hey, tenemos un mock para este archivo. Así que usemos nuestro mock y no el archivo real. Así que interseca el código y hace que el código sustituya el real. Así que volviendo a la prueba fallida. Míralo. Ahora deberías tener una pista de por qué falló y para dejarlo super claro, entendemos que lo que Vite es capaz de hacer son cosas como las siguientes. Tenemos un archivo que llama a otro archivo. Y luego cuando la función uno en el código uno llama a una función en un archivo diferente, puede interceptarlo porque funciona a nivel de importación, a nivel de importación de archivos. Tanto Jest como Vitest funcionan de esta manera. Pero lo que no son capaces de hacer es cuando tenemos ambas funciones en el mismo archivo. Así que si la función uno llama a la función dos, no tienen un mecanismo para interceptar esta llamada. Ocurre en memoria. No pasa por el sistema de importación. Y en ese caso, el mocking fallará. Esta es la razón por la que nuestra prueba falló, nuestro mocking falló. ¿Cómo podemos arreglar esto? Primero, con este entendimiento, puedes solucionar todo tipo de problemas de mocking. Por aquí, por ejemplo, podemos mover la función dos a un archivo diferente. Otra solución sería hacer que todo sea parte del mismo objeto, exportar un objeto en lugar de una exportación nombrada.
10. Vite's Customized Runtime and Import Issues
La función uno llama a la función dos en el mismo contexto de objeto. Usa Spy para reemplazar funciones dentro del objeto. Vite ofrece una gama de plugins para diferentes funcionalidades. Puedes solucionar problemas de importación personalizando el runtime de Vite. El servidor de Vite maneja la resolución de dependencias y la transformación. Considera usar el runner de pruebas incorporado o mockup para pruebas a pequeña escala. Obtén una mejor experiencia de prueba con el runtime personalizado de Vite.
Así que como puedes ver aquí, ahora la función uno llama a la función dos en el mismo contexto de objeto. Y luego necesitaríamos cambiar el archivo de prueba y usar Spy. Spy es un mecanismo diferente al mock. No funciona a nivel de importación. Sino que asume que el objeto ya vive en memoria. Y cuando el objeto está en este tipo, puede simplemente reemplazar funciones dentro. Y entonces esto simplemente funcionará.
Otra lección que aprender de este diagrama es que bajo el capó, tenemos V. Y podemos aprovecharlo. Tiene un enorme ecosistema de plugins. Así que, por ejemplo, si quieres un servidor Node.js rápido con recarga automática, lo tienes. Hay un plugin existente para esto. Quieres ESLint Check al vuelo, lo tienes. Y cientos de otros plugins, la mayoría de ellos front-end, para ser honesto. Y ahora puedes solucionar todo tipo de problemas de importación.
Por ejemplo, si intentas importar la función dos, es bastante común obtener todo tipo de fallos. Como que un miembro no existe, undefined, y así sucesivamente. Y luego te preguntas, ¿a qué reglas debería seguir aquí? ETCS-Tenom o CommonJS? Y la respuesta es ninguna. Es un runtime personalizado, sistemas de modelos personalizados que Vitest acaba de crear. Pero ahora, al menos sabes, ir a la configuración, y entiendes que el servidor es donde existe el servidor de Vite. Y maneja toda la resolución de dependencias y transformación. Y ahora puedes mirar todas las diversas configuraciones y cambiar cosas. Si quieres evitar transformar algunas de tus bibliotecas o de terceros, puedes simplemente excluirlo aquí. Si quieres tener mucho más control sobre cómo trata varios modelos CSM o CGS, hay otras entradas para esto. Pero ahora sabes dónde mirar y dónde analizar y ajustar este sistema.
Sin embargo, consideraría positivamente el runner de pruebas OGS incorporado o mockup. Si solo estás probando la biblioteca o teniendo un pequeño microservicio con no tantas pruebas, o simplemente ejecutando algunas pruebas unitarias, porque en estos casos, pagas el precio, pero obtienes mucho menos valor. Espero que para ahora entiendas cómo funciona y las diversas consideraciones para aplicarlo. Así que tienes una mejor experiencia de prueba. Muchas gracias.
Comments