Skip to content

Commit ca77b42

Browse files
committed
added tests for async flatpages
1 parent 2bd4a48 commit ca77b42

File tree

11 files changed

+853
-1
lines changed

11 files changed

+853
-1
lines changed

tests/runtests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
# and isn't in an application in INSTALLED_APPS."
3838
CONTRIB_TESTS_TO_APPS = {
3939
"deprecation": ["django.contrib.flatpages", "django.contrib.redirects"],
40-
"flatpages_tests": ["django.contrib.flatpages"],
40+
"test_flatpages": ["django_async_extensions.acontrib.flatpages"],
4141
"redirects_tests": ["django.contrib.redirects"],
4242
}
4343

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>{{ flatpage.title }}</title>
5+
</head>
6+
<body>
7+
<p>{{ flatpage.content }}</p>
8+
</body>
9+
</html>

tests/test_flatpages/__init__.py

Whitespace-only changes.

tests/test_flatpages/absolute_urls.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.urls import path
2+
3+
from django_async_extensions.acontrib.flatpages import views
4+
5+
urlpatterns = [
6+
path("flatpage/", views.flatpage, {"url": "/hardcoded/"}),
7+
]

tests/test_flatpages/no_slash_urls.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.urls import include, path
2+
3+
urlpatterns = [
4+
path("flatpage", include("django_async_extensions.acontrib.flatpages.urls")),
5+
]

tests/test_flatpages/test_csrf.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import pytest
2+
from asgiref.sync import sync_to_async
3+
4+
from django.conf import settings
5+
from django.contrib.auth.models import User
6+
from django.contrib.sites.models import Site
7+
from django.test import AsyncClient
8+
9+
from django_async_extensions.acontrib.flatpages.models import AsyncFlatPage
10+
11+
12+
@pytest.mark.django_db(transaction=True)
13+
class TestFlatpageCSRF:
14+
@pytest.fixture(autouse=True)
15+
def set_settings(self):
16+
old_installed_apps = settings.INSTALLED_APPS
17+
old_middleware = settings.MIDDLEWARE
18+
old_root_urlconf = settings.ROOT_URLCONF
19+
old_csrf_failure_view = settings.CSRF_FAILURE_VIEW
20+
old_site_id = settings.SITE_ID
21+
22+
settings.INSTALLED_APPS.append("django_async_extensions.acontrib.flatpages")
23+
settings.MIDDLEWARE = [
24+
"django.middleware.common.CommonMiddleware",
25+
"django.contrib.sessions.middleware.SessionMiddleware",
26+
"django.middleware.csrf.CsrfViewMiddleware",
27+
"django.contrib.auth.middleware.AuthenticationMiddleware",
28+
"django.contrib.messages.middleware.MessageMiddleware",
29+
"django_async_extensions.acontrib.flatpages.middleware.AsyncFlatpageFallbackMiddleware",
30+
]
31+
settings.ROOT_URLCONF = "test_flatpages.urls"
32+
settings.CSRF_FAILURE_VIEW = "django.views.csrf.csrf_failure"
33+
settings.SITE_ID = 1
34+
35+
yield settings
36+
37+
settings.INSTALLED_APPS = old_installed_apps
38+
settings.MIDDLEWARE = old_middleware
39+
settings.ROOT_URLCONF = old_root_urlconf
40+
settings.CSRF_FAILURE_VIEW = old_csrf_failure_view
41+
settings.SITE_ID = old_site_id
42+
43+
@pytest.fixture(autouse=True)
44+
def setup(self):
45+
# don't use the manager because we want to ensure the site exists
46+
# with pk=1, regardless of whether or not it already exists.
47+
self.site1 = Site(pk=1, domain="example.com", name="example.com")
48+
self.site1.save()
49+
self.fp1 = AsyncFlatPage.objects.create(
50+
url="/flatpage/",
51+
title="A Flatpage",
52+
content="Isn't it flat!",
53+
enable_comments=False,
54+
template_name="",
55+
registration_required=False,
56+
)
57+
self.fp2 = AsyncFlatPage.objects.create(
58+
url="/location/flatpage/",
59+
title="A Nested Flatpage",
60+
content="Isn't it flat and deep!",
61+
enable_comments=False,
62+
template_name="",
63+
registration_required=False,
64+
)
65+
self.fp3 = AsyncFlatPage.objects.create(
66+
url="/sekrit/",
67+
title="Sekrit Flatpage",
68+
content="Isn't it sekrit!",
69+
enable_comments=False,
70+
template_name="",
71+
registration_required=True,
72+
)
73+
self.fp4 = AsyncFlatPage.objects.create(
74+
url="/location/sekrit/",
75+
title="Sekrit Nested Flatpage",
76+
content="Isn't it sekrit and deep!",
77+
enable_comments=False,
78+
template_name="",
79+
registration_required=True,
80+
)
81+
self.fp1.sites.add(self.site1)
82+
self.fp2.sites.add(self.site1)
83+
self.fp3.sites.add(self.site1)
84+
self.fp4.sites.add(self.site1)
85+
86+
self.client = AsyncClient(enforce_csrf_checks=True)
87+
88+
async def test_view_flatpage(self):
89+
"A flatpage can be served through a view, even when the middleware is in use"
90+
response = await self.client.get("/flatpage_root/flatpage/")
91+
assert b"<p>Isn't it flat!</p>" in response.content
92+
93+
async def test_view_non_existent_flatpage(self):
94+
"""
95+
A nonexistent flatpage raises 404 when served through a view, even when
96+
the middleware is in use.
97+
"""
98+
response = await self.client.get("/flatpage_root/no_such_flatpage/")
99+
assert response.status_code == 404
100+
101+
async def test_view_authenticated_flatpage(self):
102+
"A flatpage served through a view can require authentication"
103+
response = await self.client.get("/flatpage_root/sekrit/")
104+
assert response.status_code == 302
105+
assert response.url == "/accounts/login/?next=/flatpage_root/sekrit/"
106+
user = await sync_to_async(User.objects.create_user)(
107+
"testuser", "[email protected]", "s3krit"
108+
)
109+
await self.client.aforce_login(user)
110+
response = await self.client.get("/flatpage_root/sekrit/")
111+
assert b"<p>Isn't it sekrit!</p>" in response.content
112+
113+
async def test_fallback_flatpage(self):
114+
"A flatpage can be served by the fallback middleware"
115+
response = await self.client.get("/flatpage/")
116+
assert b"<p>Isn't it flat!</p>" in response.content
117+
118+
async def test_fallback_non_existent_flatpage(self):
119+
"""
120+
A nonexistent flatpage raises a 404 when served by the fallback
121+
middleware.
122+
"""
123+
response = await self.client.get("/no_such_flatpage/")
124+
assert response.status_code == 404
125+
126+
async def test_post_view_flatpage(self):
127+
"""
128+
POSTing to a flatpage served through a view will raise a CSRF error if
129+
no token is provided.
130+
"""
131+
response = await self.client.post("/flatpage_root/flatpage/")
132+
assert response.status_code == 403
133+
134+
async def test_post_fallback_flatpage(self):
135+
"""
136+
POSTing to a flatpage served by the middleware will raise a CSRF error
137+
if no token is provided.
138+
"""
139+
response = await self.client.post("/flatpage/")
140+
assert response.status_code == 403
141+
142+
async def test_post_unknown_page(self):
143+
"POSTing to an unknown page isn't caught as a 403 CSRF error"
144+
response = await self.client.post("/no_such_page/")
145+
assert response.status_code == 404

