Files
TS_Proto/TEST-CATALOG.md
T
nilesh.pandClaude Opus 4.8 4d3eb18a6c Initial commit: TravelHub multi-tenant flight booking platform
Angular + Go + PostgreSQL sample with strict per-tenant isolation.

- Backend: Go API (basic auth, tenant-scoped repository layer, pgx pool)
- Frontend: Angular 22 SPA (search, checkout, bookings, dashboard)
- Database: schema, seed data and demo bookings migrations
- Tests: 311 across Go (integration), Angular (unit) and Playwright (e2e),
  plus a generated evidence report with PDF export
- Security: whitebox VAPT report under security/

Secrets (.env, tokens, DB credentials) are git-ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-13 11:38:01 +05:30

19 KiB
Raw Blame History

TravelHub test catalogue

Generated by npm run docs:tests from the test sources. Do not edit by hand — regenerate instead.

277 test cases across 25 files.

Suite Files Cases Command
Go 6 98 npm run test:go
Angular 12 114 npm run test:web
Playwright 7 65 npm run test:e2e
Total 25 277 npm test

Why the runners report different numbers

A case below is one thing being tested. The runners count differently, so both figures are given rather than one being quietly preferred:

  • Go reports 74 test functions plus each table-driven subtest separately, so go test -v prints more PASS lines than there are cases here. A few tables build their subtest names at runtime and cannot be listed statically; those appear as a single case.
  • Playwright re-runs auth and responsive (17 tests) under a second, mobile viewport, so a full run executes 82 tests from 65 declared.
  • Angular counts exactly as listed.

Running a single file:

cd backend && go test ./internal/repository/ -run TestCreateBookingSellsSeats -v
cd frontend && npx ng test --no-watch                 # all specs
cd e2e && npx playwright test tests/booking.spec.ts

Go (backend)

74 test functions covering 98 cases. These run against a real PostgreSQL, with a fresh tenant created and dropped per test.

backend/internal/config/config_test.go

7 tests, 7 cases.

  • Load defaults — TestLoadDefaults
  • Load requires a password — TestLoadRequiresAPassword
  • Load escapes awkward passwords — TestLoadEscapesAwkwardPasswords
  • Database url wins over parts — TestDatabaseURLWinsOverParts
  • Load reads dot env — TestLoadReadsDotEnv
  • Environment beats dot env — TestEnvironmentBeatsDotEnv
  • Load finds dot env in a parent directory — TestLoadFindsDotEnvInAParentDirectory

backend/internal/handlers/handlers_test.go

22 tests, 33 cases.

  • Health needs no credentials — TestHealthNeedsNoCredentials
  • Tenant list is public but thin — TestTenantListIsPublicButThin
  • Protected routes reject anonymous — TestProtectedRoutesRejectAnonymous
  • Session describes the caller — TestSessionDescribesTheCaller
  • Session never returns the password hash — TestSessionNeverReturnsThePasswordHash
  • Search flights returns a page — TestSearchFlightsReturnsAPage
  • Search flights validates input — TestSearchFlightsValidatesInput
    • bad date
    • bad cabin
    • good cabin
    • absurd limit is clamped
    • negative offset falls back
    • non-numeric passengers falls back
  • Get flight rejects a malformed id — TestGetFlightRejectsAMalformedID
  • Get flight across tenants is four oh four — TestGetFlightAcrossTenantsIsFourOhFour
  • Create booking returns created — TestCreateBookingReturnsCreated
  • Create booking validation — TestCreateBookingValidation
    • missing flight id
    • missing contact email
    • malformed contact email
    • no passengers
    • blank passenger name
    • more than nine passengers
  • Create booking rejects unknown fields — TestCreateBookingRejectsUnknownFields
  • Create booking rejects malformed json — TestCreateBookingRejectsMalformedJSON
  • Create booking over capacity is conflict — TestCreateBookingOverCapacityIsConflict
  • Create booking on another tenants flight is four oh four — TestCreateBookingOnAnotherTenantsFlightIsFourOhFour
  • Booking lifecycle over http — TestBookingLifecycleOverHTTP
  • List bookings rejects an unknown status — TestListBookingsRejectsAnUnknownStatus
  • Bookings are invisible to other tenants — TestBookingsAreInvisibleToOtherTenants
  • Dashboard summarises the tenant — TestDashboardSummarisesTheTenant
  • Reference lists are scoped to the tenant network — TestReferenceListsAreScopedToTheTenantNetwork
  • Unknown route and wrong method — TestUnknownRouteAndWrongMethod
    • unknown path
    • wrong method
  • Every json response carries its content type — TestEveryJSONResponseCarriesItsContentType

