← Volver al catálogo
WebGeneraciónIntermedioGratis

Generador de Tests Playwright

Genera tests E2E de producción con Playwright a partir de una historia de usuario, URL, componente o descripción de feature, siguiendo buenas prácticas de locators y aserciones web-first. Incluye patrones reutilizables para auth, CRUD, formularios, búsqueda, navegación y mocking de APIs.

Descargar SKILL.md

Descarga abierta · sin registro · para Playwright, TypeScript, Node.js

// resultado_de_ejemplo

/**

  • Leadspark CRM — Tests E2E con Playwright
  • Cliente: Leadspark CRM (SaaS B2B gestión de leads)
  • Generado por: generar-tests-playwright (CULTIVA IA)
  • Cobertura:
    • Autenticación (login / logout)
    • CRUD de leads (crear, editar, eliminar, buscar)
    • Pipeline Kanban (drag & drop, filtro por propietario)
    • Dashboard con API mocking (éxito y error 500) */

import { test, expect, Page } from '@playwright/test';

// ───────────────────────────────────────────── // Helpers / shared data // ─────────────────────────────────────────────

const USER = { email: 'ana.garcia@leadspark.io', password: 'Cultiva2025!', };

const NEW_LEAD = { name: 'Carlos Martínez', company: 'Inversiones Solaris S.L.', email: 'cmartinez@solaris.es', phone: '+34 612 345 678', value: '12000', };

// ───────────────────────────────────────────── // SUITE 1 — Autenticación // ─────────────────────────────────────────────

test.describe('Autenticación', () => { test('debería iniciar sesión con credenciales válidas', async ({ page }) => { await page.goto('/login');

await page.getByLabel('Email').fill(USER.email);
await page.getByLabel('Contraseña').fill(USER.password);
await page.getByRole('button', { name: 'Iniciar sesión' }).click();

await expect(page).toHaveURL('/dashboard');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
await expect(page.getByText(USER.email)).toBeVisible();

});

test('debería mostrar error con credenciales incorrectas', async ({ page }) => { await page.goto('/login');

await page.getByLabel('Email').fill('falso@leadspark.io');
await page.getByLabel('Contraseña').fill('wrongpassword');
await page.getByRole('button', { name: 'Iniciar sesión' }).click();

await expect(page.getByRole('alert')).toHaveText(/credenciales incorrectas/i);
await expect(page).toHaveURL('/login');

});

test('debería mantener sesión tras recargar la página', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill(USER.email); await page.getByLabel('Contraseña').fill(USER.password); await page.getByRole('button', { name: 'Iniciar sesión' }).click(); await expect(page).toHaveURL('/dashboard');

await page.reload();
await expect(page).toHaveURL('/dashboard');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();

});

test('debería cerrar sesión y redirigir a /login', async ({ page }) => { await page.goto('/dashboard');

await page.getByRole('button', { name: 'Perfil' }).click();
await page.getByRole('menuitem', { name: 'Cerrar sesión' }).click();

await expect(page).toHaveURL('/login');
await expect(page.getByRole('heading', { name: 'Inicia sesión' })).toBeVisible();

});

test('debería redirigir rutas protegidas a /login cuando no hay sesión', async ({ page }) => { await page.goto('/leads'); await expect(page).toHaveURL('/login'); }); });

// ───────────────────────────────────────────── // SUITE 2 — Gestión de Leads (CRUD) // ─────────────────────────────────────────────

