|
| 1 | +import unittest |
1 | 2 | from http import HTTPStatus |
2 | 3 |
|
| 4 | +from django.contrib.contenttypes.models import ContentType |
3 | 5 | from django.contrib.sites.models import Site |
4 | 6 | from django.test import SimpleTestCase, TestCase |
5 | 7 | from django.urls import reverse, set_urlconf |
6 | 8 | from django_hosts.resolvers import reverse as reverse_with_host, reverse_host |
7 | 9 |
|
8 | | -from djangoproject.urls import www as www_urls |
| 10 | +from djangoproject.urls import docs as docs_urls, www as www_urls |
9 | 11 | from releases.models import Release |
10 | 12 |
|
11 | 13 | from ..models import Document, DocumentRelease |
@@ -38,6 +40,146 @@ def test_internals_team(self): |
38 | 40 | fetch_redirect_response=False, |
39 | 41 | ) |
40 | 42 |
|
| 43 | + def test_redirect_index_view(self): |
| 44 | + response = self.client.get( |
| 45 | + "/en/dev/index/", # Route without name |
| 46 | + headers={"host": reverse_host("docs")}, |
| 47 | + ) |
| 48 | + self.assertRedirects(response, "/en/dev/", fetch_redirect_response=False) |
| 49 | + |
| 50 | + |
| 51 | +class LangAndReleaseRedirectTests(TestCase): |
| 52 | + @classmethod |
| 53 | + def setUpTestData(cls): |
| 54 | + cls.release = Release.objects.create(version="5.2") |
| 55 | + cls.doc_release = DocumentRelease.objects.create( |
| 56 | + release=cls.release, is_default=True |
| 57 | + ) |
| 58 | + |
| 59 | + def test_index_view_redirect_to_current_document_release(self): |
| 60 | + response = self.client.get( |
| 61 | + reverse_with_host("homepage", host="docs"), |
| 62 | + headers={"host": reverse_host("docs")}, |
| 63 | + ) |
| 64 | + self.assertRedirects( |
| 65 | + response, self.doc_release.get_absolute_url(), fetch_redirect_response=False |
| 66 | + ) |
| 67 | + |
| 68 | + def test_language_view_redirect_to_current_document_release_with_the_same_language( |
| 69 | + self, |
| 70 | + ): |
| 71 | + fr_doc_release = DocumentRelease.objects.create(release=self.release, lang="fr") |
| 72 | + response = self.client.get( |
| 73 | + "/fr/", # Route without name |
| 74 | + headers={"host": reverse_host("docs")}, |
| 75 | + ) |
| 76 | + self.assertRedirects( |
| 77 | + response, fr_doc_release.get_absolute_url(), fetch_redirect_response=False |
| 78 | + ) |
| 79 | + |
| 80 | + def test_stable_view_redirect_to_current_document_release(self): |
| 81 | + response = self.client.get( |
| 82 | + reverse_with_host( |
| 83 | + # The stable view doesn't have a name but it's basically |
| 84 | + # the document-detail route with a version set to "stable" |
| 85 | + "document-detail", |
| 86 | + kwargs={ |
| 87 | + "version": "stable", |
| 88 | + "lang": self.doc_release.lang, |
| 89 | + "url": "intro", |
| 90 | + }, |
| 91 | + host="docs", |
| 92 | + ), |
| 93 | + headers={"host": reverse_host("docs")}, |
| 94 | + ) |
| 95 | + # Using Django's `reverse()` over django-hosts's `reverse_host()` as the later |
| 96 | + # one return an absolute URL but the view redirect only using the path component |
| 97 | + expected_url = reverse( |
| 98 | + # The stable view route doesn't have a name but it's basically |
| 99 | + # the `document-detail` route with a version set to "stable" |
| 100 | + "document-detail", |
| 101 | + kwargs={ |
| 102 | + "version": self.doc_release.version, |
| 103 | + "lang": self.doc_release.lang, |
| 104 | + "url": "intro", |
| 105 | + }, |
| 106 | + urlconf=docs_urls, |
| 107 | + ) |
| 108 | + self.assertRedirects(response, expected_url, fetch_redirect_response=False) |
| 109 | + |
| 110 | + |
| 111 | +class DocumentViewTests(TestCase): |
| 112 | + @classmethod |
| 113 | + def setUpTestData(cls): |
| 114 | + cls.doc_release = DocumentRelease.objects.create(is_default=True) |
| 115 | + |
| 116 | + def test_document_index_view(self): |
| 117 | + # Set up a release so we aren't in `dev` version |
| 118 | + self.doc_release.release = Release.objects.create(version="5.2") |
| 119 | + self.doc_release.save(update_fields=["release"]) |
| 120 | + |
| 121 | + response = self.client.get( |
| 122 | + reverse_with_host( |
| 123 | + "document-index", |
| 124 | + kwargs={ |
| 125 | + "lang": self.doc_release.lang, |
| 126 | + "version": self.doc_release.version, |
| 127 | + }, |
| 128 | + host="docs", |
| 129 | + ), |
| 130 | + headers={"host": reverse_host("docs")}, |
| 131 | + ) |
| 132 | + self.assertEqual(response.status_code, 200) |
| 133 | + self.assertEqual(response.context.get("docurl"), "") |
| 134 | + self.assertEqual( |
| 135 | + response.context.get("rtd_version"), f"{self.doc_release.version}.x" |
| 136 | + ) |
| 137 | + # Check the header used for Fastly |
| 138 | + self.assertEqual(response.headers.get("Surrogate-Control"), "max-age=604800") |
| 139 | + |
| 140 | + def test_document_index_view_with_dev_version(self): |
| 141 | + response = self.client.get( |
| 142 | + reverse_with_host( |
| 143 | + "document-index", |
| 144 | + kwargs={"lang": self.doc_release.lang, "version": "dev"}, |
| 145 | + host="docs", |
| 146 | + ), |
| 147 | + headers={"host": reverse_host("docs")}, |
| 148 | + ) |
| 149 | + self.assertEqual(response.status_code, 200) |
| 150 | + self.assertEqual(response.context.get("rtd_version"), "latest") |
| 151 | + |
| 152 | + @unittest.expectedFailure |
| 153 | + def test_document_index_view_with_stable_version(self): |
| 154 | + response = self.client.get( |
| 155 | + reverse_with_host( |
| 156 | + "document-index", |
| 157 | + kwargs={"lang": self.doc_release.lang, "version": "stable"}, |
| 158 | + host="docs", |
| 159 | + ), |
| 160 | + headers={"host": reverse_host("docs")}, |
| 161 | + ) |
| 162 | + self.assertEqual(response.status_code, 200) |
| 163 | + self.assertEqual(response.context.get("rtd_version"), "latest") |
| 164 | + |
| 165 | + def test_document_detail_view(self): |
| 166 | + response = self.client.get( |
| 167 | + reverse_with_host( |
| 168 | + "document-detail", |
| 169 | + kwargs={ |
| 170 | + "lang": self.doc_release.lang, |
| 171 | + "version": "dev", |
| 172 | + "url": "intro", |
| 173 | + }, |
| 174 | + host="docs", |
| 175 | + ), |
| 176 | + headers={"host": reverse_host("docs")}, |
| 177 | + ) |
| 178 | + self.assertEqual(response.status_code, 200) |
| 179 | + self.assertEqual(response.context.get("docurl"), "intro") |
| 180 | + # Check the header used for Fastly |
| 181 | + self.assertEqual(response.headers.get("Surrogate-Control"), "max-age=604800") |
| 182 | + |
41 | 183 |
|
42 | 184 | class SearchFormTestCase(TestCase): |
43 | 185 | fixtures = ["doc_test_fixtures"] |
@@ -231,6 +373,31 @@ def test_code_links(self): |
231 | 373 | self.assertContains(response, expected_code_links, html=True) |
232 | 374 |
|
233 | 375 |
|
| 376 | +class SearchRedirectTests(TestCase): |
| 377 | + @classmethod |
| 378 | + def setUpTestData(cls): |
| 379 | + cls.doc_release = DocumentRelease.objects.create(is_default=True) |
| 380 | + |
| 381 | + def test_redirect_search_view(self): |
| 382 | + # With a `q` parameters |
| 383 | + response = self.client.get( |
| 384 | + "/search/?q=django", headers={"host": reverse_host("docs")} |
| 385 | + ) |
| 386 | + self.assertRedirects( |
| 387 | + response, |
| 388 | + "http://" + reverse_host("docs") + "/en/dev/search/?q=django", |
| 389 | + fetch_redirect_response=False, |
| 390 | + ) |
| 391 | + |
| 392 | + # Without a `q` parameters |
| 393 | + response = self.client.get("/search/", headers={"host": reverse_host("docs")}) |
| 394 | + self.assertRedirects( |
| 395 | + response, |
| 396 | + "http://" + reverse_host("docs") + "/en/dev/search/", |
| 397 | + fetch_redirect_response=False, |
| 398 | + ) |
| 399 | + |
| 400 | + |
234 | 401 | class SitemapTests(TestCase): |
235 | 402 | fixtures = ["doc_test_fixtures"] |
236 | 403 |
|
@@ -267,3 +434,104 @@ def test_sitemap_404(self): |
267 | 434 | self.assertEqual( |
268 | 435 | response.context["exception"], "No sitemap available for section: 'xx'" |
269 | 436 | ) |
| 437 | + |
| 438 | + |
| 439 | +class OpenSearchTests(TestCase): |
| 440 | + @classmethod |
| 441 | + def setUpTestData(cls): |
| 442 | + cls.doc_release = DocumentRelease.objects.create( |
| 443 | + release=Release.objects.create(version="5.2"), is_default=True |
| 444 | + ) |
| 445 | + |
| 446 | + def test_search_suggestions_view(self): |
| 447 | + # Without `q` parameter |
| 448 | + response = self.client.get( |
| 449 | + reverse_with_host( |
| 450 | + "document-search-suggestions", |
| 451 | + kwargs={ |
| 452 | + "lang": self.doc_release.lang, |
| 453 | + "version": self.doc_release.version, |
| 454 | + }, |
| 455 | + host="docs", |
| 456 | + ), |
| 457 | + headers={"host": reverse_host("docs")}, |
| 458 | + ) |
| 459 | + self.assertEqual(response.status_code, 200) |
| 460 | + self.assertEqual(response.headers["Content-Type"], "application/json") |
| 461 | + self.assertEqual(response.json(), []) |
| 462 | + |
| 463 | + # With `q` parameter but no Document |
| 464 | + response = self.client.get( |
| 465 | + reverse_with_host( |
| 466 | + "document-search-suggestions", |
| 467 | + kwargs={ |
| 468 | + "lang": self.doc_release.lang, |
| 469 | + "version": self.doc_release.version, |
| 470 | + }, |
| 471 | + host="docs", |
| 472 | + ) |
| 473 | + + "?q=test", |
| 474 | + headers={"host": reverse_host("docs")}, |
| 475 | + ) |
| 476 | + self.assertEqual(response.status_code, 200) |
| 477 | + self.assertEqual(response.headers["Content-Type"], "application/json") |
| 478 | + self.assertEqual(response.json(), ["test", [], [], []]) |
| 479 | + |
| 480 | + # # With `q` parameter and a Document |
| 481 | + document = Document.objects.create( |
| 482 | + release=self.doc_release, |
| 483 | + path="test-document", |
| 484 | + title="test title", |
| 485 | + ) |
| 486 | + response = self.client.get( |
| 487 | + reverse_with_host( |
| 488 | + "document-search-suggestions", |
| 489 | + kwargs={ |
| 490 | + "lang": self.doc_release.lang, |
| 491 | + "version": self.doc_release.version, |
| 492 | + }, |
| 493 | + host="docs", |
| 494 | + ) |
| 495 | + + "?q=test", |
| 496 | + headers={"host": reverse_host("docs")}, |
| 497 | + ) |
| 498 | + self.assertEqual(response.status_code, 200) |
| 499 | + self.assertEqual(response.headers["Content-Type"], "application/json") |
| 500 | + self.assertEqual( |
| 501 | + response.json(), |
| 502 | + [ |
| 503 | + "test", |
| 504 | + ["test title"], |
| 505 | + [], |
| 506 | + [ |
| 507 | + reverse_with_host( |
| 508 | + "contenttypes-shortcut", |
| 509 | + kwargs={ |
| 510 | + "content_type_id": ContentType.objects.get_for_model( |
| 511 | + Document |
| 512 | + ).pk, |
| 513 | + "object_id": document.id, |
| 514 | + }, |
| 515 | + ) |
| 516 | + ], |
| 517 | + ], |
| 518 | + ) |
| 519 | + |
| 520 | + def test_search_description(self): |
| 521 | + response = self.client.get( |
| 522 | + reverse_with_host( |
| 523 | + "document-search-description", |
| 524 | + kwargs={ |
| 525 | + "lang": self.doc_release.lang, |
| 526 | + "version": self.doc_release.version, |
| 527 | + }, |
| 528 | + host="docs", |
| 529 | + ), |
| 530 | + headers={"host": reverse_host("docs")}, |
| 531 | + ) |
| 532 | + self.assertEqual(response.status_code, 200) |
| 533 | + self.assertEqual( |
| 534 | + response.headers["Content-Type"], "application/opensearchdescription+xml" |
| 535 | + ) |
| 536 | + self.assertTemplateUsed("docs/search_description.html") |
| 537 | + self.assertContains(response, f"<Language>{self.doc_release.lang}</Language>") |
0 commit comments