09 January 2023

Primeros pasos con xk6-browser

Marie Cruz

Esta publicación explica cómo comenzar a usar xk6-browser, una extensión de k6 que añade API a nivel del navegador para interactuar con los navegadores y recopilar métricas de rendimiento web como parte de sus pruebas de k6.

Pruebas más allá del nivel de protocolos

Con los años, k6 se ha dado a conocer como una herramienta de pruebas de rendimiento que proporciona la mejor experiencia a desarrolladores. La mayoría de nuestros esfuerzos se han centrado en crear una herramienta que ayude a probar servidores o sistemas de backend. Sin embargo, reconocemos que las pruebas de rendimiento del backend solo abordan la mitad de las posibles pruebas de rendimiento.

Suponga que conduce pruebas de experiencia de usuario de su sitio web y verifica que no hay problemas de rendimiento al seguir una serie de pasos especificos como lo haria un usuario. En ese caso, debe ejecutar algunas de sus pruebas de rendimiento desde la perspectiva del navegador y considerar una prueba más realista del flujo de usuarios de inicio a fin (end-to-end).

La mayoría de las herramientas de pruebas de carga se centran en probar los puntos finales (endpoints) de la API, pero eso es diferente de las interacciones que sus usuarios normalmente realizarían. Sus usuarios interactúan con el navegador, por lo que también es vital probar el rendimiento del navegador para obtener una perspectiva mas realista de lo que está sucediendo cuando sus usuarios interactúan con sus aplicaciones web.

En k6, queremos comenzar a expandir nuestras pruebas de rendimiento y realizar pruebas también más allá del nivel de protocolos.

Aquí es donde entra en juego xk6-browser.

¿Qué es xk6-browser?

xk6-browser incorpora a k6 la capacidad de automatización en el navegador y pruebas de flujos de pasos en web, sin dejar atrás las características principales de k6. Le permite obtener información sobre el rendimiento de el frontend de su aplicacion al hacer pruebas.

Puede combinar pruebas a nivel del navegador y a nivel de protocolos en un script y unificado utilizando xk6-browser. Puede simular la mayor parte del tráfico de sus pruebas a nivel de protocolos y ejecutar uno o dos usuarios virtuales usando el navegador para imitar cómo interactuaría un usuario con su sitio web, aprovechando así un enfoque híbrido para las pruebas de rendimiento.

xk6-browser ofrece una solución única, ya que no tiene que emplear herramientas separadas para probar sus sistemas de frontend y backend. xk6-browser también ofrece una experiencia simplificada y una vision global de las métricas de rendimiento.

Primeros pasos con xk6-browser

Para empezar, lo primero que tiene que hacer es instalar xk6-browser. Actualmente, xk6-browser es una extensión de k6. No obstante, tenemos planeado añadirlo pronto como un módulo experimental integrado en la version base de k6.

Creación de la prueba

Una vez que haya instalado xk6-browser, puede comenzar copiando uno de nuestros scripts de ejemplo desde nuestra documentación de xk6-browser.

script.js
import { chromium } from 'k6/x/browser';
export default function () {
const browser = chromium.launch({ headless: false });
const page = browser.newPage();
}

Vamos a analizar lo que hace con el código anterior.

  1. Impertamos chromium desde el módulo k6/x/browser. chromium es de tipo BrowserType, que es el punto de entrada de xk6-browser cuando se lanza un proceso del navegador.
  2. A continuación, utilizamos la función de escenario, una funcionalidad de k6, para definir nuestro código de VUs (usuario virtuales).
  3. Para crear una nueva instancia del navegador, utilizamos el método launch de chromium, que devuelve un objeto Browser. Puede mandar diferentes parámetros dentro del launch, y uno de ellos es headless, que inica si se muestra el navegador o no.
  4. Para crear una nueva página en la instancia de su navegador, utilizamos browser.newPage().

¡Ahora viene lo divertido! Vamos a simular un usuario que visita una aplicación de prueba e inicia sesión en ella.

