# Ejecuciones de Playwright con shards

> Obtén una sola ejecución de Probara para un pipeline de Playwright con shards, con merge-reports o con una ejecución compartida, y envía una suite a varios proyectos de Probara.

Fuera de GitHub Actions, cada `playwright test` crea su propia ejecución por defecto, así que cuatro
shards son cuatro ejecuciones. En GitHub Actions los shards de un mismo workflow comparten una
ejecución automáticamente
([jobs en paralelo](https://docs.probara.net/es/developers/ci-integrations/playwright/ci-providers/#jobs-en-paralelo-una-ejecución-cerrada-por-el-job-final)).
En otros entornos, para tener **una** ejecución para todo el pipeline, elige uno de estos dos patrones.
Cada job que envía resultados necesita `PROBARA_API_TOKEN`, configurado como en la
[sección de tu proveedor de CI](https://docs.probara.net/es/developers/ci-integrations/playwright/ci-providers/).

| Patrón                                                                                        | Elígelo cuando                                                                                                               |
| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| [1. Combinar los informes blob](#patrón-1-combinar-los-informes-blob)                         | Es lo más simple, y la forma propia de Playwright. Un solo job envía; si un shard falla, no queda ninguna ejecución abierta. |
| [2. Crear la ejecución, enviar desde cada shard, cerrarla](#patrón-2-compartir-una-ejecución) | Los resultados deben aparecer mientras se ejecutan los shards.                                                               |

Los workers en paralelo de un mismo `playwright test` no necesitan nada: todos envían a través del
único reporter del proceso principal, a una sola ejecución.

## Patrón 1: combinar los informes blob

Cada shard escribe un [informe blob](https://playwright.dev/docs/test-sharding#merging-reports-from-multiple-shards)
de Playwright y lo guarda como artefacto; un último job los combina con el reporter. La ejecución
combinada contiene cada intento de cada shard, con las mismas claves que una ejecución de toda la
suite, y los archivos que llevan los informes blob (capturas, trazas, archivos de
`testInfo.attach()`).

1. Registra `blob` en CI y el reporter en el resto de entornos:

   ```ts
   // playwright.config.ts
   import { defineConfig } from '@playwright/test';

   export default defineConfig({
     reporter: process.env.CI ? 'blob' : [['list'], ['@probara/playwright-reporter']],
   });
   ```

2. Ejecuta cada shard: `npx playwright test --shard=1/4` escribe `blob-report/`. Los shards no
   necesitan token.
3. Reúne cada `blob-report/` en una carpeta y combínala con el token en el entorno:

   ```bash
   npx playwright merge-reports --reporter @probara/playwright-reporter ./all-blob-reports
   ```

Para pasar opciones al reporter al combinar, ponlas en una configuración para la combinación
(`npx playwright merge-reports --config merge.config.ts ./all-blob-reports`):

```ts
// merge.config.ts
export default {
  testDir: './tests',
  reporter: [['@probara/playwright-reporter', { projectId: 'SHOP', run: { tags: ['sharded'] } }]],
};
```

Mantén `testDir` igual que en `playwright.config`: las claves son relativas a él. Los workflows
completos están en las secciones de
[GitHub Actions](https://docs.probara.net/es/developers/ci-integrations/playwright/ci-providers/#jobs-con-shards-en-github-actions),
[GitLab CI](https://docs.probara.net/es/developers/ci-integrations/playwright/ci-providers/#jobs-con-shards-en-gitlab-ci) y
[Bitbucket Pipelines](https://docs.probara.net/es/developers/ci-integrations/playwright/ci-providers/#bitbucket-pipelines).

## Patrón 2: compartir una ejecución

Crea la ejecución, envía desde cada shard y ciérrala:

1. Un primer job ejecuta `probara run create`, que crea una ejecución automatizada vacía e imprime
   su ULID en stdout.
2. Cada shard se ejecuta con ese ULID en `PROBARA_RUN_ULID`. Un shard nunca cierra una ejecución que
   no creó, así que todos envían a la ejecución abierta. Probara concilia los shards que envían en
   el mismo momento: ningún caso se añade dos veces a la ejecución.
3. Un último job ejecuta `probara run close`, después de todos los shards, **incluso cuando alguno
   falló**.

En un shell, el flujo completo es:

```bash
PROBARA_RUN_ULID=$(npx @probara/cli run create)
export PROBARA_RUN_ULID
npx playwright test --shard=1/2
npx playwright test --shard=2/2
npx @probara/cli run close
```

Asigna el ULID en su propia línea: `export PROBARA_RUN_ULID=$(...)` ocultaría una creación fallida.
En CI, los jobs de abajo fijan la versión de la CLI (`npx --yes @probara/cli@0.2`), que no es una
dependencia del reporter; con `@probara/cli` en tus `devDependencies`, `npx @probara/cli` después de
`npm ci` ejecuta la versión del lockfile.
`probara` es la [CLI de Probara](https://docs.probara.net/es/developers/cli/); usa el mismo token y el mismo proyecto. Las
opciones de una ejecución nueva van a `run create` (`--run-name`, `--environment`, `--milestone`,
`--plan`, `--tag`...), porque los shards reutilizan la ejecución e ignoran sus propias opciones de
ejecución.

### GitHub Actions

```yaml
jobs:
  probara-run:
    runs-on: ubuntu-latest
    outputs:
      ulid: ${{ steps.create.outputs.ulid }}
    env:
      PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
      PROBARA_PROJECT: SHOP
      # A fork's build gets no secret: reporting off, so run create prints nothing and exits 0.
      PROBARA_ENABLED: ${{ secrets.PROBARA_API_TOKEN != '' }}
    steps:
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - id: create
        run: |
          ulid=$(npx --yes @probara/cli@0.2 run create)
          echo "ulid=$ulid" >> "$GITHUB_OUTPUT"

  test:
    needs: probara-run
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shardIndex: [1, 2, 3, 4]
        shardTotal: [4]
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
        env:
          PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
          PROBARA_PROJECT: SHOP
          PROBARA_RUN_ULID: ${{ needs.probara-run.outputs.ulid }}

  close-probara-run:
    needs: [probara-run, test]
    if: always() && needs.probara-run.outputs.ulid != ''
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npx --yes @probara/cli@0.2 run close
        env:
          PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
          PROBARA_PROJECT: SHOP
          PROBARA_RUN_ULID: ${{ needs.probara-run.outputs.ulid }}
```

Sin token, la CLI termina con código 2, así que el primer job define `PROBARA_ENABLED` según esté o
no el secreto: en el build de un fork, `run create` no imprime nada y termina con código 0, los
shards no envían nada y el job de cierre se omite.

### GitLab CI

Un artefacto dotenv pasa el ULID a cada job posterior:

```yaml
stages:
  - test

create-probara-run:
  stage: .pre
  image: node:22
  variables:
    PROBARA_PROJECT: SHOP
  rules:
    - if: $PROBARA_API_TOKEN
  script:
    - PROBARA_RUN_ULID=$(npx --yes @probara/cli@0.2 run create)
    - echo "PROBARA_RUN_ULID=$PROBARA_RUN_ULID" > probara.env
  artifacts:
    reports:
      dotenv: probara.env

playwright:
  stage: test
  image: mcr.microsoft.com/playwright:v1.56.1-noble
  parallel: 4
  variables:
    PROBARA_PROJECT: SHOP
  script:
    - npm ci
    - npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL

close-probara-run:
  stage: .post
  image: node:22
  variables:
    PROBARA_PROJECT: SHOP
  rules:
    - if: $PROBARA_API_TOKEN
      when: always
  script:
    - npx --yes @probara/cli@0.2 run close
```

`.pre` y `.post` son la primera y la última etapa integradas en GitLab; `when: always` cierra la
ejecución incluso después de shards fallidos. CircleCI, Azure Pipelines y Buildkite usan el mismo
patrón: consulta sus
[secciones de proveedores de CI](https://docs.probara.net/es/developers/ci-integrations/playwright/ci-providers/).

### Si el cierre nunca se ejecutó

Una ejecución sigue abierta hasta que se cierra. Ciérrala a mano, con el ULID del registro del job
de creación:

```bash
npx @probara/cli run close --run-ulid 01J9Z3K4M5N6P7Q8R9S0T1V2W3
```

## Qué patrón pierde menos

| Algo sale mal                    | Patrón 1 (combinar)                                         | Patrón 2 (ejecución compartida)                                                                                                                                                        |
| -------------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Un shard falla antes de terminar | Falta su informe blob; el resto se envía                    | Sus resultados hasta ese momento están en la ejecución                                                                                                                                 |
| Probara no está accesible        | El job de combinación no consigue enviar; vuelve a lanzarlo | El [archivo de resultados](https://docs.probara.net/es/developers/ci-integrations/playwright/results-and-retries/#archivo-de-resultados) de cada shard lo conserva (un archivo hermano en un disco compartido) |
| El job de cierre no se ejecuta   | No hay nada que cerrar                                      | La ejecución queda abierta: ciérrala a mano                                                                                                                                            |

## Varios proyectos de Probara

Una suite de Playwright puede contener las pruebas de varios proyectos de Probara: una suite
end-to-end compartida cuyos casos están en `SHOP`, `WEB` y `API`. Lista los otros proyectos en
`projects` (`PROBARA_PROJECTS=WEB,API`), y cada resultado va al proyecto de su caso, a una ejecución
de ese proyecto.

```ts
reporter: [['@probara/playwright-reporter', { projectId: 'SHOP', projects: ['WEB'] }]],
```

```ts
// tests/shared.spec.ts
import { test } from '@playwright/test';

test('SHOP-12 pays', async () => {});

test('WEB-3 shows the landing page', async () => {});

test(
  'answers the health check',
  { annotation: { type: 'probara_case', description: 'API-7' } },
  async () => {},
);

test('opens the help', async () => {});
```

```text
$ npx playwright test
[probara] Did not send the results linked to cases of API: API is neither the project (SHOP) nor one of projects (PROBARA_PROJECTS) (first seen in "answers the health check"; repeats are logged at debug)
[probara] Sending 3 results of 3 tests (3 passed, 0 failed, 0 skipped, 0 blocked); 1 linked only to cases of unlisted projects
[probara] Recorded 2 results (1 new case, 0 unmatched) in R-1 of SHOP (closed): https://app.probara.net/projects/SHOP/runs/R-1
[probara] Recorded 1 result (0 new cases, 0 unmatched) in R-2 of WEB (closed): https://app.probara.net/projects/WEB/runs/R-2
```

### Qué va a dónde

- **Según el proyecto del caso.** Un resultado vinculado a `WEB-3` va a una ejecución de `WEB`. Los
  IDs de cada proyecto listado también se vinculan desde los títulos, y salen de la clave, igual que
  los del proyecto configurado.
- **Una prueba vinculada a casos de varios proyectos** se envía una vez por caso, cada una a su
  proyecto, con sus archivos subidos a cada resultado.
- **Una prueba sin caso** va al proyecto configurado (`projectId`), donde se busca por su clave o se
  crea: las claves de automatización pertenecen a un proyecto, así que solo el proyecto configurado
  crea casos, bajo `suiteUlid`.
- **Un caso de un proyecto que no está listado** no se envía: acabaría en el proyecto equivocado,
  donde Probara rechaza su ID. Una advertencia por proyecto lo indica, y el recuento del registro
  deja fuera esos intentos. Lista el proyecto para enviarlo.

### Una ejecución por proyecto

Cada proyecto listado tiene su propia ejecución, creada con su primer resultado (un proyecto sin
resultados no tiene ejecución), con el mismo nombre, descripción, entorno (por nombre), etiquetas y
origen de CI que la del proyecto configurado, y cerrada al final como cualquier ejecución que crea
el reporter.

El hito, el plan y las configuraciones son entidades de planificación de un proyecto: un nombre que
existe en `SHOP` puede no existir en `WEB`, donde Probara rechazaría todo el informe. Por eso
`run.milestone`, `run.plan` y `run.configurations`, igual que sus formas con ULID
(`run.milestoneId`, `run.configurationUlids`, `run.environmentId`), solo van con la ejecución del
proyecto configurado, y una advertencia los nombra. Para dar los suyos a la ejecución de otro
proyecto, créala antes y reutilízala:

```bash
WEB_RUN=$(npx @probara/cli run create --project WEB --milestone "Web sprint 4")
PROBARA_RUN_ULIDS="WEB=$WEB_RUN" PROBARA_PROJECTS=WEB npx playwright test
```

`run.ulids` (`PROBARA_RUN_ULIDS=SHOP=<ulid>,WEB=<ulid>`) nombra la ejecución que reutilizar en cada
proyecto; la entrada del proyecto configurado cuenta como `run.ulid`. Una ejecución reutilizada
queda abierta salvo que `closeRun` sea `true`: ciérrala con
`probara run close --project WEB --run-ulid <ulid>`.

### Jobs con shards y varios proyectos

Crea una ejecución por proyecto antes de los shards, pásalas todas en `PROBARA_RUN_ULIDS` y ciérralas
después del último shard:

```bash
SHOP_RUN=$(npx @probara/cli run create)
WEB_RUN=$(npx @probara/cli run create --project WEB)
export PROBARA_PROJECTS=WEB PROBARA_RUN_ULIDS="SHOP=$SHOP_RUN,WEB=$WEB_RUN"
npx playwright test --shard=1/2
npx @probara/cli run close --run-ulid "$SHOP_RUN"
npx @probara/cli run close --project WEB --run-ulid "$WEB_RUN"
```

Si se reutiliza la ejecución del proyecto configurado pero un proyecto listado no tiene ejecución en
`run.ulids`, cada shard crea su propia ejecución en ese proyecto, y una advertencia lo indica.

### Fallos

Un informe fallido solo detiene su proyecto: los demás siguen. El registro nombra el proyecto de
cada error (`WEB: ...`), y un
[archivo de resultados](https://docs.probara.net/es/developers/ci-integrations/playwright/results-and-retries/#archivo-de-resultados)
conserva lo que cada proyecto no pudo enviar, con la ejecución a la que vuelve: un solo archivo para
toda la ejecución, que `probara import results 'probara-results*.json'` envía a cada proyecto.

Siguiente: [proveedores de CI](https://docs.probara.net/es/developers/ci-integrations/playwright/ci-providers/), o la
[referencia de `probara run create` y `run close`](https://github.com/cynch-me/probara-sdk/blob/main/packages/cli/docs/commands.md#probara-run-create)
(en inglés).
