¿Qué es Lighthouse?
Lighthouse es una herramienta automatizada de código abierto de Google para mejorar la calidad de páginas web. Proporciona auditorías integrales de rendimiento, accesibilidad, progressive web apps, SEO y mejores prácticas. Para ingenieros QA, Lighthouse es esencial para validar que las aplicaciones cumplan estándares modernos de rendimiento web, especialmente Core Web Vitals — las métricas clave de Google para experiencia de usuario.
Por qué Lighthouse Importa para QA
- Core Web Vitals Impactan SEO - Google usa LCP, FID y CLS como factores de ranking
- Validación de Experiencia de Usuario - Cuantifica el rendimiento percibido con métricas reales
- Integración CI/CD - Automatiza pruebas de regresión de rendimiento en pipelines
- Insights Accionables - Obtén recomendaciones específicas para mejoras de rendimiento
- Rendimiento Móvil - Prueba diseño responsive y problemas específicos de móvil
Las pruebas de rendimiento con Lighthouse se complementan perfectamente con pruebas de rendimiento de APIs para validar tiempos de respuesta del backend. Integrar Lighthouse en tu pipeline CI/CD como parte de una estrategia de testing continuo asegura que las regresiones de rendimiento se detecten automáticamente antes de llegar a producción.
Core Web Vitals Explicados
Core Web Vitals son tres métricas clave que miden la experiencia de usuario en el mundo real:
1. Largest Contentful Paint (LCP)
Qué mide: Rendimiento de carga - cuando el elemento de contenido más grande se vuelve visible.
Umbrales:
- Bueno: ≤ 2.5 segundos
- Necesita Mejora: 2.5 - 4.0 segundos
- Pobre: > 4.0 segundos
Problemas Comunes:
// Problema: JavaScript bloqueante de renderizado
<script src="analytics.js"></script>
// Solución: Diferir scripts no críticos
<script src="analytics.js" defer></script>
// Problema: Imágenes no optimizadas
<img src="hero-10mb.jpg" alt="Hero">
// Solución: Formatos modernos + imágenes responsive
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero" loading="lazy">
</picture>
Estrategias de Optimización:
- Usar CDN para assets estáticos
- Implementar lazy loading para imágenes below-fold
- Precargar recursos críticos:
<link rel="preload" href="hero.jpg" as="image"> - Optimizar tiempos de respuesta del servidor (TTFB < 600ms)
- Usar resource hints:
dns-prefetch,preconnect
2. First Input Delay (FID) / Interaction to Next Paint (INP)
Qué mide: Interactividad - retraso entre interacción del usuario y respuesta del navegador.
Umbrales FID (siendo reemplazado por INP):
- Bueno: ≤ 100ms
- Necesita Mejora: 100 - 300ms
- Pobre: > 300ms
Umbrales INP (nueva métrica desde 2024):
- Bueno: ≤ 200ms
- Necesita Mejora: 200 - 500ms
- Pobre: > 500ms
Problemas Comunes:
// Problema: Tareas largas de JavaScript bloquean el hilo principal
function processHugeDataset() {
// Loop síncrono procesando 100k items
for (let i = 0; i < 100000; i++) {
heavyCalculation(data[i]);
}
}
// Solución: Dividir en chunks pequeños con setTimeout
async function processHugeDataset() {
const chunkSize = 1000;
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.slice(i, i + chunkSize);
chunk.forEach(item => heavyCalculation(item));
// Ceder al navegador cada chunk
await new Promise(resolve => setTimeout(resolve, 0));
}
}
// Solución: Usar Web Workers para cálculos pesados
// main.js
const worker = new Worker('calculator.worker.js');
worker.postMessage({ data: largeDataset });
worker.onmessage = (e) => {
displayResults(e.data);
};
// calculator.worker.js
self.onmessage = (e) => {
const results = heavyCalculation(e.data);
self.postMessage(results);
};
Estrategias de Optimización:
- Dividir tareas largas en chunks pequeños (< 50ms cada uno)
- Usar code splitting para reducir tamaño de bundle JavaScript
- Diferir scripts de terceros
- Implementar service workers para mejor caching
- Usar
requestIdleCallbackpara trabajo no urgente
3. Cumulative Layout Shift (CLS)
Qué mide: Estabilidad visual - cambios inesperados de layout durante carga de página.
Umbrales:
- Bueno: ≤ 0.1
- Necesita Mejora: 0.1 - 0.25
- Pobre: > 0.25
Problemas Comunes:
<!-- Problema: Imágenes sin dimensiones -->
<img src="product.jpg" alt="Product">
<!-- Solución: Siempre especificar width/height -->
<img src="product.jpg" alt="Product" width="800" height="600">
<!-- Problema: Inserción dinámica de contenido -->
<div id="banner"></div>
<script>
// Carga ad asíncronamente, empujando contenido hacia abajo
loadAdvertisement('#banner');
</script>
<!-- Solución: Reservar espacio para contenido dinámico -->
<div id="banner" style="min-height: 250px;">
<!-- Ad se carga aquí sin layout shift -->
</div>
/* Problema: Web fonts causan layout shift (FOIT/FOUT) */
@font-face {
font-family: 'CustomFont';
src: url('custom-font.woff2') format('woff2');
}
/* Solución: Usar font-display para controlar comportamiento de carga */
@font-face {
font-family: 'CustomFont';
src: url('custom-font.woff2') format('woff2');
font-display: swap; /* Mostrar fallback inmediatamente, intercambiar cuando cargue */
}
/* Mejor: Precargar fuentes críticas */
/* En HTML: <link rel="preload" href="custom-font.woff2" as="font" crossorigin> */
Estrategias de Optimización:
- Siempre incluir atributos de tamaño en imágenes y videos
- Reservar espacio para ads y embeds con
min-height - Evitar insertar contenido arriba de contenido existente
- Usar animaciones
transformen lugar de propiedades que disparan layout - Precargar fuentes personalizadas y usar
font-display: swap
Ejecutar Pruebas Lighthouse
1. Chrome DevTools (Pruebas Manuales)
# Abrir Chrome DevTools
# 1. Presionar F12 o Cmd+Option+I
# 2. Ir a pestaña "Lighthouse"
# 3. Seleccionar categorías (Performance, Accessibility, etc.)
# 4. Elegir dispositivo (Mobile/Desktop)
# 5. Hacer clic en "Analyze page load"
Mejores Prácticas para Pruebas Manuales:
- Probar en modo Incógnito (sin interferencia de extensiones)
- Usar throttling para simular condiciones del mundo real (Slow 4G, 4x CPU slowdown)
- Ejecutar múltiples pruebas y promediar puntuaciones (resultados pueden variar ±5 puntos)
- Probar configuraciones móvil y desktop
2. Lighthouse CLI (Pruebas Automatizadas)
# Instalar Lighthouse
npm install -g lighthouse
# Prueba básica
lighthouse https://example.com
# Prueba móvil con formatos de salida
lighthouse https://example.com \
--output html,json,csv \
--output-path ./reports/report \
--view \
--chrome-flags="--headless"
# Prueba con throttling específico
lighthouse https://example.com \
--throttling.rttMs=150 \
--throttling.throughputKbps=1600 \
--throttling.cpuSlowdownMultiplier=4
# Probar solo categorías específicas
lighthouse https://example.com \
--only-categories=performance,accessibility
# Archivo de config personalizado
lighthouse https://example.com \
--config-path=./lighthouse-config.js
3. Lighthouse CI (Integración Continua)
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on:
pull_request:
branches: [main]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Start server
run: npm start &
- name: Wait for server
run: npx wait-on http://localhost:3000
- name: Run Lighthouse CI
run: |
npm install -g @lhci/cli
lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
- name: Upload results
uses: actions/upload-artifact@v3
with:
name: lighthouse-reports
path: .lighthouseci/
Configuración lighthouserc.json:
{
"ci": {
"collect": {
"url": ["http://localhost:3000"],
"numberOfRuns": 3,
"settings": {
"preset": "desktop",
"throttling": {
"rttMs": 40,
"throughputKbps": 10240,
"cpuSlowdownMultiplier": 1
}
}
},
"assert": {
"preset": "lighthouse:recommended",
"assertions": {
"categories:performance": ["error", {"minScore": 0.9}],
"categories:accessibility": ["error", {"minScore": 0.9}],
"first-contentful-paint": ["error", {"maxNumericValue": 2000}],
"largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
"total-blocking-time": ["error", {"maxNumericValue": 300}]
}
},
"upload": {
"target": "temporary-public-storage"
}
}
}
Interpretar Puntuaciones Lighthouse
Desglose de Puntuación de Rendimiento
La puntuación de Performance (0-100) se pondera entre múltiples métricas:
| Métrica | Peso | Descripción |
|---|---|---|
| First Contentful Paint (FCP) | 10% | Primer texto/imagen renderizado |
| Largest Contentful Paint (LCP) | 25% | Elemento de contenido más grande visible |
| Total Blocking Time (TBT) | 30% | Tiempo total que el hilo principal está bloqueado |
| Cumulative Layout Shift (CLS) | 25% | Puntuación de estabilidad visual |
| Speed Index | 10% | Qué tan rápido se muestra visualmente el contenido |
Rangos de Puntuación:
- 90-100 (Verde): Bueno - cumple mejores prácticas de rendimiento
- 50-89 (Naranja): Necesita mejora - algo de optimización requerida
- 0-49 (Rojo): Pobre - problemas significativos de rendimiento
Estrategia de Presupuesto de Rendimiento
// lighthouserc-budget.json
{
"ci": {
"assert": {
"assertions": {
// Umbrales Core Web Vitals
"largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
"total-blocking-time": ["error", {"maxNumericValue": 300}],
// Presupuestos de recursos
"resource-summary:script:size": ["error", {"maxNumericValue": 300000}],
"resource-summary:image:size": ["error", {"maxNumericValue": 500000}],
"resource-summary:stylesheet:size": ["error", {"maxNumericValue": 50000}],
"resource-summary:document:size": ["error", {"maxNumericValue": 50000}],
"resource-summary:font:size": ["error", {"maxNumericValue": 100000}],
"resource-summary:third-party:size": ["error", {"maxNumericValue": 200000}],
// Presupuestos de cantidad de solicitudes
"resource-summary:script:count": ["error", {"maxNumericValue": 15}],
"resource-summary:third-party:count": ["error", {"maxNumericValue": 10}]
}
}
}
}
Técnicas Avanzadas de Lighthouse
1. Auditorías Personalizadas
// custom-audit.js
class CustomPerformanceAudit {
static get meta() {
return {
id: 'custom-api-performance',
title: 'Tiempo de Respuesta API',
failureTitle: 'Respuestas API son lentas',
description: 'Mide tiempos de respuesta de endpoints API',
requiredArtifacts: ['devtoolsLogs']
};
}
static async audit(artifacts) {
const devtools = artifacts.devtoolsLogs.defaultPass;
const networkRecords = /* extraer registros de red */;
const apiCalls = networkRecords.filter(r =>
r.url.includes('/api/') && r.finished
);
const avgResponseTime = apiCalls.reduce((sum, call) =>
sum + call.endTime - call.startTime, 0
) / apiCalls.length;
const passed = avgResponseTime < 500; // umbral 500ms
return {
score: passed ? 1 : 0,
numericValue: avgResponseTime,
displayValue: `${Math.round(avgResponseTime)}ms promedio`,
details: {
type: 'table',
headings: [
{key: 'url', text: 'URL'},
{key: 'responseTime', text: 'Tiempo Respuesta'}
],
items: apiCalls.map(call => ({
url: call.url,
responseTime: `${Math.round(call.endTime - call.startTime)}ms`
}))
}
};
}
}
module.exports = CustomPerformanceAudit;
2. Pruebas de Flujo de Usuario (Nuevo en Lighthouse 9+)
// user-flow-test.js
import {startFlow} from 'lighthouse/lighthouse-core/fraggle-rock/api.js';
import puppeteer from 'puppeteer';
async function runUserFlow() {
const browser = await puppeteer.launch({headless: 'new'});
const page = await browser.newPage();
const flow = await startFlow(page, {name: 'Flujo checkout e-commerce'});
// Paso 1: Navegar a homepage
await flow.navigate('https://example.com', {
stepName: 'Homepage'
});
// Paso 2: Buscar producto
await flow.startTimespan({stepName: 'Interacción búsqueda'});
await page.type('#search', 'laptop');
await page.click('#search-button');
await page.waitForSelector('.search-results');
await flow.endTimespan();
// Paso 3: Página detalles producto
await flow.navigate('https://example.com/product/123', {
stepName: 'Página producto'
});
// Paso 4: Interacción añadir al carrito
await flow.startTimespan({stepName: 'Añadir al carrito'});
await page.click('#add-to-cart');
await page.waitForSelector('.cart-notification');
await flow.endTimespan();
// Paso 5: Snapshot checkout
await flow.snapshot({stepName: 'Estado página carrito'});
// Generar reporte
const report = await flow.generateReport();
fs.writeFileSync('user-flow-report.html', report);
await browser.close();
}
runUserFlow();
3. Dashboard de Monitoreo de Rendimiento
# lighthouse-monitor.py
import subprocess
import json
import datetime
from influxdb import InfluxDBClient
def run_lighthouse(url):
"""Ejecutar Lighthouse y retornar métricas"""
result = subprocess.run([
'lighthouse',
url,
'--output=json',
'--output-path=stdout',
'--chrome-flags="--headless"'
], capture_output=True, text=True)
return json.loads(result.stdout)
def extract_metrics(report):
"""Extraer métricas clave del reporte Lighthouse"""
audits = report['audits']
return {
'performance_score': report['categories']['performance']['score'] * 100,
'fcp': audits['first-contentful-paint']['numericValue'],
'lcp': audits['largest-contentful-paint']['numericValue'],
'tbt': audits['total-blocking-time']['numericValue'],
'cls': audits['cumulative-layout-shift']['numericValue'],
'speed_index': audits['speed-index']['numericValue'],
}
def send_to_influxdb(metrics, url):
"""Enviar métricas a InfluxDB para visualización Grafana"""
client = InfluxDBClient(host='localhost', port=8086, database='lighthouse')
point = {
'measurement': 'performance',
'tags': {
'url': url,
'device': 'mobile'
},
'time': datetime.datetime.utcnow().isoformat(),
'fields': metrics
}
client.write_points([point])
# Monitorear páginas cada hora
urls = [
'https://example.com',
'https://example.com/products',
'https://example.com/checkout'
]
for url in urls:
report = run_lighthouse(url)
metrics = extract_metrics(report)
send_to_influxdb(metrics, url)
print(f"✓ {url}: Puntuación Rendimiento {metrics['performance_score']}")
Cuellos de Botella Comunes y Correcciones
Problema: Bundles JavaScript Grandes
# Analizar tamaño de bundle
npm install -g webpack-bundle-analyzer
# Añadir a webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
# Build y analizar
npm run build
Soluciones:
- Code splitting:
import('./heavy-component.js').then(module => ...) - Tree shaking: Asegurar
"sideEffects": falseen package.json - Eliminar dependencias no usadas
- Usar imports dinámicos para code splitting basado en rutas
Problema: Recursos Bloqueantes de Renderizado
<!-- Problema: CSS bloqueante -->
<link rel="stylesheet" href="styles.css">
<!-- Solución: CSS crítico inline, diferir no crítico -->
<style>
/* CSS crítico above-fold inline */
.header { /* ... */ }
.hero { /* ... */ }
</style>
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
Problema: Imágenes No Optimizadas
# Instalar herramientas de optimización de imágenes
npm install -D imagemin imagemin-webp imagemin-avif
# optimize-images.js
const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');
const imageminAvif = require('imagemin-avif');
(async () => {
await imagemin(['images/*.{jpg,png}'], {
destination: 'images/optimized',
plugins: [
imageminWebp({quality: 80}),
imageminAvif({quality: 65})
]
});
})();
Conclusión
Lighthouse es una herramienta indispensable para pruebas modernas de rendimiento web. Al integrar Lighthouse en tu flujo de trabajo QA — desde auditorías manuales DevTools hasta pipelines CI/CD (como se discute en Load Testing with JMeter: Complete Guide) automatizados — aseguras que las aplicaciones cumplan estándares Core Web Vitals y entreguen experiencias excepcionales de usuario.
Conclusiones Clave:
- Enfócate en Core Web Vitals: LCP, INP/FID, CLS
- Automatiza pruebas Lighthouse en pipelines CI/CD
- (como se discute en Burp Suite for QA Engineers: Complete Security Testing Guide) Establece presupuestos de rendimiento y aplícalos
- Usa pruebas User Flow para interacciones complejas
- Monitorea rendimiento en el tiempo con dashboards
- Optimiza imágenes, JavaScript y rutas de renderizado
El rendimiento es una característica, no una reflexión tardía. Haz de las pruebas Lighthouse una parte central de tu proceso QA.
Documentacion Relacionada
- Pruebas de Rendimiento de APIs - Complementa Lighthouse con pruebas de rendimiento del backend
- Optimización de Pipelines CI/CD para Equipos QA - Integra Lighthouse en tu pipeline de entrega continua
- Testing Continuo en DevOps - Automatiza auditorías de rendimiento en cada despliegue
- Guía Completa de Playwright - Combina Lighthouse con Playwright para pruebas E2E con métricas de rendimiento
- Estrategia de Automatización de Pruebas - Incluye pruebas de rendimiento en tu estrategia de automatización