MAPUO es un framework de automatización de pruebas profesional basado en Clean Architecture y el Patrón Screenplay, diseñado para soportar pruebas Web, API y móviles con integración nativa en pipelines CI/CD.
- 🎯 Patrón Screenplay: Actor → Tareas → Preguntas para pruebas altamente mantenibles
- 🏗️ Clean Architecture: Separación clara entre lógica de negocio e infraestructura
- 🔄 Dependency Injection: Gestión de dependencias con Microsoft.Extensions.DependencyInjection
- 🌐 Multi-navegador: Soporte para Chromium, Firefox y WebKit vía Playwright con configuración flexible
- 📝 BDD/Gherkin: Pruebas legibles con SpecFlow en español
- 📊 Allure Reports: Reportes interactivos y profesionales
- 🔧 CI/CD Ready: Configuración lista para GitHub Actions y Azure DevOps
- ⚙️ Configuración externa: Timeouts, navegadores y modo headless configurables vía JSON/env
- 📸 Screenshots automáticos: Captura de pantalla en fallos
MAPUO/
├── src/
│ ├── Core/ # Lógica de negocio (independiente de herramientas)
│ │ ├── Actors/ # Definición de actores
│ │ ├── Tasks/ # Tareas de negocio
│ │ ├── Questions/ # Preguntas para validaciones
│ │ └── Abilities/ # Contratos de habilidades
│ │
│ └── Infrastructure/ # Implementación concreta
│ ├── Web/ # Playwright + habilidades Web
│ ├── API/ # HttpClient + habilidades API
│ └── DI/ # Configuración de Dependency Injection
│
├── tests/
│ ├── Unit/ # Pruebas unitarias
│ ├── Integration/ # Pruebas de integración
│ └── E2E/ # Pruebas end-to-end (SpecFlow + Playwright)
│
└── .github/workflows/ # Pipelines CI/CD
Responsabilidad: Lógica de negocio y contratos (interfaces) independientes de cualquier framework o herramienta externa.
src/Core/MAPUO.Core/
├── Actors/
│ ├── IActor.cs # Interfaz del actor
│ └── Actor.cs # Implementación del actor
├── Tasks/
│ └── ITask.cs # Contrato para tareas
├── Questions/
│ └── IQuestion.cs # Contrato para preguntas
├── Abilities/
│ ├── IAbility.cs # Interfaz base de habilidades
│ ├── IWebAbility.cs # Contrato para habilidades web
│ └── IApiAbility.cs # Contrato para habilidades API
└── Models/ # Modelos de dominio (si es necesario)
Principios aplicados:
- ✅ DIP (Dependency Inversion): Solo interfaces, sin implementaciones concretas
- ✅ SRP (Single Responsibility): Cada interfaz tiene una única responsabilidad
- ✅ ISP (Interface Segregation): Interfaces específicas y cohesivas
Responsabilidad: Implementaciones concretas de las interfaces del Core utilizando herramientas específicas (Playwright, HttpClient, etc.).
src/Infrastructure/MAPUO.Infrastructure/
├── Web/
│ ├── PlaywrightWebAbility.cs # Implementación con Playwright
│ ├── Tasks/
│ │ └── GoogleTasks.cs # Tareas específicas de Google
│ └── Questions/
│ └── GoogleQuestions.cs # Preguntas específicas de Google
├── API/
│ └── RestApiAbility.cs # Implementación con HttpClient
└── DI/
└── ContainerBootstrapper.cs # Configuración de DI
MAPUO implementa el Patrón Screenplay que permite escribir pruebas expresivas y mantenibles:
// Actor con habilidades
var actor = new Actor("Juan");
actor.CanUseWebAbility(webAbility);
// Ejecutar tareas
await actor.ExecuteAsync(new LoginWithCredentials("user", "pass"));
// Hacer preguntas
var isLoggedIn = await actor.AsksForAsync(new IsUserLoggedIn());Beneficios del Patrón Screenplay:
- 🎭 Lenguaje natural: Las pruebas se leen como historias
- 🔧 Reutilización: Tareas y preguntas se pueden reutilizar
- 🧪 Mantenibilidad: Cambios en UI no afectan la lógica de negocio
- 📈 Escalabilidad: Fácil agregar nuevas funcionalidades
Asegúrate de tener instalado:
# Clonar el repositorio
git clone https://github.com/yourorg/MAPUO.git
cd MAPUO
# Cargar scripts de ejecución
. .\RunTests.ps1
# Ejecutar setup automático
Setup-ProjectEsto:
- ✅ Restaura dependencias NuGet
- ✅ Compila la solución
- ✅ Instala navegadores Playwright (Chromium, Firefox, WebKit)
# Ejecutar pruebas E2E con navegador visible
Run-E2E-Visible¡Listo! Deberías ver el navegador Chrome abrirse automáticamente.
| Comando | Descripción |
|---|---|
Run-E2E-Visible |
Pruebas E2E con navegador visible (debugging) |
Run-E2E-Headless |
Pruebas E2E modo headless (CI/CD) |
Run-Smoke-Tests |
Solo pruebas críticas (smoke) |
Run-All-Browsers |
Pruebas en Chromium + Firefox + WebKit |
Run-All-Browsers-With-Allure |
Pruebas multi-navegador con reportes Allure |
Run-With-Allure |
Pruebas con reporte Allure |
Run-By-Category -Category smoke |
Pruebas por categoría específica |
Clean-Build |
Limpiar y recompilar solución |
Setup-Project |
Configuración inicial del proyecto |
# language: es
Característica: Autenticación de Usuario
@smoke @login
Escenario: Login exitoso con credenciales válidas
Dado que el usuario está en la página de login
Cuando ingresa las credenciales válidas
Entonces debe ver el mensaje de bienvenida
Y debe ser redirigido al dashboardpublic class LoginWithCredentials : ITask
{
private readonly string _username;
private readonly string _password;
public string Description => $"Login como '{_username}'";
public LoginWithCredentials(string username, string password)
{
_username = username;
_password = password;
}
public async Task ExecuteAsync(IActor actor)
{
var web = actor.GetAbility<IWebAbility>();
await web.WaitForSelectorAsync("#username", 5000);
await web.FillAsync("#username", _username);
await web.FillAsync("#password", _password);
await web.ClickAsync("button[type='submit']");
}
}public class TheWelcomeMessageIsVisible : IQuestion<bool>
{
public string Description => "¿El mensaje de bienvenida es visible?";
public async Task<bool> AnswerAsync(IActor actor)
{
var web = actor.GetAbility<IWebAbility>();
try
{
await web.WaitForSelectorAsync(".welcome-message", 3000);
return await web.IsVisibleAsync(".welcome-message");
}
catch
{
return false;
}
}
}[Binding]
public class LoginStepDefinitions
{
private readonly IActor _actor;
public LoginStepDefinitions(ScenarioContext context)
{
_actor = context.Get<IActor>("Actor");
}
[Given(@"que el usuario está en la página de login")]
public async Task GivenUserIsOnLoginPage()
{
var web = _actor.GetAbility<IWebAbility>();
await web.NavigateToAsync("https://myapp.com/login");
}
[When(@"ingresa las credenciales válidas")]
public async Task WhenEntersValidCredentials()
{
await _actor.ExecuteAsync(
new LoginWithCredentials("admin@test.com", "Admin123!")
);
}
[Then(@"debe ver el mensaje de bienvenida")]
public async Task ThenShouldSeeWelcomeMessage()
{
var isVisible = await _actor.AsksForAsync(new TheWelcomeMessageIsVisible());
Assert.That(isVisible, Is.True, "Mensaje de bienvenida no visible");
}
}Crear tests/E2E/MAPUO.Tests.E2E/webconfig.json:
{
"Browsers": ["chromium", "firefox", "webkit"],
"DefaultTimeout": 30000,
"Headless": false,
"SlowMo": 0
}# Configuración vía environment variables
$env:BROWSER = "chromium"
$env:HEADLESS = "true"
$env:TEST_ENV = "CI"- Instalar Allure CLI:
npm install -g allure-commandline- Ejecutar pruebas con reportes:
Run-With-Allure- Ver reporte:
Open-Allure-Report- 📈 Reportes interactivos: Dashboards con gráficos y tendencias
- 🏷️ Categorización: Tests organizados por severidad, tags, features
- 📸 Evidencias: Screenshots automáticos en fallos
- 🔍 Búsqueda avanzada: Filtrar por estado, duración, tags
- 📊 Estadísticas: Métricas de ejecución y cobertura
El proyecto incluye pipelines listos para usar:
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 9.0.x
- name: Install Playwright
run: dotnet test --filter "Category=setup"
- name: Run Tests
run: dotnet test --filter "Category!=setup"
- name: Upload Allure Results
uses: actions/upload-artifact@v3
with:
name: allure-results
path: allure-results/# azure-pipelines.yml
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
version: '9.0.x'
- task: DotNetCoreCLI@2
inputs:
command: 'test'
projects: '**/*Tests.csproj'
arguments: '--configuration Release'Característica: Autenticación
@smoke
Escenario: Login exitoso
Dado que el usuario está en la página de login
Cuando ingresa "admin@test.com" y "Admin123!"
Entonces debe ver el dashboardCaracterística: Búsqueda de Productos
@regression
Escenario: Búsqueda exitosa
Dado que el usuario está en la página principal
Cuando busca "Laptop Dell XPS"
Entonces debe ver al menos 1 resultado
Y el primer resultado debe contener "Dell"Característica: Registro de Usuario
@e2e
Escenario: Registro exitoso
Dado que el usuario está en la página de registro
Cuando completa el formulario con datos válidos
Y hace clic en "Registrarse"
Entonces debe ver "Registro exitoso"
Y debe recibir un email de confirmación- Fork el proyecto
- Crear feature branch (
git checkout -b feature/AmazingFeature) - Commit cambios (
git commit -m 'Add AmazingFeature') - Push al branch (
git push origin feature/AmazingFeature) - Abrir Pull Request
Este proyecto está bajo la licencia MIT. Ver LICENSE para más detalles.
- Equipo MAPUO - Desarrollo inicial
- Microsoft Playwright Team
- SpecFlow Contributors
- Clean Architecture Community
- Screenplay Pattern Advocates
Para reportar problemas o sugerencias, por favor crear un issue.
- .NET SDK 9.0 o superior
- PowerShell 7+ (para scripts)
- Git (para clonar el repositorio)
# Clonar el repositorio
git clone https://github.com/yourorg/MAPUO.git
cd MAPUO
# Restaurar dependencias
dotnet restore
# Compilar la solución
dotnet build
# Instalar navegadores de Playwright
& ".\tests\E2E\MAPUO.Tests.E2E\bin\Debug\net9.0\playwright.ps1" installdotnet test tests/E2E/MAPUO.Tests.E2E/MAPUO.Tests.E2E.csproj$env:HEADLESS="false"
dotnet test tests/E2E/MAPUO.Tests.E2E/MAPUO.Tests.E2E.csproj$env:HEADLESS="true"
dotnet test tests/E2E/MAPUO.Tests.E2E/MAPUO.Tests.E2E.csproj$env:BROWSER="firefox" # Opciones: chromium, firefox, webkit
dotnet test tests/E2E/MAPUO.Tests.E2E/MAPUO.Tests.E2E.csproj# Ejecutar solo pruebas smoke
dotnet test --filter "Category=smoke"
# Ejecutar solo pruebas web
dotnet test --filter "Category=web"MAPUO soporta ejecución de pruebas en múltiples navegadores de forma flexible:
Edita tests/E2E/MAPUO.Tests.E2E/webconfig.json:
{
"BrowserType": "chromium",
"Headless": true,
"Browsers": ["chromium", "firefox", "webkit"]
}# Usar script PowerShell (lee configuración del JSON)
Run-All-Browsers
# O especificar navegador individual
$env:BROWSER="firefox"
dotnet test tests/E2E/MAPUO.Tests.E2E/MAPUO.Tests.E2E.csproj# En GitHub Actions
- name: Run E2E Tests
run: |
dotnet test tests/E2E/MAPUO.Tests.E2E/MAPUO.Tests.E2E.csproj
env:
BROWSER: ${{ matrix.browser }}
HEADLESS: true
strategy:
matrix:
browser: [chromium, firefox, webkit]- .NET Preview: El proyecto usa .NET 9.0 (versión preliminar). Esta advertencia desaparecerá cuando .NET 9.0 sea estable.
- Dependabot: Las dependencias se actualizan automáticamente semanalmente vía GitHub Dependabot.
El proyecto está configurado con Dependabot para mantener las dependencias actualizadas:
- 📅 Frecuencia: Semanal
- 🔄 Alcance: Todos los paquetes NuGet
- ✅ Revisión: PRs automáticas con asignación
- ✅ Versión actual: 1.57.0 (actualizada automáticamente)
- 🔄 Actualizaciones: Gestionadas por Dependabot
- 📦 Compatibilidad: Todas las versiones del framework son compatibles
Crear archivo .feature en tests/E2E/MAPUO.Tests.E2E/:
# language: es
Característica: Login de Usuario
Como usuario registrado
Quiero poder autenticarme en la aplicación
Para acceder a mi cuenta
@smoke @web
Escenario: Login exitoso con credenciales válidas
Dado que el usuario navega a la página de login
Cuando ingresa credenciales válidas
Entonces debe ser redirigido al dashboardusing MAPUO.Core.Tasks;
using MAPUO.Core.Actors;
using MAPUO.Core.Abilities;
public class LoginTask : ITask
{
private readonly string _username;
private readonly string _password;
public string Description => $"Login con usuario '{_username}'";
public LoginTask(string username, string password)
{
_username = username;
_password = password;
}
public async Task ExecuteAsync(IActor actor)
{
var webAbility = actor.GetAbility<IWebAbility>();
await webAbility.FillAsync("#username", _username);
await webAbility.FillAsync("#password", _password);
await webAbility.ClickAsync("#login-btn");
}
}using MAPUO.Core.Questions;
using MAPUO.Core.Actors;
using MAPUO.Core.Abilities;
public class TheUserIsLoggedIn : IQuestion<bool>
{
public string Description => "¿El usuario está autenticado?";
public async Task<bool> AnswerAsync(IActor actor)
{
var webAbility = actor.GetAbility<IWebAbility>();
return await webAbility.IsVisibleAsync("#user-profile");
}
}[Binding]
public class LoginStepDefinitions
{
private readonly IActor _actor;
public LoginStepDefinitions(ScenarioContext scenarioContext)
{
_actor = scenarioContext.Get<IActor>("Actor");
}
[When(@"ingresa credenciales válidas")]
public async Task WhenIngresaCredencialesValidas()
{
await _actor.ExecuteAsync(new LoginTask("user@test.com", "password123"));
}
[Then(@"debe ser redirigido al dashboard")]
public async Task ThenDebeSerRedirigidoAlDashboard()
{
var isLoggedIn = await _actor.AsksForAsync(new TheUserIsLoggedIn());
Assert.That(isLoggedIn, Is.True);
}
}| Variable | Descripción | Valores | Default |
|---|---|---|---|
HEADLESS |
Modo headless del navegador | true, false |
false |
BROWSER |
Tipo de navegador | chromium, firefox, webkit |
chromium |
Ver specflow.json para personalizar:
- Lenguaje de los features
- Manejo de errores
- Configuración de trace
Los reportes de Allure se generan automáticamente en allure-results/.
Para visualizar:
# Instalar Allure (solo una vez)
npm install -g allure-commandline
# Generar y abrir reporte
allure serve allure-resultsLos screenshots de fallos se guardan en TestResults/Screenshots/.
MAPUO soporta la generación automática de evidencias para mejorar el debugging y documentación de pruebas:
Edita tests/E2E/MAPUO.Tests.E2E/webconfig.json:
{
"RecordVideo": false,
"ScreenshotsBeforeStep": false,
"ScreenshotsAfterStep": false,
"ScreenshotsOnFailure": true,
"EvidenceBasePath": "TestResults/Evidence"
}- Video: Graba la ejecución completa del escenario (solo modo no-headless)
- Screenshots antes del paso: Captura antes de cada acción (Navigate, Click, Fill)
- Screenshots después del paso: Captura después de cada acción
- Screenshots en fallo: Siempre activo, captura cuando un escenario falla
$env:RECORD_VIDEO="true"
$env:SCREENSHOTS_BEFORE_STEP="true"
$env:SCREENSHOTS_AFTER_STEP="true"
$env:SCREENSHOTS_ON_FAILURE="true"
$env:EVIDENCE_BASE_PATH="TestResults/Evidence"TestResults/Evidence/
├── Videos/
│ ├── NombreEscenario/
│ │ ├── chromium/
│ │ └── firefox/
├── Screenshots/
│ ├── NombreEscenario/
│ │ ├── chromium/
│ │ │ ├── before_navigate/
│ │ │ ├── after_click/
│ │ │ └── failure/
# Ejecutar con video y screenshots
$env:RECORD_VIDEO="true"
$env:SCREENSHOTS_BEFORE_STEP="true"
$env:SCREENSHOTS_AFTER_STEP="true"
Run-E2E-Visible
# Ejecutar en múltiples navegadores con evidencias
Run-All-Browsers-With-Allure- SRP (Single Responsibility): Cada clase tiene una única responsabilidad
- OCP (Open/Closed): Abierto para extensión, cerrado para modificación
- LSP (Liskov Substitution): Las abstracciones son intercambiables
- ISP (Interface Segregation): Interfaces específicas y cohesivas
- DIP (Dependency Inversion): Dependencias inyectadas, no instanciadas
- Fork el proyecto
- Crear feature branch (
git checkout -b feature/AmazingFeature) - Commit cambios (
git commit -m 'Add AmazingFeature') - Push al branch (
git push origin feature/AmazingFeature) - Abrir Pull Request
Este proyecto está bajo la licencia MIT. Ver LICENSE para más detalles.
- Equipo MAPUO - Desarrollo inicial
- Microsoft Playwright Team
- SpecFlow Contributors
- Clean Architecture Community
- Screenplay Pattern Advocates
Para reportar problemas o sugerencias, por favor crear un issue.