π¨ Hotel Booking Wiki
The Hotel Booking application is a multi-resource property management system designed for QA practice. It covers the full hospitality lifecycle β from adding properties and defining room types to creating bookings with dynamic pricing, updating booking statuses, and submitting guest reviews.
A unique feature is the QA Chaos Lab, which injects intentional failures into API responses to simulate real-world instability: network delays, data corruption, race conditions, and permission issues. This makes Hotel the ideal app for resilience and negative testing.
Key Characteristics
- 4 interconnected resource types: Properties β Room Types β Bookings β Reviews
- Dynamic total amount calculation:
price_per_night Γ rooms Γ nights - Booking statuses with strict lifecycle transitions
- Reviews restricted to
CHECKED_OUTbookings only - Chaos Lab with 4 chaos packs at configurable intensity (0β100%)
- Data reset to template state via
POST /api/hotel/reset - All endpoints require API key authentication
Quick Start
Authorization: qac_live_<your_api_key> in the request header. Get your key from the Profile page.
UI Overview
The Hotel interface is a single-page application with four tabs: Properties, Room Types, Bookings, and Reviews. A hotel banner image appears at the top of each tab. The top navigation provides access to the QA Chaos Lab, API Docs, Data Viewer, and Profile.
Properties Tab
Contains an Add New Property form with fields: Property Name*, City*, Country*, Star Rating (1β5 dropdown), Address*, Postal Code, Phone, Email, Check-In Time (default 03:00 PM), Check-Out Time (default 11:00 AM), Description textarea, and Cancellation Policy textarea (default: "Free cancellation up to 24 hours before check-in").
Below the form: My Properties table with columns β Name, City, Country, Rating (star icons), Status (ACTIVE badge), and Actions (DELETE button in red).
Room Types Tab
Contains an Add Room Type form: Select Property* (dropdown), Room Type Name*, Bed Type* (Single/Double/Queen/King/Twin), Max Occupancy*, Room Size (sqm), Price Per Night ($)*, Total Rooms*, Description, Amenities (comma-separated, e.g. "WiFi, TV, AC, Mini Bar").
Below: Room Types table β Property, Room Type, Bed Type, Max Occupancy, Price/Night, Total Rooms, Status (AVAILABLE badge), Actions (DELETE).
Bookings Tab
Stats dashboard at top: Total Bookings, Pending, Confirmed, Checked In, Total Revenue (in dollars).
Create New Booking form: Property*, Room Type* (filtered by selected property), Guest Name*, Guest Email*, Guest Phone*, Check-In Date*, Check-Out Date*, Number of Guests*, Number of Rooms (default 1), Special Requests textarea.
All Bookings section with Filter by Status dropdown (All Statuses). Table columns: Confirmation #, Guest, Property, Room Type, Check-In, Check-Out, Guests, Total Amount, Status, Actions.
Reviews Tab
Guest Reviews table: Guest, Property, Rating, Comment, Date. The + ADD REVIEW button (top right) opens the review submission form. Reviews require a completed (CHECKED_OUT) booking.
Top Navigation
| Item | Description |
|---|---|
| π² Chaos (cyan badge) | Opens the QA Chaos Lab modal β toggles chaos for the session |
| π API Docs | Links to Swagger UI with full API reference |
| π Data Viewer | Read-only table view of all hotel data |
| β Profile | Returns to main profile/apps page |
| βοΈ / π | Dark/light theme toggle |
QA Chaos Lab
The Chaos Lab is a unique testing feature that randomly injects failures into Hotel API responses. It is controlled per-user and does not affect other users. Click the π² Chaos button in the top nav to open the modal.
Configuration
- Chaos Session toggle β Enables/disables chaos for the current session
- Intensity slider β 0% = never triggers, 100% = always triggers, default 50%
- Random Seed β Enter the same seed to reproduce specific chaos scenarios
Network Instability
Simulates network delays, timeouts, and connection issues. Returns 1xx, 5xx, and 503 errors for random requests.
Data Validation Errors
Corrupts API responses: removes fields, breaks JSON structure, changes data types, injects null values.
Race Conditions
Corrupts data BEFORE/AFTER one rule triggers: stringβnumbers swaps, drops fields, swaps values unexpectedly.
Security & Permissions
Tests authentication boundaries, access control, permission escalation, and security edge cases.
Property Flow
Properties are the top-level resource. All other resources (room types, bookings, reviews) belong to a property. Properties can be active or inactive.
- Required fields:
name,address,city,country - Star rating must be between 1 and 5 (integer)
- Default check-in time:
15:00:00, default check-out:11:00:00 - Deleting a property cascades down β room types, bookings, and reviews are also removed
- Filter by
is_activeandcityquery params
Room Types Flow
Room types define the inventory under a property. They set the price, capacity, and availability used when creating bookings.
- Required:
property_id,name,max_occupancy,bed_type,price_per_night,total_rooms - Bed types:
Single,Double,Queen,King,Twin is_availableflag β unavailable room types cannot be booked- Amenities passed as a comma-separated string in the UI, stored as an array
- Validation:
max_occupancy β₯ 1,price_per_night β₯ 0,total_rooms β₯ 1
Booking Flow
Bookings represent guest reservations. The total amount is auto-calculated and the confirmation number is auto-generated.
Booking Lifecycle
Business Rules
- Check-out date must be strictly after check-in date
- Number of guests must be β₯ 1, number of rooms β₯ 1
- Room type must be
is_available = trueto book - Total amount =
price_per_night Γ number_of_rooms Γ nights - Confirmation number format:
HB20260414-XXXXXX(date + random) - Cancellation requires recording
cancellation_reason(optional but tracked)
Review Flow
Guests can leave a review only after their booking reaches CHECKED_OUT status. Only one review per booking is permitted.
- Required:
booking_id,property_id,rating(1β5) - Optional sub-ratings:
cleanliness_rating,service_rating,location_rating,value_rating - Submitting a review for a non-CHECKED_OUT booking returns 400
- Duplicate reviews for the same booking return 400 (unique constraint)
API β Properties
Base path: /api/hotel/properties
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | required | Property name |
address | string | required | Street address |
city | string | required | City |
country | string | required | Country |
star_rating | integer | optional | 1β5 |
postal_code | string | optional | |
phone | string | optional | |
email | string | optional | |
check_in_time | string | optional | Default: 15:00:00 |
check_out_time | string | optional | Default: 11:00:00 |
description | string | optional | |
cancellation_policy | string | optional | Default: "Free cancellation up to 24 hours before check-in" |
Returns: 201 with created property object. 400 if required fields missing or star_rating out of range.
| Query Param | Type | Notes |
|---|---|---|
is_active | boolean | Filter by active/inactive |
city | string | Case-insensitive partial match |
Returns: 200 with array of properties, ordered by created_at DESC.
Returns: 200 with property object. 404 if not found or not owned by the authenticated user.
Updatable fields: name, description, address, city, country, postal_code, phone, email, star_rating, check_in_time, check_out_time, cancellation_policy, is_active.
Returns 400 if no valid fields provided. Unknown fields are silently ignored.
Returns: 200 with deleted property. 404 if not found.
API β Room Types
Base path: /api/hotel/room-types
| Field | Type | Required | Notes |
|---|---|---|---|
property_id | uuid | required | Must be owned by authenticated user |
name | string | required | e.g. "Deluxe Suite" |
max_occupancy | integer | required | β₯ 1 |
bed_type | string | required | Single, Double, Queen, King, Twin |
price_per_night | number | required | β₯ 0 |
total_rooms | integer | required | β₯ 1 |
room_size_sqm | number | optional | |
description | string | optional | |
amenities | array | optional | e.g. ["WiFi","TV","AC"] |
| Query Param | Notes |
|---|---|
property_id | Filter by property UUID |
is_available | true/false |
Ordered by price_per_night ASC.
Returns: 200 with room type. 404 if not found or property not owned by authenticated user.
Updatable: name, description, max_occupancy, bed_type, room_size_sqm, amenities, price_per_night, total_rooms, images, is_available. Returns 400 if no valid fields provided.
Returns 200 with deleted room type object. 404 if not found.
| Query Param | Required | Notes |
|---|---|---|
property_id | required | UUID |
room_type_id | required | UUID |
check_in_date | required | YYYY-MM-DD |
check_out_date | required | YYYY-MM-DD |
API β Bookings
Base path: /api/hotel/bookings
| Field | Type | Required | Notes |
|---|---|---|---|
property_id | uuid | required | |
room_type_id | uuid | required | Must belong to property |
guest_name | string | required | |
guest_email | string | required | |
guest_phone | string | required | |
check_in_date | date | required | YYYY-MM-DD |
check_out_date | date | required | Must be after check-in |
number_of_guests | integer | required | β₯ 1 |
number_of_rooms | integer | optional | Default: 1 |
special_requests | string | optional |
Total amount is auto-calculated: price_per_night Γ number_of_rooms Γ nights. Confirmation number auto-generated.
| Query Param | Notes |
|---|---|
property_id | Filter by property |
status | PENDING, CONFIRMED, CHECKED_IN, CHECKED_OUT, CANCELLED, NO_SHOW |
check_in_date | Filter bookings with check-in on or after this date |
check_out_date | Filter bookings with check-out on or before this date |
Body: { "status": "CONFIRMED", "cancellation_reason": "..." }
Valid statuses: PENDING, CONFIRMED, CHECKED_IN, CHECKED_OUT, CANCELLED, NO_SHOW
Sets confirmed_at when status becomes CONFIRMED. Sets cancelled_at when status becomes CANCELLED.
Returns 200 with deleted booking object. 404 if not found.
Deletes all user's hotel data and repopulates from template. Returns counts of deleted and created resources.
API β Reviews
Base path: /api/hotel/reviews
| Field | Type | Required | Notes |
|---|---|---|---|
booking_id | uuid | required | Booking must be CHECKED_OUT |
property_id | uuid | required | |
rating | integer | required | 1β5 |
cleanliness_rating | integer | optional | 1β5 |
service_rating | integer | optional | 1β5 |
location_rating | integer | optional | 1β5 |
value_rating | integer | optional | 1β5 |
comment | string | optional |
Returns 400 if booking is not CHECKED_OUT or if a review already exists for the booking.
| Query Param | Notes |
|---|---|
property_id | Filter by property UUID |
Ordered by created_at DESC. Includes guest name and property name in the response.
Test Cases
Properties
- Send POST /api/hotel/properties with
name,address,city,country
id and is_active: true- Send POST /api/hotel/properties with valid required fields and
star_rating: 6
- Send POST /api/hotel/properties with name, address, country β omit city
- Create a property
- PUT /api/hotel/properties/:id with
{ "is_active": false } - GET /api/hotel/properties?is_active=false
- PUT /api/hotel/properties/:id with body
{ "unknown_field": "value" }
Room Types
- POST /api/hotel/room-types with valid fields and
price_per_night: 0
- POST /api/hotel/room-types with
price_per_night: -50
- POST /api/hotel/room-types with a valid
property_idthat belongs to a different user
- PUT /api/hotel/room-types/:id with
{ "is_available": false } - POST /api/hotel/bookings referencing that room type
Bookings
- Create a room type with
price_per_night: 100 - POST booking with same-day dates spanning 3 nights,
number_of_rooms: 2
total_amount = 100 Γ 2 Γ 3 = 600- POST /api/hotel/bookings with
check_in_date=check_out_date
- POST booking where check_out_date < check_in_date
- Create booking β status:
PENDING - PATCH status β
CONFIRMED(confirmed_at is set) - PATCH status β
CHECKED_IN - PATCH status β
CHECKED_OUT
- PATCH /api/hotel/bookings/:id/status with
{ "status": "CANCELLED", "cancellation_reason": "Guest request" }
cancelled_at timestamp set, cancellation_reason stored- PATCH /api/hotel/bookings/:id/status with
{ "status": "DONE" }
Reviews
- Complete full booking lifecycle to CHECKED_OUT
- POST /api/hotel/reviews with booking_id, property_id, rating: 4
- Create a booking (status: PENDING)
- POST /api/hotel/reviews with that booking_id
- Submit a successful review for a CHECKED_OUT booking
- POST the same booking_id + property_id again
- POST /api/hotel/reviews with
rating: 0for a valid CHECKED_OUT booking
UI Test Cases
- Navigate to Hotel app β Properties tab
- Verify form contains: Property Name*, City*, Country*, Star Rating dropdown, Address*, Postal Code, Phone, Email, Check-In Time, Check-Out Time, Description, Cancellation Policy
- Leave Property Name, City, Country, and Address blank
- Click ADD PROPERTY
- Add a property
- Verify table shows: Name, City, Country, Rating (stars), Status (ACTIVE badge), Actions (DELETE)
- Add 2 properties
- Navigate to Room Types tab
- Click Select Property dropdown
- Add a room type
- Verify the Room Types table row shows AVAILABLE badge in Status column
- Navigate to Bookings tab with no bookings created
- Select Property A in Create New Booking form
- Note Room Type options
- Change Property to Property B
- Create bookings with different statuses
- Use Filter by Status dropdown in All Bookings section
- Select "CONFIRMED"
- Navigate to Reviews tab with no reviews submitted
- Click π² Chaos button in top nav
- Verify modal opens with: session toggle, intensity slider, random seed input, 4 chaos pack checkboxes
- Click X to close
- Open Chaos modal
- Drag intensity slider to 0%
- Drag to 100%
- Set to 50%
- Add a property
- Click DELETE button in its table row
- Confirm deletion prompt if shown
QA Tasks
Hands-on challenges designed for manual testing, API automation, and chaos resilience testing.
Create a property β add a room type β make a booking β progress it through PENDING β CONFIRMED β CHECKED_IN β CHECKED_OUT β submit a review. Verify the total amount calculation is correct at each step.
Automate a suite of booking date edge cases: same-day check-out, check-out before check-in, 1-night stays, and multi-month stays. Assert correct 400/201 responses and validate calculated amounts.
Enable Chaos Pack A at 75% intensity. Perform a booking creation workflow and observe how many requests fail. Verify your client retries on 5xx errors and surfaces friendly error messages on timeout.
Attempt to POST a review for bookings in each non-CHECKED_OUT status (PENDING, CONFIRMED, CHECKED_IN, CANCELLED, NO_SHOW). Verify all return 400. Only CHECKED_OUT allows a review.
Create properties with star_rating: 0, 1, 3, 5, and 6. Document which values succeed and which fail. Try updating an existing property's star rating to out-of-range values via PUT.
Use two different API keys. Create a property with User A. Attempt to create a room type under that property with User B's key. Document the response. Try to fetch User A's bookings with User B. Assert no data leaks across users.
Enable Pack B (Data Validation Errors) at 100% intensity. Run GET /api/hotel/properties and GET /api/hotel/bookings repeatedly. Document all response anomalies: missing fields, wrong types, broken JSON. Test whether your parser/client handles them gracefully.
Disable a room type via PUT (is_available: false), then attempt to book it. Restore it (is_available: true) and book again successfully. Use the availability check endpoint to query before booking.
Delete all properties manually. Then call POST /api/hotel/reset. Verify the response reports created properties and room types. Check the Properties tab in UI and confirm template data is restored.
Enable chaos and note the Random Seed value displayed. Perform 5 API operations and note which ones failed. Reset the seed to the same value. Repeat the same 5 operations and verify the same failures occur β chaos is reproducible with the same seed.