Add search page and thing detail with AJAX
All checks were successful
Build containers when image tags change / build-if-image-changed (., web, containers, main container, git.baumann.gr/adebaumann/labhelper) (push) Successful in 32s
Build containers when image tags change / build-if-image-changed (data-loader, loader, initContainers, init-container, git.baumann.gr/adebaumann/labhelper-data-loader) (push) Successful in 7s

This commit is contained in:
2025-12-28 22:39:57 +01:00
parent 06cbae93dc
commit f30627196e
6 changed files with 539 additions and 5 deletions

View File

@@ -487,3 +487,179 @@ class BoxDetailViewTests(TestCase):
"""Box detail URL should be reversible by name."""
url = reverse('box_detail', kwargs={'box_id': 'BOX001'})
self.assertEqual(url, '/box/BOX001/')
class ThingDetailViewTests(TestCase):
"""Tests for thing detail view."""
def setUp(self):
"""Set up test fixtures."""
self.client = Client()
self.box_type = BoxType.objects.create(
name='Standard Box',
width=200,
height=100,
length=300
)
self.box = Box.objects.create(
id='BOX001',
box_type=self.box_type
)
self.thing_type = ThingType.objects.create(name='Electronics')
self.thing = Thing.objects.create(
name='Arduino Uno',
thing_type=self.thing_type,
box=self.box,
description='A microcontroller board'
)
def test_thing_detail_returns_200(self):
"""Thing detail page should return 200 status."""
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertEqual(response.status_code, 200)
def test_thing_detail_returns_404_for_invalid_thing(self):
"""Thing detail page should return 404 for non-existent thing."""
response = self.client.get('/thing/99999/')
self.assertEqual(response.status_code, 404)
def test_thing_detail_shows_thing_name(self):
"""Thing detail page should show thing name."""
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertContains(response, 'Arduino Uno')
def test_thing_detail_shows_type(self):
"""Thing detail page should show thing type."""
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertContains(response, 'Electronics')
def test_thing_detail_shows_description(self):
"""Thing detail page should show thing description."""
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertContains(response, 'A microcontroller board')
def test_thing_detail_shows_box(self):
"""Thing detail page should show box info."""
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertContains(response, 'BOX001')
self.assertContains(response, 'Standard Box')
def test_thing_detail_uses_correct_template(self):
"""Thing detail page should use correct template."""
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertTemplateUsed(response, 'boxes/thing_detail.html')
def test_thing_detail_url_name(self):
"""Thing detail URL should be reversible by name."""
url = reverse('thing_detail', kwargs={'thing_id': 1})
self.assertEqual(url, '/thing/1/')
class SearchViewTests(TestCase):
"""Tests for search view."""
def setUp(self):
"""Set up test client."""
self.client = Client()
def test_search_returns_200(self):
"""Search page should return 200 status."""
response = self.client.get('/search/')
self.assertEqual(response.status_code, 200)
def test_search_contains_search_input(self):
"""Search page should contain search input field."""
response = self.client.get('/search/')
self.assertContains(response, 'id="search-input"')
def test_search_contains_results_container(self):
"""Search page should contain results table."""
response = self.client.get('/search/')
self.assertContains(response, 'id="results-container"')
class SearchApiTests(TestCase):
"""Tests for search API."""
def setUp(self):
"""Set up test fixtures."""
self.client = Client()
self.box_type = BoxType.objects.create(
name='Standard Box',
width=200,
height=100,
length=300
)
self.box = Box.objects.create(
id='BOX001',
box_type=self.box_type
)
self.thing_type = ThingType.objects.create(name='Electronics')
Thing.objects.create(
name='Arduino Uno',
thing_type=self.thing_type,
box=self.box,
description='A microcontroller board'
)
Thing.objects.create(
name='Raspberry Pi',
thing_type=self.thing_type,
box=self.box
)
def test_search_api_returns_empty_for_short_query(self):
"""Search API should return empty results for queries under 2 chars."""
response = self.client.get('/search/api/?q=a')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()['results'], [])
def test_search_api_returns_results(self):
"""Search API should return matching results."""
response = self.client.get('/search/api/?q=ard')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['name'], 'Arduino Uno')
def test_search_api_is_case_insensitive(self):
"""Search API should be case-insensitive."""
response = self.client.get('/search/api/?q=ARDUINO')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['name'], 'Arduino Uno')
def test_search_api_truncates_description(self):
"""Search API should truncate long descriptions."""
Thing.objects.create(
name='Long Description Item',
thing_type=self.thing_type,
box=self.box,
description='A' * 200
)
response = self.client.get('/search/api/?q=long')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertLessEqual(len(results[0]['description']), 100)
def test_search_api_limits_results(self):
"""Search API should limit results to 50."""
for i in range(60):
Thing.objects.create(
name=f'Item {i}',
thing_type=self.thing_type,
box=self.box
)
response = self.client.get('/search/api/?q=Item')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 50)
def test_search_api_includes_type_and_box(self):
"""Search API results should include type and box info."""
response = self.client.get('/search/api/?q=ard')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(results[0]['type'], 'Electronics')
self.assertEqual(results[0]['box'], 'BOX001')