Skip to content

Commit 55daaa2

Browse files
committed
Add new tests for form events
1 parent 3ed84db commit 55daaa2

File tree

8 files changed

+215
-5
lines changed

8 files changed

+215
-5
lines changed

tests/test_app/forms/components.py

+72-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from reactpy import component, html
1+
from reactpy import component, hooks, html
22

33
from reactpy_django.components import django_form
44

5-
from .forms import BasicForm, DatabaseBackedForm
5+
from .forms import BasicForm, DatabaseBackedForm, EventForm
66

77

88
@component
@@ -22,3 +22,73 @@ def bootstrap_form():
2222
@component
2323
def database_backed_form():
2424
return django_form(DatabaseBackedForm, bottom_children=(html.input({"type": "submit"}),))
25+
26+
27+
@component
28+
def sync_event_form():
29+
success, set_success = hooks.use_state(False)
30+
error, set_error = hooks.use_state(False)
31+
receive_data, set_receive_data = hooks.use_state(False)
32+
change, set_change = hooks.use_state(False)
33+
34+
def on_success(event):
35+
set_success(True)
36+
37+
def on_error(event):
38+
set_error(True)
39+
40+
def on_receive_data(event):
41+
set_receive_data(True)
42+
43+
def on_change(event):
44+
set_change(True)
45+
46+
return django_form(
47+
EventForm,
48+
on_success=on_success,
49+
on_error=on_error,
50+
on_receive_data=on_receive_data,
51+
on_change=on_change,
52+
top_children=[
53+
html.div({"id": "success", "data-value": success}, f"Success: {success}"),
54+
html.div({"id": "error", "data-value": error}, f"Error: {error}"),
55+
html.div({"id": "receive_data", "data-value": receive_data}, f"Receive Data: {receive_data}"),
56+
html.div({"id": "change", "data-value": change}, f"Change: {change}"),
57+
],
58+
bottom_children=[html.input({"type": "submit"})],
59+
)
60+
61+
62+
@component
63+
def async_event_form():
64+
success, set_success = hooks.use_state(False)
65+
error, set_error = hooks.use_state(False)
66+
receive_data, set_receive_data = hooks.use_state(False)
67+
change, set_change = hooks.use_state(False)
68+
69+
async def on_success(event):
70+
set_success(True)
71+
72+
async def on_error(event):
73+
set_error(True)
74+
75+
async def on_receive_data(event):
76+
set_receive_data(True)
77+
78+
async def on_change(event):
79+
set_change(True)
80+
81+
return django_form(
82+
EventForm,
83+
on_success=on_success,
84+
on_error=on_error,
85+
on_receive_data=on_receive_data,
86+
on_change=on_change,
87+
top_children=[
88+
html.div({"id": "success", "data-value": success}, f"Success: {success}"),
89+
html.div({"id": "error", "data-value": error}, f"Error: {error}"),
90+
html.div({"id": "receive_data", "data-value": receive_data}, f"Receive Data: {receive_data}"),
91+
html.div({"id": "change", "data-value": change}, f"Change: {change}"),
92+
],
93+
bottom_children=[html.input({"type": "submit"})],
94+
)

tests/test_app/forms/forms.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class BasicForm(forms.Form):
77
# Render one of every Django field type
88
# https://docs.djangoproject.com/en/stable/ref/forms/fields/#field-types
99
boolean_field = forms.BooleanField(label="boolean")
10-
char_field = forms.CharField(label="chars", max_length=7)
10+
char_field = forms.CharField(label="chars")
1111
choice_field = forms.ChoiceField(label="choice", choices=[("1", "One"), ("2", "Two")])
1212
date_field = forms.DateField(label="date")
1313
date_time_field = forms.DateTimeField(label="date time")
@@ -44,3 +44,7 @@ class DatabaseBackedForm(forms.ModelForm):
4444
class Meta:
4545
model = models.TodoItem
4646
fields = "__all__"
47+
48+
49+
class EventForm(forms.Form):
50+
char_field = forms.CharField(label="chars")

tests/test_app/forms/urls.py

+2
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@
66
path("form/", views.form),
77
path("form/bootstrap/", views.bootstrap_form),
88
path("form/model/", views.model_form),
9+
path("form/sync_event/", views.sync_event_form),
10+
path("form/async_event/", views.async_event_form),
911
]

tests/test_app/forms/views.py

+8
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ def bootstrap_form(request):
1111

1212
def model_form(request):
1313
return render(request, "model_form.html", {})
14+
15+
16+
def sync_event_form(request):
17+
return render(request, "sync_event_form.html", {})
18+
19+
20+
def async_event_form(request):
21+
return render(request, "async_event_form.html", {})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{% load static %} {% load reactpy %}
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
5+
<head>
6+
<meta charset="UTF-8" />
7+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
9+
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}" />
10+
<title>ReactPy</title>
11+
<style>
12+
iframe {
13+
width: 100%;
14+
height: 45px;
15+
}
16+
</style>
17+
</head>
18+
19+
<body>
20+
<h1>ReactPy Async Event Form Test Page</h1>
21+
<hr>
22+
{% component "test_app.forms.components.async_event_form" %}
23+
<hr>
24+
</body>
25+
26+
</html>

tests/test_app/templates/form.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
</head>
1818

