diff options
author | 2021-03-25 16:36:16 +0800 | |
---|---|---|
committer | 2021-03-25 16:36:16 +0800 | |
commit | acf7880e233faeb91ce2eeb59855f40b6e7db3e0 (patch) | |
tree | 6c4eff2c0249a1f9cec1832c55312da6016a3c40 | |
parent | Replace `markdown2` with `markdown` and `python-frontmatter`. (diff) |
Refactor content app tests.
The tests uses pyfakefs to simulate a fake filesystem that is reused
over the content app tests.
Test coverage for the app is brought to 100%.
-rw-r--r-- | Pipfile | 1 | ||||
-rw-r--r-- | Pipfile.lock | 10 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/helpers.py | 84 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_content/_info.yml | 2 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_content/category/_info.yml | 2 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_content/category/subcategory/_info.yml | 2 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_content/category/subcategory/test4.md | 6 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_content/category/test3.md | 6 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_content/test.md | 10 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_content/test2.md | 6 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_utils.py | 185 | ||||
-rw-r--r-- | pydis_site/apps/content/tests/test_views.py | 267 | ||||
-rw-r--r-- | pydis_site/apps/content/utils.py | 2 | ||||
-rw-r--r-- | pydis_site/apps/content/views/page_category.py | 2 |
14 files changed, 295 insertions, 290 deletions
@@ -36,6 +36,7 @@ mccabe = "~=0.6.1" pep8-naming = "~=0.9" pre-commit = "~=2.1" unittest-xml-reporting = "~=3.0" +pyfakefs = "~=4.4.0" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 4f8bd0d3..6125e538 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a338a377b64a5d25bf925646c97d932a2d1c783fc8f40d91b6a9ab8f30c2b14e" + "sha256": "dc85f4f1b6ef58c2832d79542d6e88729cd2464bdf9324fef4d0757561f07ca7" }, "pipfile-spec": 6, "requires": { @@ -605,6 +605,14 @@ "markers": "python_version >= '3.6'", "version": "==6.0.0" }, + "pyfakefs": { + "hashes": [ + "sha256:082d863e0e2a74351f697da404e329a91e18e5055942e59d1b836e8459b2c94c", + "sha256:1ac3b2845dabe69af56c20691b9347914581195ccdde352535fb7d4ff0055c19" + ], + "index": "pypi", + "version": "==4.4.0" + }, "pyflakes": { "hashes": [ "sha256:910208209dcea632721cb58363d0f72913d9e8cf64dc6f8ae2e02a3609aba40d", diff --git a/pydis_site/apps/content/tests/helpers.py b/pydis_site/apps/content/tests/helpers.py new file mode 100644 index 00000000..4e0cca34 --- /dev/null +++ b/pydis_site/apps/content/tests/helpers.py @@ -0,0 +1,84 @@ +from pyfakefs.fake_filesystem_unittest import TestCase + +# Valid markdown content with YAML metadata +MARKDOWN_WITH_METADATA = """ +--- +title: TestTitle +description: TestDescription +relevant_links: + Python Discord: https://pythondiscord.com + Discord: https://discord.com +--- +# This is a header. +""" + +MARKDOWN_WITHOUT_METADATA = """#This is a header.""" + +# Valid YAML in a _info.yml file +CATEGORY_INFO = """ +name: Category Name +description: Description +""" + +# The HTML generated from the above markdown data +PARSED_HTML = ( + '<h1 id="this-is-a-header">This is a header.' + '<a class="headerlink" href="#this-is-a-header" title="Permanent link">¶</a></h1>' +) + +# The YAML metadata parsed from the above markdown data +PARSED_METADATA = { + "title": "TestTitle", "description": "TestDescription", + "relevant_links": { + "Python Discord": "https://pythondiscord.com", + "Discord": "https://discord.com" + } +} + +# The YAML data parsed from the above _info.yml file +PARSED_CATEGORY_INFO = {"name": "Category Name", "description": "Description"} + + +class MockPagesTestCase(TestCase): + """ + TestCase with a fake filesystem for testing. + + Structure: + ├── _info.yml + ├── root.md + ├── root_without_metadata.md + ├── not_a_page.md + ├── tmp + | ├── _info.yml + | └── category_without_info + └── category + ├── _info.yml + ├── with_metadata.md + └── subcategory + ├── with_metadata.md + └── without_metadata.md + """ + + def setUp(self): + """Create the fake filesystem.""" + self.setUpPyfakefs() + + self.fs.create_file("_info.yml", contents=CATEGORY_INFO) + self.fs.create_file("root.md", contents=MARKDOWN_WITH_METADATA) + self.fs.create_file("root_without_metadata.md", contents=MARKDOWN_WITHOUT_METADATA) + self.fs.create_file("not_a_page.md/_info.yml", contents=CATEGORY_INFO) + self.fs.create_file("category/_info.yml", contents=CATEGORY_INFO) + self.fs.create_file("category/with_metadata.md", contents=MARKDOWN_WITH_METADATA) + self.fs.create_file("category/subcategory/_info.yml", contents=CATEGORY_INFO) + self.fs.create_file( + "category/subcategory/with_metadata.md", contents=MARKDOWN_WITH_METADATA + ) + self.fs.create_file( + "category/subcategory/without_metadata.md", contents=MARKDOWN_WITHOUT_METADATA + ) + + # There is always a `tmp` directory in the filesystem, so make it a category + # for testing purposes. + # See: https://jmcgeheeiv.github.io/pyfakefs/release/usage.html#os-temporary-directories + self.fs.create_file("tmp/_info.yml", contents=CATEGORY_INFO) + self.fs.create_dir("tmp/category_without_info") diff --git a/pydis_site/apps/content/tests/test_content/_info.yml b/pydis_site/apps/content/tests/test_content/_info.yml deleted file mode 100644 index ad5fc113..00000000 --- a/pydis_site/apps/content/tests/test_content/_info.yml +++ /dev/null @@ -1,2 +0,0 @@ -name: Base Category -description: Base Description diff --git a/pydis_site/apps/content/tests/test_content/category/_info.yml b/pydis_site/apps/content/tests/test_content/category/_info.yml deleted file mode 100644 index 8311509d..00000000 --- a/pydis_site/apps/content/tests/test_content/category/_info.yml +++ /dev/null @@ -1,2 +0,0 @@ -name: My Category -description: My Description diff --git a/pydis_site/apps/content/tests/test_content/category/subcategory/_info.yml b/pydis_site/apps/content/tests/test_content/category/subcategory/_info.yml deleted file mode 100644 index f1c40264..00000000 --- a/pydis_site/apps/content/tests/test_content/category/subcategory/_info.yml +++ /dev/null @@ -1,2 +0,0 @@ -name: My Category 1 -description: My Description 1 diff --git a/pydis_site/apps/content/tests/test_content/category/subcategory/test4.md b/pydis_site/apps/content/tests/test_content/category/subcategory/test4.md deleted file mode 100644 index 1763a869..00000000 --- a/pydis_site/apps/content/tests/test_content/category/subcategory/test4.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Test 4 -description: Testing 4 ---- - -This is also test content and in subcategory. diff --git a/pydis_site/apps/content/tests/test_content/category/test3.md b/pydis_site/apps/content/tests/test_content/category/test3.md deleted file mode 100644 index 9f294130..00000000 --- a/pydis_site/apps/content/tests/test_content/category/test3.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Test 3 -description: Testing 3 ---- - -This is too test content, but in category. diff --git a/pydis_site/apps/content/tests/test_content/test.md b/pydis_site/apps/content/tests/test_content/test.md deleted file mode 100644 index 709860d1..00000000 --- a/pydis_site/apps/content/tests/test_content/test.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Test -description: Testing -relevant_links: - Asking Good Questions: https://pythondiscord.com/pages/resources/guides/asking-good-questions/ - Help Channel Guide: https://pythondiscord.com/pages/resources/guides/help-channels/ - Code of Conduct: https://pythondiscord.com/pages/code-of-conduct/ ---- - -This is test content. diff --git a/pydis_site/apps/content/tests/test_content/test2.md b/pydis_site/apps/content/tests/test_content/test2.md deleted file mode 100644 index 0e57c3cd..00000000 --- a/pydis_site/apps/content/tests/test_content/test2.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Test 2 -description: Testing 2 ---- - -This is too test content. diff --git a/pydis_site/apps/content/tests/test_utils.py b/pydis_site/apps/content/tests/test_utils.py index 3831ad33..58175d6f 100644 --- a/pydis_site/apps/content/tests/test_utils.py +++ b/pydis_site/apps/content/tests/test_utils.py @@ -1,150 +1,91 @@ from pathlib import Path -from unittest.mock import patch -from django.conf import settings from django.http import Http404 -from django.test import TestCase, override_settings -from markdown2 import markdown from pydis_site.apps.content import utils +from pydis_site.apps.content.tests.helpers import ( + MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA +) -BASE_PATH = Path(settings.BASE_DIR, "pydis_site", "apps", "content", "tests", "test_content") +class GetCategoryTests(MockPagesTestCase): + """Tests for the get_category function.""" -class TestGetCategory(TestCase): - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_category_successfully(self): - """Check does this get right data from category data file.""" - path = BASE_PATH.joinpath("category") - result = utils.get_category(path) + def test_get_valid_category(self): + result = utils.get_category(Path("category")) - self.assertEqual(result, {"name": "My Category", "description": "My Description"}) + self.assertEqual(result, {"name": "Category Name", "description": "Description"}) - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_category_not_exists(self): - """Check does this raise 404 error when category don't exists.""" + def test_get_nonexistent_category(self): with self.assertRaises(Http404): - path = BASE_PATH.joinpath("invalid") - utils.get_category(path) + utils.get_category(Path("invalid")) - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_category_not_directory(self): - """Check does this raise 404 error when category isn't directory.""" + def test_get_category_with_path_to_file(self): + # Valid categories are directories, not files with self.assertRaises(Http404): - path = BASE_PATH.joinpath("test.md") - utils.get_category(path) + utils.get_category(Path("root.md")) + def test_get_category_without_info_yml(self): + # Categories should provide an _info.yml file + with self.assertRaises(FileNotFoundError): + utils.get_category(Path("tmp/category_without_info")) -class TestGetCategories(TestCase): - @override_settings(PAGES_PATH=BASE_PATH) - @patch("pydis_site.apps.content.utils.get_category") - def test_get_categories(self, get_category_mock): - """Check does this return test content categories.""" - get_category_mock.return_value = {"name": "My Category", "description": "My Description"} - path = BASE_PATH.joinpath("category") - result = utils.get_categories(path) +class GetCategoriesTests(MockPagesTestCase): + """Tests for the get_categories function.""" - self.assertEqual( - result, {"subcategory": {"name": "My Category", "description": "My Description"}} - ) + def test_get_root_categories(self): + result = utils.get_categories(Path(".")) + + info = PARSED_CATEGORY_INFO + self.assertEqual(result, {"category": info, "tmp": info, "not_a_page.md": info}) + + def test_get_categories_with_subcategories(self): + result = utils.get_categories(Path("category")) + + self.assertEqual(result, {"subcategory": PARSED_CATEGORY_INFO}) + + def test_get_categories_without_subcategories(self): + result = utils.get_categories(Path("category/subcategory")) + + self.assertEqual(result, {}) - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_categories_in_category(self): - """Check does this call joinpath when getting subcategories.""" - path = BASE_PATH.joinpath("category") - result = utils.get_categories(path) + +class GetCategoryPagesTests(MockPagesTestCase): + """Tests for the get_category_pages function.""" + + def test_get_pages_in_root_category_successfully(self): + """The method should successfully retrieve page metadata.""" + root_category_pages = utils.get_category_pages(Path(".")) self.assertEqual( - result, {"subcategory": {"name": "My Category 1", "description": "My Description 1"}} + root_category_pages, {"root": PARSED_METADATA, "root_without_metadata": {}} ) + def test_get_pages_in_subcategories_successfully(self): + """The method should successfully retrieve page metadata.""" + category_pages = utils.get_category_pages(Path("category")) -class TestGetPages(TestCase): - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_all_root_pages(self): - """Check does this return all root level testing content.""" - path = BASE_PATH - result = utils.get_pages(path) - - for case in ["test", "test2"]: - with self.subTest(guide=case): - md = markdown(BASE_PATH.joinpath(f"{case}.md").read_text(), extras=["metadata"]) - - self.assertIn(case, result) - self.assertEqual(md.metadata, result[case]) - - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_all_category_pages(self): - """Check does this return all category testing content.""" - path = BASE_PATH.joinpath("category") - result = utils.get_pages(path) - - md = markdown(BASE_PATH.joinpath("category", "test3.md").read_text(), extras=["metadata"]) - - self.assertIn("test3", result) - self.assertEqual(md.metadata, result["test3"]) - - -class TestGetPage(TestCase): - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_root_page_success(self): - """Check does this return page HTML and metadata when root page exist.""" - path = BASE_PATH.joinpath("test.md") - result = utils.get_page(path) - - md = markdown( - BASE_PATH.joinpath("test.md").read_text(), - extras=[ - "metadata", - "fenced-code-blocks", - "header-ids", - "strike", - "target-blank-links", - "tables", - "task_list" - ] - ) + # Page metadata is properly retrieved + self.assertEqual(category_pages, {"with_metadata": PARSED_METADATA}) - self.assertEqual(result, {"page": str(md), "metadata": md.metadata}) - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_root_page_dont_exist(self): - """Check does this raise Http404 when root page don't exist.""" - with self.assertRaises(Http404): - path = BASE_PATH.joinpath("invalid") - utils.get_page(path) - - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_category_page_success(self): - """Check does this return page HTML and metadata when category guide exist.""" - path = BASE_PATH.joinpath("category", "test3.md") - result = utils.get_page(path) - - md = markdown( - BASE_PATH.joinpath("category", "test3.md").read_text(), - extras=[ - "metadata", - "fenced-code-blocks", - "header-ids", - "strike", - "target-blank-links", - "tables", - "task_list" - ] - ) +class GetPageTests(MockPagesTestCase): + """Tests for the get_page function.""" - self.assertEqual(result, {"page": str(md), "metadata": md.metadata}) + def test_get_page(self): + cases = [ + ("Root page with metadata", "root.md", PARSED_HTML, PARSED_METADATA), + ("Root page without metadata", "root_without_metadata.md", PARSED_HTML, {}), + ("Page with metadata", "category/with_metadata.md", PARSED_HTML, PARSED_METADATA), + ("Page without metadata", "category/subcategory/without_metadata.md", PARSED_HTML, {}), + ] - @override_settings(PAGES_PATH=BASE_PATH) - def test_get_category_page_dont_exist(self): - """Check does this raise Http404 when category page don't exist.""" - with self.assertRaises(Http404): - path = BASE_PATH.joinpath("category", "invalid") - utils.get_page(path) + for msg, page_path, expected_html, expected_metadata in cases: + with self.subTest(msg=msg): + html, metadata = utils.get_page(Path(page_path)) + self.assertEqual(html, expected_html) + self.assertEqual(metadata, expected_metadata) - @patch("pydis_site.settings.PAGES_PATH", new=BASE_PATH) - def test_get_category_page_category_dont_exist(self): - """Check does this raise Http404 when category don't exist.""" + def test_get_nonexistent_page_returns_404(self): with self.assertRaises(Http404): - path = BASE_PATH.joinpath("invalid", "some-guide") - utils.get_page(path) + utils.get_page(Path("invalid")) diff --git a/pydis_site/apps/content/tests/test_views.py b/pydis_site/apps/content/tests/test_views.py index c61671a2..560378bc 100644 --- a/pydis_site/apps/content/tests/test_views.py +++ b/pydis_site/apps/content/tests/test_views.py @@ -1,140 +1,145 @@ from pathlib import Path -from unittest.mock import patch +from unittest import TestCase -from django.conf import settings from django.http import Http404 -from django.test import RequestFactory, TestCase, override_settings -from django_hosts.resolvers import reverse +from django.test import RequestFactory, SimpleTestCase, override_settings +from pyfakefs import fake_filesystem_unittest +from pydis_site.apps.content.tests.helpers import ( + MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA +) from pydis_site.apps.content.views import PageOrCategoryView -BASE_PATH = Path(settings.BASE_DIR, "pydis_site", "apps", "content", "tests", "test_content") - - -class TestPageOrCategoryView(TestCase): - @override_settings(PAGES_PATH=BASE_PATH) - @patch("pydis_site.apps.content.views.page_category.utils.get_page") - @patch("pydis_site.apps.content.views.page_category.utils.get_category") - def test_page_return_code_200(self, get_category_mock, get_page_mock): - get_page_mock.return_value = {"guide": "test", "metadata": {}} - - url = reverse("content:page_category", args=["test2"]) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - get_category_mock.assert_called_once() - get_page_mock.assert_called_once() - - @patch("pydis_site.apps.content.views.page_category.utils.get_page") - @patch("pydis_site.apps.content.views.page_category.utils.get_category") - @override_settings(PAGES_PATH=BASE_PATH) - def test_page_return_404(self, get_category_mock, get_page_mock): - """Check that return code is 404 when invalid page provided.""" - get_page_mock.side_effect = Http404("Page not found.") - - url = reverse("content:page_category", args=["invalid-guide"]) - response = self.client.get(url) - self.assertEqual(response.status_code, 404) - get_page_mock.assert_not_called() - get_category_mock.assert_not_called() - - @patch("pydis_site.apps.content.views.page_category.utils.get_category") - @patch("pydis_site.apps.content.views.page_category.utils.get_pages") - @patch("pydis_site.apps.content.views.page_category.utils.get_categories") - @override_settings(PAGES_PATH=BASE_PATH) - def test_valid_category_code_200( - self, - get_categories_mock, - get_pages_mock, - get_category_mock - ): - """Check that return code is 200 when visiting valid category.""" - get_category_mock.return_value = {"name": "test", "description": "test"} - get_pages_mock.return_value = {} - - url = reverse("content:page_category", args=["category"]) - response = self.client.get(url) - - self.assertEqual(response.status_code, 200) - get_pages_mock.assert_called_once() - self.assertEqual(get_category_mock.call_count, 2) - get_categories_mock.assert_called_once() - - @patch("pydis_site.apps.content.views.page_category.utils.get_category") - @patch("pydis_site.apps.content.views.page_category.utils.get_pages") - @patch("pydis_site.apps.content.views.page_category.utils.get_categories") - @override_settings(PAGES_PATH=BASE_PATH) - def test_invalid_category_code_404( - self, - get_categories_mock, - get_pages_mock, - get_category_mock - ): - """Check that return code is 404 when trying to visit invalid category.""" - get_category_mock.side_effect = Http404("Category not found.") - - url = reverse("content:page_category", args=["invalid-category"]) - response = self.client.get(url) - - self.assertEqual(response.status_code, 404) - get_category_mock.assert_not_called() - get_pages_mock.assert_not_called() - get_categories_mock.assert_not_called() - - @patch("pydis_site.apps.content.views.page_category.utils.get_page") - @patch("pydis_site.apps.content.views.page_category.utils.get_category") - @override_settings(PAGES_PATH=BASE_PATH) - def test_valid_category_page_code_200( - self, - get_category_mock, - get_page_mock - ): - """Check that return code is 200 when visiting valid category page.""" - get_page_mock.return_value = {"guide": "test", "metadata": {}} - - url = reverse("content:page_category", args=["category/test3"]) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - get_page_mock.assert_called_once() - self.assertEqual(get_category_mock.call_count, 2) - - @patch("pydis_site.apps.content.views.page_category.utils.get_page") - @patch("pydis_site.apps.content.views.page_category.utils.get_category") - @override_settings(PAGES_PATH=BASE_PATH) - def test_invalid_category_page_code_404( - self, - get_category_mock, - get_page_mock - ): - """Check that return code is 200 when trying to visit invalid category page.""" - get_page_mock.side_effect = Http404("Page not found.") - - url = reverse("content:page_category", args=["category/invalid"]) - response = self.client.get(url) - self.assertEqual(response.status_code, 404) - get_page_mock.assert_not_called() - get_category_mock.assert_not_called() - - @override_settings(PAGES_PATH=BASE_PATH) - def test_page_category_template_names(self): - """Check that this return category, page template or raise Http404.""" - factory = RequestFactory() + +# Set the module constant within Patcher to use the fake filesystem +# https://jmcgeheeiv.github.io/pyfakefs/master/usage.html#modules-to-reload +with fake_filesystem_unittest.Patcher() as _: + BASE_PATH = Path(".") + + +@override_settings(PAGES_PATH=BASE_PATH) +class PageOrCategoryViewTests(MockPagesTestCase, SimpleTestCase, TestCase): + """Tests for the PageOrCategoryView class.""" + + def setUp(self): + """Set test helpers, then set up fake filesystem.""" + self.factory = RequestFactory() + self.view = PageOrCategoryView.as_view() + self.ViewClass = PageOrCategoryView() + super().setUp() + + # Integration tests + def test_valid_page_or_category_returns_200(self): + cases = [ + ("Page at root", "root"), + ("Category page", "category"), + ("Page in category", "category/with_metadata"), + ("Subcategory page", "category/subcategory"), + ("Page in subcategory", "category/subcategory/with_metadata"), + ] + for msg, path in cases: + with self.subTest(msg=msg, path=path): + request = self.factory.get(f"/{path}") + response = self.view(request, location=path) + self.assertEqual(response.status_code, 200) + + def test_nonexistent_page_returns_404(self): + with self.assertRaises(Http404): + request = self.factory.get("/invalid") + self.view(request, location="invalid") + + # Unit tests + def test_get_template_names_returns_correct_templates(self): + category_template = "content/listing.html" + page_template = "content/page.html" + cases = [ + ("root", page_template), + ("root_without_metadata", page_template), + ("category/with_metadata", page_template), + ("category/subcategory/with_metadata", page_template), + ("category", category_template), + ("category/subcategory", category_template), + ] + + for path, expected_template in cases: + with self.subTest(path=path, expected_template=expected_template): + self.ViewClass.full_location = Path(path) + self.assertEqual(self.ViewClass.get_template_names(), [expected_template]) + + def test_get_template_names_with_nonexistent_paths_returns_404(self): + for path in ("invalid", "another_invalid", "nonexistent"): + with self.subTest(path=path): + self.ViewClass.full_location = Path(path) + with self.assertRaises(Http404): + self.ViewClass.get_template_names() + + def test_get_context_data_with_valid_page(self): + """The method should return required fields in the template context.""" + request = self.factory.get("/root") + self.ViewClass.setup(request) + self.ViewClass.dispatch(request, location="root") + + cases = [ + ("Context includes HTML page content", "page", PARSED_HTML), + ("Context includes page title", "page_title", PARSED_METADATA["title"]), + ( + "Context includes page description", + "page_description", + PARSED_METADATA["description"] + ), + ( + "Context includes relevant link names and URLs", + "relevant_links", + PARSED_METADATA["relevant_links"] + ), + ] + context = self.ViewClass.get_context_data() + for msg, key, expected_value in cases: + with self.subTest(msg=msg): + self.assertEqual(context[key], expected_value) + + def test_get_context_data_with_valid_category(self): + """The method should return required fields in the template context.""" + request = self.factory.get("/category") + self.ViewClass.setup(request) + self.ViewClass.dispatch(request, location="category") + cases = [ - {"location": "category", "output": ["content/listing.html"]}, - {"location": "test", "output": ["content/page.html"]}, - {"location": "invalid", "output": None, "raises": Http404} + ( + "Context includes subcategory names and their information", + "categories", + {"subcategory": PARSED_CATEGORY_INFO} + ), + ( + "Context includes page names and their metadata", + "pages", + {"with_metadata": PARSED_METADATA} + ), + ( + "Context includes page description", + "page_description", + PARSED_CATEGORY_INFO["description"] + ), + ("Context includes page title", "page_title", PARSED_CATEGORY_INFO["name"]), ] - for case in cases: - with self.subTest(location=case["location"], output=case["output"]): - request = factory.get(f"/pages/{case['location']}") - instance = PageOrCategoryView() - instance.request = request - location = Path(case["location"]) - instance.location = location - instance.full_location = BASE_PATH / location - - if "raises" in case: - with self.assertRaises(case["raises"]): - instance.get_template_names() - else: - self.assertEqual(case["output"], instance.get_template_names()) + context = self.ViewClass.get_context_data() + for msg, key, expected_value in cases: + with self.subTest(msg=msg): + self.assertEqual(context[key], expected_value) + + def test_get_context_data_breadcrumbs(self): + """The method should return correct breadcrumbs.""" + request = self.factory.get("/category/subcategory/with_metadata") + self.ViewClass.setup(request) + self.ViewClass.dispatch(request, location="category/subcategory/with_metadata") + + context = self.ViewClass.get_context_data() + self.assertEquals( + context["breadcrumb_items"], + [ + {"name": PARSED_CATEGORY_INFO["name"], "path": "."}, + {"name": PARSED_CATEGORY_INFO["name"], "path": "category"}, + {"name": PARSED_CATEGORY_INFO["name"], "path": "category/subcategory"}, + ] + ) diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py index 11d2b792..726c991f 100644 --- a/pydis_site/apps/content/utils.py +++ b/pydis_site/apps/content/utils.py @@ -33,7 +33,7 @@ def get_category_pages(path: Path) -> Dict[str, Dict]: for item in path.glob("*.md"): if item.is_file(): - pages[item.stem] = frontmatter.load(item) + pages[item.stem] = frontmatter.load(item).metadata return pages diff --git a/pydis_site/apps/content/views/page_category.py b/pydis_site/apps/content/views/page_category.py index 4a2ed2d6..eec4e7e5 100644 --- a/pydis_site/apps/content/views/page_category.py +++ b/pydis_site/apps/content/views/page_category.py @@ -13,7 +13,7 @@ class PageOrCategoryView(TemplateView): def dispatch(self, request: t.Any, *args, **kwargs) -> t.Any: """Conform URL path location to the filesystem path.""" - self.location = Path(self.kwargs.get("location", "")) + self.location = Path(kwargs.get("location", "")) self.full_location = settings.PAGES_PATH / self.location return super().dispatch(request, *args, **kwargs) |