mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-17 21:06:04 +00:00
refactored adapters to run test suites (#126)
* refactored adapters to run test suites * fix bun version for tests * added missing adapter tests and refactored examples to use `bknd.config.ts` where applicable
This commit is contained in:
@@ -5,6 +5,15 @@ export * from "./node.adapter";
|
||||
export { StorageLocalAdapter, type LocalAdapterConfig };
|
||||
export { nodeTestRunner } from "./test";
|
||||
|
||||
let registered = false;
|
||||
export function registerLocalMediaAdapter() {
|
||||
registries.media.register("local", StorageLocalAdapter);
|
||||
if (!registered) {
|
||||
registries.media.register("local", StorageLocalAdapter);
|
||||
registered = true;
|
||||
}
|
||||
|
||||
return (config: Partial<LocalAdapterConfig> = {}) => {
|
||||
const adapter = new StorageLocalAdapter(config);
|
||||
return adapter.toJSON(true);
|
||||
};
|
||||
}
|
||||
|
||||
15
app/src/adapter/node/node.adapter.native-spec.ts
Normal file
15
app/src/adapter/node/node.adapter.native-spec.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { describe, before, after } from "node:test";
|
||||
import * as node from "./node.adapter";
|
||||
import { adapterTestSuite } from "adapter/adapter-test-suite";
|
||||
import { nodeTestRunner } from "adapter/node";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
|
||||
before(() => disableConsoleLog());
|
||||
after(enableConsoleLog);
|
||||
|
||||
describe("node adapter", () => {
|
||||
adapterTestSuite(nodeTestRunner, {
|
||||
makeApp: node.createApp,
|
||||
makeHandler: node.createHandler,
|
||||
});
|
||||
});
|
||||
15
app/src/adapter/node/node.adapter.spec.ts
Normal file
15
app/src/adapter/node/node.adapter.spec.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { afterAll, beforeAll, describe } from "bun:test";
|
||||
import * as node from "./node.adapter";
|
||||
import { adapterTestSuite } from "adapter/adapter-test-suite";
|
||||
import { bunTestRunner } from "adapter/bun/test";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
afterAll(enableConsoleLog);
|
||||
|
||||
describe("node adapter (bun)", () => {
|
||||
adapterTestSuite(bunTestRunner, {
|
||||
makeApp: node.createApp,
|
||||
makeHandler: node.createHandler,
|
||||
});
|
||||
});
|
||||
@@ -2,11 +2,11 @@ import path from "node:path";
|
||||
import { serve as honoServe } from "@hono/node-server";
|
||||
import { serveStatic } from "@hono/node-server/serve-static";
|
||||
import { registerLocalMediaAdapter } from "adapter/node/index";
|
||||
import type { App } from "bknd";
|
||||
import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
|
||||
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter";
|
||||
import { config as $config } from "bknd/core";
|
||||
|
||||
export type NodeBkndConfig = RuntimeBkndConfig & {
|
||||
type NodeEnv = NodeJS.ProcessEnv;
|
||||
export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & {
|
||||
port?: number;
|
||||
hostname?: string;
|
||||
listener?: Parameters<typeof honoServe>[1];
|
||||
@@ -14,14 +14,11 @@ export type NodeBkndConfig = RuntimeBkndConfig & {
|
||||
relativeDistPath?: string;
|
||||
};
|
||||
|
||||
export function serve({
|
||||
distPath,
|
||||
relativeDistPath,
|
||||
port = $config.server.default_port,
|
||||
hostname,
|
||||
listener,
|
||||
...config
|
||||
}: NodeBkndConfig = {}) {
|
||||
export async function createApp<Env = NodeEnv>(
|
||||
{ distPath, relativeDistPath, ...config }: NodeBkndConfig<Env> = {},
|
||||
args: Env = {} as Env,
|
||||
opts?: RuntimeOptions,
|
||||
) {
|
||||
const root = path.relative(
|
||||
process.cwd(),
|
||||
path.resolve(distPath ?? relativeDistPath ?? "./node_modules/bknd/dist", "static"),
|
||||
@@ -30,23 +27,39 @@ export function serve({
|
||||
console.warn("relativeDistPath is deprecated, please use distPath instead");
|
||||
}
|
||||
|
||||
let app: App;
|
||||
registerLocalMediaAdapter();
|
||||
return await createRuntimeApp(
|
||||
{
|
||||
...config,
|
||||
serveStatic: serveStatic({ root }),
|
||||
},
|
||||
// @ts-ignore
|
||||
args ?? { env: process.env },
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
export function createHandler<Env = NodeEnv>(
|
||||
config: NodeBkndConfig<Env> = {},
|
||||
args: Env = {} as Env,
|
||||
opts?: RuntimeOptions,
|
||||
) {
|
||||
return async (req: Request) => {
|
||||
const app = await createApp(config, args ?? (process.env as Env), opts);
|
||||
return app.fetch(req);
|
||||
};
|
||||
}
|
||||
|
||||
export function serve<Env = NodeEnv>(
|
||||
{ port = $config.server.default_port, hostname, listener, ...config }: NodeBkndConfig<Env> = {},
|
||||
args: Env = {} as Env,
|
||||
opts?: RuntimeOptions,
|
||||
) {
|
||||
honoServe(
|
||||
{
|
||||
port,
|
||||
hostname,
|
||||
fetch: async (req: Request) => {
|
||||
if (!app) {
|
||||
registerLocalMediaAdapter();
|
||||
app = await createRuntimeApp({
|
||||
...config,
|
||||
serveStatic: serveStatic({ root }),
|
||||
});
|
||||
}
|
||||
|
||||
return app.fetch(req);
|
||||
},
|
||||
fetch: createHandler(config, args, opts),
|
||||
},
|
||||
(connInfo) => {
|
||||
console.log(`Server is running on http://localhost:${connInfo.port}`);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { StorageLocalAdapter } from "./StorageLocalAdapter";
|
||||
// @ts-ignore
|
||||
import { assetsPath, assetsTmpPath } from "../../../../__test__/helper";
|
||||
import { adapterTestSuite } from "media/storage/adapters/adapter-test-suite";
|
||||
import { bunTestRunner } from "adapter/bun/test";
|
||||
|
||||
describe("StorageLocalAdapter (bun)", async () => {
|
||||
const adapter = new StorageLocalAdapter({
|
||||
@@ -10,5 +11,5 @@ describe("StorageLocalAdapter (bun)", async () => {
|
||||
});
|
||||
|
||||
const file = Bun.file(`${assetsPath}/image.png`);
|
||||
await adapterTestSuite({ test, expect }, adapter, file);
|
||||
await adapterTestSuite(bunTestRunner, adapter, file);
|
||||
});
|
||||
|
||||
@@ -7,14 +7,14 @@ export const localAdapterConfig = Type.Object(
|
||||
{
|
||||
path: Type.String({ default: "./" }),
|
||||
},
|
||||
{ title: "Local", description: "Local file system storage" },
|
||||
{ title: "Local", description: "Local file system storage", additionalProperties: false },
|
||||
);
|
||||
export type LocalAdapterConfig = Static<typeof localAdapterConfig>;
|
||||
|
||||
export class StorageLocalAdapter extends StorageAdapter {
|
||||
private config: LocalAdapterConfig;
|
||||
|
||||
constructor(config: any) {
|
||||
constructor(config: Partial<LocalAdapterConfig> = {}) {
|
||||
super();
|
||||
this.config = parse(localAdapterConfig, config);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,17 @@ import nodeAssert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import type { Matcher, Test, TestFn, TestRunner } from "core/test";
|
||||
|
||||
// Track mock function calls
|
||||
const mockCalls = new WeakMap<Function, number>();
|
||||
function createMockFunction<T extends (...args: any[]) => any>(fn: T): T {
|
||||
const mockFn = (...args: Parameters<T>) => {
|
||||
const currentCalls = mockCalls.get(mockFn) || 0;
|
||||
mockCalls.set(mockFn, currentCalls + 1);
|
||||
return fn(...args);
|
||||
};
|
||||
return mockFn as T;
|
||||
}
|
||||
|
||||
const nodeTestMatcher = <T = unknown>(actual: T, parentFailMsg?: string) =>
|
||||
({
|
||||
toEqual: (expected: T, failMsg = parentFailMsg) => {
|
||||
@@ -23,6 +34,18 @@ const nodeTestMatcher = <T = unknown>(actual: T, parentFailMsg?: string) =>
|
||||
const e = Array.isArray(expected) ? expected : [expected];
|
||||
nodeAssert.ok(e.includes(actual), failMsg);
|
||||
},
|
||||
toHaveBeenCalled: (failMsg = parentFailMsg) => {
|
||||
const calls = mockCalls.get(actual as Function) || 0;
|
||||
nodeAssert.ok(calls > 0, failMsg || "Expected function to have been called at least once");
|
||||
},
|
||||
toHaveBeenCalledTimes: (expected: number, failMsg = parentFailMsg) => {
|
||||
const calls = mockCalls.get(actual as Function) || 0;
|
||||
nodeAssert.strictEqual(
|
||||
calls,
|
||||
expected,
|
||||
failMsg || `Expected function to have been called ${expected} times`,
|
||||
);
|
||||
},
|
||||
}) satisfies Matcher<T>;
|
||||
|
||||
const nodeTestResolverProxy = <T = unknown>(
|
||||
@@ -63,6 +86,7 @@ nodeTest.skipIf = (condition: boolean): Test => {
|
||||
|
||||
export const nodeTestRunner: TestRunner = {
|
||||
test: nodeTest,
|
||||
mock: createMockFunction,
|
||||
expect: <T = unknown>(actual?: T, failMsg?: string) => ({
|
||||
...nodeTestMatcher(actual, failMsg),
|
||||
resolves: nodeTestResolverProxy(actual as Promise<T>, {
|
||||
|
||||
Reference in New Issue
Block a user