1919
<body>
20-
<h1>ReactPy Forms Test Page</h1>
20+
<h1>ReactPy Form Test Page</h1>
2121
<hr>
2222
{% component "test_app.forms.components.basic_form" %}
2323
<hr>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{% load static %} {% load reactpy %}
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
5+
<head>
6+
<meta charset="UTF-8" />
7+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
9+
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}" />
10+
<title>ReactPy</title>
11+
<style>
12+
iframe {
13+
width: 100%;
14+
height: 45px;
15+
}
16+
</style>
17+
</head>
18+
19+
<body>
20+
<h1>ReactPy Sync Event Form Test Page</h1>
21+
<hr>
22+
{% component "test_app.forms.components.sync_event_form" %}
23+
<hr>
24+
</body>
25+
26+
</html>

tests/test_app/tests/test_components.py

+75-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import socket
44
from time import sleep
5+
from uuid import uuid4
56

67
import pytest
78
from playwright.sync_api import TimeoutError, expect
@@ -782,6 +783,7 @@ def test_bootstrap_form(self):
782783
def test_model_form(self):
783784
navigate_to_page(self, "/form/model/")
784785

786+
uuid = uuid4().hex
785787
self.page.wait_for_selector("form")
786788

787789
sleep(1)
@@ -792,8 +794,9 @@ def test_model_form(self):
792794
assert len(self.page.query_selector_all(".errorlist")) == 1
793795

794796
# Fill out the form
795-
self.page.locator("#id_text").type("test", delay=CLICK_DELAY)
797+
self.page.locator("#id_text").type(uuid, delay=CLICK_DELAY)
796798

799+
# Submit the form
797800
self.page.wait_for_selector("input[type=submit]").click(delay=CLICK_DELAY)
798801

799802
# Wait for the error message to disappear (indicating that the form has been re-rendered)
@@ -803,4 +806,75 @@ def test_model_form(self):
803806
assert len(self.page.query_selector_all(".errorlist")) == 0
804807

805808
# Make sure text field is empty
809+
expect(self.page.locator("#id_text")).to_be_empty()
806810
assert self.page.locator("#id_text").get_attribute("value") == ""
811+
812+
# Check if `auto_save` created the TodoItem's database entry
813+
try:
814+
from test_app.models import TodoItem
815+
816+
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
817+
818+
assert TodoItem.objects.filter(text=uuid).exists()
819+
finally:
820+
os.environ.pop("DJANGO_ALLOW_ASYNC_UNSAFE")
821+
822+
def test_sync_form_events(self):
823+
navigate_to_page(self, "/form/sync_event/")
824+
self.page.wait_for_selector("form")
825+
826+
# Check initial state
827+
self.page.wait_for_selector("#success[data-value='false']")
828+
self.page.wait_for_selector("#error[data-value='false']")
829+
self.page.wait_for_selector("#receive_data[data-value='false']")
830+
self.page.wait_for_selector("#change[data-value='false']")
831+
832+
# Submit empty the form
833+
sleep(1)
834+
self.page.wait_for_selector("input[type=submit]").click(delay=CLICK_DELAY)
835+
836+
# The empty form was submitted, should result in an error
837+
self.page.wait_for_selector("#success[data-value='false']")
838+
self.page.wait_for_selector("#error[data-value='true']")
839+
self.page.wait_for_selector("#receive_data[data-value='true']")
840+
self.page.wait_for_selector("#change[data-value='false']")
841+
842+
# Fill out the form and re-submit
843+
self.page.wait_for_selector("#id_char_field").type("test", delay=CLICK_DELAY)
844+
self.page.wait_for_selector("input[type=submit]").click(delay=CLICK_DELAY)
845+
846+
# Form should have been successfully submitted
847+
self.page.wait_for_selector("#success[data-value='true']")
848+
self.page.wait_for_selector("#error[data-value='true']")
849+
self.page.wait_for_selector("#receive_data[data-value='true']")
850+
self.page.wait_for_selector("#change[data-value='true']")
851+
852+
def test_async_form_events(self):
853+
navigate_to_page(self, "/form/async_event/")
854+
self.page.wait_for_selector("form")
855+
856+
# Check initial state
857+
self.page.wait_for_selector("#success[data-value='false']")
858+
self.page.wait_for_selector("#error[data-value='false']")
859+
self.page.wait_for_selector("#receive_data[data-value='false']")
860+
self.page.wait_for_selector("#change[data-value='false']")
861+
862+
# Submit empty the form
863+
sleep(1)
864+
self.page.wait_for_selector("input[type=submit]").click(delay=CLICK_DELAY)
865+
866+
# The empty form was submitted, should result in an error
867+
self.page.wait_for_selector("#success[data-value='false']")
868+
self.page.wait_for_selector("#error[data-value='true']")
869+
self.page.wait_for_selector("#receive_data[data-value='true']")
870+
self.page.wait_for_selector("#change[data-value='false']")
871+
872+
# Fill out the form and re-submit
873+
self.page.wait_for_selector("#id_char_field").type("test", delay=CLICK_DELAY)
874+
self.page.wait_for_selector("input[type=submit]").click(delay=CLICK_DELAY)
875+
876+
# Form should have been successfully submitted
877+
self.page.wait_for_selector("#success[data-value='true']")
878+
self.page.wait_for_selector("#error[data-value='true']")
879+
self.page.wait_for_selector("#receive_data[data-value='true']")
880+
self.page.wait_for_selector("#change[data-value='true']")

0 commit comments

Comments
 (0)