Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
290 changes: 279 additions & 11 deletions docs/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import unittest
from http import HTTPStatus

from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.test import SimpleTestCase, TestCase
from django.urls import reverse, set_urlconf
from django_hosts.resolvers import reverse as reverse_with_host
from django_hosts.resolvers import reverse as reverse_with_host, reverse_host

from djangoproject.urls import www as www_urls
from djangoproject.urls import docs as docs_urls, www as www_urls
from releases.models import Release

from ..models import Document, DocumentRelease
Expand All @@ -29,7 +31,7 @@ def test_team_url(self):
def test_internals_team(self):
response = self.client.get(
"/en/dev/internals/team/",
headers={"host": "docs.djangoproject.localhost:8000"},
headers={"host": reverse_host("docs")},
)
self.assertRedirects(
response,
Expand All @@ -38,6 +40,146 @@ def test_internals_team(self):
fetch_redirect_response=False,
)

def test_redirect_index_view(self):
response = self.client.get(
"/en/dev/index/", # Route without name
headers={"host": reverse_host("docs")},
)
self.assertRedirects(response, "/en/dev/", fetch_redirect_response=False)


class LangAndReleaseRedirectTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.release = Release.objects.create(version="5.2")
cls.doc_release = DocumentRelease.objects.create(
release=cls.release, is_default=True
)

def test_index_view_redirect_to_current_document_release(self):
response = self.client.get(
reverse_with_host("homepage", host="docs"),
headers={"host": reverse_host("docs")},
)
self.assertRedirects(
response, self.doc_release.get_absolute_url(), fetch_redirect_response=False
)

def test_language_view_redirect_to_current_document_release_with_the_same_language(
self,
):
fr_doc_release = DocumentRelease.objects.create(release=self.release, lang="fr")
response = self.client.get(
"/fr/", # Route without name
headers={"host": reverse_host("docs")},
)
self.assertRedirects(
response, fr_doc_release.get_absolute_url(), fetch_redirect_response=False
)

def test_stable_view_redirect_to_current_document_release(self):
response = self.client.get(
reverse_with_host(
# The stable view doesn't have a name but it's basically
# the document-detail route with a version set to "stable"
"document-detail",
kwargs={
"version": "stable",
"lang": self.doc_release.lang,
"url": "intro",
},
host="docs",
),
headers={"host": reverse_host("docs")},
)
# Using Django's `reverse()` over django-hosts's `reverse_host()` as the later
# one return an absolute URL but the view redirect only using the path component
expected_url = reverse(
# The stable view route doesn't have a name but it's basically
# the `document-detail` route with a version set to "stable"
"document-detail",
kwargs={
"version": self.doc_release.version,
"lang": self.doc_release.lang,
"url": "intro",
},
urlconf=docs_urls,
)
self.assertRedirects(response, expected_url, fetch_redirect_response=False)


class DocumentViewTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.doc_release = DocumentRelease.objects.create(is_default=True)

def test_document_index_view(self):
# Set up a release so we aren't in `dev` version
self.doc_release.release = Release.objects.create(version="5.2")
self.doc_release.save(update_fields=["release"])

response = self.client.get(
reverse_with_host(
"document-index",
kwargs={
"lang": self.doc_release.lang,
"version": self.doc_release.version,
},
host="docs",
),
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context.get("docurl"), "")
self.assertEqual(
response.context.get("rtd_version"), f"{self.doc_release.version}.x"
)
# Check the header used for Fastly
self.assertEqual(response.headers.get("Surrogate-Control"), "max-age=604800")

def test_document_index_view_with_dev_version(self):
response = self.client.get(
reverse_with_host(
"document-index",
kwargs={"lang": self.doc_release.lang, "version": "dev"},
host="docs",
),
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context.get("rtd_version"), "latest")

@unittest.expectedFailure
def test_document_index_view_with_stable_version(self):
response = self.client.get(
reverse_with_host(
"document-index",
kwargs={"lang": self.doc_release.lang, "version": "stable"},
host="docs",
),
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context.get("rtd_version"), "latest")

def test_document_detail_view(self):
response = self.client.get(
reverse_with_host(
"document-detail",
kwargs={
"lang": self.doc_release.lang,
"version": "dev",
"url": "intro",
},
host="docs",
),
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context.get("docurl"), "intro")
# Check the header used for Fastly
self.assertEqual(response.headers.get("Surrogate-Control"), "max-age=604800")


class SearchFormTestCase(TestCase):
fixtures = ["doc_test_fixtures"]
Expand Down Expand Up @@ -80,14 +222,14 @@ def tearDownClass(cls):

def test_empty_get(self):
response = self.client.get(
"/en/dev/search/", headers={"host": "docs.djangoproject.localhost:8000"}
"/en/dev/search/", headers={"host": reverse_host("docs")}
)
self.assertEqual(response.status_code, 200)

