Selenium vs Playwright: 28 posts, misma app, mi veredicto
12 posts de Selenium, 16 de Playwright. Misma app, mismo criterio. Qué encontré, qué prefiero, y el bug que solo uno detectó. Comparación final.
Por qué este post existe
En diciembre 2025 arranqué un framework de Selenium con Java desde cero. 12 posts después tenía 96 tests, Allure Reports, CI/CD con GitHub Actions y un reporte público en GitHub Pages.
En marzo 2026 arranqué otro framework, esta vez con Playwright y TypeScript. 16 posts después tenía 17 tests de producción en e2e/, 12 specs didácticos en learning/, HTML reporter, CI/CD, y otro reporte público.
Ambos frameworks testean la misma app: demo.serenity.is. Mismo login, misma grilla de clientes, mismo Excel de 91 registros, mismo CRUD. Las dos series documentan decisiones reales, errores reales y código que funciona en producción.
Ahora puedo comparar con experiencia real en ambos. No desde la documentación, no desde un tutorial. Desde haberlos construido yo, contra la misma app, con el mismo criterio.
Los números
Antes de opinar, los datos.
Selenium + Java
- 96 tests en Allure (pero ojo con este número, lo explico abajo)
- 36 segundos de ejecución (CI, headless)
- 12 posts en el blog
- Framework: TestNG + Allure Reports + Maven + Apache POI
- Reporte público: cesarbeassuarez.github.io/selenium-java-framework
Playwright + TypeScript
- 17 tests e2e + 12 specs didácticos
- 1.2 minutos de ejecución (CI, Chromium)
- 16 posts en el blog
- Framework: Playwright Test + HTML Reporter + npm + exceljs
- Reporte público: cesarbeassuarez.github.io/playwright-typescript-framework
Sobre los 96 vs 17: el número de Selenium es engañoso. De esos 96, 91 son filas de la grilla de clientes validadas contra Excel — cada fila es un test individual porque así funciona DataProvider en TestNG. El resto son 5 tests de login. El framework de Selenium se enfocó en login + validación de datos de grilla. Playwright expandió la cobertura a más escenarios porque la serie fue más larga y el framework lo permite nativamente.
Playwright tiene 17 tests en e2e/, pero cubren más funcionalidad: login (positivo + negativo parametrizado), validación contra Excel (1 test con 910 soft assertions), ordenamiento de grilla, filtros Select2, búsqueda, 4 tests de API nativo y visual regression. Si contara cada soft assertion de Excel como test individual (como hace Selenium con DataProvider), Playwright tendría más de 900 "tests" solo en ese spec.
El número importa menos que lo que cada framework testea. Playwright cubre más escenarios de negocio con menos tests porque soft assertions permiten validar todo dentro de un solo test sin que un fallo detenga los demás.
El bug que importa
Antes de comparar feature por feature, un caso concreto de por qué la elección de framework no es cosmética.
En el Post 9 de Playwright validé 91 clientes de la grilla contra datos de un Excel. La misma validación que hice con Selenium + Apache POI en el Post 10 de esa serie.
Playwright encontró un bug que Selenium nunca detectó: el cliente WOLZA tenía un doble espacio en el campo ContactTitle en el Excel ("Sales Manager" en vez de "Sales Manager"). Llevaba meses ahí. La suite de Selenium pasaba en verde sin chistar.
¿Por qué? Playwright y Selenium parsean el texto del DOM de manera diferente. Playwright usa textContent de forma más estricta en ciertos contextos, y la comparación contra Excel expuso el mismatch. Selenium normalizaba o ignoraba la diferencia.
No es que Selenium esté mal. Pero Playwright, por cómo maneja el text content, expuso algo que llevaba meses oculto. Eso solo ya justifica evaluar seriamente qué framework elegís para validaciones de datos.
La comparación real
No voy a comparar features en abstracto. Voy a comparar lo que viví construyendo ambos frameworks.
Setup: cuánto tardé en tener el primer test corriendo
Selenium: Necesité instalar Java 17, configurar Maven, agregar dependencias en el pom.xml (Selenium, WebDriverManager, TestNG), hacer reload de Maven, y recién ahí escribir el test. El primer test fue en el Post 1, pero para tener algo usable necesité hasta el Post 4 (config.properties, DriverManager, estructura de carpetas).
Playwright: npm init playwright@latest. Eso. En el Post 1 ya tenía 9 tests corriendo en 3 browsers contra una app real. El setup incluye el test runner, el reporter y la configuración de browsers.
La diferencia es grande. En Selenium tuve que construir infraestructura antes de testear. En Playwright la infraestructura viene incluida.
Estructura de proyecto
Selenium: separación src/main/java vs src/test/java (convención Maven). BasePage, BaseTest, ConfigReader, DriverManager, AllureScreenshot, ExcelReader, AllureListener, DataProviders en clases separadas. Antes de escribir un test de negocio, tuve que crear toda esa estructura pensando en escalabilidad.
Playwright: carpetas pages/, fixtures/, tests/, utils/, y playwright.config.ts. Sin src/main vs src/test. Sin BaseTest. Sin DriverManager. Sin ConfigReader. Los fixtures reemplazan la mitad de esas clases.
En Selenium construí ~15 archivos de infraestructura antes de tener tests de negocio. En Playwright fueron ~5.
Locators y herramientas de desarrollo
Acá es donde Playwright marca la mayor diferencia para mí.
Codegen (npx playwright codegen) es como tener dos herramientas de TestComplete en una: el Object Spy para obtener localizadores y el Record Script que graba secuencia de pasos. Abrís la app, hacés click, y Playwright te genera los locators por rol, por texto, por test-id. Son locators legibles: getByRole('button', { name: 'Ingresar' }) en vez de By.cssSelector("#btnLogin").
UI Mode (npx playwright test --ui) es lo mejor que tiene Playwright. Permite debuggear con screenshots de la app en cada paso, adelantar, retroceder, ver qué pasó exactamente. Es un time-travel debugger para tests. En Selenium no existe nada parecido — cuando un test falla, tenés que re-correrlo, poner breakpoints, mirar la consola.
En mi serie de Selenium, debugging significaba: poner System.out.println, re-ejecutar, mirar el log. En Playwright abro UI Mode y veo exactamente qué pasó, en qué paso, con screenshot incluido.
Esperas
Selenium: Tuve un post entero (Post 6) dedicado a esperas. ImplicitWait, ExplicitWait, FluentWait, por qué Thread.sleep destruye tests. Construí esperas explícitas propias en BasePage. Es algo que tenés que entender sí o sí para que los tests no sean flaky.
Playwright: No escribí ni una sola espera en 16 posts. Las assertions hacen auto-retry, los locators esperan automáticamente. El concepto de "espera" casi no existe. Funciona.
Assertions
Selenium + TestNG: Assert.assertEquals(actual, expected). Si falla, el test muere ahí. Para soft assertions tuve que armar helpers custom.
Playwright: expect(locator).toHaveText('algo') con auto-retry incluido. Soft assertions con expect.soft() nativo. En el Post 9 hice 910 comparaciones con soft assertions contra Excel — en Selenium eso requirió código custom.
Autenticación
Selenium: Login en cada test. En @BeforeMethod abro el browser, voy al login, ingreso credenciales. Cada test repite ese flow. Para optimizar tendría que serializar cookies manualmente.
Playwright: storageState. Login una vez en auth.setup.ts, cookies guardadas en JSON, todos los tests arrancan ya autenticados. Dos líneas en la config. Lo que en Selenium es código custom, acá es configuración.
Data-driven testing
Selenium + TestNG: DataProviders con Object[][]. Funciona bien, pero la lectura de Excel requiere Apache POI — una librería que no es trivial de usar.
Playwright + TypeScript: Arrays + for...of. Sin clase especial, sin framework extra. La lectura de Excel con exceljs es más directa que con Apache POI. Los DataProviders de TestNG son más formales; el approach de Playwright es más flexible.
API testing
Selenium: No tiene. Necesitás RestAssured, HttpClient, o herramientas externas. En mi caso usé Postman + Newman en una serie separada.
Playwright: request context built-in. En el Post 13 hice 4 tests de API contra demo.serenity.is sin salir del framework. storageState + CSRF token + validaciones. Sin Postman, sin RestAssured, sin herramientas extra.
Network interception
Selenium: No existe nativamente. Necesitás BrowserMob Proxy u otras herramientas externas.
Playwright: page.route() y page.on(). En el Post 14 intercepté, mockeé y bloqueé requests HTTP en un solo spec, sin mock servers ni proxies.
Visual testing
Selenium: Necesitás Ashot u otra librería externa. Configuración manual de baselines, comparación, thresholds.
Playwright: toHaveScreenshot() nativo. Golden files, diff con pixels, maxDiffPixels para tolerancia. En el Post 15 detecté un diff de 11,964 pixels entre baseline y actual. Built-in, sin librerías extra.
Reporting
Selenium: Allure Reports. Externo, requiere dependencias en Maven, anotaciones @Step, @Description, @Severity, un listener custom, y configurar el plugin de Allure para generar el reporte. El resultado es potente: screenshots en fallo, steps detallados, categorización por severidad. Pero requiere trabajo.
Playwright: HTML Reporter built-in. Cero configuración. Muestra tests, tiempos, traces, filtros por status. Menos personalizable que Allure, pero funciona sin agregar nada.
CI/CD
Ambos usan GitHub Actions + GitHub Pages para publicar reportes. La diferencia principal: en Selenium tuve 7 errores reales que resolver en CI (Post 12 de esa serie). En Playwright también hubo errores (storageState en CI, visual tests en Linux vs Windows), pero el setup base fue más directo.
Ejecución paralela
Selenium + TestNG: Configurar paralelo en testng.xml, usar ThreadLocal para el driver, asegurarte de que los tests están aislados. Es posible, pero requiere diseño previo.
Playwright: workers en la config. Aislamiento por defecto (cada test tiene su propio browser context). En el Post 12 probé con distintos workers y descubrí que 2 era el óptimo para mi máquina. Más no siempre es más rápido.
Configuración centralizada
Selenium: distribuida entre config.properties, ConfigReader.java, DriverManager.java, testng.xml, logback.xml. Son 5 archivos para lo que en Playwright es uno.
Playwright: playwright.config.ts. Todo: baseURL, locale, browsers, timeouts, retries, workers, storageState, testIgnore, reporter. Un archivo.
La tabla resumen
| Concepto | Selenium (Java) | Playwright (TypeScript) |
|---|---|---|
| Primer test funcional | Post 1 + 3 posts de infraestructura | Post 1, 9 tests en 3 browsers |
| Lifecycle de tests | @BeforeMethod / @AfterMethod + BaseTest | Fixtures ({ page }, custom fixtures) |
| Driver | DriverManager + ThreadLocal | Built-in, Playwright lo maneja |
| Auth reuse | Manual (cookies) | storageState + auth.setup.ts |
| Esperas | WebDriverWait, FluentWait (post dedicado) | Auto-waiting (no escribí ninguna) |
| Assertions | Assert.assertEquals() + helpers custom | expect() con auto-retry + soft nativo |
| Data-driven | @DataProvider + Object[][] | Arrays + for...of |
| Paralelo | testng.xml + ThreadLocal | workers en config, aislamiento por defecto |
| API testing | Herramienta externa (RestAssured, Postman) | request context built-in |
| Visual testing | Ashot (externo) | toHaveScreenshot() nativo |
| Network mock | No nativo (proxy) | page.route() built-in |
| Reporting | Allure (externo, potente) | HTML Reporter (built-in, simple) |
| Excel | Apache POI | exceljs |
| Config | 5 archivos | 1 archivo (playwright.config.ts) |
| CI/CD | Maven + GitHub Actions | npm + GitHub Actions |
| Debugging | Breakpoints + console + re-run | UI Mode (time-travel, screenshots) |
| Locators | By.id, By.cssSelector, By.xpath | getByRole, getByText, codegen |
Mi veredicto
Si mañana arranco un proyecto nuevo, empiezo con Playwright.
No por hype, no por tendencia. Por experiencia concreta con ambos.
Codegen me da lo que en TestComplete son dos herramientas separadas: Object Spy para obtener localizadores y Record Script para grabar secuencia de pasos. En Playwright es un solo comando. Y los locators que genera son por rol, legibles, mantenibles.
UI Mode es lo mejor que tiene Playwright. Debuggear con screenshots de la app en cada paso, adelantar, retroceder, ver exactamente qué pasó. Un time-travel debugger. En Selenium, debugging es poner prints y re-ejecutar.
La estructura es más simple. En Selenium necesité ~15 archivos de infraestructura antes de escribir un test de negocio. En Playwright necesité ~5. Fixtures reemplazan BaseTest + DriverManager. La config es un archivo, no cinco.
TypeScript se siente menos ceremonioso que Java. Menos boilerplate, menos configuración. Y VS Code es más liviano que IntelliJ para este tipo de proyectos.
¿Cuándo usaría Selenium? Trabajaría con Selenium sin problema. Si la empresa ya tiene un framework maduro con Selenium, sumarme a ese equipo y fortalecerlo tiene todo el sentido — migrar por migrar no es criterio técnico. Selenium es estable, está probado, tiene el ecosistema más grande, y la experiencia que tengo con Java + TestNG + Allure es directamente aplicable.
Pero para arrancar de cero, Playwright.
Dicho esto: lo que aprendí construyendo el framework de Selenium es lo que me permitió construir el de Playwright con criterio. Esperas explícitas, Page Object Model, DataProviders, Allure, CI/CD — todo eso lo entendí primero en Selenium. Playwright simplifica muchas de esas cosas, pero entenderlas a fondo primero te da una base que no se reemplaza con ningún framework. Si hoy puedo evaluar ambos con criterio real, es porque construí Selenium primero.
28 posts. Dos frameworks. Una app. Cinco meses. Cada línea de código tiene un "por qué" escrito en algún post.
Los repos:
- Selenium + Java: github.com/cesarbeassuarez/selenium-java-framework
- Playwright + TypeScript: github.com/cesarbeassuarez/playwright-typescript-framework
Los reportes:
- Allure: cesarbeassuarez.github.io/selenium-java-framework
- Playwright HTML: cesarbeassuarez.github.io/playwright-typescript-framework