Ir al contenido

Las mismas pruebas que pasan en tu máquina se ejecutan en CI con un solo cambio: la clave de API viene de los secretos del sistema de CI. Esta página explica eso, cómo usar las direcciones para que las ejecuciones en paralelo no se estorben, un informe de los correos de cada ejecución en el pull request y cómo dar acceso a los agentes de programación en la nube.

Crea una clave en la app en Project settings → API keys (consulta claves de API) y guárdala como un secreto llamado PROXYMAIL_QA_API_KEY. En GitHub Actions:

.github/workflows/e2e.yml
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
env:
PROXYMAIL_QA_API_KEY: ${{ secrets.PROXYMAIL_QA_API_KEY }}

Otros sistemas de CI funcionan igual: una variable CI/CD enmascarada en GitLab, una variable de contexto o de proyecto en CircleCI, una variable de entorno en las credenciales de Jenkins. Mantén la clave fuera del repositorio y de los registros.

Una clave funciona dentro de un proyecto, así que dale a CI su propio proyecto (o al menos su propia clave). Así sus direcciones quedan separadas de las que usas a mano, y revocar la clave de CI no afecta a nadie.

Una dirección por ejecución, con etiquetas plus

Sección titulada «Una dirección por ejecución, con etiquetas plus»

Una cuenta Free tiene 500 direcciones en total, hasta 50 al día, que un pipeline con mucha actividad puede agotar; el plan Team no tiene límite. No necesitas una dirección nueva para cada prueba: el correo enviado a name+anything@ llega a name@, y esperar en la dirección etiquetada encuentra solo el correo enviado a esa etiqueta.

Así que crea una dirección para la ejecución y dale a cada prueba su propia etiqueta:

One address, a tag per test
// Once per run (Playwright's globalSetup, say): POST /v1/addresses
const base = 'k7f2x9ab12cd@mailclub.dev';
// In each test: sign up with a tagged version of it…
const address = base.replace('@', `+${process.env.GITHUB_RUN_ID}-${testInfo.workerIndex}-${Date.now()}@`);
// …then wait on that same tagged address.
// GET /v1/addresses/{address}/code only finds mail sent to that tag.

Con el cliente de Node.js, eso es qa.createAddress() una vez y qa.waitForCode(tagged, { since }) por prueba.

Algunas apps rechazan un + en los formularios de registro; para esas, crea una dirección por prueba. Direcciones de correo poco comunes indica qué caracteres puede contener una etiqueta.

Pasa since con la hora en que la prueba envió el formulario, para que una espera nunca recoja un correo de un paso o ejecución anterior:

const submitted = new Date();
await page.getByRole('button', { name: 'Sign up' }).click();
// GET /v1/addresses/{address}/code?since=<submitted, ISO 8601>

Cada clave puede hacer 60 solicitudes por minuto en Free y 600 en Team (límites). Una espera es una sola solicitud, dure lo que dure (hasta 30 segundos), así que unos pocos workers en paralelo en Free funcionan bien. Para suites grandes, usa el plan Team o una clave por pipeline.

Elimina las direcciones al final de la ejecución con DELETE /v1/addresses/{address}, por ejemplo en el globalTeardown de Playwright. Lo que dejes se elimina cuando vence. Eliminar una dirección base también elimina el correo enviado a sus etiquetas.

La acción de Proxy Mail QA agrupa las pruebas de correo de un job en una ejecución y publica lo que vio en el pull request: qué correos llegaron y cuánto después de que la prueba enviara el formulario, los códigos, adónde va cada enlace, las comprobaciones de correo que ejecutaste (con cuántos correos probablemente acabarían en spam, cuando las comprobaciones de spam están activadas en Labs), las comprobaciones de baja, ofertas y cupones, las pruebas que fallaron y cualquier correo que nunca llegó. El mismo informe va en el resumen del job, y cualquiera del proyecto puede abrir la ejecución en la app, donde Informe de QA de esta ejecución da las direcciones y correos de la ejecución como un informe de QA para imprimir o guardar como PDF.

