1import os 2import unittest 3from unittest import mock 4 5from django.conf import settings 6from django.core import mail 7from django.test import RequestFactory, TestCase 8 9from contact_form.forms import AkismetContactForm, ContactForm 10 11 12class ContactFormTests(TestCase): 13 """ 14 Tests the base ContactForm. 15 16 """ 17 18 valid_data = {"name": "Test", "email": "test@example.com", "body": "Test message"} 19 20 def request(self): 21 return RequestFactory().request() 22 23 def test_request_required(self): 24 """ 25 Can't instantiate without an HttpRequest. 26 27 """ 28 self.assertRaises(TypeError, ContactForm) 29 30 def test_valid_data_required(self): 31 """ 32 Can't try to build the message dict unless data is valid. 33 34 """ 35 data = {"name": "Test", "body": "Test message"} 36 form = ContactForm(request=self.request(), data=data) 37 self.assertRaises(ValueError, form.get_message_dict) 38 self.assertRaises(ValueError, form.get_context) 39 40 def test_send(self): 41 """ 42 Valid form can and does in fact send email. 43 44 """ 45 form = ContactForm(request=self.request(), data=self.valid_data) 46 self.assertTrue(form.is_valid()) 47 48 form.save() 49 self.assertEqual(1, len(mail.outbox)) 50 51 message = mail.outbox[0] 52 self.assertTrue(self.valid_data["body"] in message.body) 53 self.assertEqual(settings.DEFAULT_FROM_EMAIL, message.from_email) 54 self.assertEqual(form.recipient_list, message.recipients()) 55 56 def test_no_sites(self): 57 """ 58 Sites integration works with or without installed 59 contrib.sites. 60 61 """ 62 with self.modify_settings(INSTALLED_APPS={"remove": ["django.contrib.sites"]}): 63 form = ContactForm(request=self.request(), data=self.valid_data) 64 self.assertTrue(form.is_valid()) 65 66 form.save() 67 self.assertEqual(1, len(mail.outbox)) 68 69 def test_recipient_list(self): 70 """ 71 Passing recipient_list when instantiating ContactForm properly 72 overrides the list of recipients. 73 74 """ 75 recipient_list = ["recipient_list@example.com"] 76 form = ContactForm( 77 request=self.request(), data=self.valid_data, recipient_list=recipient_list 78 ) 79 self.assertTrue(form.is_valid()) 80 81 form.save() 82 self.assertEqual(1, len(mail.outbox)) 83 84 message = mail.outbox[0] 85 self.assertEqual(recipient_list, message.recipients()) 86 87 def test_callable_template_name(self): 88 """ 89 When a template_name() method is defined, it is used and 90 preferred over a 'template_name' attribute. 91 92 """ 93 94 class CallableTemplateName(ContactForm): 95 def template_name(self): 96 return "contact_form/test_callable_template_name.html" 97 98 form = CallableTemplateName(request=self.request(), data=self.valid_data) 99 self.assertTrue(form.is_valid()) 100 101 form.save() 102 self.assertEqual(1, len(mail.outbox)) 103 104 message = mail.outbox[0] 105 self.assertTrue("Callable template_name used." in message.body) 106 107 def test_callable_message_parts(self): 108 """ 109 Message parts implemented as methods are called and preferred 110 over attributes. 111 112 """ 113 overridden_data = { 114 "from_email": "override@example.com", 115 "message": "Overridden message.", 116 "recipient_list": ["override_recpt@example.com"], 117 "subject": "Overridden subject", 118 } 119 120 class CallableMessageParts(ContactForm): 121 def from_email(self): 122 return overridden_data["from_email"] 123 124 def message(self): 125 return overridden_data["message"] 126 127 def recipient_list(self): 128 return overridden_data["recipient_list"] 129 130 def subject(self): 131 return overridden_data["subject"] 132 133 form = CallableMessageParts(request=self.request(), data=self.valid_data) 134 self.assertTrue(form.is_valid()) 135 136 self.assertEqual(overridden_data, form.get_message_dict()) 137 138 139@unittest.skipUnless( 140 getattr(settings, "AKISMET_API_KEY", os.getenv("PYTHON_AKISMET_API_KEY")) 141 is not None, 142 "AkismetContactForm requires Akismet configuration", 143) 144class AkismetContactFormTests(TestCase): 145 """ 146 Tests the Akismet contact form. 147 148 """ 149 150 def request(self): 151 return RequestFactory().request() 152 153 def test_akismet_form_spam(self): 154 """ 155 The Akismet contact form correctly rejects spam. 156 157 """ 158 data = { 159 "name": "viagra-test-123", 160 "email": "email@example.com", 161 "body": "This is spam.", 162 } 163 with mock.patch("akismet.Akismet", autospec=True) as akismet_mock: 164 instance = akismet_mock.return_value 165 instance.verify_key.return_value = True 166 instance.comment_check.return_value = True 167 form = AkismetContactForm(request=self.request(), data=data) 168 self.assertFalse(form.is_valid()) 169 self.assertTrue(str(form.SPAM_MESSAGE) in form.errors["body"]) 170 171 def test_akismet_form_ham(self): 172 """ 173 The Akismet contact form correctly accepts non-spam. 174 175 """ 176 data = {"name": "Test", "email": "email@example.com", "body": "Test message."} 177 with mock.patch("akismet.Akismet", autospec=True) as akismet_mock: 178 instance = akismet_mock.return_value 179 instance.verify_key.return_value = True 180 instance.comment_check.return_value = False 181 form = AkismetContactForm(request=self.request(), data=data) 182 self.assertTrue(form.is_valid()) 183 184 def test_akismet_form_no_body(self): 185 """ 186 The Akismet contact form correctly skips validation when no email 187 body is provided. 188 189 """ 190 data = {"name": "Test", "email": "email@example.com"} 191 with mock.patch("akismet.Akismet", autospec=True) as akismet_mock: 192 form = AkismetContactForm(request=self.request(), data=data) 193 self.assertFalse(form.is_valid()) 194 akismet_mock.assert_not_called() 195 self.assertFalse(form.is_valid()) 196