mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
c1ab004c0c
@ -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)
|
||||
|
77
InvenTree/order/test_views.py
Normal file
77
InvenTree/order/test_views.py
Normal file
@ -0,0 +1,77 @@
|
||||
""" 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))
|
@ -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
|
||||
|
@ -58,4 +58,4 @@
|
||||
name: 'Bob'
|
||||
description: 'Can we build it?'
|
||||
assembly: true
|
||||
|
||||
purchaseable: false
|
218
InvenTree/part/test_views.py
Normal file
218
InvenTree/part/test_views.py
Normal file
@ -0,0 +1,218 @@
|
||||
""" 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
|
||||
|
||||
from .models import Part
|
||||
|
||||
|
||||
class PartViewTestCase(TestCase):
|
||||
|
||||
fixtures = [
|
||||
'category',
|
||||
'part',
|
||||
'bom',
|
||||
'location',
|
||||
'company',
|
||||
'supplier_part',
|
||||
]
|
||||
|
||||
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 PartListTest(PartViewTestCase):
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
|
||||
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'])
|
||||
|
||||
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 PartTests(PartViewTestCase):
|
||||
""" Tests for Part forms """
|
||||
|
||||
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)
|
||||
|
||||
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_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)
|
||||
|
||||
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):
|
||||
""" 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):
|
||||
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 """
|
||||
|
||||
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('<img src=', data)
|
||||
|
||||
def test_invalid_part(self):
|
||||
response = self.client.get(reverse('part-qr', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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)
|
@ -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
|
||||
|
130
InvenTree/stock/test_views.py
Normal file
130
InvenTree/stock/test_views.py
Normal file
@ -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)
|
@ -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:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user