diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 74ee428a5..b4de943e0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,10 +16,11 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ 3.8, 3.9, '3.10' ] + python-version: [ 3.9, '3.10' ] requirements-file: [ dj42_cms40.txt, dj32_cms40.txt, + dj42_cms41.txt, ] steps: diff --git a/djangocms_navigation/admin.py b/djangocms_navigation/admin.py index e6f6846be..021646c91 100644 --- a/djangocms_navigation/admin.py +++ b/djangocms_navigation/admin.py @@ -15,6 +15,7 @@ from django.template.response import TemplateResponse from django.urls import path, re_path, reverse, reverse_lazy from django.utils.html import format_html, format_html_join +from django.utils.safestring import mark_safe from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from django.views.i18n import JavaScriptCatalog @@ -26,7 +27,7 @@ from djangocms_versioning.models import Version from treebeard.admin import TreeAdmin -from .compat import TREEBEARD_4_5 +from .compat import CMS_41, TREEBEARD_4_5 from .conf import TREE_MAX_RESULT_PER_PAGE_COUNT from .filters import LanguageFilter from .forms import MenuContentForm, MenuItemForm @@ -36,11 +37,22 @@ from .views import ContentObjectSelect2View, MessageStorageView +menuitem_admin_class = [TreeAdmin] + try: - from djangocms_version_locking.helpers import ( - content_is_unlocked_for_user, - version_is_locked, - ) + if CMS_41: + from cms.admin.utils import ChangeListActionsMixin + + from djangocms_versioning.helpers import ( + content_is_unlocked_for_user, + version_is_locked, + ) + menuitem_admin_class.insert(0, ChangeListActionsMixin) + else: + from djangocms_version_locking.helpers import ( + content_is_unlocked_for_user, + version_is_locked, + ) using_version_lock = True LOCK_MESSAGE = _( @@ -79,7 +91,7 @@ class MenuContentAdmin(ExtendedVersionAdminMixin, admin.ModelAdmin): class Media: js = ("admin/js/jquery.init.js", "djangocms_versioning/js/actions.js",) - css = {"all": ("djangocms_versioning/css/actions.css", "djangocms_version_locking/css/version-locking.css",)} + css = {"all": ("djangocms_version_locking/css/version-locking.css",)} def _list_actions(self, request): """ @@ -138,6 +150,8 @@ def get_list_display(self, request): def is_locked(self, obj): version = self.get_version(obj) if version.state == DRAFT and version_is_locked(version): + if CMS_41: + return mark_safe('') return render_to_string("djangocms_version_locking/admin/locked_icon.html") return "" @@ -185,6 +199,15 @@ def _get_main_navigation_link(self, obj, request, disabled=False): if obj.menu.main_navigation: disabled = True + if CMS_41: + return self.admin_action_button( + url=main_navigation_url, + icon="home", + title=_("Make Main Navigation"), + name="make-main-navigation", + disabled=disabled, + ) + return render_to_string( "admin/djangocms_navigation/icons/main_navigation.html", {"url": main_navigation_url, "disabled": disabled} @@ -262,7 +285,7 @@ def get_menuitem_link(self, obj): @admin.register(MenuItem) -class MenuItemAdmin(TreeAdmin): +class MenuItemAdmin(*menuitem_admin_class): form = MenuItemForm menu_content_model = MenuContent menu_model = Menu @@ -276,7 +299,6 @@ class MenuItemAdmin(TreeAdmin): class Media: css = { "all": ( - "djangocms_versioning/css/actions.css", "djangocms_navigation/css/navigation_admin_changelist.css", ) } @@ -389,6 +411,16 @@ def _get_edit_link(self, obj, request, disabled=False): args=[request.menu_content_id, obj.id] ) + if CMS_41: + return self.admin_action_button( + edit_url, + icon="pencil", + title=_("Edit"), + name="edit", + disabled=disabled, + keepsideframe=False, + ) + return render_to_string( "djangocms_versioning/admin/icons/edit_icon.html", {"url": edit_url, "disabled": disabled, "object_id": obj.id} @@ -402,6 +434,15 @@ def _get_delete_link(self, obj, request, disabled=False): args=[request.menu_content_id, obj.id] ) + if CMS_41: + return self.admin_action_button( + delete_url, + icon="bin", + title=_("Discord"), + name="discard", + disabled=disabled, + ) + return render_to_string( "djangocms_versioning/admin/discard_icon.html", {"discard_url": delete_url, "disabled": disabled, "object_id": obj.id}, diff --git a/djangocms_navigation/compat.py b/djangocms_navigation/compat.py index 3517f7d59..2711c8d79 100644 --- a/djangocms_navigation/compat.py +++ b/djangocms_navigation/compat.py @@ -1,5 +1,8 @@ +from cms import __version__ as CMS_VERSION + from packaging.version import Version from treebeard import __version__ as treebeard_version TREEBEARD_4_5 = Version(treebeard_version) < Version('4.6') +CMS_41 = Version("4.1") <= Version(CMS_VERSION) diff --git a/djangocms_navigation/test_utils/factories.py b/djangocms_navigation/test_utils/factories.py index a96bed0c6..fc644f1d4 100644 --- a/djangocms_navigation/test_utils/factories.py +++ b/djangocms_navigation/test_utils/factories.py @@ -12,6 +12,7 @@ from djangocms_versioning.models import Version from factory.fuzzy import FuzzyChoice, FuzzyInteger, FuzzyText +from ..compat import CMS_41 from ..models import Menu, MenuContent, MenuItem @@ -125,9 +126,14 @@ class PageContentWithVersionFactory(PageContentFactory): def version(self, create, extracted, **kwargs): # NOTE: Use this method as below to define version attributes: # PageContentWithVersionFactory(version__label='label1') + if not create: # Simple build, do nothing. return + + if not CMS_41 and 'locked_by' in kwargs: + kwargs.pop('locked_by') + PageVersionFactory(content=self, **kwargs) diff --git a/djangocms_navigation/utils.py b/djangocms_navigation/utils.py index 30064dc54..bfb168d21 100644 --- a/djangocms_navigation/utils.py +++ b/djangocms_navigation/utils.py @@ -10,6 +10,8 @@ from djangocms_versioning.constants import DRAFT, PUBLISHED from djangocms_versioning.helpers import remove_published_where +from .compat import CMS_41 + def get_admin_name(model, name): name = '{}_{}_{}'.format( @@ -97,9 +99,17 @@ def get_latest_page_content_for_page_grouper(obj, language): :return: A queryset if an item exists, or None if not. :rtype: Queryset object, or None """ - page_contents = PageContent.objects.filter( - page=obj, - language=language, - versions__state__in=[DRAFT, PUBLISHED] - ).order_by("-versions__pk") - return remove_published_where(page_contents).first() + if CMS_41: + page_contents = PageContent.admin_manager.filter( + page=obj, + language=language, + versions__state__in=[DRAFT, PUBLISHED] + ).order_by("-versions__pk") + return page_contents.first() + else: + page_contents = PageContent.objects.filter( + page=obj, + language=language, + versions__state__in=[DRAFT, PUBLISHED] + ).order_by("-versions__pk") + return remove_published_where(page_contents).first() diff --git a/djangocms_navigation/views.py b/djangocms_navigation/views.py index bb49a4ff4..acf5e5b6f 100644 --- a/djangocms_navigation/views.py +++ b/djangocms_navigation/views.py @@ -10,6 +10,7 @@ from djangocms_versioning.constants import ARCHIVED, UNPUBLISHED +from djangocms_navigation.compat import CMS_41 from djangocms_navigation.utils import is_model_supported, supported_models @@ -38,10 +39,16 @@ def get(self, request, *args, **kwargs): # Removing unpublished pages from queryset if model == Page: - queryset_data = [ - page for page in queryset_data - if not getattr(page.get_title_obj().versions.first(), "state", None) in [ARCHIVED, UNPUBLISHED] - ] + if CMS_41: + queryset_data = [ + page for page in queryset_data + if getattr(page.get_content_obj().versions.first(), "state", None) not in [ARCHIVED, UNPUBLISHED] + ] + else: + queryset_data = [ + page for page in queryset_data + if getattr(page.get_title_obj().versions.first(), "state", None) not in [ARCHIVED, UNPUBLISHED] + ] data = { "results": [{"text": str(obj), "id": obj.pk} for obj in queryset_data] diff --git a/tests/requirements/dj42_cms41.txt b/tests/requirements/dj42_cms41.txt new file mode 100644 index 000000000..1a27c0a13 --- /dev/null +++ b/tests/requirements/dj42_cms41.txt @@ -0,0 +1,21 @@ +beautifulsoup4 +coverage +django-app-helper +django-classy-tags +django-sekizai +factory_boy +flake8 +isort +lxml +tox + +django>=4.2,<5.0 +django-treebeard>=4.6.0 +django-cms>=4.1.0 +djangocms-text-ckeditor==5.1.5 +djangocms-versioning==2.1.0 +https://github.com/FreemanPancake/djangocms-version-locking/tarball/feature/djangocms4x-compat#egg=djangocms-version-locking +https://github.com/django-cms/djangocms-moderation/tarball/master#egg=djangocms-moderation +https://github.com/FidelityInternational/djangocms-references/tarball/feat/cms41-compat#egg=djangocms-references +https://github.com/django-cms/djangocms-alias/tarball/master#egg=djangocms-alias +https://github.com/django-cms/djangocms-snippet/tarball/master#egg=djangocms-snippet \ No newline at end of file diff --git a/tests/test_admin.py b/tests/test_admin.py index 8a0466c40..b1a7d557e 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -6,6 +6,7 @@ from unittest.mock import patch from django.contrib import admin +from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.contrib.messages import get_messages from django.contrib.sites.models import Site @@ -14,7 +15,7 @@ from django.test.utils import override_settings from django.utils.translation import gettext_lazy as _ -from cms.api import add_plugin, create_page, create_title +from cms.api import add_plugin, create_page from cms.test_utils.testcases import CMSTestCase from cms.toolbar.utils import get_object_preview_url from cms.utils.compat import DJANGO_4_1 @@ -30,13 +31,21 @@ MenuItemAdmin, MenuItemChangeList, ) -from djangocms_navigation.compat import TREEBEARD_4_5 +from djangocms_navigation.compat import CMS_41, TREEBEARD_4_5 from djangocms_navigation.models import Menu, MenuContent, MenuItem from djangocms_navigation.test_utils import factories from .utils import UsefulAssertsMixin, disable_versioning_for_navigation +versioning_substr = "" +if CMS_41: + from cms.api import create_page_content # noqa: F401 +else: + from cms.api import create_title as create_page_content # noqa: F401 + versioning_substr = "-versioning" + + class MenuItemChangelistTestCase(CMSTestCase): def setUp(self): self.user = self.get_superuser() @@ -218,14 +227,15 @@ def test_list_display_without_version_locking(self): list_display[0:4], ["title", "get_author", "get_modified_date", "get_versioning_state"] ) - self.assertIn("cms-versioning-action-btn", list_display[-1]) + + self.assertIn(f"cms{versioning_substr}-action-btn", list_display[-1]) # The preview button is present - self.assertIn("cms-versioning-action-preview", list_display[-1]) + self.assertIn(f"cms{versioning_substr}-action-preview", list_display[-1]) # The edit button is present - self.assertIn("cms-versioning-action-edit", list_display[-1]) + self.assertIn(f"cms{versioning_substr}-action-edit", list_display[-1]) self.assertIn("cms-form-get-method", list_display[-1]) - self.assertIn("js-versioning-action", list_display[-1]) - self.assertIn("js-versioning-keep-sideframe", list_display[-1]) + self.assertIn(f"js{versioning_substr}-action", list_display[-1]) + self.assertIn(f"js{versioning_substr}-keep-sideframe", list_display[-1]) @override_settings(DJANGOCMS_NAVIGATION_VERSIONING_ENABLED=False) @disable_versioning_for_navigation() @@ -368,7 +378,15 @@ def test_get_changelist_template_preview(self): class MenuItemAdminVersionLocked(CMSTestCase, UsefulAssertsMixin): def setUp(self): - self.menu_content = factories.MenuContentWithVersionFactory(version__state=DRAFT) + self.author_user = factories.UserFactory(is_staff=True) + menu_edit_creation_param = { + "version__state": DRAFT, + } + if CMS_41: + menu_edit_creation_param.update({ + "version__locked_by": self.author_user, + }) + self.menu_content = factories.MenuContentWithVersionFactory(**menu_edit_creation_param) self.item = factories.ChildMenuItemFactory(parent=self.menu_content.root) self.change_url = reverse( @@ -378,7 +396,12 @@ def setUp(self): self.client.force_login(self.get_superuser()) # moving a node - menu_content = factories.MenuContentWithVersionFactory() + menu_move_creation_param = {} + if CMS_41: + menu_move_creation_param.update({ + "version__locked_by": self.author_user, + }) + menu_content = factories.MenuContentWithVersionFactory(**menu_move_creation_param) self.child = factories.ChildMenuItemFactory(parent=menu_content.root) self.child_of_child = factories.ChildMenuItemFactory(parent=self.child) self.move_url = reverse( @@ -1356,6 +1379,16 @@ def test_menuitem_delete_view_item_with_children(self): content ) + def get_permission(self, codename): + _list = codename.split('.') + app_label = '' + if len(_list) > 1: + app_label = _list[0] + codename = _list[1] + return Permission.objects.get(codename=codename, content_type__app_label=app_label) + else: + return Permission.objects.get(codename=codename) + def test_menuitem_delete_view_with_permission(self): """ With appropriate permissions, the delete view allows deletion of Menuitems @@ -1364,14 +1397,17 @@ def test_menuitem_delete_view_with_permission(self): "user_with_delete", is_staff=True ) menu_content = factories.MenuContentWithVersionFactory(version__created_by=user_with_delete_permissions) - child = factories.ChildMenuItemFactory(parent=menu_content.root) - new_child = factories.ChildMenuItemFactory(parent=menu_content.root) - child_of_child = factories.ChildMenuItemFactory(parent=child) - factories.ChildMenuItemFactory(parent=child_of_child) + child = factories.ChildMenuItemFactory(title="child", parent=menu_content.root) + new_child = factories.ChildMenuItemFactory(title="new_child", parent=menu_content.root) + child_of_child = factories.ChildMenuItemFactory(title="child_of_child", parent=child) + factories.ChildMenuItemFactory(title="child_of_child_2", parent=child_of_child) self.add_permission(user_with_delete_permissions, "view_menucontentversion") self.add_permission(user_with_delete_permissions, "delete_menuitem") + if CMS_41: + self.add_permission(user_with_delete_permissions, "djangocms_versioning.delete_versionlock") + # Delete one, editable node, with no children delete_url_single = reverse( "admin:djangocms_navigation_menuitem_delete", args=(menu_content.id, new_child.id,) @@ -1984,7 +2020,7 @@ def test_preview_link(self): func = self.modeladmin._list_actions(self.get_request("/admin")) response = func(menu_content) - self.assertIn("cms-versioning-action-preview", response) + self.assertIn(f"cms{versioning_substr}-action-preview", response) self.assertIn('title="Preview"', response) self.assertIn(preview_endpoint, response) @@ -1999,7 +2035,7 @@ def test_edit_link(self): edit_endpoint = reverse("admin:djangocms_versioning_menucontentversion_edit_redirect", args=(version.pk,),) response = func(menu_content) - self.assertIn("cms-versioning-action-btn", response) + self.assertIn(f"cms{versioning_substr}-action-btn", response) self.assertIn('title="Edit"', response) self.assertIn(edit_endpoint, response) @@ -2023,7 +2059,7 @@ def test_edit_link_not_shown(self): response = func(version.content) - self.assertNotIn("cms-versioning-action-edit ", response) + self.assertNotIn("cms-action-edit ", response) class MenuItemListActionsTestCase(CMSTestCase): @@ -2043,7 +2079,7 @@ def test_edit_link(self): ) response = func(menu_content.root) - self.assertIn("cms-versioning-action-btn", response) + self.assertIn(f"cms{versioning_substr}-action-btn", response) self.assertIn('title="Edit"', response) self.assertIn(edit_endpoint, response) @@ -2064,9 +2100,14 @@ def test_menucontent_changelist_url_link_opens_in_sideframe(self): request.menu_content_id = menucontent.pk url_markup = self.menucontent_modeladmin._get_edit_link(menucontent, request) - # The url link should keep the sideframe open - self.assertIn("js-versioning-keep-sideframe", url_markup) - self.assertNotIn("js-versioning-close-sideframe", url_markup) + if CMS_41: + # The url link should keep the sideframe close + self.assertNotIn("js-keep-sideframe", url_markup) + self.assertIn("js-close-sideframe", url_markup) + else: + # The url link should keep the sideframe open + self.assertIn("js-versioning-keep-sideframe", url_markup) + self.assertNotIn("js-versioning-close-sideframe", url_markup) def test_menucontent_preview_link_opens_in_sideframe(self): """ @@ -2079,9 +2120,14 @@ def test_menucontent_preview_link_opens_in_sideframe(self): request.menu_content_id = menucontent.pk url_markup = self.menucontent_modeladmin._get_preview_link(menucontent, request) - # The url link should keep the sideframe open - self.assertIn("js-versioning-keep-sideframe", url_markup) - self.assertNotIn("js-versioning-close-sideframe", url_markup) + if CMS_41: + # The url link should keep the sideframe close + self.assertNotIn("js-keep-sideframe", url_markup) + self.assertIn("js-close-sideframe", url_markup) + else: + # The url link should keep the sideframe open + self.assertIn("js-versioning-keep-sideframe", url_markup) + self.assertNotIn("js-versioning-close-sideframe", url_markup) def test_menuitem_changelist_edit_url_link_opens_in_sideframe(self): """ @@ -2096,9 +2142,14 @@ def test_menuitem_changelist_edit_url_link_opens_in_sideframe(self): request.menu_content_id = menucontent.pk url_markup = self.menuitem_modeladmin._get_edit_link(child, request) - # The url link should keep the sideframe open - self.assertIn("js-versioning-keep-sideframe", url_markup) - self.assertNotIn("js-versioning-close-sideframe", url_markup) + if CMS_41: + # The url link should keep the sideframe close + self.assertNotIn("js-keep-sideframe", url_markup) + self.assertIn("js-close-sideframe", url_markup) + else: + # The url link should keep the sideframe open + self.assertIn("js-versioning-keep-sideframe", url_markup) + self.assertNotIn("js-versioning-close-sideframe", url_markup) def test_menuitem_changelist_delete_url_link_opens_in_sideframe(self): """ @@ -2113,9 +2164,14 @@ def test_menuitem_changelist_delete_url_link_opens_in_sideframe(self): request.menu_content_id = menucontent.pk url_markup = self.menuitem_modeladmin._get_delete_link(child, request) - # The url link should keep the sideframe open - self.assertIn("js-versioning-keep-sideframe", url_markup) - self.assertNotIn("js-versioning-close-sideframe", url_markup) + if CMS_41: + # The url link should keep the sideframe open by default + self.assertIn("js-keep-sideframe", url_markup) + self.assertNotIn("js-close-sideframe", url_markup) + else: + # The url link should keep the sideframe open + self.assertIn("js-versioning-keep-sideframe", url_markup) + self.assertNotIn("js-versioning-close-sideframe", url_markup) class ReferencesIntegrationTestCase(CMSTestCase): @@ -2137,7 +2193,7 @@ def test_menucontent_references_integration(self): in_navigation=True, **kwargs ) - page_content = create_title("en", "Draft Page", page, created_by=self.user) + page_content = create_page_content("en", "Draft Page", page, created_by=self.user) placeholder = factories.PlaceholderFactory( source=page_content, diff --git a/tests/test_cms_menus.py b/tests/test_cms_menus.py index d84ace4b0..8d114d5c4 100644 --- a/tests/test_cms_menus.py +++ b/tests/test_cms_menus.py @@ -327,12 +327,14 @@ def test_draft_menu_on_draft_page(self): page=page, language=self.language, version__created_by=self.get_superuser(), + version__locked_by=self.get_superuser(), version__state=PUBLISHED, ) pagecontent_draft = factories.PageContentWithVersionFactory( page=page, language=self.language, version__created_by=self.get_superuser(), + version__locked_by=self.get_superuser(), version__state=DRAFT, ) draft_child = factories.ChildMenuItemFactory(parent=menu_cont_draft.root, content=pagecontent_draft.page) @@ -373,12 +375,14 @@ def test_draft_menu_on_published_page(self): page=page, language=self.language, version__created_by=self.get_superuser(), + version__locked_by=self.get_superuser(), version__state=PUBLISHED, ) pagecontent_draft = factories.PageContentWithVersionFactory( page=page, language=self.language, version__created_by=self.get_superuser(), + version__locked_by=self.get_superuser(), version__state=DRAFT, ) @@ -393,8 +397,7 @@ def test_draft_menu_on_published_page(self): # Node added in draft menu version is not rendered in published view, only published menu nodes are rendered with self.login_user_context(self.get_superuser()): - response = self.client.get(pagecontent_published.page.get_absolute_url()) - + response = self.client.get(pagecontent_draft.page.get_absolute_url()) self.assertEqual(response.status_code, 200) self.assertIn(published_child.title, str(response.content)) self.assertNotIn(draft_child.title, str(response.content)) @@ -451,13 +454,20 @@ def setUp(self): self.language = "en" # A page that will contain a menu i.e. we can see the menu rendered on this page preview_pagecontent = factories.PageContentWithVersionFactory( + language=self.language, + version__created_by=self.get_superuser(), + version__locked_by=self.get_superuser(), + version__state=DRAFT, + ) + published_pagecontent = factories.PageContentWithVersionFactory( language=self.language, version__created_by=self.get_superuser(), version__state=PUBLISHED, ) + self.edit_endpoint = get_object_edit_url(preview_pagecontent, language=self.language) self.preview_endpoint = get_object_preview_url(preview_pagecontent, language=self.language) - self.live_endpoint = preview_pagecontent.get_absolute_url(language=self.language) + self.live_endpoint = published_pagecontent.get_absolute_url(language=self.language) # Menu creation self.menu = factories.MenuFactory() self.published_menu_content = factories.MenuContentWithVersionFactory( @@ -1536,6 +1546,7 @@ def test_menu_with_multiple_languages(self): 'request': self.get_request( root_pagecontent_it.page.get_absolute_url(language="it"), language="it", page=root_pagecontent_it.page) } + context_it_raw['request'].GET = {'language': 'it'} context_it = Context(context_it_raw) context_it = add_toolbar_to_request(context_it, root_pagecontent_it, view_mode="edit") template.render(context_it) @@ -1678,14 +1689,21 @@ class MainNavigationIntegrationTestCase(CMSTestCase): """ def setUp(self): # create a page and urls we can use to make a request with the test client + self.draft_pagecontent = factories.PageContentWithVersionFactory( + language="en", + version__created_by=self.get_superuser(), + version__locked_by=self.get_superuser(), + version__state=DRAFT, + ) + self.pagecontent = factories.PageContentWithVersionFactory( language="en", version__created_by=self.get_superuser(), version__state=PUBLISHED, ) self.live_url = self.pagecontent.get_absolute_url() - self.edit_url = get_object_edit_url(self.pagecontent, language="en") - self.preview_url = get_object_preview_url(self.pagecontent, language="en") + self.edit_url = get_object_edit_url(self.draft_pagecontent, language="en") + self.preview_url = get_object_preview_url(self.draft_pagecontent, language="en") # create two menus, neither marked as the main navigation self.first_menucontent = factories.MenuContentWithVersionFactory( language="en", @@ -1753,7 +1771,6 @@ def test_both_main_navigation(self): edit_response = self.client.get(self.edit_url) preview_response = self.client.get(self.preview_url) live_response = self.client.get(self.live_url) - for response in [edit_response, preview_response, live_response]: with self.subTest(response): nav_tree = get_nav_from_response(response) @@ -1791,6 +1808,13 @@ def test_both_main_navigation_multiple_sites(self): version__state=PUBLISHED, page__node__site=site_2, ) + site_2_draft_pagecontent = factories.PageContentWithVersionFactory( + language="en", + version__created_by=self.get_superuser(), + version__locked_by=self.get_superuser(), + version__state=DRAFT, + page__node__site=site_2, + ) # test for when the menu is marked main navigation, and when it isnt for is_main_navigation in [False, True]: @@ -1800,8 +1824,8 @@ def test_both_main_navigation_multiple_sites(self): make_main_navigation(site_2_menucontent) with self.login_user_context(self.get_superuser()): - edit_response = self.client.get(get_object_edit_url(site_2_pagecontent)) - preview_response = self.client.get(get_object_preview_url(site_2_pagecontent)) + edit_response = self.client.get(get_object_edit_url(site_2_draft_pagecontent)) + preview_response = self.client.get(get_object_preview_url(site_2_draft_pagecontent)) live_response = self.client.get(site_2_pagecontent.get_absolute_url()) for response in [edit_response, preview_response, live_response]: diff --git a/tests/test_helpers.py b/tests/test_helpers.py index d340a718e..7a6911dff 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -160,7 +160,7 @@ def test_select_node_from_deeply_nested_nodes(self): factories.ChildMenuItemFactory(parent=menuversions.content.root) child3 = factories.ChildMenuItemFactory(parent=menuversions.content.root) factories.ChildMenuItemFactory(parent=child3) - max_queries = 52 + max_queries = 58 page_url = page_content.page.get_absolute_url() with self.assertNumQueries(FuzzyInt(3, max_queries)): diff --git a/tests/test_utils.py b/tests/test_utils.py index a1c2ab234..990205e43 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -108,6 +108,12 @@ def setUp(self): version__state=PUBLISHED, ) + # for draft version get edit url. + self.page_content_draft = factories.PageContentWithVersionFactory( + version__created_by=self.get_superuser(), + version__state=DRAFT, + ) + def test_live_endpoint(self): live_endpoint = self.page_content.get_absolute_url(language=self.page_content.language) @@ -128,7 +134,7 @@ def test_preview_endpoint(self): self.assertTrue(actual) def test_edit_endpoint(self): - edit_endpoint = get_object_edit_url(self.page_content, language=self.page_content.language) + edit_endpoint = get_object_edit_url(self.page_content_draft, language=self.page_content.language) with self.login_user_context(self.get_superuser()): response = self.client.get(edit_endpoint) diff --git a/tests/test_views.py b/tests/test_views.py index f2fbf4611..83151d7e7 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -127,11 +127,11 @@ def test_raise_error_when_return_unregistered_user_model_in_select2_view(self): def test_select2_view_text_page_repr(self): """Result should contain model repr text""" page_contenttype_id = ContentType.objects.get_for_model(Page).id - PageContentFactory( - title="test", menu_title="test", page_title="test", language="en" + PageContentWithVersionFactory( + title="test", menu_title="test", page_title="test", language="en", version__state=PUBLISHED ) # flake8: noqa - PageContentFactory( - title="test2", menu_title="test2", page_title="test2", language="en" + PageContentWithVersionFactory( + title="test2", menu_title="test2", page_title="test2", language="en", version__state=PUBLISHED ) # flake8: noqa with self.login_user_context(self.superuser): response = self.client.get( @@ -145,11 +145,11 @@ def test_select2_view_text_page_repr(self): def test_select2_view_search_text_page(self): """ Both pages should appear in results for test query""" page_contenttype_id = ContentType.objects.get_for_model(Page).id - PageContentFactory( - title="test", menu_title="test", page_title="test", language="en" + PageContentWithVersionFactory( + title="test", menu_title="test", page_title="test", language="en", version__state=PUBLISHED ) - PageContentFactory( - title="test2", menu_title="test2", page_title="test2", language="en" + PageContentWithVersionFactory( + title="test2", menu_title="test2", page_title="test2", language="en", version__state=PUBLISHED ) with self.login_user_context(self.superuser): response = self.client.get( @@ -163,11 +163,11 @@ def test_select2_view_search_text_page(self): def test_select2_view_search_exact_text_page(self): """ One page should appear in results for test2 exact query""" page_contenttype_id = ContentType.objects.get_for_model(Page).id - PageContentFactory( - title="test", menu_title="test", page_title="test", language="en" + PageContentWithVersionFactory( + title="test", menu_title="test", page_title="test", language="en", version__state=PUBLISHED ) - PageContentFactory( - title="test2", menu_title="test2", page_title="test2", language="en" + PageContentWithVersionFactory( + title="test2", menu_title="test2", page_title="test2", language="en", version__state=PUBLISHED ) with self.login_user_context(self.superuser): response = self.client.get( @@ -272,8 +272,8 @@ def test_with_pages_in_multiple_languages(self): Check that when page content exists in multiple languages, only pages for the current language are returned """ page_contenttype_id = ContentType.objects.get_for_model(Page).id - french = PageContentFactory( - title="test", menu_title="test", page_title="test", language="fr", + french = PageContentWithVersionFactory( + title="test", menu_title="test", page_title="test", language="fr", version__state=PUBLISHED ) PageContentFactory.create_batch(10, title="test", menu_title="test", page_title="test", language="en") @@ -300,7 +300,13 @@ def test_with_pages_for_multiple_sites(self): site1 = Site.objects.create(name="site1.com", domain="site1.com") site2 = Site.objects.create(name="site2.com", domain="site2.com") PageContentFactory.create_batch(10, title="test", page__node__site=site1, language="en") - expected = PageContentFactory(title="test", menu_title="site2 page", page__node__site=site2, language="en") + expected = PageContentWithVersionFactory( + title="test", + menu_title="site2 page", + page__node__site=site2, + language="en", + version__state=PUBLISHED + ) with self.login_user_context(self.superuser): response = self.client.get( @@ -322,7 +328,9 @@ def test_searching_for_page_slug(self): """ page_contenttype_id = ContentType.objects.get_for_model(Page).id PageContentFactory.create_batch(10, language="en") - expected = PageContentFactory(title="Test search by slug", menu_title="Test search by slug", language="en") + expected = PageContentWithVersionFactory( + title="Test search by slug", menu_title="Test search by slug", language="en", version__state=PUBLISHED + ) slug = expected.page.get_slug("en") # early smoke test to stop us getting a false positive by finding the page by its title rather than slug self.assertNotEqual(expected.title.lower(), slug) @@ -347,7 +355,13 @@ def test_searching_for_page_path(self): """ page_contenttype_id = ContentType.objects.get_for_model(Page).id PageContentFactory.create_batch(10, language="en") - expected = PageContentFactory(menu_title="Test search by overwritten url", language="en") + expected = PageContentWithVersionFactory( + title="test", + menu_title="Test search by overwritten url", + page_title="test", + language="en", + version__state=PUBLISHED + ) # update page urls to use a randomly generated path to represent setting an overwritten url path = fake.uri_path() expected.page.urls.update(path=path) @@ -480,7 +494,7 @@ def test_page_queryset_filters_pages_by_current_language(self): for language in ["en", "fr", "de", "it"]: with self.subTest(msg=language): request = self.get_request(language=language) - request.GET = {"content_type_id": self.page_contenttype_id, "query": "test"} + request.GET = {"content_type_id": self.page_contenttype_id, "query": "test", "language": language} self.view.request = request results = self.view.get_data() diff --git a/tox.ini b/tox.ini index bbf18d355..7394d0349 100644 --- a/tox.ini +++ b/tox.ini @@ -2,20 +2,21 @@ envlist = flake8 isort - py{38,39,310}-dj{32,42}-sqlite-cms40 + py{39,310}-dj{32,42}-sqlite-cms{40,41} skip_missing_interpreters=True [testenv] +allowlist_externals=coverage deps = flake8: -r{toxinidir}/tests/requirements/requirements_base.txt isort: -r{toxinidir}/tests/requirements/requirements_base.txt - dj32: -r{toxinidir}/tests/requirements/dj32_cms40.txt - dj42: -r{toxinidir}/tests/requirements/dj42_cms40.txt + dj32-cms40: -r{toxinidir}/tests/requirements/dj32_cms40.txt + dj42-cms40: -r{toxinidir}/tests/requirements/dj42_cms40.txt + dj42-cms41: -r{toxinidir}/tests/requirements/dj42_cms41.txt basepython = - py38: python3.8 py39: python3.9 py310: python3.10