Home Features Docs Blog Security Examples FAQ
Documentation

Learn djust Inside & Out.

Everything you need to build reactive, real-time Django applications with djust.

Testing

Test your LiveViews, components, and forms with djust's testing utilities.

LiveViewTestClient

Test LiveViews without a browser or WebSocket:

from djust.testing import LiveViewTestClient
from myapp.views import CounterView

def test_counter():
    client = LiveViewTestClient(CounterView)
    client.mount()

    client.assert_state(count=0)
    client.send_event('increment')
    client.assert_state(count=1)

    html = client.render()
    assert 'Count: 1' in html

Test Client Methods

Method Description
mount(**params) Initialize the view with parameters
send_event(event_name, **params) Send an event and get the result
assert_state(**expected) Assert state values
render() Get rendered HTML

With pytest

import pytest
from djust.testing import LiveViewTestClient

@pytest.fixture
def search_client():
    return LiveViewTestClient(SearchView)

def test_search(search_client):
    search_client.mount()
    search_client.send_event('search', query='laptop')
    assert len(search_client.state['results']) > 0

With Django TestCase

from django.test import TestCase
from djust.testing import LiveViewTestClient

class TodoViewTests(TestCase):
    def setUp(self):
        self.client = LiveViewTestClient(TodoView)

    def test_add_todo(self):
        self.client.mount()
        self.client.send_event('add_todo', text='Buy milk')
        self.client.assert_state(
            todos=[{'text': 'Buy milk', 'done': False}]
        )

Testing Forms

def test_form_validation():
    client = LiveViewTestClient(ContactView)
    client.mount()

    # Test invalid email
    client.send_event('validate_field',
                      field_name='email',
                      value='invalid')
    assert 'email' in client.state['field_errors']

    # Test valid submission
    client.send_event('submit', data={
        'name': 'John',
        'email': 'john@example.com',
        'message': 'Hello!'
    })
    assert client.state.get('success_message')

Snapshot Testing

from djust.testing import SnapshotTestMixin
from django.test import TestCase

class ProfileViewSnapshotTests(SnapshotTestMixin, TestCase):
    def test_profile_renders_correctly(self):
        client = LiveViewTestClient(ProfileView)
        client.mount(user_id=1)

        self.assertMatchesSnapshot(
            client.render(),
            'profile_view'
        )

Performance Testing

from djust.testing import performance_test

class PerformanceTests(TestCase):

    @performance_test(max_time_ms=100, max_queries=5)
    def test_dashboard_performance(self):
        client = LiveViewTestClient(DashboardView)
        client.mount()
        client.send_event('refresh_data')

Integration Testing

With Selenium

from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class BrowserTests(StaticLiveServerTestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.browser = webdriver.Chrome()

    def test_counter_increments(self):
        self.browser.get(f'{self.live_server_url}/counter/')

        # Wait for LiveView connection
        WebDriverWait(self.browser, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '[dj-connected]'))
        )

        # Click increment
        button = self.browser.find_element(By.CSS_SELECTOR, '[dj-click="increment"]')
        button.click()

        # Assert updated
        WebDriverWait(self.browser, 5).until(
            EC.text_to_be_present_in_element((By.CSS_SELECTOR, 'h1'), 'Count: 1')
        )

With Playwright

def test_counter_with_playwright(browser, live_server):
    page = browser.new_page()
    page.goto(f'{live_server.url}/counter/')

    page.wait_for_selector('[dj-connected]')
    page.click('[dj-click="increment"]')
    page.wait_for_selector('text=Count: 1')

Best Practices

Test State Changes, Not Implementation

# Good
client.mount()
client.send_event('increment')
client.assert_state(count=1)

# Bad
client.mount()
client.view.increment()  # Don't call methods directly

Test Edge Cases

def test_empty_list():
    client.mount()
    client.assert_state(items=[])

def test_many_items():
    client.mount()
    for i in range(100):
        client.send_event('add_item', name=f'Item {i}')
    assert len(client.state['items']) == 100

Next Steps