PhoenixLiveGantt.TestHelpers (PhoenixLiveGantt v0.1.1)

Copy Markdown View Source

Render, inspect, and assert helpers for the PhoenixLiveGantt view. Replaces ad-hoc probe scripts with a one-line call. Used from tests, IEx, and the mix phoenix_live_gantt.dump task.

events = [%PhoenixLiveGantt.Task{id: "a", start: ~D[2026-04-01], end: ~D[2026-04-05]}]
html = render_waterfall(events)
geom = inspect_waterfall(events)
dump_waterfall(events)        # pretty-prints to stdout

Pass any waterfall attr as an option:

render_waterfall(events,
  connectors: [%{from: "a", to: "b"}],
  zoom: :day,
  bus_stagger_outgoing_px: 4
)

:date_range defaults to a tight range derived from the events.

Also provides geometry assertions for tests:

Lives in lib/ (not test/support/) because the mix task uses it at dev runtime.

Summary

Functions

Assert that no connector's arrow tip pierces meaningfully INTO the target bar.

Assert that every arrowhead sits on its connector's shaft END — the head is drawn in a separate, non-stretched overlay layer (so it stays a crisp px triangle while the shaft SVG stretches with the responsive fill), and it must track the shaft's TRUE terminal point even after path rewrites (consolidate_piercing_trunks can re-route a forward path so it ends at a different y). :tol_px (default 2) absorbs the percent↔pixel round-trip.

Assert that every detour path satisfies the geometric invariants PhoenixLiveGantt's stem-shifting logic relies on

Assert that all SOURCE attach y values for connectors emerging from source_id are evenly spaced. Catches lane-stagger rounding bugs.

Assert that no connector's trunk visually pierces an unrelated bar. Walks each path's vertical trunk segment and checks that no other task's bar rectangle (excluding the connector's own endpoints) sits in the trunk's x-column AND overlaps the trunk's y-span.

Assert every connector's path consists only of axis-aligned segments (pure horizontal H or vertical V moves from the initial M point). Catches malformed paths or unexpected shape families.

Assert all numeric path coordinates are non-negative. Negative coords mean a path went off the chart's left/top edge — usually a bug.

Assert that every connector's SOURCE attach y falls inside the source bar's actual vertical extent (with optional inset for rounded corners).

Compare two geometry maps and return a structured diff describing what changed. Useful for "I changed X — what else moved?" workflows.

Render, inspect, and pretty-print to stdout. Returns the geometry map for further inspection.

Run every geometry assertion against the given html and return a list of issues found. Each issue is {name, exception_message}. Useful as a one-stop "is this render sane?" check.

Render then immediately inspect into a structured geometry map.

Render the PhoenixLiveGantt component with the given events and options. All component attrs default to their declared defaults; opts override. Returns the rendered HTML string.

Functions

assert_arrow_tips_clear_target_bars(html, opts \\ [])

Assert that no connector's arrow tip pierces meaningfully INTO the target bar.

Arrow tips intentionally land ON the target bar's edge (gap 0) so they read as connected at any responsive fill factor — visual separation is the fixed-px arrowhead overlay's job, not a natural-px gap that would stretch. So this guards against tips landing INSIDE the bar (a refX/offset bug): a tip is a violation when it sits more than :tol_px (default 2, absorbing the percent↔pixel round-trip) to the bar-interior side of the near edge. Only FS arrows (target_entry=:west) are checked, since their geometry is the most predictable.

assert_arrowheads_at_path_ends(html, opts \\ [])

Assert that every arrowhead sits on its connector's shaft END — the head is drawn in a separate, non-stretched overlay layer (so it stays a crisp px triangle while the shaft SVG stretches with the responsive fill), and it must track the shaft's TRUE terminal point even after path rewrites (consolidate_piercing_trunks can re-route a forward path so it ends at a different y). :tol_px (default 2) absorbs the percent↔pixel round-trip.

