From d8b7e240f0cc4f80dd2480812faa6aac89ca7561 Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 17:59:47 +0100 Subject: [PATCH 01/12] chore: remove unnecessary test --- tests/.gitignore | 0 tests/RegisterEventSubscribers.test.ts | 53 -------------------------- 2 files changed, 53 deletions(-) delete mode 100644 tests/.gitignore delete mode 100644 tests/RegisterEventSubscribers.test.ts diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/tests/RegisterEventSubscribers.test.ts b/tests/RegisterEventSubscribers.test.ts deleted file mode 100644 index ee69af9..0000000 --- a/tests/RegisterEventSubscribers.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { describe, expect, test, vi } from 'vitest'; -import { create, type KoalaConfig, koalaDefaultConfig } from '../src'; - -describe('Register Event Subscribers', () => { - test('Register single subscriber for an event', () => { - const config = { - ...koalaDefaultConfig, - eventSubscribers: { - firstEvent: vi.fn(), - }, - }; - const app = create(config as unknown as KoalaConfig); - - app.emit('firstEvent', 'data1'); - - expect(config.eventSubscribers.firstEvent).toHaveBeenCalledWith('data1'); - }); - - test('Register multiple subscribers for an event', () => { - const firstSubscriber = vi.fn(); - const secondSubscriber = vi.fn(); - const config = { - ...koalaDefaultConfig, - eventSubscribers: { - multiEvent: [firstSubscriber, secondSubscriber], - }, - }; - const app = create(config as unknown as KoalaConfig); - - app.emit('multiEvent', 'data2'); - - expect(firstSubscriber).toHaveBeenCalledWith('data2'); - expect(secondSubscriber).toHaveBeenCalledWith('data2'); - }); - - test('Register async subscriber for an event', () => { - const internalFn = vi.fn(); - const asyncSubscriber = async (data: string): Promise => { - await internalFn(data); - }; - const config = { - ...koalaDefaultConfig, - eventSubscribers: { - asyncEvent: asyncSubscriber, - }, - }; - const app = create(config as unknown as KoalaConfig); - - app.emit('asyncEvent', 'data3'); - - expect(internalFn).toHaveBeenCalledWith('data3'); - }); -}); From 4962801969f26094249c4dbf8dd37ed2c6957fa3 Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 18:14:55 +0100 Subject: [PATCH 02/12] chore: add end-to-end test for response generation --- tests/generate-response.e2e.test.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/generate-response.e2e.test.ts diff --git a/tests/generate-response.e2e.test.ts b/tests/generate-response.e2e.test.ts new file mode 100644 index 0000000..b370445 --- /dev/null +++ b/tests/generate-response.e2e.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from 'vitest'; +import { createTestAgent, type HttpScope, Route } from '../src'; + +class MyController { + @Route({ method: 'GET', path: '/response-basics' }) + responseBasics(scope: HttpScope): void { + scope.response.set('Custom-Header', 'HeaderValue'); + scope.response.body = { message: 'Response Basics' }; + scope.response.status = 200; + } +} + +describe('Generate Response E2E Test', () => { + test('response basics', async () => { + const agent = createTestAgent({ controllers: [MyController] }); + + const response = await agent.get('/response-basics'); + + expect(response.status).toBe(200); + expect(response.body).toEqual({ message: 'Response Basics' }); + expect(response.headers['custom-header']).toBe('HeaderValue'); + }); +}); From 14f7e980f8911d2bc002930b876be7d59d749ad9 Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 19:09:23 +0100 Subject: [PATCH 03/12] chore: add end-to-end tests for request properties and file uploads --- tests/request-props.e2e.test.ts | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/request-props.e2e.test.ts diff --git a/tests/request-props.e2e.test.ts b/tests/request-props.e2e.test.ts new file mode 100644 index 0000000..fde660d --- /dev/null +++ b/tests/request-props.e2e.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, test } from 'vitest'; +import { createTestAgent, type HttpRequest, type HttpScope, Route, UploadedFile } from '../src'; + +interface MyRequest extends HttpRequest { + body: { name: string }; + params: { id: string }; + headers: { foo: string }; + files: { + avatar: UploadedFile; + }; +} + +class MyController { + @Route({ method: 'POST', path: '/my-action/:id' }) + myAction(scope: HttpScope): void { + scope.response.body = { + greeting: `Hello, ${scope.request.body.name}!`, + sentId: scope.request.params.id, + barHeader: scope.request.headers.foo, + }; + } + + @Route({ method: 'POST', path: '/upload-avatar', options: { multipart: true } }) + multipartUpload(scope: HttpScope): void { + scope.response.body = { + uploadedFileName: scope.request.files.avatar.originalFilename, + }; + } +} + +describe('Request Body E2E Test', () => { + test('access request props', async () => { + const agent = createTestAgent({ controllers: [MyController] }); + + const response = await agent.post('/my-action/13').send({ name: 'Koala' }).set('foo', 'bar'); + + expect(response.body).toEqual({ + greeting: 'Hello, Koala!', + sentId: '13', + barHeader: 'bar', + }); + }); + + test('access uploaded files', async () => { + const agent = createTestAgent({ controllers: [MyController] }); + + const response = await agent.post('/upload-avatar').attach('avatar', 'tests/fixtures/avatar.png'); + + expect(response.body).toEqual({ + uploadedFileName: 'avatar.png', + }); + }); +}); From 5f46fdf8d5d90eea7fd7452ae0cdca6f6416b032 Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 19:16:35 +0100 Subject: [PATCH 04/12] chore: add end-to-end tests for serving static files --- tests/serve-static-files.e2e.test.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/serve-static-files.e2e.test.ts diff --git a/tests/serve-static-files.e2e.test.ts b/tests/serve-static-files.e2e.test.ts new file mode 100644 index 0000000..9eec67e --- /dev/null +++ b/tests/serve-static-files.e2e.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, test } from 'vitest'; +import { createTestAgent, type KoalaConfig } from '../src'; + +describe('Serve static files E2E Test', () => { + test('serve text file', async () => { + const agent = createTestAgent({ + staticFiles: { root: 'tests/fixtures' }, + } as unknown as KoalaConfig); + + const response = await agent.get('/sample.txt'); + + expect(response.status).toBe(200); + expect(response.headers['content-type']).toBe('text/plain; charset=utf-8'); + expect(response.text).toBe('Howdy!\n'); + }); + + test('serve image file', async () => { + const agent = createTestAgent({ + staticFiles: { root: 'tests/fixtures' }, + } as unknown as KoalaConfig); + + const response = await agent.get('/avatar.png'); + + expect(response.status).toBe(200); + expect(response.headers['content-type']).toBe('image/png'); + expect(response.body).toBeInstanceOf(Buffer); + }); +}); From c2571deadc9c467ad685632ce2a8a71efb5511d6 Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 19:28:28 +0100 Subject: [PATCH 05/12] feat(kernel): integrate http kernel into the app --- src/Application/ApplicationFactory.test.ts | 175 --------------------- src/Application/ApplicationFactory.ts | 3 + tests/event-subscribers.e2e.test.ts | 39 +++++ 3 files changed, 42 insertions(+), 175 deletions(-) delete mode 100644 src/Application/ApplicationFactory.test.ts create mode 100644 tests/event-subscribers.e2e.test.ts diff --git a/src/Application/ApplicationFactory.test.ts b/src/Application/ApplicationFactory.test.ts deleted file mode 100644 index 1496996..0000000 --- a/src/Application/ApplicationFactory.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import Koa from 'koa'; -import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { create } from '@/Application/ApplicationFactory'; -import { KoalaConfig, koalaDefaultConfig } from '@/Config'; -import type { HttpRequest, HttpScope, NextMiddleware, UploadedFile } from '@/Http'; -import { Route } from '@/Routing'; -import { createTestAgent, TestAgent } from '@/Testing'; - -describe('Application', () => { - let agent: TestAgent; - beforeEach(() => { - agent = createTestAgent(koalaDefaultConfig); - }); - - const middleware1 = function (_: HttpScope, next: NextMiddleware): Promise { - return next(); - }; - const service = vi.fn(); - - const middleware2 = function (_: HttpScope, next: NextMiddleware): Promise { - service(); - return next(); - }; - - interface BarRequest extends HttpRequest { - body?: { - name: string; - }; - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - class FooController { - @Route({ method: 'any', path: '/bar', options: { parseBody: false }, middleware: [middleware1, middleware2] }) - bar(scope: HttpScope): void { - scope.response.body = { - name: scope.request.body?.name ?? 'Koala', - }; - } - - @Route({ method: 'post', path: '/qux' }) - qux(scope: HttpScope): void { - scope.response.body = scope.request.body; - } - - @Route({ method: ['get', 'post'], path: '/handle-multiple-methods' }) - handleMultipleMethods(scope: HttpScope): void { - scope.response.body = { method: scope.request.method }; - } - - @Route({ method: 'get', path: '/access-route-params/:id' }) - accessRouteParams(scope: HttpScope): void { - scope.response.body = { id: scope.request.params.id }; - } - - @Route({ method: 'post', path: '/upload', options: { multipart: true } }) - upload(scope: HttpScope): void { - const avatar = scope.request.files?.avatar as unknown as UploadedFile; - scope.response.body = avatar.originalFilename; - } - - @Route({ method: 'get', path: '/set-header' }) - setHeader(scope: HttpScope): void { - scope.response.setHeader('X-Foo', 'Bar').setHeader('X-Bar', 'Foo').body = 'Header set'; - } - - @Route({ method: 'get', path: '/with-headers' }) - withHeaders(scope: HttpScope): void { - scope.response.withHeaders({ - 'X-Foo': 'Bar', - 'X-Bar': 'Foo', - }).body = 'Headers set'; - } - } - - test('it creates application instance', () => { - const app = create(koalaDefaultConfig); - - expect(app).toBeInstanceOf(Koa); - }); - - test('app provides access to scope', () => { - const app = create(koalaDefaultConfig); - - expect(app.scope).toBe(app.context); - }); - - test('e2e set header', async () => { - const response = await agent.get('/set-header'); - - expect(response.header['x-foo']).toBe('Bar'); - expect(response.header['x-bar']).toBe('Foo'); - }); - - test('e2e with headers', async () => { - const response = await agent.get('/with-headers'); - - expect(response.header['x-foo']).toBe('Bar'); - expect(response.header['x-bar']).toBe('Foo'); - }); - - test('e2e with body', async () => { - const response = await agent.post('/qux').send({ name: 'Koala' }); - - expect(response.status).toBe(200); - expect(response.body).toEqual({ name: 'Koala' }); - }); - - test('e2e without body', async () => { - const response = await agent.get('/bar').send({ name: 'Not Koala' }); - - expect(response.status).toBe(200); - expect(response.body).toEqual({ name: 'Koala' }); - }); - - test('it should call middleware', async () => { - await agent.get('/bar'); - - expect(service).toHaveBeenCalled(); - }); - - test('it should handle multiple methods', async () => { - const response1 = await agent.get('/handle-multiple-methods'); - const response2 = await agent.post('/handle-multiple-methods'); - - expect(response1.status).toBe(200); - expect(response2.status).toBe(200); - expect(response1.body).toEqual({ method: 'GET' }); - expect(response2.body).toEqual({ method: 'POST' }); - }); - - test('it should access route params', async () => { - const id = '123'; - const response = await agent.get(`/access-route-params/${id}`); - - expect(response.status).toBe(200); - expect(response.body).toEqual({ id }); - }); - - test('upload file', async () => { - const response = await agent.post('/upload').attach('avatar', 'tests/fixtures/avatar.png'); - - expect(response.text).toBe('avatar.png'); - }); -}); - -describe('Global Middleware', () => { - test('it should register configured global middleware', async () => { - const middlewareFn = vi.fn(); - const config = { - controllers: [], - globalMiddleware: [middlewareFn], - }; - const testAgent = createTestAgent(config as KoalaConfig); - - await testAgent.get('/'); - - expect(middlewareFn).toHaveBeenCalled(); - }); -}); - -describe('Serving Static Files', () => { - test('it should serve public static files', async () => { - const config = { - staticFiles: { - root: 'tests/fixtures', - }, - }; - const testAgent = createTestAgent(config as KoalaConfig); - - const response = await testAgent.get('/sample.txt'); - - expect(response.status).toBe(200); - expect(response.text).toBe('Howdy!\n'); - }); -}); diff --git a/src/Application/ApplicationFactory.ts b/src/Application/ApplicationFactory.ts index 9eeb3b4..818ad64 100644 --- a/src/Application/ApplicationFactory.ts +++ b/src/Application/ApplicationFactory.ts @@ -6,6 +6,7 @@ import { extendResponse } from '@/Application/Response'; import { type KoalaConfig } from '@/Config'; import { type HttpMiddleware, type HttpScope } from '@/Http'; import { serveStaticFiles } from '@/Http/Files'; +import { httpKernel } from '@/Kernel'; import { getRoutes } from '@/Routing'; export function create(config: KoalaConfig): Application { @@ -13,6 +14,8 @@ export function create(config: KoalaConfig): Application { app.scope = app.context; app.use(extendResponse); + app.use(httpKernel); + if (undefined !== config.globalMiddleware) registerGlobalMiddleware(app, config.globalMiddleware); app.use(serveStaticFiles(config.staticFiles)); diff --git a/tests/event-subscribers.e2e.test.ts b/tests/event-subscribers.e2e.test.ts new file mode 100644 index 0000000..cab0077 --- /dev/null +++ b/tests/event-subscribers.e2e.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, test, vi } from 'vitest'; +import { createTestAgent, KoalaConfig, Route } from '../src'; +import { useEmit } from '../src/Kernel'; + +class MyController { + @Route({ method: 'ANY', path: '/publish-event' }) + publishEvent(): void { + const emitter = useEmit(); + emitter.emit('myEvent', { data: 'event-data' }); + } +} + +describe('Event subscribers e2e Test', () => { + test('subscribe to and event', async () => { + const handler = vi.fn(); + const agent = createTestAgent({ + controllers: [MyController], + eventSubscribers: { myEvent: handler }, + } as unknown as KoalaConfig); + + await agent.get('/publish-event'); + + expect(handler).toHaveBeenCalledWith({ data: 'event-data' }); + }); + + test('multiple subscribers to an event', async () => { + const handler1 = vi.fn(); + const handler2 = vi.fn(); + const agent = createTestAgent({ + controllers: [MyController], + eventSubscribers: { myEvent: [handler1, handler2] }, + } as unknown as KoalaConfig); + + await agent.get('/publish-event'); + + expect(handler1).toHaveBeenCalledWith({ data: 'event-data' }); + expect(handler2).toHaveBeenCalledWith({ data: 'event-data' }); + }); +}); From 36d5b760fef52c63624487e6bdabae636a9e94cc Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 19:43:48 +0100 Subject: [PATCH 06/12] chore: add end-to-end test for global middleware registration --- tests/routing.e2e.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/routing.e2e.test.ts diff --git a/tests/routing.e2e.test.ts b/tests/routing.e2e.test.ts new file mode 100644 index 0000000..2f3b15a --- /dev/null +++ b/tests/routing.e2e.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, test, vi } from 'vitest'; +import { createTestAgent, type KoalaConfig } from '../src'; + +describe('Routing E2E Test', () => { + test('register global middleware', async () => { + const middleware = vi.fn(); + const config = { + globalMiddleware: [middleware], + }; + const agent = createTestAgent(config as unknown as KoalaConfig); + + await agent.get('/some-route'); + + expect(middleware).toHaveBeenCalled(); + }); +}); From 8dab01083c611b0061e08fa7838d58595890157f Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 19:48:14 +0100 Subject: [PATCH 07/12] chore: enhance ApplicationFactory with event subscriber handling and add tests --- src/Application/ApplicationFactory.test.ts | 9 +++++++++ src/Application/ApplicationFactory.ts | 14 ++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 src/Application/ApplicationFactory.test.ts diff --git a/src/Application/ApplicationFactory.test.ts b/src/Application/ApplicationFactory.test.ts new file mode 100644 index 0000000..14e8dda --- /dev/null +++ b/src/Application/ApplicationFactory.test.ts @@ -0,0 +1,9 @@ +import { expect, test } from 'vitest'; +import { create } from '@/Application/ApplicationFactory'; +import { koalaDefaultConfig } from '@/Config'; + +test('create app with default config', () => { + const app = create(koalaDefaultConfig); + + expect(app).toBeDefined(); +}); diff --git a/src/Application/ApplicationFactory.ts b/src/Application/ApplicationFactory.ts index 818ad64..e69c7b2 100644 --- a/src/Application/ApplicationFactory.ts +++ b/src/Application/ApplicationFactory.ts @@ -6,7 +6,7 @@ import { extendResponse } from '@/Application/Response'; import { type KoalaConfig } from '@/Config'; import { type HttpMiddleware, type HttpScope } from '@/Http'; import { serveStaticFiles } from '@/Http/Files'; -import { httpKernel } from '@/Kernel'; +import { type EventSubscriber, httpKernel } from '@/Kernel'; import { getRoutes } from '@/Routing'; export function create(config: KoalaConfig): Application { @@ -16,7 +16,9 @@ export function create(config: KoalaConfig): Application { app.use(extendResponse); app.use(httpKernel); - if (undefined !== config.globalMiddleware) registerGlobalMiddleware(app, config.globalMiddleware); + if (undefined !== config.globalMiddleware) { + registerGlobalMiddleware(app, config.globalMiddleware); + } app.use(serveStaticFiles(config.staticFiles)); @@ -25,7 +27,9 @@ export function create(config: KoalaConfig): Application { app.use(router.routes()); app.use(router.allowedMethods()); - registerEventSubscribers(app, config.eventSubscribers); + if (undefined !== config.eventSubscribers) { + registerEventSubscribers(app, config.eventSubscribers); + } return app; } @@ -51,9 +55,7 @@ function registerGlobalMiddleware(app: Application, middleware: HttpMiddleware[] } } -function registerEventSubscribers(app: Application, map: KoalaConfig['eventSubscribers']): void { - if (undefined === map) return; - +function registerEventSubscribers(app: Application, map: Record): void { for (const [event, subscribers] of Object.entries(map)) { if (Array.isArray(subscribers)) { for (const subscriber of subscribers) app.on(event, subscriber as unknown as (...args: unknown[]) => void); From d4191bd7463e9fe5e84263352145460c3e90f4cc Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 19:49:57 +0100 Subject: [PATCH 08/12] chore: update upgrade docs --- UPGRADE-3.0.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 6c3f45c..3cfb1e8 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -2,10 +2,4 @@ # Event -- Remove `eventBusMiddleware` and use `httpKernel` instead. -- Replace all the types from `@koala-ts/framework/Event` with types from `@koala-ts/framework/Kernel`. - -```diff --- import { eventBusMiddleware } from '@koala-ts/framework/Event'; -++ import { httpKernel } from '@koala-ts/framework/Kernel'; -``` +- Remove all usage of the `Event` module. From 109bd409ef3a76c76103bc1a944566602a48ef5b Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 20:14:22 +0100 Subject: [PATCH 09/12] chore(config): disable dotenv logs --- src/Config/ConfigLoader.test.ts | 20 ++++++++++++++++---- src/Config/ConfigLoader.ts | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Config/ConfigLoader.test.ts b/src/Config/ConfigLoader.test.ts index 394639e..6113aad 100644 --- a/src/Config/ConfigLoader.test.ts +++ b/src/Config/ConfigLoader.test.ts @@ -10,14 +10,18 @@ describe('Load env config', () => { test('it should load .env file', () => { loadEnvConfig('development'); - expect(configSpy).toHaveBeenCalledWith({ path: expect.stringContaining('.env'), override: true }); + expect(configSpy).toHaveBeenCalledWith({ path: expect.stringContaining('.env'), override: true, quiet: true }); expect(expandSpy).toHaveBeenCalled(); }); test('it should load .env.local file', () => { loadEnvConfig('development'); - expect(configSpy).toHaveBeenCalledWith({ path: expect.stringContaining('.env.local'), override: true }); + expect(configSpy).toHaveBeenCalledWith({ + path: expect.stringContaining('.env.local'), + override: true, + quiet: true, + }); expect(expandSpy).toHaveBeenCalled(); }); @@ -30,14 +34,22 @@ describe('Load env config', () => { test('it should load .env. file', () => { loadEnvConfig('development'); - expect(configSpy).toHaveBeenCalledWith({ path: expect.stringContaining('.env.development'), override: true }); + expect(configSpy).toHaveBeenCalledWith({ + path: expect.stringContaining('.env.development'), + override: true, + quiet: true, + }); expect(expandSpy).toHaveBeenCalled(); }); test('it should load .env..local file', () => { loadEnvConfig('test'); - expect(configSpy).toHaveBeenCalledWith({ path: expect.stringContaining('.env.test.local'), override: true }); + expect(configSpy).toHaveBeenCalledWith({ + path: expect.stringContaining('.env.test.local'), + override: true, + quiet: true, + }); expect(expandSpy).toHaveBeenCalled(); }); }); diff --git a/src/Config/ConfigLoader.ts b/src/Config/ConfigLoader.ts index 921a8f0..9c928d4 100644 --- a/src/Config/ConfigLoader.ts +++ b/src/Config/ConfigLoader.ts @@ -17,6 +17,7 @@ function loadEnvFile(fileName: string): void { const expandedOptions = dotenv.config({ path: path.resolve(rootDir, fileName), override: true, + quiet: true, }); dotenvExpand.expand(expandedOptions); From 6f5cd26f91587a9417d69c2170073e9222f16f3d Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 20:19:25 +0100 Subject: [PATCH 10/12] chore: fix typo --- tests/request-props.e2e.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/request-props.e2e.test.ts b/tests/request-props.e2e.test.ts index fde660d..42967be 100644 --- a/tests/request-props.e2e.test.ts +++ b/tests/request-props.e2e.test.ts @@ -28,7 +28,7 @@ class MyController { } } -describe('Request Body E2E Test', () => { +describe('Request Properties E2E Test', () => { test('access request props', async () => { const agent = createTestAgent({ controllers: [MyController] }); From 0a262e39daf9dbf8d3ad04ecc2e6918c0084d5bf Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 20:19:44 +0100 Subject: [PATCH 11/12] chore: add test for async event subscriber --- tests/event-subscribers.e2e.test.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/event-subscribers.e2e.test.ts b/tests/event-subscribers.e2e.test.ts index cab0077..ff21dfa 100644 --- a/tests/event-subscribers.e2e.test.ts +++ b/tests/event-subscribers.e2e.test.ts @@ -10,8 +10,8 @@ class MyController { } } -describe('Event subscribers e2e Test', () => { - test('subscribe to and event', async () => { +describe('Event subscribers E2E Test', () => { + test('subscribe to an event', async () => { const handler = vi.fn(); const agent = createTestAgent({ controllers: [MyController], @@ -36,4 +36,19 @@ describe('Event subscribers e2e Test', () => { expect(handler1).toHaveBeenCalledWith({ data: 'event-data' }); expect(handler2).toHaveBeenCalledWith({ data: 'event-data' }); }); + + test('register async event subscriber', async () => { + const internalFn = vi.fn(); + const asyncSubscriber = async (data: string): Promise => { + await internalFn(data); + }; + const agent = createTestAgent({ + controllers: [MyController], + eventSubscribers: { myEvent: asyncSubscriber }, + } as unknown as KoalaConfig); + + await agent.get('/publish-event'); + + expect(internalFn).toHaveBeenCalledWith({ data: 'event-data' }); + }); }); From 20bc77935bdb16df4f310b1d69dc7a0b4a5bc58f Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sun, 28 Dec 2025 20:42:06 +0100 Subject: [PATCH 12/12] chore: test non parsed body --- tests/request-props.e2e.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/request-props.e2e.test.ts b/tests/request-props.e2e.test.ts index 42967be..bc74de4 100644 --- a/tests/request-props.e2e.test.ts +++ b/tests/request-props.e2e.test.ts @@ -1,3 +1,4 @@ +import getRawBody from 'raw-body'; import { describe, expect, test } from 'vitest'; import { createTestAgent, type HttpRequest, type HttpScope, Route, UploadedFile } from '../src'; @@ -26,6 +27,12 @@ class MyController { uploadedFileName: scope.request.files.avatar.originalFilename, }; } + + @Route({ method: 'POST', path: '/non-parsed-body', options: { parseBody: false } }) + async nonParsedBody(scope: HttpScope): Promise { + const rawBody = await getRawBody(scope.request.req, { encoding: 'utf8' }); + scope.response.body = { rawBody }; + } } describe('Request Properties E2E Test', () => { @@ -50,4 +57,15 @@ describe('Request Properties E2E Test', () => { uploadedFileName: 'avatar.png', }); }); + + test('non-parsed body', async () => { + const agent = createTestAgent({ controllers: [MyController] }); + const rawBody = 'raw body content'; + + const response = await agent.post('/non-parsed-body').set('Content-Type', 'text/plain').send(rawBody); + + expect(response.body).toEqual({ + rawBody, + }); + }); });