You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_alert.py 10.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. from unittest import mock
  2. from django_webtest import WebTest
  3. from django.contrib.auth.models import AnonymousUser
  4. from django.urls import reverse
  5. from django.core import mail
  6. from django.test import TestCase
  7. from oscar.apps.customer.alerts.utils import (
  8. send_alert_confirmation, send_product_alerts)
  9. from oscar.apps.customer.forms import ProductAlertForm
  10. from oscar.apps.customer.models import ProductAlert
  11. from oscar.test.factories import (
  12. create_product, create_stockrecord, ProductAlertFactory, UserFactory)
  13. class TestAUser(WebTest):
  14. def setUp(self):
  15. self.user = UserFactory()
  16. self.product = create_product(num_in_stock=0)
  17. def test_can_create_a_stock_alert(self):
  18. product_page = self.app.get(self.product.get_absolute_url(), user=self.user)
  19. form = product_page.forms['alert_form']
  20. form.submit()
  21. alerts = ProductAlert.objects.filter(user=self.user)
  22. self.assertEqual(1, len(alerts))
  23. alert = alerts[0]
  24. self.assertEqual(ProductAlert.ACTIVE, alert.status)
  25. self.assertEqual(alert.product, self.product)
  26. def test_cannot_create_multiple_alerts_for_one_product(self):
  27. ProductAlertFactory(user=self.user, product=self.product,
  28. status=ProductAlert.ACTIVE)
  29. # Alert form should not allow creation of additional alerts.
  30. form = ProductAlertForm(user=self.user, product=self.product, data={})
  31. self.assertFalse(form.is_valid())
  32. self.assertIn(
  33. "You already have an active alert for this product",
  34. form.errors['__all__'][0])
  35. class TestAUserWithAnActiveStockAlert(WebTest):
  36. def setUp(self):
  37. self.user = UserFactory()
  38. self.product = create_product()
  39. self.stockrecord = create_stockrecord(self.product, num_in_stock=0)
  40. product_page = self.app.get(self.product.get_absolute_url(),
  41. user=self.user)
  42. form = product_page.forms['alert_form']
  43. form.submit()
  44. def test_can_cancel_it(self):
  45. alerts = ProductAlert.objects.filter(user=self.user)
  46. self.assertEqual(1, len(alerts))
  47. alert = alerts[0]
  48. self.assertFalse(alert.is_cancelled)
  49. self.app.get(
  50. reverse('customer:alerts-cancel-by-pk', kwargs={'pk': alert.pk}),
  51. user=self.user)
  52. alerts = ProductAlert.objects.filter(user=self.user)
  53. self.assertEqual(1, len(alerts))
  54. alert = alerts[0]
  55. self.assertTrue(alert.is_cancelled)
  56. def test_gets_notified_when_it_is_back_in_stock(self):
  57. self.stockrecord.num_in_stock = 10
  58. self.stockrecord.save()
  59. self.assertEqual(1, self.user.notifications.all().count())
  60. def test_gets_emailed_when_it_is_back_in_stock(self):
  61. self.stockrecord.num_in_stock = 10
  62. self.stockrecord.save()
  63. self.assertEqual(1, len(mail.outbox))
  64. def test_does_not_get_emailed_when_it_is_saved_but_still_zero_stock(self):
  65. self.stockrecord.num_in_stock = 0
  66. self.stockrecord.save()
  67. self.assertEqual(0, len(mail.outbox))
  68. @mock.patch('oscar.apps.customer.alerts.utils.services.notify_user')
  69. def test_site_notification_sent(self, mock_notify):
  70. self.stockrecord.num_in_stock = 10
  71. self.stockrecord.save()
  72. mock_notify.assert_called_once_with(
  73. self.user,
  74. '{} is back in stock'.format(self.product.title),
  75. body='<a href="{}">{}</a> is back in stock'.format(
  76. self.product.get_absolute_url(), self.product.title)
  77. )
  78. @mock.patch('oscar.apps.customer.alerts.utils.services.notify_user')
  79. def test_product_title_truncated_in_alert_notification_subject(self, mock_notify):
  80. self.product.title = ('Aut nihil dignissimos perspiciatis. Beatae sed consequatur odit incidunt. '
  81. 'Quaerat labore perferendis quasi aut sunt maxime accusamus laborum. '
  82. 'Ut quam repudiandae occaecati eligendi. Nihil rem vel eos.')
  83. self.product.save()
  84. self.stockrecord.num_in_stock = 10
  85. self.stockrecord.save()
  86. mock_notify.assert_called_once_with(
  87. self.user,
  88. '{} is back in stock'.format(self.product.title[:200]),
  89. body='<a href="{}">{}</a> is back in stock'.format(
  90. self.product.get_absolute_url(), self.product.title)
  91. )
  92. class TestAnAnonymousUser(WebTest):
  93. def test_can_create_a_stock_alert(self):
  94. product = create_product(num_in_stock=0)
  95. product_page = self.app.get(product.get_absolute_url())
  96. form = product_page.forms['alert_form']
  97. form['email'] = 'john@smith.com'
  98. form.submit()
  99. alerts = ProductAlert.objects.filter(email='john@smith.com')
  100. self.assertEqual(1, len(alerts))
  101. alert = alerts[0]
  102. self.assertEqual(ProductAlert.UNCONFIRMED, alert.status)
  103. self.assertEqual(alert.product, product)
  104. def test_can_cancel_unconfirmed_stock_alert(self):
  105. alert = ProductAlertFactory(
  106. user=None, email='john@smith.com', status=ProductAlert.UNCONFIRMED)
  107. self.app.get(
  108. reverse('customer:alerts-cancel-by-key', kwargs={'key': alert.key}))
  109. alert.refresh_from_db()
  110. self.assertTrue(alert.is_cancelled)
  111. def test_cannot_create_multiple_alerts_for_one_product(self):
  112. product = create_product(num_in_stock=0)
  113. alert = ProductAlertFactory(user=None, product=product,
  114. email='john@smith.com')
  115. alert.status = ProductAlert.ACTIVE
  116. alert.save()
  117. # Alert form should not allow creation of additional alerts.
  118. form = ProductAlertForm(user=AnonymousUser(), product=product,
  119. data={'email': 'john@smith.com'})
  120. self.assertFalse(form.is_valid())
  121. self.assertIn(
  122. "There is already an active stock alert for john@smith.com",
  123. form.errors['__all__'][0])
  124. def test_cannot_create_multiple_unconfirmed_alerts(self):
  125. # Create an unconfirmed alert
  126. ProductAlertFactory(
  127. user=None, email='john@smith.com', status=ProductAlert.UNCONFIRMED)
  128. # Alert form should not allow creation of additional alerts.
  129. form = ProductAlertForm(
  130. user=AnonymousUser(),
  131. product=create_product(num_in_stock=0),
  132. data={'email': 'john@smith.com'},
  133. )
  134. self.assertFalse(form.is_valid())
  135. self.assertIn(
  136. "john@smith.com has been sent a confirmation email for another "
  137. "product alert on this site.", form.errors['__all__'][0])
  138. class TestHurryMode(TestCase):
  139. def setUp(self):
  140. self.user = UserFactory()
  141. self.product = create_product()
  142. def test_hurry_mode_not_set_when_stock_high(self):
  143. # One alert, 5 items in stock. No need to hurry.
  144. create_stockrecord(self.product, num_in_stock=5)
  145. ProductAlert.objects.create(user=self.user, product=self.product)
  146. send_product_alerts(self.product)
  147. self.assertEqual(1, len(mail.outbox))
  148. self.assertNotIn(
  149. 'Beware that the amount of items in stock is limited',
  150. mail.outbox[0].body)
  151. def test_hurry_mode_set_when_stock_low(self):
  152. # Two alerts, 1 item in stock. Hurry mode should be set.
  153. create_stockrecord(self.product, num_in_stock=1)
  154. ProductAlert.objects.create(user=self.user, product=self.product)
  155. ProductAlert.objects.create(user=UserFactory(), product=self.product)
  156. send_product_alerts(self.product)
  157. self.assertEqual(2, len(mail.outbox))
  158. self.assertIn(
  159. 'Beware that the amount of items in stock is limited',
  160. mail.outbox[0].body)
  161. def test_hurry_mode_not_set_multiple_stockrecords(self):
  162. # Two stockrecords, 5 items in stock for one. No need to hurry.
  163. create_stockrecord(self.product, num_in_stock=1)
  164. create_stockrecord(self.product, num_in_stock=5)
  165. ProductAlert.objects.create(user=self.user, product=self.product)
  166. send_product_alerts(self.product)
  167. self.assertNotIn(
  168. 'Beware that the amount of items in stock is limited',
  169. mail.outbox[0].body)
  170. def test_hurry_mode_set_multiple_stockrecords(self):
  171. # Two stockrecords, low stock on both. Hurry mode should be set.
  172. create_stockrecord(self.product, num_in_stock=1)
  173. create_stockrecord(self.product, num_in_stock=1)
  174. ProductAlert.objects.create(user=self.user, product=self.product)
  175. ProductAlert.objects.create(user=UserFactory(), product=self.product)
  176. send_product_alerts(self.product)
  177. self.assertIn(
  178. 'Beware that the amount of items in stock is limited',
  179. mail.outbox[0].body)
  180. class TestAlertMessageSending(TestCase):
  181. def setUp(self):
  182. self.user = UserFactory()
  183. self.product = create_product()
  184. create_stockrecord(self.product, num_in_stock=1)
  185. @mock.patch('oscar.apps.customer.utils.Dispatcher.dispatch_direct_messages')
  186. def test_alert_confirmation_uses_dispatcher(self, mock_dispatch):
  187. alert = ProductAlert.objects.create(
  188. email='test@example.com',
  189. key='dummykey',
  190. status=ProductAlert.UNCONFIRMED,
  191. product=self.product
  192. )
  193. send_alert_confirmation(alert)
  194. self.assertEqual(mock_dispatch.call_count, 1)
  195. self.assertEqual(mock_dispatch.call_args[0][0], 'test@example.com')
  196. @mock.patch('oscar.apps.customer.utils.Dispatcher.dispatch_user_messages')
  197. def test_alert_uses_dispatcher(self, mock_dispatch):
  198. ProductAlert.objects.create(user=self.user, product=self.product)
  199. send_product_alerts(self.product)
  200. self.assertEqual(mock_dispatch.call_count, 1)
  201. self.assertEqual(mock_dispatch.call_args[0][0], self.user)
  202. def test_alert_creates_email_obj(self):
  203. ProductAlert.objects.create(user=self.user, product=self.product)
  204. send_product_alerts(self.product)
  205. self.assertEqual(self.user.emails.count(), 1)