diff --git a/tests/integration/nested-routers.test.ts b/tests/integration/nested-routers.test.ts new file mode 100644 index 0000000..4d1ec1d --- /dev/null +++ b/tests/integration/nested-routers.test.ts @@ -0,0 +1,82 @@ +import 'isomorphic-fetch' + +import { OpenAPIRoute } from '../../src/route' +import { Path } from '../../src/parameters' +import { OpenAPIRouter } from '../../src/openapi' +import { buildRequest } from '../utils' + +const innerRouter = OpenAPIRouter({ base: '/api/v1' }) +class ToDoGet extends OpenAPIRoute { + static schema = { + tags: ['ToDo'], + summary: 'Get a single ToDo', + parameters: { + id: Path(Number), + }, + responses: { + '200': { + schema: { + todo: { + lorem: String, + ipsum: String, + }, + }, + }, + }, + } + + async handle(request: Request, env: any, context: any, data: Record) { + return { + todo: { + lorem: 'lorem', + ipsum: 'ipsum', + }, + } + } +} + +innerRouter.get('/todo/:id', ToDoGet) +innerRouter.all('*', () => Response.json({ message: 'Not Found' }, { status: 404 })) + +const router = OpenAPIRouter({ + schema: { + info: { + title: 'Radar Worker API', + version: '1.0', + }, + }, +}) + +router.all('/api/v1/*', innerRouter) +router.all('*', () => new Response('Not Found.', { status: 404 })) + +describe('innerRouter', () => { + it('simpleSuccessfulCall', async () => { + const request = await router.handle(buildRequest({ method: 'GET', path: `/api/v1/todo/1` })) + const resp = await request.json() + + expect(request.status).toEqual(200) + expect(resp).toEqual({ + todo: { + lorem: 'lorem', + ipsum: 'ipsum', + }, + }) + }) + + it('innerCatchAll', async () => { + const request = await router.handle(buildRequest({ method: 'GET', path: `/api/v1/asd` })) + const resp = await request.json() + + expect(request.status).toEqual(404) + expect(resp).toEqual({ message: 'Not Found' }) + }) + + it('outerCatchAll', async () => { + const request = await router.handle(buildRequest({ method: 'GET', path: `/asd` })) + const resp = await request.text() + + expect(request.status).toEqual(404) + expect(resp).toEqual('Not Found.') + }) +}) diff --git a/tests/integration/parameters.test.ts b/tests/integration/parameters.test.ts index a00bf02..ba1bcb9 100644 --- a/tests/integration/parameters.test.ts +++ b/tests/integration/parameters.test.ts @@ -367,3 +367,88 @@ describe('queryParametersValidation', () => { expect(resp.errors.p_optional).toBeUndefined() }) }) + +describe('bodyParametersValidation', () => { + test('requiredFieldTitle', async () => { + const request = await todoRouter.handle( + buildRequest({ + method: 'POST', + path: '/todos', + json: () => { + return {} + }, + }) + ) + const resp = await request.json() + + expect(request.status).toEqual(400) + + // the current body implementation only validates 1 field at time + expect(resp.errors['body.title']).toEqual('is required') + }) + + test('requiredFieldTipe', async () => { + const request = await todoRouter.handle( + buildRequest({ + method: 'POST', + path: '/todos', + json: () => { + return { + title: 'my todo', + } + }, + }) + ) + const resp = await request.json() + + expect(request.status).toEqual(400) + + // the current body implementation only validates 1 field at time + expect(resp.errors['body.type']).toEqual('is required') + }) + + test('validRequest', async () => { + const request = await todoRouter.handle( + buildRequest({ + method: 'POST', + path: '/todos', + json: () => { + return { + title: 'my todo', + type: 'nextWeek', + } + }, + }), + {}, + {} + ) + const resp = await request.json() + + expect(request.status).toEqual(200) + + expect(resp).toEqual({ todo: { title: 'my todo', type: 'nextWeek' } }) + }) + + test('validRequestWithOptionalParameters', async () => { + const request = await todoRouter.handle( + buildRequest({ + method: 'POST', + path: '/todos', + json: () => { + return { + title: 'my todo', + description: 'this will be done', + type: 'nextWeek', + } + }, + }), + {}, + {} + ) + const resp = await request.json() + + expect(request.status).toEqual(200) + + expect(resp).toEqual({ todo: { title: 'my todo', description: 'this will be done', type: 'nextWeek' } }) + }) +}) diff --git a/tests/router.ts b/tests/router.ts index 50e3b2d..e4901aa 100644 --- a/tests/router.ts +++ b/tests/router.ts @@ -102,9 +102,44 @@ export class ToDoGet extends OpenAPIRoute { } } +export class ToDoCreate extends OpenAPIRoute { + static schema = { + tags: ['ToDo'], + summary: 'Create a new ToDo', + requestBody: { + title: String, + description: new Str({ required: false }), + type: new Enumeration({ + values: { + nextWeek: 'nextWeek', + nextMonth: 'nextMonth', + }, + }), + }, + responses: { + '200': { + schema: { + todo: { + title: 'My new todo', + description: 'This really needs to be done next week', + type: 'nextWeek', + }, + }, + }, + }, + } + + async handle(request: Request, env: any, context: any, data: Record) { + return { + todo: data.body, + } + } +} + export const todoRouter = OpenAPIRouter() todoRouter.get('/todos', ToDoList) todoRouter.get('/todos/:id', ToDoGet) +todoRouter.post('/todos', ToDoCreate) // 404 for everything else todoRouter.all('*', () => new Response('Not Found.', { status: 404 }))