assert_detour_invariants_hold(html)

Assert that every detour path satisfies the geometric invariants PhoenixLiveGantt's stem-shifting logic relies on:

  • stem_out > x1 — source-side stem must be strictly east of the source bar's reference x (FS shape requirement).
  • stem_in < arrow_stop — target-side stem must be strictly west of the arrow tip (FS approach requirement).

Catches regressions in maybe_shift_stem_out / maybe_shift_stem_in where a stem could be shifted to an x that breaks the shape's geometric validity.

assert_lanes_evenly_spaced(html, source_id, opts \\ [])

Assert that all SOURCE attach y values for connectors emerging from source_id are evenly spaced. Catches lane-stagger rounding bugs.

Pass :tolerance_px (default 0) to allow off-by-N differences in spacings (useful for sub-pixel rendering).

assert_no_unrelated_bar_pierced(html, opts \\ [])

Assert that no connector's trunk visually pierces an unrelated bar. Walks each path's vertical trunk segment and checks that no other task's bar rectangle (excluding the connector's own endpoints) sits in the trunk's x-column AND overlaps the trunk's y-span.

Catches the "arrow visibly cuts through a task bar" class of bug that avoid_collisions is supposed to prevent.

Pass :tolerance_px (default 0) to allow slight overlaps (useful for cases where a bar shares an x-edge with the trunk by 1px).

assert_paths_axis_aligned(html)

Assert every connector's path consists only of axis-aligned segments (pure horizontal H or vertical V moves from the initial M point). Catches malformed paths or unexpected shape families.

assert_paths_have_valid_coords(html, opts \\ [])

Assert all numeric path coordinates are non-negative. Negative coords mean a path went off the chart's left/top edge — usually a bug.

Pass :allow_negative to skip (some edge cases legitimately do go negative, e.g., :ss arrows near x=0).

assert_source_attaches_inside_bar(html, opts \\ [])

Assert that every connector's SOURCE attach y falls inside the source bar's actual vertical extent (with optional inset for rounded corners).

Uses Inspector's per-bar top/bottom (derived from real row positions, including group headers) — accurate even when group headers shift the row stride.

:corner_inset_px (default 4) — px to inset from bar's top/bottom for the rounded-corner area. Defaults match PhoenixLiveGantt's bus_stagger_corner_clearance_px.

diff_waterfalls(before_geom, after_geom)

Compare two geometry maps and return a structured diff describing what changed. Useful for "I changed X — what else moved?" workflows.

before = inspect_waterfall(events)
# ... change something ...
after = inspect_waterfall(events)
diff_waterfalls(before, after)
# %{
#   row_order: %{changed: false} | %{from: [...], to: [...]},
#   connectors: %{added: [...], removed: [...], changed: [...]},
#   edges: %{earlier_delta: int, later_delta: int}
# }

dump_waterfall(events, opts \\ [])

@spec dump_waterfall(
  [PhoenixLiveGantt.Task.t()],
  keyword()
) :: map()

Render, inspect, and pretty-print to stdout. Returns the geometry map for further inspection.

find_geometry_issues(html, opts \\ [])

Run every geometry assertion against the given html and return a list of issues found. Each issue is {name, exception_message}. Useful as a one-stop "is this render sane?" check.

Pass :opts_for to override per-assertion options:

find_geometry_issues(html,
  opts_for: %{
    assert_arrow_tips_clear_target_bars: [min_gap_px: 2]
  }
)

inspect_waterfall(events, opts \\ [])

@spec inspect_waterfall(
  [PhoenixLiveGantt.Task.t()],
  keyword()
) :: map()

Render then immediately inspect into a structured geometry map.

render_waterfall(events, opts \\ [])

@spec render_waterfall(
  [PhoenixLiveGantt.Task.t()],
  keyword()
) :: String.t()

Render the PhoenixLiveGantt component with the given events and options. All component attrs default to their declared defaults; opts override. Returns the rendered HTML string.