script.js
import { chromium } from 'k6/x/browser';
import { check } from 'k6'
export default function () {
const browser = chromium.launch({ headless: false });
const page = browser.newPage();
page
.goto('https://test.k6.io/my_messages.php', { waitUntil: 'networkidle' })
.then(() => {
// Enter login credentials and login
page.locator('input[name="login"]').type('admin');
page.locator('input[name="password"]').type('123');
// Wait for asynchronous operations to complete
return Promise.all([
page.waitForNavigation(),
page.locator('input[type="submit"]').click(),
]).then(() => {
check(page, {
'header': page.locator('h2').textContent() == 'Welcome, admin!',
});
});
}).finally(() => {
page.close();
browser.close();
});
}

En el código anterior suceden muchas cosas, pero destaca que comenzamos a usar operaciones asíncronas, así que vamos a analizarlo de nuevo.

  1. Visitamos la página usando page.goto y pasamos la URL de la aplicación de prueba. También estamos esperando a que la red esté inactiva, lo cual sucederá si no hay conexiones de red durante al menos 500 ms. page.goto también es una operación asíncrona, por lo que esto devuelve un objeto tipo promesa.
  2. Una vez la promesa recibe respuesta, utilizamos page.locator para interactuar con los elementos que queremos. En el ejemplo, estamos creando dos localizadores. Uno para el nombre de inicio de sesión y otro para la contraseña. Utilizamos el método type para escribir el nombre y la contraseña en los campos.
  3. Para hacer clic en el botón de inicio de sesión, utilizamos el método click, que es una operación asíncrona. Al hacer clic en el botón «Enviar», también comienza la navegación a la página y tendremos que esperar hasta que se cargue por completo, por lo que es necesario ejecutar page.waitForNavigation(), otra operación asíncrona, ya que la página no estará lista hasta que se complete la navegación.
  4. Dado que hay dos operaciones asíncronas, necesitamos usar Promise.all([]) para esperar a que las dos promesas sean respondidas antes de continuar para evitar cualquier condición de carrera.
  5. A continuación, usamos la función check de k6 para verificar el contenido de texto de un elemento específico.
  6. Finalmente, cerramos la página y el navegador.

Ejecución de la prueba

Para ejecutar la prueba, abra el terminal de su elección, vaya al directorio donde tiene instalado el binario xk6-browser y utilice el siguiente comando.

xk6-browser run script.js

Si tiene algún problema al ejecutar el comando, consulte nuestra documentación para ejecutar una prueba.

Debería ver una prueba similar a la que se muestra en el siguiente vídeo:

Al lanzarse el navegador, puede ver mejor lo que realmente ven sus usuarios, por lo que también puede encontrar puntos ciegos y detectar problemas relacionados con los navegadores que no se detectarían a nivel de protocolos.

Métricas del navegador

Cuando la ejecución termine, aparte de las métricas que k6 habitualmente rastrea, se trazan métricas adicionales del navegador como parte del resultado del resumen de k6.

browser_dom_content_loaded.......: avg=36.72ms min=544µs med=22.61ms max=87.02ms p(90)=74.14ms p(95)=80.58ms
browser_first_contentful_paint...: avg=47.52ms min=22.01ms med=47.52ms max=73.02ms p(90)=67.92ms p(95)=70.47ms
browser_first_meaningful_paint...: avg=75.22ms min=75.22ms med=75.22ms max=75.22ms p(90)=75.22ms p(95)=75.22ms
browser_first_paint..............: avg=45.72ms min=21.96ms med=45.72ms max=69.49ms p(90)=64.73ms p(95)=67.11ms
browser_loaded...................: avg=38.14ms min=5.28ms med=22.45ms max=86.68ms p(90)=73.83ms p(95)=80.26ms
note

Las métricas anteriores todavía están sujetas a cambios. Nuestro objetivo es poder informar sobre los Core Web Vitals, así como sobre otros Web Vitals, para contribuir a una mejor comprensión de la experiencia del usuario.

API de xk6-browser

La API de xk6-browser tiene como objetivo proporcionar una compatibilidad aproximada con la API de Playwright para NodeJS, lo que significa que los usuarios de k6 no tienen que aprender una API completamente nueva.

Por el momento, la API de k6 es síncrona. Sin embargo, dado que muchas operaciones del navegador ocurren de forma asíncrona y para apegarse mas a la API de Playwright, estamos trabajando en la migración de la mayoría de los métodos xk6-browser para que sean asíncronos. Esto implica que, aunque el navegador xk6 ya puede utilizarse, debe tener en cuenta que nuestra API todavía está experimentando algunos cambios.

