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
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:
176
boxes/tests.py
176
boxes/tests.py
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user