Files
paliad/frontend/src/client/fristenrechner-wizard.test.ts
mAi 70985d88b0
Some checks failed
Paliad CI gate / build (push) Has been cancelled
Paliad CI gate / test-go (push) Has been cancelled
Paliad CI gate / deploy (push) Has been cancelled
feat(fristenrechner): Slice S4 — Mode B wizard (m/paliad#146)
Mode B "🧭 Geführt" — the guided 3-5 row wizard defined in
docs/design-fristenrechner-overhaul-2026-05-26.md §3.2. Lands the
user on a single procedural_event (the trigger), then transitions
to the shared §4 result view.

Frontend:
  * `fristenrechner-wizard.ts` — row stack with R1..R5:
      R1 Was ist passiert?           (event_kind, always asked)
      R2 Vor welchem Gericht?        (jurisdiction, skip if R1 narrows)
      R3 In welchem Verfahren?       (proceeding_type, auto-skip when
                                      narrowed pool has 1 option)
      R4 Welches Schriftstück?       (procedural_event, landing)
      R5 Welche Seite vertreten Sie? (party, only when follow-ups
                                      differ by primary_party)
    Row badges per §11.Q3: R1+R2 = Filter, R3+R4+R5 = Qualifier.
    R5 has NO "Beide" option per §11.Q8 — Mode B is the file-mode
    where perspective is a qualifier.
  * Project prefill — derives R3 + R2 jurisdiction from
    project.proceeding_type, R5 from project.our_side. Annotates
    pre-filled rows with "aus Akte" tag and implicit rows with
    "implizit" tag per §11.Q10 ("erhalten" annotation when a pick is
    carried across an upstream change).
  * R4-to-result transition — after R4 the wizard fetches /follow-
    ups (no dates) to inspect primary_party variance. If both
    claimant and defendant rules exist AND R5 isn't already set,
    swaps the loading row for the R5 chip picker. Otherwise jumps
    straight to mountResultView.
  * URL state — `?mode=wizard&kind=…&forum=…&pt=…&r4=…&party=…`
    keeps deep-link / back-nav consistent (the launchResult step
    sets `event=` so the result view picks up).
  * `fristenrechner-result.ts` mountModeShell now dispatches the
    "wizard" tab to the wizard module (was a coming-soon
    placeholder).
  * 18 i18n keys added (DE + EN parity), 145-line CSS block for the
    wizard row stack with Filter / Qualifier badge styling and
    "aus Akte" annotation chip.

Backend:
  * `ProceedingListOptions.EventKind` adds an EXISTS subquery
    filter on `paliad.sequencing_rules` ⨯ `paliad.procedural_events`
    so Mode B R3 chips only show proceedings whose event roster
    contains at least one event of the requested kind (design
    §6.3). Endpoint param: `event_kind=` on
    /api/tools/proceeding-types.

Test updates:
  * `TestListProceedings` switched from SKIP-when-column-missing to
    asserting the live filter — mig 153 has landed, `kind` column
    is in place. New subtests: kind=proceeding includes
    upc.inf.cfi and excludes the phase row upc.cfi.interim;
    event_kind=filing narrows to proceedings with filing events.
  * `fristenrechner-wizard.test.ts` covers
    `followUpsDifferByParty` — the R5 trigger predicate. 7 cases:
    asymmetric → true; uniform / both / court / empty → false.

Verified — bun build clean (2971 i18n keys), 256 frontend tests
pass (incl. 7 new), go build + vet clean, live-DB
TestListProceedings passes all 6 subtests against mig 153 data.
2026-05-27 10:14:37 +02:00

48 lines
1.6 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { followUpsDifferByParty } from "./fristenrechner-wizard";
describe("followUpsDifferByParty — R5 trigger condition (S4, design §3.2)", () => {
test("true when both claimant and defendant rules present", () => {
expect(followUpsDifferByParty([
{ primary_party: "claimant" },
{ primary_party: "defendant" },
])).toBe(true);
});
test("false when all claimant", () => {
expect(followUpsDifferByParty([
{ primary_party: "claimant" },
{ primary_party: "claimant" },
])).toBe(false);
});
test("false when all defendant", () => {
expect(followUpsDifferByParty([
{ primary_party: "defendant" },
])).toBe(false);
});
test("false when only 'both' rules", () => {
// "Both" rules are bilateral procedural moves (Vertraulichkeits-
// Erwiderung); they don't gate R5 because either party can be
// looking at them.
expect(followUpsDifferByParty([
{ primary_party: "both" },
{ primary_party: "both" },
])).toBe(false);
});
test("false when only court rules", () => {
expect(followUpsDifferByParty([
{ primary_party: "court" },
])).toBe(false);
});
test("true when mixed with both / court alongside the asymmetric pair", () => {
expect(followUpsDifferByParty([
{ primary_party: "both" },
{ primary_party: "claimant" },
{ primary_party: "court" },
{ primary_party: "defendant" },
])).toBe(true);
});
test("false on empty list", () => {
expect(followUpsDifferByParty([])).toBe(false);
});
});