djust 0.5.1rc3

Pre-releaseReleased

Added

  • LiveView testing utilities (v0.5.1 P2) — Seven new methods on LiveViewTestClient for Phoenix LiveViewTest parity: assert_push_event(event_name, params=None) verifies a handler queued a client-bound push event (payload match is subset-based so tests stay resilient to later payload additions); assert_patch(path=None, params=None) / assert_redirect(path=None, params=None) assert live_patch / live_redirect calls; render_async() drains pending start_async / assign_async tasks synchronously so subsequent assertions see their results; follow_redirect() resolves the queued redirect via Django's URL router and returns a new test client mounted on the destination view; assert_stream_insert(stream_name, item=None) verifies stream operations (item subset-match for dicts); trigger_info(message) synthetically delivers a handle_info message so pubsub / pg_notify handlers can be tested without real backend wiring. Full user-facing guide at docs/website/guides/testing.md. 21 new test cases. (python/djust/testing.py)
  • dj-dialog — native <dialog> modal integration (v0.5.1 P2) — Declarative opt-in for the HTML <dialog> element's built-in modal behavior. Mark a <dialog> with dj-dialog="open" to call showModal() (backdrop, focus-trap, and Escape handling all browser-native); set dj-dialog="close" to call close(). A document-level MutationObserver watches for attribute changes and DOM insertions so VDOM morphs that swap dj-dialog work automatically without per-element re-registration. Idempotent — re-asserting "open" on an already-open dialog is a no-op; gracefully ignores non-<dialog> elements carrying the attribute. ~80 LOC JS in python/djust/static/djust/src/35-dj-dialog.js. 8 JSDOM tests in tests/js/dj_dialog.test.js.
  • Type-safe template validation — manage.py djust_typecheck (v0.5.1 P2, differentiator) — Static analysis that reads every LiveView template, extracts every variable and tag reference, and reports names not covered by the view's declared context. "Declared context" is the union of public class attributes, self.foo = ... assignments anywhere in the class (AST-extracted — not run), @property methods, literal-dict keys returned from get_context_data, template-local bindings ({% for %} / {% with %} / {% inputs_for as %}), framework built-ins (user, request, csrf_token, forloop, djust, etc.), and anything listed in settings.DJUST_TEMPLATE_GLOBALS. Silencing: per-template pragma ({# djust_typecheck: noqa name1, name2 #}), per-view strict_context = True opt-in, or the project-wide globals setting. Flags: --json, --strict, --app, --view. Neither Phoenix nor React catches template-variable typos statically without an external type system — this is a genuine djust differentiator. 14 tests in python/djust/tests/test_djust_typecheck.py. Full guide at docs/website/guides/typecheck.md. (python/djust/management/commands/djust_typecheck.py)
  • Dev-mode error overlay (v0.5.1 P2) — Next.js/Vite-style full-screen error panel that renders in the browser whenever a LiveView handler raises an exception and Django DEBUG=True. Displays the error message, the event that triggered the handler, the server-sent Python traceback, an optional hint, and validation details when present. Dismissal: Escape key, close button, or backdrop click. A second error replaces the current panel rather than stacking. All field values HTML-escaped to prevent traceback injection. Gated on window.DEBUG_MODE — production builds render nothing (Django also strips traceback / debug_detail / hint from the error frame in non-DEBUG mode, so there's nothing to leak). Exposes window.djustErrorOverlay.show(detail) / .dismiss() for manual invocation from devtools. 10 JSDOM tests in tests/js/error_overlay.test.js. Full guide at docs/website/guides/error-overlay.md. (python/djust/static/djust/src/36-error-overlay.js)
  • Nested formset helpers — {% inputs_for %} + FormSetHelpersMixin (v0.5.1 P2) — djust-native support for Django formset / inline-formset patterns. Template side: {% inputs_for formset as form %}...{% endinputs_for %} iterates any BaseFormSet and exposes each bound child form with its per-row prefix intact so rendered inputs submit under the correct Django-expected names; loop metadata (inputs_for_loop.counter, .counter0, .first, .last) mirrors the {% for %} conventions. Server side: djust.formsets.add_row(cls, data=..., prefix=...) and remove_row(cls, row_prefix, data=..., prefix=...) handle management-form bookkeeping — add_row bumps TOTAL_FORMS (capped at max_num when set, absolute_max otherwise) and preserves existing row data; remove_row writes the standard DELETE=on flag so formset.deleted_forms picks it up on save(). FormSetHelpersMixin wires pre-baked add_row / remove_row event handlers to a formset_classes = {"addresses": AddressFormSet} declaration, with the formset name doubling as the prefix so multiple formsets on one view don't collide on management-form keys. Fails loud if mount() forgets to initialize self._formset_data. 16 tests in python/djust/tests/test_formsets.py. (python/djust/formsets.py, python/djust/templatetags/djust_formsets.py)

All releases · Atom feed