@cevek/screentest 0.3.2 → 0.3.3
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 +6 -3
- package/dist/global-setup.js +59 -11
- package/dist/index.js +14 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -159,12 +159,15 @@ Or pass `--worker-url` / `--token` to `screentest` directly.
|
|
|
159
159
|
## CI
|
|
160
160
|
|
|
161
161
|
```yaml
|
|
162
|
-
- run: npx screentest serve #
|
|
162
|
+
- run: npx screentest serve # build image + start daemon
|
|
163
163
|
- run: CI=1 npx vitest run --config vitest.screentest.config.ts
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
In `CI=1` the
|
|
167
|
-
open the UI.
|
|
166
|
+
In `CI=1` the globalSetup exits with vitest's code and never tries to
|
|
167
|
+
open the UI. Full recipe (GitHub Actions example, docker layer caching
|
|
168
|
+
to skip the ~2 min cold-start build, downloading actuals for offline
|
|
169
|
+
review, pnpm/yarn variants) is in the [CI guide on
|
|
170
|
+
GitHub](https://github.com/x-cevek/screentest/blob/main/docs/ci.md).
|
|
168
171
|
|
|
169
172
|
## Input format reference
|
|
170
173
|
|
package/dist/global-setup.js
CHANGED
|
@@ -83,7 +83,8 @@ function countLeaves(doc) {
|
|
|
83
83
|
for (const g of doc.groups) walk(g.items);
|
|
84
84
|
return n;
|
|
85
85
|
}
|
|
86
|
-
async function generateDoc(projectRoot, snapshotFile, actualDir, docFile, cacheDir) {
|
|
86
|
+
async function generateDoc(projectRoot, snapshotFile, actualDir, docFile, cacheDir, opts = {}) {
|
|
87
|
+
const detectDeletions = opts.detectDeletions ?? true;
|
|
87
88
|
const snap = await readSnapshot(snapshotFile);
|
|
88
89
|
const expectedByPath = indexSnapshot(snap);
|
|
89
90
|
const actuals = await walkActual(actualDir);
|
|
@@ -121,21 +122,24 @@ async function generateDoc(projectRoot, snapshotFile, actualDir, docFile, cacheD
|
|
|
121
122
|
});
|
|
122
123
|
summary.change++;
|
|
123
124
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
if (detectDeletions) {
|
|
126
|
+
for (const [key, hash] of expectedByPath) {
|
|
127
|
+
if (seen.has(key) || !hash) continue;
|
|
128
|
+
insertLeaf(doc, key.split("/"), {
|
|
129
|
+
type: "deleted",
|
|
130
|
+
expectedHash: hash,
|
|
131
|
+
patchSnapshotJsonFile: snapshotFile
|
|
132
|
+
});
|
|
133
|
+
summary.deleted++;
|
|
134
|
+
}
|
|
132
135
|
}
|
|
133
136
|
await fs.mkdir(cacheDir, { recursive: true });
|
|
134
137
|
await fs.writeFile(docFile, JSON.stringify(doc, null, 2));
|
|
135
138
|
const total = countLeaves(doc);
|
|
139
|
+
const deletedSummary = detectDeletions ? `deleted: ${summary.deleted}, ` : "";
|
|
136
140
|
process.stdout.write(
|
|
137
141
|
`Wrote ${docFile}
|
|
138
|
-
${total} diff${total === 1 ? "" : "s"} to review (new: ${summary.new}, change: ${summary.change},
|
|
142
|
+
${total} diff${total === 1 ? "" : "s"} to review (new: ${summary.new}, change: ${summary.change}, ${deletedSummary}unchanged: ${summary.unchanged}${detectDeletions ? "" : "; deletion detection disabled \u2014 subset run"})
|
|
139
143
|
`
|
|
140
144
|
);
|
|
141
145
|
return total;
|
|
@@ -208,6 +212,40 @@ async function resolveWsEndpoint() {
|
|
|
208
212
|
);
|
|
209
213
|
return ws;
|
|
210
214
|
}
|
|
215
|
+
function detectVitestFilter() {
|
|
216
|
+
if (process.env.SCREENTEST_FORCE_DELETION_DETECTION) {
|
|
217
|
+
return { filtered: false, reason: null };
|
|
218
|
+
}
|
|
219
|
+
const argv = process.argv;
|
|
220
|
+
for (let i = 0; i < argv.length; i++) {
|
|
221
|
+
const a = argv[i];
|
|
222
|
+
if (a === "-t" || a === "--testNamePattern") return { filtered: true, reason: a };
|
|
223
|
+
if (a?.startsWith("--testNamePattern=")) return { filtered: true, reason: a };
|
|
224
|
+
}
|
|
225
|
+
const runIdx = argv.indexOf("run");
|
|
226
|
+
if (runIdx === -1) return { filtered: false, reason: null };
|
|
227
|
+
const flagsTakingValue = /* @__PURE__ */ new Set([
|
|
228
|
+
"--config",
|
|
229
|
+
"-c",
|
|
230
|
+
"--reporter",
|
|
231
|
+
"--root",
|
|
232
|
+
"-r",
|
|
233
|
+
"--mode",
|
|
234
|
+
"--inspect-brk",
|
|
235
|
+
"--inspect",
|
|
236
|
+
"--coverage.reporter",
|
|
237
|
+
"--shard"
|
|
238
|
+
]);
|
|
239
|
+
for (let i = runIdx + 1; i < argv.length; i++) {
|
|
240
|
+
const a = argv[i];
|
|
241
|
+
if (a.startsWith("-")) {
|
|
242
|
+
if (flagsTakingValue.has(a)) i += 1;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
return { filtered: true, reason: a };
|
|
246
|
+
}
|
|
247
|
+
return { filtered: false, reason: null };
|
|
248
|
+
}
|
|
211
249
|
function spawnUI(docFile) {
|
|
212
250
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
213
251
|
const bin = join3(here, "index.js");
|
|
@@ -229,6 +267,15 @@ async function setup(project) {
|
|
|
229
267
|
return async () => {
|
|
230
268
|
if (server) await server.close().catch(() => {
|
|
231
269
|
});
|
|
270
|
+
const filter = detectVitestFilter();
|
|
271
|
+
if (filter.filtered) {
|
|
272
|
+
process.stderr.write(
|
|
273
|
+
`[screentest] subset run detected (${filter.reason}) \u2014 skipping deletion
|
|
274
|
+
[screentest] detection so untouched tests in snapshot.json are preserved.
|
|
275
|
+
[screentest] Run the full suite without filters to see deletions.
|
|
276
|
+
`
|
|
277
|
+
);
|
|
278
|
+
}
|
|
232
279
|
let total = 0;
|
|
233
280
|
try {
|
|
234
281
|
total = await generateDoc(
|
|
@@ -236,7 +283,8 @@ async function setup(project) {
|
|
|
236
283
|
paths.snapshotFile,
|
|
237
284
|
paths.actualDir,
|
|
238
285
|
paths.docFile,
|
|
239
|
-
paths.cacheDir
|
|
286
|
+
paths.cacheDir,
|
|
287
|
+
{ detectDeletions: !filter.filtered }
|
|
240
288
|
);
|
|
241
289
|
} catch (err) {
|
|
242
290
|
const msg = err instanceof Error ? err.message : String(err);
|
package/dist/index.js
CHANGED
|
@@ -15243,7 +15243,8 @@ function countLeaves(doc) {
|
|
|
15243
15243
|
for (const g of doc.groups) walk(g.items);
|
|
15244
15244
|
return n;
|
|
15245
15245
|
}
|
|
15246
|
-
async function generateDoc(projectRoot, snapshotFile, actualDir, docFile, cacheDir) {
|
|
15246
|
+
async function generateDoc(projectRoot, snapshotFile, actualDir, docFile, cacheDir, opts = {}) {
|
|
15247
|
+
const detectDeletions = opts.detectDeletions ?? true;
|
|
15247
15248
|
const snap = await readSnapshot(snapshotFile);
|
|
15248
15249
|
const expectedByPath = indexSnapshot(snap);
|
|
15249
15250
|
const actuals = await walkActual(actualDir);
|
|
@@ -15281,21 +15282,24 @@ async function generateDoc(projectRoot, snapshotFile, actualDir, docFile, cacheD
|
|
|
15281
15282
|
});
|
|
15282
15283
|
summary.change++;
|
|
15283
15284
|
}
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15285
|
+
if (detectDeletions) {
|
|
15286
|
+
for (const [key, hash2] of expectedByPath) {
|
|
15287
|
+
if (seen.has(key) || !hash2) continue;
|
|
15288
|
+
insertLeaf(doc, key.split("/"), {
|
|
15289
|
+
type: "deleted",
|
|
15290
|
+
expectedHash: hash2,
|
|
15291
|
+
patchSnapshotJsonFile: snapshotFile
|
|
15292
|
+
});
|
|
15293
|
+
summary.deleted++;
|
|
15294
|
+
}
|
|
15292
15295
|
}
|
|
15293
15296
|
await fs4.mkdir(cacheDir, { recursive: true });
|
|
15294
15297
|
await fs4.writeFile(docFile, JSON.stringify(doc, null, 2));
|
|
15295
15298
|
const total = countLeaves(doc);
|
|
15299
|
+
const deletedSummary = detectDeletions ? `deleted: ${summary.deleted}, ` : "";
|
|
15296
15300
|
process.stdout.write(
|
|
15297
15301
|
`Wrote ${docFile}
|
|
15298
|
-
${total} diff${total === 1 ? "" : "s"} to review (new: ${summary.new}, change: ${summary.change},
|
|
15302
|
+
${total} diff${total === 1 ? "" : "s"} to review (new: ${summary.new}, change: ${summary.change}, ${deletedSummary}unchanged: ${summary.unchanged}${detectDeletions ? "" : "; deletion detection disabled \u2014 subset run"})
|
|
15299
15303
|
`
|
|
15300
15304
|
);
|
|
15301
15305
|
return total;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.3.
|
|
6
|
+
"version": "0.3.3",
|
|
7
7
|
"description": "Local desktop tool for visual screenshot-test review — CLI, runner helpers, and review UI shipped as a single package.",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"type": "module",
|