Testing API Reference
On this page
from djust.testing import LiveViewTestClient, SnapshotTestMixin, LiveViewSmokeTest, performance_test
class LiveViewTestClient
Test LiveViews without a browser or WebSocket connection.
LiveViewTestClient(view_class, request_factory=None, user=None)
Parameters:
view_class— TheLiveViewsubclass to testrequest_factory— Optional DjangoRequestFactory. Creates one if not provided.user— Optional authenticated user to attach to requests.
Methods
mount(via_websocket=True, **params) -> LiveViewTestClient
Initialize the view. Calls mount() on the LiveView. The default
via_websocket=True mounts as the WebSocket path does; pass
via_websocket=False to exercise the HTTP-prerender branch instead. No
login or permission check runs here.
client = LiveViewTestClient(MyView)
client.mount() # No URL params
client.mount(item_id=5) # With URL kwargs
client.mount(page=2, query="test") # Multiple params
Returns self for chaining.
send_event(event_name, raise_on_missing=True, **params) -> dict
Send an event to the view. Calls the named event handler.
result = client.send_event("increment")
result = client.send_event("search", value="laptop")
result = client.send_event("delete_item", item_id=5)
Parameters:
event_name(str) — The handler method nameraise_on_missing(bool) — IfTrue(default), raiseNoHandlerFoundErrorwhen no handler exists forevent_name. PassFalseto get a{"success": False, ...}result instead.**params— Event parameters passed to the handler
Returns: a dict with the keys success, error, state_before, state_after and duration_ms. The handler's own return value is discarded.
An exception raised inside the handler is captured and reported as success=False with the message in error; it is not raised. Assert result["success"] so a crashing handler fails your test:
result = client.send_event("search", value="laptop")
assert result["success"], result["error"]
assert_state(**expected)
Assert that the view's current state matches the expected values.
client.assert_state(count=3)
client.assert_state(is_valid=True, success_message="Saved!")
Raises AssertionError if any attribute doesn't match.
render() -> str
Render the current state to HTML and return it.
html = client.render()
assert "laptop" in html
assert "<li>" in html
get_state() -> dict
The current view state as a dictionary. Useful for assertions not covered by assert_state():
state = client.get_state()
assert "email" in state["field_errors"]
assert len(state["items"]) == 3
Example: Full Test
from django.test import TestCase
from djust.testing import LiveViewTestClient
from myapp.views import CounterView
class TestCounterView(TestCase):
def test_initial_state(self):
client = LiveViewTestClient(CounterView)
client.mount()
client.assert_state(count=0)
def test_increment(self):
client = LiveViewTestClient(CounterView)
client.mount()
client.send_event("increment")
client.assert_state(count=1)
client.send_event("increment")
client.assert_state(count=2)
def test_renders_count(self):
client = LiveViewTestClient(CounterView)
client.mount()
client.send_event("increment")
html = client.render()
self.assertIn("1", html)
def test_authenticated(self):
from django.contrib.auth.models import User
user = User.objects.create_user("test", password="pass")
client = LiveViewTestClient(ProtectedView, user=user)
client.mount()
# `user` is not view state; check the request the view was mounted with
self.assertEqual(client.view_instance.request.user, user)
class SnapshotTestMixin
Compare rendered HTML against stored snapshot files.
Methods
assert_html_snapshot(name, html)
Normalize html (whitespace, comments) and compare it against a stored snapshot at <test file's directory>/snapshots/{name}.html.snapshot.
On first run, saves the snapshot. Subsequent runs compare against it.
Parameters:
name(str) — Snapshot name (no extension)html(str) — HTML to compare
Class attributes:
snapshot_dir(str, default"snapshots") — directory, relative to the test file, that holds snapshotsupdate_snapshots(bool, defaultFalse) — ifTrue, overwrite stored snapshots instead of comparing
from django.test import TestCase
from djust.testing import LiveViewTestClient, SnapshotTestMixin
from myapp.views import ProductCardView
class TestProductCard(TestCase, SnapshotTestMixin):
def test_renders_product(self):
client = LiveViewTestClient(ProductCardView)
client.mount(product_id=1)
self.assert_html_snapshot("product_card_default", client.render())
To update all snapshots after an intentional UI change:
UPDATE_SNAPSHOTS=1 pytest
class LiveViewSmokeTest
Auto-discover all LiveView subclasses in an app and run smoke tests.
Class Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
app_label | str | None | Only test views in this Django app |
max_queries | int | 50 | Fail if mounting + rendering a view exceeds this many DB queries |
fuzz | bool | True | Send XSS and type-mismatch payloads to handlers |
skip_views | list | [] | View classes to skip |
view_config | dict | {} | Per-view setup: {ViewClass: {"mount_params": {...}, "user": user}} |
Example
from django.test import TestCase
from djust.testing import LiveViewSmokeTest
class TestAllMyAppViews(TestCase, LiveViewSmokeTest):
app_label = "myapp"
max_queries = 15
fuzz = True
This auto-discovers all LiveView subclasses in myapp and:
- Mounts each view
- Asserts it renders without raising
- Checks DB query counts stay under
max_queries - If
fuzz=True, sends malformed payloads and asserts no uncaught exceptions
@performance_test
Decorator that enforces performance budgets on test methods.
@performance_test(max_time_ms=50, max_queries=3)
Parameters:
max_time_ms(float, default100) — Maximum milliseconds the whole test method may takemax_queries(int, default10) — Maximum DB queries allowed across the whole test methodtrack_memory(bool, defaultFalse) — Track memory allocated during the test withtracemallocmax_memory_bytes(int, optional) — Maximum bytes allocated whentrack_memory=True
from django.test import TestCase
from djust.testing import LiveViewTestClient, performance_test
class TestSearchPerformance(TestCase):
@performance_test(max_time_ms=50, max_queries=3)
def test_search_is_fast(self):
client = LiveViewTestClient(SearchView)
client.mount()
client.send_event("search", value="laptop")
Fails if the whole test method — including client setup and mount(), not just search — takes more than 50 ms or runs more than 3 queries.
See Also
- Testing guide — patterns and best practices
- LiveView API