mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-14 23:26:39 +03:00
Addresses two cursor review findings:
- {#each} bodies whose bound values appear in attributes (href={link.href},
src={item.img}) now record attr slots; the browser hydrates them from the
rendered attribute so component previews no longer mount with empty links.
Single-expression attributes hydrate exactly; mixed values stay unhydrated
as before. A new slot classifier also refuses shapes that would crash a
shallow hydration item (deep paths, method calls, bare item renders) and
routes them to source-preview mode instead.
- Style directives now run the mixed loop/outer identifier check before the
free-identifier param check, so style:width={base + r.pct} falls back
instead of minting a broken param.
Tests: attr-slot analysis units, crashy/lossy fallback units, an attribute-
bound anchor in the stateful SvelteKit fixture asserted through accept, and
a mountedDomProbe e2e hook that reads the hydrated href off the mounted
variant DOM (verified to fail when hydration is disabled).
AI-assisted (Claude Code).
Co-Authored-By: Claude Code <noreply@anthropic.com>
145 lines
3.4 KiB
JSON
145 lines
3.4 KiB
JSON
{
|
|
"name": "Vite 8 + SvelteKit stateful page",
|
|
"config": {
|
|
"files": [
|
|
"src/app.html"
|
|
],
|
|
"insertBefore": "</body>",
|
|
"commentSyntax": "html"
|
|
},
|
|
"sourceFiles": [
|
|
"DESIGN.md",
|
|
"src/app.html",
|
|
"src/routes/+page.svelte",
|
|
"src/routes/+layout.svelte",
|
|
"svelte.config.js",
|
|
"vite.config.js"
|
|
],
|
|
"generatedFiles": [],
|
|
"wrapCases": [
|
|
{
|
|
"name": "wraps hero title through Svelte component preview",
|
|
"args": {
|
|
"classes": "hero-title",
|
|
"tag": "h1"
|
|
},
|
|
"expectedFile": "node_modules/.impeccable-live/wraptest0/manifest.json",
|
|
"expectedSourceFile": "src/routes/+page.svelte",
|
|
"expectedPreviewMode": "svelte-component"
|
|
},
|
|
{
|
|
"name": "wraps the each-block list through Svelte component preview",
|
|
"args": {
|
|
"classes": "expense-list",
|
|
"tag": "ul"
|
|
},
|
|
"expectedFile": "node_modules/.impeccable-live/wraptest1/manifest.json",
|
|
"expectedSourceFile": "src/routes/+page.svelte",
|
|
"expectedPreviewMode": "svelte-component"
|
|
}
|
|
],
|
|
"runtime": {
|
|
"styling": "plain-css",
|
|
"install": [
|
|
"npm",
|
|
"install",
|
|
"--no-audit",
|
|
"--no-fund",
|
|
"--loglevel=error"
|
|
],
|
|
"devCommand": [
|
|
"npx",
|
|
"vite",
|
|
"dev",
|
|
"--host",
|
|
"127.0.0.1"
|
|
],
|
|
"readyPattern": "Local:\\s+https?://[^:]+:(\\d+)",
|
|
"readyTimeoutMs": 120000,
|
|
"steer": false,
|
|
"pickSelector": "ul.expense-list",
|
|
"pickPosition": {
|
|
"x": 10,
|
|
"y": 10
|
|
},
|
|
"variantSequence": [
|
|
3,
|
|
1,
|
|
2
|
|
],
|
|
"acceptedSourcePattern": "<ul[^>]*class=\"[^\"]*\\bexpense-list\\b",
|
|
"assertSourceContains": [
|
|
"{#each expenses as expense, i}",
|
|
"{expense.name}",
|
|
"{expense.amount}",
|
|
"href={expense.doc}"
|
|
],
|
|
"preActions": [
|
|
{
|
|
"type": "click",
|
|
"selector": "[data-testid='add-expense']"
|
|
},
|
|
{
|
|
"type": "wait",
|
|
"selector": "[data-testid='expense-row'][data-index='0']"
|
|
},
|
|
{
|
|
"type": "click",
|
|
"selector": "[data-testid='add-expense']"
|
|
},
|
|
{
|
|
"type": "wait",
|
|
"selector": "[data-testid='expense-row'][data-index='1']"
|
|
},
|
|
{
|
|
"type": "click",
|
|
"selector": "[data-testid='add-expense']"
|
|
},
|
|
{
|
|
"type": "wait",
|
|
"selector": "[data-testid='expense-row'][data-index='2']"
|
|
}
|
|
],
|
|
"stateProbe": {
|
|
"textSelector": "[data-testid='open-count']",
|
|
"expectedText": "3 offen",
|
|
"windowProperty": "__impeccableStatefulMounts",
|
|
"expectedWindowValue": 1,
|
|
"expectWindowUnchanged": true
|
|
},
|
|
"paramsScenario": {
|
|
"variant": 2,
|
|
"rangeLabel": "Lead",
|
|
"rangeValue": 1.8,
|
|
"stepsLabel": "Density",
|
|
"stepsOptionLabel": "Snug",
|
|
"expectSourceContains": [
|
|
"line-height: 1.8",
|
|
"letter-spacing: 0.01em"
|
|
],
|
|
"expectSourceMissing": [
|
|
"letter-spacing: 0.14em"
|
|
]
|
|
},
|
|
"componentFailureScenarios": {
|
|
"variant": 2,
|
|
"storageLoss": false
|
|
},
|
|
"probe": {
|
|
"expectLiveInit": true,
|
|
"expectConsoleClean": true
|
|
},
|
|
"mountedDomProbe": [
|
|
{
|
|
"selector": "ul.expense-list a.expense-doc",
|
|
"attr": "href",
|
|
"expect": "/receipts/snack"
|
|
},
|
|
{
|
|
"selector": "ul.expense-list strong.expense-name",
|
|
"expect": "Design snack"
|
|
}
|
|
]
|
|
}
|
|
}
|