Add tests for search page
This commit is contained in:
parent
edbedcd0fa
commit
6403aca2a2
3 changed files with 142 additions and 5 deletions
8
website/search/factories.py
Normal file
8
website/search/factories.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from website.common.factories import BaseContentFactory
|
||||||
|
|
||||||
|
from .models import SearchPage
|
||||||
|
|
||||||
|
|
||||||
|
class SearchPageFactory(BaseContentFactory):
|
||||||
|
class Meta:
|
||||||
|
model = SearchPage
|
|
@ -1,7 +1,7 @@
|
||||||
from django.core.paginator import EmptyPage, Paginator
|
from django.core.paginator import EmptyPage, Paginator
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
from django.http.response import HttpResponse, HttpResponseBadRequest
|
from django.http.response import Http404, HttpResponse, HttpResponseBadRequest
|
||||||
from django.shortcuts import render
|
from django.template.response import TemplateResponse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.views.decorators.http import require_GET
|
from django.views.decorators.http import require_GET
|
||||||
|
@ -46,7 +46,7 @@ class SearchPage(RoutablePageMixin, BaseContentPage):
|
||||||
serializer = SearchParamsSerializer(data=request.GET)
|
serializer = SearchParamsSerializer(data=request.GET)
|
||||||
|
|
||||||
if not serializer.is_valid():
|
if not serializer.is_valid():
|
||||||
return render(
|
return TemplateResponse(
|
||||||
request,
|
request,
|
||||||
"search/enter-search-term.html",
|
"search/enter-search-term.html",
|
||||||
{"MIN_SEARCH_LENGTH": MIN_SEARCH_LENGTH},
|
{"MIN_SEARCH_LENGTH": MIN_SEARCH_LENGTH},
|
||||||
|
@ -82,8 +82,8 @@ class SearchPage(RoutablePageMixin, BaseContentPage):
|
||||||
)
|
)
|
||||||
|
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
results = []
|
raise Http404
|
||||||
|
|
||||||
context["results"] = results
|
context["results"] = results
|
||||||
|
|
||||||
return render(request, "search/search_results.html", context)
|
return TemplateResponse(request, "search/search_results.html", context)
|
||||||
|
|
129
website/search/tests.py
Normal file
129
website/search/tests.py
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from website.common.factories import ContentPageFactory
|
||||||
|
from website.home.models import HomePage
|
||||||
|
|
||||||
|
from .factories import SearchPageFactory
|
||||||
|
from .models import SearchPage
|
||||||
|
|
||||||
|
|
||||||
|
class SearchPageTestCase(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls) -> None:
|
||||||
|
cls.home_page = HomePage.objects.get()
|
||||||
|
cls.page = SearchPageFactory(parent=cls.home_page)
|
||||||
|
|
||||||
|
def test_accessible(self) -> None:
|
||||||
|
response = self.client.get(self.page.url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.context["search_url"], "results/")
|
||||||
|
self.assertEqual(response.context["MIN_SEARCH_LENGTH"], 3)
|
||||||
|
|
||||||
|
def test_initial_query(self) -> None:
|
||||||
|
response = self.client.get(self.page.url, {"q": "post 1"})
|
||||||
|
self.assertEqual(response.context["search_query"], "post 1")
|
||||||
|
self.assertTemplateNotUsed(response, "search/enter-search-term.html")
|
||||||
|
|
||||||
|
search_input = BeautifulSoup(response.content, "lxml").find("input")
|
||||||
|
self.assertEqual(search_input.attrs["value"], "post 1")
|
||||||
|
|
||||||
|
def test_search_input(self) -> None:
|
||||||
|
response = self.client.get(self.page.url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.content, "lxml")
|
||||||
|
search_input = soup.find("input")
|
||||||
|
|
||||||
|
self.assertEqual(search_input.attrs["name"], "q")
|
||||||
|
self.assertEqual(search_input.attrs["hx-get"], "results/")
|
||||||
|
self.assertEqual(search_input.attrs["value"], "")
|
||||||
|
|
||||||
|
self.assertEqual(len(soup.select(search_input.attrs["hx-target"])), 1)
|
||||||
|
self.assertEqual(len(soup.select(search_input.attrs["hx-indicator"])), 1)
|
||||||
|
|
||||||
|
|
||||||
|
class SearchPageResultsTestCase(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls) -> None:
|
||||||
|
cls.home_page = HomePage.objects.get()
|
||||||
|
cls.page = SearchPageFactory(parent=cls.home_page)
|
||||||
|
|
||||||
|
for i in range(SearchPage.PAGE_SIZE + 1):
|
||||||
|
ContentPageFactory(parent=cls.home_page, title=f"Post {i}")
|
||||||
|
|
||||||
|
cls.url = cls.page.url + cls.page.reverse_subpage("results")
|
||||||
|
|
||||||
|
def test_returns_results(self) -> None:
|
||||||
|
with self.assertNumQueries(11):
|
||||||
|
response = self.client.get(self.url, {"q": "post"}, HTTP_HX_REQUEST="true")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertEqual(len(response.context["results"]), SearchPage.PAGE_SIZE)
|
||||||
|
self.assertEqual(response.context["paginator"].count, SearchPage.PAGE_SIZE + 1)
|
||||||
|
self.assertEqual(response.context["search_query"], "post")
|
||||||
|
self.assertEqual(response.context["page_num"], 1)
|
||||||
|
|
||||||
|
def test_page_trigger(self) -> None:
|
||||||
|
response = self.client.get(self.url, {"q": "post"}, HTTP_HX_REQUEST="true")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
trigger = BeautifulSoup(response.content, "lxml").find(
|
||||||
|
"span", attrs={"hx-trigger": "revealed"}
|
||||||
|
)
|
||||||
|
self.assertEqual(trigger.attrs["hx-swap"], "outerHTML")
|
||||||
|
self.assertEqual(trigger.attrs["hx-get"], "results/?q=post&page=2")
|
||||||
|
|
||||||
|
def test_pagination(self) -> None:
|
||||||
|
response = self.client.get(
|
||||||
|
self.url, {"q": "post", "page": 2}, HTTP_HX_REQUEST="true"
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertEqual(response.context["page_num"], 2)
|
||||||
|
self.assertEqual(len(response.context["results"]), 1)
|
||||||
|
|
||||||
|
self.assertIsNone(
|
||||||
|
BeautifulSoup(response.content, "lxml").find(
|
||||||
|
"span", attrs={"hx-trigger": "revealed"}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_too_high_page(self) -> None:
|
||||||
|
with self.assertNumQueries(46):
|
||||||
|
response = self.client.get(
|
||||||
|
self.url, {"q": "post", "page": 3}, HTTP_HX_REQUEST="true"
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_returns_result(self) -> None:
|
||||||
|
response = self.client.get(self.url, {"q": "post 1"}, HTTP_HX_REQUEST="true")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertEqual(len(response.context["results"]), 1)
|
||||||
|
self.assertEqual(list(response.context["results"])[0].title, "Post 1")
|
||||||
|
|
||||||
|
def test_no_results(self) -> None:
|
||||||
|
response = self.client.get(self.url, {"q": "nothing"}, HTTP_HX_REQUEST="true")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertEqual(len(response.context["results"]), 0)
|
||||||
|
self.assertContains(response, "No results found")
|
||||||
|
|
||||||
|
def test_no_query(self) -> None:
|
||||||
|
with self.assertNumQueries(7):
|
||||||
|
response = self.client.get(self.url, HTTP_HX_REQUEST="true")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(response, "search/enter-search-term.html")
|
||||||
|
|
||||||
|
def test_empty_query(self) -> None:
|
||||||
|
with self.assertNumQueries(7):
|
||||||
|
response = self.client.get(self.url, {"q": ""}, HTTP_HX_REQUEST="true")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(response, "search/enter-search-term.html")
|
||||||
|
|
||||||
|
def test_not_htmx(self) -> None:
|
||||||
|
with self.assertNumQueries(7):
|
||||||
|
response = self.client.get(self.url)
|
||||||
|
self.assertEqual(response.status_code, 400)
|
Loading…
Reference in a new issue