您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

test_product.py 13KB

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