Lifecycle harness

Reproduce the LiveView integration bugs that break animation hooks — before the team hits them.

FLIP-tracked
(_layoutElements.size)
Mounted hooks
([data-lm-config])
0
Spawn/clear
cycles
Leak harness — 0 live element(s)
destroyed() cleanup & leaks
What
Removing a motion element must run destroyed(): clear the loop timer, run all _cleanups, disconnect observers, and untrack FLIP.
Why risky
Leaked IntersectionObservers, event listeners, or an orphaned setTimeout loop accumulate over a long session.
How to trigger
Spawn a batch of elements (in_view + loop + hover + layout all set), then destroy them. Repeat several cycles.
Expected
After Clear all, the FLIP-tracking map returns to 0 and mounted-hook count returns to baseline; nothing climbs monotonically across cycles.
Failure looks like
Counters climb every cycle → a leak to fix before rollout.
Code
assets/js/live_animate.js:257 (destroyed)assets/js/live_animate.js:477 (IntersectionObserver)
Exit-race harness — 0 item(s)
Exit animation race (rapid add/remove)
What
Exit uses the phx-remove transition binding (time = duration + 50) plus a MutationObserver on the lm-animating-exit class.
Why risky
Removing many elements in one batch, or re-adding an element with the same id mid-exit, can race the observer or strand a position:fixed clone.
How to trigger
Add a batch, then Remove all (fast); or Remove + re-add same id, which re-adds 50ms into the exit.
Expected
Every exiting element animates out and is fully removed; no ghost fixed clones; the re-added id animates in cleanly.
Failure looks like
Leftover fixed-position ghosts, elements that vanish with no exit, or a re-added id that never animates.
Code
assets/js/live_animate.js:326 (_setupExit)assets/js/live_animate.js:355 (exit observer)