diff --git a/apps/api/src/page/create.ts b/apps/api/src/page/create.ts index 26c32fc..f4d13a6 100644 --- a/apps/api/src/page/create.ts +++ b/apps/api/src/page/create.ts @@ -20,7 +20,7 @@ const route = createRoute({ }, }, responses: { - 200: { + 201: { content: { 'application/json': { schema: PageOutput, @@ -62,6 +62,6 @@ export const registerPageCreate = (api: typeof pageApi) => { ) } - return c.json(PageOutput.parse(result), 200) + return c.json(PageOutput.parse(result), 201) }) } diff --git a/apps/api/src/page/delete.ts b/apps/api/src/page/delete.ts index 456a737..5aefeb4 100644 --- a/apps/api/src/page/delete.ts +++ b/apps/api/src/page/delete.ts @@ -35,7 +35,7 @@ export const registerPageDelete = (api: typeof pageApi) => { const userId = await verifyAuthentication(c) const { id } = c.req.valid('param') - const result = await db + const [result] = await db .delete(page) .where(and(eq(page.userId, userId), eq(page.id, id))) .returning() diff --git a/apps/api/src/page/page.test.ts b/apps/api/src/page/page.test.ts new file mode 100644 index 0000000..fc7fdc2 --- /dev/null +++ b/apps/api/src/page/page.test.ts @@ -0,0 +1,171 @@ +import { afterAll, beforeAll, describe, expect, test } from 'bun:test' +import { access_token, db, user } from '@boring.tools/database' +import type { + AccessTokenCreateInput, + AccessTokenListOutput, + AccessTokenOutput, + ChangelogCreateInput, + ChangelogCreateOutput, + ChangelogListOutput, + ChangelogOutput, + PageCreateInput, + PageListOutput, + PageOutput, + PageUpdateInput, + UserOutput, +} from '@boring.tools/schema' +import type { z } from '@hono/zod-openapi' +import { eq } from 'drizzle-orm' +import { fetch } from '../utils/testing/fetch' + +describe('Page', () => { + let testUser: z.infer + let testAccessToken: z.infer + let createdAccessToken: z.infer + let testPage: z.infer + + beforeAll(async () => { + const createdUser = await db + .insert(user) + .values({ email: 'page@test.local', providerId: 'test_000' }) + .returning() + const tAccessToken = await db + .insert(access_token) + .values({ + token: '1234567890', + userId: createdUser[0].id, + name: 'testtoken', + }) + .returning() + testAccessToken = tAccessToken[0] as z.infer + testUser = createdUser[0] as z.infer + }) + + afterAll(async () => { + await db.delete(user).where(eq(user.email, 'page@test.local')) + }) + + describe('Create', () => { + test('Success', async () => { + const payload: z.infer = { + title: 'Test Page', + changelogIds: [], + } + + const res = await fetch( + { + path: '/v1/page', + method: 'POST', + body: payload, + }, + testAccessToken.token as string, + ) + + const json = (await res.json()) as z.infer + testPage = json + expect(res.status).toBe(201) + }) + }) + + describe('By Id', () => { + test('Success', async () => { + const res = await fetch( + { + path: `/v1/page/${testPage.id}`, + method: 'GET', + }, + testAccessToken.token as string, + ) + + expect(res.status).toBe(200) + }) + + test('Not Found', async () => { + const res = await fetch( + { + path: '/v1/page/635f4aa7-79fc-4d6b-af7d-6731999cc8bb', + method: 'GET', + }, + testAccessToken.token as string, + ) + + expect(res.status).toBe(404) + }) + }) + + describe('Update', () => { + test('Success', async () => { + const update: z.infer = { + title: 'Test Update', + } + const res = await fetch( + { + path: `/v1/page/${testPage.id}`, + method: 'PUT', + body: update, + }, + testAccessToken.token as string, + ) + + expect(res.status).toBe(200) + }) + }) + + describe('Public', () => { + test('Success', async () => { + const res = await fetch( + { + path: `/v1/page/${testPage.id}/public`, + method: 'GET', + }, + testAccessToken.token as string, + ) + + expect(res.status).toBe(200) + }) + }) + + describe('List', () => { + test('Success', async () => { + const res = await fetch( + { + path: '/v1/page', + method: 'GET', + }, + testAccessToken.token as string, + ) + + expect(res.status).toBe(200) + + const json = (await res.json()) as z.infer + // Check if token is redacted + expect(json).toHaveLength(1) + }) + }) + + describe('Remove', () => { + test('Success', async () => { + const res = await fetch( + { + path: `/v1/page/${testPage.id}`, + method: 'DELETE', + }, + testAccessToken.token as string, + ) + + expect(res.status).toBe(200) + }) + + test('Not found', async () => { + const res = await fetch( + { + path: `/v1/page/${testPage.id}`, + method: 'DELETE', + }, + testAccessToken.token as string, + ) + + expect(res.status).toBe(404) + }) + }) +}) diff --git a/apps/api/src/page/public.ts b/apps/api/src/page/public.ts index 2aabd2d..22d5b1e 100644 --- a/apps/api/src/page/public.ts +++ b/apps/api/src/page/public.ts @@ -91,6 +91,7 @@ export const registerPagePublic = (api: typeof pageApi) => { } redis.set(id, JSON.stringify(mappedResult), { EX: 60 }) - return c.json(PagePublicOutput.parse(mappedResult), 200) + const asd = PagePublicOutput.parse(mappedResult) + return c.json(asd, 200) }) } diff --git a/bun.lockb b/bun.lockb index 6d066c9..aa813c0 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/packages/schema/src/page/base.ts b/packages/schema/src/page/base.ts index 0ad9e3c..929c9c9 100644 --- a/packages/schema/src/page/base.ts +++ b/packages/schema/src/page/base.ts @@ -7,8 +7,8 @@ export const PageOutput = z example: '', }), title: z.string(), - description: z.string().optional(), - icon: z.string(), + description: z.string().optional().nullable(), + icon: z.string().optional().nullable(), changelogs: z.array(ChangelogOutput).optional(), }) .openapi('Page') diff --git a/packages/schema/src/page/create.ts b/packages/schema/src/page/create.ts index 8db11f8..303c0d7 100644 --- a/packages/schema/src/page/create.ts +++ b/packages/schema/src/page/create.ts @@ -5,10 +5,10 @@ export const PageCreateInput = z title: z.string().min(3).openapi({ example: 'My page', }), - description: z.string().optional().openapi({ + description: z.string().optional().nullable().openapi({ example: '', }), - icon: z.string().optional().openapi({ + icon: z.string().optional().nullable().openapi({ example: 'base64...', }), changelogIds: z.array(z.string().uuid()), diff --git a/packages/schema/src/page/public.ts b/packages/schema/src/page/public.ts index 4d36b14..519ff5c 100644 --- a/packages/schema/src/page/public.ts +++ b/packages/schema/src/page/public.ts @@ -2,21 +2,23 @@ import { z } from '@hono/zod-openapi' export const PagePublicOutput = z.object({ title: z.string(), - description: z.string(), + description: z.string().nullable(), icon: z.string(), - changelogs: z.array( - z.object({ - title: z.string(), - description: z.string(), - versions: z.array( - z.object({ - markdown: z.string(), - version: z.string(), - releasedAt: z.date(), - }), - ), - }), - ), + changelogs: z + .array( + z.object({ + title: z.string(), + description: z.string(), + versions: z.array( + z.object({ + markdown: z.string(), + version: z.string(), + releasedAt: z.date(), + }), + ), + }), + ) + .optional(), }) export const PagePublicParams = z.object({