Add CLI and infra test coverage
This commit is contained in:
76
src/commands/up.test.ts
Normal file
76
src/commands/up.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { CliDeps } from "../cli/deps.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { upCommand } from "./up.js";
|
||||
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(() => {
|
||||
throw new Error("exit");
|
||||
}),
|
||||
};
|
||||
|
||||
const makeDeps = (): CliDeps => ({
|
||||
ensurePortAvailable: vi.fn().mockResolvedValue(undefined),
|
||||
readEnv: vi.fn().mockReturnValue({
|
||||
whatsappFrom: "whatsapp:+1555",
|
||||
whatsappSenderSid: "WW",
|
||||
}),
|
||||
ensureBinary: vi.fn().mockResolvedValue(undefined),
|
||||
ensureFunnel: vi.fn().mockResolvedValue(undefined),
|
||||
getTailnetHostname: vi.fn().mockResolvedValue("tailnet-host"),
|
||||
startWebhook: vi.fn().mockResolvedValue({ server: true }),
|
||||
createClient: vi.fn().mockReturnValue({ client: true }),
|
||||
findWhatsappSenderSid: vi.fn().mockResolvedValue("SID123"),
|
||||
updateWebhook: vi.fn().mockResolvedValue(undefined),
|
||||
});
|
||||
|
||||
describe("upCommand", () => {
|
||||
it("throws on invalid port", async () => {
|
||||
await expect(() =>
|
||||
upCommand({ port: "0", path: "/cb" }, makeDeps(), runtime),
|
||||
).rejects.toThrow("Port must be between 1 and 65535");
|
||||
});
|
||||
|
||||
it("performs dry run and returns mock data", async () => {
|
||||
runtime.log.mockClear();
|
||||
const result = await upCommand(
|
||||
{ port: "42873", path: "/cb", dryRun: true },
|
||||
makeDeps(),
|
||||
runtime,
|
||||
);
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
"[dry-run] would enable funnel on port 42873",
|
||||
);
|
||||
expect(result?.publicUrl).toBe("https://dry-run/cb");
|
||||
expect(result?.senderSid).toBeUndefined();
|
||||
});
|
||||
|
||||
it("enables funnel, starts webhook, and updates Twilio", async () => {
|
||||
const deps = makeDeps();
|
||||
const res = await upCommand(
|
||||
{ port: "42873", path: "/hook", verbose: true },
|
||||
deps,
|
||||
runtime,
|
||||
);
|
||||
expect(deps.ensureBinary).toHaveBeenCalledWith(
|
||||
"tailscale",
|
||||
undefined,
|
||||
runtime,
|
||||
);
|
||||
expect(deps.ensureFunnel).toHaveBeenCalled();
|
||||
expect(deps.startWebhook).toHaveBeenCalled();
|
||||
expect(deps.updateWebhook).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
"SID123",
|
||||
"https://tailnet-host/hook",
|
||||
"POST",
|
||||
runtime,
|
||||
);
|
||||
expect(res?.publicUrl).toBe("https://tailnet-host/hook");
|
||||
// waiter is returned to keep the process alive in real use.
|
||||
expect(typeof res?.waiter).toBe("function");
|
||||
});
|
||||
});
|
||||
56
src/commands/webhook.test.ts
Normal file
56
src/commands/webhook.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { CliDeps } from "../cli/deps.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
|
||||
import { webhookCommand } from "./webhook.js";
|
||||
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(() => {
|
||||
throw new Error("exit");
|
||||
}),
|
||||
};
|
||||
|
||||
const deps: CliDeps = {
|
||||
ensurePortAvailable: vi.fn().mockResolvedValue(undefined),
|
||||
startWebhook: vi.fn().mockResolvedValue({ server: true }),
|
||||
};
|
||||
|
||||
describe("webhookCommand", () => {
|
||||
it("throws on invalid port", async () => {
|
||||
await expect(() =>
|
||||
webhookCommand({ port: "70000", path: "/hook" }, deps, runtime),
|
||||
).rejects.toThrow("Port must be between 1 and 65535");
|
||||
});
|
||||
|
||||
it("logs dry run instead of starting server", async () => {
|
||||
runtime.log.mockClear();
|
||||
const res = await webhookCommand(
|
||||
{ port: "42873", path: "/hook", reply: "dry-run" },
|
||||
deps,
|
||||
runtime,
|
||||
);
|
||||
expect(res).toBeUndefined();
|
||||
expect(runtime.log).toHaveBeenCalledWith(
|
||||
"[dry-run] would start webhook on port 42873 path /hook",
|
||||
);
|
||||
});
|
||||
|
||||
it("starts webhook when valid", async () => {
|
||||
const res = await webhookCommand(
|
||||
{ port: "42873", path: "/hook", reply: "ok", verbose: true },
|
||||
deps,
|
||||
runtime,
|
||||
);
|
||||
expect(deps.startWebhook).toHaveBeenCalledWith(
|
||||
42873,
|
||||
"/hook",
|
||||
"ok",
|
||||
true,
|
||||
runtime,
|
||||
);
|
||||
expect(res).toEqual({ server: true });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user