Files
sase.tr/MANIFEST.md
Fusion 759e5c8e9a feat(FN-400): Phase-1 selector & route manifest for FN-367/FN-368
Commits merged:
- feat(FN-400): Phase-1 selector & route manifest for FN-367/FN-368

Files changed:
MANIFEST.md | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

Fusion-Task-Id: FN-400
2026-05-16 11:15:24 +03:00

8.9 KiB
Raw Blame History

FN-400 — Phase-1 Selector & Route Manifest

Scope: sase.tr web app (apps/web), current main (commit 08dbde7). Source of truth for FN-367: commit e274e02 (feat(FN-367): add inline retry affordance after VIN decode failure). Source of truth for FN-368: commit 0ce68a7 (feat(FN-368): parts panel loading state, inert unavailable rows, escape hatch). Convention note: This codebase does not use data-testid. Testability hooks are data-faro-user-action-name="…" plus semantic ARIA (role, aria-live, aria-disabled). All selectors below were re-verified against the shipped tree.


FN-367 — VIN decode failure → rage clicks

Route(s)

  • css=/dashboard/search — file: apps/web/src/routes/dashboard/search.tsx:46 (createFileRoute("/dashboard/search")). VIN decode is triggered exclusively from this route. Successful decode navigates to /dashboard/vehicles/$id (search.tsx:179).

Input selector (VIN field)

  • css=input[maxlength="17"] — file: apps/web/src/routes/dashboard/search.tsx:333-358.
  • Stable accessor (preferred): role=textbox with placeholder "Şase numarasını girin (17 karakter)" (search.tsx:334).
  • No data-testid, no data-faro-user-action-name on the input. Use the placeholder or role=textbox.

Submit / decode trigger

  • text="Şase Çöz" button (type=submit) — file: apps/web/src/routes/dashboard/search.tsx:399-409.
  • Stable accessor: role=button with name "Şase Çöz".
  • Form submit handler: handleSearch (search.tsx:204).
  • No data-faro-user-action-name on the submit button.

Error / failure-state selector (the element a user would rage-click)

  • role="alert" + aria-live="assertive" on the error banner — file: apps/web/src/routes/dashboard/search.tsx:412-471 (attributes at lines 414 and 415).
  • Title text inside the banner: "Şase çözümlenemedi" (search.tsx:421).
  • Introduced/touched by FN-367 (commit e274e02). Confirmed present in current tree.

Retry affordance selector (introduced by FN-367)

  • data-faro-user-action-name="vin-decode-retry" — file: apps/web/src/routes/dashboard/search.tsx:446.
  • Button text: "Tekrar Dene" (search.tsx:453).
  • Rendered conditionally: only when error does not contain the substrings "abone olun" (subscription wall) or "tanınamadı" (unknown VIN — that branch shows a different "report to admin" CTA instead). See guard at search.tsx:443.
  • Handler: handleRetry (search.tsx:189), which fires PostHog event vin_decode_retry_clicked (search.tsx:193).

data-testid hooks added by FN-367

  • NOT PRESENT IN CURRENT CODE. FN-367 did not add data-testid attributes. The verification-relevant hooks it added are: (1) data-faro-user-action-name="vin-decode-retry" on the retry button (search.tsx:446), (2) role="alert" + aria-live="assertive" on the error banner (search.tsx:414-415). The vitest test file apps/web/src/routes/__tests__/dashboard-search.test.tsx queries by role/name, not by testid — Playwright should follow the same pattern.

Other useful hooks on this route

  • data-faro-user-action-name="fill-example-vin" — example-VIN helper button (search.tsx:390).
  • data-faro-user-action-name="select-history-vin" — history-row buttons (search.tsx:560).

FN-368 — Parts panel → rage clicks → abandonment

Route(s)

The parts panel is rendered indirectly via <SchemaViewer>, which is mounted on four category-level routes (all four are in scope; the "vehicle detail page" referenced in the spec is the first):

  • css=/dashboard/vehicles/$id/categories/$categoryId — file: apps/web/src/routes/dashboard/vehicles_/$id/categories_/$categoryId.tsx:157-158. Primary post-VIN-decode parts surface.
  • css=/dashboard/catalog/$brandName/$modelId/categories/$categoryId — file: apps/web/src/routes/dashboard/catalog_/$brandName_/$modelId/categories_/$categoryId.tsx:224-225.
  • css=/dashboard/catalog/emex/$catalogCode/$vehicleId/groups/$groupId — file: apps/web/src/routes/dashboard/catalog_/emex/$catalogCode_/$vehicleId_/groups/$groupId.tsx:83.
  • css=/dashboard/catalog/pcat/$catalogId/$modelId/$carId/groups/$groupId — file: apps/web/src/routes/dashboard/catalog_/pcat/$catalogId_/$modelId_/$carId_/groups/$groupId.tsx:100.

