@cevek/screentest 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # screentest
2
+
3
+ Local desktop tool for visual screenshot-test review. Takes a JSON tree of
4
+ diffs as input, serves a React UI on `127.0.0.1`, lets a human accept new /
5
+ changed snapshots one-by-one or in bulk. Accepted screenshots are uploaded to
6
+ your Cloudflare Worker (R2) and the diff is written back into your project's
7
+ `snapshot.json`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm i -D @cevek/screentest
13
+ # or pnpm add -D @cevek/screentest / yarn add -D @cevek/screentest
14
+ ```
15
+
16
+ `screentest` is a CLI — no library API. The package installs a single
17
+ `screentest` bin into `node_modules/.bin/`.
18
+
19
+ ## Run
20
+
21
+ ```bash
22
+ screentest <doc-json-path> [--port 5174] [--no-open]
23
+ [--worker-url <url>] [--token <token>]
24
+ ```
25
+
26
+ `doc.json` is the input describing what to review. See the
27
+ [input format](#input-format-docjson) below.
28
+
29
+ Env vars:
30
+
31
+ | Var | Default |
32
+ | ----------------------- | ----------------------------------------- |
33
+ | `CLOUDFLARE_WORKER_URL` | `https://screentests.x-cevek.workers.dev` |
34
+ | `CLOUDFLARE_TOKEN` | `SECRET_123` |
35
+
36
+ You almost certainly want to point these at your own R2-backed Worker. See
37
+ the worker template at <https://github.com/x-cevek/screentest/tree/main/cloudflare-worker>.
38
+
39
+ ## Hotkeys
40
+
41
+ | Key | Action |
42
+ | ------------------------------ | --------------------------------------- |
43
+ | `↑` / `↓` | Previous / next pending test |
44
+ | `Enter` | Accept current (if valid) |
45
+ | `Cmd/Ctrl + wheel` over canvas | Move comparison slider |
46
+ | Hold mouse on **Show diff** | Purple-pixel overlay (change-type only) |
47
+
48
+ ## Input format: doc.json
49
+
50
+ ```json
51
+ {
52
+ "groups": [
53
+ {
54
+ "name": "team",
55
+ "items": [
56
+ {
57
+ "name": "login",
58
+ "type": "new",
59
+ "actualFilename": "actual/team/login.png",
60
+ "patchSnapshotJsonFile": "/abs/path/to/snapshot.json"
61
+ },
62
+ {
63
+ "name": "page",
64
+ "type": "change",
65
+ "expectedHash": "aaa…(64 hex chars)…",
66
+ "actualFilename": "actual/team/page.png",
67
+ "patchSnapshotJsonFile": "/abs/path/to/snapshot.json"
68
+ },
69
+ {
70
+ "name": "deprecated-banner",
71
+ "type": "deleted",
72
+ "expectedHash": "bbb…(64 hex chars)…",
73
+ "patchSnapshotJsonFile": "/abs/path/to/snapshot.json"
74
+ }
75
+ ]
76
+ }
77
+ ]
78
+ }
79
+ ```
80
+
81
+ Three test-item types:
82
+
83
+ - **`new`** — `actualFilename` required. On accept, hashes the file (SHA-256
84
+ hex), uploads it to Cloudflare, inserts `{ name, hash }` into the snapshot
85
+ file.
86
+ - **`change`** — both `actualFilename` and `expectedHash` required. Tool shows
87
+ expected vs actual with a slider + purple-pixel diff overlay. On accept, same
88
+ as `new` (re-hash, re-upload, update the entry).
89
+ - **`deleted`** — `expectedHash` required, no `actualFilename`. Tool shows the
90
+ expected image plus a "this will be removed" plate. On accept, removes the
91
+ entry from the snapshot file and prunes any group that becomes empty.
92
+
93
+ Paths in `actualFilename` are resolved relative to the doc.json directory.
94
+ `patchSnapshotJsonFile` can be relative or absolute.
95
+
96
+ ## Snapshot file format
97
+
98
+ What the tool writes into `patchSnapshotJsonFile`:
99
+
100
+ ```json
101
+ {
102
+ "groups": [
103
+ {
104
+ "name": "team",
105
+ "items": [
106
+ { "name": "login", "hash": "aaa…(64 hex chars)…" },
107
+ { "name": "page", "hash": "bbb…(64 hex chars)…" }
108
+ ]
109
+ }
110
+ ]
111
+ }
112
+ ```
113
+
114
+ Writes are atomic (tmp file + rename) and serialized by a per-file mutex
115
+ inside the server, so concurrent accepts don't race.
116
+
117
+ ## How tests produce doc.json
118
+
119
+ The tool does NOT capture screenshots — it only reviews them. Producing the
120
+ actual screenshots and the doc.json is your test runner's job. The simplest
121
+ pattern:
122
+
123
+ 1. In each test, take a screenshot with Playwright; save to a known path; hash
124
+ it; compare to the entry in `snapshot.json` for that test. Fail the test
125
+ on mismatch.
126
+ 2. On failure (locally), run a script that walks the captured screenshots,
127
+ diffs them against `snapshot.json` (new / change / deleted), and writes a
128
+ `doc.json`.
129
+ 3. Spawn `screentest doc.json`. User reviews and accepts.
130
+
131
+ See the [example test-runner setup](https://github.com/x-cevek/screentest/tree/main/test-project)
132
+ for a reference implementation (Vitest + Playwright + helpers).
133
+
134
+ ## Security
135
+
136
+ - Server listens only on `127.0.0.1` — never on `0.0.0.0`.
137
+ - `actual` files are served strictly from a whitelist computed from
138
+ `doc.json` at startup. No path-traversal possible from the HTTP layer.
139
+ - Stays in-process; no daemon, no auto-update.
140
+
141
+ ## Cloudflare Worker
142
+
143
+ The Worker is the blob store. It stores accepted screenshots keyed by their
144
+ SHA-256 hash and serves them back on subsequent reviews. See the
145
+ [worker template + wrangler config](https://github.com/x-cevek/screentest/tree/main/cloudflare-worker)
146
+ for the minimal implementation backed by R2.