Skip to content

Commit

Permalink
fix: koa tests [wip]
Browse files Browse the repository at this point in the history
Signed-off-by: seven <zilisheng1996@gmail.com>
  • Loading branch information
Blankll committed Dec 21, 2024
1 parent dd420ba commit 9d2afb8
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 45 deletions.
262 changes: 262 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@
},
"devDependencies": {
"@eslint/js": "^9.12.0",
"@koa/router": "^13.1.0",
"@types/debug": "^4.1.12",
"@types/express": "^5.0.0",
"@types/koa__router": "^12.0.4",
"@types/jest": "^29.5.13",
"@types/koa": "^2.15.0",
"@types/koa__router": "^12.0.4",
"@types/node": "^22.7.4",
"@typescript-eslint/eslint-plugin": "^8.8.0",
"@typescript-eslint/parser": "^8.8.0",
Expand All @@ -68,7 +69,7 @@
"husky": "^9.1.6",
"jest": "^29.7.0",
"koa": "^2.15.3",
"@koa/router": "^13.1.0",
"koa-body": "^6.0.1",
"prettier": "^3.3.3",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
Expand Down
5 changes: 2 additions & 3 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Context, Event } from './types';
import ServerlessRequest from './serverlessRequest';
import url from 'node:url';
import ServerlessResponse from './serverlessResponse';
import { debug } from './common';

// const requestRemoteAddress = (event) => {
Expand All @@ -16,6 +15,7 @@ export const constructFrameworkContext = (event: Event, context: Context) => {
const request = new ServerlessRequest({
method: event.httpMethod,
headers: event.headers,
path: event.path,
body:
event.body !== undefined && event.body !== null
? Buffer.from(event.body, event.isBase64Encoded ? 'base64' : 'utf8')
Expand All @@ -27,7 +27,6 @@ export const constructFrameworkContext = (event: Event, context: Context) => {
}),
isBase64Encoded: event.isBase64Encoded,
});
const response = new ServerlessResponse(request);

return { request, response };
return { request };
};
25 changes: 25 additions & 0 deletions src/framework.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Express } from 'express';
import Application from 'koa';
import ServerlessResponse from './serverlessResponse';
import ServerlessRequest from './serverlessRequest';

// eslint-disable-next-line
const callableFn = (callback: (req: any, res: any) => Promise<void>) => {
return async (request: ServerlessRequest) => {
const response = new ServerlessResponse(request);

callback(request, response);

return response;
};
};

export const constructFramework = (app: Express | Application) => {
if (app instanceof Application) {
return callableFn(app.callback());
} else if (typeof app === 'function') {
return callableFn(app);
} else {
throw new Error(`Unsupported framework ${app}`);
}
};
9 changes: 4 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { Express } from 'express';
import Application from 'koa';
import { ServerlessAdapter } from './types';
import sendRequest from './sendRequest';
import { IncomingHttpHeaders } from 'http';
import { constructFrameworkContext } from './context';
import { buildResponse, waitForStreamComplete } from './transport';
import { constructFramework } from './framework';

const serverlessAdapter: ServerlessAdapter = (app: Express | Application) => {
const serverlessFramework = constructFramework(app);
return async (event, context) => {
const { request, response } = constructFrameworkContext(event, context);
const { request } = constructFrameworkContext(event, context);

try {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
await sendRequest(app, request, response);
const response = await serverlessFramework(request);
await waitForStreamComplete(response);
return buildResponse({ request, response });
} catch (err) {
Expand Down
28 changes: 11 additions & 17 deletions src/serverlessRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const HTTPS_PORT = 443;
interface ServerlessRequestOptions {
method: string;
url: string;
path: string;
headers: { [key: string]: string | number };
body: Buffer | string | undefined;
remoteAddress: string;
Expand All @@ -21,46 +22,39 @@ export default class ServerlessRequest extends IncomingMessage {

isBase64Encoded: boolean;

constructor({
method,
url,
headers,
body,
remoteAddress,
isBase64Encoded,
}: ServerlessRequestOptions) {
constructor(request: ServerlessRequestOptions) {
super({
encrypted: true,
readable: false,
remoteAddress,
remoteAddress: request.remoteAddress,
address: () => ({ port: HTTPS_PORT }),
end: NO_OP,
destroy: NO_OP,
path: request.path,
} as unknown as Socket);

const combinedHeaders = Object.fromEntries(
Object.entries({
...headers,
'content-length': Buffer.byteLength(body ?? '').toString(),
...request.headers,
'content-length': Buffer.byteLength(request.body ?? '').toString(),
}).map(([key, value]) => [key.toLowerCase(), value]),
);

Object.assign(this, {
...request,
complete: true,
httpVersion: '1.1',
httpVersionMajor: '1',
httpVersionMinor: '1',
method,
url,
headers: combinedHeaders,
});

this.body = body;
this.ip = remoteAddress;
this.isBase64Encoded = isBase64Encoded;
this.body = request.body;
this.ip = request.remoteAddress;
this.isBase64Encoded = request.isBase64Encoded;

this._read = () => {
this.push(body);
this.push(request.body);
this.push(null);
};
}
Expand Down
8 changes: 4 additions & 4 deletions src/transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ export const waitForStreamComplete = (stream: Writable): Promise<Writable> => {
}

return new Promise((resolve, reject) => {
stream.once('error', complete);
stream.once('end', complete);
stream.once('finish', complete);

let isComplete = false;

function complete(err?: Error) {
Expand All @@ -31,6 +27,10 @@ export const waitForStreamComplete = (stream: Writable): Promise<Writable> => {
resolve(stream);
}
}

stream.once('error', complete);
stream.once('end', complete);
stream.once('finish', complete);
});
};

Expand Down
21 changes: 7 additions & 14 deletions tests/index-koa.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Koa from 'koa';
import Router from '@koa/router';
import koaBody from 'koa-body';
import serverlessAdapter from '../src';
import { defaultContext, defaultEvent } from './fixtures/fcContext';

Expand All @@ -8,27 +9,26 @@ describe('koa', () => {
let router: Router;
beforeEach(() => {
app = new Koa();
app.use(koaBody());
router = new Router();
});

it('basic middleware should set statusCode and default body', async () => {
router.get('/api/test', (ctx) => {
ctx.status = 200;
ctx.body = 'Hello, world!';
ctx.status = 418;
ctx.body = 'Hello, world koa!';
});
app.use(router.routes());

const response = await serverlessAdapter(app)(defaultEvent, defaultContext);

expect(response.statusCode).toEqual(418);
expect(response.body).toEqual(`I'm a teapot`);
expect(response.body).toEqual('Hello, world koa!');
});

it('basic middleware should get text body', async () => {
router.get('/api/test', (ctx) => {
ctx.status = 200;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
ctx.body = ctx.request.body;
});
app.use(router.routes());
Expand All @@ -53,21 +53,15 @@ describe('koa', () => {
it('basic middleware should get json body', async () => {
router.get('/api/test', (ctx) => {
ctx.status = 200;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
ctx.body = ctx.request.body.hello;
});

const response = await serverlessAdapter(app)(
{
...defaultEvent,
httpMethod: 'GET',
body: JSON.stringify({
hello: 'world',
}),
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ hello: 'world' }),
headers: { 'Content-Type': 'application/json' },
},
defaultContext,
);
Expand All @@ -80,7 +74,6 @@ describe('koa', () => {
router.get('/api/test', (ctx) => {
ctx.status = 200;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
ctx.body = ctx.request.body.hello;
});

Expand Down

0 comments on commit 9d2afb8

Please sign in to comment.