QA for a Short-Let Booking Platform: Calendars, Payments, Double-Booking
Founder & Lead Engineer, RAITHub
The bug that costs a short-let platform the most is double-booking: two guests confirmed for the same nights. Test it under concurrency, not one request at a time, because the failure only appears when two bookings race. Then test calendar and time-zone edge cases, payment holds and captures, and cancellation and refund rules. The happy-path booking everyone demos is the one case that rarely breaks.
If you would rather have it tested for you, see how RAITHub would test this below. This is a reusable test plan for any booking or short-let platform, whoever built it, and it pairs with the general pre-launch QA checklist.
What breaks on a booking platform, and what catches it?
Very little breaks on the happy path. The money and reputation bugs live in concurrency, dates, holds and cancellations. Write your tests from this list, not from the demo flow.
| What goes wrong | Real cause | Test that catches it |
|---|---|---|
| Two guests booked for the same nights | Two requests check availability, then both write | Fire two concurrent bookings for the same dates; assert exactly one succeeds |
| A night shows free that is actually held | A pending payment does not block the calendar | Start a booking, leave it pending, and try to book the same night |
| Wrong number of nights or wrong price | Check-in and check-out handled in different time zones | Book across a daylight-saving change and across midnight in the property's zone |
| Guest charged but no booking | Payment captured before the booking is committed | Fail the booking write after a successful charge; assert a refund or no capture |
| Refund wrong on cancellation | Cancellation policy not applied, or applied twice | Cancel inside and outside the free window; assert the exact refund |
| A blocked or past date is bookable | Validation only in the calendar widget | Post a booking for a blocked or past date through the API directly |
How do you test that two guests cannot book the same nights?
With a concurrency test, because a check-then-write that looks fine sequentially fails when two requests interleave. The reliable fix is to let the database enforce non-overlap, then prove it. In PostgreSQL, an exclusion constraint on a date range rejects any overlapping row:
CREATE EXTENSION IF NOT EXISTS btree_gist;
ALTER TABLE bookings
ADD CONSTRAINT no_overlap
EXCLUDE USING gist (
property_id WITH =,
daterange(check_in, check_out, '[)') WITH &&
)
WHERE (status IN ('held', 'confirmed'));
With the constraint in place, two overlapping writes cannot both commit: the second fails, and your code turns that into a clean "no longer available" message. Prove it by firing two bookings at once for the same property and dates, and asserting exactly one wins:
import { test, expect } from '@playwright/test'
test('only one of two concurrent bookings for the same nights succeeds', async ({ playwright }) => {
const api = await playwright.request.newContext()
const body = {
propertyId: process.env.PROPERTY_ID,
checkIn: '2027-05-01',
checkOut: '2027-05-04',
}
const [a, b] = await Promise.all([
api.post('/api/bookings', { data: body }),
api.post('/api/bookings', { data: body }),
])
const statuses = [a.status(), b.status()].sort()
// One created (201), one rejected as unavailable (409)
expect(statuses).toEqual([201, 409])
})
Run this many times, and from more than two callers, because a race that fails one time in fifty still double-books someone. If both ever succeed, the constraint or the transaction is missing. The same pattern applies to overselling stock in e-commerce; the transaction detail is in stop overselling with stock reservation.
How do you test the calendar and time zones?
Dates are where bookings quietly go wrong, because a night is a local concept and servers run in UTC. Test the edges, not a mid-month stay.
- Book a stay that crosses a daylight-saving change in the property's time zone, and confirm the number of nights and the total are right.
- Book a single night and confirm check-out is the next day, not the same day, with the half-open range handled consistently.
- Confirm a guest in a different time zone from the property sees the same dates the host set, not a date shifted by their own offset.
- Try to book a date in the past, or a blocked or maintenance date, through the API directly. It must be refused.
- Confirm a minimum-stay or changeover-day rule is enforced on the server, not only greyed out in the widget.
How do you test payments, holds and captures?
A booking links a calendar hold to a payment, so the two must stay in step. Test in your provider's test mode with test cards; Stripe publishes a full set in its testing documentation.
- Hold the nights, then take payment. If the payment fails, the hold must be released so the dates free up.
- Capture money only when the booking is confirmed. If the booking write fails after a successful charge, assert a refund or that nothing was captured.
- Deliver the same payment webhook twice and confirm the booking is created or confirmed once. Stripe recommends recording processed event IDs so duplicates are skipped (Stripe: webhooks).
- Close the tab mid-payment and confirm the booking ends clearly confirmed or clearly cancelled, never half-created with the nights stuck on hold.
- Expire an abandoned hold on a timer and confirm the nights become bookable again.
The full payment test plan, with replays and test clocks, is in testing payments and webhooks end to end.
How do you test cancellations and refunds?
Cancellation policies are rules with dates and money, so test each branch against a hand calculation.
- Cancel inside the free window and confirm the full refund, the released nights and the guest email all match.
- Cancel outside the free window and confirm the partial or no refund matches the policy exactly.
- Cancel a booking that is still in a pending hold and confirm no charge was made.
- Issue a host-side cancellation and confirm the guest is refunded in full and the dates reopen.
- Try to cancel the same booking twice and confirm the refund is issued once.
Buy, build or hire this testing?
| Option | Choose this when | Trade-off |
|---|---|---|
| Off-the-shelf booking SaaS or a channel manager | You run a few properties and do not need custom rules | Little of your own code to test; you inherit the vendor's calendar and payout behaviour |
| Your own Playwright concurrency suite | A developer can own the double-booking and payment tests and keep them current | Lowest cost to run; you must design the concurrency tests, which is the hard part |
| A freelance tester before launch | You want one outside pass | Concurrency and date bugs are easy to miss without load; check their experience |
| A managed QA plan or a one-off pre-launch audit | You want double-booking, calendars, payments and cancellations tested end to end | An outside dependency; keep the tests in your repository |
Doing it yourself is realistic: plan 3 to 5 days for a developer who knows the stack. The main risk of going alone is testing bookings one at a time, which never reproduces a double-booking.
Why RAITHub for this
- Money-under-concurrency is everyday work. TheSkinProof, the founder's own marketplace venture built and run by RAITHub, decrements per-variant stock inside the order transaction so it cannot oversell, with 750+ tests across 217 API endpoints. PropDesk collects rent through Stripe inside a 1,024-test suite.
- Tests that run concurrently, so a race that double-books one time in fifty is caught before a guest is.
- Honest limits. Security testing is application-level, against OWASP guidance; it is not a CREST- or PCI-certified penetration test. The figures above are test suites for platforms RAITHub built, not a standalone QA case study.
When you don't need us
- You list on a marketplace that owns the calendar and payments. Test your own glue code and the payout reconciliation.
- You have a QA engineer who owns release testing. Give them this plan.
- You need a certified penetration test report. Use a certified firm; RAITHub is not SOC 2 or ISO 27001 certified.
How RAITHub would test this
- Scope: agree the calendar rules, the payment flow and the cancellation policy on a free 15-minute call.
- Plan: a risk map led by double-booking, with concurrency, calendar, payment and cancellation tests.
- Test: concurrent bookings for the same nights, time-zone and blocked-date edges, holds and captures in test mode, and each cancellation branch against a hand calculation.
- Deliver: a ranked bug report with reproduction steps and a suggested fix, plus the concurrency and payment tests as automated tests in your repository.
- What you receive: the report, the tests and a handover note. IP is yours; an NDA is standard.
The audit is fixed-price, quoted in writing after the call. See QA as a Service, AI-built app testing, and, if you are still building, SaaS development and the PropTech industry page. To book it, ask for a pre-launch QA audit.
Documentation checked on 10 October 2026.
Frequently asked questions
How do you prevent double-booking on a short-let platform?
Let the database enforce non-overlap, for example with a PostgreSQL exclusion constraint on the date range, so two overlapping bookings cannot both commit. Then prove it with a concurrency test that fires two bookings for the same nights and asserts exactly one succeeds.
Why does a booking need a concurrency test?
Because a check-then-write that passes when requests run one at a time fails when two race. Double-booking only appears under concurrency, so you must fire overlapping requests at once, and repeatedly, to reproduce it.
How do you test calendars and time zones in a booking app?
Test stays that cross a daylight-saving change and midnight in the property's zone, confirm nights and totals are correct, and confirm a guest in another zone sees the dates the host set. Also post a past or blocked date through the API to confirm it is refused.
What should happen if payment fails after the nights are held?
The hold must be released so the dates free up, and nothing should be captured. Test this by failing the payment on a held booking and confirming the calendar reopens and no charge remains.
How do you test cancellation and refund rules?
Cancel inside and outside the free window, cancel a pending hold, and issue a host-side cancellation, checking each refund against a hand calculation. Also cancel the same booking twice to confirm the refund is issued once.
Is this testing the same as a penetration test?
No. This is functional and application-level testing of your booking, calendar and payment rules against OWASP guidance. A penetration test is a broader, often certified engagement. If a customer or auditor needs a pentest report, use a certified provider.
Related posts
Ready to discuss your project?
Book a free 15-minute technical audit with our engineering team.