backend/internal/middleware/middleware_test.go

10 tests, 20 cases.

  • Basic auth accepts valid credentials — TestBasicAuthAcceptsValidCredentials
  • Basic auth is case insensitive on email — TestBasicAuthIsCaseInsensitiveOnEmail
  • Basic auth rejections — TestBasicAuthRejections
    • no credentials at all
    • wrong password
    • unknown user
    • unknown tenant
    • valid credentials against another tenant
    • missing tenant header
    • malformed authorization header
  • Basic auth refuses suspended tenant — TestBasicAuthRefusesSuspendedTenant
  • Unauthorized does not trigger the browser dialog — TestUnauthorizedDoesNotTriggerTheBrowserDialog
  • Tenant falls back to subdomain — TestTenantFallsBackToSubdomain
  • Tenant header beats subdomain — TestTenantHeaderBeatsSubdomain
  • Require admin — TestRequireAdmin
    • admin passes
    • agent is refused
  • Cors — TestCORS
    • echoes an allowed origin
    • tolerates a trailing slash in configuration
    • ignores an origin that is not on the list
    • answers preflight without reaching the handler
  • Recoverer turns panic into five hundred — TestRecovererTurnsPanicIntoFiveHundred

backend/internal/repository/booking_repo_test.go

15 tests, 15 cases.

  • Create booking sells seats — TestCreateBookingSellsSeats
  • Create booking stores passenger detail — TestCreateBookingStoresPassengerDetail
  • Create booking rejects blank date of birth — TestCreateBookingRejectsBlankDateOfBirth
  • Create booking refuses more seats than remain — TestCreateBookingRefusesMoreSeatsThanRemain
  • Create booking requires a passenger — TestCreateBookingRequiresAPassenger
  • Create booking cannot reach another tenants flight — TestCreateBookingCannotReachAnotherTenantsFlight
  • Create booking refuses cancelled flight — TestCreateBookingRefusesCancelledFlight
  • Create booking does not oversell under concurrency — TestCreateBookingDoesNotOversellUnderConcurrency
  • Cancel booking returns seats — TestCancelBookingReturnsSeats
  • Cancel booking is not repeatable — TestCancelBookingIsNotRepeatable
  • Cancel booking across tenants is not found — TestCancelBookingAcrossTenantsIsNotFound
  • List bookings isolates tenants and filters status — TestListBookingsIsolatesTenantsAndFiltersStatus
  • Booking by id across tenants is not found — TestBookingByIDAcrossTenantsIsNotFound
  • Booking references are unique within a tenant — TestBookingReferencesAreUniqueWithinATenant
  • Dashboard stats count only this tenant — TestDashboardStatsCountOnlyThisTenant

backend/internal/repository/flight_repo_test.go

13 tests, 16 cases.

  • Search flights filters by route — TestSearchFlightsFiltersByRoute
  • Search flights lowercase iata still matches — TestSearchFlightsLowercaseIATAStillMatches
  • Search flights isolates tenants — TestSearchFlightsIsolatesTenants
  • Flight by id across tenants is not found — TestFlightByIDAcrossTenantsIsNotFound
  • Flight by id unknown is not found — TestFlightByIDUnknownIsNotFound
  • Search flights hides departed and cancelled — TestSearchFlightsHidesDepartedAndCancelled
  • Search flights respects party size — TestSearchFlightsRespectsPartySize
  • Search flights filters by cabin — TestSearchFlightsFiltersByCabin
  • Search flights filters by departure day — TestSearchFlightsFiltersByDepartureDay
  • Search flights sorting — TestSearchFlightsSorting
    • price
    • duration
    • departure
    • nonsense-falls-back-to-price
  • Search flights paginates — TestSearchFlightsPaginates
  • Search flights computes duration — TestSearchFlightsComputesDuration
  • List airports covers only this tenants network — TestListAirportsCoversOnlyThisTenantsNetwork

backend/internal/repository/identity_repo_test.go

7 tests, 7 cases.

  • Tenant by slug — TestTenantBySlug
  • Tenant by slug unknown is not found — TestTenantBySlugUnknownIsNotFound
  • Tenant by slug suspended is not found — TestTenantBySlugSuspendedIsNotFound
  • User by email is case insensitive — TestUserByEmailIsCaseInsensitive
  • User by email is scoped to tenant — TestUserByEmailIsScopedToTenant
  • Same email can exist in two tenants — TestSameEmailCanExistInTwoTenants
  • List tenants excludes suspended — TestListTenantsExcludesSuspended