.github/workflows/e2e.yml
jobs:
e2e:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v7
- uses: aaquib90/proxymail-qa-action@v1
with:
api-key: ${{ secrets.PROXYMAIL_QA_API_KEY }}
- run: npm ci
- run: npx playwright test
env:
PROXYMAIL_QA_API_KEY: ${{ secrets.PROXYMAIL_QA_API_KEY }}

La acción define PROXYMAIL_QA_RUN para los pasos posteriores. El cliente de Node.js (0.5.0 o posterior), el helper de Python y el helper de Detox y Appium lo leen, así que las llamadas que tus pruebas ya hacen se suman a la ejecución. Los demás helpers móviles lo reciben igual que la clave: una variable de entorno para XCUITest, un argumento de instrumentación para Espresso, un --dart-define para Flutter y -e para Maestro. Desde otras herramientas, envía el id en un encabezado: Proxy-Mail-QA-Run: $PROXYMAIL_QA_RUN.

Después del job, haya pasado o no, la acción termina la ejecución y publica el informe, y actualiza su comentario en cada push. Una ejecución falla cuando un correo que las pruebas esperaban nunca llegó, llegó uno cuando no debía, falló una comprobación de correo, falló una prueba, llegó marketing después de darse de baja, una persona recibió una oferta dos veces, se aceptó un cupón que no debía aceptarse o una nota lo indicó. Para que en ese caso también falle el job, aunque las pruebas hayan pasado, define fail-job: true. Las ejecuciones con el mismo nombre comparten comentario, así que dale a los jobs de matriz su propio nombre: name: e2e (${{ matrix.browser }}).

El informe también compara la ejecución con las últimas 10 ejecuciones terminadas con el mismo nombre y enumera lo que cambió: correos que tardaron mucho más de lo habitual en llegar, una prueba que ahora recibe dos correos en lugar de uno, pruebas que fallan por primera vez o de vez en cuando, comprobaciones de correo que ahora fallan, pasos (esperas, conteos, cancelación de suscripción, comprobaciones de ofertas y cupones) que pasaron la última vez y no se ejecutaron o ahora fallan, y un remitente o sitio de enlace nuevo. Mantener el mismo nombre entre ejecuciones es lo que hace que esto funcione.

Las pull requests desde forks no reciben secretos, así que ahí la acción avisa y no inicia ninguna ejecución.

@v1 sigue cada versión 1.x, así que las correcciones te llegan sin hacer ningún cambio. Para aplicar cambios solo cuando tú decidas, fija el commit de una versión, con su número en un comentario: uses: aaquib90/proxymail-qa-action@<commit> # v1.0.1. Los commits están en la página de tags, y Dependabot mantiene actualizado un commit fijado.

Una ejecución guarda las direcciones, los códigos (con el descuento de un cupón y lo que respondió el pago), los tiempos, los resultados de las comprobaciones, los nombres y errores de las pruebas fallidas, y el sitio y la ruta de cada enlace, ocultando cualquier parte de la ruta que parezca un token. Nunca guarda el texto ni el asunto de un correo, ni la query de un enlace, donde suelen estar los tokens de inicio de sesión. Las ejecuciones se guardan durante 90 días.

En otros casos (otro sistema de CI o la sesión de un agente), inicia una ejecución con POST /v1/runs, envía su id en el encabezado Proxy-Mail-QA-Run, termínala con POST /v1/runs/{id}/finish y obtén el informe con GET /v1/runs/{id}?format=markdown. Con el cliente de Node.js, son qa.startRun(), qa.finishRun() y qa.runReport(). Consulta la REST API.

El informe puede indicar a qué prueba pertenece cada correo y enumerar las pruebas que fallaron con lo que hicieron sus correos.

Playwright: importa test desde proxymail-qa/playwright y usa su fixture qa, un cliente que nombra su prueba en cada llamada, y añade el reporter, que registra las pruebas fallidas e inestables y los totales. La línea de una prueba fallida nombra el paso o la acción del navegador que falló (como At “Enter the code › locator.fill(…)”):

playwright.config.ts
export default defineConfig({
reporter: [['list'], ['proxymail-qa/playwright/reporter']],
});
signup.spec.ts
import { test, expect } from 'proxymail-qa/playwright';
test('sign-up sends one code', async ({ page, qa }) => {
const { address } = await qa.createAddress();
// …sign up, wait for the code, check the email…
});

