import { beforeEach, describe, expect, it } from 'bun:test' import type { Database } from 'bun:sqlite' import { Hono } from 'hono' import { createEmptyBook, createEmptyTeachingDesign } from '../../shared/domain/teachingDesign' import { openDb } from '../db' import { createBooksRouter } from './books' describe('books routes', () => { let app: Hono let db: Database beforeEach(() => { db = openDb(':memory:') app = new Hono().route('/api/books', createBooksRouter(db)) }) async function createViaApi(name: string): Promise<{ id: string }> { const res = await app.request('/api/books', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name }), }) return (await res.json()) as { id: string } } it('lists no books initially', async () => { const res = await app.request('/api/books') expect(res.status).toBe(200) expect(await res.json()).toEqual([]) }) it('creates a book', async () => { const res = await app.request('/api/books', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: '示例整本' }), }) expect(res.status).toBe(200) const body = (await res.json()) as { name: string; data: { designs: unknown[] } } expect(body.name).toBe('示例整本') expect(body.data.designs).toEqual([]) }) it('returns 400 when creating without a name', async () => { const res = await app.request('/api/books', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}), }) expect(res.status).toBe(400) }) it('gets a created book', async () => { const created = await createViaApi('示例整本') const res = await app.request(`/api/books/${created.id}`) expect(res.status).toBe(200) expect(((await res.json()) as { id: string }).id).toBe(created.id) }) it('returns 404 for a missing book', async () => { const res = await app.request('/api/books/missing') expect(res.status).toBe(404) }) it('saves book data without cover state', async () => { const created = await createViaApi('示例整本') const data = createEmptyBook() data.designs.push(createEmptyTeachingDesign('1.md')) const res = await app.request(`/api/books/${created.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: { ...data, cover: { courseName: '旧课程', teacherName: '旧教师' } } }), }) expect(res.status).toBe(200) const fetched = await app.request(`/api/books/${created.id}`) const body = (await fetched.json()) as { data: Record } expect(body.data).not.toHaveProperty('cover') }) it('returns 404 when saving data for a missing book', async () => { const res = await app.request('/api/books/missing', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: createEmptyBook() }), }) expect(res.status).toBe(404) }) it('returns 400 when saving without data', async () => { const created = await createViaApi('示例整本') const res = await app.request(`/api/books/${created.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}), }) expect(res.status).toBe(400) }) it('renames a book', async () => { const created = await createViaApi('旧名称') const res = await app.request(`/api/books/${created.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: '新名称' }), }) expect(res.status).toBe(200) expect(((await res.json()) as { name: string }).name).toBe('新名称') }) it('returns 404 when renaming a missing book', async () => { const res = await app.request('/api/books/missing', { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: '新名称' }), }) expect(res.status).toBe(404) }) it('deletes a book', async () => { const created = await createViaApi('示例整本') const res = await app.request(`/api/books/${created.id}`, { method: 'DELETE' }) expect(res.status).toBe(200) expect(await res.json()).toEqual({ ok: true }) expect((await app.request(`/api/books/${created.id}`)).status).toBe(404) }) it('returns 404 when deleting a missing book', async () => { const res = await app.request('/api/books/missing', { method: 'DELETE' }) expect(res.status).toBe(404) }) })