# CI/CD and Automated Tests

Virtual Printer is meant to be driven by test code, not only by hand. The printer is a real TCP
listener, so the code under test prints exactly the way it prints in production, and everything around
that step — creating the printer, reading the result back, injecting faults — happens over the HTTP API.

## The round trip a test makes

The HTTP/REST API exists for exactly that, and the whole round trip is scriptable with no
hardware and no browser open. A test typically does:

1. `POST /api/workspaces` — create a throwaway workspace (anonymous; returns the workspace token)
2. `POST /api/auth/login` — exchange the token for a bearer access token
3. `POST /api/printers` — create the printer; the response carries `settings.publicHost` and
   `settings.tcpListenPort`
4. **Print over raw TCP** — the code under test opens a socket to that host and port and writes its
   bytes, the same call path it uses in production
5. `GET /api/printers/{id}/documents/canvas` — read the parsed document back and assert on the
   rendered elements: text, alignment, fonts, barcodes, QR codes, images, cuts

Instead of polling in step 5, subscribe to the SSE stream
`GET /api/printers/{id}/documents/canvas/stream` and wait for the document event.

Documents come back as structured JSON rather than a picture, so assertions read the receipt the
way a person would - see [Asserting on a receipt](/docs/ci-cd/assertions). Nothing has to be scraped
out of the web interface, and nothing has to be downloaded by hand.

Also useful in tests:

- `PATCH /api/printers/{id}/operational-flags` — inject paper out, cover open, offline, error or
  paper near end, and start/stop the listener
- `PATCH /api/printers/{id}/drawers` — set the emulated cash-drawer state
- `POST /api/printers/{id}/documents/import` — replay a captured payload (base64) as if it had been
  printed, which is handy for reproducing a bug report
- `DELETE /api/printers/{id}/documents` — clear documents between test cases

The full endpoint reference, including the request and response shapes, is in
[API endpoints](/docs/api/endpoints).

## Should CI use its own workspace?

That is the simplest setup: a workspace is created anonymously in a single call, so a pipeline can
create one per run and delete it at the end (`DELETE /api/workspaces`), which keeps test documents out
of the workspace you use interactively. If you prefer a long-lived CI workspace, keep its token as a
pipeline secret and reuse the same printer — its port does not change.

