Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

test_alert.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. import mock
  2. import warnings
  3. from django_webtest import WebTest
  4. from django.contrib.auth.models import AnonymousUser
  5. from django.core.urlresolvers import reverse
  6. from django.core import mail
  7. from django.test import TestCase
  8. from oscar.utils.deprecation import RemovedInOscar20Warning
  9. from oscar.apps.customer.alerts.utils import (
  10. send_alert_confirmation, send_product_alerts)
  11. from oscar.apps.customer.forms import ProductAlertForm
  12. from oscar.apps.customer.models import ProductAlert
  13. from oscar.test.factories import (
  14. create_product, create_stockrecord, ProductAlertFactory, UserFactory)
  15. class TestAUser(WebTest):
  16. def setUp(self):
  17. self.user = UserFactory()
  18. self.product = create_product(num_in_stock=0)
  19. def test_can_create_a_stock_alert(self):
  20. product_page = self.app.get(self.product.get_absolute_url(), user=self.user)
  21. form = product_page.forms['alert_form']
  22. form.submit()
  23. alerts = ProductAlert.objects.filter(user=self.user)
  24. self.assertEqual(1, len(alerts))
  25. alert = alerts[0]
  26. self.assertEqual(ProductAlert.ACTIVE, alert.status)
  27. self.assertEqual(alert.product, self.product)
  28. def test_cannot_create_multiple_alerts_for_one_product(self):
  29. ProductAlertFactory(user=self.user, product=self.product,
  30. status=ProductAlert.ACTIVE)
  31. # Alert form should not allow creation of additional alerts.
  32. form = ProductAlertForm(user=self.user, product=self.product, data={})
  33. self.assertFalse(form.is_valid())
  34. self.assertIn(
  35. "You already have an active alert for this product",
  36. form.errors['__all__'][0])
  37. class TestAUserWithAnActiveStockAlert(WebTest):
  38. def setUp(self):
  39. self.user = UserFactory()
  40. self.product = create_product()
  41. self.stockrecord = create_stockrecord(self.product, num_in_stock=0)
  42. product_page = self.app.get(self.product.get_absolute_url(),
  43. user=self.user)
  44. form = product_page.forms['alert_form']
  45. form.submit()
  46. def test_can_cancel_it(self):
  47. alerts = ProductAlert.objects.filter(user=self.user)
  48. self.assertEqual(1, len(alerts))
  49. alert = alerts[0]
  50. self.assertFalse(alert.is_cancelled)
  51. self.app.get(
  52. reverse('customer:alerts-cancel-by-pk', kwargs={'pk': alert.pk}),
  53. user=self.user)
  54. alerts = ProductAlert.objects.filter(user=self.user)
  55. self.assertEqual(1, len(alerts))
  56. alert = alerts[0]
  57. self.assertTrue(alert.is_cancelled)
  58. def test_gets_notified_when_it_is_back_in_stock(self):
  59. self.stockrecord.num_in_stock = 10
  60. self.stockrecord.save()
  61. self.assertEqual(1, self.user.notifications.all().count())
  62. def test_gets_emailed_when_it_is_back_in_stock(self):
  63. self.stockrecord.num_in_stock = 10
  64. self.stockrecord.save()
  65. self.assertEqual(1, len(mail.outbox))
  66. def test_does_not_get_emailed_when_it_is_saved_but_still_zero_stock(self):
  67. self.stockrecord.num_in_stock = 0
  68. self.stockrecord.save()
  69. self.assertEqual(0, len(mail.outbox))
  70. class TestAnAnonymousUser(WebTest):
  71. def test_can_create_a_stock_alert(self):
  72. product = create_product(num_in_stock=0)
  73. product_page = self.app.get(product.get_absolute_url())
  74. form = product_page.forms['alert_form']
  75. form['email'] = 'john@smith.com'
  76. form.submit()
  77. alerts = ProductAlert.objects.filter(email='john@smith.com')
  78. self.assertEqual(1, len(alerts))
  79. alert = alerts[0]
  80. self.assertEqual(ProductAlert.UNCONFIRMED, alert.status)
  81. self.assertEqual(alert.product, product)
  82. def test_can_cancel_unconfirmed_stock_alert(self):
  83. alert = ProductAlertFactory(
  84. user=None, email='john@smith.com', status=ProductAlert.UNCONFIRMED)
  85. self.app.get(
  86. reverse('customer:alerts-cancel-by-key', kwargs={'key': alert.key}))
  87. alert.refresh_from_db()
  88. self.assertTrue(alert.is_cancelled)
  89. def test_cannot_create_multiple_alerts_for_one_product(self):
  90. product = create_product(num_in_stock=0)
  91. alert = ProductAlertFactory(user=None, product=product,
  92. email='john@smith.com')
  93. alert.status = ProductAlert.ACTIVE
  94. alert.save()
  95. # Alert form should not allow creation of additional alerts.
  96. form = ProductAlertForm(user=AnonymousUser(), product=product,
  97. data={'email': 'john@smith.com'})
  98. self.assertFalse(form.is_valid())
  99. self.assertIn(
  100. "There is already an active stock alert for john@smith.com",
  101. form.errors['__all__'][0])
  102. def test_cannot_create_multiple_unconfirmed_alerts(self):
  103. # Create an unconfirmed alert
  104. ProductAlertFactory(
  105. user=None, email='john@smith.com', status=ProductAlert.UNCONFIRMED)
  106. # Alert form should not allow creation of additional alerts.
  107. form = ProductAlertForm(
  108. user=AnonymousUser(),
  109. product=create_product(num_in_stock=0),
  110. data={'email': 'john@smith.com'},
  111. )
  112. self.assertFalse(form.is_valid())
  113. self.assertIn(
  114. "john@smith.com has been sent a confirmation email for another "
  115. "product alert on this site.", form.errors['__all__'][0])
  116. class TestHurryMode(TestCase):
  117. def setUp(self):
  118. self.user = UserFactory()
  119. self.product = create_product()
  120. def test_hurry_mode_not_set_when_stock_high(self):
  121. # One alert, 5 items in stock. No need to hurry.
  122. create_stockrecord(self.product, num_in_stock=5)
  123. ProductAlert.objects.create(user=self.user, product=self.product)
  124. send_product_alerts(self.product)
  125. self.assertEqual(1, len(mail.outbox))
  126. self.assertNotIn(
  127. 'Beware that the amount of items in stock is limited',
  128. mail.outbox[0].body)
  129. def test_hurry_mode_set_when_stock_low(self):
  130. # Two alerts, 1 item in stock. Hurry mode should be set.
  131. create_stockrecord(self.product, num_in_stock=1)
  132. ProductAlert.objects.create(user=self.user, product=self.product)
  133. ProductAlert.objects.create(user=UserFactory(), product=self.product)
  134. send_product_alerts(self.product)
  135. self.assertEqual(2, len(mail.outbox))
  136. self.assertIn(
  137. 'Beware that the amount of items in stock is limited',
  138. mail.outbox[0].body)
  139. def test_hurry_mode_not_set_multiple_stockrecords(self):
  140. # Two stockrecords, 5 items in stock for one. No need to hurry.
  141. create_stockrecord(self.product, num_in_stock=1)
  142. create_stockrecord(self.product, num_in_stock=5)
  143. ProductAlert.objects.create(user=self.user, product=self.product)
  144. send_product_alerts(self.product)
  145. self.assertNotIn(
  146. 'Beware that the amount of items in stock is limited',
  147. mail.outbox[0].body)
  148. def test_hurry_mode_set_multiple_stockrecords(self):
  149. # Two stockrecords, low stock on both. Hurry mode should be set.
  150. create_stockrecord(self.product, num_in_stock=1)
  151. create_stockrecord(self.product, num_in_stock=1)
  152. ProductAlert.objects.create(user=self.user, product=self.product)
  153. ProductAlert.objects.create(user=UserFactory(), product=self.product)
  154. send_product_alerts(self.product)
  155. self.assertIn(
  156. 'Beware that the amount of items in stock is limited',
  157. mail.outbox[0].body)
  158. class TestAlertMessageSending(TestCase):
  159. def setUp(self):
  160. self.user = UserFactory()
  161. self.product = create_product()
  162. create_stockrecord(self.product, num_in_stock=1)
  163. @mock.patch('oscar.apps.customer.utils.Dispatcher.dispatch_direct_messages')
  164. def test_alert_confirmation_uses_dispatcher(self, mock_dispatch):
  165. alert = ProductAlert.objects.create(
  166. email='test@example.com',
  167. key='dummykey',
  168. status=ProductAlert.UNCONFIRMED,
  169. product=self.product
  170. )
  171. send_alert_confirmation(alert)
  172. self.assertEqual(mock_dispatch.call_count, 1)
  173. self.assertEqual(mock_dispatch.call_args[0][0], 'test@example.com')
  174. @mock.patch('oscar.apps.customer.utils.Dispatcher.dispatch_user_messages')
  175. def test_alert_uses_dispatcher(self, mock_dispatch):
  176. ProductAlert.objects.create(user=self.user, product=self.product)
  177. send_product_alerts(self.product)
  178. self.assertEqual(mock_dispatch.call_count, 1)
  179. self.assertEqual(mock_dispatch.call_args[0][0], self.user)
  180. def test_alert_creates_email_obj(self):
  181. ProductAlert.objects.create(user=self.user, product=self.product)
  182. send_product_alerts(self.product)
  183. self.assertEqual(self.user.emails.count(), 1)
  184. @staticmethod
  185. def _load_deprecated_template(path):
  186. from django.template.loader import select_template
  187. # Replace the old template paths with new ones, thereby mocking
  188. # the presence of the deprecated templates.
  189. if path.startswith('customer/alerts/emails/'):
  190. old_path = path.replace('customer/alerts/emails/', '')
  191. path_map = {
  192. 'confirmation_body.txt': 'confirmation_body.txt',
  193. 'confirmation_subject.txt': 'confirmation_subject.txt',
  194. 'alert_body.txt': 'body.txt',
  195. 'alert_subject.txt': 'subject.txt',
  196. }
  197. new_path = 'customer/emails/commtype_product_alert_{}'.format(
  198. path_map[old_path]
  199. )
  200. # We use 'select_template' because 'load_template' is mocked...
  201. return select_template([new_path])
  202. return select_template([path])
  203. @mock.patch('oscar.apps.customer.alerts.utils.loader.get_template')
  204. def test_deprecated_notification_templates_work(self, mock_loader):
  205. """
  206. This test can be removed when support for the deprecated templates is
  207. dropped.
  208. """
  209. mock_loader.side_effect = self._load_deprecated_template
  210. with warnings.catch_warnings(record=True) as warning_list:
  211. warnings.simplefilter("always")
  212. alert = ProductAlert.objects.create(
  213. email='test@example.com',
  214. key='dummykey',
  215. status=ProductAlert.UNCONFIRMED,
  216. product=self.product
  217. )
  218. send_alert_confirmation(alert)
  219. # Check that warnings were raised
  220. self.assertTrue(
  221. any(item.category == RemovedInOscar20Warning for item in warning_list))
  222. # Check that alerts were still sent
  223. self.assertEqual(len(mail.outbox), 1)
  224. @mock.patch('oscar.apps.customer.alerts.utils.loader.get_template')
  225. def test_deprecated_alert_templates_work(self, mock_loader):
  226. """
  227. This test can be removed when support for the deprecated templates is
  228. dropped.
  229. """
  230. mock_loader.side_effect = self._load_deprecated_template
  231. with warnings.catch_warnings(record=True) as warning_list:
  232. warnings.simplefilter("always")
  233. ProductAlert.objects.create(user=self.user, product=self.product)
  234. send_product_alerts(self.product)
  235. # Check that warnings were raised
  236. self.assertTrue(
  237. any(item.category == RemovedInOscar20Warning for item in warning_list))
  238. # Check that alerts were still sent
  239. self.assertEqual(len(mail.outbox), 1)