Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 43 additions & 9 deletions pms/templates/rooms.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,53 @@
{% extends "main.html"%}

{% block content %}
<h1>Habitaciones del hotel</h1>
{% for room in rooms%}
<div class="d-flex justify-content-between align-items-center mt-4 mb-3">
<h1 class="mb-0">Habitaciones del hotel</h1>
</div>

<form method="GET" action="" class="mb-4">
<div class="input-group">
<input
type="search"
name="q"
class="form-control"
placeholder="Buscar por nombre de habitación…"
value="{{ query }}"
aria-label="Buscar habitación"
autocomplete="off"
>
<button class="btn btn-primary" type="submit">
<i class="bi bi-search me-1"></i> Buscar
</button>
{% if query %}
<a href="{% url 'rooms' %}" class="btn btn-outline-secondary">Limpiar</a>
{% endif %}
</div>
</form>

{% if query %}
<p class="text-muted small mb-3">
{% if rooms %}
{{ rooms|length }} resultado{{ rooms|length|pluralize:"s" }} para "<strong>{{ query }}</strong>"
{% else %}
No se encontraron habitaciones para "<strong>{{ query }}</strong>".
{% endif %}
</p>
{% endif %}

{% for room in rooms %}
<div class="row card mt-3 mb-3 hover-card bg-tr-250">
<div class="col p-3">
<div class="">
{{room.name}} ({{room.room_type__name}})
</div>
<div>{{ room.name }} ({{ room.room_type__name }})</div>
<div>
<a href="{% url 'room_details' pk=room.id%}">Ver detalles</a>
<a href="{% url 'room_details' pk=room.id %}">Ver detalles</a>
</div>

</div>

</div>
{% empty %}
{% if not query %}
<p class="text-muted mt-4">No hay habitaciones registradas.</p>
{% endif %}
{% endfor %}
{% endblock content%}
{% endblock content %}

91 changes: 89 additions & 2 deletions pms/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,90 @@
from django.test import TestCase
from django.test import TestCase, Client
from django.urls import reverse

from .models import Room, Room_type


class RoomsViewSearchTest(TestCase):
"""Tests for the room list search filter (GET ?q=)."""

@classmethod
def setUpTestData(cls):
room_type = Room_type.objects.create(name="Estándar", price=80.0, max_guests=2)
Room.objects.create(name="Habitación 101", description="Vista al jardín", room_type=room_type)
Room.objects.create(name="Habitación 202", description="Vista a la piscina", room_type=room_type)
Room.objects.create(name="Suite Presidencial", description="Planta ática", room_type=room_type)

def setUp(self):
self.client = Client()
self.url = reverse("rooms")

# --- baseline ---

def test_returns_200(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)

def test_no_query_returns_all_rooms(self):
response = self.client.get(self.url)
self.assertEqual(len(response.context["rooms"]), 3)

def test_empty_query_string_returns_all_rooms(self):
response = self.client.get(self.url, {"q": ""})
self.assertEqual(len(response.context["rooms"]), 3)

def test_whitespace_only_query_returns_all_rooms(self):
"""Strips whitespace so ' ' is treated as no query."""
response = self.client.get(self.url, {"q": " "})
self.assertEqual(len(response.context["rooms"]), 3)

# --- filtering ---

def test_search_returns_matching_rooms(self):
response = self.client.get(self.url, {"q": "Habitación"})
rooms = list(response.context["rooms"])
self.assertEqual(len(rooms), 2)
self.assertTrue(all("Habitación" in r["name"] for r in rooms))

def test_search_partial_match(self):
response = self.client.get(self.url, {"q": "101"})
rooms = list(response.context["rooms"])
self.assertEqual(len(rooms), 1)
self.assertEqual(rooms[0]["name"], "Habitación 101")

def test_search_no_results(self):
response = self.client.get(self.url, {"q": "xyzabc"})
rooms = list(response.context["rooms"])
self.assertEqual(len(rooms), 0)

# --- case insensitivity ---

def test_search_is_case_insensitive_lowercase(self):
response = self.client.get(self.url, {"q": "suite"})
rooms = list(response.context["rooms"])
self.assertEqual(len(rooms), 1)
self.assertEqual(rooms[0]["name"], "Suite Presidencial")

def test_search_is_case_insensitive_uppercase_ascii(self):
# SQLite's LIKE only case-folds ASCII characters; use an ASCII-safe term.
response = self.client.get(self.url, {"q": "SUITE"})
rooms = list(response.context["rooms"])
self.assertEqual(len(rooms), 1)
self.assertEqual(rooms[0]["name"], "Suite Presidencial")

# --- context ---

def test_query_term_preserved_in_context(self):
response = self.client.get(self.url, {"q": "Suite"})
self.assertEqual(response.context["query"], "Suite")

def test_empty_query_context_is_empty_string(self):
response = self.client.get(self.url)
self.assertEqual(response.context["query"], "")

# --- ordering ---

def test_results_ordered_by_name(self):
response = self.client.get(self.url)
names = [r["name"] for r in response.context["rooms"]]
self.assertEqual(names, sorted(names))

# Create your tests here.
13 changes: 10 additions & 3 deletions pms/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,16 @@ def get(self, request, pk):

class RoomsView(View):
def get(self, request):
# renders a list of rooms
rooms = Room.objects.all().values("name", "room_type__name", "id")
query = request.GET.get("q", "").strip()
rooms = Room.objects.select_related("room_type").values("name", "room_type__name", "id")

if query:
rooms = rooms.filter(name__icontains=query)

rooms = rooms.order_by("name")

context = {
'rooms': rooms
"rooms": rooms,
"query": query,
}
return render(request, "rooms.html", context)