Tooché #9 — Integrando framework de testing con Phaser (Karma, Mocha, HeadlessChrome)

Jordi
6 min readApr 8, 2018

Mientras las pruebas y testeos con los usuarios del juego Tooché siguen en marcha, he aprovechado para revisar el funcionamiento de Phaser e integrar un framework de testing que me permita hacer TDD. Tras varios intentos, he acabado instalando algo estable. La intención de este post es explicar las alternativas y cómo me ha llevado al final a este framework.

Recuerda que tienes todo el código disponible en: https://github.com/jmarti-theinit/tooche-game

Tooché es un juego que estoy elaborando en mis ratos libres, y cuyo desarrollo y reflexiones libero de forma pública: https://medium.com/@itortv/voy-a-compartir-todo-el-trabajo-de-mi-futuro-pet-project-me-acompa%C3%B1as-4ff3d6c69cd

Componentes de testing instalado

Finalmente he optado por instalar el runner de Karma con Mocha y con Headless Chrome, pero sinceramente, no ha sido mi primera opción.

Utilizo Karma como runner para ejecutar los tests con el código JS procesado por webpack; gracias a karma-webpack.

Utilizo Mocha porque es el framework de testing que he utilizado últimamente (he usado Jasmine anteriormente, pero me siento cómodo con Mocha + Chai).

Utilizo Headless Chrome como browser del Karma para que Phaser pueda trabajar con un elemento “canvas” real.

En estos momentos, el objetivo es empezar a andar con un framework que me permita hacer TDD con Phaser. Ahora mismo, he montado un framework que me permite hacer eso, y voy a dar mis primeros pasitos. Si tuviera experiencia con Phaser, probablemente sabría desacoplar los tests al uso del “canvas” en Phaser y no debería haber necesitado Headless Chrome (a no ser que desarrollara tests funcionales end to end, lo cual no creo que sea el caso). Entiendo por tanto que parte de mi aprendizaje en este proyecto irá en esa línea.

Estructura de archivos

Dentro del fichero test/unit/karma.conf.js tenemos la configuración que nos permite ejecutar karma con webpack y con Headless Chrome.

karma.conf.js

El archivo “webpack.test.config” difiere del webpack de desarrollo en la deshabilitación de los siguientes plugins: CommonsChunk. HtmlWebpack y BrowserSync.

Y aunque últimamente suelo integrar dentro del código de producción los tests, en este caso he optado por separarlo a una carpeta “test/unit/specs”. He realizado esto porque veo coherente introducir los tests en el código de producción cuando dividimos el código en componentes, de modo que se visibiliza que cuando agarro un componente (“una carpeta”) me llevo todo, incluido sus tests.

Sin embargo, no tengo muy claro que en este proyecto vaya a dividir la estructura en componentes; y no sé ni cómo se haría. Por lo tanto, empezaré “por lo fácil” y poco a poco iré descubriendo si es buena idea dividir la presentación y lógica en componentes, y cómo hacerlo.

Otras alternativas fallidas

Versión 1: Mocha a secas (vía node)

Debido a que quiero trabajar con código ES6, he integrado webpack para el empaquetado de la aplicación, y he configurado un loader que permita transpilar vía babel.

Sin embargo, si intento ejecutar el entorno de testing de forma independiente vía node, necesitaré que los archivos se transpilen. Una forma de hacer eso es generando un fichero “test/common.js” con un require de babel-register. De esta forma, todos los ficheros de JS que se van cargando, irán siendo transpilados.

Sin embargo, esta primera opción no funciona porque Phaser necesita que las variables PIXI y p2 estén definidas a modo global. Intenté que el test/common.js expusiera dichas variables antes de la carga de Phaser y fue imposible.

Esto es algo que ya tengo resuelto con Webpack a través de los “expose-loader”.

PIXI, Phaser y p2 expuestos gracias a expose-loader

Por lo tanto, tenía que buscar la forma de cargar Mocha con webpack.

Versión 2: Mocha + mocha-webpack

Allí es donde “mocha-webpack” vino al rescate y sinceramente, resolvió el problema, aunque nos encontramos enseguida con otro…

Un artículo que me ayudó en el proceso de montar mocha-webpack:

Una vez creado el webpack.conf.test.js en base al webpack.conf.js que ya tenía, deshabilitado los plugins mencionados anteriormente, y apuntado a él vía mocha-webpack.opts, los tests fallaban por una nueva razón: “No se puede encontrar canvas” (no tengo los errores exactos porque ya he evolucionado el framework, pero era algo similar a eso).

Esto se debe a que Mocha se ejecuta en node, y por tanto, no hay un canvas real.

Versión 3: Mocha + mocha-webpack + jsdom

Hay una solución para este problema y se llama JSDOM, y en teoría, jsdom soporta canvas.

jsdom includes support for using the canvas or canvas-prebuilt package to extend any <canvas> elements with the canvas API. To make this work, you need to include canvas as a dependency in your project, as a peer of jsdom. If jsdom can find the canvas package, it will use it, but if it's not present, then <canvas> elements will behave like <div>s.

Y efectivamente, al incorporar el elemento jsdom, se solucionó el problema anterior, pero surgió uno nuevo: “Cannot create Canvas 2d, aborting”.

Otras alternativas en esta línea me llevaron a mockear el canvas con canvas-mock, pero tampoco funcionaron.

Creo que si hubiera seguido trabajado en esa línea, habría encontrado la forma de hacerlo funcionar, porque en teoría tenía los componentes que lo debían hacer funcionar. Sin embargo, en mi cabeza rondaba la idea de hacer en un futuro tests más funcionales (y con screenshots), y empezaba a fantasear con la idea de utilizar Karma para usar un browser “de verdad” por debajo.

Así que aquí hice un punto y aparte.

Versión 4: Karma + PhantomJS

Mi primer intento (y sí, no fue el último) fue utilizar Karma con PhantomJS. PhantomJS es un webkit headless, y se interrelaciona con Karma muy bien.

Sin embargo, cuando me las prometía muy felices, me encuentro con un error misterioso del tipo “unexpected token ‘)’”.

Tras varios intentos de depuración y búsquedas en internet, mi interpretación del problema es que creo que la forma de transpirar babel resultaba en código que a PhantomJS no le gustaba. Algo similar encontré en esta línea (no creo que fuera lo mismo, pero me sonaba parecido):

Así que decidí pasar a Headless Chrome y descubrir este nuevo mundo. Tenía ganas de encontrar una excusa para probarlo, y finalmente la encontré.

Bonus

Muy avispado y acertado estuvo @artolamola cuando conté en twitter que finalmente había enganchado Phaser con Karma, Mocha y HeadlessChrome.

¡Oh sí! Tengo ganas de probar Puppeteer, conectarlo y trastear. Cuando tenga controlado TDD mediante tests unitarios y de integración, mi intención será realizar algún test funcional y sacar screenshots cuando falle. Tengo ganas de probar eso.

¿Ves otras alternativas al framework? ¿Ves otros usos de Puppetter? ¿He recorrido medio mundo para instalar lo que finalmente podía haber sido más evidente? ¿Tú haces testing con Phaser o PIXI y lo haces de otro modo? ¡Cuéntame cosas!

Recuerda que si deseas recibir artículos como este durante el desarrollo del juego Tooché, puedes apuntarte a su lista de distribución: https://goo.gl/forms/mI2koSmiOksnBIzZ2

--

--

Jordi

Learning and growing in teams that develop software and create impact. I work in @lifullconnect