Saltar al contenido principal

Pruebas automatizadas

La automatización de pruebas es una manera eficiente de validar que el código de la aplicación funciona como se pretende. Mientras Electron no mantiene activamente su propia solución de pruebas, esta guía recorrerá un par de maneras en que puedes ejecutar pruebas automatizadas de extremo a extremo en tu aplicación Electron.

Usando la interfaz WebDriver

Para ChromeDriver - WebDriver para Chrome:

WebDriver es una herramienta de código abierto para pruebas automatizadas de aplicaciones web en varios navegadores. Provee la capacidad de navegar por páginas web, sistema de usuarios, ejecución de JavaScript, y más. ChromeDriver es un servidor independiente que implementa el protocolo de cable de WebDriver para Chromium. Ha sido desarrollado por miembros de los equipos de Chromium y WebDriver.

Hay algunas maneras en que puedes configurar las pruebas usando WebDriver.

Con WebdriverIO

WebdriverIO (WDIO) es un framework para automatización de pruebas que provee un paquete Node.js para pruebas con WebDriver. Su ecosistema además incluye varios complementos (p. ej. reportes y servicios) que pueden ayudarte a armar su configuración de prueba.

Install the test runner

Primero necesitas ejecutar el kit de herramientas de inicio WebdriverIO en el directorio raíz de tu proyecto:

npx wdio . --yes

Esto instala todos los paquetes necesarios para ti y genera un archivo de configuración wdio.conf.js.

Conecta WDIO a tu aplicación Electron

Actualiza las capacidades en tu archivo de configuración para apuntar al binario de tu aplicación Electron:

wdio.conf.js
exports.config = {
// ...
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': {
binary: '/path/to/your/electron/binary', // Ruta a tu binario de Electron.
args: [/* cli arguments */] // Opcional, tal vez 'app=' + /ruta/hacia/tu/aplicación/
}
}]
// ...
}

Ejecutar tus pruebas

Para ejecutar tus pruebas:

$ npx wdio run wdio.conf.js

Con Selenium

Selenium es un framework de automatización web que expone enlaces a las APIs de WebDriver en muchos lenguajes. Sus enlaces Node.js están disponibles bajo el paquete selenium-webdriver en NPM.

Ejecurar un servidor ChromeDriver

Para usar Selenium con Electron, necesitas descargar y ejecutar el binario electron-chromedriver:

npm install --save-dev electron-chromedriver
./node_modules/.bin/chromedriver
Starting ChromeDriver (v2.10.291558) on port 9515
Only local connections are allowed.

Recuerde el puerto número 9515, que usaremos más adelante.

Conectar Selenium a ChromeDriver

A continuación, instalar Selenium dentro de tu proyecto:

npm install --save-dev selenium-webdriver

El uso de Selenium-web driver con Electron es el mismo que con sitios normales, excepto que tienes tiene que especificar manualmente como conectar el ChromeDriver y donde se encuentra el binario o ejecutable de Electron:

test.js
const webdriver = require('selenium-webdriver')
const driver = new webdriver.Builder()
// El "9515" es el puerto abierto por el ChromeDriver.
.usingServer('http://localhost:9515')
.withCapabilities({
'goog:chromeOptions': {
// Here is the path to your Electron binary.
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
}
})
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
.build()
driver.get('http://www.google.com')
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
driver.findElement(webdriver.By.name('btnG')).click()
driver.wait(() => {
return driver.getTitle().then((title) => {
return title === 'webdriver - Google Search'
})
}, 1000)
driver.quit()

Usando Playwright

Microsoft Playwright es un framework de pruebas de extremo a extremo construido usando protocolos de depuración remotos específicos del navegador, similar a la API Node.js de Puppeteer "headless" pero dirigida hacia pruebas de extremo a extremo. Playwright tiene soporte experimental de Electron a través del soporte de Electron para el Protocolo de Chrome DevTools (CDP).

Instala las dependencias

Puede instalar Playwright a través de su gestor de paquetes Node.js preferido. El equipo de Playwright recomienda usar la variable de entorno PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD para evitar descargas innecesarias del navegador al probar una aplicación Electron.

PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --save-dev playwright

Playwright también viene con su propio test runner, Playwright Test, que está construido para pruebas de punto a extremo. También puedes instalarlo como una dependencia de desarrollo en su proyecto:

npm install --save-dev @playwright/test

:::precaución Dependencias

Este tutorial fue escrito [email protected] y @playwright/[email protected]. Echa un vistazo a la página de versiones de Playwright para aprender sobre cambios que podrían afectar el código a continuación.

:::

Usando test runners de terceros

Si estás interesado en usar un test runner alternativo (por ejemplo, Jest o Mocha), echa un vistazo a la guía de Playwright Test Runners de Terceros .

Escribe tus tests

Playwright ejecuta tu aplicación en modo desarrollo a través de la API _electron.launch. Para apuntar esta API a su aplicación de Electron puede pasar la ruta al punto de entrada de su proceso principal (en este caso main.js).

const { _electron: electron } = require('playwright')
const { test } = require('@playwright/test')

test('launch app', async () => {
const electronApp = await electron. aunch({ args: ['main.js'] })
// cerrar la aplicación
await electronApp.close()
})

Después de eso, tendrás acceso a una instancia de la clase ElectronApp de Playwright. Esta es una clase poderosa que tiene acceso a módulos del proceso principal, por ejemplo:

const { _electron: electron } = require('playwright')
const { test } = require('@playwright/test')

test('get isPackaged', async () => {
const electronApp = await electron. aunch({ args: ['main. s'] })
const isPackaged = await electronApp. valuate(async ({ app }) => {
// Esto se ejecuta en el proceso principal de Electron, aquí siempre es
// el resultado del require('electron') en el script principal de la aplicación.
return app.isPackaged
})
console.log(isPackaged) // false (porque estamos en modo de desarrollo)
// cerrar la aplicación
esperar electronApp.close()
})

