Titiritero con ES6 en un nodo y navegador, o por qué Zora es el mejor marco de prueba en su nicho

Todo está bien siempre que necesite ejecutar fuentes JS a través de los dummies para crear un paquete, pero el infierno comienza cuando desea escribir pruebas para su sitio o biblioteca. El problema es que todos los marcos de prueba utilizan funciones específicas de un nodo y / o están escritos en ES5. Por lo tanto, iniciar las pruebas E2E no es una tarea trivial y ofrece bailar con una pandereta de transpilaciones y mapas fuente para cubrir el código. ¿No quieres que los errores apunten al lugar equivocado?



En este artículo, describiré mi experiencia usando Puppeteer para una tarea pequeña,
y cómo lancé los módulos ES6 en el nodo y el navegador, teniendo solo una fuente para pruebas sin colectores.


¿Por qué titiriteros en absoluto? ¿Por qué no WebDriver? Acabo de notar cómo los creadores de las populares bibliotecas WebGL de código abierto están atormentados, por ejemplo, tienen 300 páginas con ejemplos, cada uno de los cuales puede romper con cualquier confirmación. Los revisan después de cada cambio, y si olvidaron abrir algo, lo siento ¯\_(ツ)_/¯ , se rompió. Si nadie ha resuelto este problema, decidí probarlo en mi pequeña lib. El primer pensamiento fue ejecutar headless-gl, pero está obsoleto. Node-gles ya es compatible con WebGL2, pero no es la rara extensión que utilicé. WebDriver? Ni siquiera lo he probado. No estoy seguro de si esto es posible, no necesitaba python / C # / Java, pero necesitaba JS / TS con el último nodo y la última API del navegador, por lo que las características de vuelo pueden ser de la última especificación.


¿Por qué son los módulos ES6? La compatibilidad con WebGL y ES6 en los navegadores es casi la misma. Y con módulos de paquete o no, deje que el usuario decida, simplemente puede recopilar ambas versiones. Pero resulta que para las pruebas unitarias, es muy conveniente usar la versión con los módulos, ya que los mapas de origen se extraen de manera muy simple, y luego puede ejecutar las pruebas sin gestos adicionales en el nodo o en el navegador. Ejecutándolos en titiriteros, E2E con cobertura de código es casi gratis. Probablemente se necesitaba un mecanografiado con un objetivo en ES6, pero en un pequeño proyecto cubierto con pruebas, el js normal también funcionará.


Entonces, suficientes introducciones, puse a puppeteer y puppeteer-to-istanbul en el proyecto y escribí tal envoltorio


 // puppeteer.js import puppeteer from 'puppeteer'; import pup2ist from 'puppeteer-to-istanbul'; (async () => { const browser = await puppeteer.launch({ headless: process.env.HEADLESS, // headless customization slowMo: 250 // good fature for new configs }); const page = (await browser.pages())[0]; // enable coverage await page.coverage.startJSCoverage(); await page.coverage.startCSSCoverage(); // some additional code with console events here... // navigate to unit test page await page.goto('http://127.0.0.1:1234/'); // disable coverage const jsCoverage = await page.coverage.stopJSCoverage(); const cssCoverage = await page.coverage.stopCSSCoverage(); pup2ist.write([...jsCoverage, ...cssCoverage]) await new Promise(resolve => setTimeout(resolve, 6000)); await browser.close(); })(); 

Que se puede ejecutar con el node --experimental-modules --no-warnings ./test/puppeteer.js comando node --experimental-modules --no-warnings ./test/puppeteer.js con un nodo 11+, o incluso sin indicadores en el nodo 13.2+. Por supuesto que puedes usar require , entonces ... ¿Pero por qué? Esto generalmente es un back-end, ¡aquí ni siquiera se necesita asistencia al cliente! El siguiente código de package.json nos permite personalizar las descargas SIN CABEZA en la consola y en la nube de CI si se requieren diferentes configuraciones para ellas. En travs / circle-ci, Linux probablemente se instalará y allí puede establecer variables de entorno en este formato. concurrently abre dos procesos en una consola en paralelo.


 // package.json { //bla-bla... "type": "module", // this line indicates that we are using es6 modules "scripts": { "test": "node --experimental-modules --no-warnings ./test/puppeteer.js", "server": "http-server -c-1 -p 1234", "not-bad-cmd--dude": "concurrently -k -s first \"npm:test\" \"npm:server\"", "ci": "HEADLESS=true concurrently -k -s first \"npm:test\" \"npm:server\"", } } 

En la máquina local, después de ingresar el npm run server , se iniciará el npm run server http, y en npm run test en una ventana separada, la ventana de Chrome. Eso es básicamente todo lo que necesitas saber sobre titiriteros. Aquí se encuentran más ejemplos de capturas de pantalla, emulaciones de dispositivos, áreas de administración, etc. Por cierto, junto con el paquete puppeteer , instaló un cromo separado en node_modules , si no lo necesita, reemplácelo con puppeteer-core o puppeteer-firefox . Cabe señalar que en el ejemplo anterior, obtuvimos una cobertura de código JS / CSS gratuita que está escrita en la carpeta .nyc_output, hasta que nos centremos en esto, en esta etapa no tenemos frío, no está caliente, pero si hay algo, está ahí y estadísticas La cobertura de prueba está casi lista para ver.



Ahora pasemos a las pruebas en sí mismas, tratando de elegir dónde ejecutaré E2E en mi pequeña lib, encontré los siguientes gráficos, que compararon el rendimiento de los marcos para las pruebas. Probablemente, el tiempo de ejecución no es tan importante, pero cuando algunos Jest los inician 10 veces más lento, surge la pregunta "¿qué es y por qué es necesario?". El criterio de selección principal era ejecutar es6 con la línea <script type="module" src="./test.js"></script> en la página html. Dado que al momento de escribir mi código, el nodo aún no era totalmente compatible con ES6 (ayer se lanzó 12.3 en el que se eliminaron las banderas). Decidí que si toma el marco con las fuentes en TS o ES6 +, definitivamente debería comenzar. En general, probablemente podría tomar algún tipo de moca, declararlo más arriba en la página y consultar la clase declarada, pero ¿qué sucede si se produce un error? En general, puede nombrar su prueba de corredor favorita aquí. Solo diré que Zora admite el formato TAP, y eso significa que todo un zoológico de comedores TAP es adecuado para ello. Tiene la mayoría de las afirmaciones, admite asíncrono, es uno de los más rápidos, escrito en ES6 puro sin dependencias del nodo en sí. Me pareció un verdadero diamante para pequeños proyectos.


Como resultado, obtuve algunas pruebas que funcionan tanto en el navegador como en el nodo. La documentación de Zora tiene instrucciones completas sobre aserciones y agrupaciones de comandos.


 // test.js import MyLibrary from '../dist/my-library.module.js'; import { test } from 'https://cdn.jsdelivr.net/npm/zora@3.0.3/dist/bundle/module.js'; test('CPU', async (t) => { // some stuff here t.ok(tfps != null, 'fps = ' + (tfps != null ? tfps.toFixed(1) : 'null')); t.ok(tcpu != null, 'cpu = ' + (tcpu != null ? tcpu.toFixed(1) : 'null')); }); test('Memory', async (t) => { // some stuff here t.ok(tmem != null, 'mem = ' + (tmem != null ? tmem.toFixed(1) : 'null')); }); // etc... 

Para mostrar la consola sin ensamblajes, tuve que hacer un sniffer similar. La consola desnuda no es muy presentable, sería posible conectar la salida TAP en algún lugar para guiar el maratón. Pero lo curioso es que los resultados de la prueba en su cliente se pueden ver en línea . Además, exactamente el mismo código se ejecuta en CI en cualquier confirmación.


 <!DOCTYPE html> <html lang="en"> <head> <!-- some declarations in head --> </head> <body> <!-- some declarations in body --> <script> const addSniffer = (spyTarget) => function() { spyTarget.apply(window.console, arguments); sniffer([...arguments]); } window.console.log = addSniffer(window.console.log); window.console.error = addSniffer(window.console.error); let screen = document.getElementById('screen'); function sniffer(string) { let screen = document.getElementById("screen"); string.forEach(line => { let div = document.createElement("div"); let text = document.createTextNode(line); div.appendChild(text) screen.appendChild(div); }); } </script> <script type="module" src="./test.js"></script> </body> </html> 

Pero eso no es todo, con las pruebas ya preparadas, puede conectar bots como renovate / greenkeeper / dependdabot, que actualizarían las dependencias en su biblioteca y realizarán confirmaciones automáticas, después de verificar la corrección de las actualizaciones. Y travis / github-ci / circle-ci habría subido una nueva versión de paquetes npm.


Por ejemplo, dicha configuración de renovate, realiza confirmaciones automáticas los domingos y eleva la versión


 { "automerge": true, "automergeType": "branch", "bumpVersion": "patch", "schedule": ["on sunday"], "ignorePaths": [".circleci"] } 

Y travis, cuando usted mismo aumentó la versión o algún bot, puede cargar automáticamente el paquete a npm. Para hacer esto, cree una cuenta en travis-ci.org , habilite f2a como se describe en este artículo , ingrese dos claves secretas $NPM_EMAIL y $NPM_TOKEN , y cree una configuración similar.


 language: node_js node_js: '12' script: - npm run ci deploy: provider: npm edge: true email: $NPM_EMAIL api_key: $NPM_TOKEN on: branch: master 

En total, de alguna manera es posible, pero es difícil deshacerse de las notificaciones del github de que apareció una vulnerabilidad en algún tipo de dependencia: D

Source: https://habr.com/ru/post/466551/


All Articles