Skip to content

test(adapter): multi-step booking lifecycle tests#70

Merged
Jesssullivan merged 1 commit intomainfrom
feat/homegrown-adapter-tests-phase2
Apr 18, 2026
Merged

test(adapter): multi-step booking lifecycle tests#70
Jesssullivan merged 1 commit intomainfrom
feat/homegrown-adapter-tests-phase2

Conversation

@Jesssullivan
Copy link
Copy Markdown
Owner

Summary

  • Adds sequenced mock DB builder (createSequencedMockDb) for testing methods with multiple sequential queries
  • Tests createBooking (4-step: resolve service → find/create client → get practitioner → insert)
  • Tests getBooking (4-table join: booking + service + client + practitioner)
  • Tests rescheduleBooking (select existing → update → getBooking refresh)
  • Error paths: service not found during booking, booking not found, missing service graceful fallback
  • 36 total tests (up from 28 in phase 1)

Follows up on #69 (merged).

Test plan

  • All 36 tests pass
  • Full suite: 614 tests pass (21 files)

Tracker: TIN-104

Sequenced mock DB builder enables testing methods that make
multiple sequential queries: createBooking (service+client+
practitioner+insert), getBooking (4-table join), rescheduleBooking
(select+update+getBooking). 36 tests total (up from 28).
Covers error paths (service not found, booking not found) and
edge cases (new client during booking, missing service fallback).
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 18, 2026

Greptile Summary

Adds createSequencedMockDb, a closure-based sequenced mock that returns different rows for successive select/insert calls, then uses it to cover the 3 multi-step booking lifecycle methods (createBooking, getBooking, rescheduleBooking) plus their error paths. The approach is sound: each d.select().from() call increments a shared counter, so the correct fixture row is returned for each of the N sequential DB queries inside each adapter method.

Confidence Score: 5/5

Safe to merge — all findings are P2 style suggestions with no correctness impact.

The sequenced mock design is correct: the shared selectCall/insertCall closure counters correctly track sequential DB queries across all tested methods. All 8 new tests match the adapter's actual call sequences. The single comment is a documentation nit on an already-passing test.

No files require special attention.

Important Files Changed

Filename Overview
src/adapters/tests/homegrown-adapter.test.ts Adds createSequencedMockDb and 8 new multi-step lifecycle tests (createBooking ×3, getBooking ×3, rescheduleBooking ×2); one test implicitly triggers a 4th undocumented select for practitioner lookup in the "missing service" scenario, but this is handled gracefully and does not cause failures.

Sequence Diagram

sequenceDiagram
    participant T as Test
    participant A as HomegrownAdapter
    participant DB as SequencedMockDb

    note over T,DB: createBooking (existing client)
    T->>A: createBooking(request)
    A->>DB: select → from(services) → where → limit(1)
    DB-->>A: [SERVICE_ROW] (seq[0])
    A->>DB: select → from(clients) → where(email) → limit(1)
    DB-->>A: [CLIENT_ROW] (seq[1])
    A->>DB: update(clients).set().where()
    DB-->>A: undefined
    A->>DB: select → from(practitioners) → where(handle) → limit(1)
    DB-->>A: [PRACTITIONER_ROW] (seq[2])
    A->>DB: insert(bookings).values().returning()
    DB-->>A: [BOOKING_ROW] (ins[0])
    A-->>T: Booking domain object

    note over T,DB: getBooking (4-table join)
    T->>A: getBooking(id)
    A->>DB: select → from(bookings) → where → limit(1)
    DB-->>A: [BOOKING_ROW] (seq[0])
    A->>DB: select → from(services) → where → limit(1)
    DB-->>A: [SERVICE_ROW] (seq[1])
    A->>DB: select → from(clients) → where → limit(1)
    DB-->>A: [CLIENT_ROW] (seq[2])
    A->>DB: select → from(practitioners) → where → limit(1)
    DB-->>A: [PRACTITIONER_ROW] (seq[3])
    A-->>T: Booking with joined data

    note over T,DB: rescheduleBooking
    T->>A: rescheduleBooking(id, newDatetime)
    A->>DB: select → from(bookings) → where → limit(1)
    DB-->>A: [BOOKING_ROW] (seq[0])
    A->>DB: update(bookings).set().where()
    DB-->>A: undefined
    A->>A: getBooking(id) [internal, 4 selects seq[1..4]]
    A-->>T: Updated Booking
Loading

Reviews (1): Last reviewed commit: "test(adapter): add multi-step booking li..." | Re-trigger Greptile

Comment on lines +723 to +736
it('handles missing service gracefully', async () => {
const mockDb = createSequencedMockDb([
[BOOKING_ROW], // booking exists
[], // service not found
[CLIENT_ROW], // client
]);

const adapter = createHomegrownAdapter({ getDb: async () => mockDb });
const result = await Effect.runPromise(adapter.getBooking('booking-uuid-1'));

// Falls back to 'Unknown' for service name, 'USD' for currency
expect(result.serviceName).toBe('Unknown');
expect(result.currency).toBe('USD');
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Undocumented 4th select in sequence

BOOKING_ROW.practitionerId is 'prac-uuid-1' (truthy), so getBooking will always execute the conditional practitioner select — meaning 4 selects fire here, not 3. The 4th call resolves to selectSequence[3] ?? [], returning an empty array, which is handled gracefully (providerName = undefined). The test passes, but a future reader counting the sequence entries will be off by one. Consider either adding a 4th entry or using a BOOKING_ROW variant with practitionerId: null to make the intent explicit.

Suggested change
it('handles missing service gracefully', async () => {
const mockDb = createSequencedMockDb([
[BOOKING_ROW], // booking exists
[], // service not found
[CLIENT_ROW], // client
]);
const adapter = createHomegrownAdapter({ getDb: async () => mockDb });
const result = await Effect.runPromise(adapter.getBooking('booking-uuid-1'));
// Falls back to 'Unknown' for service name, 'USD' for currency
expect(result.serviceName).toBe('Unknown');
expect(result.currency).toBe('USD');
});
it('handles missing service gracefully', async () => {
const mockDb = createSequencedMockDb([
[BOOKING_ROW], // booking exists
[], // service not found
[CLIENT_ROW], // client
[], // practitioner (BOOKING_ROW.practitionerId is set; graceful fallback)
]);

@Jesssullivan Jesssullivan merged commit 5653e2d into main Apr 18, 2026
7 of 9 checks passed
@Jesssullivan Jesssullivan deleted the feat/homegrown-adapter-tests-phase2 branch April 18, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant