@decocms/parity 0.1.0 → 0.1.1
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 +7 -0
- package/dist/cli.js +49 -2
- package/package.json +85 -85
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.1] — 2026-05-22
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- `cache-coverage`: classify `decoims.com` (deco image proxy) and `assets.decocache.com` (deco edge cache) as first-party so they remain eligible for cache-opportunity reporting instead of being silently skipped as third-party. ([#5](https://github.com/decocms/parity/pull/5))
|
|
15
|
+
- `purchase-journey-flow`: never silently return `pass` when zero comparable steps were evaluated. The check now returns `skipped` when the flow wasn't requested, and `fail` (critical) when the flow was requested but neither side produced a capture or when capture arrays came back empty. Previously a fully broken cand home would still get a green verdict on the purchase-journey check. ([#6](https://github.com/decocms/parity/pull/6))
|
|
16
|
+
|
|
10
17
|
## [0.1.0] — 2026-05-12
|
|
11
18
|
|
|
12
19
|
First public release.
|
package/dist/cli.js
CHANGED
|
@@ -540,7 +540,7 @@ function isThirdParty(url, baseHost) {
|
|
|
540
540
|
return false;
|
|
541
541
|
if (u.hostname.endsWith(`.${cleanedBase}`))
|
|
542
542
|
return false;
|
|
543
|
-
if (u.hostname.includes("vtexassets") || u.hostname.includes("decoassets") || u.hostname.includes("vteximg"))
|
|
543
|
+
if (u.hostname.includes("vtexassets") || u.hostname.includes("decoassets") || u.hostname.includes("vteximg") || u.hostname.includes("decocache") || u.hostname.includes("decoims"))
|
|
544
544
|
return false;
|
|
545
545
|
return true;
|
|
546
546
|
} catch {
|
|
@@ -7466,11 +7466,49 @@ function purchaseJourneyFlow(ctx) {
|
|
|
7466
7466
|
let totalSteps = 0;
|
|
7467
7467
|
let failedSteps = 0;
|
|
7468
7468
|
let asymmetricSkips = 0;
|
|
7469
|
+
const hasAnyPurchaseFlow = ctx.prodFlows.some((f) => f.flow === "purchase-journey") || ctx.candFlows.some((f) => f.flow === "purchase-journey");
|
|
7470
|
+
if (!hasAnyPurchaseFlow) {
|
|
7471
|
+
return {
|
|
7472
|
+
name: "purchase-journey-flow",
|
|
7473
|
+
status: "skipped",
|
|
7474
|
+
severity: "critical",
|
|
7475
|
+
durationMs: Date.now() - start,
|
|
7476
|
+
summary: "purchase-journey não estava no escopo do run (sem captura de flow)",
|
|
7477
|
+
issues: [],
|
|
7478
|
+
data: { totalSteps: 0, failedSteps: 0, asymmetricSkips: 0 }
|
|
7479
|
+
};
|
|
7480
|
+
}
|
|
7469
7481
|
for (const viewport of ctx.viewports) {
|
|
7470
7482
|
const prodFlow = findFlow(ctx.prodFlows, viewport);
|
|
7471
7483
|
const candFlow = findFlow(ctx.candFlows, viewport);
|
|
7472
|
-
if (!prodFlow || !candFlow)
|
|
7484
|
+
if (!prodFlow || !candFlow) {
|
|
7485
|
+
if (prodFlow && !candFlow) {
|
|
7486
|
+
issues.push({
|
|
7487
|
+
id: `pj:${viewport}:missing-cand-flow`,
|
|
7488
|
+
severity: "critical",
|
|
7489
|
+
category: "functional",
|
|
7490
|
+
check: "purchase-journey-flow",
|
|
7491
|
+
summary: `[${viewport}] cand não produziu captura da purchase-journey (prod produziu) — checkout indisponível ou cliente nunca hidratou`
|
|
7492
|
+
});
|
|
7493
|
+
} else if (!prodFlow && candFlow) {
|
|
7494
|
+
issues.push({
|
|
7495
|
+
id: `pj:${viewport}:missing-prod-flow`,
|
|
7496
|
+
severity: "high",
|
|
7497
|
+
category: "functional",
|
|
7498
|
+
check: "purchase-journey-flow",
|
|
7499
|
+
summary: `[${viewport}] prod não produziu captura da purchase-journey — selectors podem estar desalinhados com a source-of-truth`
|
|
7500
|
+
});
|
|
7501
|
+
} else {
|
|
7502
|
+
issues.push({
|
|
7503
|
+
id: `pj:${viewport}:no-flow-either-side`,
|
|
7504
|
+
severity: "critical",
|
|
7505
|
+
category: "functional",
|
|
7506
|
+
check: "purchase-journey-flow",
|
|
7507
|
+
summary: `[${viewport}] purchase-journey foi requisitada mas não há captura em prod nem cand — flow falhou completamente`
|
|
7508
|
+
});
|
|
7509
|
+
}
|
|
7473
7510
|
continue;
|
|
7511
|
+
}
|
|
7474
7512
|
const prodSteps = indexBy(prodFlow.steps ?? [], (s) => s.name);
|
|
7475
7513
|
const candSteps = indexBy(candFlow.steps ?? [], (s) => s.name);
|
|
7476
7514
|
const allNames = new Set([...prodSteps.keys(), ...candSteps.keys()]);
|
|
@@ -7518,6 +7556,15 @@ function purchaseJourneyFlow(ctx) {
|
|
|
7518
7556
|
} else if (p.status === "skipped" && c.status === "ok") {}
|
|
7519
7557
|
}
|
|
7520
7558
|
}
|
|
7559
|
+
if (totalSteps === 0 && issues.length === 0) {
|
|
7560
|
+
issues.push({
|
|
7561
|
+
id: "pj:zero-steps-evaluated",
|
|
7562
|
+
severity: "critical",
|
|
7563
|
+
category: "functional",
|
|
7564
|
+
check: "purchase-journey-flow",
|
|
7565
|
+
summary: "purchase-journey rodou mas avaliou 0 step(s) — capturas existem mas estão vazias dos dois lados (selectors quebrados ou home não hidratou)"
|
|
7566
|
+
});
|
|
7567
|
+
}
|
|
7521
7568
|
const status = issues.some((i) => i.severity === "critical") ? "fail" : issues.length > 0 ? "warn" : "pass";
|
|
7522
7569
|
return {
|
|
7523
7570
|
name: "purchase-journey-flow",
|
package/package.json
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
2
|
+
"name": "@decocms/parity",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "E2E parity validator for site migrations. Compares prod vs cand and reports UI, functional, SEO, visual, and Web Vitals deltas with an LLM-ranked HTML report.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/decocms/parity.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/decocms/parity#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/decocms/parity/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"deco",
|
|
17
|
+
"tanstack",
|
|
18
|
+
"fresh",
|
|
19
|
+
"migration",
|
|
20
|
+
"e2e",
|
|
21
|
+
"playwright",
|
|
22
|
+
"web-vitals",
|
|
23
|
+
"visual-regression",
|
|
24
|
+
"visual-diff",
|
|
25
|
+
"llm",
|
|
26
|
+
"claude",
|
|
27
|
+
"anthropic",
|
|
28
|
+
"cli",
|
|
29
|
+
"parity",
|
|
30
|
+
"regression-testing"
|
|
31
|
+
],
|
|
32
|
+
"bin": {
|
|
33
|
+
"parity": "dist/cli.js"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md",
|
|
38
|
+
"AGENTS.md",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"dev": "bun run --hot src/cli.ts",
|
|
44
|
+
"build": "bun build src/cli.ts --target=node --outfile=dist/cli.js --packages=external && bun run scripts/postbuild.ts",
|
|
45
|
+
"check": "tsc --noEmit",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest",
|
|
48
|
+
"test:coverage": "vitest run --coverage",
|
|
49
|
+
"test:e2e": "vitest run tests/e2e",
|
|
50
|
+
"deadcode": "knip",
|
|
51
|
+
"lint": "biome lint .",
|
|
52
|
+
"fmt": "biome format --write .",
|
|
53
|
+
"prepublishOnly": "bun run check && bun run build"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=20",
|
|
57
|
+
"bun": ">=1.1"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@anthropic-ai/sdk": "^0.40.0",
|
|
61
|
+
"chalk": "^5.3.0",
|
|
62
|
+
"cheerio": "^1.0.0",
|
|
63
|
+
"commander": "^12.1.0",
|
|
64
|
+
"open": "^10.1.0",
|
|
65
|
+
"ora": "^8.1.1",
|
|
66
|
+
"pixelmatch": "^6.0.0",
|
|
67
|
+
"playwright": "^1.49.0",
|
|
68
|
+
"pngjs": "^7.0.0",
|
|
69
|
+
"zod": "^3.24.1"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@biomejs/biome": "^1.9.4",
|
|
73
|
+
"@types/node": "^22.10.0",
|
|
74
|
+
"@types/pixelmatch": "^5.2.6",
|
|
75
|
+
"@types/pngjs": "^6.0.5",
|
|
76
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
77
|
+
"knip": "^6.13.1",
|
|
78
|
+
"typescript": "^5.7.2",
|
|
79
|
+
"vitest": "^2.1.8"
|
|
80
|
+
},
|
|
81
|
+
"publishConfig": {
|
|
82
|
+
"access": "public"
|
|
83
|
+
},
|
|
84
|
+
"trustedDependencies": [
|
|
85
|
+
"@biomejs/biome"
|
|
86
|
+
]
|
|
87
87
|
}
|