184 lines
5.6 KiB
TypeScript
184 lines
5.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
createStackConfig,
|
|
formatServiceLogs,
|
|
getDefaultTemporalCandidates,
|
|
resolveTemporalCli,
|
|
selectServicesForLogs,
|
|
} from "../../scripts/dev-stack/stack.mjs";
|
|
|
|
describe("createStackConfig", () => {
|
|
it("derives frontend and sibling backend paths from the workspace root", () => {
|
|
const config = createStackConfig("/Volumes/DockCase/codes/auto-virtual-tryon-frontend");
|
|
|
|
expect(config.frontendRoot).toBe("/Volumes/DockCase/codes/auto-virtual-tryon-frontend");
|
|
expect(config.backendRoot).toBe("/Volumes/DockCase/codes/auto-virtual-tryon");
|
|
expect(config.runtimeRoot).toBe(
|
|
"/Volumes/DockCase/codes/auto-virtual-tryon-frontend/.dev-stack",
|
|
);
|
|
expect(config.temporalDatabaseFile).toBe(
|
|
"/Volumes/DockCase/codes/auto-virtual-tryon-frontend/.dev-stack/temporal-cli-dev.db",
|
|
);
|
|
});
|
|
|
|
it("builds the expected service commands", () => {
|
|
const config = createStackConfig("/Volumes/DockCase/codes/auto-virtual-tryon-frontend");
|
|
|
|
expect(config.services).toEqual([
|
|
{
|
|
key: "temporal",
|
|
cwd: "/Volumes/DockCase/codes/auto-virtual-tryon-frontend/.dev-stack",
|
|
port: 7233,
|
|
command: [
|
|
"__TEMPORAL_CLI__",
|
|
"server",
|
|
"start-dev",
|
|
"--ip",
|
|
"127.0.0.1",
|
|
"--port",
|
|
"7233",
|
|
"--headless",
|
|
"--db-filename",
|
|
"/Volumes/DockCase/codes/auto-virtual-tryon-frontend/.dev-stack/temporal-cli-dev.db",
|
|
],
|
|
},
|
|
{
|
|
key: "backend-api",
|
|
cwd: "/Volumes/DockCase/codes/auto-virtual-tryon",
|
|
port: 8000,
|
|
command: [
|
|
"/Volumes/DockCase/codes/auto-virtual-tryon/.venv/bin/python",
|
|
"-m",
|
|
"uvicorn",
|
|
"app.main:app",
|
|
"--host",
|
|
"127.0.0.1",
|
|
"--port",
|
|
"8000",
|
|
],
|
|
},
|
|
{
|
|
key: "backend-worker",
|
|
cwd: "/Volumes/DockCase/codes/auto-virtual-tryon",
|
|
port: null,
|
|
command: [
|
|
"/Volumes/DockCase/codes/auto-virtual-tryon/.venv/bin/python",
|
|
"-m",
|
|
"app.workers.runner",
|
|
],
|
|
},
|
|
{
|
|
key: "frontend",
|
|
cwd: "/Volumes/DockCase/codes/auto-virtual-tryon-frontend",
|
|
port: 3000,
|
|
command: [
|
|
"/Volumes/DockCase/codes/auto-virtual-tryon-frontend/node_modules/.bin/next",
|
|
"dev",
|
|
"--hostname",
|
|
"127.0.0.1",
|
|
"--port",
|
|
"3000",
|
|
],
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("resolveTemporalCli", () => {
|
|
it("prefers a CLI already available on PATH", () => {
|
|
const resolved = resolveTemporalCli({
|
|
pathLookupResult: "/usr/local/bin/temporal",
|
|
candidatePaths: ["/tmp/temporal-sdk-python-1.24.0"],
|
|
existingPaths: new Set(["/usr/local/bin/temporal", "/tmp/temporal-sdk-python-1.24.0"]),
|
|
});
|
|
|
|
expect(resolved).toBe("/usr/local/bin/temporal");
|
|
});
|
|
|
|
it("falls back to a downloaded SDK binary when PATH does not contain temporal", () => {
|
|
const resolved = resolveTemporalCli({
|
|
pathLookupResult: null,
|
|
candidatePaths: ["/tmp/temporal-sdk-python-1.24.0", "/tmp/temporal-cli"],
|
|
existingPaths: new Set(["/tmp/temporal-sdk-python-1.24.0"]),
|
|
});
|
|
|
|
expect(resolved).toBe("/tmp/temporal-sdk-python-1.24.0");
|
|
});
|
|
|
|
it("returns null when no temporal binary is available", () => {
|
|
const resolved = resolveTemporalCli({
|
|
pathLookupResult: null,
|
|
candidatePaths: ["/tmp/temporal-sdk-python-1.24.0"],
|
|
existingPaths: new Set<string>(),
|
|
});
|
|
|
|
expect(resolved).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("getDefaultTemporalCandidates", () => {
|
|
it("includes the known SDK cache binary names under the temp directory", () => {
|
|
expect(getDefaultTemporalCandidates("/var/folders/example/T")).toEqual([
|
|
"/var/folders/example/T/temporal-sdk-python-1.24.0",
|
|
"/var/folders/example/T/temporal-sdk-python-1.25.0",
|
|
"/var/folders/example/T/temporal-sdk-python-1.26.0",
|
|
"/var/folders/example/T/temporal-cli",
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("selectServicesForLogs", () => {
|
|
it("returns every service when no filter is provided", () => {
|
|
const config = createStackConfig("/Volumes/DockCase/codes/auto-virtual-tryon-frontend");
|
|
|
|
expect(
|
|
selectServicesForLogs(config.services, null).map((service: { key: string }) => service.key),
|
|
).toEqual(["temporal", "backend-api", "backend-worker", "frontend"]);
|
|
});
|
|
|
|
it("filters to a single service key", () => {
|
|
const config = createStackConfig("/Volumes/DockCase/codes/auto-virtual-tryon-frontend");
|
|
|
|
expect(
|
|
selectServicesForLogs(config.services, "frontend").map((service: { key: string }) => service.key),
|
|
).toEqual(["frontend"]);
|
|
});
|
|
|
|
it("throws a helpful error for an unknown service", () => {
|
|
const config = createStackConfig("/Volumes/DockCase/codes/auto-virtual-tryon-frontend");
|
|
|
|
expect(() => selectServicesForLogs(config.services, "foo")).toThrow(
|
|
"Unknown service \"foo\". Expected one of: temporal, backend-api, backend-worker, frontend",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("formatServiceLogs", () => {
|
|
it("formats sections with stable headers and preserves line order", () => {
|
|
const output = formatServiceLogs([
|
|
{
|
|
key: "frontend",
|
|
logFilePath: "/tmp/frontend.log",
|
|
lines: ["> dev", "ready"],
|
|
},
|
|
{
|
|
key: "backend-api",
|
|
logFilePath: "/tmp/backend-api.log",
|
|
lines: [],
|
|
},
|
|
]);
|
|
|
|
expect(output).toBe(
|
|
[
|
|
"--- frontend (/tmp/frontend.log) ---",
|
|
"> dev",
|
|
"ready",
|
|
"",
|
|
"--- backend-api (/tmp/backend-api.log) ---",
|
|
"(log file is empty)",
|
|
].join("\n"),
|
|
);
|
|
});
|
|
});
|