test(httpkernel): enforce compile-time validation for signatures

- Replace runtime 500 errors with compile-time validation for invalid
  middleware and handler signatures using `assertThrows`
- Improve test clarity by explicitly checking for expected exceptions
  and error messages
This commit is contained in:
2025-05-27 14:50:01 +02:00
parent aea3fb45e7
commit 731bba22d8

View File

@@ -1,4 +1,7 @@
import { assertEquals } from 'https://deno.land/std@0.204.0/assert/mod.ts'; import {
assertEquals,
assertThrows,
} from 'https://deno.land/std@0.204.0/assert/mod.ts';
import { HttpKernel } from '../HttpKernel.ts'; import { HttpKernel } from '../HttpKernel.ts';
import type { IRouteDefinition } from '../Interfaces/mod.ts'; import type { IRouteDefinition } from '../Interfaces/mod.ts';
@@ -88,30 +91,32 @@ Deno.test('HttpKernel: middleware short-circuits pipeline', async () => {
assertEquals(calls, ['mw1']); assertEquals(calls, ['mw1']);
}); });
Deno.test('HttpKernel: invalid middleware or handler signature triggers 500', async () => { Deno.test('HttpKernel: invalid middleware or handler signature throws at compile time', () => {
const kernel = new HttpKernel(); const kernel = new HttpKernel();
// Middleware with wrong signature (missing ctx, next) // Middleware with wrong signature (missing ctx, next)
kernel.route({ method: 'GET', path: '/bad-mw' }) assertThrows(
// @ts-expect-error invalid middleware () => {
.middleware(() => new Response('invalid')) kernel.route({ method: 'GET', path: '/bad-mw' })
.handle((_ctx) => Promise.resolve(new Response('ok'))); // @ts-expect-error invalid middleware
.middleware(() => new Response('invalid'))
const res1 = await kernel.handle(new Request('http://localhost/bad-mw')); .handle((_ctx) => Promise.resolve(new Response('ok')));
assertEquals(res1.status, 500); },
assertEquals(await res1.text(), 'Internal Server Error'); TypeError,
'Middleware at index 0 is not a valid function.',
);
// Handler with wrong signature (no ctx) // Handler with wrong signature (no ctx)
kernel.route({ method: 'GET', path: '/bad-handler' }) assertThrows(
.middleware(async (_ctx, next) => await next()) () => {
// @ts-expect-error invalid handler kernel.route({ method: 'GET', path: '/bad-handler' })
.handle(() => new Response('invalid')); .middleware(async (_ctx, next) => await next())
// @ts-expect-error invalid handler
const res2 = await kernel.handle( .handle(() => new Response('invalid'));
new Request('http://localhost/bad-handler'), },
TypeError,
'Route handler must be a function returning a Promise<Response>.',
); );
assertEquals(res2.status, 500);
assertEquals(await res2.text(), 'Internal Server Error');
}); });
Deno.test('HttpKernel: 404 for unmatched route', async () => { Deno.test('HttpKernel: 404 for unmatched route', async () => {
@@ -124,7 +129,7 @@ Deno.test('HttpKernel: skips route with wrong method', async () => {
const kernel = new HttpKernel(); const kernel = new HttpKernel();
kernel.route({ method: 'POST', path: '/only-post' }) kernel.route({ method: 'POST', path: '/only-post' })
.handle(() => Promise.resolve(new Response('nope'))); .handle((_ctx) => Promise.resolve(new Response('nope')));
const res = await kernel.handle( const res = await kernel.handle(
new Request('http://localhost/only-post', { method: 'GET' }), new Request('http://localhost/only-post', { method: 'GET' }),
@@ -152,7 +157,7 @@ Deno.test('HttpKernel: handler throws → error propagates', async () => {
const kernel = new HttpKernel(); const kernel = new HttpKernel();
kernel.route({ method: 'GET', path: '/throw' }) kernel.route({ method: 'GET', path: '/throw' })
.handle(() => { .handle((_ctx) => {
throw new Error('fail!'); throw new Error('fail!');
}); });