Seperate CUI url paths and tests (#6543)

* move CUI JS files to CUI url section

* add flag to seperate CUI code and tests

* re-enable tests

* move urls back to backend patterns

* swap switch logic

* fix merge

* returning PUI paths if CUI not enabled

* revert test changes

* fix plugin settings url

* URL is not dependant on UI generation

* small fixes

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>

---------

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
This commit is contained in:
Matthias Mair 2024-02-22 22:56:50 +00:00 committed by GitHub
parent f5e02fd292
commit 6f0b2b31a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 156 additions and 34 deletions

View File

@ -913,3 +913,10 @@ def inheritors(cls: type[Inheritors_T]) -> set[type[Inheritors_T]]:
def is_ajax(request):
"""Check if the current request is an AJAX request."""
return request.headers.get('x-requested-with') == 'XMLHttpRequest'
def pui_url(subpath: str) -> str:
"""Return the URL for a PUI subpath."""
if not subpath.startswith('/'):
subpath = '/' + subpath
return f'/{settings.FRONTEND_URL_BASE}{subpath}'

View File

@ -80,6 +80,9 @@ DEBUG = get_boolean_setting('INVENTREE_DEBUG', 'debug', True)
ENABLE_CLASSIC_FRONTEND = get_boolean_setting(
'INVENTREE_CLASSIC_FRONTEND', 'classic_frontend', True
)
# Disable CUI parts if CUI tests are disabled
if TESTING and '--exclude-tag=cui' in sys.argv:
ENABLE_CLASSIC_FRONTEND = False
ENABLE_PLATFORM_FRONTEND = get_boolean_setting(
'INVENTREE_PLATFORM_FRONTEND', 'platform_frontend', True
)

View File

@ -2,6 +2,7 @@
from django.conf import settings
from django.http import Http404
from django.test import tag
from django.urls import reverse
from error_report.models import Error
@ -10,6 +11,8 @@ from InvenTree.exceptions import log_error
from InvenTree.unit_test import InvenTreeTestCase
# TODO change test to not rely on CUI
@tag('cui')
class MiddlewareTests(InvenTreeTestCase):
"""Test for middleware functions."""

View File

@ -4,10 +4,11 @@ import os
import re
from pathlib import Path
from django.test import TestCase
from django.test import TestCase, tag
from django.urls import reverse
@tag('cui')
class URLTest(TestCase):
"""Test all files for broken url tags."""

View File

@ -3,6 +3,7 @@
import os
from django.contrib.auth import get_user_model
from django.test import tag
from django.urls import reverse
from InvenTree.unit_test import InvenTreeTestCase
@ -35,6 +36,7 @@ class ViewTests(InvenTreeTestCase):
return str(response.content.decode())
@tag('cui')
def test_panels(self):
"""Test that the required 'panels' are present."""
content = self.get_index_page()
@ -43,6 +45,7 @@ class ViewTests(InvenTreeTestCase):
# TODO: In future, run the javascript and ensure that the panels get created!
@tag('cui')
def test_settings_page(self):
"""Test that the 'settings' page loads correctly."""
# Settings page loads
@ -101,6 +104,8 @@ class ViewTests(InvenTreeTestCase):
self.assertNotIn(f'select-{panel}', content)
self.assertNotIn(f'panel-{panel}', content)
# TODO: Replace this with a PUI test
@tag('cui')
def test_url_login(self):
"""Test logging in via arguments."""
# Log out

View File

@ -12,7 +12,7 @@ from django.conf import settings
from django.contrib.auth import get_user_model
from django.core import mail
from django.core.exceptions import ValidationError
from django.test import TestCase, override_settings
from django.test import TestCase, override_settings, tag
from django.urls import reverse
import pint.errors
@ -1319,6 +1319,8 @@ class MagicLoginTest(InvenTreeTestCase):
self.assertEqual(resp.wsgi_request.user, self.user)
# TODO - refactor to not use CUI
@tag('cui')
class MaintenanceModeTest(InvenTreeTestCase):
"""Unit tests for maintenance mode."""

View File

@ -362,15 +362,19 @@ translated_javascript_urls = [
]
backendpatterns = [
# "Dynamic" javascript files which are rendered using InvenTree templating.
path('js/dynamic/', include(dynamic_javascript_urls)),
path('js/i18n/', include(translated_javascript_urls)),
path('auth/', include('rest_framework.urls', namespace='rest_framework')),
path('auth/', auth_request),
path('api/', include(apipatterns)),
path('api-doc/', SpectacularRedocView.as_view(url_name='schema'), name='api-doc'),
]
if settings.ENABLE_CLASSIC_FRONTEND:
# "Dynamic" javascript files which are rendered using InvenTree templating.
backendpatterns += [
re_path(r'^js/dynamic/', include(dynamic_javascript_urls)),
re_path(r'^js/i18n/', include(translated_javascript_urls)),
]
classic_frontendpatterns = [
# Apps
path('build/', include(build_urls)),
@ -436,6 +440,15 @@ if settings.ENABLE_CLASSIC_FRONTEND:
frontendpatterns += classic_frontendpatterns
if settings.ENABLE_PLATFORM_FRONTEND:
frontendpatterns += platform_urls
if not settings.ENABLE_CLASSIC_FRONTEND:
# Add a redirect for login views
frontendpatterns += [
path(
'accounts/login/',
RedirectView.as_view(url=settings.FRONTEND_URL_BASE, permanent=False),
name='account_login',
)
]
urlpatterns += frontendpatterns
@ -461,5 +474,14 @@ urlpatterns.append(
# Send any unknown URLs to the parts page
urlpatterns += [
re_path(r'^.*$', RedirectView.as_view(url='/index/', permanent=False), name='index')
re_path(
r'^.*$',
RedirectView.as_view(
url='/index/'
if settings.ENABLE_CLASSIC_FRONTEND
else settings.FRONTEND_URL_BASE,
permanent=False,
),
name='index',
)
]

View File

@ -4,6 +4,7 @@ import decimal
import logging
import os
from datetime import datetime
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
@ -161,7 +162,9 @@ class Build(InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models.InvenTreeNo
def get_absolute_url(self):
"""Return the web URL associated with this BuildOrder"""
return reverse('build-detail', kwargs={'pk': self.id})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('build-detail', kwargs={'pk': self.id})
return InvenTree.helpers.pui_url(f'/build/{self.id}')
reference = models.CharField(
unique=True,

View File

@ -1,5 +1,7 @@
"""Basic unit tests for the BuildOrder app"""
from django.conf import settings
from django.test import tag
from django.urls import reverse
from datetime import datetime, timedelta
@ -40,7 +42,8 @@ class BuildTestSimple(InvenTreeTestCase):
def test_url(self):
"""Test URL lookup"""
b1 = Build.objects.get(pk=1)
self.assertEqual(b1.get_absolute_url(), '/build/1/')
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertEqual(b1.get_absolute_url(), '/build/1/')
def test_is_complete(self):
"""Test build completion status"""
@ -116,11 +119,13 @@ class TestBuildViews(InvenTreeTestCase):
is_building=True,
)
@tag('cui')
def test_build_index(self):
"""Test build index view."""
response = self.client.get(reverse('build-index'))
self.assertEqual(response.status_code, 200)
@tag('cui')
def test_build_detail(self):
"""Test the detail view for a Build object."""
pk = 1

View File

@ -5,6 +5,7 @@ from datetime import datetime
from decimal import Decimal
from django.apps import apps
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
from django.db import models
@ -216,7 +217,9 @@ class Company(
def get_absolute_url(self):
"""Get the web URL for the detail view for this Company."""
return reverse('company-detail', kwargs={'pk': self.id})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('company-detail', kwargs={'pk': self.id})
return InvenTree.helpers.pui_url(f'/company/{self.id}')
def get_image_url(self):
"""Return the URL of the image for this company."""
@ -683,7 +686,9 @@ class SupplierPart(
def get_absolute_url(self):
"""Return the web URL of the detail view for this SupplierPart."""
return reverse('supplier-part-detail', kwargs={'pk': self.id})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('supplier-part-detail', kwargs={'pk': self.id})
return InvenTree.helpers.pui_url(f'/purchasing/supplier-part/{self.id}')
def api_instance_filters(self):
"""Return custom API filters for this particular instance."""

View File

@ -1,10 +1,12 @@
"""Unit tests for Company views (see views.py)."""
from django.test import tag
from django.urls import reverse
from InvenTree.unit_test import InvenTreeTestCase
@tag('cui')
class CompanyViewTest(InvenTreeTestCase):
"""Tests for various 'Company' views."""

View File

@ -3,6 +3,7 @@
import os
from decimal import Decimal
from django.conf import settings
from django.core.exceptions import ValidationError
from django.test import TestCase
@ -59,7 +60,8 @@ class CompanySimpleTest(TestCase):
def test_company_url(self):
"""Test the detail URL for a company."""
c = Company.objects.get(pk=1)
self.assertEqual(c.get_absolute_url(), '/company/1/')
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertEqual(c.get_absolute_url(), '/company/1/')
def test_image_renamer(self):
"""Test the company image upload functionality."""

View File

@ -142,7 +142,8 @@ class LabelTest(InvenTreeAPITestCase):
# Test that each element has been rendered correctly
self.assertIn(f'part: {part_pk} - {part_name}', content)
self.assertIn(f'data: {{"part": {part_pk}}}', content)
self.assertIn(f'http://testserver/part/{part_pk}/', content)
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertIn(f'http://testserver/part/{part_pk}/', content)
# Check that a encoded image has been generated
self.assertIn('data:image/png;charset=utf-8;base64,', content)

View File

@ -6,6 +6,7 @@ import sys
from datetime import datetime
from decimal import Decimal
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
@ -41,7 +42,7 @@ from InvenTree.fields import (
InvenTreeURLField,
RoundingDecimalField,
)
from InvenTree.helpers import decimal2string
from InvenTree.helpers import decimal2string, pui_url
from InvenTree.helpers_model import getSetting, notify_responsible
from InvenTree.status_codes import (
PurchaseOrderStatus,
@ -348,7 +349,9 @@ class PurchaseOrder(TotalPriceMixin, Order):
def get_absolute_url(self):
"""Get the 'web' URL for this order."""
return reverse('po-detail', kwargs={'pk': self.pk})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('po-detail', kwargs={'pk': self.pk})
return pui_url(f'/purchasing/purchase-order/{self.pk}')
@staticmethod
def get_api_url():
@ -804,7 +807,9 @@ class SalesOrder(TotalPriceMixin, Order):
def get_absolute_url(self):
"""Get the 'web' URL for this order."""
return reverse('so-detail', kwargs={'pk': self.pk})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('so-detail', kwargs={'pk': self.pk})
return pui_url(f'/sales/sales-order/{self.pk}')
@staticmethod
def get_api_url():
@ -1940,7 +1945,9 @@ class ReturnOrder(TotalPriceMixin, Order):
def get_absolute_url(self):
"""Get the 'web' URL for this order."""
return reverse('return-order-detail', kwargs={'pk': self.pk})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('return-order-detail', kwargs={'pk': self.pk})
return pui_url(f'/sales/return-order/{self.pk}')
@staticmethod
def get_api_url():

View File

@ -1,5 +1,6 @@
"""Unit tests for Order views (see views.py)."""
from django.test import tag
from django.urls import reverse
from InvenTree.unit_test import InvenTreeTestCase
@ -34,6 +35,7 @@ class OrderViewTestCase(InvenTreeTestCase):
]
@tag('cui')
class PurchaseOrderListTest(OrderViewTestCase):
"""Unit tests for the PurchaseOrder index page."""
@ -44,6 +46,7 @@ class PurchaseOrderListTest(OrderViewTestCase):
self.assertEqual(response.status_code, 200)
@tag('cui')
class PurchaseOrderTests(OrderViewTestCase):
"""Tests for PurchaseOrder views."""
@ -65,6 +68,7 @@ class PurchaseOrderTests(OrderViewTestCase):
self.assertIn('streaming_content', dir(response))
@tag('cui')
class SalesOrderViews(OrderViewTestCase):
"""Unit tests for the SalesOrder pages."""
@ -79,6 +83,7 @@ class SalesOrderViews(OrderViewTestCase):
self.assertEqual(response.status_code, 200)
@tag('cui')
class ReturnOrderVIews(OrderViewTestCase):
"""Unit tests for the ReturnOrder pages."""

View File

@ -4,6 +4,7 @@ from datetime import datetime, timedelta
from decimal import Decimal
import django.core.exceptions as django_exceptions
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import TestCase
@ -41,7 +42,10 @@ class OrderTest(TestCase):
for pk in range(1, 8):
order = PurchaseOrder.objects.get(pk=pk)
self.assertEqual(order.get_absolute_url(), f'/order/purchase-order/{pk}/')
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertEqual(
order.get_absolute_url(), f'/order/purchase-order/{pk}/'
)
self.assertEqual(order.reference, f'PO-{pk:04d}')

View File

@ -132,7 +132,9 @@ class PartCategory(InvenTree.models.InvenTreeTree):
def get_absolute_url(self):
"""Return the web URL associated with the detail view for this PartCategory instance."""
return reverse('category-detail', kwargs={'pk': self.id})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('category-detail', kwargs={'pk': self.id})
return helpers.pui_url(f'/part/category/{self.id}')
def clean(self):
"""Custom clean action for the PartCategory model.
@ -754,7 +756,9 @@ class Part(
def get_absolute_url(self):
"""Return the web URL for viewing this part."""
return reverse('part-detail', kwargs={'pk': self.id})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('part-detail', kwargs={'pk': self.id})
return helpers.pui_url(f'/part/{self.id}')
def get_image_url(self):
"""Return the URL of the image for this part."""

View File

@ -1,5 +1,6 @@
"""Unit tests for the PartCategory model."""
from django.conf import settings
from django.core.exceptions import ValidationError
from django.test import TestCase
@ -125,7 +126,8 @@ class CategoryTest(TestCase):
def test_url(self):
"""Test that the PartCategory URL works."""
self.assertEqual(self.capacitors.get_absolute_url(), '/part/category/3/')
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertEqual(self.capacitors.get_absolute_url(), '/part/category/3/')
def test_part_count(self):
"""Test that the Category part count works."""

View File

@ -237,7 +237,8 @@ class PartTest(TestCase):
def test_attributes(self):
"""Test Part attributes."""
self.assertEqual(self.r1.name, 'R_2K2_0805')
self.assertEqual(self.r1.get_absolute_url(), '/part/3/')
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertEqual(self.r1.get_absolute_url(), '/part/3/')
def test_category(self):
"""Test PartCategory path."""

View File

@ -1,5 +1,6 @@
"""Unit tests for Part Views (see views.py)."""
from django.test import tag
from django.urls import reverse
from InvenTree.unit_test import InvenTreeTestCase
@ -16,6 +17,7 @@ class PartViewTestCase(InvenTreeTestCase):
superuser = True
@tag('cui')
class PartListTest(PartViewTestCase):
"""Unit tests for the PartList view."""
@ -33,6 +35,7 @@ class PartListTest(PartViewTestCase):
class PartDetailTest(PartViewTestCase):
"""Unit tests for the PartDetail view."""
@tag('cui')
def test_part_detail(self):
"""Test that we can retrieve a part detail page."""
pk = 1
@ -50,6 +53,7 @@ class PartDetailTest(PartViewTestCase):
self.assertEqual(response.context['part'].pk, pk)
self.assertEqual(response.context['category'], part.category)
@tag('cui')
def test_part_detail_from_ipn(self):
"""Test that we can retrieve a part detail page from part IPN.

View File

@ -3,7 +3,7 @@
import os
from django.conf import settings
from django.test import TestCase
from django.test import TestCase, tag
from django.urls import include, path, re_path, reverse
from error_report.models import Error
@ -363,6 +363,7 @@ class PanelMixinTests(InvenTreeTestCase):
plugins = registry.with_mixin('panel', active=False)
self.assertEqual(len(plugins), 0)
@tag('cui')
def test_disabled(self):
"""Test that the panels *do not load* if the plugin is not enabled."""
plugin = registry.get_plugin('samplepanel')
@ -390,6 +391,7 @@ class PanelMixinTests(InvenTreeTestCase):
self.assertNotIn('Hello world', str(response.content))
self.assertNotIn('Custom Part Panel', str(response.content))
@tag('cui')
def test_enabled(self):
"""Test that the panels *do* load if the plugin is enabled."""
plugin = registry.get_plugin('samplepanel')

View File

@ -1,5 +1,6 @@
"""Unit tests for InvenTreeBarcodePlugin."""
from django.conf import settings
from django.urls import reverse
import part.models
@ -270,9 +271,10 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
self.assertEqual(
response.data['stocklocation']['api_url'], '/api/stock/location/5/'
)
self.assertEqual(
response.data['stocklocation']['web_url'], '/stock/location/5/'
)
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertEqual(
response.data['stocklocation']['web_url'], '/stock/location/5/'
)
self.assertEqual(response.data['plugin'], 'InvenTreeBarcode')
# Scan a Part object

View File

@ -13,6 +13,7 @@ from django.urls.base import reverse
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from InvenTree.helpers import pui_url
from plugin.helpers import get_git_log
logger = logging.getLogger('inventree')
@ -364,7 +365,13 @@ class InvenTreePlugin(VersionMixin, MixinBase, MetaBase):
@property
def settings_url(self):
"""URL to the settings panel for this plugin."""
return f'{reverse("settings")}#select-plugin-{self.slug}'
if settings.ENABLE_CLASSIC_FRONTEND:
return f'{reverse("settings")}#select-plugin-{self.slug}'
config = self.plugin_config()
if config:
return pui_url(f'/settings/admin/plugin/{config.pk}/')
else:
return pui_url('/settings/admin/plugin/')
# region package info
def _get_package_commit(self):

View File

@ -7,6 +7,7 @@ import os
from datetime import datetime, timedelta
from decimal import Decimal, InvalidOperation
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import FieldError, ValidationError
from django.core.validators import MinValueValidator
@ -258,7 +259,9 @@ class StockLocation(
def get_absolute_url(self):
"""Return url for instance."""
return reverse('stock-location-detail', kwargs={'pk': self.id})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('stock-location-detail', kwargs={'pk': self.id})
return InvenTree.helpers.pui_url(f'/stock/location/{self.id}')
def get_stock_items(self, cascade=True):
"""Return a queryset for all stock items under this category.
@ -727,7 +730,9 @@ class StockItem(
def get_absolute_url(self):
"""Return url for instance."""
return reverse('stock-item-detail', kwargs={'pk': self.id})
if settings.ENABLE_CLASSIC_FRONTEND:
return reverse('stock-item-detail', kwargs={'pk': self.id})
return InvenTree.helpers.pui_url(f'/stock/item/{self.id}')
def get_part_name(self):
"""Returns part name."""
@ -2304,7 +2309,9 @@ class StockItemTracking(InvenTree.models.InvenTreeModel):
def get_absolute_url(self):
"""Return url for instance."""
return f'/stock/track/{self.id}'
if settings.ENABLE_CLASSIC_FRONTEND:
return f'/stock/track/{self.id}'
return InvenTree.helpers.pui_url(f'/stock/item/{self.item.id}')
def label(self):
"""Return label."""

View File

@ -1,6 +1,7 @@
"""Unit tests for Stock views (see views.py)."""
from django.contrib.auth.models import Group
from django.test import tag
from django.urls import reverse
from common.models import InvenTreeSetting
@ -18,6 +19,7 @@ class StockViewTestCase(InvenTreeTestCase):
roles = 'all'
@tag('cui')
class StockListTest(StockViewTestCase):
"""Tests for Stock list views."""
@ -30,6 +32,7 @@ class StockListTest(StockViewTestCase):
class StockDetailTest(StockViewTestCase):
"""Unit test for the 'stock detail' page."""
@tag('cui')
def test_basic_info(self):
"""Test that basic stock item info is rendered."""
url = reverse('stock-item-detail', kwargs={'pk': 1})

View File

@ -2,6 +2,7 @@
import datetime
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db.models import Sum
from django.test import override_settings
@ -256,9 +257,9 @@ class StockTest(StockTestBase):
def test_url(self):
"""Test get_absolute_url function."""
it = StockItem.objects.get(pk=2)
self.assertEqual(it.get_absolute_url(), '/stock/item/2/')
self.assertEqual(self.home.get_absolute_url(), '/stock/location/1/')
if settings.ENABLE_CLASSIC_FRONTEND:
self.assertEqual(it.get_absolute_url(), '/stock/item/2/')
self.assertEqual(self.home.get_absolute_url(), '/stock/location/1/')
def test_strings(self):
"""Test str function."""

View File

@ -2,7 +2,7 @@
from django.apps import apps
from django.contrib.auth.models import Group
from django.test import TestCase
from django.test import TestCase, tag
from django.urls import reverse
from InvenTree.unit_test import InvenTreeTestCase
@ -165,6 +165,8 @@ class OwnerModelTest(InvenTreeTestCase):
self.assertEqual(response.status_code, status_code)
return response.data
# TODO: Find out why this depends on CUI
@tag('cui')
def test_owner(self):
"""Tests for the 'owner' model."""
# Check that owner was created for user

View File

@ -804,10 +804,17 @@ def test_translations(c):
'migrations': 'Run migration unit tests',
'report': 'Display a report of slow tests',
'coverage': 'Run code coverage analysis (requires coverage package)',
'cui': 'Do not run CUI tests',
}
)
def test(
c, disable_pty=False, runtest='', migrations=False, report=False, coverage=False
c,
disable_pty=False,
runtest='',
migrations=False,
report=False,
coverage=False,
cui=False,
):
"""Run unit-tests for InvenTree codebase.
@ -843,6 +850,9 @@ def test(
else:
cmd += ' --exclude-tag migration_test'
if cui:
cmd += ' --exclude-tag=cui'
if coverage:
# Run tests within coverage environment, and generate report
c.run(f'coverage run {managePyPath()} {cmd}')