- src/db/schema.ts: users, memberCredentials, calendars, calendarEvents tables - users: composite unique on oidc_iss+oidc_sub (D-10 identity) - calendar_events: separate dtstart_utc (TIMESTAMP) and dtstart_date (DATE) + allDay boolean (D-13) - src/db/client.ts: drizzle(mysql2 pool) singleton export `db` - drizzle.config.ts: dialect mysql, schema → migrations, dbCredentials from env - src/routes/health.ts: GET / with real SELECT 1 DB round-trip, 200 or 503 - src/index.ts: Hono app with /health mounted before auth, serveStatic for PWA - tests/health.test.ts: 2 tests pass (mocked DB); TDD GREEN gate - apps/pwa/src/App.tsx: React shell fetching /health via TanStack Query
39 lines
1.3 KiB
TypeScript
39 lines
1.3 KiB
TypeScript
/**
|
|
* GET /health — end-to-end skeleton test
|
|
*
|
|
* Behavior:
|
|
* - GET /health returns 200 with { ok: true, db: "up" } after DB round-trip succeeds
|
|
* - GET /health returns 503 if the DB round-trip throws
|
|
*/
|
|
|
|
import { describe, it, expect, vi } from 'vitest'
|
|
|
|
// vi.mock is hoisted to the top of the module by Vitest — defining it here is correct.
|
|
// The factory is called before any test runs.
|
|
vi.mock('../src/db/client.js', () => ({
|
|
db: {
|
|
execute: vi.fn().mockResolvedValue([[{ '1': 1 }]]),
|
|
},
|
|
}))
|
|
|
|
describe('GET /health', () => {
|
|
it('returns 200 with { ok: true, db: "up" } when DB round-trip succeeds', async () => {
|
|
const { app } = await import('../src/index.js')
|
|
const res = await app.request('/health')
|
|
expect(res.status).toBe(200)
|
|
const body = await res.json() as { ok: boolean; db: string }
|
|
expect(body.ok).toBe(true)
|
|
expect(body.db).toBe('up')
|
|
})
|
|
|
|
it('returns 503 when DB round-trip throws', async () => {
|
|
const { db } = await import('../src/db/client.js')
|
|
// Temporarily override execute to throw
|
|
vi.mocked(db.execute).mockRejectedValueOnce(new Error('DB connection failed'))
|
|
|
|
const { app } = await import('../src/index.js')
|
|
const res = await app.request('/health')
|
|
expect(res.status).toBe(503)
|
|
})
|
|
})
|