tuffgal 0.1.0-alpha.1 → 0.1.0-alpha.10
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/CHANGELOG.md +174 -0
- package/README.md +23 -14
- package/dist/cli.js +45 -18
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +10 -11
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/supervise.d.ts.map +1 -1
- package/dist/commands/supervise.js +3 -25
- package/dist/commands/supervise.js.map +1 -1
- package/dist/config.d.ts +93 -22
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +146 -3
- package/dist/config.js.map +1 -1
- package/dist/coverage/flows.d.ts +2 -7
- package/dist/coverage/flows.d.ts.map +1 -1
- package/dist/coverage/flows.js.map +1 -1
- package/dist/coverage/screens.d.ts +2 -7
- package/dist/coverage/screens.d.ts.map +1 -1
- package/dist/coverage/screens.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/reporter/assets/report.css +641 -0
- package/dist/reporter/assets/report.js +248 -0
- package/dist/reporter/template.d.ts +3 -5
- package/dist/reporter/template.d.ts.map +1 -1
- package/dist/reporter/template.js +275 -151
- package/dist/reporter/template.js.map +1 -1
- package/dist/runner/approve.d.ts +12 -2
- package/dist/runner/approve.d.ts.map +1 -1
- package/dist/runner/approve.js +20 -7
- package/dist/runner/approve.js.map +1 -1
- package/dist/runner/bridges/devServers.d.ts.map +1 -1
- package/dist/runner/bridges/devServers.js +4 -28
- package/dist/runner/bridges/devServers.js.map +1 -1
- package/dist/runner/coverage.d.ts +2 -1
- package/dist/runner/coverage.d.ts.map +1 -1
- package/dist/runner/coverage.js +10 -5
- package/dist/runner/coverage.js.map +1 -1
- package/dist/runner/interpolate.d.ts.map +1 -1
- package/dist/runner/interpolate.js +4 -1
- package/dist/runner/interpolate.js.map +1 -1
- package/dist/runner/run.d.ts.map +1 -1
- package/dist/runner/run.js +36 -4
- package/dist/runner/run.js.map +1 -1
- package/dist/runner/runAction.d.ts +6 -0
- package/dist/runner/runAction.d.ts.map +1 -1
- package/dist/runner/runAction.js +75 -29
- package/dist/runner/runAction.js.map +1 -1
- package/dist/runner/runStory.d.ts +29 -2
- package/dist/runner/runStory.d.ts.map +1 -1
- package/dist/runner/runStory.js +183 -57
- package/dist/runner/runStory.js.map +1 -1
- package/dist/runner/scheduler.d.ts +7 -5
- package/dist/runner/scheduler.d.ts.map +1 -1
- package/dist/runner/scheduler.js +73 -23
- package/dist/runner/scheduler.js.map +1 -1
- package/dist/runner/steps/intercept.d.ts.map +1 -1
- package/dist/runner/steps/intercept.js +8 -2
- package/dist/runner/steps/intercept.js.map +1 -1
- package/dist/runner/steps/navigate.d.ts +3 -1
- package/dist/runner/steps/navigate.d.ts.map +1 -1
- package/dist/runner/steps/navigate.js +2 -2
- package/dist/runner/steps/navigate.js.map +1 -1
- package/dist/runner/steps/read.d.ts +4 -2
- package/dist/runner/steps/read.d.ts.map +1 -1
- package/dist/runner/steps/read.js +4 -2
- package/dist/runner/steps/read.js.map +1 -1
- package/dist/runner/storyFilter.d.ts +11 -0
- package/dist/runner/storyFilter.d.ts.map +1 -0
- package/dist/runner/storyFilter.js +12 -0
- package/dist/runner/storyFilter.js.map +1 -0
- package/dist/schema/action.d.ts +12 -1
- package/dist/schema/action.d.ts.map +1 -1
- package/dist/schema/action.js +13 -7
- package/dist/schema/action.js.map +1 -1
- package/dist/schema/load.d.ts.map +1 -1
- package/dist/schema/load.js +10 -1
- package/dist/schema/load.js.map +1 -1
- package/dist/schema/result.d.ts +35 -0
- package/dist/schema/result.d.ts.map +1 -1
- package/dist/schema/result.js +25 -1
- package/dist/schema/result.js.map +1 -1
- package/dist/schema/story.d.ts +15 -0
- package/dist/schema/story.d.ts.map +1 -1
- package/dist/schema/story.js +45 -7
- package/dist/schema/story.js.map +1 -1
- package/dist/screenshots/baselineStore.d.ts +25 -0
- package/dist/screenshots/baselineStore.d.ts.map +1 -1
- package/dist/screenshots/baselineStore.js +53 -5
- package/dist/screenshots/baselineStore.js.map +1 -1
- package/dist/screenshots/capture.d.ts.map +1 -1
- package/dist/screenshots/capture.js +12 -0
- package/dist/screenshots/capture.js.map +1 -1
- package/dist/screenshots/diff.d.ts.map +1 -1
- package/dist/screenshots/diff.js +12 -0
- package/dist/screenshots/diff.js.map +1 -1
- package/dist/util.d.ts +16 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +48 -0
- package/dist/util.js.map +1 -0
- package/package.json +11 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# 🪵 Changelog
|
|
2
|
+
|
|
3
|
+
**All notable project changes will be documented in this file.** The format
|
|
4
|
+
is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
5
|
+
this project uses [Pride Versioning](https://pridever.org) → `PROUD.DEFAULT.SHAME`
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
_Nothing right now_
|
|
10
|
+
|
|
11
|
+
## [0.1.0-alpha.10] — 2026-06-22
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Per-breakpoint database isolation.** alpha.9 ran each breakpoint in its own
|
|
16
|
+
browser context but applied a story's fixtures only once, before the
|
|
17
|
+
breakpoint loop — so a story that mutated server state passed at the first
|
|
18
|
+
mode and then ran the next mode against the mutated rows (a registered user
|
|
19
|
+
collided on the second mode, an already-read link no longer showed as unread,
|
|
20
|
+
an emptied list had nothing left to empty). Fixtures are now re-applied before
|
|
21
|
+
**every** breakpoint, resetting that state to a known baseline per mode.
|
|
22
|
+
Fixtures are idempotent, so non-mutating stories are unaffected.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **`${breakpoint}` interpolation token.** The current mode name is exposed to
|
|
27
|
+
action interpolation as `${breakpoint}`, so a story can key data it creates
|
|
28
|
+
through the app (with no backing fixture to reset) per mode — e.g.
|
|
29
|
+
`fresh+${breakpoint}@example.test` registers a distinct user at each viewport
|
|
30
|
+
instead of colliding on a shared value. A story parameter literally named
|
|
31
|
+
`breakpoint` overrides the injected value.
|
|
32
|
+
|
|
33
|
+
## [0.1.0-alpha.9] — 2026-06-21
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- Breakpoint modes, replacing the single `viewport` config
|
|
38
|
+
- `mobile` 375×667 / `tablet` 768×1024 / `laptop` 1024×768 / `desktop` 1280×800
|
|
39
|
+
- Each mode runs in its own browser context + produces its own baselines
|
|
40
|
+
- Each `config.breakpoints` entry is a bare name (registry dimensions) or `{ name, width?, height? }` to override that mode's size; an omitted axis inherits the registry default
|
|
41
|
+
- Order preserved; when a name repeats, the first entry wins
|
|
42
|
+
- Omit `breakpoints` to run a single `desktop` mode (1280×800)
|
|
43
|
+
- Per-story `breakpoints` field, same shape, that **replaces** the project's modes for that story — a story may run a mode the project does not configure, and its overrides resolve against the registry
|
|
44
|
+
- Breakpoint grouping in the HTML report, each group labelled with the real capture size; a single-mode story renders as a flat list with no breakpoint chrome
|
|
45
|
+
- Pre-breakpoint baselines at `<action>/0.png` are read as fallbacks until promoted
|
|
46
|
+
|
|
47
|
+
### Removed
|
|
48
|
+
|
|
49
|
+
**Breaking:** `viewport` config field + per-story `viewport` override. Set
|
|
50
|
+
a single mode's size with `breakpoints: [{ name: 'desktop', width, height }]`
|
|
51
|
+
instead.
|
|
52
|
+
|
|
53
|
+
## [0.1.0-alpha.8] — 2026-06-20
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- Reset page scroll to origin before each full-page capture, so `position: sticky` and `fixed` elements no longer render shifted by `scrollY`
|
|
58
|
+
|
|
59
|
+
## [0.1.0-alpha.7] — 2026-06-20
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- Add `npm run preview` to render a sample HTML report
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- Capitalize the report title to "Tuffgal report" and show a friendlier timestamp
|
|
68
|
+
- Convey story status as a colored, marked story name instead of a badge
|
|
69
|
+
- Make the whole action row clickable to toggle screenshots
|
|
70
|
+
- Move the expand/collapse buttons to the right of the filters; the story-count status now sits beside the filters, with filter-aware labels
|
|
71
|
+
- Rename "pass" terminology to "passed" throughout the HTML report
|
|
72
|
+
- Show the status badge as plain text (no glyphs)
|
|
73
|
+
- Validate the consumer config before resolving it, failing with the config file path instead of an opaque `TypeError`
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
|
|
77
|
+
- Guard the diff core against non-RGBA PNG pixel formats so a format change fails loudly instead of scoring garbage
|
|
78
|
+
- Memoize coverage init so concurrent workers no longer orphan the HTML report
|
|
79
|
+
- Raise subtle-text contrast to clear WCAG 1.4.3 (4.5:1) in both light and dark themes
|
|
80
|
+
- Reject non-finite or non-positive numeric CLI flags at parse time (e.g. `--idle-limit foo` no longer busy-loops the supervisor)
|
|
81
|
+
- Render the HTML report's default screenshot server-side so screenshots still show when JavaScript fails or is disabled
|
|
82
|
+
- Serialize per-baseline writes so stories sharing an action no longer race to create the same baseline under `--workers > 1`
|
|
83
|
+
|
|
84
|
+
### Removed
|
|
85
|
+
|
|
86
|
+
- Drop redundant "Failures" section at the bottom of the HTML report
|
|
87
|
+
- Stop linking to Playwright trace in the HTML report
|
|
88
|
+
|
|
89
|
+
## [0.1.0-alpha.6] — 2026-06-11
|
|
90
|
+
|
|
91
|
+
### Added
|
|
92
|
+
|
|
93
|
+
- Add per-story overrides for browser `viewport` optional config field
|
|
94
|
+
- Add `tuffgal approve --new-only` flag to limit baselines to new stories
|
|
95
|
+
- Allow reports to be filtered by passed, changed, or failed
|
|
96
|
+
- Allow reports to expand/contract all screenshots
|
|
97
|
+
|
|
98
|
+
### Changed
|
|
99
|
+
|
|
100
|
+
- Edit `tuffgal run` output to group changed, failed at end w/ report link
|
|
101
|
+
- Skip npm release if no version bump
|
|
102
|
+
|
|
103
|
+
## [0.1.0-alpha.5] — 2026-06-11
|
|
104
|
+
|
|
105
|
+
### Added
|
|
106
|
+
|
|
107
|
+
`navigate` step accepts an optional `waitUntil` field (`'load' |
|
|
108
|
+
'domcontentloaded' | 'networkidle' | 'commit'`) that overrides Playwright's
|
|
109
|
+
`page.goto` ready signal on a per-step basis. Defaults to `'networkidle'`.
|
|
110
|
+
Use `'domcontentloaded'` for dev-mode pages with long-tail external fetches
|
|
111
|
+
that prevent `networkidle` from settling.
|
|
112
|
+
|
|
113
|
+
## [0.1.0-alpha.4] — 2026-06-06
|
|
114
|
+
|
|
115
|
+
### Added
|
|
116
|
+
|
|
117
|
+
- `tuffgal approve` now updates the a11y snapshot at the same time as the screenshot
|
|
118
|
+
- `--story` works the same way on both `tuffgal run` and `tuffgal approve`
|
|
119
|
+
- Two stories with the same filename in different folders is now an error
|
|
120
|
+
|
|
121
|
+
### Changed
|
|
122
|
+
|
|
123
|
+
- Stories that get skipped b/c a prereq failed now show up in the run report + totals
|
|
124
|
+
- Screenshot comparison uses SSIM only
|
|
125
|
+
- README and `docs/` pages now match how the code actually works lol
|
|
126
|
+
|
|
127
|
+
### Removed
|
|
128
|
+
|
|
129
|
+
- **Breaking:** Removed the legacy `diff.maxDiffRatio` setting
|
|
130
|
+
- **Breaking:** Dropped the `ci` block from `TuffgalConfig` and the public API
|
|
131
|
+
- Removed stale `bin/**` and `schema/**` paths
|
|
132
|
+
|
|
133
|
+
## [0.1.0-alpha.3] — 2026-06-06
|
|
134
|
+
|
|
135
|
+
Grants clipboard permissions in browser contexts.
|
|
136
|
+
|
|
137
|
+
Without `permissions: ['clipboard-read', 'clipboard-write']` Playwright
|
|
138
|
+
default-denies clipboard API access, which breaks any story using the Web
|
|
139
|
+
Clipboard API.
|
|
140
|
+
|
|
141
|
+
## [0.1.0-alpha.2] — 2026-06-04
|
|
142
|
+
|
|
143
|
+
`npm run build` now copies `src/reporter/assets/{report.css,report.js}`
|
|
144
|
+
into `dist/reporter/assets/`. Earlier alpha builds shipped without the
|
|
145
|
+
reporter's static assets, so the generated HTML report rendered without
|
|
146
|
+
styling or interactivity.
|
|
147
|
+
|
|
148
|
+
## [0.1.0-alpha.1] — 2026-06-04
|
|
149
|
+
|
|
150
|
+
### Changed
|
|
151
|
+
|
|
152
|
+
- Package now ships compiled `dist/` instead of raw `.ts` sources
|
|
153
|
+
- CLI entry point is `./dist/cli.js`
|
|
154
|
+
|
|
155
|
+
### Fixed
|
|
156
|
+
|
|
157
|
+
- Corrected `bin` extension and publish flags for the alpha channel
|
|
158
|
+
|
|
159
|
+
## [0.1.0-alpha.0] — 2026-06-04
|
|
160
|
+
|
|
161
|
+
Initial public alpha. Tuffgal extracted from [Linklater](https://github.com/nschneble/linklater)'s
|
|
162
|
+
in-tree visual testing workspace.
|
|
163
|
+
|
|
164
|
+
[Unreleased]: https://github.com/nschneble/tuffgal/compare/v0.1.0-alpha.9...HEAD
|
|
165
|
+
[0.1.0-alpha.9]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.9
|
|
166
|
+
[0.1.0-alpha.8]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.8
|
|
167
|
+
[0.1.0-alpha.7]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.7
|
|
168
|
+
[0.1.0-alpha.6]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.6
|
|
169
|
+
[0.1.0-alpha.5]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.5
|
|
170
|
+
[0.1.0-alpha.4]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.4
|
|
171
|
+
[0.1.0-alpha.3]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.3
|
|
172
|
+
[0.1.0-alpha.2]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.2
|
|
173
|
+
[0.1.0-alpha.1]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.1
|
|
174
|
+
[0.1.0-alpha.0]: https://github.com/nschneble/tuffgal/releases/tag/v0.1.0-alpha.0
|
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Tuffgal
|
|
2
2
|
|
|
3
|
-
](LICENSE)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
> screenshots become a committable build artifact.
|
|
5
|
+
JSON-driven visual regression testing for web apps.
|
|
7
6
|
|
|
8
7
|
<img src="tuffgal.png" alt="Tuffgal" />
|
|
9
8
|
|
|
10
|
-
**Status:** Pre-
|
|
11
|
-
|
|
9
|
+
**Status:** Pre-1.0. Published on npm as `tuffgal@0.1.0-alpha.{n}` with
|
|
10
|
+
provenance. [Linklater](https://github.com/nschneble/linklater) is the
|
|
11
|
+
pilot consumer.
|
|
12
12
|
|
|
13
13
|
Public API is unstable until `v1.0.0`.
|
|
14
14
|
|
|
@@ -24,17 +24,21 @@ When a screenshot changes, a human reviews the diff and decides what to do.
|
|
|
24
24
|
|
|
25
25
|
## What ships in v1
|
|
26
26
|
|
|
27
|
-
-
|
|
28
|
-
`navigate`, `read`, `scroll`, `type`, `wait`, `waitFor
|
|
29
|
-
|
|
27
|
+
- 9 step primitives composed into actions: `click`, `input`, `intercept`,
|
|
28
|
+
`navigate`, `read`, `scroll`, `type`, `wait`, `waitFor`
|
|
29
|
+
- An implicit screenshot at the end of every action
|
|
30
|
+
- Named breakpoint modes (`mobile`, `tablet`, `laptop`, `desktop`) keyed to
|
|
31
|
+
Tailwind widths. Pick which to run per project or per story. Each mode
|
|
32
|
+
gets its own baseline and a per-mode group in the HTML report
|
|
30
33
|
- DAG scheduler with `needs`/`produces` labels and parallel workers
|
|
31
34
|
- SSIM-gated visual diff + pixelmatch overlay + a11y-tree snapshots
|
|
32
35
|
- Trace zip on failure (Playwright trace viewer)
|
|
33
36
|
- Clock freeze (`page.clock.install`)
|
|
34
37
|
- Storage-state persistence across stories
|
|
35
|
-
- Static HTML reporter
|
|
38
|
+
- Static HTML reporter
|
|
36
39
|
- V8 coverage (optional via `monocart-coverage-reports`)
|
|
37
|
-
- Per-
|
|
40
|
+
- Per-run DB reset + per-breakpoint fixture hooks (consumer-supplied via config),
|
|
41
|
+
plus a `${breakpoint}` interpolation token for per-mode test data
|
|
38
42
|
- Process supervisor for dev-server hot-reload rot (it happens)
|
|
39
43
|
|
|
40
44
|
## What's explicitly out of scope (v1)
|
|
@@ -45,18 +49,23 @@ When a screenshot changes, a human reviews the diff and decides what to do.
|
|
|
45
49
|
- WebDriver / Puppeteer substrate
|
|
46
50
|
- Supporting browsers other than Chromium
|
|
47
51
|
|
|
48
|
-
## Quick start
|
|
52
|
+
## Quick start
|
|
49
53
|
|
|
50
54
|
```bash
|
|
51
|
-
npm install -D tuffgal
|
|
55
|
+
npm install -D tuffgal@alpha
|
|
52
56
|
npx tuffgal init # scaffolds tuffgal.config.ts
|
|
53
57
|
npx tuffgal run # runs all stories
|
|
54
58
|
```
|
|
55
59
|
|
|
60
|
+
For CI on GitHub Actions, use the companion
|
|
61
|
+
[`nschneble/tuffgal-action`](https://github.com/nschneble/tuffgal-action)
|
|
62
|
+
composite action.
|
|
63
|
+
|
|
56
64
|
## Documentation
|
|
57
65
|
|
|
58
66
|
- [App contract](docs/app-contract.md)
|
|
59
67
|
- [Authoring guide](docs/authoring.md)
|
|
68
|
+
- [Changelog](CHANGELOG.md)
|
|
60
69
|
- [CI integration](docs/ci.md)
|
|
61
70
|
- [Config reference](docs/config.md)
|
|
62
71
|
- [Migrating from Cypress](docs/migration-cypress.md)
|
|
@@ -76,8 +85,8 @@ MIT. See [LICENSE](LICENSE).
|
|
|
76
85
|
| Core extraction | ✅ |
|
|
77
86
|
| Bridges | ✅ |
|
|
78
87
|
| Linklater migration | ✅ |
|
|
79
|
-
| GitHub Action |
|
|
80
|
-
| `v0.1.0-alpha` npm publish |
|
|
88
|
+
| GitHub Action | ✅ |
|
|
89
|
+
| `v0.1.0-alpha` npm publish | ✅ |
|
|
81
90
|
| `v1.0.0` public launch | ⏳ |
|
|
82
91
|
| `v1.1.0` AI fuzzy matching | Deferred |
|
|
83
92
|
|
package/dist/cli.js
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { approveAll } from "./runner/approve.js";
|
|
2
3
|
import { init } from "./commands/init.js";
|
|
3
|
-
import { supervise } from "./commands/supervise.js";
|
|
4
4
|
import { loadConfig } from "./config.js";
|
|
5
|
-
import { approveAll } from "./runner/approve.js";
|
|
6
5
|
import { runAll } from "./runner/run.js";
|
|
6
|
+
import { supervise } from "./commands/supervise.js";
|
|
7
|
+
const COMMANDS = ['approve', 'help', 'init', 'run', 'supervise'];
|
|
7
8
|
function parseArguments(argv) {
|
|
8
9
|
const [command, ...rest] = argv;
|
|
9
10
|
const parsed = {
|
|
10
|
-
command: command
|
|
11
|
-
command === 'approve' ||
|
|
12
|
-
command === 'init' ||
|
|
13
|
-
command === 'supervise' ||
|
|
14
|
-
command === 'help'
|
|
11
|
+
command: COMMANDS.includes(command)
|
|
15
12
|
? command
|
|
16
13
|
: 'help',
|
|
17
14
|
headed: false,
|
|
18
15
|
manageServers: false,
|
|
19
16
|
coverage: false,
|
|
17
|
+
newOnly: false,
|
|
20
18
|
};
|
|
21
19
|
for (let index = 0; index < rest.length; index += 1) {
|
|
22
20
|
const arg = rest[index];
|
|
@@ -33,11 +31,11 @@ function parseArguments(argv) {
|
|
|
33
31
|
parsed.storyFilter = arg.slice('--story='.length);
|
|
34
32
|
}
|
|
35
33
|
else if (arg === '--workers') {
|
|
36
|
-
parsed.workers =
|
|
34
|
+
parsed.workers = numericFlag('--workers', rest[index + 1]);
|
|
37
35
|
index += 1;
|
|
38
36
|
}
|
|
39
37
|
else if (arg.startsWith('--workers=')) {
|
|
40
|
-
parsed.workers =
|
|
38
|
+
parsed.workers = numericFlag('--workers', arg.slice('--workers='.length));
|
|
41
39
|
}
|
|
42
40
|
else if (arg === '--manage-servers') {
|
|
43
41
|
parsed.manageServers = true;
|
|
@@ -45,37 +43,56 @@ function parseArguments(argv) {
|
|
|
45
43
|
else if (arg === '--coverage') {
|
|
46
44
|
parsed.coverage = true;
|
|
47
45
|
}
|
|
46
|
+
else if (arg === '--new-only') {
|
|
47
|
+
parsed.newOnly = true;
|
|
48
|
+
}
|
|
48
49
|
else if (arg === '--healthcheck-interval') {
|
|
49
|
-
parsed.healthcheckIntervalMs =
|
|
50
|
+
parsed.healthcheckIntervalMs = numericFlag('--healthcheck-interval', rest[index + 1]);
|
|
50
51
|
index += 1;
|
|
51
52
|
}
|
|
52
53
|
else if (arg.startsWith('--healthcheck-interval=')) {
|
|
53
|
-
parsed.healthcheckIntervalMs =
|
|
54
|
+
parsed.healthcheckIntervalMs = numericFlag('--healthcheck-interval', arg.slice('--healthcheck-interval='.length));
|
|
54
55
|
}
|
|
55
56
|
else if (arg === '--idle-limit') {
|
|
56
|
-
parsed.idleLimitMs =
|
|
57
|
+
parsed.idleLimitMs = numericFlag('--idle-limit', rest[index + 1]);
|
|
57
58
|
index += 1;
|
|
58
59
|
}
|
|
59
60
|
else if (arg.startsWith('--idle-limit=')) {
|
|
60
|
-
parsed.idleLimitMs =
|
|
61
|
+
parsed.idleLimitMs = numericFlag('--idle-limit', arg.slice('--idle-limit='.length));
|
|
61
62
|
}
|
|
62
63
|
else if (arg === '--max-runtime') {
|
|
63
|
-
parsed.maxRuntimeMs =
|
|
64
|
+
parsed.maxRuntimeMs = numericFlag('--max-runtime', rest[index + 1]);
|
|
64
65
|
index += 1;
|
|
65
66
|
}
|
|
66
67
|
else if (arg.startsWith('--max-runtime=')) {
|
|
67
|
-
parsed.maxRuntimeMs =
|
|
68
|
+
parsed.maxRuntimeMs = numericFlag('--max-runtime', arg.slice('--max-runtime='.length));
|
|
68
69
|
}
|
|
69
70
|
else if (arg === '--max-respawns') {
|
|
70
|
-
parsed.maxRespawns =
|
|
71
|
+
parsed.maxRespawns = numericFlag('--max-respawns', rest[index + 1]);
|
|
71
72
|
index += 1;
|
|
72
73
|
}
|
|
73
74
|
else if (arg.startsWith('--max-respawns=')) {
|
|
74
|
-
parsed.maxRespawns =
|
|
75
|
+
parsed.maxRespawns = numericFlag('--max-respawns', arg.slice('--max-respawns='.length));
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
return parsed;
|
|
78
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Parses a numeric CLI flag, rejecting anything non-finite or <= 0. Without
|
|
82
|
+
* this, `--idle-limit foo` became `NaN` and flowed into `setTimeout(…, NaN)`,
|
|
83
|
+
* which behaves as `0` and busy-loops the supervisor's healthcheck. Fail loudly
|
|
84
|
+
* at parse time instead.
|
|
85
|
+
*/
|
|
86
|
+
function numericFlag(flag, raw) {
|
|
87
|
+
const value = Number(raw);
|
|
88
|
+
if (raw === undefined ||
|
|
89
|
+
raw === '' ||
|
|
90
|
+
!Number.isFinite(value) ||
|
|
91
|
+
value <= 0) {
|
|
92
|
+
throw new Error(`${flag} requires a positive number (got "${raw ?? ''}")`);
|
|
93
|
+
}
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
79
96
|
function printHelp() {
|
|
80
97
|
process.stdout.write([
|
|
81
98
|
'Usage: tuffgal <command> [options]',
|
|
@@ -95,6 +112,9 @@ function printHelp() {
|
|
|
95
112
|
' --manage-servers Spawn devServers.command, wait, run, then kill it.',
|
|
96
113
|
' --coverage Capture V8 JS + CSS coverage and emit a monocart report.',
|
|
97
114
|
'',
|
|
115
|
+
'Approve options:',
|
|
116
|
+
' --new-only Only promote new baselines; skip changed.',
|
|
117
|
+
'',
|
|
98
118
|
'Supervise options:',
|
|
99
119
|
' --healthcheck-interval N Probe interval in ms (default 30_000).',
|
|
100
120
|
' --idle-limit N Ms with no `tuffgal run` heartbeat before exit (default 600_000).',
|
|
@@ -104,6 +124,13 @@ function printHelp() {
|
|
|
104
124
|
}
|
|
105
125
|
async function main() {
|
|
106
126
|
const args = parseArguments(process.argv.slice(2));
|
|
127
|
+
if (args.newOnly &&
|
|
128
|
+
(args.command === 'run' ||
|
|
129
|
+
args.command === 'supervise' ||
|
|
130
|
+
args.command === 'init')) {
|
|
131
|
+
process.stderr.write('tuffgal error: --new-only is only valid with the `approve` subcommand\n');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
107
134
|
if (args.command === 'help') {
|
|
108
135
|
printHelp();
|
|
109
136
|
return;
|
|
@@ -121,12 +148,12 @@ async function main() {
|
|
|
121
148
|
manageServers: args.manageServers,
|
|
122
149
|
coverage: args.coverage,
|
|
123
150
|
});
|
|
124
|
-
process.stdout.write(`\nTotals: ${result.totals.passed} pass · ${result.totals.changed} changed · ${result.totals.failed} failed\n`);
|
|
125
151
|
process.exit(result.totals.failed > 0 ? 1 : 0);
|
|
126
152
|
}
|
|
127
153
|
if (args.command === 'approve') {
|
|
128
154
|
const summary = await approveAll(config, {
|
|
129
155
|
storyFilter: args.storyFilter,
|
|
156
|
+
newOnly: args.newOnly,
|
|
130
157
|
});
|
|
131
158
|
process.stdout.write(`\nApproved ${summary.approved} baselines; skipped ${summary.skipped} actions.\n`);
|
|
132
159
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AA+EA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C9D"}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { mkdir, writeFile
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { join, relative } from 'node:path';
|
|
3
|
+
import { pathExists } from "../util.js";
|
|
3
4
|
const CONFIG_FILES = ['tuffgal.config.ts', 'tuffgal.config.js'];
|
|
4
5
|
const CONFIG_TEMPLATE = `import { defineConfig } from 'tuffgal';
|
|
5
6
|
|
|
@@ -29,7 +30,14 @@ export default defineConfig({
|
|
|
29
30
|
// leave this empty — cookies always persist via Playwright storage state.
|
|
30
31
|
// storageStatePins: ['session_token'],
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
// Breakpoint modes to run, keyed to Tailwind widths:
|
|
34
|
+
// mobile 375x667 · tablet 768x1024 · laptop 1024x768 · desktop 1280x800
|
|
35
|
+
// Each mode gets its own baseline + a group in the report. Omit to run a
|
|
36
|
+
// single \`desktop\` mode (1280x800). Override a mode's size with an object,
|
|
37
|
+
// e.g. { name: 'desktop', width: 1440, height: 900 }. A story can run its own
|
|
38
|
+
// modes via its own \`breakpoints\` field, which replace these for that story.
|
|
39
|
+
// breakpoints: ['mobile', 'tablet', 'laptop', 'desktop'],
|
|
40
|
+
|
|
33
41
|
defaultTimeoutMs: 10_000,
|
|
34
42
|
navigationTimeoutMs: 15_000,
|
|
35
43
|
frozenTime: '2026-01-15T12:00:00.000Z',
|
|
@@ -111,13 +119,4 @@ export async function init(options) {
|
|
|
111
119
|
'',
|
|
112
120
|
].join('\n'));
|
|
113
121
|
}
|
|
114
|
-
async function pathExists(absolute) {
|
|
115
|
-
try {
|
|
116
|
-
await access(absolute);
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
122
|
//# sourceMappingURL=init.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,YAAY,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;AAEhE,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DvB,CAAC;AAEF,MAAM,sBAAsB,GAAG;IAC7B,iBAAiB;IACjB,iBAAiB;IACjB,mBAAmB;CACpB,CAAC;AAEF,MAAM,gBAAgB,GAAG;;;CAGxB,CAAC;AAMF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAoB;IAC7C,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAExB,KAAK,MAAM,SAAS,IAAI,YAAY,EAAE,CAAC;QACrC,IAAI,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CACb,GAAG,SAAS,sBAAsB,GAAG,2BAA2B;gBAC9D,+CAA+C,CAClD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;IAClD,MAAM,SAAS,CAAC,UAAU,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,SAAS,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,mBAAmB,IAAI,CAC9D,CAAC;IAEF,KAAK,MAAM,YAAY,IAAI,sBAAsB,EAAE,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACjC,MAAM,SAAS,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACzD,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QACvC,MAAM,SAAS,CAAC,aAAa,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;QACzD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;QACE,EAAE;QACF,qCAAqC;QACrC,0DAA0D;QAC1D,sDAAsD;QACtD,qDAAqD;QACrD,kDAAkD;QAClD,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervise.d.ts","sourceRoot":"","sources":["../../src/commands/supervise.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"supervise.d.ts","sourceRoot":"","sources":["../../src/commands/supervise.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,cAAc,CAAC;AAYpE,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAuGf"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { createWriteStream, mkdirSync, statSync } from 'node:fs';
|
|
3
|
-
import { createConnection } from 'node:net';
|
|
4
3
|
import { join, resolve } from 'node:path';
|
|
4
|
+
import { parseHostPort, probeTcp, sleep } from "../util.js";
|
|
5
5
|
const HEARTBEAT_FILE = '.heartbeat';
|
|
6
6
|
const SIGTERM_GRACE_MS = 5_000;
|
|
7
7
|
const HEALTHCHECK_PROBE_TIMEOUT_MS = 2_000;
|
|
@@ -125,25 +125,8 @@ async function probeAllHealthchecks(devServers) {
|
|
|
125
125
|
return results.every((result) => result);
|
|
126
126
|
}
|
|
127
127
|
function probeUrl(url) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
? Number(parsed.port)
|
|
131
|
-
: parsed.protocol === 'https:'
|
|
132
|
-
? 443
|
|
133
|
-
: 80;
|
|
134
|
-
const host = parsed.hostname;
|
|
135
|
-
return new Promise((resolveProbe) => {
|
|
136
|
-
const socket = createConnection({ port, host });
|
|
137
|
-
const cleanup = (result) => {
|
|
138
|
-
socket.removeAllListeners();
|
|
139
|
-
socket.destroy();
|
|
140
|
-
resolveProbe(result);
|
|
141
|
-
};
|
|
142
|
-
socket.once('connect', () => cleanup(true));
|
|
143
|
-
socket.once('error', () => cleanup(false));
|
|
144
|
-
socket.once('timeout', () => cleanup(false));
|
|
145
|
-
socket.setTimeout(HEALTHCHECK_PROBE_TIMEOUT_MS);
|
|
146
|
-
});
|
|
128
|
+
const { host, port } = parseHostPort(url);
|
|
129
|
+
return probeTcp(host, port, HEALTHCHECK_PROBE_TIMEOUT_MS);
|
|
147
130
|
}
|
|
148
131
|
function heartbeatIsStale(heartbeatPath, idleLimitMs) {
|
|
149
132
|
try {
|
|
@@ -197,9 +180,4 @@ function numberFromEnv(name, fallback) {
|
|
|
197
180
|
const parsed = Number(raw);
|
|
198
181
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
199
182
|
}
|
|
200
|
-
function sleep(ms) {
|
|
201
|
-
return new Promise((resolveSleep) => {
|
|
202
|
-
setTimeout(resolveSleep, ms);
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
183
|
//# sourceMappingURL=supervise.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervise.js","sourceRoot":"","sources":["../../src/commands/supervise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"supervise.js","sourceRoot":"","sources":["../../src/commands/supervise.ts"],"names":[],"mappings":"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"}
|