Write unittests --------------- In the :ref:`quick start guide ` we created our first Brython app. Continuing it, let's create some tests, check if H1 is inserted into DOM, and our code is working properly. To run client side tests, you need to activate django-brython testing middleware: .. code-block:: python # project/settings.py MIDDLEWARE = [ # ... 'django_brython.middleware.BrythonUnittestMiddleware' ] Create test class, which will run in the browser. Place the testing logic into test_* functions as you do in normal Django testcases. .. code-block:: python # frontend/tests/brython.py from browser import document class BrythonTest: def test_example(self): h1 = document.getElementById('main') # Force AssertionError assert h1.text == 'wrong content' Start the dev server, and try to open the index page, with the following query string:: http://localhost:8000/backend/index/?__BRYTHON_UNITTEST__=frontend.tests.brython.BrythonTest.test_example So any view can test against any testcase specified by the full path in HTTP GET parameter. If you check the debug console in your browser, the assertion is shown. The MIDDLEWARE injekts the testing code at the end of your HTML, and runs it. Integrate test into Django testing framework ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you would like to run the previously created test when you call,:: python manage.py test then you need to connect the client side test with Django testing framework. Firstly create StaticLiveServerTestCase, which runs a browser with Selenium webdriver: .. code-block:: python # frontend/tests/test_django.py from django.contrib.staticfiles.testing import StaticLiveServerTestCase from selenium import webdriver from .brython import BrythonTest class Test1(StaticLiveServerTestCase, BrythonTest): def setUp(self): self.driver = webdriver.Chrome() def tearDown(self): self.driver.quit() This class inherits from LiveServerTestCase and also the previously created BrythonTest class. Modify the BrythonTest, and decorate the test_* methods: .. code-block:: python from browser import document from django_brython.testing import location, reverse class BrythonTest: @location(reverse('backend:index')) def test_example(self): h1 = document.getElementById('main') assert h1.text == 'wrong content' This decorator tells to the test runner which URL to open before running the client side Brython tests. Please use django_brython reverse method instead of Django's builtin. If you run the tests, the Brython exceptions will shown in the console:: python manage.py test Creating test database for alias 'default'... System check identified no issues (0 silenced). E ====================================================================== ERROR: test_example (frontend.tests.test_django.Test1) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/project/django_brython/testing.py", line 64, in dec return runner() File "/tmp/project/django_brython/testing.py", line 49, in __call__ raise Exception(test_result['exception']) Exception: Traceback (most recent call last): File "http://localhost:48535/backend/index/?__BRYTHON_UNITTEST__=frontend.tests.brython.BrythonTest.test_example/__main__2", line 9, in func() File "/brython/django_brython/testing.py", line 11, in dec return function(inst) File "/brython/frontend/tests/brython.py", line 11, in test_example assert h1.textContent == 'wrong content' AssertionError: AssertionError ---------------------------------------------------------------------- Ran 1 test in 13.104s FAILED (errors=1) Destroying test database for alias 'default'... Race conditions ^^^^^^^^^^^^^^^ If you run this test a lot of time, then sometimes you'll get AttributeError:: brython.js:6308 Traceback (most recent call last): File "http://localhost:8000/backend/index/?__BRYTHON_UNITTEST__=frontend.tests.brython.BrythonTest.test_example/__main__2", line 7, in func() File "/brython/django_brython/testing.py", line 36, in dec return function(inst) File "/brython/frontend/tests/brython.py", line 12, in test_example assert h.text == "wrong content" AttributeError: text This effect is because there is some race condittion between the client site codes (frontend/main.py) and the unittests. Each Brython script is loaded with ajax calls, in your client codes can have async functions too. That's why the scripts running order isn't predicted. **Solution 1:** Call your business logic from unittest. Modify the main.py, create a function: .. code-block:: python # frontend/main.py from browser import document, html def display(): print('Hello World from Brython') # Insert Header into document body document <= html.H1("HELLO FROM BRYTHON", Id="main") if __name__ == '__main__': display() .. code-block:: python from frontend.main import display class BrythonTest: @location(reverse('backend:index')) def test_example(self): display() h = document.getElementById("main") assert h.text == "HELLO FROM BRYTHON" **Solution 2:** Setup a *wait_for* condition in your location decorator. The test runner will wait until the specified condition is met: .. code-block:: python class BrythonTest: @location(reverse('backend:index'), wait_for=lambda: document.getElementById("main") is not None) def test_example(self): h = document.getElementById("main") assert h.text == "HELLO FROM BRYTHON"