@decocms/parity 0.8.0 → 0.9.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/AGENTS.md +52 -3
- package/CHANGELOG.md +24 -1
- package/README.md +49 -2
- package/dist/cli.js +7155 -4259
- package/package.json +2 -2
package/AGENTS.md
CHANGED
|
@@ -29,6 +29,16 @@ Do **not** run parity for:
|
|
|
29
29
|
| "is the new site missing cache?" | `parity cache --cand ... --pages 30` |
|
|
30
30
|
| "I want an LLM prompt with all the issues" | `parity prompt <runId>` (writes Markdown to stdout) |
|
|
31
31
|
| "explain this specific issue" | `parity explain <runId> <issueId>` (needs `ANTHROPIC_API_KEY`) |
|
|
32
|
+
| "does THIS single site actually work?" | `parity e2e --url ... --flows ...` (no comparison — pre-launch / partner audit) |
|
|
33
|
+
| "exercise search / cart / login on a site" | `parity e2e --url ... --flows=search,cart-interactions,login` |
|
|
34
|
+
|
|
35
|
+
### `parity run` vs `parity e2e` — decision tree
|
|
36
|
+
|
|
37
|
+
- Have two URLs (prod source-of-truth + candidate)? → `parity run` (regression detection)
|
|
38
|
+
- Have ONE URL and want to validate it works end-to-end? → `parity e2e` (functional validation)
|
|
39
|
+
- Have ONE URL and only need absolute checks (vitals/console/SEO)? → `parity audit` (lighter, no flows)
|
|
40
|
+
|
|
41
|
+
`parity e2e` reuses the same flows + checks as `parity run`, just in single-site mode (checks adapt with absolute criteria when one side is empty).
|
|
32
42
|
|
|
33
43
|
## Reading the JSON output
|
|
34
44
|
|
|
@@ -41,8 +51,11 @@ Do **not** run parity for:
|
|
|
41
51
|
issues: Issue[], // all raw issues from every check
|
|
42
52
|
checks: CheckResult[], // one per check; .data has structured details
|
|
43
53
|
visualDiff: {
|
|
44
|
-
pagesChecked, pagesWithDiffs, pagesPassed,
|
|
45
|
-
|
|
54
|
+
pagesChecked, pagesWithDiffs, pagesPassed, pagesFailed,
|
|
55
|
+
parityOk: boolean, // ⭐ binary signal — see below
|
|
56
|
+
pagesFromCache: number, // how many verdicts came from cross-run cache
|
|
57
|
+
llmCallsUsed: number,
|
|
58
|
+
results: VisualDiffPage[] // per page: prod/cand screenshots, sections, LLM diffs, cachedAt?
|
|
46
59
|
},
|
|
47
60
|
flowCaptures: FlowCapture[] // per-flow page captures with vitals + network
|
|
48
61
|
}
|
|
@@ -52,11 +65,22 @@ To programmatically decide if a migration is ready:
|
|
|
52
65
|
|
|
53
66
|
```ts
|
|
54
67
|
const run = JSON.parse(fs.readFileSync(`${runDir}/report.json`));
|
|
68
|
+
|
|
69
|
+
// Binary signal — most agent loops want this.
|
|
70
|
+
if (run.visualDiff?.parityOk === false) {
|
|
71
|
+
// at least one page is rendering wrong; surface to user
|
|
72
|
+
const broken = run.visualDiff.results.filter(p => p.verdict !== "pass");
|
|
73
|
+
// each entry has pageKey, viewport, pctDiff, differences, sectionsOnlyInProd
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Issue-level gating (independent of visual parity)
|
|
55
77
|
if (run.verdict.critical === 0 && run.verdict.high === 0) {
|
|
56
78
|
// ship it
|
|
57
79
|
}
|
|
58
80
|
```
|
|
59
81
|
|
|
82
|
+
`visualDiff.parityOk` is `true` iff every page in `results` has `verdict === "pass"`. The check itself accounts for the budget-cap edge case: pages where the LLM was skipped AND pctDiff was meaningfully high are surfaced as `"diffs"` rather than silently falling through to `"pass"`. Trust this flag for "is parity OK?" automation.
|
|
83
|
+
|
|
60
84
|
## Driving fixes from the output
|
|
61
85
|
|
|
62
86
|
The most useful flow for an AI agent is:
|
|
@@ -82,11 +106,36 @@ The CLI never fails just because the LLM is unavailable. Issues will still be re
|
|
|
82
106
|
|
|
83
107
|
## Cost-conscious usage
|
|
84
108
|
|
|
85
|
-
A `--preset full` run with visual diff ≈ 6-
|
|
109
|
+
A `--preset full` run with visual diff ≈ 6-24 Claude calls × ~$0.01-0.02 each. Cheap, but in tight loops:
|
|
86
110
|
|
|
87
111
|
- Use `--preset smoke` first (no LLM, ~30s) to validate the URLs respond
|
|
88
112
|
- Use `--no-visual-diff` if you only care about functional checks
|
|
89
113
|
- Use `parity journey` (no aggregation step) for the tightest CI loop
|
|
114
|
+
- **The cross-run cache** (`parity-output/cache/verdicts.json`) automatically skips the LLM call on pages whose screenshots haven't changed since the last verdict. Re-runs after a partial fix typically only spend LLM calls on the pages that actually changed.
|
|
115
|
+
|
|
116
|
+
## Picking which pages to verify
|
|
117
|
+
|
|
118
|
+
Default behavior: `parity run` discovers a representative sample from prod's sitemap (1 home + a few PLPs + a few PDPs, capped by `--visual-pages`).
|
|
119
|
+
|
|
120
|
+
When you need deterministic coverage (e.g. you know `/account` and `/checkout` are the routes at risk), bypass discovery:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# explicit list — useful when an agent loop knows which routes matter
|
|
124
|
+
parity run --prod ... --cand ... --pages "/,/account,/p/known-product,/categoria/calcas"
|
|
125
|
+
|
|
126
|
+
# read paths from a file (one per line; # for comments)
|
|
127
|
+
parity run --prod ... --cand ... --pages-file ./targets.txt
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
These flags override sitemap sampling entirely. Every listed path gets captured + compared, no cap from `--visual-pages`.
|
|
131
|
+
|
|
132
|
+
## Cache flags
|
|
133
|
+
|
|
134
|
+
- Default: cache is **on**. Persists at `<output>/cache/verdicts.json` between runs.
|
|
135
|
+
- `--no-cache` — ignore existing cache entries; force fresh LLM judgment on every page.
|
|
136
|
+
- `--clear-cache` — wipe the cache file before the run starts (use after a prompt change or when verdicts feel stale).
|
|
137
|
+
|
|
138
|
+
The cache key is `sha256(prod_screenshot_bytes + cand_screenshot_bytes + LLM_PROMPT_VERSION)`. Any byte change in either screenshot invalidates the entry naturally. The `LLM_PROMPT_VERSION` constant (in `src/llm/visual-semantic-diff.ts`) bumps the entire cache atomically when the prompt or tool schema changes — no need to wipe by hand.
|
|
90
139
|
|
|
91
140
|
Hard caps already in place:
|
|
92
141
|
|
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,30 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
-
## [0.
|
|
8
|
+
## [0.9.0](https://github.com/decocms/parity/compare/v0.8.1...v0.9.0) (2026-05-29)
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
* **e2e command:** new `parity e2e --url=<URL>` for single-site functional validation. Runs all functional flows (homepage, plp, pdp, purchase-journey, search, cart-interactions, optionally login) plus all checks in single-site mode. Use for pre-launch / partner-site verification when there's no prod baseline to compare against.
|
|
13
|
+
* **search flow:** new `flowSearch` (6 steps: visit-home → open-search → type-and-autocomplete → submit-results → search-no-results → search-empty-state). Resolves the search term inteligentemente via cascade (rc.search.terms → cache → LLM suggest → PT-BR fallbacks). Generates a deterministic unicode `no-results` term per run to exercise the empty-state UI without false matches.
|
|
14
|
+
* **cart-interactions flow:** new `flowCartInteractions` (7 steps: seed-cart → read-baseline → increment-qty → decrement-qty → apply-invalid-coupon → remove-item → verify-empty-state). Seeds via PJ-style navigation (home → PLP → PDP → add → minicart) then exercises each cart interaction with before/after qty+price validation.
|
|
15
|
+
* **login flow:** new `flowLogin` (5 steps, gated by `rc.login.enabled` + `PARITY_LOGIN_EMAIL` / `PARITY_LOGIN_PASSWORD` env vars). Validates invalid-credential error + valid-credential redirect + account area access. Credentials never read from `.parityrc.json` (env vars only).
|
|
16
|
+
* **10 new checks:** `search-presence`, `search-autocomplete`, `search-results`, `search-no-results`, `cart-interactions-flow`, `not-found-parity`, `cookie-cep-modal-cls`, `pdp-gallery-related`, `footer-links-health`, `login-flow`. All adapt to comparative (`parity run`) vs single-site (`parity e2e`) mode.
|
|
17
|
+
* **universal `findElement(page, ctx, { key, intent, budget })` helper:** unifies the override → learned → defaults → LLM-recovery cascade behind one call. Replaces ~80 lines of boilerplate across the new flows and is now the recommended pattern for any new selector-driven step.
|
|
18
|
+
* **21 new selector keys:** `searchTrigger`, `searchInput`, `searchSuggestions`, `cartItemRow`, `cartQuantityIncrement`/`Decrement`, `cartRemoveItem`, `cartCouponInput`/`Submit`, `cartTotalPrice`, `pdpGalleryThumbnail`/`Main`, `pdpRelatedShelf`, `loginTrigger`/`EmailInput`/`PasswordInput`/`Submit`/`ErrorMessage`, `accountMenuTrigger`. Defaults cover VTEX/Shopify/Deco patterns; LLM discovery extended to suggest them when missing.
|
|
19
|
+
* **`StepCapture` validations:** `searchValidation` (term/mode/resultCount/suggestionCount/hasEmptyState), `cartItemValidation` (action/before/after/succeeded), `loginValidation` (stage/errorMessage).
|
|
20
|
+
* **`ParityRc` blocks:** `search.terms` / `search.noResultsTerm`, `login.enabled`, `footer.maxLinks` / `followExternal`, `notFound.testUrl`.
|
|
21
|
+
* **preset `full`:** now includes `search,cart-interactions` alongside `purchase-journey`.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
* **cache-coverage false positives:** assets with `cache-control: public, max-age=N≥60s` are no longer flagged as "MISS opportunities" just because `fromCache=false` (which is always the case on a cold Playwright session). New `cacheable` decision state recognizes properly-configured cache headers. On Miess this dropped flagged opportunities from 323 → 0 — the assets had 1-year `max-age` headers and weren't actually misconfigured.
|
|
26
|
+
* **http-status-parity in single-site mode:** the check no longer flags every captured page as "missing in prod" when `parity e2e` runs with an empty prod slot by convention. Returns `skipped` when prod is empty and cand has content.
|
|
27
|
+
* **audit-seo noindex exceptions:** `/search`, `/buscapagina` (VTEX legacy), `/s` (VTEX Intelligent Search), `/account`, `/checkout`, `/cart`, `/login`, `/404` and friends no longer trigger `noindex` high-severity issues — those routes SHOULD be noindex by SEO best practice.
|
|
28
|
+
* **search-no-results severity scaling:** unicode term returning 1-10 products is now `medium` "fuzzy fallback" rather than `critical` "matches everything"; only >10 products without empty state remains critical. Matches real VTEX Intelligent Search behavior on stores like Miess.
|
|
29
|
+
* **search empty-state detection:** waits for SPA hydration (`networkidle` + 800ms) before checking; combines `innerText` + captured HTML + proximity heuristic so VTEX Intelligent Search empty states are reliably detected.
|
|
30
|
+
* **cache-coverage wording in single-site mode:** says `"no site"` instead of `"em cand"` when running without a prod baseline.
|
|
31
|
+
* **e2e flow `runId` propagation:** `FlowContext.runId` is now plumbed from `e2e.ts` / `run.ts` so the deterministic no-results unicode term uses the actual run id (was previously taking the literal string `"screenshots"` from `outDir.split("/").pop()`).
|
|
9
32
|
|
|
10
33
|
### Fixed
|
|
11
34
|
|
package/README.md
CHANGED
|
@@ -22,6 +22,16 @@ Built originally for Fresh → TanStack Start migrations of Deco storefronts, bu
|
|
|
22
22
|
| Lazy section presence | Deco `/deco/render` and `/_loader/*` routes responding |
|
|
23
23
|
| SEO deep audit | robots.txt, sitemap, noindex regressions |
|
|
24
24
|
| Cache coverage | Cache hit rate, opportunities to cache |
|
|
25
|
+
| **Search presence** | Search input reachable from home in both |
|
|
26
|
+
| **Search autocomplete** | Typing reveals suggestions; cand keeps parity with prod |
|
|
27
|
+
| **Search results** | Same keyword returns comparable product counts |
|
|
28
|
+
| **Search no-results** | Unicode garbage term shows empty state, doesn't match products |
|
|
29
|
+
| **Cart interactions** | Increment / decrement / coupon / remove all behave in cand |
|
|
30
|
+
| **404 parity** | Invalid URL returns 404 (no catch-all 200 in cand) |
|
|
31
|
+
| **Cookie/CEP modal CLS** | Modals don't introduce layout shifts >0.1 in cand |
|
|
32
|
+
| **PDP gallery + related** | Image gallery + "Related products" shelf still render |
|
|
33
|
+
| **Footer links health** | Institutional links (privacy, contact, etc.) aren't broken in cand |
|
|
34
|
+
| **Login flow** _(opt-in)_ | Valid credentials log in; invalid ones show a clear error |
|
|
25
35
|
|
|
26
36
|
All results are aggregated (optionally via Claude) and ranked by severity. Each issue includes screenshots, reproduction, and a suggested fix.
|
|
27
37
|
|
|
@@ -62,6 +72,7 @@ Individual flags always override the preset.
|
|
|
62
72
|
| ------------------ | ----------------------------------------------------------------------------- |
|
|
63
73
|
| `parity run` | Full comparison run between two URLs |
|
|
64
74
|
| `parity audit` | **Single-site** absolute audit (no prod×cand). Console + Vitals + SEO + Imgs |
|
|
75
|
+
| `parity e2e` | **Single-site** functional end-to-end: all flows + all checks. ONE URL. |
|
|
65
76
|
| `parity journey` | CI-friendly: only the purchase journey, with JUnit / GitHub annotations |
|
|
66
77
|
| `parity vitals` | Crawl N pages, compare Web Vitals prod vs cand |
|
|
67
78
|
| `parity cache` | CDN cache analysis, opportunities, request categorization |
|
|
@@ -128,6 +139,27 @@ If `ANTHROPIC_API_KEY` is set, the LLM is invoked automatically and prints a one
|
|
|
128
139
|
|
|
129
140
|
The same flags are available individually on `parity section`: `--heatmap`, `--css-source`, `--prompt`, `--llm-summary`. Use those when you only need one signal; `parity fix` is the "do everything" shortcut.
|
|
130
141
|
|
|
142
|
+
## `parity e2e` — single-site functional run
|
|
143
|
+
|
|
144
|
+
The `audit` command runs absolute checks (vitals, console, network, images, SEO) — useful but doesn't exercise interactions. `parity e2e` runs **all the functional flows** (homepage, plp, pdp, purchase-journey, search, cart-interactions, optionally login) against a single URL plus all parity checks in single-site mode.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Quick e2e for a single site (no comparison, ~3-5min)
|
|
148
|
+
parity e2e --url https://www.example.com
|
|
149
|
+
|
|
150
|
+
# Pick specific flows
|
|
151
|
+
parity e2e --url https://www.example.com --flows=search,cart-interactions
|
|
152
|
+
|
|
153
|
+
# Override LLM-discovered search term
|
|
154
|
+
parity e2e --url https://www.example.com --search-terms="camisa,promocao"
|
|
155
|
+
|
|
156
|
+
# With login (credentials via env or flags)
|
|
157
|
+
PARITY_LOGIN_EMAIL=test@example.com PARITY_LOGIN_PASSWORD=*** \
|
|
158
|
+
parity e2e --url https://www.example.com --flows=login
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Use `parity e2e` when** you want to validate "does this site actually work end-to-end?" — pre-launch, post-deploy, partner sites. **Use `parity run` when** you need to detect *regressions* between two versions (prod vs migration candidate).
|
|
162
|
+
|
|
131
163
|
## Configuration (optional)
|
|
132
164
|
|
|
133
165
|
`.parityrc.json` at the project root — selector overrides and run defaults:
|
|
@@ -142,11 +174,26 @@ The same flags are available individually on `parity section`: `--heatmap`, `--c
|
|
|
142
174
|
"minicartTrigger": "[data-minicart-trigger]",
|
|
143
175
|
"cepInputPdp": "input[name='shipping-zipcode']",
|
|
144
176
|
"cepInputCart": "input[name='cart-zipcode']",
|
|
145
|
-
"checkoutButton": "a:has-text('Finalizar compra')"
|
|
146
|
-
|
|
177
|
+
"checkoutButton": "a:has-text('Finalizar compra')",
|
|
178
|
+
"searchInput": "input[type='search']",
|
|
179
|
+
"cartCouponInput": "input[name*='coupon']"
|
|
180
|
+
},
|
|
181
|
+
"search": {
|
|
182
|
+
"terms": ["camisa", "promocao"]
|
|
183
|
+
},
|
|
184
|
+
"footer": {
|
|
185
|
+
"maxLinks": 20,
|
|
186
|
+
"followExternal": false
|
|
187
|
+
},
|
|
188
|
+
"notFound": {
|
|
189
|
+
"testUrl": "/this-page-definitely-does-not-exist"
|
|
190
|
+
},
|
|
191
|
+
"login": { "enabled": true }
|
|
147
192
|
}
|
|
148
193
|
```
|
|
149
194
|
|
|
195
|
+
> **Credentials are NEVER read from `.parityrc.json`.** Set `PARITY_LOGIN_EMAIL` and `PARITY_LOGIN_PASSWORD` as environment variables (`.parityrc.json` is for non-secret config only).
|
|
196
|
+
|
|
150
197
|
`.parityignore` — noise suppression:
|
|
151
198
|
|
|
152
199
|
```json
|