kopia lustrzana https://github.com/wagtail/wagtail
757 wiersze
29 KiB
Python
757 wiersze
29 KiB
Python
import datetime
|
|
from io import BytesIO
|
|
|
|
from django.contrib.admin.utils import quote
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
from openpyxl import load_workbook
|
|
|
|
from wagtail.test.testapp.models import FeatureCompleteToy, JSONStreamModel
|
|
from wagtail.test.utils.wagtail_tests import WagtailTestUtils
|
|
from wagtail.utils.deprecation import RemovedInWagtail60Warning
|
|
|
|
|
|
class TestModelViewSetGroup(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
def test_menu_items(self):
|
|
response = self.client.get(reverse("wagtailadmin_home"))
|
|
self.assertEqual(response.status_code, 200)
|
|
# Menu label falls back to the title-cased app label
|
|
self.assertContains(
|
|
response,
|
|
'"name": "tests", "label": "Tests", "icon_name": "folder-open-inverse"',
|
|
)
|
|
# Title-cased from verbose_name_plural
|
|
self.assertContains(response, "Json Stream Models")
|
|
self.assertContains(response, reverse("streammodel:index"))
|
|
self.assertEqual(reverse("streammodel:index"), "/admin/streammodel/")
|
|
# Set on class
|
|
self.assertContains(response, "JSON MinMaxCount StreamModel")
|
|
self.assertContains(response, reverse("minmaxcount_streammodel:index"))
|
|
self.assertEqual(
|
|
reverse("minmaxcount_streammodel:index"),
|
|
"/admin/minmaxcount-streammodel/",
|
|
)
|
|
# Set on instance
|
|
self.assertContains(response, "JSON BlockCounts StreamModel")
|
|
self.assertContains(response, reverse("blockcounts_streammodel:index"))
|
|
self.assertEqual(
|
|
reverse("blockcounts_streammodel:index"),
|
|
"/admin/blockcounts/streammodel/",
|
|
)
|
|
|
|
|
|
class TestTemplateConfiguration(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
cls.default = JSONStreamModel.objects.create(
|
|
body='[{"type": "text", "value": "foo"}]',
|
|
)
|
|
cls.custom = FeatureCompleteToy.objects.create(name="Test Toy")
|
|
|
|
def get_default_url(self, view_name, args=()):
|
|
return reverse(f"streammodel:{view_name}", args=args)
|
|
|
|
def get_custom_url(self, view_name, args=()):
|
|
return reverse(f"feature_complete_toy:{view_name}", args=args)
|
|
|
|
def test_default_templates(self):
|
|
pk = quote(self.default.pk)
|
|
cases = {
|
|
"index": (
|
|
[],
|
|
"wagtailadmin/generic/index.html",
|
|
),
|
|
"index_results": (
|
|
[],
|
|
"wagtailadmin/generic/listing_results.html",
|
|
),
|
|
"add": (
|
|
[],
|
|
"wagtailadmin/generic/create.html",
|
|
),
|
|
"edit": (
|
|
[pk],
|
|
"wagtailadmin/generic/edit.html",
|
|
),
|
|
"delete": (
|
|
[pk],
|
|
"wagtailadmin/generic/confirm_delete.html",
|
|
),
|
|
}
|
|
for view_name, (args, template_name) in cases.items():
|
|
with self.subTest(view_name=view_name):
|
|
response = self.client.get(self.get_default_url(view_name, args=args))
|
|
self.assertTemplateUsed(response, template_name)
|
|
|
|
def test_custom_template_lookups(self):
|
|
pk = quote(self.custom.pk)
|
|
cases = {
|
|
"override with index_template_name": (
|
|
"index",
|
|
[],
|
|
"tests/fctoy_index.html",
|
|
),
|
|
"with app label and model name": (
|
|
"add",
|
|
[],
|
|
"customprefix/tests/featurecompletetoy/create.html",
|
|
),
|
|
"with app label": (
|
|
"edit",
|
|
[pk],
|
|
"customprefix/tests/edit.html",
|
|
),
|
|
"without app label and model name": (
|
|
"delete",
|
|
[pk],
|
|
"customprefix/confirm_delete.html",
|
|
),
|
|
}
|
|
for case, (view_name, args, template_name) in cases.items():
|
|
with self.subTest(case=case):
|
|
response = self.client.get(self.get_custom_url(view_name, args=args))
|
|
self.assertTemplateUsed(response, template_name)
|
|
self.assertContains(
|
|
response, "<p>Some extra custom content</p>", html=True
|
|
)
|
|
|
|
def test_wagtail_admin_template_mixin_variables(self):
|
|
pk = quote(self.custom.pk)
|
|
cases = {
|
|
"index": ([], "Feature complete toys", None),
|
|
"add": ([], "New", "Feature complete toy"),
|
|
"edit": ([pk], "Editing", str(self.custom)),
|
|
"delete": ([pk], "Delete", str(self.custom)),
|
|
}
|
|
for view_name, (args, title, subtitle) in cases.items():
|
|
with self.subTest(view_name=view_name):
|
|
response = self.client.get(self.get_custom_url(view_name, args=args))
|
|
soup = self.get_soup(response.content)
|
|
h1 = soup.select_one("h1")
|
|
self.assertIsNotNone(h1)
|
|
self.assertEqual(
|
|
"".join(h1.find_all(string=True, recursive=False)).strip(), title
|
|
)
|
|
subtitle_el = h1.select_one("span")
|
|
if subtitle:
|
|
self.assertIsNotNone(subtitle_el)
|
|
self.assertEqual(subtitle_el.string, subtitle)
|
|
else:
|
|
self.assertIsNone(subtitle_el)
|
|
icon = h1.select_one("svg use[href='#icon-media']")
|
|
self.assertIsNotNone(icon)
|
|
|
|
|
|
class TestCustomColumns(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
FeatureCompleteToy.objects.create(name="Racecar")
|
|
FeatureCompleteToy.objects.create(name="level")
|
|
FeatureCompleteToy.objects.create(name="Lotso")
|
|
|
|
def test_list_display(self):
|
|
index_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(index_url)
|
|
# "name" column
|
|
self.assertContains(response, "Racecar")
|
|
self.assertContains(response, "level")
|
|
self.assertContains(response, "Lotso")
|
|
# BooleanColumn("is_cool")
|
|
soup = self.get_soup(response.content)
|
|
|
|
help = soup.select_one("td:has(svg.icon-help)")
|
|
self.assertIsNotNone(help)
|
|
self.assertEqual(help.text.strip(), "None")
|
|
|
|
success = soup.select_one("td:has(svg.icon-success.w-text-positive-100)")
|
|
self.assertIsNotNone(success)
|
|
self.assertEqual(success.text.strip(), "True")
|
|
|
|
error = soup.select_one("td:has(svg.icon-error.w-text-critical-100)")
|
|
self.assertIsNotNone(error)
|
|
self.assertEqual(error.text.strip(), "False")
|
|
|
|
updated_at = soup.select("th a")[-1]
|
|
self.assertEqual(updated_at.text.strip(), "Updated")
|
|
self.assertEqual(updated_at["href"], f"{index_url}?ordering=_updated_at")
|
|
|
|
|
|
class TestListFilter(WagtailTestUtils, TestCase):
|
|
cases = {
|
|
"list": ("feature_complete_toy", "release_date", "Release date"),
|
|
"dict": ("fctoy_alt1", "name__icontains", "Name contains"),
|
|
"filterset_class": (
|
|
"fctoy-alt2",
|
|
"release_date__year__lte",
|
|
"Release date year is less than or equal to",
|
|
),
|
|
}
|
|
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
def get(self, url_namespace, params=None):
|
|
return self.client.get(reverse(f"{url_namespace}:index"), params)
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
FeatureCompleteToy.objects.create(
|
|
name="Buzz Lightyear",
|
|
release_date=datetime.date(1995, 11, 19),
|
|
)
|
|
FeatureCompleteToy.objects.create(
|
|
name="Forky",
|
|
release_date=datetime.date(2019, 6, 11),
|
|
)
|
|
|
|
def test_unfiltered_no_results(self):
|
|
FeatureCompleteToy.objects.all().delete()
|
|
for case, (url_namespace, lookup, label_text) in self.cases.items():
|
|
with self.subTest(case=case):
|
|
response = self.get(url_namespace)
|
|
self.assertTemplateUsed(response, "wagtailadmin/shared/filters.html")
|
|
self.assertContains(
|
|
response,
|
|
"There are no feature complete toys to display",
|
|
)
|
|
self.assertNotContains(
|
|
response,
|
|
"No feature complete toys match your query",
|
|
)
|
|
self.assertNotContains(response, "Buzz Lightyear")
|
|
self.assertNotContains(response, "Forky")
|
|
|
|
soup = self.get_soup(response.content)
|
|
label = soup.select_one(f"label#id_{lookup}-label")
|
|
self.assertIsNotNone(label)
|
|
self.assertEqual(label.text.strip(), label_text)
|
|
input = soup.select_one(f"input#id_{lookup}")
|
|
self.assertIsNotNone(input)
|
|
|
|
def test_unfiltered_with_results(self):
|
|
for case, (url_namespace, lookup, label_text) in self.cases.items():
|
|
with self.subTest(case=case):
|
|
response = self.get(url_namespace)
|
|
self.assertTemplateUsed(response, "wagtailadmin/shared/filters.html")
|
|
self.assertContains(response, "Buzz Lightyear")
|
|
self.assertContains(response, "Forky")
|
|
self.assertNotContains(response, "There are 2 matches")
|
|
self.assertNotContains(
|
|
response,
|
|
"There are no feature complete toys to display",
|
|
)
|
|
self.assertNotContains(
|
|
response,
|
|
"No feature complete toys match your query",
|
|
)
|
|
|
|
soup = self.get_soup(response.content)
|
|
label = soup.select_one(f"label#id_{lookup}-label")
|
|
self.assertIsNotNone(label)
|
|
self.assertEqual(label.text.strip(), label_text)
|
|
input = soup.select_one(f"input#id_{lookup}")
|
|
self.assertIsNotNone(input)
|
|
|
|
def test_empty_filter_with_results(self):
|
|
for case, (url_namespace, lookup, label_text) in self.cases.items():
|
|
with self.subTest(case=case):
|
|
response = self.get(url_namespace, {lookup: ""})
|
|
self.assertTemplateUsed(response, "wagtailadmin/shared/filters.html")
|
|
self.assertContains(response, "Buzz Lightyear")
|
|
self.assertContains(response, "Forky")
|
|
self.assertNotContains(response, "There are 2 matches")
|
|
self.assertNotContains(
|
|
response,
|
|
"No feature complete toys match your query",
|
|
)
|
|
|
|
soup = self.get_soup(response.content)
|
|
label = soup.select_one(f"label#id_{lookup}-label")
|
|
self.assertIsNotNone(label)
|
|
self.assertEqual(label.text.strip(), label_text)
|
|
input = soup.select_one(f"input#id_{lookup}")
|
|
self.assertIsNotNone(input)
|
|
self.assertFalse(input.attrs.get("value"))
|
|
|
|
def test_filtered_no_results(self):
|
|
lookup_values = {
|
|
"release_date": "1999-09-09",
|
|
"name__icontains": "Woody",
|
|
"release_date__year__lte": "1990",
|
|
}
|
|
for case, (url_namespace, lookup, label_text) in self.cases.items():
|
|
with self.subTest(case=case):
|
|
value = lookup_values[lookup]
|
|
response = self.get(url_namespace, {lookup: value})
|
|
self.assertTemplateUsed(response, "wagtailadmin/shared/filters.html")
|
|
self.assertContains(
|
|
response,
|
|
"No feature complete toys match your query",
|
|
)
|
|
self.assertNotContains(response, "Buzz Lightyear")
|
|
self.assertNotContains(response, "Forky")
|
|
self.assertNotContains(response, "There are 2 matches")
|
|
|
|
soup = self.get_soup(response.content)
|
|
label = soup.select_one(f"label#id_{lookup}-label")
|
|
self.assertIsNotNone(label)
|
|
self.assertEqual(label.text.strip(), label_text)
|
|
input = soup.select_one(f"input#id_{lookup}")
|
|
self.assertIsNotNone(input)
|
|
self.assertEqual(input.attrs.get("value"), value)
|
|
|
|
def test_filtered_with_results(self):
|
|
lookup_values = {
|
|
"release_date": "1995-11-19",
|
|
"name__icontains": "Ightyear",
|
|
"release_date__year__lte": "2017",
|
|
}
|
|
for case, (url_namespace, lookup, label_text) in self.cases.items():
|
|
with self.subTest(case=case):
|
|
value = lookup_values[lookup]
|
|
response = self.get(url_namespace, {lookup: value})
|
|
self.assertTemplateUsed(response, "wagtailadmin/shared/filters.html")
|
|
self.assertContains(response, "Buzz Lightyear")
|
|
self.assertContains(response, "There is 1 match")
|
|
self.assertNotContains(response, "Forky")
|
|
self.assertNotContains(
|
|
response,
|
|
"No feature complete toys match your query",
|
|
)
|
|
|
|
soup = self.get_soup(response.content)
|
|
label = soup.select_one(f"label#id_{lookup}-label")
|
|
self.assertIsNotNone(label)
|
|
self.assertEqual(label.text.strip(), label_text)
|
|
input = soup.select_one(f"input#id_{lookup}")
|
|
self.assertIsNotNone(input)
|
|
self.assertEqual(input.attrs.get("value"), value)
|
|
|
|
|
|
class TestSearchIndexView(WagtailTestUtils, TestCase):
|
|
url_name = "index"
|
|
cases = {
|
|
# With the default search backend
|
|
"default": ("feature_complete_toy", "release_date"),
|
|
# With Django ORM
|
|
None: ("fctoy-alt2", "release_date__year__lte"),
|
|
}
|
|
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
FeatureCompleteToy.objects.create(
|
|
name="Buzz Lightyear",
|
|
release_date=datetime.date(1995, 11, 19),
|
|
)
|
|
FeatureCompleteToy.objects.create(
|
|
name="Forky",
|
|
release_date=datetime.date(2019, 6, 11),
|
|
)
|
|
|
|
def assertInputRendered(self, response, search_q):
|
|
soup = self.get_soup(response.content)
|
|
input = soup.select_one("input#id_q")
|
|
self.assertIsNotNone(input)
|
|
self.assertEqual(input.attrs.get("value"), search_q)
|
|
|
|
def get(self, url_namespace, params=None):
|
|
return self.client.get(reverse(f"{url_namespace}:{self.url_name}"), params)
|
|
|
|
def test_search_disabled(self):
|
|
response = self.get("fctoy_alt1", {"q": "ork"})
|
|
self.assertContains(response, "Forky")
|
|
self.assertContains(response, "Buzz Lightyear")
|
|
self.assertNotContains(response, "There are 2 matches")
|
|
soup = self.get_soup(response.content)
|
|
input = soup.select_one("input#id_q")
|
|
self.assertIsNone(input)
|
|
|
|
def test_search_no_results(self):
|
|
for backend, (url_namespace, _) in self.cases.items():
|
|
with self.subTest(backend=backend):
|
|
response = self.get(url_namespace, {"q": "Woody"})
|
|
self.assertContains(
|
|
response,
|
|
"No feature complete toys match your query",
|
|
)
|
|
self.assertNotContains(response, "Buzz Lightyear")
|
|
self.assertNotContains(response, "Forky")
|
|
self.assertInputRendered(response, "Woody")
|
|
|
|
def test_search_with_results(self):
|
|
for backend, (url_namespace, _) in self.cases.items():
|
|
with self.subTest(backend=backend):
|
|
response = self.get(url_namespace, {"q": "ork"})
|
|
self.assertContains(response, "Forky")
|
|
self.assertNotContains(response, "Buzz Lightyear")
|
|
self.assertContains(response, "There is 1 match")
|
|
self.assertInputRendered(response, "ork")
|
|
|
|
def test_filtered_searched_no_results(self):
|
|
lookup_values = {
|
|
"release_date": "2019-06-11",
|
|
"release_date__year__lte": "2023",
|
|
}
|
|
for backend, (url_namespace, lookup) in self.cases.items():
|
|
with self.subTest(backend=backend):
|
|
value = lookup_values[lookup]
|
|
response = self.get(url_namespace, {"q": "Woody", lookup: value})
|
|
self.assertContains(
|
|
response,
|
|
"No feature complete toys match your query",
|
|
)
|
|
self.assertNotContains(response, "Buzz Lightyear")
|
|
self.assertNotContains(response, "Forky")
|
|
self.assertInputRendered(response, "Woody")
|
|
|
|
def test_filtered_searched_with_results(self):
|
|
lookup_values = {
|
|
"release_date": "2019-06-11",
|
|
"release_date__year__lte": "2023",
|
|
}
|
|
for backend, (url_namespace, lookup) in self.cases.items():
|
|
with self.subTest(backend=backend):
|
|
value = lookup_values[lookup]
|
|
response = self.get(url_namespace, {"q": "ork", lookup: value})
|
|
self.assertContains(response, "Forky")
|
|
self.assertNotContains(response, "Buzz Lightyear")
|
|
self.assertContains(response, "There is 1 match")
|
|
self.assertInputRendered(response, "ork")
|
|
|
|
|
|
class TestSearchIndexResultsView(TestSearchIndexView):
|
|
url_name = "index_results"
|
|
|
|
def assertInputRendered(self, response, search_q):
|
|
# index_results view doesn't render the search input
|
|
pass
|
|
|
|
|
|
class TestListExport(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
FeatureCompleteToy.objects.create(
|
|
name="Racecar",
|
|
release_date=datetime.date(1995, 11, 19),
|
|
)
|
|
FeatureCompleteToy.objects.create(
|
|
name="LEVEL",
|
|
release_date=datetime.date(2010, 6, 18),
|
|
)
|
|
FeatureCompleteToy.objects.create(
|
|
name="Catso",
|
|
release_date=datetime.date(2010, 6, 18),
|
|
)
|
|
|
|
def test_export_disabled(self):
|
|
index_url = reverse("fctoy_alt1:index")
|
|
response = self.client.get(index_url)
|
|
soup = self.get_soup(response.content)
|
|
|
|
csv_link = soup.select_one(f"a[href='{index_url}?export=csv']")
|
|
self.assertIsNone(csv_link)
|
|
xlsx_link = soup.select_one(f"a[href='{index_url}?export=xlsx']")
|
|
self.assertIsNone(xlsx_link)
|
|
|
|
def test_get_not_export_shows_export_buttons(self):
|
|
index_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(index_url)
|
|
soup = self.get_soup(response.content)
|
|
|
|
csv_link = soup.select_one(f"a[href='{index_url}?export=csv']")
|
|
self.assertIsNotNone(csv_link)
|
|
self.assertEqual(csv_link.text.strip(), "Download CSV")
|
|
xlsx_link = soup.select_one(f"a[href='{index_url}?export=xlsx']")
|
|
self.assertIsNotNone(xlsx_link)
|
|
self.assertEqual(xlsx_link.text.strip(), "Download XLSX")
|
|
|
|
def test_get_filtered_shows_export_buttons_with_filters(self):
|
|
index_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(index_url, {"release_date": "2010-06-18"})
|
|
soup = self.get_soup(response.content)
|
|
|
|
csv_link = soup.select_one(
|
|
f"a[href='{index_url}?release_date=2010-06-18&export=csv']"
|
|
)
|
|
self.assertIsNotNone(csv_link)
|
|
self.assertEqual(csv_link.text.strip(), "Download CSV")
|
|
xlsx_link = soup.select_one(
|
|
f"a[href='{index_url}?release_date=2010-06-18&export=xlsx']"
|
|
)
|
|
self.assertIsNotNone(xlsx_link)
|
|
self.assertEqual(xlsx_link.text.strip(), "Download XLSX")
|
|
|
|
def test_csv_export(self):
|
|
index_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(index_url, {"export": "csv"})
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(
|
|
response.get("Content-Disposition"),
|
|
'attachment; filename="feature-complete-toys.csv"',
|
|
)
|
|
|
|
data_lines = response.getvalue().decode().strip().split("\r\n")
|
|
self.assertEqual(data_lines[0], "Name,Launch date,Is cool")
|
|
self.assertEqual(data_lines[1], "Catso,2010-06-18,False")
|
|
self.assertEqual(data_lines[2], "LEVEL,2010-06-18,True")
|
|
self.assertEqual(data_lines[3], "Racecar,1995-11-19,")
|
|
self.assertEqual(len(data_lines), 4)
|
|
|
|
def test_csv_export_filtered(self):
|
|
index_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(
|
|
index_url,
|
|
{"release_date": "2010-06-18", "export": "csv"},
|
|
)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(
|
|
response.get("Content-Disposition"),
|
|
'attachment; filename="feature-complete-toys.csv"',
|
|
)
|
|
|
|
data_lines = response.getvalue().decode().strip().split("\r\n")
|
|
self.assertEqual(data_lines[0], "Name,Launch date,Is cool")
|
|
self.assertEqual(data_lines[1], "Catso,2010-06-18,False")
|
|
self.assertEqual(data_lines[2], "LEVEL,2010-06-18,True")
|
|
self.assertEqual(len(data_lines), 3)
|
|
|
|
def test_xlsx_export(self):
|
|
index_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(index_url, {"export": "xlsx"})
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(
|
|
response.get("Content-Disposition"),
|
|
'attachment; filename="feature-complete-toys.xlsx"',
|
|
)
|
|
|
|
workbook_data = response.getvalue()
|
|
worksheet = load_workbook(filename=BytesIO(workbook_data)).active
|
|
cell_array = [[cell.value for cell in row] for row in worksheet.rows]
|
|
self.assertEqual(cell_array[0], ["Name", "Launch date", "Is cool"])
|
|
self.assertEqual(cell_array[1], ["Catso", datetime.date(2010, 6, 18), False])
|
|
self.assertEqual(cell_array[2], ["LEVEL", datetime.date(2010, 6, 18), True])
|
|
self.assertEqual(cell_array[3], ["Racecar", datetime.date(1995, 11, 19), None])
|
|
self.assertEqual(len(cell_array), 4)
|
|
|
|
def test_xlsx_export_filtered(self):
|
|
index_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(
|
|
index_url,
|
|
{"release_date": "2010-06-18", "export": "xlsx"},
|
|
)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(
|
|
response.get("Content-Disposition"),
|
|
'attachment; filename="feature-complete-toys.xlsx"',
|
|
)
|
|
|
|
workbook_data = response.getvalue()
|
|
worksheet = load_workbook(filename=BytesIO(workbook_data)).active
|
|
cell_array = [[cell.value for cell in row] for row in worksheet.rows]
|
|
self.assertEqual(cell_array[0], ["Name", "Launch date", "Is cool"])
|
|
self.assertEqual(cell_array[1], ["Catso", datetime.date(2010, 6, 18), False])
|
|
self.assertEqual(cell_array[2], ["LEVEL", datetime.date(2010, 6, 18), True])
|
|
self.assertEqual(len(cell_array), 3)
|
|
|
|
|
|
class TestPagination(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
objects = [FeatureCompleteToy(name=f"Frisbee {i}") for i in range(32)]
|
|
FeatureCompleteToy.objects.bulk_create(objects)
|
|
|
|
def test_default_list_pagination(self):
|
|
list_url = reverse("fctoy_alt1:index")
|
|
response = self.client.get(list_url)
|
|
|
|
# Default is 20 per page
|
|
self.assertEqual(FeatureCompleteToy.objects.all().count(), 32)
|
|
self.assertContains(response, "Page 1 of 2")
|
|
self.assertContains(response, "Next")
|
|
self.assertContains(response, list_url + "?p=2")
|
|
|
|
def test_custom_list_pagination(self):
|
|
list_url = reverse("feature_complete_toy:index")
|
|
response = self.client.get(list_url)
|
|
|
|
# Custom is set to display 5 per page
|
|
self.assertEqual(FeatureCompleteToy.objects.all().count(), 32)
|
|
self.assertContains(response, "Page 1 of 7")
|
|
self.assertContains(response, "Next")
|
|
self.assertContains(response, list_url + "?p=2")
|
|
|
|
|
|
class TestOrdering(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
objects = [
|
|
FeatureCompleteToy(name="CCCCCCCCCC", strid="1"),
|
|
FeatureCompleteToy(name="AAAAAAAAAA", strid="2"),
|
|
FeatureCompleteToy(name="DDDDDDDDDD", strid="3"),
|
|
FeatureCompleteToy(name="BBBBBBBBBB", strid="4"),
|
|
]
|
|
FeatureCompleteToy.objects.bulk_create(objects)
|
|
|
|
def test_default_order(self):
|
|
response = self.client.get(reverse("fctoy_alt1:index"))
|
|
# Without ordering on the model, should be ordered descending by pk
|
|
self.assertFalse(FeatureCompleteToy._meta.ordering)
|
|
self.assertEqual(
|
|
[obj.name for obj in response.context["object_list"]],
|
|
[
|
|
"BBBBBBBBBB",
|
|
"DDDDDDDDDD",
|
|
"AAAAAAAAAA",
|
|
"CCCCCCCCCC",
|
|
],
|
|
)
|
|
|
|
def test_custom_order(self):
|
|
response = self.client.get(reverse("feature_complete_toy:index"))
|
|
# Should respect the viewset's ordering
|
|
self.assertFalse(FeatureCompleteToy._meta.ordering)
|
|
self.assertEqual(
|
|
[obj.name for obj in response.context["object_list"]],
|
|
[
|
|
"AAAAAAAAAA",
|
|
"BBBBBBBBBB",
|
|
"CCCCCCCCCC",
|
|
"DDDDDDDDDD",
|
|
],
|
|
)
|
|
|
|
|
|
class TestBreadcrumbs(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
cls.object = FeatureCompleteToy.objects.create(name="Test Toy")
|
|
|
|
def assertItemsRendered(self, items, response):
|
|
items = [{"label": "Home", "url": "/admin/"}] + items
|
|
soup = self.get_soup(response.content)
|
|
breadcrumbs = soup.select_one('[data-controller="w-breadcrumbs"]')
|
|
rendered_items = breadcrumbs.select("ol > li")
|
|
arrows = soup.select("ol > li > svg")
|
|
self.assertEqual(len(rendered_items), len(items))
|
|
self.assertEqual(len(arrows), len(items) - 1)
|
|
|
|
for item, rendered_item in zip(items, rendered_items):
|
|
if item.get("url"):
|
|
element = rendered_item.select_one("a")
|
|
self.assertIsNotNone(element)
|
|
self.assertEqual(element["href"], item["url"])
|
|
else:
|
|
element = rendered_item.select_one("div")
|
|
self.assertIsNotNone(element)
|
|
self.assertEqual(element.text.strip(), item["label"])
|
|
|
|
def test_index_view(self):
|
|
response = self.client.get(reverse("feature_complete_toy:index"))
|
|
items = [
|
|
{
|
|
"label": "Feature complete toys",
|
|
}
|
|
]
|
|
self.assertItemsRendered(items, response)
|
|
|
|
def test_add_view(self):
|
|
response = self.client.get(reverse("feature_complete_toy:add"))
|
|
items = [
|
|
{
|
|
"url": reverse("feature_complete_toy:index"),
|
|
"label": "Feature complete toys",
|
|
},
|
|
{
|
|
"label": "New: Feature complete toy",
|
|
},
|
|
]
|
|
self.assertItemsRendered(items, response)
|
|
|
|
def test_edit_view(self):
|
|
edit_url = reverse("feature_complete_toy:edit", args=(quote(self.object.pk),))
|
|
response = self.client.get(edit_url)
|
|
items = [
|
|
{
|
|
"url": reverse("feature_complete_toy:index"),
|
|
"label": "Feature complete toys",
|
|
},
|
|
{
|
|
"label": str(self.object),
|
|
},
|
|
]
|
|
self.assertItemsRendered(items, response)
|
|
|
|
def test_delete_view(self):
|
|
delete_url = reverse(
|
|
"feature_complete_toy:delete",
|
|
args=(quote(self.object.pk),),
|
|
)
|
|
response = self.client.get(delete_url)
|
|
soup = self.get_soup(response.content)
|
|
breadcrumbs = soup.select_one('[data-controller="w-breadcrumbs"]')
|
|
# Delete view shouldn't render breadcrumbs
|
|
self.assertIsNone(breadcrumbs)
|
|
|
|
|
|
class TestLegacyPatterns(WagtailTestUtils, TestCase):
|
|
# RemovedInWagtail60Warning: legacy integer pk-based URLs will be removed
|
|
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
cls.object = JSONStreamModel.objects.create(
|
|
body='[{"type": "text", "value": "foo"}]',
|
|
)
|
|
|
|
def test_legacy_edit(self):
|
|
edit_url = reverse("streammodel:edit", args=(quote(self.object.pk),))
|
|
legacy_edit_url = "/admin/streammodel/1/"
|
|
with self.assertWarnsRegex(
|
|
RemovedInWagtail60Warning,
|
|
"`/<pk>/` edit view URL pattern has been deprecated in favour of /edit/<pk>/.",
|
|
):
|
|
response = self.client.get(legacy_edit_url)
|
|
self.assertEqual(edit_url, "/admin/streammodel/edit/1/")
|
|
self.assertRedirects(response, edit_url, 301)
|
|
|
|
def test_legacy_delete(self):
|
|
delete_url = reverse("streammodel:delete", args=(quote(self.object.pk),))
|
|
legacy_delete_url = "/admin/streammodel/1/delete/"
|
|
with self.assertWarnsRegex(
|
|
RemovedInWagtail60Warning,
|
|
"`/<pk>/delete/` delete view URL pattern has been deprecated in favour of /delete/<pk>/.",
|
|
):
|
|
response = self.client.get(legacy_delete_url)
|
|
self.assertEqual(delete_url, "/admin/streammodel/delete/1/")
|
|
self.assertRedirects(response, delete_url, 301)
|