From f26243af97dd28c8d59918f6fb1f008c7217184b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 22:19:17 +1000 Subject: [PATCH 01/18] Tests for Part index / --- InvenTree/part/test_views.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 InvenTree/part/test_views.py diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py new file mode 100644 index 0000000000..5680dfdebe --- /dev/null +++ b/InvenTree/part/test_views.py @@ -0,0 +1,32 @@ +""" Unit tests for Part Views (see views.py) """ + +from django.test import TestCase +from django.urls import reverse +from django.contrib.auth import get_user_model + +class PartViewTestCase(TestCase): + + fixtures = [ + 'category', + 'part', + 'location', + ] + + def setUp(self): + super().setUp() + + # Create a user + User = get_user_model() + User.objects.create_user('username', 'user@email.com', 'password') + + self.client.login(username='username', password='password') + + def test_part_index(self): + response = self.client.get(reverse('part-index')) + self.assertEqual(response.status_code, 200) + + keys = response.context.keys() + self.assertIn('csrf_token', keys) + self.assertIn('parts', keys) + self.assertIn('user', keys) + From a70484caff4b0f04de64fe09c6ff2c99a89910cd Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 22:45:02 +1000 Subject: [PATCH 02/18] Test PartDetail view --- InvenTree/part/test_views.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 5680dfdebe..ae268e873a 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -4,6 +4,8 @@ from django.test import TestCase from django.urls import reverse from django.contrib.auth import get_user_model +from .models import Part + class PartViewTestCase(TestCase): fixtures = [ @@ -21,6 +23,9 @@ class PartViewTestCase(TestCase): self.client.login(username='username', password='password') + +class PartListTest(PartViewTestCase): + def test_part_index(self): response = self.client.get(reverse('part-index')) self.assertEqual(response.status_code, 200) @@ -30,3 +35,34 @@ class PartViewTestCase(TestCase): self.assertIn('parts', keys) self.assertIn('user', keys) + +class PartDetailTest(PartViewTestCase): + + def test_part_detail(self): + """ Test that we can retrieve a part detail page """ + + pk = 1 + + response = self.client.get(reverse('part-detail', args=(pk,))) + self.assertEqual(response.status_code, 200) + + part = Part.objects.get(pk=pk) + + keys = response.context.keys() + + self.assertIn('part', keys) + self.assertIn('category', keys) + + self.assertEqual(response.context['part'].pk, pk) + self.assertEqual(response.context['category'], part.category) + + self.assertFalse(response.context['editing_enabled']) + + def test_editable(self): + + pk = 1 + response = self.client.get(reverse('part-detail', args=(pk,)), {'edit': True}) + + self.assertEqual(response.status_code, 200) + self.assertTrue(response.context['editing_enabled']) + From 7db97f22262258799606421fd7bea42a19750f5e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 22:45:10 +1000 Subject: [PATCH 03/18] Test Part QR Code view --- InvenTree/part/test_views.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index ae268e873a..acf24eb515 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -66,3 +66,27 @@ class PartDetailTest(PartViewTestCase): self.assertEqual(response.status_code, 200) self.assertTrue(response.context['editing_enabled']) + +class PartQRTest(PartViewTestCase): + """ Tests for the Part QR Code AJAX view """ + + def test_html_redirect(self): + # A HTML request for a QR code should be redirected (use an AJAX request instead) + response = self.client.get(reverse('part-qr', args=(1,))) + self.assertEqual(response.status_code, 302) + + def test_valid_part(self): + response = self.client.get(reverse('part-qr', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + data = str(response.content) + + self.assertIn('Part QR Code', data) + self.assertIn(' Date: Thu, 8 Aug 2019 22:50:17 +1000 Subject: [PATCH 04/18] Test for Part Editing form --- InvenTree/part/test_views.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index acf24eb515..2c2ec4cf59 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -67,6 +67,27 @@ class PartDetailTest(PartViewTestCase): self.assertTrue(response.context['editing_enabled']) +class PartEditTest(PartViewTestCase): + """ Tests for Part editing form """ + + def test_get_edit(self): + response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + keys = response.context.keys() + data = str(response.content) + + self.assertIn('part', keys) + self.assertIn('csrf_token', keys) + + self.assertIn('html_form', data) + self.assertIn('"title":', data) + + def test_invalid_part(self): + response = self.client.get(reverse('part-edit', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 404) + + class PartQRTest(PartViewTestCase): """ Tests for the Part QR Code AJAX view """ From afcd41135856421c9ab6447d5e5ab590f63bda3f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:00:01 +1000 Subject: [PATCH 05/18] (partial) tests for attachment forms --- InvenTree/part/test_views.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 2c2ec4cf59..c58959aeb3 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -83,10 +83,27 @@ class PartEditTest(PartViewTestCase): self.assertIn('html_form', data) self.assertIn('"title":', data) - def test_invalid_part(self): - response = self.client.get(reverse('part-edit', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 404) +class PartAttachmentTests(PartViewTestCase): + + def test_valid_create(self): + """ test creation of an attachment for a valid part """ + + response = self.client.get(reverse('part-attachment-create'), {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_invalid_create(self): + """ test creation of an attachment for an invalid part """ + + with self.assertRaises(Part.DoesNotExist): + response = self.client.get(reverse('part-attachment-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + + def test_edit(self): + """ test editing an attachment """ + + # TODO + pass + class PartQRTest(PartViewTestCase): """ Tests for the Part QR Code AJAX view """ From 21d2c434ff45c4dda3bdb2558be9fe0ffc65b995 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:04:58 +1000 Subject: [PATCH 06/18] Test for part export view - Needs some more work (parts need supplier parts!) --- InvenTree/part/test_views.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index c58959aeb3..98f3e0ec94 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -35,6 +35,14 @@ class PartListTest(PartViewTestCase): self.assertIn('parts', keys) self.assertIn('user', keys) + def test_export(self): + """ Export part data to CSV """ + + response = self.client.get(reverse('part-export'), {'parts': '1,2,3,4,5,6,7,8,9,10'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + + self.assertEqual(response.status_code, 200) + self.assertIn('streaming_content', dir(response)) + class PartDetailTest(PartViewTestCase): @@ -67,11 +75,13 @@ class PartDetailTest(PartViewTestCase): self.assertTrue(response.context['editing_enabled']) + + class PartEditTest(PartViewTestCase): """ Tests for Part editing form """ def test_get_edit(self): - response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) keys = response.context.keys() @@ -103,7 +113,7 @@ class PartAttachmentTests(PartViewTestCase): # TODO pass - + class PartQRTest(PartViewTestCase): """ Tests for the Part QR Code AJAX view """ From f2992480635dd6586e709753e2af40dac4dd2068 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:06:22 +1000 Subject: [PATCH 07/18] Improve testing for part export --- InvenTree/part/test_views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 98f3e0ec94..8865fe9e63 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -11,7 +11,10 @@ class PartViewTestCase(TestCase): fixtures = [ 'category', 'part', + 'bom', 'location', + 'company', + 'supplier_part', ] def setUp(self): From ab3e66d57899c6172c37a52cc7a3a6c26e884ebc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:10:07 +1000 Subject: [PATCH 08/18] Test for BOM download --- InvenTree/part/test_views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 8865fe9e63..778a3ef076 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -77,8 +77,13 @@ class PartDetailTest(PartViewTestCase): self.assertEqual(response.status_code, 200) self.assertTrue(response.context['editing_enabled']) + def test_bom_download(self): + """ Test downloading a BOM for a valid part """ - + response = self.client.get(reverse('bom-export', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + self.assertIn('streaming_content', dir(response)) + class PartEditTest(PartViewTestCase): """ Tests for Part editing form """ From d6f1fe74d14c7f49016e7118f9e4506c73c97dfa Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:16:03 +1000 Subject: [PATCH 09/18] Tests for PartCategory forms --- InvenTree/part/test_views.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 778a3ef076..acdeeb6d1c 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -146,3 +146,25 @@ class PartQRTest(PartViewTestCase): data = str(response.content) self.assertIn('Error:', data) + + +class CategoryTest(PartViewTestCase): + """ Tests for PartCategory related views """ + + def test_create(self): + """ Test view for creating a new category """ + response = self.client.get(reverse('category-create'), {'category': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + + self.assertEqual(response.status_code, 200) + + def test_create_invalid_parent(self): + """ test creation of a new category with an invalid parent """ + response = self.client.get(reverse('category-create'), {'category': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + + # Form should still return OK + self.assertEqual(response.status_code, 200) + + def test_edit(self): + """ Retrieve the part category editing form """ + response = self.client.get(reverse('category-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) From 51e4a4c00666c28ec6e51f96469affd111bb1c18 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:22:26 +1000 Subject: [PATCH 10/18] Tests for BomItem forms --- InvenTree/part/test_views.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index acdeeb6d1c..c042a6a861 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -168,3 +168,22 @@ class CategoryTest(PartViewTestCase): """ Retrieve the part category editing form """ response = self.client.get(reverse('category-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) + + +class BomItemTests(PartViewTestCase): + """ Tests for BomItem related views """ + + def test_create_valid_parent(self): + """ Create a BomItem for a valid part """ + response = self.client.get(reverse('bom-item-create'), {'parent': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_create_no_parent(self): + """ Create a BomItem without a parent """ + response = self.client.get(reverse('bom-item-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_create_invalid_parent(self): + """ Create a BomItem with an invalid parent """ + response = self.client.get(reverse('bom-item-create'), {'parent': 99999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) From 3a87cd866c68a040343941d3cb5e563b85fcd428 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:32:34 +1000 Subject: [PATCH 11/18] Tests for part creation - Need more tests for POST action --- InvenTree/part/test_views.py | 28 +++++++++++++++++++++++++--- InvenTree/part/views.py | 6 +++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index c042a6a861..9e51679e9a 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -85,10 +85,10 @@ class PartDetailTest(PartViewTestCase): self.assertIn('streaming_content', dir(response)) -class PartEditTest(PartViewTestCase): - """ Tests for Part editing form """ +class PartTests(PartViewTestCase): + """ Tests for Part forms """ - def test_get_edit(self): + def test_part_edit(self): response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) @@ -101,6 +101,28 @@ class PartEditTest(PartViewTestCase): self.assertIn('html_form', data) self.assertIn('"title":', data) + def test_part_create(self): + """ Launch form to create a new part """ + response = self.client.get(reverse('part-create'), {'category': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # And again, with an invalid category + response = self.client.get(reverse('part-create'), {'category': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # And again, with no category + response = self.client.get(reverse('part-create'), {'name': 'Test part'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_part_duplicate(self): + """ Launch form to duplicate part """ + + # First try with an invalid part + response = self.client.get(reverse('part-duplicate', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + response = self.client.get(reverse('part-duplicate', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) class PartAttachmentTests(PartViewTestCase): diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 74adc490b8..b7bed73003 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -295,7 +295,7 @@ class PartDuplicate(AjaxCreateView): def get_part_to_copy(self): try: return Part.objects.get(id=self.kwargs['pk']) - except Part.DoesNotExist: + except (Part.DoesNotExist, ValueError): return None def get_context_data(self): @@ -419,7 +419,7 @@ class PartCreate(AjaxCreateView): if cat_id: try: context['category'] = PartCategory.objects.get(pk=cat_id) - except PartCategory.DoesNotExist: + except (PartCategory.DoesNotExist, ValueError): pass return context @@ -494,7 +494,7 @@ class PartCreate(AjaxCreateView): category = PartCategory.objects.get(pk=self.get_category_id()) initials['category'] = category initials['keywords'] = category.default_keywords - except PartCategory.DoesNotExist: + except (PartCategory.DoesNotExist, ValueError): pass # Allow initial data to be passed through as arguments From b872a121316657995186bb0a06f10d429d430690 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:34:32 +1000 Subject: [PATCH 12/18] Test for making part variant --- InvenTree/part/test_views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 9e51679e9a..212df848f3 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -124,6 +124,12 @@ class PartTests(PartViewTestCase): response = self.client.get(reverse('part-duplicate', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) + def test_make_variant(self): + + response = self.client.get(reverse('make-part-variant', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + class PartAttachmentTests(PartViewTestCase): def test_valid_create(self): From 45d5667ccc786b0f2f2c9c7653a485546be7e060 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:36:32 +1000 Subject: [PATCH 13/18] PEP fixes --- InvenTree/part/test_views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index 212df848f3..c1dc38862c 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -6,6 +6,7 @@ from django.contrib.auth import get_user_model from .models import Part + class PartViewTestCase(TestCase): fixtures = [ @@ -142,7 +143,7 @@ class PartAttachmentTests(PartViewTestCase): """ test creation of an attachment for an invalid part """ with self.assertRaises(Part.DoesNotExist): - response = self.client.get(reverse('part-attachment-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.client.get(reverse('part-attachment-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') def test_edit(self): """ test editing an attachment """ From b924265c9abc9b626d3f3d1ac9ae69b8ed3c5731 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:49:35 +1000 Subject: [PATCH 14/18] Some tests for views in order app --- InvenTree/order/test_views.py | 78 +++++++++++++++++++++++++++++++++++ InvenTree/order/views.py | 2 +- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 InvenTree/order/test_views.py diff --git a/InvenTree/order/test_views.py b/InvenTree/order/test_views.py new file mode 100644 index 0000000000..1ddf6b4296 --- /dev/null +++ b/InvenTree/order/test_views.py @@ -0,0 +1,78 @@ +""" Unit tests for Order views (see views.py) """ + +from django.test import TestCase +from django.urls import reverse +from django.contrib.auth import get_user_model + + +class OrderViewTestCase(TestCase): + + fixtures = [ + 'category', + 'part', + 'bom', + 'location', + 'company', + 'supplier_part', + 'stock', + 'order', + ] + + def setUp(self): + super().setUp() + + # Create a user + User = get_user_model() + User.objects.create_user('username', 'user@email.com', 'password') + + self.client.login(username='username', password='password') + + +class OrderListTest(OrderViewTestCase): + + def test_order_list(self): + response = self.client.get(reverse('purchase-order-index')) + + self.assertEqual(response.status_code, 200) + + +class POTests(OrderViewTestCase): + """ Tests for PurchaseOrder views """ + + def test_detail_view(self): + """ Retrieve PO detail view """ + response = self.client.get(reverse('purchase-order-detail', args=(1,))) + self.assertEqual(response.status_code, 200) + keys = response.context.keys() + self.assertIn('OrderStatus', keys) + + def test_po_create(self): + """ Launch forms to create new PurchaseOrder""" + url = reverse('purchase-order-create') + + # Without a supplier ID + response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # With a valid supplier ID + response = self.client.get(url, {'supplier': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # With an invalid supplier ID + response = self.client.get(url, {'supplier': 'goat'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_po_edit(self): + """ Launch form to edit a PurchaseOrder """ + + response = self.client.get(reverse('purchase-order-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_po_export(self): + """ Export PurchaseOrder """ + + response = self.client.get(reverse('purchase-order-export', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + + # Response should be streaming-content (file download) + self.assertIn('streaming_content', dir(response)) + \ No newline at end of file diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index ae27a0bcc4..5b7aca5cdc 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -84,7 +84,7 @@ class PurchaseOrderCreate(AjaxCreateView): try: supplier = Company.objects.get(id=supplier_id) initials['supplier'] = supplier - except Company.DoesNotExist: + except (Company.DoesNotExist, ValueError): pass return initials From e849f62a6a8674c310bdab9320317f79d6cc2afe Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 8 Aug 2019 23:50:11 +1000 Subject: [PATCH 15/18] PEP --- InvenTree/order/test_views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/InvenTree/order/test_views.py b/InvenTree/order/test_views.py index 1ddf6b4296..a197455a8a 100644 --- a/InvenTree/order/test_views.py +++ b/InvenTree/order/test_views.py @@ -47,7 +47,7 @@ class POTests(OrderViewTestCase): self.assertIn('OrderStatus', keys) def test_po_create(self): - """ Launch forms to create new PurchaseOrder""" + """ Launch forms to create new PurchaseOrder""" url = reverse('purchase-order-create') # Without a supplier ID @@ -75,4 +75,3 @@ class POTests(OrderViewTestCase): # Response should be streaming-content (file download) self.assertIn('streaming_content', dir(response)) - \ No newline at end of file From bd61c89094880f940b602e5a077cb22ea50c6deb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 9 Aug 2019 20:13:23 +1000 Subject: [PATCH 16/18] Tests for stock app views --- InvenTree/part/fixtures/part.yaml | 2 +- InvenTree/stock/test_views.py | 130 ++++++++++++++++++++++++++++++ InvenTree/stock/views.py | 4 +- 3 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 InvenTree/stock/test_views.py diff --git a/InvenTree/part/fixtures/part.yaml b/InvenTree/part/fixtures/part.yaml index 7d669cf49d..3f7fbb9886 100644 --- a/InvenTree/part/fixtures/part.yaml +++ b/InvenTree/part/fixtures/part.yaml @@ -58,4 +58,4 @@ name: 'Bob' description: 'Can we build it?' assembly: true - \ No newline at end of file + purchaseable: false \ No newline at end of file diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py new file mode 100644 index 0000000000..c640859ca2 --- /dev/null +++ b/InvenTree/stock/test_views.py @@ -0,0 +1,130 @@ +""" Unit tests for Stock views (see views.py) """ + +from django.test import TestCase +from django.urls import reverse +from django.contrib.auth import get_user_model + + +class StockViewTestCase(TestCase): + + fixtures = [ + 'category', + 'part', + 'company', + 'location', + 'supplier_part', + 'stock', + ] + + def setUp(self): + super().setUp() + + # Create a user + User = get_user_model() + User.objects.create_user('username', 'user@email.com', 'password') + + self.client.login(username='username', password='password') + + +class StockListTest(StockViewTestCase): + """ Tests for Stock list views """ + + def test_stock_index(self): + response = self.client.get(reverse('stock-index')) + self.assertEqual(response.status_code, 200) + + +class StockLocationTest(StockViewTestCase): + """ Tests for StockLocation views """ + + def test_location_edit(self): + response = self.client.get(reverse('stock-location-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_qr_code(self): + # Request the StockLocation QR view + response = self.client.get(reverse('stock-location-qr', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Test for an invalid StockLocation + response = self.client.get(reverse('stock-location-qr', args=(999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_create(self): + # Test StockLocation creation view + response = self.client.get(reverse('stock-location-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Create with a parent + response = self.client.get(reverse('stock-location-create'), {'location': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Create with an invalid parent + response = self.client.get(reverse('stock-location-create'), {'location': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + +class StockItemTest(StockViewTestCase): + """" Tests for StockItem views """ + + def test_qr_code(self): + # QR code for a valid item + response = self.client.get(reverse('stock-item-qr', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # QR code for an invalid item + response = self.client.get(reverse('stock-item-qr', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + data = str(response.content) + self.assertIn('Error:', data) + + def test_adjust_items(self): + url = reverse('stock-adjust') + + # Move items + response = self.client.get(url, {'stock[]': [1,2,3,4,5], 'action': 'move'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Count part + response = self.client.get(url, {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Remove items + response = self.client.get(url, {'location': 1, 'action': 'take'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Add items + response = self.client.get(url, {'item': 1, 'action': 'add'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Blank response + response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # TODO - Tests for POST data + + def test_edit_item(self): + # Test edit view for StockItem + response = self.client.get(reverse('stock-item-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Test with a non-purchaseable part + response = self.client.get(reverse('stock-item-edit', args=(100,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + def test_create_item(self): + # Test creation of StockItem + response = self.client.get(reverse('stock-item-create'), {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + response = self.client.get(reverse('stock-item-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Copy from a valid item, valid location + response = self.client.get(reverse('stock-item-create'), {'location': 1, 'copy': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) + + # Copy from an invalid item, invalid location + response = self.client.get(reverse('stock-item-create'), {'location': 999, 'copy': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) \ No newline at end of file diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 6fbea9d885..3d36eb91b9 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -168,9 +168,9 @@ class StockAdjust(AjaxView, FormMixin): elif 'item' in self.request.GET: items = [StockItem.objects.get(id=self.request.GET.get('item'))] - # Unsupported query + # Unsupported query (no items) else: - items = None + items = [] for item in items: From a36d99b3e7e3d64b72576697c2d8e85c2d4520a3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 9 Aug 2019 20:14:47 +1000 Subject: [PATCH 17/18] PEP fixes --- InvenTree/stock/test_views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py index c640859ca2..5a7278d7d8 100644 --- a/InvenTree/stock/test_views.py +++ b/InvenTree/stock/test_views.py @@ -83,7 +83,7 @@ class StockItemTest(StockViewTestCase): url = reverse('stock-adjust') # Move items - response = self.client.get(url, {'stock[]': [1,2,3,4,5], 'action': 'move'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + response = self.client.get(url, {'stock[]': [1, 2, 3, 4, 5], 'action': 'move'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) # Count part @@ -127,4 +127,4 @@ class StockItemTest(StockViewTestCase): # Copy from an invalid item, invalid location response = self.client.get(reverse('stock-item-create'), {'location': 999, 'copy': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) \ No newline at end of file + self.assertEqual(response.status_code, 200) From df470ca26d8f69ebf4d98ae423739e610c7d6375 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 9 Aug 2019 20:30:31 +1000 Subject: [PATCH 18/18] Tests for serial number extraction --- InvenTree/InvenTree/tests.py | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py index ccdf2e2d43..2d1b345687 100644 --- a/InvenTree/InvenTree/tests.py +++ b/InvenTree/InvenTree/tests.py @@ -1,5 +1,6 @@ from django.test import TestCase import django.core.exceptions as django_exceptions +from django.core.exceptions import ValidationError from .validators import validate_overage, validate_part_name from . import helpers @@ -100,3 +101,50 @@ class TestDownloadFile(TestCase): def test_download(self): helpers.DownloadFile("hello world", "out.txt") helpers.DownloadFile(bytes("hello world".encode("utf8")), "out.bin") + + +class TestSerialNumberExtraction(TestCase): + """ Tests for serial number extraction code """ + + def test_simple(self): + + e = helpers.ExtractSerialNumbers + + sn = e("1-5", 5) + self.assertEqual(len(sn), 5) + for i in range(1, 6): + self.assertIn(i, sn) + + sn = e("1, 2, 3, 4, 5", 5) + self.assertEqual(len(sn), 5) + + sn = e("1-5, 10-15", 11) + self.assertIn(3, sn) + self.assertIn(13, sn) + + def test_failures(self): + + e = helpers.ExtractSerialNumbers + + # Test duplicates + with self.assertRaises(ValidationError): + e("1,2,3,3,3", 5) + + # Test invalid length + with self.assertRaises(ValidationError): + e("1,2,3", 5) + + # Test empty string + with self.assertRaises(ValidationError): + e(", , ,", 0) + + # Test incorrect sign in group + with self.assertRaises(ValidationError): + e("10-2", 8) + + # Test invalid group + with self.assertRaises(ValidationError): + e("1-5-10", 10) + + with self.assertRaises(ValidationError): + e("10, a, 7-70j", 4)