SchemaViewer then renders <PartsPanel> at apps/web/src/components/schema/schema-viewer.tsx:100 (no-schema fallback) and :168 (split-pane right column).

Parts panel container selector

  • text="Parcalar" — the heading inside the container header — file: apps/web/src/components/schema/parts-panel.tsx:95 (loading state) and :112 (loaded state).
  • Stable accessor: role=heading with name "Parcalar".
  • No dedicated container data-testid or data-faro-user-action-name on the wrapper <div>. Use the heading text to scope locators.

Part category / part item selector (the elements users were rage-clicking pre-fix)

  • data-faro-user-action-name="select-part" on each part row — file: apps/web/src/components/schema/parts-panel.tsx:146.
  • Available rows: role="button" + tabIndex={0} (parts-panel.tsx:148-149).
  • Unavailable rows (the inert, post-fix state that visually replaces the rage-clicked target): aria-disabled="true" + tabIndex={-1} + stripped click/keydown handlers (parts-panel.tsx:147-149, with handler-strip logic at :166-181).
  • Visual hint: className includes opacity-40 on unavailable rows (parts-panel.tsx:158).

Loading / skeleton state selector

  • text="Yukleniyor..." (note: no diacritics in source) inside the panel header during load — file: apps/web/src/components/schema/parts-panel.tsx:96.
  • Skeleton rows are 8× <Skeleton> elements rendered from SKELETON_ROW_KEYS (parts-panel.tsx:18, mapped at :101-103).
  • Stable accessor: scope to panel by role=heading name=Parcalar, then assert sibling text="Yukleniyor...".
  • Introduced by FN-368 (the entire if (isLoading) block at parts-panel.tsx:89-106 is new in commit 0ce68a7).

Empty / error state selector

  • Empty state: text="Bu kategori icin parca bulunamadi." — file: apps/web/src/components/schema/parts-panel.tsx:119.
  • Escape-hatch button (introduced by FN-368): text="Geri don" — file: apps/web/src/components/schema/parts-panel.tsx:121 (<Button … onClick={() => window.history.back()}>Geri don</Button>).
  • Stable accessor for escape hatch: role=button name "Geri don".
  • No dedicated error state. The panel does not render a server-error branch — upstream use-parts failures bubble to the page-level loading skeleton in SchemaViewer (schema-viewer.tsx:69-83). Flag for verification author: if FN-368 testing needs an explicit error UI, it does not exist in current code.

data-testid hooks added by FN-368

  • NOT PRESENT IN CURRENT CODE. FN-368 did not add data-testid attributes. The verification-relevant hooks it added are:
    • data-faro-user-action-name="select-part" on every row (parts-panel.tsx:146).
    • aria-disabled="true" on unavailable rows (parts-panel.tsx:147).
    • role="button" + tabIndex={0} on available rows; tabIndex={-1} on unavailable rows (parts-panel.tsx:148-149).
    • Loading-state branch with "Yukleniyor..." text + skeleton rows (parts-panel.tsx:89-106).
    • "Geri don" escape-hatch button in empty state (parts-panel.tsx:120-123).

The companion vitest spec apps/web/src/components/schema/__tests__/parts-panel.test.tsx (added by FN-368) queries by role / accessible-name / text — Playwright should match that pattern.


Drift check

Selector In commit In current main Status
role="alert" + aria-live="assertive" on VIN error banner e274e02 search.tsx search.tsx:414-415 unchanged
data-faro-user-action-name="vin-decode-retry" e274e02 search.tsx search.tsx:446 unchanged
"Tekrar Dene" button text e274e02 search.tsx:453 unchanged
data-faro-user-action-name="select-part" 0ce68a7 parts-panel.tsx parts-panel.tsx:146 unchanged
aria-disabled="true" on unavailable rows 0ce68a7 parts-panel.tsx:147 unchanged
"Yukleniyor..." loading text 0ce68a7 parts-panel.tsx:96 unchanged
"Geri don" empty-state escape hatch 0ce68a7 parts-panel.tsx:121 unchanged

No drift between the FN-367 / FN-368 PRs and current shipped code on main as of 08dbde7.


  1. [data-faro-user-action-name="…"] — preferred where present.
  2. getByRole(role, { name })role=alert, role=button, role=heading, role=textbox.
  3. getByText("…") / getByPlaceholder("…") — last resort for elements without (1) or (2).

Do not request new data-testid attributes unless a target has none of the above; that would force a code change purely for testability and conflicts with the established convention.