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_product.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. import datetime
  2. import os
  3. import posixpath
  4. import shutil
  5. from PIL import Image
  6. from django.conf import settings
  7. from django.urls import reverse
  8. from django.utils import timezone
  9. from oscar.test import factories
  10. from oscar.test.testcases import WebTestCase
  11. from oscar.core.compat import get_user_model
  12. from oscar.core.loading import get_model
  13. from oscar.apps.catalogue.models import Product, ProductAttribute
  14. from oscar.test.factories import (
  15. CategoryFactory, ProductFactory, ProductAttributeFactory,
  16. ProductClassFactory)
  17. from six import BytesIO
  18. from webtest import Upload
  19. User = get_user_model()
  20. ProductImage = get_model('catalogue', 'ProductImage')
  21. class ProductWebTest(WebTestCase):
  22. is_staff = True
  23. def setUp(self):
  24. self.user = User.objects.create_user(username='testuser',
  25. email='test@email.com',
  26. password='somefancypassword')
  27. self.user.is_staff = self.is_staff
  28. self.user.save()
  29. def get(self, url, **kwargs):
  30. kwargs['user'] = self.user
  31. return self.app.get(url, **kwargs)
  32. class TestGatewayPage(ProductWebTest):
  33. is_staff = True
  34. def test_redirects_to_list_page_when_no_query_param(self):
  35. url = reverse('dashboard:catalogue-product-create')
  36. response = self.get(url)
  37. self.assertRedirects(response,
  38. reverse('dashboard:catalogue-product-list'))
  39. def test_redirects_to_list_page_when_invalid_query_param(self):
  40. url = reverse('dashboard:catalogue-product-create')
  41. response = self.get(url + '?product_class=bad')
  42. self.assertRedirects(response,
  43. reverse('dashboard:catalogue-product-list'))
  44. def test_redirects_to_form_page_when_valid_query_param(self):
  45. pclass = ProductClassFactory(name='Books', slug='books')
  46. url = reverse('dashboard:catalogue-product-create')
  47. response = self.get(url + '?product_class=%s' % pclass.pk)
  48. expected_url = reverse('dashboard:catalogue-product-create',
  49. kwargs={'product_class_slug': pclass.slug})
  50. self.assertRedirects(response, expected_url)
  51. class TestCreateParentProduct(ProductWebTest):
  52. is_staff = True
  53. def setUp(self):
  54. self.pclass = ProductClassFactory(name='Books', slug='books')
  55. super().setUp()
  56. def submit(self, title=None, category=None, upc=None):
  57. url = reverse('dashboard:catalogue-product-create',
  58. kwargs={'product_class_slug': self.pclass.slug})
  59. product_form = self.get(url).form
  60. product_form['title'] = title
  61. product_form['upc'] = upc
  62. product_form['structure'] = 'parent'
  63. if category:
  64. product_form['productcategory_set-0-category'] = category.id
  65. return product_form.submit()
  66. def test_title_is_required(self):
  67. response = self.submit(title='')
  68. self.assertContains(response, "must have a title")
  69. self.assertEqual(Product.objects.count(), 0)
  70. def test_requires_a_category(self):
  71. response = self.submit(title="Nice T-Shirt")
  72. self.assertContains(response, "must have at least one category")
  73. self.assertEqual(Product.objects.count(), 0)
  74. def test_for_smoke(self):
  75. category = CategoryFactory()
  76. response = self.submit(title='testing', category=category)
  77. self.assertIsRedirect(response)
  78. self.assertEqual(Product.objects.count(), 1)
  79. def test_doesnt_allow_duplicate_upc(self):
  80. ProductFactory(parent=None, upc="12345")
  81. category = CategoryFactory()
  82. self.assertTrue(Product.objects.get(upc="12345"))
  83. response = self.submit(title="Nice T-Shirt", category=category,
  84. upc="12345")
  85. self.assertEqual(Product.objects.count(), 1)
  86. self.assertNotEqual(Product.objects.get(upc='12345').title,
  87. 'Nice T-Shirt')
  88. self.assertContains(response,
  89. "Product with this UPC already exists.")
  90. class TestCreateChildProduct(ProductWebTest):
  91. is_staff = True
  92. def setUp(self):
  93. self.pclass = ProductClassFactory(name='Books', slug='books')
  94. self.parent = ProductFactory(structure='parent', stockrecords=[])
  95. super().setUp()
  96. def test_categories_are_not_required(self):
  97. url = reverse('dashboard:catalogue-product-create-child',
  98. kwargs={'parent_pk': self.parent.pk})
  99. page = self.get(url)
  100. product_form = page.form
  101. product_form['title'] = expected_title = 'Nice T-Shirt'
  102. product_form.submit()
  103. try:
  104. product = Product.objects.get(title=expected_title)
  105. except Product.DoesNotExist:
  106. self.fail('creating a child product did not work')
  107. self.assertEqual(product.parent, self.parent)
  108. class TestProductUpdate(ProductWebTest):
  109. def test_product_update_form(self):
  110. self.product = factories.ProductFactory()
  111. url = reverse('dashboard:catalogue-product',
  112. kwargs={'pk': self.product.id})
  113. page = self.get(url)
  114. product_form = page.form
  115. product_form['title'] = expected_title = 'Nice T-Shirt'
  116. page = product_form.submit()
  117. product = Product.objects.get(id=self.product.id)
  118. self.assertEqual(page.context['product'], self.product)
  119. self.assertEqual(product.title, expected_title)
  120. class TestProductClass(ProductWebTest):
  121. def setUp(self):
  122. super().setUp()
  123. self.pclass = ProductClassFactory(name='T-Shirts', slug='tshirts')
  124. for attribute_type, __ in ProductAttribute.TYPE_CHOICES:
  125. values = {
  126. 'type': attribute_type, 'code': attribute_type,
  127. 'product_class': self.pclass, 'name': attribute_type,
  128. }
  129. if attribute_type == ProductAttribute.OPTION:
  130. option_group = factories.AttributeOptionGroupFactory()
  131. self.option = factories.AttributeOptionFactory(group=option_group)
  132. values['option_group'] = option_group
  133. elif attribute_type == ProductAttribute.MULTI_OPTION:
  134. option_group = factories.AttributeOptionGroupFactory()
  135. self.multi_option = factories.AttributeOptionFactory(group=option_group)
  136. values['option_group'] = option_group
  137. ProductAttributeFactory(**values)
  138. self.product = factories.ProductFactory(product_class=self.pclass)
  139. self.url = reverse('dashboard:catalogue-product',
  140. kwargs={'pk': self.product.id})
  141. self.image_folder = datetime.datetime.now().strftime(settings.OSCAR_IMAGE_FOLDER)
  142. def tearDown(self):
  143. root_image_folder = self.image_folder.split(os.sep)[0]
  144. shutil.rmtree(posixpath.join(settings.MEDIA_ROOT, root_image_folder), ignore_errors=True)
  145. def generate_test_image(self, name):
  146. tempfile = BytesIO()
  147. image = Image.new("RGBA", size=(50, 50), color=(256, 0, 0))
  148. image.save(tempfile, "PNG")
  149. tempfile.seek(0)
  150. return tempfile.read()
  151. def test_product_update_attribute_values(self):
  152. page = self.get(self.url)
  153. product_form = page.form
  154. # Send string field values due to an error
  155. # in the Webtest during multipart form encode.
  156. product_form['attr_text'] = 'test1'
  157. product_form['attr_integer'] = '1'
  158. product_form['attr_float'] = '1.2'
  159. product_form['attr_boolean'] = 'yes'
  160. product_form['attr_richtext'] = 'longread'
  161. product_form['attr_date'] = '2016-10-12'
  162. product_form['attr_file'] = Upload('file1.txt', b"test", 'text/plain')
  163. product_form['attr_image'] = Upload('image1.png', self.generate_test_image('image1.png'), 'image/png')
  164. product_form.submit()
  165. # Reloading model instance to re-initiate ProductAttributeContainer
  166. # with new attributes.
  167. self.product = Product.objects.get(pk=self.product.id)
  168. self.assertEqual(self.product.attr.text, 'test1')
  169. self.assertEqual(self.product.attr.integer, 1)
  170. self.assertEqual(self.product.attr.float, 1.2)
  171. self.assertTrue(self.product.attr.boolean)
  172. self.assertEqual(self.product.attr.richtext, 'longread')
  173. self.assertEqual(self.product.attr.date, datetime.date(2016, 10, 12))
  174. self.assertEqual(self.product.attr.file.name, posixpath.join(self.image_folder, 'file1.txt'))
  175. self.assertEqual(self.product.attr.image.name, posixpath.join(self.image_folder, 'image1.png'))
  176. page = self.get(self.url)
  177. product_form = page.form
  178. product_form['attr_text'] = 'test2'
  179. product_form['attr_integer'] = '2'
  180. product_form['attr_float'] = '5.2'
  181. product_form['attr_boolean'] = ''
  182. product_form['attr_richtext'] = 'article'
  183. product_form['attr_date'] = '2016-10-10'
  184. product_form['attr_file'] = Upload('file2.txt', b"test", 'text/plain')
  185. product_form['attr_image'] = Upload('image2.png', self.generate_test_image('image2.png'), 'image/png')
  186. product_form.submit()
  187. self.product = Product.objects.get(pk=self.product.id)
  188. self.assertEqual(self.product.attr.text, 'test2')
  189. self.assertEqual(self.product.attr.integer, 2)
  190. self.assertEqual(self.product.attr.float, 5.2)
  191. self.assertFalse(self.product.attr.boolean)
  192. self.assertEqual(self.product.attr.richtext, 'article')
  193. self.assertEqual(self.product.attr.date, datetime.date(2016, 10, 10))
  194. self.assertEqual(self.product.attr.file.name, posixpath.join(self.image_folder, 'file2.txt'))
  195. self.assertEqual(self.product.attr.image.name, posixpath.join(self.image_folder, 'image2.png'))
  196. class TestProductImages(ProductWebTest):
  197. def setUp(self):
  198. super().setUp()
  199. self.product = factories.ProductFactory()
  200. self.url = reverse('dashboard:catalogue-product',
  201. kwargs={'pk': self.product.id})
  202. self.image_folder = timezone.now().strftime(settings.OSCAR_IMAGE_FOLDER)
  203. def tearDown(self):
  204. root_image_folder = self.image_folder.split(os.sep)[0]
  205. shutil.rmtree(root_image_folder, ignore_errors=True)
  206. def generate_test_image(self, name):
  207. tempfile = BytesIO()
  208. image = Image.new("RGBA", size=(50, 50), color=(256, 0, 0))
  209. image.save(tempfile, "PNG")
  210. tempfile.seek(0)
  211. return tempfile.read()
  212. def test_product_images_upload(self):
  213. page = self.get(self.url)
  214. product_form = page.form
  215. product_form['images-0-original'] = Upload('image1.png', self.generate_test_image('image1.png'), 'image/png')
  216. product_form['images-1-original'] = Upload('image2.png', self.generate_test_image('image2.png'), 'image/png')
  217. product_form.submit(name='action', value='continue').follow()
  218. self.product = Product.objects.get(pk=self.product.id)
  219. self.assertEqual(self.product.images.count(), 2)
  220. page = self.get(self.url)
  221. product_form = page.form
  222. product_form['images-2-original'] = Upload('image3.png', self.generate_test_image('image3.png'), 'image/png')
  223. product_form.submit()
  224. self.product = Product.objects.get(pk=self.product.id)
  225. self.assertEqual(self.product.images.count(), 3)
  226. images = self.product.images.all()
  227. self.assertEqual(images[0].original.name, os.path.join(self.image_folder, 'image1.png'))
  228. self.assertEqual(images[0].display_order, 0)
  229. self.assertEqual(images[1].original.name, os.path.join(self.image_folder, 'image2.png'))
  230. self.assertEqual(images[1].display_order, 1)
  231. self.assertEqual(images[2].original.name, os.path.join(self.image_folder, 'image3.png'))
  232. self.assertEqual(images[2].display_order, 2)
  233. def test_product_images_reordering(self):
  234. self.images = factories.ProductImageFactory.create_batch(3, product=self.product)
  235. image_ids = list(self.product.images.values_list('id', flat=True))
  236. self.assertEqual(image_ids, [3, 2, 1])
  237. page = self.get(self.url)
  238. product_form = page.form
  239. product_form['images-0-display_order'] = '5'
  240. product_form['images-1-display_order'] = '3'
  241. product_form['images-2-display_order'] = '4'
  242. product_form.submit()
  243. self.product = Product.objects.get(pk=self.product.id)
  244. display_orders = list(self.product.images.values_list('display_order', flat=True))
  245. image_ids = list(self.product.images.values_list('id', flat=True))
  246. self.assertEqual(display_orders, [0, 1, 2])
  247. self.assertEqual(image_ids, [2, 1, 3])