También puede crear objetos individuales de Página desde instancias de Electron BrowserWindow. Por ejemplo, para tomar la primera ventana del navegador y guardar una captura de pantalla:

const { _electron: electron } = require('playwright')
const { test } = require('@playwright/test')

test('launch app', async () => {
const electronApp = await electron. aunch({ args: ['main.js'] })
const window = await electronApp.firstWindow()
await window.screenshot({ path: 'intro.png' })
// cerrar la aplicación
await electronApp.close()
})

Al juntar todo esto usando el ejecutor de pruebas de PlayWright, vamos a crear un archivo de prueba example.spec.js con una sola prueba y afirmación:

example.spec.js
const { _electron: electron } = require('playwright')
const { test, expect } = require('@playwright/test')

test('example test', async () => {
const electronApp = await electron.launch({ args: ['.'] })
const isPackaged = await electronApp. valuate(async ({ app }) => {
// Esto se ejecuta en el proceso principal de Electron, aquí siempre es
// el resultado del require('electron') en el script principal de la aplicación.
return app.isPackaged
})

expect(isPackaged).toBe(false)

// Wait for the first BrowserWindow to open
// and return its Page object
const window = await electronApp.firstWindow()
await window.screenshot({ path: 'intro.png' })

// close app
await electronApp.close()
})

Luego, ejecuta Playwright Test usando npx playwright test. Deberías ver como pasa la prueba, y tener una intro.png captura de pantalla en tu sistema de archivos.

☁  $ npx playwright test

Running 1 test using 1 worker

✓ example.spec.js:4:1 › example test (1s)
info

La prueba de Playwright ejecutará cualquier archivo que coincida con la expresión regular .*(test|spec)\.(js|ts|mjs). Puedes personalizar esta coincidencia en las opciones de configuración de la prueba de Playwright.

:::Leer más

Revisa la documentación de Playwright para las APIs completas de clase Electron y ElectronApplication.

:::

Usar un controlador de prueba personalizado

También es posible escribir tu propio controlador personalizado usando el IPC-over-STDIO incorporado de node. js. Los controladores de prueba personalizados requieren que escribas un código de aplicación adicional, pero tienen una carga inferior y le permiten exponer métodos personalizados a su suite de pruebas.

Para crear un controlador personalizado, usaremos la API child_process de node. js. El conjunto de pruebas generará el proceso de Electron, luego establecerá un protocolo de mensajería simple:

testDriver.js
const childProcess = require('node:child_process')
const electronPath = require('electron')

// spawn the process
const env = { /* ... */ }
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })

// listen for IPC messages from the app
appProcess.on('message', (msg) => {
// ...
})

// envía un mensaje IPC a la aplicación
appProcess.send({ my: 'message' })

Dentro de la aplicación Electron, puedes escuchar mensajes y enviar respuestas usando la API de Node.js process:

main.js
// escucha mensajes de la suite de pruebas
process.on('message', (msg) => {
// ...
})

// envía un mensaje a la suite de pruebas
process.send({ my: 'message' })

Ahora podemos comunicar desde la suite de test a la aplicación Electron usando el objeto appProcess.

Por conveniencia, es posible que desees encapsular appProcess en un objeto de controlador que ofrezca más funciones de alto nivel. Aquí hay un ejemplo de cómo puedes hacer esto. Empecemos por crear una clase de TestDriver:

testDriver.js
class TestDriver {
constructor ({ path, args, env }) {
this.rpcCalls = []

// start child process
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })

// handle rpc responses
this.process.on('message', (message) => {
// pop the handler
const rpcCall = this.rpcCalls[message.msgId]
if (!rpcCall) return
this.rpcCalls[message.msgId] = null
// reject/resolve
if (message.reject) rpcCall.reject(message.reject)
else rpcCall.resolve(message.resolve)
})

// wait for ready
this.isReady = this.rpc('isReady').catch((err) => {
console.error('Application failed to start', err)
this.stop()
process.exit(1)
})
}

// simple RPC call
// to use: driver.rpc('method', 1, 2, 3).then(...)
async rpc (cmd, ...args) {
// send rpc request
const msgId = this.rpcCalls.length
this.process.send({ msgId, cmd, args })
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
}

stop () {
this.process.kill()
}
}

module.exports = { TestDriver }

En el código de tu aplicación, puedes escribir un manejador simple para recibir llamadas RPC:

main.js
const METHODS = {
isReady () {
// hacer cualquier configuración necesaria
return true
}
// definir tus métodos RPC aquí
}

const onMessage = async ({ msgId, cmd, args }) => {
let method = METHODS[cmd]
if (! ethod) method = () => new Error('Método inválido: ' + cmd)
try {
const resolve = await method(. .args)
proceso. end({ msgId, resolve })
} catch (err) {
const reject = {
message: err.message,
stack: err.stack,
name: err.name
}
process. end({ msgId, reject })
}
}

if (process.env.APP_TEST_DRIVER) {
process.on('message', onMessage)
}

Luego, en tu suite de pruebas, puedes usar tu clase TestDriver con el framework de automatización de prueba de tu elección. El siguiente ejemplo usa ava, pero otras opciones populares como Jest o Mocha también funcionan:

test.js
const test = require('ava')
const electronPath = require('electron')
const { TestDriver } = require('. testDriver')

const app = new TestDriver({
path: electronPath,
args: ['. app'],
env: {
NODE_ENV: 'test'
}
})
test.before(async t => {
await app.isReady
})
test. fter.always('cleanup', async t => {
await app.stop()
})