test.describe('Gestión de Leads', () => { test.use({ storageState: 'tests/e2e/.auth/ana.json' });

test('debería crear un nuevo lead correctamente', async ({ page }) => { await page.goto('/leads/new');

await page.getByLabel('Nombre completo').fill(NEW_LEAD.name);
await page.getByLabel('Empresa').fill(NEW_LEAD.company);
await page.getByLabel('Email').fill(NEW_LEAD.email);
await page.getByLabel('Teléfono').fill(NEW_LEAD.phone);
await page.getByLabel('Valor estimado (€)').fill(NEW_LEAD.value);
await page.getByRole('combobox', { name: 'Etapa' }).selectOption('Prospecto');

await page.getByRole('button', { name: 'Guardar lead' }).click();

await expect(page.getByRole('alert')).toHaveText(/lead creado/i);
await expect(page).toHaveURL(/\/leads\/\d+/);
await expect(page.getByRole('heading', { name: NEW_LEAD.name })).toBeVisible();

});

test('debería mostrar errores de validación en campos requeridos', async ({ page }) => { await page.goto('/leads/new');

await page.getByRole('button', { name: 'Guardar lead' }).click();

await expect(page.getByText('El nombre es obligatorio')).toBeVisible();
await expect(page.getByText('El email es obligatorio')).toBeVisible();

});

test('debería validar formato de email incorrecto', async ({ page }) => { await page.goto('/leads/new');

await page.getByLabel('Nombre completo').fill('Test Lead');
await page.getByLabel('Email').fill('no-es-un-email');
await page.getByRole('button', { name: 'Guardar lead' }).click();

await expect(page.getByText('Email no válido')).toBeVisible();

});

test('debería editar un lead existente', async ({ page }) => { await page.goto('/leads');

await page.getByRole('row', { name: /Inversiones Solaris/ })
  .getByRole('button', { name: 'Editar' })
  .click();

await page.getByLabel('Empresa').clear();
await page.getByLabel('Empresa').fill('Solaris Global S.A.');
await page.getByRole('button', { name: 'Guardar cambios' }).click();

await expect(page.getByRole('alert')).toHaveText(/cambios guardados/i);
await expect(page.getByText('Solaris Global S.A.')).toBeVisible();

});

test('debería eliminar un lead con confirmación de diálogo', async ({ page }) => { await page.goto('/leads');

await page.getByRole('row', { name: /Solaris Global/ })
  .getByRole('button', { name: 'Eliminar' })
  .click();

// Diálogo de confirmación
await expect(page.getByRole('dialog')).toBeVisible();
await expect(page.getByRole('dialog')).toHaveText(/¿Confirmas la eliminación/i);
await page.getByRole('button', { name: 'Sí, eliminar' }).click();

await expect(page.getByRole('alert')).toHaveText(/lead eliminado/i);
await expect(page.getByText('Solaris Global')).not.toBeVisible();

});

test('debería buscar leads por nombre', async ({ page }) => { await page.goto('/leads');

await page.getByPlaceholder('Buscar leads…').fill('Martínez');
await page.getByRole('button', { name: 'Buscar' }).click();

const rows = page.getByRole('row').filter({ hasText: 'Martínez' });
await expect(rows).not.toHaveCount(0);
await expect(page.getByText('García López')).not.toBeVisible();

});

test('debería mostrar estado vacío cuando la búsqueda no da resultados', async ({ page }) => { await page.goto('/leads');

await page.getByPlaceholder('Buscar leads…').fill('xyzimpossiblequery');
await page.getByRole('button', { name: 'Buscar' }).click();

await expect(page.getByText('No se encontraron leads')).toBeVisible();

}); });

// ───────────────────────────────────────────── // SUITE 3 — Pipeline Kanban // ─────────────────────────────────────────────

test.describe('Pipeline Kanban', () => { test.use({ storageState: 'tests/e2e/.auth/ana.json' });

test('debería mostrar las cuatro columnas del pipeline', async ({ page }) => { await page.goto('/pipeline');

for (const col of ['Prospecto', 'Contactado', 'Propuesta', 'Cerrado']) {
  await expect(page.getByRole('region', { name: col })).toBeVisible();
}

});

test('debería mover un lead a la siguiente etapa con drag & drop', async ({ page }) => { await page.goto('/pipeline');

const sourceCard = page.locator('[data-testid="kanban-card"]', { hasText: 'Carlos Martínez' });
const targetColumn = page.getByRole('region', { name: 'Contactado' });

await sourceCard.dragTo(targetColumn);

await expect(targetColumn.locator('[data-testid="kanban-card"]', { hasText: 'Carlos Martínez' })).toBeVisible();

});

test('debería filtrar el pipeline por propietario', async ({ page }) => { await page.goto('/pipeline');

await page.getByRole('combobox', { name: 'Propietario' }).selectOption('Ana García');

const allCards = page.locator('[data-testid="kanban-card"]');
const count = await allCards.count();
for (let i = 0; i < count; i++) {
  await expect(allCards.nth(i).getByText('Ana García')).toBeVisible();
}

});

test('debería mostrar el panel de detalle al hacer clic en una tarjeta', async ({ page }) => { await page.goto('/pipeline');

await page.locator('[data-testid="kanban-card"]', { hasText: 'Carlos Martínez' }).click();

await expect(page.getByRole('complementary', { name: 'Detalle del lead' })).toBeVisible();
await expect(page.getByText(NEW_LEAD.email)).toBeVisible();
await expect(page.getByText('12.000 €')).toBeVisible();

}); });

// ───────────────────────────────────────────── // SUITE 4 — Dashboard con API Mocking // ─────────────────────────────────────────────