Angular (frontend)

114 tests. Vitest with jsdom, via ng test.

frontend/src/app/core/api.service.spec.ts

10 tests.

  • ApiService › searchFlights
    • sends only the filters that were actually set
    • drops empty strings so a cleared filter does not narrow the search
    • keeps a zero offset, which is a real value rather than an absent one
  • ApiService
    • requests one flight by id
  • ApiService › listBookings
    • defaults to the first page of every status
    • passes a status filter through when given
  • ApiService
    • posts a booking
    • cancels a booking with an empty body
    • reads the dashboard
    • reads the tenant reference lists

frontend/src/app/core/auth.guard.spec.ts

5 tests.

  • authGuard
    • lets a signed-in user through
    • redirects to sign-in and remembers where the user was heading
    • omits returnTo when the destination was the root
  • guestGuard
    • lets a signed-out visitor reach the sign-in screen
    • sends an already signed-in user to the dashboard

frontend/src/app/core/auth.interceptor.spec.ts

8 tests.

  • authInterceptor
    • stamps API calls with the credentials and tenant
    • leaves non-API requests alone
    • does not overwrite credentials a caller set explicitly
    • adds nothing when signed out
    • signs out and redirects when stored credentials go stale
    • does not sign out on a 401 from an unstamped request
    • leaves the session intact for other error statuses
    • passes the error through to the caller

frontend/src/app/core/auth.service.spec.ts

12 tests.

  • AuthService
    • starts signed out with nothing in storage
    • fetches the public tenant list without credentials
    • verifies credentials against the chosen tenant before storing them
    • leaves no trace when the server rejects the credentials
    • reports the admin role
    • revalidates stored credentials on restore
    • discards stored credentials the server no longer accepts
    • restores without a second round trip once the session is known
    • short-circuits restore when there are no credentials
    • clears everything on sign out
    • treats unreadable storage as signed out rather than crashing
    • ignores a stored value of the wrong shape

frontend/src/app/features/bookings/booking-detail.spec.ts

8 tests.

  • BookingDetailPage
    • loads the booking with its travellers
    • shows the confirmation banner only when arriving from checkout
    • asks for confirmation before cancelling
    • lets the user back out
    • cancels on confirmation and reflects the new status
    • reports a cancel that failed and leaves the booking alone
    • offers no cancel control on an already cancelled booking
    • shows a not-found state for a booking in another agency

frontend/src/app/features/bookings/bookings.spec.ts

6 tests.

  • BookingsPage
    • loads every booking on open
    • filters by status and starts again from page one
    • pages through a long list
    • shows an empty state with a way forward
    • surfaces a load failure
    • renders a row with the reference, route and status

frontend/src/app/features/checkout/checkout.spec.ts

16 tests.

  • CheckoutPage
    • loads the flight and prefills the agent as the contact
    • opens with one traveller form by default
    • honours the traveller count carried over from search
    • clamps a silly traveller count to what the cabin allows
    • never asks for more travellers than there are seats
    • ignores a non-numeric traveller count
    • adds and removes travellers, repricing as it goes
    • will not go below one traveller or above nine
    • warns when the party outgrows the remaining seats
    • blocks submission until every required field is filled
    • submits the booking and moves to the confirmation
    • explains a seat sold out from under the form
    • explains a flight that disappeared
    • relays the server`s own validation message
    • shows a not-found state when the flight cannot be loaded
    • renders cabin codes as words

frontend/src/app/features/dashboard/dashboard.spec.ts

7 tests.

  • DashboardPage
    • greets the user by first name and names the agency
    • renders the headline figures
    • scales the route bars against the biggest earner
    • keeps a tiny route visible rather than drawing nothing
    • copes with no sales at all
    • treats a null topRoutes as an empty list
    • surfaces a failure to load

frontend/src/app/features/login/login.spec.ts

14 tests.

  • LoginPage
    • loads the agency list on open
    • preselects the only agency in a single-tenant deployment
    • does not preselect when there is a real choice to make
    • explains a backend that is not running
    • fills the form from a demo chip
    • refuses to submit an incomplete form
    • rejects a malformed email before calling the server
    • signs in and moves to the dashboard
    • returns the user to the page they were trying to reach
    • reports wrong credentials in the agency`s terms
    • reports an unreachable API distinctly from a bad password
    • falls back to a generic message for unexpected failures
    • renders one option per agency plus the placeholder
    • shows four demo account shortcuts

frontend/src/app/features/search/search.spec.ts

