@cevek/screentest 0.2.0 → 0.2.2
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 +22 -6
- package/dist/index.js +37 -8
- package/dist/runner.d.ts +1 -4
- package/dist/templates/Dockerfile.npm.tests +17 -0
- package/dist/templates/Dockerfile.pnpm.tests +28 -0
- package/dist/templates/Dockerfile.yarn.tests +21 -0
- package/package.json +1 -1
- package/dist/templates/Dockerfile.tests +0 -19
- /package/dist/templates/{vitest.config.ts → vitest.screentest.config.ts} +0 -0
package/README.md
CHANGED
|
@@ -7,45 +7,59 @@ screenshots. Everything ships in one npm package — no copy-paste.
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# pick your package manager — all three are supported:
|
|
11
|
+
npm i -D @cevek/screentest playwright vitest && npx playwright install firefox
|
|
12
|
+
# pnpm add -D @cevek/screentest playwright vitest && pnpm exec playwright install firefox
|
|
13
|
+
# yarn add -D @cevek/screentest playwright vitest && yarn playwright install firefox
|
|
12
14
|
```
|
|
13
15
|
|
|
14
16
|
`playwright` and `vitest` are peer-deps — keep them in your devDependencies.
|
|
15
17
|
|
|
18
|
+
`screentest init` detects your package manager (from your lockfile or
|
|
19
|
+
`packageManager` field) and writes a matching `Dockerfile.tests`.
|
|
20
|
+
|
|
16
21
|
## Quick start
|
|
17
22
|
|
|
18
23
|
```bash
|
|
19
24
|
# 1. Scaffold the test harness into your project.
|
|
20
|
-
|
|
25
|
+
npx screentest init
|
|
21
26
|
|
|
22
27
|
# 2. Build the Docker image once.
|
|
23
28
|
docker build -f Dockerfile.tests -t screentest-tests .
|
|
24
29
|
|
|
25
30
|
# 3. Run.
|
|
26
|
-
APP_URL=http://localhost:5050
|
|
31
|
+
APP_URL=http://localhost:5050 npx screentest test
|
|
27
32
|
```
|
|
28
33
|
|
|
29
34
|
`screentest init` creates:
|
|
30
35
|
|
|
31
36
|
- `Dockerfile.tests` — playwright-noble + your project deps + vitest CMD
|
|
32
|
-
-
|
|
37
|
+
(auto-picked for pnpm / npm / yarn based on your lockfile)
|
|
38
|
+
- `vitest.screentest.config.ts` — separate vitest config wired with the
|
|
39
|
+
package's globalSetup. Kept under its own name so your normal
|
|
40
|
+
`vitest.config.ts` (unit tests) is untouched.
|
|
33
41
|
- `tests/example.test.ts` — minimal Playwright test using the runner helpers
|
|
34
42
|
|
|
35
43
|
Existing files are not overwritten — re-run `init` safely.
|
|
36
44
|
|
|
45
|
+
`screentest test` always runs vitest with
|
|
46
|
+
`--config vitest.screentest.config.ts`, so unit tests via plain `vitest run`
|
|
47
|
+
and screenshot tests via `screentest test` stay completely separate.
|
|
48
|
+
|
|
37
49
|
## Commands
|
|
38
50
|
|
|
39
51
|
```bash
|
|
40
52
|
screentest <doc-json-path> [--port 5174] [--no-open]
|
|
41
53
|
[--worker-url URL] [--token TOKEN]
|
|
42
54
|
```
|
|
55
|
+
|
|
43
56
|
Open the review UI on a pre-built `doc.json`. Used internally by `screentest
|
|
44
57
|
test` and `screentest review`.
|
|
45
58
|
|
|
46
59
|
```bash
|
|
47
60
|
screentest test [--host]
|
|
48
61
|
```
|
|
62
|
+
|
|
49
63
|
Default workflow: run vitest **inside Docker** (network=host), and on failure
|
|
50
64
|
auto-launch the review UI. `--host` runs vitest on the host instead (debug
|
|
51
65
|
only — bytes diverge from your CI baseline). Set `CI=1` to skip the auto-UI
|
|
@@ -54,11 +68,13 @@ launch.
|
|
|
54
68
|
```bash
|
|
55
69
|
screentest review
|
|
56
70
|
```
|
|
71
|
+
|
|
57
72
|
Skip vitest, just regenerate `doc.json` from cached actuals and open the UI.
|
|
58
73
|
|
|
59
74
|
```bash
|
|
60
75
|
screentest init
|
|
61
76
|
```
|
|
77
|
+
|
|
62
78
|
Scaffold Dockerfile + vitest config + example test (see above).
|
|
63
79
|
|
|
64
80
|
## Writing tests
|
|
@@ -121,7 +137,7 @@ Or pass `--worker-url` / `--token` to `screentest` directly.
|
|
|
121
137
|
|
|
122
138
|
```yaml
|
|
123
139
|
- run: docker build -f Dockerfile.tests -t screentest-tests .
|
|
124
|
-
- run: CI=1
|
|
140
|
+
- run: CI=1 npx screentest test
|
|
125
141
|
```
|
|
126
142
|
|
|
127
143
|
In `CI=1` the orchestrator exits with vitest's code and never tries to open
|
package/dist/index.js
CHANGED
|
@@ -15265,7 +15265,12 @@ async function runVitestInDocker(snapshotFile, cacheDir) {
|
|
|
15265
15265
|
async function runOrchestrator(opts = {}) {
|
|
15266
15266
|
const paths = resolveRunnerPaths();
|
|
15267
15267
|
if (opts.reviewOnly) {
|
|
15268
|
-
const total = await generateDoc(
|
|
15268
|
+
const total = await generateDoc(
|
|
15269
|
+
paths.snapshotFile,
|
|
15270
|
+
paths.actualDir,
|
|
15271
|
+
paths.docFile,
|
|
15272
|
+
paths.cacheDir
|
|
15273
|
+
);
|
|
15269
15274
|
if (total === 0) {
|
|
15270
15275
|
process.stdout.write("Nothing to review \u2014 all snapshots match.\n");
|
|
15271
15276
|
return 0;
|
|
@@ -15281,7 +15286,7 @@ async function runOrchestrator(opts = {}) {
|
|
|
15281
15286
|
await fs4.rm(paths.actualDir, { recursive: true, force: true });
|
|
15282
15287
|
let testCode;
|
|
15283
15288
|
if (opts.hostMode) {
|
|
15284
|
-
testCode = await run("
|
|
15289
|
+
testCode = await run("npx", ["vitest", "--config", "vitest.screentest.config.ts", "run"]);
|
|
15285
15290
|
} else {
|
|
15286
15291
|
if (opts.requireDockerImage !== false && !ensureDockerImage()) {
|
|
15287
15292
|
return 1;
|
|
@@ -15292,7 +15297,12 @@ async function runOrchestrator(opts = {}) {
|
|
|
15292
15297
|
process.stderr.write(
|
|
15293
15298
|
"\n\u2192 Tests failed \u2014 launching screentest for review.\n Close the tool (Ctrl+C) when done; the original failure will still propagate.\n\n"
|
|
15294
15299
|
);
|
|
15295
|
-
const total = await generateDoc(
|
|
15300
|
+
const total = await generateDoc(
|
|
15301
|
+
paths.snapshotFile,
|
|
15302
|
+
paths.actualDir,
|
|
15303
|
+
paths.docFile,
|
|
15304
|
+
paths.cacheDir
|
|
15305
|
+
);
|
|
15296
15306
|
if (total > 0) {
|
|
15297
15307
|
const reviewCode = await run("node", [process.argv[1], paths.docFile]);
|
|
15298
15308
|
if (reviewCode !== 0 && reviewCode !== 130) {
|
|
@@ -15310,17 +15320,36 @@ async function runOrchestrator(opts = {}) {
|
|
|
15310
15320
|
}
|
|
15311
15321
|
|
|
15312
15322
|
// src/init.ts
|
|
15313
|
-
import { copyFile, mkdir } from "fs/promises";
|
|
15323
|
+
import { copyFile, mkdir, readFile } from "fs/promises";
|
|
15314
15324
|
import { existsSync as existsSync2 } from "fs";
|
|
15315
15325
|
import { dirname as dirname4, join as join4, resolve as resolve6 } from "path";
|
|
15316
15326
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15327
|
+
async function detectPackageManager(cwd) {
|
|
15328
|
+
if (existsSync2(join4(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15329
|
+
if (existsSync2(join4(cwd, "yarn.lock"))) return "yarn";
|
|
15330
|
+
if (existsSync2(join4(cwd, "package-lock.json"))) return "npm";
|
|
15331
|
+
try {
|
|
15332
|
+
const pkg = JSON.parse(
|
|
15333
|
+
await readFile(join4(cwd, "package.json"), "utf8")
|
|
15334
|
+
);
|
|
15335
|
+
const pm = pkg.packageManager ?? "";
|
|
15336
|
+
if (pm.startsWith("pnpm")) return "pnpm";
|
|
15337
|
+
if (pm.startsWith("yarn")) return "yarn";
|
|
15338
|
+
} catch {
|
|
15339
|
+
}
|
|
15340
|
+
return "npm";
|
|
15341
|
+
}
|
|
15317
15342
|
async function runInit() {
|
|
15318
15343
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
15319
|
-
const templatesDir = [resolve6(here, "
|
|
15344
|
+
const templatesDir = [resolve6(here, "./templates"), resolve6(here, "../templates")].find((p) => existsSync2(p)) ?? resolve6(here, "./templates");
|
|
15320
15345
|
const cwd = process.cwd();
|
|
15346
|
+
const pm = await detectPackageManager(cwd);
|
|
15347
|
+
process.stdout.write(`Detected package manager: ${pm}
|
|
15348
|
+
|
|
15349
|
+
`);
|
|
15321
15350
|
const targets = [
|
|
15322
|
-
{ from:
|
|
15323
|
-
{ from: "vitest.config.ts", to: "vitest.config.ts" },
|
|
15351
|
+
{ from: `Dockerfile.${pm}.tests`, to: "Dockerfile.tests" },
|
|
15352
|
+
{ from: "vitest.screentest.config.ts", to: "vitest.screentest.config.ts" },
|
|
15324
15353
|
{ from: "example.test.ts", to: "tests/example.test.ts" }
|
|
15325
15354
|
];
|
|
15326
15355
|
for (const { from, to } of targets) {
|
|
@@ -15345,7 +15374,7 @@ async function runInit() {
|
|
|
15345
15374
|
`
|
|
15346
15375
|
Next steps:
|
|
15347
15376
|
1. docker build -f Dockerfile.tests -t screentest-tests .
|
|
15348
|
-
2. APP_URL=http://localhost:<your-app-port>
|
|
15377
|
+
2. APP_URL=http://localhost:<your-app-port> npx screentest test
|
|
15349
15378
|
`
|
|
15350
15379
|
);
|
|
15351
15380
|
return 0;
|
package/dist/runner.d.ts
CHANGED
|
@@ -15,10 +15,7 @@ export function compareSnapshot(page: Page, name: string): Promise<void>;
|
|
|
15
15
|
* Freeze `Date` inside `ctx`. `when` may be an ISO string, unix-ms number,
|
|
16
16
|
* or `Date`. Must be called BEFORE the first navigation in the context.
|
|
17
17
|
*/
|
|
18
|
-
export function freezeDate(
|
|
19
|
-
ctx: BrowserContext,
|
|
20
|
-
when: string | number | Date,
|
|
21
|
-
): Promise<void>;
|
|
18
|
+
export function freezeDate(ctx: BrowserContext, when: string | number | Date): Promise<void>;
|
|
22
19
|
|
|
23
20
|
/**
|
|
24
21
|
* Wait for `document.fonts.ready` and every `<img>` to reach `complete`.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
FROM mcr.microsoft.com/playwright:v1.60.0-noble
|
|
2
|
+
|
|
3
|
+
WORKDIR /work
|
|
4
|
+
|
|
5
|
+
# Install dependencies. --ignore-scripts skips your project's postinstall
|
|
6
|
+
# hooks (which usually scan src/ — not needed for the test image).
|
|
7
|
+
COPY package.json package-lock.json ./
|
|
8
|
+
RUN npm ci --ignore-scripts
|
|
9
|
+
|
|
10
|
+
# Only the bits needed to run vitest.
|
|
11
|
+
COPY vitest.screentest.config.ts ./
|
|
12
|
+
COPY tsconfig*.json ./
|
|
13
|
+
COPY tests ./tests
|
|
14
|
+
|
|
15
|
+
# Run vitest directly (skipping `npm exec`) — keeps the test image simple
|
|
16
|
+
# and matches how the host orchestrator invokes it.
|
|
17
|
+
CMD ["./node_modules/.bin/vitest", "--config", "vitest.screentest.config.ts", "run"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
FROM mcr.microsoft.com/playwright:v1.60.0-noble
|
|
2
|
+
|
|
3
|
+
WORKDIR /work
|
|
4
|
+
|
|
5
|
+
# corepack lets us use whatever pnpm version your project's `packageManager`
|
|
6
|
+
# field pins (pnpm 11 by default in modern projects). If your project uses
|
|
7
|
+
# npm or yarn instead, swap the install commands accordingly.
|
|
8
|
+
RUN corepack enable
|
|
9
|
+
|
|
10
|
+
# Install dependencies. Flags:
|
|
11
|
+
# --ignore-scripts skips your project's postinstall hooks (which
|
|
12
|
+
# usually scan src/ — not needed for the test image).
|
|
13
|
+
# --config.minimumReleaseAge=0 bypass pnpm 11's supply-chain policy for
|
|
14
|
+
# freshly-published packages (the test image is
|
|
15
|
+
# ephemeral, runs only what's already in lockfile).
|
|
16
|
+
COPY package.json pnpm-lock.yaml ./
|
|
17
|
+
COPY pnpm-workspace.yaml* ./
|
|
18
|
+
RUN pnpm install --frozen-lockfile --ignore-scripts --config.minimumReleaseAge=0
|
|
19
|
+
|
|
20
|
+
# Only the bits needed to run vitest.
|
|
21
|
+
COPY vitest.screentest.config.ts ./
|
|
22
|
+
COPY tsconfig*.json ./
|
|
23
|
+
COPY tests ./tests
|
|
24
|
+
|
|
25
|
+
# Run vitest directly (not via pnpm exec) — pnpm 11 re-runs its supply-chain
|
|
26
|
+
# policy on every exec, which would re-fail freshly-published packages
|
|
27
|
+
# even after install succeeded.
|
|
28
|
+
CMD ["./node_modules/.bin/vitest", "--config", "vitest.screentest.config.ts", "run"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
FROM mcr.microsoft.com/playwright:v1.60.0-noble
|
|
2
|
+
|
|
3
|
+
WORKDIR /work
|
|
4
|
+
|
|
5
|
+
# corepack lets yarn 2+/berry self-install from your project's
|
|
6
|
+
# `packageManager` field. For yarn 1 it's a no-op (yarn is bundled in newer
|
|
7
|
+
# Node images anyway).
|
|
8
|
+
RUN corepack enable
|
|
9
|
+
|
|
10
|
+
# Install dependencies. --ignore-scripts skips your project's postinstall
|
|
11
|
+
# hooks (which usually scan src/ — not needed for the test image).
|
|
12
|
+
COPY package.json yarn.lock ./
|
|
13
|
+
COPY .yarnrc.yml* ./
|
|
14
|
+
RUN yarn install --frozen-lockfile --ignore-scripts
|
|
15
|
+
|
|
16
|
+
# Only the bits needed to run vitest.
|
|
17
|
+
COPY vitest.screentest.config.ts ./
|
|
18
|
+
COPY tsconfig*.json ./
|
|
19
|
+
COPY tests ./tests
|
|
20
|
+
|
|
21
|
+
CMD ["./node_modules/.bin/vitest", "--config", "vitest.screentest.config.ts", "run"]
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.2",
|
|
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",
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
FROM mcr.microsoft.com/playwright:v1.60.0-noble
|
|
2
|
-
|
|
3
|
-
WORKDIR /work
|
|
4
|
-
|
|
5
|
-
# Install pnpm — if your project uses npm/yarn, swap the next two lines.
|
|
6
|
-
RUN npm install -g pnpm@9
|
|
7
|
-
|
|
8
|
-
# Install dependencies. --ignore-scripts skips your project's postinstall
|
|
9
|
-
# hooks (which usually scan src/ — not needed for the test image).
|
|
10
|
-
COPY package.json pnpm-lock.yaml ./
|
|
11
|
-
COPY pnpm-workspace.yaml* ./
|
|
12
|
-
RUN pnpm install --frozen-lockfile --ignore-scripts
|
|
13
|
-
|
|
14
|
-
# Only the bits needed to run vitest.
|
|
15
|
-
COPY vitest.config.ts ./
|
|
16
|
-
COPY tsconfig*.json ./
|
|
17
|
-
COPY tests ./tests
|
|
18
|
-
|
|
19
|
-
CMD ["pnpm", "exec", "vitest", "run"]
|
|
File without changes
|