test.describe('Dashboard — métricas con API mocked', () => { test.use({ storageState: 'tests/e2e/.auth/ana.json' });

test('debería mostrar métricas de conversión desde la API', async ({ page }) => { await page.route('**/api/metrics', (route) => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ totalLeads: 142, leadsConvertidos: 38, tasaConversion: 26.8, ingresosMes: 87500, leadsPorEtapa: { Prospecto: 62, Contactado: 41, Propuesta: 21, Cerrado: 18, }, }), }); });

await page.goto('/dashboard');

await expect(page.getByTestId('metric-total-leads')).toHaveText('142');
await expect(page.getByTestId('metric-conversion-rate')).toHaveText('26,8 %');
await expect(page.getByTestId('metric-revenue')).toHaveText('87.500 €');
await expect(page.getByRole('img', { name: 'Gráfico de pipeline' })).toBeVisible();

});

test('debería manejar error 500 de la API con mensaje amigable', async ({ page }) => { await page.route('**/api/metrics', (route) => { route.fulfill({ status: 500 }); });

await page.goto('/dashboard');

await expect(page.getByRole('alert')).toHaveText(/no se pudieron cargar las métricas/i);
await expect(page.getByRole('button', { name: 'Reintentar' })).toBeVisible();

});

test('debería reintentar la carga de métricas al hacer clic en Reintentar', async ({ page }) => { let callCount = 0;

await page.route('**/api/metrics', (route) => {
  callCount++;
  if (callCount === 1) {
    route.fulfill({ status: 500 });
  } else {
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({
        totalLeads: 58,
        leadsConvertidos: 14,
        tasaConversion: 24.1,
        ingresosMes: 32000,
      }),
    });
  }
});

await page.goto('/dashboard');
await expect(page.getByRole('alert')).toHaveText(/no se pudieron cargar/i);

await page.getByRole('button', { name: 'Reintentar' }).click();

await expect(page.getByTestId('metric-total-leads')).toHaveText('58');
await expect(page.getByRole('alert')).not.toBeVisible();

}); });

// ───────────────────────────────────────────── // SUITE 5 — Navegación y responsive // ─────────────────────────────────────────────

test.describe('Navegación y responsive', () => { test.use({ storageState: 'tests/e2e/.auth/ana.json' });

test('debería navegar entre secciones principales usando el menú lateral', async ({ page }) => { await page.goto('/dashboard');

await page.getByRole('link', { name: 'Leads' }).click();
await expect(page).toHaveURL('/leads');
await expect(page.getByRole('heading', { level: 1 })).toHaveText('Leads');

await page.getByRole('link', { name: 'Pipeline' }).click();
await expect(page).toHaveURL('/pipeline');

});

test('debería mostrar menú hamburguesa en móvil', async ({ page }) => { await page.setViewportSize({ width: 390, height: 844 }); // iPhone 14 await page.goto('/dashboard');

await expect(page.getByRole('navigation')).not.toBeVisible();
await page.getByRole('button', { name: 'Abrir menú' }).click();
await expect(page.getByRole('navigation')).toBeVisible();

});

test('debería cerrar el menú móvil al seleccionar una opción', async ({ page }) => { await page.setViewportSize({ width: 390, height: 844 }); await page.goto('/dashboard');

await page.getByRole('button', { name: 'Abrir menú' }).click();
await page.getByRole('link', { name: 'Leads' }).click();

await expect(page.getByRole('navigation')).not.toBeVisible();
await expect(page).toHaveURL('/leads');

}); });

// qué_hace

Genera tests E2E listos para producción con Playwright a partir de cualquier descripción de comportamiento o componente.

// cómo_lo_hace

Explora la configuración y convenciones del proyecto, selecciona plantillas de patrones (auth, CRUD, formularios, búsqueda) y produce archivos .spec.ts/.spec.js con locators semánticos, aserciones web-first y cobertura de casos límite.

// ejemplo_de_uso

Para equipos que quieren automatizar pruebas E2E sin escribir tests desde cero. Ej.: describir el flujo de registro de usuario y recibir un archivo .spec.ts con Playwright que cubre el happy path y los casos de error principales.

// plataformas

PlaywrightTypeScriptNode.js
Categoría
Web
Tipo
Generación
Nivel
Intermedio
Licencia
MIT
Seguridad
seguro · riesgo bajo
Versión
1.0.0

// opiniones_de_la_comunidad

Opiniones

Cargando opiniones…

// pase_cultiva_ia

Llévate todo el arsenal con el Pase

Todas las skills, prompts y automatizaciones del catálogo en un único archivo, listas para usar: un pago, acceso de por vida y las novedades que añadamos. Sin suscripción.

Pago único · IVA incluido · pago seguro con Stripe.

Acceso inmediato · si no es lo que esperabas, te devolvemos los 10 €.