## Testplan – Stack link (`data-stack-link`) & z-index ### A. Regler (krav som testes) - **SL1**: Hvert event har en gyldig `data-stack-link` JSON med felterne `{ prev, stackLevel }`. - **SL2**: `stackLevel` ≥ 1 og heltal. Nederste event i en stack har `prev = null` og `stackLevel = 1`. - **SL3**: `prev` refererer til **eksisterende** event-ID i **samme lane** (ingen cross-lane links). - **SL4**: Kæden er **acyklisk** (ingen loops) og uden “dangling” referencer. - **SL5**: For en given stack er levels **kontiguøse** (1..N uden huller). - **SL6**: Ved **flyt/resize/slet** genberegnes stack-links deterministisk (samme input ⇒ samme output). - **Z1**: z-index er en **strengt voksende funktion** af `stackLevel` (fx `zIndex = base + stackLevel`). - **Z2**: For overlappende events i **samme lane** gælder: højere `stackLevel` **renderes visuelt ovenpå** lavere level (ingen tekst skjules af et lavere level). - **Z3**: z-index må **ikke** afhænge af DOM-indsættelsesrækkefølge—kun af `stackLevel` (og evt. lane-offset). - **Z4** (valgfrit): På tværs af lanes kan systemet enten bruge samme base eller lane-baseret offset (fx `zIndex = lane*100 + stackLevel`). Uanset valg må events i **samme lane** aldrig blive skjult af events i en **anden** lane, når de overlapper visuelt. ### B. Unit tests (logik for stack link) 1. **Basestack** *Givet* en enkelt event A 10:00–11:00, *Når* stack beregnes, *Så* `A.prev=null` og `A.stackLevel=1` (SL2). 2. **Simpel overlap** *Givet* A 10:00–13:00 og B 10:45–11:15 i samme lane, *Når* stack beregnes, *Så* `B.prev='A'` og `B.stackLevel=2` (SL1–SL3). 3. **Fler-leddet overlap** *Givet* A 10–13, B 10:45–11:15, C 11:00–11:30, *Når* stack beregnes, *Så* `B.stackLevel=2`, `C.stackLevel≥2`, ingen huller i levels (SL5). 4. **Ingen overlap** *Givet* A 10:00–11:00 og B 11:30–12:00 i samme lane, *Når* stack beregnes, *Så* `A.stackLevel=1`, `B.stackLevel=1`, `prev=null` for begge (SL2). 5. **Cross-lane isolation** *Givet* A(lane1) 10–13 og B(lane2) 10:15–11:00, *Når* stack beregnes, *Så* `B.prev` **må ikke** pege på A (SL3). 6. **Acyklisk garanti** *Givet* en vilkårlig mængde overlappende events, *Når* stack beregnes, *Så* kan traversal fra top → `prev` aldrig besøge samme ID to gange (SL4). 7. **Sletning i kæde** *Givet* A→B→C (`prev`-kæde), *Når* B slettes, *Så* peger C.prev nu på A (eller `null` hvis A ikke findes), og levels reindekseres 1..N (SL5–SL6). 8. **Resize der fjerner overlap** *Givet* A 10–13 og B 10:45–11:15 (stacked), *Når* B resizes til 13:00–13:30, *Så* `B.prev=null`, `B.stackLevel=1` (SL6). 9. **Determinisme** *Givet* samme inputliste i samme sortering, *Når* stack beregnes to gange, *Så* er output (prev/stackLevel pr. event) identisk (SL6). ### C. Integration/DOM tests (z-index & rendering) 10. **Z-index mapping** *Givet* mapping `zIndex = base + stackLevel`, *Når* tre overlappende events har levels 1,2,3, *Så* er `zIndex` hhv. stigende og uden lighed (Z1). 11. **Visuel prioritet** *Givet* to overlappende events i samme lane med levels 1 (A) og 2 (B), *Når* kalenderen renderes, *Så* kan B’s titel læses fuldt ud, og A’s ikke dækker B (Z2). 12. **DOM-orden er irrelevant** *Givet* to overlappende events, *Når* DOM-indsættelsesrækkefølgen byttes, *Så* er visuel orden uændret, styret af z-index (Z3). 13. **Lane-isolation** *Givet* A(lane1, level 2) og B(lane2, level 1), *Når* de geometrisk overlapper (smal viewport), *Så* skjuler lane2 ikke lane1 i strid med reglen—afhængigt af valgt z-index strategi (Z4). Dokumentér valgt strategi. 14. **Tekst-visibility** *Givet* N overlappende events, *Når* der renderes, *Så* er der ingen CSS-egenskaber (opacity/clip/overflow) der gør højere level mindre synlig end lavere (Z2). ### D. Scenarie-baserede tests (1–7) 15. **S1 – Overlap ovenpå** Lunch `prev=Excursion`, `stackLevel=2`; `zIndex(Lunch) > zIndex(Excursion)`. 16. **S2 – Flere overlappende** Lunch og Breakfast har `stackLevel≥2`; ingen huller 1..N; z-index følger levels. 17. **S3 – Side-by-side** Overlappende events i samme lane har stigende `stackLevel`; venstre offset stiger med level; z-index følger levels. 18. **S4 – Sekvens** For hvert overlap i sekvens: korrekt `prev` til nærmeste base; contiguøse levels; z-index stigende. 19. **S5 – <30 min ⇒ lane 2** Lunch i lane 2; ingen `prev` der peger cross-lane; levels starter ved 1 i begge lanes; z-index valideres pr. lane. 20. **S6 – Stack + lane** Lane 1: Excursion & Breakfast (levels 1..N). Lane 2: Lunch (level 1). Ingen cross-lane `prev`. Z-index korrekt i lane 1. 21. **S7 – Frivillig lane 2** Events i lane 2 har egne levels startende på 1; z-index følger levels i hver lane. ### E. Edge cases 22. **Samme starttid** To events med identisk start i samme lane fordeles deterministisk: det først behandlede bliver base (`level=1`), det næste `level=2`. Z-index følger. 23. **Mange levels** *Givet* 6 overlappende events, *Når* der renderes, *Så* er levels 1..6 uden huller og z-index 6 er visuelt øverst. 24. **Ugyldigt JSON** *Givet* en defekt `data-stack-link`, *Når* komponenten loader, *Så* logges fejl og stack genberegnes fra start/end (self-healing), hvorefter valid `data-stack-link` skrives (SL1, SL6). ### F. Implementationsnoter (hjælp til test) - Z-index funktion bør være **enkel og auditérbar**, fx: `zIndex = 100 + stackLevel` (samme lane) eller `zIndex = lane*100 + stackLevel` (multi-lane isolation). - Test for acykliskhed: lav traversal fra hver node: gentagen ID ⇒ fejl. - Test for contiguity: hent alle `stackLevel` i en stack, sortér, forvent `[1..N]` uden huller. - Test for cross-lane: sammenlign `event.dataset.lane` for `id` og dets `prev`—de skal være ens.