16 tests.

  • SearchPage
    • searches once on open and fills the airport pickers
    • asks for the first page with the default page size
    • passes the filter panel through to the API
    • returns to page one when the filters change
    • clears the filters on reset
  • SearchPage › pagination
    • describes the visible slice
    • moves forward and back
    • never steps past the ends
  • SearchPage
    • reports an empty result set rather than an error
    • surfaces a failed search
    • carries the traveller count into checkout
  • SearchPage › presentation helpers
    • marks an arrival on a later calendar day
    • shows no offset for a same-day arrival
    • flags scarce inventory as urgent
    • renders cabin codes as words
  • SearchPage
    • renders a result card with the fare and route

frontend/src/app/layout/shell.spec.ts

8 tests.

  • Shell
    • keeps the agency permanently on screen
    • shows who is signed in
  • Shell › initials
    • takes the first letter of the first two names
    • copes with a single name
    • copes with extra spacing
    • falls back when there is no name yet
  • Shell
    • offers the three main destinations
    • signs out and returns to the sign-in screen

frontend/src/app/shared/duration.pipe.spec.ts

4 tests.

  • DurationPipe
    • renders hours and zero-padded minutes
    • drops the hour part under an hour
    • handles long-haul durations past a day
    • renders a placeholder for missing or nonsensical values

Playwright (end to end)

65 tests, each run against a real browser and the real stack.

e2e/tests/auth.spec.ts

13 tests.

  • Sign in
    • offers every active agency in the picker
    • a demo shortcut fills the whole form
    • signs an agent into their own agency
    • signs an admin in and shows the admin role
    • rejects a wrong password
    • rejects valid credentials aimed at the wrong agency
    • will not submit without an agency
    • rejects a malformed email before contacting the server
  • Session
    • survives a page reload
    • sends an anonymous visitor to sign-in and back again
    • signing out clears the session for good
    • an already signed-in user is moved off the sign-in screen
    • stale stored credentials are discarded

e2e/tests/booking.spec.ts

7 tests.

  • Booking a flight
    • carries the fare and traveller count into checkout
    • reprices as travellers are added and removed
    • refuses to submit with missing traveller names
    • books, confirms, lists and cancels, returning the seats
    • a cancel can be backed out of
    • the bookings list filters by status
    • a booking opened directly shows no stale confirmation banner

e2e/tests/dashboard.spec.ts

6 tests.

  • Dashboard
    • greets the agent and names the agency
    • shows the four headline figures
    • lists recent bookings and best routes from the seed data
    • a new sale moves the figures, and cancelling moves them back
    • a recent booking row opens the booking
    • the new booking shortcut goes to search

e2e/tests/responsive.spec.ts

4 tests.

  • Layout
    • the sign-in screen fits without sideways scrolling
    • the console screens fit at phone width
    • wide tables scroll inside their own container
    • the sidebar collapses into a top bar on narrow screens

e2e/tests/search.spec.ts

11 tests.

  • Flight search
    • opens with the agency inventory already listed
    • offers only airports this agency flies
    • narrows results to a route
    • a route with no inventory shows an empty state
    • resets back to the full list
    • sorts by lowest fare
    • sorts by shortest trip
    • filters by cabin
    • hides flights without room for the whole party
    • pages through results without repeating them
    • a result card carries everything needed to choose

e2e/tests/simulation.spec.ts

19 tests.

  • When the API fails
    • search shows an error instead of an empty page
    • the dashboard explains itself rather than showing zeroes
    • the bookings list reports a failure
    • a missing backend is named on the sign-in screen
    • going offline mid-session surfaces a failure, not a hang
  • When the API is slow
    • search shows skeletons while it waits
    • the sign-in button reports that it is working
    • the dashboard shows skeleton tiles before its figures
  • When the session expires
    • a 401 mid-session returns the agent to sign-in
  • Edge cases in the data
    • an agency with no inventory sees an empty state, not an error
    • a brand new agency sees zeroes without a broken dashboard
    • the last seat is flagged as urgent
    • a seat sold during checkout is explained clearly
    • a party larger than the cabin is blocked before submitting
    • a huge result set still paginates sensibly
  • Awkward content
    • very long names do not break the layout or escape the page
    • markup in data is rendered as text, never as HTML
  • Keyboard operation
    • the sign-in form can be completed without a mouse
    • every interactive control on search is reachable by tab

e2e/tests/tenant-isolation.spec.ts

5 tests.

  • Tenant isolation
    • the same route is priced per agency
    • the sidebar always names the agency you are working in
    • one agency never sees another agency booking
    • revenue figures are per agency
    • a deep link to another agency flight is refused