Skip to content
Dashboard
Menu Integrations · Test & build reports in CI

Integrations

Test & build reports in CI

Playwright reports, coverage HTML, Storybook builds, Lighthouse runs — they all produce a folder of HTML that usually dies as a zipped artifact nobody opens. Ship it instead: one step with bitgate/ship-page-action@v1 turns it into a link on the PR.

The pattern

  • One stable URL per PR. name: pr-${{ github.event.number }} gives every pull request a named drop — each push replaces the content, the link never changes.
  • The URL lands on the PR. Add comment: true and on pull_request events the action posts a comment with the live link, updating that same comment on re-runs. Needs the pull-requests: write permission.
  • Reports clean up after themselves. Anonymous and free drops expire after 7 days — long enough for any review cycle. Paid accounts can set any ttl or none at all.

name and api-key need a paid plan — mint an sp_… key in the dashboard and store it as a repo secret. Skip both and the action deploys anonymously: a fresh random URL every run, still free.

Playwright HTML report

The whole playwright-report/ folder — traces, screenshots and all — goes up as one multi-file drop. if: always() so a red run still publishes its report:

yaml
- name: Run Playwright tests
  run: npx playwright test
- uses: bitgate/ship-page-action@v1
  if: always()
  with:
    path: playwright-report
    name: pr-${{ github.event.number }}
    api-key: ${{ secrets.SHIP_API_KEY }}
    comment: true

Don’t want to think about paths at all? engine: playwright makes the action auto-detect the report folder — see the action reference.

Coverage reports

Works the same for jest, vitest and c8 — anything that writes an HTML coverage folder (coverage/ with an index.html):

yaml
- name: Tests with coverage
  run: npx vitest run --coverage --coverage.reporter=html
- uses: bitgate/ship-page-action@v1
  if: always()
  with:
    path: coverage
    name: pr-${{ github.event.number }}
    api-key: ${{ secrets.SHIP_API_KEY }}

Storybook

A static Storybook build is just a directory — ship storybook-static/ and designers get a clickable link instead of a local build:

yaml
- name: Build Storybook
  run: npx storybook build -o storybook-static
- uses: bitgate/ship-page-action@v1
  with:
    path: storybook-static
    name: pr-${{ github.event.number }}
    api-key: ${{ secrets.SHIP_API_KEY }}

Lighthouse

Lighthouse emits a single self-contained HTML file — deploy the preview, audit it, ship the report, all in one job:

yaml
- uses: bitgate/ship-page-action@v1
  id: preview
  with:
    path: dist
    name: pr-${{ github.event.number }}
    api-key: ${{ secrets.SHIP_API_KEY }}
- name: Lighthouse audit
  run: npx lighthouse ${{ steps.preview.outputs.url }} --output=html --output-path=./lighthouse.html --chrome-flags="--headless --no-sandbox"
- uses: bitgate/ship-page-action@v1
  with:
    path: lighthouse.html
    name: pr-${{ github.event.number }}-lighthouse
    api-key: ${{ secrets.SHIP_API_KEY }}

Note the suffix on the second name — names are scoped per account, so each drop in a workflow needs its own. Anything not on GitHub? The same recipes are one curl each — see CI with plain curl.