tests/test_flatpages/test_forms.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import pytest
2+
3+
from asgiref.sync import sync_to_async
4+
5+
from django.conf import settings
6+
from django.contrib.sites.models import Site
7+
from django.utils import translation
8+
9+
from django_async_extensions.acontrib.flatpages.forms import AsyncFlatpageForm
10+
from django_async_extensions.acontrib.flatpages.models import AsyncFlatPage
11+
12+
13+
@pytest.mark.django_db(transaction=True)
14+
class TestFlatpageAdminForm:
15+
@pytest.fixture(autouse=True)
16+
def set_settings(self):
17+
old_installed_apps = settings.INSTALLED_APPS
18+
old_site_id = settings.SITE_ID
19+
20+
settings.INSTALLED_APPS.append("django_async_extensions.acontrib.flatpages")
21+
settings.SITE_ID = 1
22+
23+
yield
24+
25+
settings.INSTALLED_APPS = old_installed_apps
26+
settings.SITE_ID = old_site_id
27+
28+
@pytest.fixture(autouse=True)
29+
def setup(self):
30+
# don't use the manager because we want to ensure the site exists
31+
# with pk=1, regardless of whether or not it already exists.
32+
self.site1 = Site(pk=1, domain="example.com", name="example.com")
33+
self.site1.save()
34+
35+
# Site fields cache needs to be cleared after flatpages is added to
36+
# INSTALLED_APPS
37+
Site._meta._expire_cache()
38+
self.form_data = {
39+
"title": "A test page",
40+
"content": "This is a test",
41+
"sites": [settings.SITE_ID],
42+
}
43+
44+
def test_flatpage_admin_form_url_validation(self):
45+
"The flatpage admin form correctly validates urls"
46+
assert AsyncFlatpageForm(
47+
data=dict(url="/new_flatpage/", **self.form_data)
48+
).is_valid()
49+
assert AsyncFlatpageForm(
50+
data=dict(url="/some.special~chars/", **self.form_data)
51+
).is_valid()
52+
assert AsyncFlatpageForm(
53+
data=dict(url="/some.very_special~chars-here/", **self.form_data)
54+
).is_valid()
55+
56+
assert (
57+
AsyncFlatpageForm(data=dict(url="/a space/", **self.form_data)).is_valid()
58+
is False
59+
)
60+
assert (
61+
AsyncFlatpageForm(data=dict(url="/a % char/", **self.form_data)).is_valid()
62+
is False
63+
)
64+
assert (
65+
AsyncFlatpageForm(data=dict(url="/a ! char/", **self.form_data)).is_valid()
66+
is False
67+
)
68+
assert (
69+
AsyncFlatpageForm(data=dict(url="/a & char/", **self.form_data)).is_valid()
70+
is False
71+
)
72+
assert (
73+
AsyncFlatpageForm(data=dict(url="/a ? char/", **self.form_data)).is_valid()
74+
is False
75+
)
76+
77+
def test_flatpage_requires_leading_slash(self):
78+
form = AsyncFlatpageForm(data=dict(url="no_leading_slash/", **self.form_data))
79+
with translation.override("en"):
80+
assert form.is_valid() is False
81+
assert form.errors["url"] == ["URL is missing a leading slash."]
82+
83+
@pytest.fixture()
84+
def common_fixture(self, settings):
85+
old_middleware = settings.MIDDLEWARE
86+
settings.MIDDLEWARE = ["django.middleware.common.CommonMiddleware"]
87+
88+
yield
89+
settings.MIDDLEWARE = old_middleware
90+
91+
@pytest.fixture()
92+
def append_True_fixture(self, settings):
93+
old_append_slash = settings.APPEND_SLASH
94+
settings.APPEND_SLASH = True
95+
yield
96+
settings.APPEND_SLASH = old_append_slash
97+
98+
def test_flatpage_requires_trailing_slash_with_append_slash(
99+
self, common_fixture, append_True_fixture
100+
):
101+
form = AsyncFlatpageForm(data=dict(url="/no_trailing_slash", **self.form_data))
102+
with translation.override("en"):
103+
assert (
104+
form.fields["url"].help_text
105+
== "Example: “/about/contact/”. Make sure to have leading and "
106+
"trailing slashes."
107+
)
108+
assert form.is_valid() is False
109+
assert form.errors["url"] == ["URL is missing a trailing slash."]
110+
111+
@pytest.fixture()
112+
def append_False_fixture(self, settings):
113+
old_append_slash = settings.APPEND_SLASH
114+
settings.APPEND_SLASH = False
115+
yield
116+
settings.APPEND_SLASH = old_append_slash
117+
118+
async def test_flatpage_doesnt_requires_trailing_slash_without_append_slash(
119+
self, common_fixture, append_False_fixture
120+
):
121+
form = await sync_to_async(AsyncFlatpageForm)(
122+
data=dict(url="/no_trailing_slash", **self.form_data)
123+
)
124+
assert await sync_to_async(form.is_valid)()
125+
with translation.override("en"):
126+
assert (
127+
form.fields["url"].help_text
128+
== "Example: “/about/contact”. Make sure to have a leading slash."
129+
)
130+
131+
def test_flatpage_admin_form_url_uniqueness_validation(self):
132+
"""
133+
The flatpage admin form correctly enforces url uniqueness among
134+
flatpages of the same site.
135+
"""
136+
data = dict(url="/myflatpage1/", **self.form_data)
137+
138+
AsyncFlatpageForm(data=data).save()
139+
140+
f = AsyncFlatpageForm(data=data)
141+
142+
with translation.override("en"):
143+
assert f.is_valid() is False
144+
145+
assert f.errors == {
146+
"__all__": [
147+
"Flatpage with url /myflatpage1/ already exists for site "
148+
"example.com"
149+
]
150+
}
151+
152+
def test_flatpage_admin_form_edit(self):
153+
"""
154+
Existing flatpages can be edited in the admin form without triggering
155+
the url-uniqueness validation.
156+
"""
157+
existing = AsyncFlatPage.objects.create(
158+
url="/myflatpage1/", title="Some page", content="The content"
159+
)
160+
existing.sites.add(settings.SITE_ID)
161+
162+
data = dict(url="/myflatpage1/", **self.form_data)
163+
164+
f = AsyncFlatpageForm(data=data, instance=existing)
165+
166+
assert f.is_valid(), f.errors
167+
168+
updated = f.save()
169+
170+
assert updated.title == "A test page"
171+
172+
def test_flatpage_nosites(self):
173+
data = dict(url="/myflatpage1/", **self.form_data)
174+
data.update({"sites": ""})
175+
176+
f = AsyncFlatpageForm(data=data)
177+
178+
assert f.is_valid() is False
179+
180+
assert f.errors == {"sites": [translation.gettext("This field is required.")]}

0 commit comments

Comments
 (0)