Por el momento, unos cuantos métodos como page.goto(), page.waitForNavigation() y Locator.click() devuelven objetos tipo promesa de JavaScript. En el futuro, podremos soportar sintaxis «async» y «await» para una mayor simplicidad.

Para obtener más ejemplos sobre cómo usar la API de xk6-browser, consulte los ejemplos de xk6-browser.

Un enfoque híbrido para las pruebas de rendimiento

Si unicamente tomamos en cuenta el rendimiento web, esto puede conducir a una falsa confianza en el rendimiento general de la aplicación cuando aumenta la cantidad de tráfico.

Es muy recomendable que para tener una imagen completa del rendimiento de su aplicación también ponga a prueba sus sistemas de backend a través de pruebas a nivel de protocolos.

Sin embargo, existen algunos problemas asociados con las pruebas basadas en protocolos, como:

  • No profundizan en la experiencia del usuario, ya que no se toma en cuenta el navegador.
  • Los scripts pueden tardar tiempo en crearse y ser cada vez más difíciles de mantener a medida que la aplicación crece.
  • Se ignoran las métricas de rendimiento del navegador.

Por otro lado, realizar pruebas de carga poniendo en marcha muchos navegadores requiere muchos más recursos de generación de carga, lo que puede terminar siendo bastante costoso.

Para mitigar las deficiencias de cada enfoque, una práctica recomendada es adoptar un enfoque híbrido para las pruebas de rendimiento, que es una combinación de pruebas tanto de los sistemas de backend como de frontend a través de protocolos y pruebas en el nivel del navegador. Con un enfoque híbrido, se debe generar la mayoría de su carga a través del nivel de protocolos y simultáneamente simular uno o dos usuarios virtuales a nivel del navegador, con lo que también podrá ver lo que sucede en el frontend.

Lo mejor de xk6-browser es que ofrece este enfoque híbrido para las pruebas de rendimiento. Si bien puede hacer esto con herramientas separadas, lo bueno de usar xk6-browser es que es parte de k6, lo que significa que puede realizar pruebas a nivel de protocolo y a nivel del navegador en el mismo script.

Veamos cómo se traduce eso en el código.

Creación de la prueba

Un escenario común que recomendamos es combinar un subconjunto más pequeño de pruebas a nivel del navegador con una prueba más grande a nivel de protocolos. Para ejecutar una prueba a nivel del navegador y a nivel de protocolos simultáneamente, puede usar scenarios.

script.js
1import { chromium } from 'k6/x/browser';
2import { check } from 'k6';
3import http from 'k6/http';
4
5export const options = {
6 scenarios: {
7 browser: {
8 executor: 'constant-vus',
9 exec: 'browser',
10 vus: 1,
11 duration: '10s',
12 },
13 news: {
14 executor: 'constant-vus',
15 exec: 'news',
16 vus: 20,
17 duration: '1m',
18 },
19 },
20};
21
22export function browser() {
23 const browser = chromium.launch({ headless: false });
24 const page = browser.newPage();
25
26 page
27 .goto('https://test.k6.io/browser.php', { waitUntil: 'networkidle' })
28 .then(() => {
29 page.locator('#checkbox1').check();
30
31 check(page, {
32 'checkbox is checked': (p) =>
33 p.locator('#checkbox-info-display').textContent() === 'Thanks for checking the box',
34 });
35 })
36 .finally(() => {
37 page.close();
38 browser.close();
39 });
40}
41
42export function news() {
43 const res = http.get('https://test.k6.io/news.php');
44
45 check(res, {
46 'status is 200': (r) => r.status === 200,
47 });
48}

Vamos a volver a analizar el código anterior.

  1. Estamos utilizando opciones para configurar nuestro comportamiento de prueba. En este script en particular, estamos definiendo dos escenarios para configurar una carga de trabajo específica, uno para la prueba a nivel del navegador, llamada browser, y otro para la prueba a nivel de protocolos, llamada news.

  2. Tanto el escenario browser como el news están utilizando el ejecutor constant-vu, que introduce un número constante de usuarios virtuales para ejecutar tantas iteraciones como sea posible durante una cantidad de tiempo específica.

  3. A continuación, se declaran dos funciones de JavaScript, browser() y news(). Estas funciones contienen el código que ejecutará un usuario virtual. La función browser() representa nuestra prueba a nivel del navegador y simplemente visita una URL de prueba, hace clic en una casilla de verificación y comprueba si la casilla de verificación se ha marcado correctamente. Mientras que la función news(), que representa nuestra prueba a nivel de protocolos, envía una solicitud GET a una URL diferente y comprueba si el código de estado devuelve 200.

  4. Dado que estamos usando escenarios, las dos funciones son independientes entre sí y, por lo tanto, se ejecutan en paralelo.

