Skip to content

feat(attachments): let automated tests attach logs, HAR files, videos, traces and HTML - #133

Merged
snevesbarros merged 2 commits into
masterfrom
claude/angles-dashboard-sdet-features-g34tzr
Oct 3, 2026
Merged

snevesbarros merged 2 commits into
masterfrom
claude/angles-dashboard-sdet-features-g34tzr

Conversation

@snevesbarros

Copy link
Copy Markdown
Collaborator

Summary

Automated tests can now attach files to their results and have them shown on the execution: console logs, network HAR files, videos, Playwright traces, page HTML snapshots and images.

A test only creates its execution when it finishes (or, in batch mode, when the whole run finishes), so files are uploaded against the build while the test runs, the same way screenshots are. The execution then lists the returned ids when it's saved, either for the whole test or on a step.

API

  • POST /build/:buildId/attachment (multipart field attachment). The kind and the type the file is served with come from the file extension, never from the client's mime type:

    • .log / .txt: log
    • .json: json
    • .har: har
    • .webm / .mp4: video
    • .zip: trace when the name contains "trace", otherwise archive
    • .html / .htm: html
    • .png / .jpg / .jpeg / .gif / .webp: image

    Any other extension is rejected with a 400. The size limit is ANGLES_ATTACHMENT_MAX_SIZE_MB (default 100). The response never includes server paths.

  • attachments on an execution, and on a step's attachments, for both POST /execution and PUT /build/:id/executions. Ids that weren't uploaded against the execution's own build are dropped. The rest are linked to the execution when it's saved, so an execution can never claim another build's (or team's) file. Malformed ids return a 422.

  • GET /attachment?executionId= and ?buildId= list a test's or a build's attachments (metadata only).

  • GET /attachment/:id/file serves files with X-Content-Type-Options: nosniff and Content-Security-Policy: sandbox. HTML snapshots, traces and archives are always served as downloads, so a snapshot's scripts never run on the API origin with the viewer's session. Range requests work, so videos can be seeked. Add ?download=true to force a download.

  • Clean-up:

    • DELETE /attachment/:id also removes the file's references from executions and steps.
    • Deleting an execution deletes the files it claimed.
    • Deleting a build, by hand or through the nightly clean-up, deletes all of its files.

Also

  • Documents the endpoints in swagger.json and adds docs/test-attachments.md.
  • Adds the build and execution attachment indexes to setup/mongo-init.js and the Kubernetes init script.
  • Exposes ANGLES_ATTACHMENT_MAX_SIZE_MB in docker-compose.yml and the Kubernetes ConfigMap.

Compatibility

Every execution response now includes an attachments array. Released clients are unaffected: the Java client's Gson ignores unknown fields, the Python client returns plain dicts, and in JavaScript an extra property is harmless.

Related PRs (merge this one first)

  • UI: AnglesHQ/angles-ui (same branch name): attachment chips and a viewer for each kind
  • Clients (same branch name): angles-javascript-client, angles-java-client, angles-python-client, which add attachFile / attach_file and friends
  • Docs: angleshq.github.io

Testing

  • New test/test-attachment.tests.js (24 tests) covers:
    • every kind, server-generated names and no server paths in responses
    • unsupported types, missing files, unknown builds and other teams
    • linking from POST /execution and from batches
    • dropping foreign ids, and ids posted with a new build
    • listing, and the file headers, downloads and range requests
    • reference clean-up on attachment delete, and file clean-up on execution and build delete
  • Ran the full suite against a local MongoDB: 573 passing (549 before, plus 24 new). npx eslint app test is clean.
  • Exercised end to end with the new UI and all three clients against a running instance, using a real video, trace and HAR that Playwright recorded.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KgQXSUjuLVXmLWxobnMfSf


Generated by Claude Code

…, traces and HTML

Automated tests can now upload files with their results and show them on the
execution:

- POST /build/:buildId/attachment stores a file against the build while the
  test runs (the execution does not exist yet, the same reason screenshots
  hang off the build). The kind and the type it is served with come from the
  file extension, never the client's mime type: log/txt, json, har,
  webm/mp4, zip (trace or archive), html/htm and images. The size limit is
  ANGLES_ATTACHMENT_MAX_SIZE_MB (default 100).
- Executions list the returned ids in `attachments`, or on a step's
  `attachments`, for POST /execution and PUT /build/:id/executions. Ids
  that were not uploaded against the execution's own build are dropped, and
  the rest are linked to the execution when it is saved.
- GET /attachment?executionId= or ?buildId= lists them without server paths.
- Files are served with nosniff and a sandbox CSP. HTML snapshots, traces
  and archives are always downloads, so a snapshot's scripts never run on the
  API origin. Range requests work, so videos can be seeked.
- Deleting an attachment removes its references; deleting an execution or
  build (including the nightly clean-up) removes its files.

Also documents the endpoints in swagger.json and docs/test-attachments.md,
adds the attachment indexes to the Mongo init scripts, and exposes the size
limit in docker-compose and the Kubernetes config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KgQXSUjuLVXmLWxobnMfSf
@snevesbarros
snevesbarros merged commit 34c945f into master Oct 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants