Skip to content

Commit 54af7c5

Browse files
committed
add basic test of IDOM
1 parent edeadbe commit 54af7c5

File tree

10 files changed

+96
-25
lines changed

10 files changed

+96
-25
lines changed

noxfile.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ def test(session: Session) -> None:
4646
@nox.session
4747
def test_suite(session: Session) -> None:
4848
"""Run the Python-based test suite"""
49-
session.env["IDOM_DEBUG_MODE"] = "1"
5049
install_requirements_file(session, "test-env")
5150
session.install(".[all]")
52-
session.chdir("tests")
53-
session.run("figure-it-out")
51+
52+
session.chdir(HERE / "tests")
53+
session.env["IDOM_DEBUG_MODE"] = "1"
54+
session.run("python", "manage.py", "build_js")
55+
session.run("python", "manage.py", "test")
5456

5557

5658
@nox.session

requirements/test-env.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
django
2+
selenium
3+
4+
# required due issue with channels:
5+
# https://github.com/django/channels/issues/1639#issuecomment-817994671
6+
twisted<21

src/django_idom/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
from .websocket_consumer import IdomAsyncWebSocketConsumer
44

5+
56
__all__ = ["IdomAsyncWebSocketConsumer"]

src/django_idom/websocket_consumer.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
from typing import Any
44

55
from channels.generic.websocket import AsyncJsonWebsocketConsumer
6-
7-
from idom.core.layout import Layout
86
from idom.core.dispatcher import dispatch_single_view
9-
from idom.core.component import ComponentConstructor
7+
from idom.core.layout import Layout, LayoutEvent
8+
from idom.core.proto import ComponentConstructor
109

1110

1211
class IdomAsyncWebSocketConsumer(AsyncJsonWebsocketConsumer):
@@ -20,22 +19,26 @@ def __init__(
2019

2120
async def connect(self) -> None:
2221
await super().connect()
23-
self._idom_recv_queue = recv_queue = asyncio.Queue()
24-
self._idom_dispatcher_future = asyncio.ensure_future(
25-
dispatch_single_view(
26-
Layout(self._idom_component_constructor()),
27-
self.send_json,
28-
recv_queue.get,
29-
)
30-
)
22+
self._idom_dispatcher_future = asyncio.ensure_future(self._run_dispatch_loop())
3123

32-
async def close(self, *args: Any, **kwargs: Any) -> None:
24+
async def disconnect(self, code: int) -> None:
3325
if self._idom_dispatcher_future.done():
3426
await self._idom_dispatcher_future
3527
else:
3628
self._idom_dispatcher_future.cancel()
37-
await asyncio.wait([self._idom_dispatcher_future])
38-
await super().close(*args, **kwargs)
29+
await super().disconnect(code)
3930

4031
async def receive_json(self, content: Any, **kwargs: Any) -> None:
41-
await self._idom_recv_queue.put(content)
32+
await self._idom_recv_queue.put(LayoutEvent(**content))
33+
34+
async def _run_dispatch_loop(self):
35+
self._idom_recv_queue = recv_queue = asyncio.Queue()
36+
try:
37+
await dispatch_single_view(
38+
Layout(self._idom_component_constructor()),
39+
self.send_json,
40+
recv_queue.get,
41+
)
42+
except Exception:
43+
await self.close()
44+
raise

tests/test_app/asgi.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
from django.conf.urls import url
1313
from django.core.asgi import get_asgi_application
1414

15-
from .views import HelloWorld
15+
from .views import Root
16+
1617

1718
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_app.settings")
1819

@@ -23,11 +24,12 @@
2324

2425
from django_idom import IdomAsyncWebSocketConsumer
2526

27+
2628
application = ProtocolTypeRouter(
2729
{
2830
"http": http_asgi_app,
2931
"websocket": URLRouter(
30-
[url("", IdomAsyncWebSocketConsumer.as_asgi(component=HelloWorld))]
32+
[url("", IdomAsyncWebSocketConsumer.as_asgi(component=Root))]
3133
),
3234
}
3335
)

tests/test_app/management/commands/build_js.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import subprocess
22
from pathlib import Path
3+
34
from django.core.management.base import BaseCommand
45

6+
57
HERE = Path(__file__).parent
68
JS_DIR = HERE.parent.parent.parent / "js"
79

tests/test_app/settings.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import os
1313
from pathlib import Path
1414

15+
1516
# Build paths inside the project like this: BASE_DIR / 'subdir'.
1617
BASE_DIR = Path(__file__).resolve().parent.parent
1718

@@ -78,8 +79,11 @@
7879
DATABASES = {
7980
"default": {
8081
"ENGINE": "django.db.backends.sqlite3",
81-
"NAME": BASE_DIR / "db.sqlite3",
82-
}
82+
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
83+
"TEST": {
84+
"NAME": os.path.join(BASE_DIR, "db_test.sqlite3"),
85+
},
86+
},
8387
}
8488

8589

tests/test_app/tests.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1-
from django.test import TestCase
1+
from channels.testing import ChannelsLiveServerTestCase
2+
from selenium import webdriver
3+
from selenium.webdriver.support.ui import WebDriverWait
24

3-
# Create your tests here.
5+
6+
class TestIdomCapabilities(ChannelsLiveServerTestCase):
7+
def setUp(self):
8+
self.driver = make_driver(5, 5)
9+
self.driver.get(self.live_server_url)
10+
11+
def tearDown(self) -> None:
12+
self.driver.quit()
13+
14+
def wait_until(self, condition, timeout=5):
15+
WebDriverWait(self.driver, timeout).until(lambda driver: condition())
16+
17+
def test_hello_world(self):
18+
self.driver.find_element_by_id("hello-world")
19+
20+
def test_counter(self):
21+
button = self.driver.find_element_by_id("counter-inc")
22+
count = self.driver.find_element_by_id("counter-num")
23+
24+
for i in range(5):
25+
self.wait_until(lambda: count.get_attribute("data-count") == str(i))
26+
button.click()
27+
28+
29+
def make_driver(page_load_timeout, implicit_wait_timeout):
30+
driver = webdriver.Chrome()
31+
driver.set_page_load_timeout(page_load_timeout)
32+
driver.implicitly_wait(implicit_wait_timeout)
33+
return driver

tests/test_app/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
1919
"""
2020
from django.urls import path
21+
2122
from .views import base_template
2223

24+
2325
urlpatterns = [path("", base_template)]

tests/test_app/views.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import idom
2-
from django.template import loader
32
from django.http import HttpResponse
3+
from django.template import loader
44

55

66
def base_template(request):
@@ -9,6 +9,26 @@ def base_template(request):
99
return HttpResponse(template.render(context, request))
1010

1111

12+
@idom.component
13+
def Root():
14+
return idom.html.div(HelloWorld(), Counter())
15+
16+
1217
@idom.component
1318
def HelloWorld():
1419
return idom.html.h1({"id": "hello-world"}, "Hello World!")
20+
21+
22+
@idom.component
23+
def Counter():
24+
count, set_count = idom.hooks.use_state(0)
25+
return idom.html.div(
26+
idom.html.button(
27+
{"id": "counter-inc", "onClick": lambda event: set_count(count + 1)},
28+
"Click me!",
29+
),
30+
idom.html.p(
31+
{"id": "counter-num", "data-count": count},
32+
f"Current count is: {count}",
33+
),
34+
)

0 commit comments

Comments
 (0)