winterspec
Version:
Write Winter-CG compatible routes with filesystem routing and tons of features
85 lines (84 loc) • 3.16 kB
JavaScript
import path from "node:path";
import hash from "object-hash";
import getPort from "@ava/get-port";
import { registerSharedWorker } from "ava/plugin";
import { devServer } from "../../dev/dev.js";
import { loadConfig } from "../../config/index.js";
import { fileURLToPath } from "node:url";
import { once } from "node:events";
const getWorker = async (initialData) => {
const key = hash(initialData);
const dirname = path.dirname(fileURLToPath(import.meta.url));
const filename = new URL(`file:${path.resolve(dirname, "worker-wrapper.ts")}#${key}`);
if (process.env.IS_TESTING_EDGESPEC) {
const { registerSharedTypeScriptWorker } = await import("ava-typescript-worker");
const normalizedCrossPlatformFilePath = process.platform === "win32"
? { ...filename, pathname: filename.pathname.replace("/", "") }
: filename;
return registerSharedTypeScriptWorker({
filename: normalizedCrossPlatformFilePath,
initialData: initialData,
});
}
return registerSharedWorker({
filename,
initialData: initialData,
supportedProtocols: ["ava-4"],
});
};
/**
* Start a test dev server for AVA. This works in watch mode too!
* Check out the [docs](https://github.com/tscircuit/winterspec/blob/main/docs/testing.md) for more information.
*
* @param t test context from AVA
*/
export const getTestServer = async (t, options) => {
const rootDirectory = options?.rootDirectory ?? process.cwd();
const worker = await getWorker({
rootDirectory,
});
const [port] = await Promise.all([getPort(), worker.available]);
let httpServerRpcCallback;
const onReceivedBuildResult = (build) => {
if (build.type === "failure") {
console.error(build.errorMessage);
t.fail("Failed to build");
}
};
const serverFixture = await devServer.headless.startServer({
port,
config: await loadConfig(rootDirectory),
rpcChannel: {
post: (data) => worker.publish(data),
on: (data) => {
httpServerRpcCallback = data;
},
},
middleware: options?.middleware ?? [],
onBuildEnd(build) {
onReceivedBuildResult(build);
},
});
const messageHandlerAbortController = new AbortController();
const messageHandlerPromise = Promise.race([
once(messageHandlerAbortController.signal, "abort"),
(async () => {
for await (const msg of worker.subscribe()) {
httpServerRpcCallback(msg.data);
if (messageHandlerAbortController.signal.aborted) {
break;
}
}
})(),
]);
t.teardown(async () => {
messageHandlerAbortController.abort();
await messageHandlerPromise;
await serverFixture.stop();
});
// Calling .getBuildResult() here handles the case where the build is already ready but the build errored and we need to log & cancel the test
onReceivedBuildResult(await serverFixture.getBuildResult());
return {
port,
};
};