pytest: importa los hooks del helper de Python en conftest.py:

conftest.py
from proxymail_qa import pytest_runtest_setup, pytest_runtest_teardown, pytest_runtest_logreport, pytest_sessionfinish

Pruebas móviles: cada helper móvil recibe el nombre de la prueba: ProxyMailQA(test:) en Swift, Kotlin y Dart, TEST en el env de un script de Maestro, y la prueba actual de Jest (o setTest) para Detox y Appium.

Otras herramientas envían el nombre de la prueba, codificado con porcentajes, en un encabezado Proxy-Mail-QA-Test, y los resultados a POST /v1/runs/{id}/tests (REST API). Ambos no hacen nada fuera de una ejecución y nunca hacen fallar las pruebas.

Cuando una espera vuelve vacía, la respuesta indica el motivo hasta donde Proxy Mail QA puede saberlo (hint, y refused para el correo que rechazamos). La causa habitual en CI es el proveedor de correo del entorno de staging: en modo sandbox o de prueba solo envía a direcciones verificadas, así que el correo nunca sale. GET /v1/addresses/{address}/delivery comprueba una dirección sin esperar. Más información en ¿No llega el correo de prueba?

Si todas las ejecuciones fallan a la vez, o la API responde con errores 5xx, revisa nuestra página de estado antes de cambiar tus pruebas.

Iniciar sesión en el MCP server desde el navegador requiere a una persona, así que los agentes que se ejecutan en la nube usan una clave de API, enviada como token Bearer. Dales una clave de un proyecto creado para ese fin.

Escribe la configuración de MCP en un paso antes de la acción, con la clave tomada de un secreto, y permite las herramientas que necesita el agente:

.github/workflows/claude.yml
- name: Proxy Mail QA for Claude
run: |
cat > /tmp/mcp.json << 'EOF'
{
"mcpServers": {
"proxymail-qa": {
"type": "http",
"url": "https://api.proxymail.qa/mcp",
"headers": { "Authorization": "Bearer ${{ secrets.PROXYMAIL_QA_API_KEY }}" }
}
}
}
EOF
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: |
--mcp-config /tmp/mcp.json
--allowedTools mcp__proxymail-qa__get_project,mcp__proxymail-qa__create_address,mcp__proxymail-qa__wait_for_code,mcp__proxymail-qa__wait_for_link,mcp__proxymail-qa__check_delivery,mcp__proxymail-qa__delete_address

En el Settings → Copilot → MCP servers del repositorio, añade:

{
"mcpServers": {
"proxymail-qa": {
"type": "http",
"url": "https://api.proxymail.qa/mcp",
"headers": { "Authorization": "Bearer $COPILOT_MCP_PROXYMAIL_QA_API_KEY" },
"tools": ["get_project", "create_address", "wait_for_code", "wait_for_link", "check_delivery", "delete_address"]
}
}
}

Luego añade la clave como secreto de Agents llamado COPILOT_MCP_PROXYMAIL_QA_API_KEY en el entorno copilot del repositorio: Copilot solo pasa a los servidores MCP los secretos cuyo nombre empieza por COPILOT_MCP_. El agente de programación de Copilot no puede iniciar sesión desde el navegador; por eso necesita la clave.

Para la CLI de Codex en un job de CI (codex exec), añade el servidor a ~/.codex/config.toml y define PROXYMAIL_QA_API_KEY a partir del secreto CI:

~/.codex/config.toml
[mcp_servers.proxymail-qa]
url = "https://api.proxymail.qa/mcp"
bearer_token_env_var = "PROXYMAIL_QA_API_KEY"

La documentación de Codex no indica si sus tareas en la nube pueden acceder a servidores MCP remotos. Si las tuyas no pueden, pide a Codex que llame a la REST API, con la clave de la configuración del entorno.

¿Tienes una pregunta sobre esta página?

Pregunta en cualquier idioma. La documentación puede responderte de inmediato, o puedes enviar tu pregunta al equipo de Proxy Mail QA, que responde en inglés.