De MFTF a Playwright para tests E2E en Magento 2
Las ventajas de los tests E2E modernos en TypeScript frente al viejo método de XML y Selenium
En esta página
Durante años mis tests de extremo a extremo (E2E) en Magento 2 estaban escritos en MFTF, el Magento Functional Testing Framework. Viene con la plataforma y cumple, pero cada test significaba escribir XML movido por Selenium por debajo: verboso, lento y difícil de depurar. Hace un tiempo trasladé ese trabajo a Playwright como alternativa a MFTF, y no pienso volver atrás. Esto es lo que cambió de verdad, característica por característica.
La forma antigua frente a la nueva
MFTF
la forma tradicional
- Tests escritos en XML
- Repartidos en muchos ficheros
- Selenium: más lento y frágil
- Depuras desde una captura
- Acoplado al core de Magento
Playwright
la forma moderna
- Tests escritos en TypeScript
- Un único fichero legible
- Auto-espera y en paralelo
- Depuras con el trace viewer
- Una dependencia independiente
El mismo objetivo — «¿sigue funcionando el checkout?» — por dos caminos muy distintos.
El resto de este artículo son, en realidad, esas filas explicadas.
XML en varios ficheros frente a un único spec de TypeScript
En MFTF un simple test de «añadir al carrito» se reparte entre un fichero de test, un fichero de sección para los selectores y un fichero de datos para el producto — todo XML, todo referenciado entre sí con claves de texto:
<!-- Test/Mftf/Test/AddToCartTest.xml -->
<test name="AddSimpleProductToCartTest">
<amOnPage url="{{SimpleProduct.urlKey}}.html" stepKey="goToProduct"/>
<waitForPageLoad stepKey="waitForProductPage"/>
<click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addToCart"/>
<waitForElementVisible selector="{{StorefrontMessagesSection.success}}" stepKey="waitForSuccess"/>
<see userInput="You added Simple Product to your shopping cart." stepKey="assertSuccess"/>
</test>El mismo test en Playwright es un único fichero, y se lee como los pasos que daría una persona:
test('añade un producto al carrito', async ({ page }) => {
await page.goto('/simple-product.html');
await page.getByRole('button', { name: 'Add to Cart' }).click();
await expect(page.getByRole('alert')).toContainText('added');
});Sin fichero de sección, sin fichero de datos, sin un stepKey en cada línea. Tu editor lo autocompleta, TypeScript
detecta las erratas y refactorizar es un rename en vez de un buscar-y-reemplazar por todo el XML.
Esperas manuales frente a auto-espera
Fíjate en lo que falta en la versión de Playwright: los pasos waitForPageLoad y waitForElementVisible. Playwright
auto-espera — un clic espera primero a que el elemento sea visible, esté habilitado y estable, y expect(...)
reintenta hasta que la aserción pasa o se agota el tiempo. En MFTF (vía Selenium) añades esas esperas a mano, y olvidar
una es la causa clásica de un test que pasa en local y falla en CI. La mayor parte de mis fallos intermitentes
simplemente desapareció.
Una captura frente al trace viewer
Esto cambió mi forma de depurar. Cuando un test de MFTF falla en CI normalmente obtienes una captura y un stack trace, y te toca adivinar. Playwright graba un trace en el primer reintento — una línea de tiempo completa que abres en local y recorres:
npx playwright show-trace trace.zipCada acción, cada petición de red, un snapshot del DOM en cada paso y la consola. En vez de reproducir el fallo, lo ves
ocurrir. También hay un modo UI en vivo (--ui) para escribir tests y un generador de código (--codegen) que
escribe los selectores por ti.
Lento y secuencial frente a rápido y en paralelo
Playwright ejecuta los tests en paralelo entre procesos de trabajo desde el primer momento, y la automatización del navegador habla directamente con Chromium en lugar de pasar por la pila de Selenium/WebDriver. En las suites que he migrado el tiempo de reloj bajó drásticamente — lo suficiente como para que correr E2E en cada push sea realista en lugar de una tarea nocturna.
Datos de prueba limpios y aislados
Lo único que vale la pena conservar de MFTF son sus data fixtures — nunca asumas que los datos «ya están ahí». Playwright lo hace elegante con las fixtures: cada test siembra exactamente lo que necesita a través de la API REST de Magento, lo usa y lo destruye después, sin esfuerzo por parte de quien escribe el test. Los ejecuto contra un entorno local de Warden que se parece mucho a producción.
Cada test siembra sus propios datos y los destruye — sin estado compartido, sin dejar nada en la base de datos.
En el spec nunca ves la fontanería. Solo pides la fixture:
test('muestra mis pedidos', async ({ authenticatedPage }) => {
// se creó un cliente nuevo y se inició sesión por ti;
// se elimina automáticamente cuando el test termina.
await authenticatedPage.goto('/customer/account/');
await expect(authenticatedPage.getByRole('heading', { name: 'My Account' })).toBeVisible();
});Sin atarse al ciclo de versiones de Magento
Como MFTF viene con la plataforma, su versión se mueve cuando Magento se mueve. Playwright es solo una dependencia de desarrollo de npm que actualizas a tu ritmo, independiente de la versión de Magento de la tienda. Una cosa menos acoplada a la actualización.
Lo único que MFTF sí tiene
Por justicia: MFTF viene con una enorme biblioteca de action groups y secciones de página ya hechas para los flujos del core, y se mantiene estrictamente dentro de las herramientas de Magento. Si eso le importa a tu equipo, sigue siendo una opción defendible. Para el trabajo que hago, nada de eso compensó la velocidad, los specs en TypeScript y el trace viewer de Playwright.
Hacerlo reutilizable
Un paso extra mereció la pena entre proyectos: moví las piezas compartidas — page objects, fixtures, el helper de la API, una configuración base y un workflow de CI — a un único paquete interno que cada tienda instala, de modo que un arreglo en un sitio llega a todas. Esa forma reutilizable está inspirada en el magento2-bdd-e2e-testing-suite de elgentos (MIT) — una estupenda suite de Playwright de código abierto para Magento 2 y Hyvä. Si estás probando una sola tienda y quieres algo ya hecho, empieza por ahí.