Test, build, and share data

Preserve failure evidence

Upload test reports, screenshots, logs, and summaries even when the main test step fails.

When tests fail, the default behavior stops the job. Steps after the failing step never run. If your screenshot upload comes after npm test, you get a red run and no picture of what broke.

That sends people rerunning jobs blindly. Reruns cost minutes and sometimes hide intermittent failures.

Upload steps should use explicit conditions. if: failure() uploads only on failure. if: always() also runs on cancel unless you add extra guards.

Upload evidence even on failure

Use if: always() on upload steps that must run when tests fail:

- name: Run browser tests
  run: npm run test:e2e

- name: Upload Playwright report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: playwright-report
    path: playwright-report/
    retention-days: 7

always() runs unless the job was cancelled. You get HTML reports and screenshots from the failed run.

Be careful: always() also runs on success. That is fine for test reports. It is not fine for deploy steps.

Keep evidence focused and redacted

Do not dump every environment variable into a public artifact. Secrets can leak through build logs, .env copies, or HAR files.

Collect what a developer needs:

  • junit or HTML test report
  • one failing screenshot
  • trimmed server log

Set retention-days so old failures do not fill storage forever.

Diagnose without a local rerun

Force a browser test to fail on purpose. Open the workflow run page, download the artifact, and find the failing selector from the report alone.

If a teammate can do that without you on a call, your evidence step works.

Large video artifacts slow downloads. Prefer one PNG and a short HTML report for pull request debugging.

Try this on your own project: break one assertion, confirm the artifact still uploads, then fix the test.

Lesson completed