Ejecución de la prueba

Usando el mismo comando de ejecución xk6-browser que en el caso anterior, debería ver un resultado similar al siguiente:

running (1m00.1s), 00/21 VUs, 12953 complete and 0 interrupted iterations
browser ✓ [======================================] 1 VUs 10s
news ✓ [======================================] 20 VUs 1m0s
✓ status is 200
✓ checkbox is checked
browser_dom_content_loaded.......: avg=12.27ms min=68µs med=11.76ms max=26.77ms p(90)=25.56ms p(95)=26.36ms
browser_first_contentful_paint...: avg=21.93ms min=12.5ms med=25.32ms max=26.19ms p(90)=25.83ms p(95)=26.01ms
browser_first_paint..............: avg=21.88ms min=12.45ms med=25.27ms max=26.14ms p(90)=25.78ms p(95)=25.96ms
browser_loaded...................: avg=12.18ms min=984µs med=11.74ms max=25.65ms p(90)=24.37ms p(95)=25.19ms
checks...........................: 100.00% ✓ 129530
data_received....................: 21 MB 341 kB/s
data_sent........................: 1.4 MB 24 kB/s
http_req_blocked.................: avg=2.14ms min=1µs med=2µs max=290.37ms p(90)=4µs p(95)=4µs
http_req_connecting..............: avg=1.09ms min=0s med=0s max=195ms p(90)=0s p(95)=0s
http_req_duration................: avg=90.59ms min=80.93ms med=92.8ms max=542.92ms p(90)=96.89ms p(95)=102.83ms
{ expected_response:true }.....: avg=90.49ms min=80.93ms med=92.8ms max=542.92ms p(90)=96.86ms p(95)=102.81ms
http_req_failed..................: 0.00% ✓ 012946
http_req_receiving...............: avg=154.41µs min=17µs med=47µs max=97ms p(90)=67µs p(95)=76µs
http_req_sending.................: avg=20.36µs min=0s med=14µs max=32.36ms p(90)=20µs p(95)=21µs
http_req_tls_handshaking.........: avg=1.16ms min=0s med=0s max=183.1ms p(90)=0s p(95)=0s
http_req_waiting.................: avg=90.41ms min=80.85ms med=92.72ms max=542.86ms p(90)=96.77ms p(95)=102.74ms
http_reqs........................: 12960 215.658713/s
iteration_duration...............: avg=93.58ms min=81.05ms med=92.95ms max=1.83s p(90)=97.54ms p(95)=103.37ms
iterations.......................: 12953 215.542231/s
vus..............................: 20 min=20 max=21
vus_max..........................: 21 min=21 max=21

Dado que todo está en un solo script, se permite una mayor colaboración entre los equipos y una vista unificada de las métricas de rendimiento desde una perspectiva a nivel del navegador y de protocolos.

Planes futuros

Nuestro objetivo es que xk6-browser se convierta en parte del núcleo de k6 una vez que alcance sus objetivos de estabilidad. Consideramos que la automatización del navegador es una parte importante de las pruebas de aplicaciones web, y tenemos grandes objetivos para xk6-browser. Nuestra hoja de ruta detalla las actualizaciones de estado esenciales y nuestros objetivos a corto, medio y largo plazo.

Participen!

¡Necesitamos su ayuda! Dado que xk6-browser todavía es relativamente nuevo, necesitamos la ayuda de la comunidad para probar la herramienta y que nos compartan sus comentarios al respecto.

Consulte nuestro proyecto de GitHub, lea nuestra documentación y experimente con la herramienta. Si encuentra algún problema, comuníquenoslo en nuestro proyecto de GitHub o eche un vistazo a nuestro foro de la comunidad para obtener más ayuda.

< Back to all posts