# -*- coding: utf-8 -*-
import json
import unittest
from django import VERSION as DJANGO_VERSION
from django.conf import settings
from django.contrib.auth.models import Group, Permission
from django.core import mail
from django.core.management import call_command
from django.test import TestCase, override_settings
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from taggit.models import Tag
from wagtail.admin.auth import user_has_any_page_permission
from wagtail.admin.mail import send_mail
from wagtail.admin.menu import MenuItem
from wagtail.core.models import Page
from wagtail.tests.testapp.models import RestaurantTag
from wagtail.tests.utils import WagtailTestUtils
class TestHome(TestCase, WagtailTestUtils):
def setUp(self):
# Login
self.login()
def test_simple(self):
response = self.client.get(reverse('wagtailadmin_home'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Welcome to the Test Site Wagtail CMS")
def test_admin_menu(self):
response = self.client.get(reverse('wagtailadmin_home'))
self.assertEqual(response.status_code, 200)
# check that media attached to menu items is correctly pulled in
if DJANGO_VERSION >= (3, 1):
self.assertContains(
response,
'',
html=True
)
else:
self.assertContains(
response,
'',
html=True
)
# check that custom menu items (including classname / attrs parameters) are pulled in
self.assertContains(
response,
'Kittens!',
html=True
)
# Check that the explorer menu item is here, with the right start page.
self.assertContains(
response,
'data-explorer-start-page="1"'
)
# check that is_shown is respected on menu items
response = self.client.get(reverse('wagtailadmin_home') + '?hide-kittens=true')
self.assertNotContains(
response,
'Kittens!'
)
def test_never_cache_header(self):
# This tests that wagtailadmins global cache settings have been applied correctly
response = self.client.get(reverse('wagtailadmin_home'))
self.assertIn('no-cache', response['Cache-Control'])
self.assertIn('no-store', response['Cache-Control'])
self.assertIn('max-age=0', response['Cache-Control'])
self.assertIn('must-revalidate', response['Cache-Control'])
@unittest.skipIf(settings.AUTH_USER_MODEL == 'emailuser.EmailUser', "Only applicable to CustomUser")
def test_nonascii_email(self):
# Test that non-ASCII email addresses don't break the admin; previously these would
# cause a failure when generating Gravatar URLs
self.create_superuser(username='snowman', email='☃@thenorthpole.com', password='password')
# Login
self.assertTrue(self.client.login(username='snowman', password='password'))
response = self.client.get(reverse('wagtailadmin_home'))
self.assertEqual(response.status_code, 200)
class TestEditorHooks(TestCase, WagtailTestUtils):
def setUp(self):
self.homepage = Page.objects.get(id=2)
self.login()
def test_editor_css_hooks_on_add(self):
response = self.client.get(reverse('wagtailadmin_pages:add', args=('tests', 'simplepage', self.homepage.id)))
self.assertEqual(response.status_code, 200)
self.assertContains(response, '')
def test_editor_js_hooks_on_add(self):
response = self.client.get(reverse('wagtailadmin_pages:add', args=('tests', 'simplepage', self.homepage.id)))
self.assertEqual(response.status_code, 200)
self.assertContains(response, '')
def test_editor_css_hooks_on_edit(self):
response = self.client.get(reverse('wagtailadmin_pages:edit', args=(self.homepage.id, )))
self.assertEqual(response.status_code, 200)
self.assertContains(response, '')
def test_editor_js_hooks_on_edit(self):
response = self.client.get(reverse('wagtailadmin_pages:edit', args=(self.homepage.id, )))
self.assertEqual(response.status_code, 200)
self.assertContains(response, '')
class TestSendMail(TestCase):
def test_send_email(self):
send_mail("Test subject", "Test content", ["nobody@email.com"], "test@email.com")
# Check that the email was sent
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "Test subject")
self.assertEqual(mail.outbox[0].body, "Test content")
self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
self.assertEqual(mail.outbox[0].from_email, "test@email.com")
@override_settings(WAGTAILADMIN_NOTIFICATION_FROM_EMAIL='anothertest@email.com')
def test_send_fallback_to_wagtailadmin_notification_from_email_setting(self):
send_mail("Test subject", "Test content", ["nobody@email.com"])
# Check that the email was sent
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "Test subject")
self.assertEqual(mail.outbox[0].body, "Test content")
self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
self.assertEqual(mail.outbox[0].from_email, "anothertest@email.com")
@override_settings(DEFAULT_FROM_EMAIL='yetanothertest@email.com')
def test_send_fallback_to_default_from_email_setting(self):
send_mail("Test subject", "Test content", ["nobody@email.com"])
# Check that the email was sent
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "Test subject")
self.assertEqual(mail.outbox[0].body, "Test content")
self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
self.assertEqual(mail.outbox[0].from_email, "yetanothertest@email.com")
def test_send_default_from_email(self):
send_mail("Test subject", "Test content", ["nobody@email.com"])
# Check that the email was sent
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "Test subject")
self.assertEqual(mail.outbox[0].body, "Test content")
self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
self.assertEqual(mail.outbox[0].from_email, "webmaster@localhost")
def test_send_html_email(self):
"""Test that the kwarg 'html_message' works as expected on send_mail by creating 'alternatives' on the EmailMessage object"""
send_mail("Test HTML subject", "TEXT content", ["has.html@email.com"], html_message="
Test HTML content
")
send_mail("Test TEXT subject", "TEXT content", ["mr.plain.text@email.com"])
# Check that the emails were sent
self.assertEqual(len(mail.outbox), 2)
# check that the first email is the HTML email
email_message = mail.outbox[0]
self.assertEqual(email_message.subject, "Test HTML subject")
self.assertEqual(email_message.alternatives, [('
Test HTML content
', 'text/html')])
self.assertEqual(email_message.body, "TEXT content") # note: plain text will alwasy be added to body, even with alternatives
self.assertEqual(email_message.to, ["has.html@email.com"])
# confirm that without html_message kwarg we do not get 'alternatives'
email_message = mail.outbox[1]
self.assertEqual(email_message.subject, "Test TEXT subject")
self.assertEqual(email_message.alternatives, [])
self.assertEqual(email_message.body, "TEXT content")
self.assertEqual(email_message.to, ["mr.plain.text@email.com"])
class TestTagsAutocomplete(TestCase, WagtailTestUtils):
def setUp(self):
self.login()
Tag.objects.create(name="Test", slug="test")
RestaurantTag.objects.create(name="Italian", slug="italian")
RestaurantTag.objects.create(name="Indian", slug="indian")
def test_tags_autocomplete(self):
response = self.client.get(reverse('wagtailadmin_tag_autocomplete'), {
'term': 'test'
})
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data, ['Test'])
def test_tags_autocomplete_partial_match(self):
response = self.client.get(reverse('wagtailadmin_tag_autocomplete'), {
'term': 'te'
})
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data, ['Test'])
def test_tags_autocomplete_different_term(self):
response = self.client.get(reverse('wagtailadmin_tag_autocomplete'), {
'term': 'hello'
})
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data, [])
def test_tags_autocomplete_no_term(self):
response = self.client.get(reverse('wagtailadmin_tag_autocomplete'))
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data, [])
def test_tags_autocomplete_custom_model(self):
response = self.client.get(
reverse('wagtailadmin_tag_model_autocomplete', args=('tests', 'restauranttag')),
{'term': 'ital'}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data, ['Italian'])
# should not return results from the standard Tag model
response = self.client.get(
reverse('wagtailadmin_tag_model_autocomplete', args=('tests', 'restauranttag')),
{'term': 'test'}
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/json')
data = json.loads(response.content.decode('utf-8'))
self.assertEqual(data, [])
class TestMenuItem(TestCase, WagtailTestUtils):
def setUp(self):
self.login()
response = self.client.get(reverse('wagtailadmin_home'))
self.request = response.wsgi_request
def test_menuitem_reverse_lazy_url_pass(self):
menuitem = MenuItem(_('Test'), reverse_lazy('wagtailadmin_home'))
self.assertEqual(menuitem.is_active(self.request), True)
class TestUserPassesTestPermissionDecorator(TestCase, WagtailTestUtils):
"""
Test for custom user_passes_test permission decorators.
testapp_bob_only_zone is a view configured to only grant access to users with a first_name of Bob
"""
def test_user_passes_test(self):
# create and log in as a user called Bob
self.create_superuser(first_name='Bob', last_name='Mortimer', username='test', password='password')
self.login(username='test', password='password')
response = self.client.get(reverse('testapp_bob_only_zone'))
self.assertEqual(response.status_code, 200)
def test_user_fails_test(self):
# create and log in as a user not called Bob
self.create_superuser(first_name='Vic', last_name='Reeves', username='test', password='password')
self.login(username='test', password='password')
response = self.client.get(reverse('testapp_bob_only_zone'))
self.assertRedirects(response, reverse('wagtailadmin_home'))
def test_user_fails_test_ajax(self):
# create and log in as a user not called Bob
self.create_superuser(first_name='Vic', last_name='Reeves', username='test', password='password')
self.login(username='test', password='password')
response = self.client.get(reverse('testapp_bob_only_zone'), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 403)
class TestUserHasAnyPagePermission(TestCase, WagtailTestUtils):
def test_superuser(self):
user = self.create_superuser(
username='superuser', email='admin@example.com', password='p')
self.assertTrue(user_has_any_page_permission(user))
def test_inactive_superuser(self):
user = self.create_superuser(
username='superuser', email='admin@example.com', password='p')
user.is_active = False
self.assertFalse(user_has_any_page_permission(user))
def test_editor(self):
user = self.create_user(
username='editor', email='ed@example.com', password='p')
editors = Group.objects.get(name='Editors')
user.groups.add(editors)
self.assertTrue(user_has_any_page_permission(user))
def test_moderator(self):
user = self.create_user(
username='moderator', email='mod@example.com', password='p')
editors = Group.objects.get(name='Moderators')
user.groups.add(editors)
self.assertTrue(user_has_any_page_permission(user))
def test_no_permissions(self):
user = self.create_user(
username='pleb', email='pleb@example.com', password='p')
user.user_permissions.add(
Permission.objects.get(content_type__app_label='wagtailadmin', codename='access_admin')
)
self.assertFalse(user_has_any_page_permission(user))
class Test404(TestCase, WagtailTestUtils):
def test_admin_404_template_used_append_slash_true(self):
self.login()
with self.settings(APPEND_SLASH=True):
response = self.client.get('/admin/sdfgdsfgdsfgsdf', follow=True)
# Check 404 error after CommonMiddleware redirect
self.assertEqual(response.status_code, 404)
self.assertTemplateUsed(response, 'wagtailadmin/404.html')
def test_not_logged_in_redirect(self):
response = self.client.get('/admin/sdfgdsfgdsfgsdf/')
# Check that the user was redirected to the login page and that next was set correctly
self.assertRedirects(response, reverse('wagtailadmin_login') + '?next=/admin/sdfgdsfgdsfgsdf/')
class TestAdminURLAppendSlash(TestCase, WagtailTestUtils):
def setUp(self):
# Find root page
self.root_page = Page.objects.get(id=2)
def test_return_correct_view_for_correct_url_without_ending_slash(self):
self.login()
with self.settings(APPEND_SLASH=True):
# Remove trailing slash from URL
response = self.client.get(reverse('wagtailadmin_explore_root')[:-1], follow=True)
# Check that correct page is returned after CommonMiddleware redirect
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailadmin/pages/index.html')
self.assertEqual(Page.objects.get(id=1), response.context['parent_page'])
self.assertTrue(response.context['pages'].paginator.object_list.filter(id=self.root_page.id).exists())
class TestRemoveStaleContentTypes(TestCase):
def test_remove_stale_content_types_preserves_access_admin_permission(self):
call_command('remove_stale_contenttypes', interactive=False)
self.assertTrue(
Permission.objects.filter(content_type__app_label='wagtailadmin', codename='access_admin').exists()
)