def test_search_type_filter_all(self):
response = self.client.get(
"/en/5.1/search/?q=generic",
headers={"host": "docs.djangoproject.localhost:8000"},
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertContains(
Expand All @@ -101,7 +243,7 @@ def test_search_type_filter_by_doc_types(self):
with self.subTest(category=category):
response = self.client.get(
f"/en/5.1/search/?q=generic&category={category.value}",
headers={"host": "docs.djangoproject.localhost:8000"},
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertContains(
Expand All @@ -118,7 +260,7 @@ def test_search_type_filter_by_doc_types(self):
def test_search_category_filter_invalid_doc_categories(self):
response = self.client.get(
"/en/5.1/search/?q=generic&category=invalid-so-ignored",
headers={"host": "docs.djangoproject.localhost:8000"},
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertContains(
Expand All @@ -130,7 +272,7 @@ def test_search_category_filter_invalid_doc_categories(self):
def test_search_category_filter_no_results(self):
response = self.client.get(
"/en/5.1/search/?q=potato&category=ref",
headers={"host": "docs.djangoproject.localhost:8000"},
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertContains(response, self.active_filter, count=1)
Expand Down Expand Up @@ -220,7 +362,7 @@ def test_code_links(self):
with self.subTest(query=query):
response = self.client.get(
f"/en/5.1/search/?q={query}",
headers={"host": "docs.djangoproject.localhost:8000"},
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertContains(
Expand All @@ -231,6 +373,31 @@ def test_code_links(self):
self.assertContains(response, expected_code_links, html=True)


class SearchRedirectTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.doc_release = DocumentRelease.objects.create(is_default=True)

def test_redirect_search_view(self):
# With a `q` parameters
response = self.client.get(
"/search/?q=django", headers={"host": reverse_host("docs")}
)
self.assertRedirects(
response,
"http://" + reverse_host("docs") + "/en/dev/search/?q=django",
fetch_redirect_response=False,
)

# Without a `q` parameters
response = self.client.get("/search/", headers={"host": reverse_host("docs")})
self.assertRedirects(
response,
"http://" + reverse_host("docs") + "/en/dev/search/",
fetch_redirect_response=False,
)


class SitemapTests(TestCase):
fixtures = ["doc_test_fixtures"]

Expand All @@ -242,7 +409,7 @@ def tearDownClass(cls):

def test_sitemap_index(self):
response = self.client.get(
"/sitemap.xml", headers={"host": "docs.djangoproject.localhost:8000"}
"/sitemap.xml", headers={"host": reverse_host("docs")}
)
self.assertContains(response, "<sitemap>", count=2)
en_sitemap_url = reverse_with_host(
Expand All @@ -261,9 +428,110 @@ def test_sitemap(self):

def test_sitemap_404(self):
response = self.client.get(
"/sitemap-xx.xml", headers={"host": "docs.djangoproject.localhost:8000"}
"/sitemap-xx.xml", headers={"host": reverse_host("docs")}
)
self.assertEqual(response.status_code, 404)
self.assertEqual(
response.context["exception"], "No sitemap available for section: 'xx'"
)


class OpenSearchTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.doc_release = DocumentRelease.objects.create(
release=Release.objects.create(version="5.2"), is_default=True
)

def test_search_suggestions_view(self):
# Without `q` parameter
response = self.client.get(
reverse_with_host(
"document-search-suggestions",
kwargs={
"lang": self.doc_release.lang,
"version": self.doc_release.version,
},
host="docs",
),
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.headers["Content-Type"], "application/json")
self.assertEqual(response.json(), [])

# With `q` parameter but no Document
response = self.client.get(
reverse_with_host(
"document-search-suggestions",
kwargs={
"lang": self.doc_release.lang,
"version": self.doc_release.version,
},
host="docs",
)
+ "?q=test",
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.headers["Content-Type"], "application/json")
self.assertEqual(response.json(), ["test", [], [], []])

# # With `q` parameter and a Document
document = Document.objects.create(
release=self.doc_release,
path="test-document",
title="test title",
)
response = self.client.get(
reverse_with_host(
"document-search-suggestions",
kwargs={
"lang": self.doc_release.lang,
"version": self.doc_release.version,
},
host="docs",
)
+ "?q=test",
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.headers["Content-Type"], "application/json")
self.assertEqual(
response.json(),
[
"test",
["test title"],
[],
[
reverse_with_host(
"contenttypes-shortcut",
kwargs={
"content_type_id": ContentType.objects.get_for_model(
Document
).pk,
"object_id": document.id,
},
)
],
],
)

def test_search_description(self):
response = self.client.get(
reverse_with_host(
"document-search-description",
kwargs={
"lang": self.doc_release.lang,
"version": self.doc_release.version,
},
host="docs",
),
headers={"host": reverse_host("docs")},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.headers["Content-Type"], "application/opensearchdescription+xml"
)
self.assertTemplateUsed("docs/search_description.html")
self.assertContains(response, f"<Language>{self.doc_release.lang}</Language>")
3 changes: 3 additions & 0 deletions docs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def document(request, lang, version, url):

canonical_version = DocumentRelease.objects.current_version()
canonical = version == canonical_version
# FIXME: I think it's dead code.
# The stable view route is higher than document-* ones,
# and test_document_index_view_with_stable_version failed with a 302
if version == "stable":
version = canonical_version

Expand Down