140 lines
3.9 KiB
TypeScript
140 lines
3.9 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { createMockTwilio } from "../test/mocks/twilio.js";
|
|
import { statusCommand } from "./commands/status.js";
|
|
import { createDefaultDeps } from "./index.js";
|
|
import * as providerWeb from "./provider-web.js";
|
|
import { defaultRuntime } from "./runtime.js";
|
|
|
|
vi.mock("twilio", () => {
|
|
const { factory } = createMockTwilio();
|
|
return { default: factory };
|
|
});
|
|
|
|
import * as index from "./index.js";
|
|
import * as provider from "./provider-web.js";
|
|
|
|
beforeEach(() => {
|
|
index.program.exitOverride();
|
|
process.env.TWILIO_ACCOUNT_SID = "AC123";
|
|
process.env.TWILIO_WHATSAPP_FROM = "whatsapp:+15551234567";
|
|
process.env.TWILIO_AUTH_TOKEN = "token";
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("CLI commands", () => {
|
|
it("exposes login command", () => {
|
|
const names = index.program.commands.map((c) => c.name());
|
|
expect(names).toContain("login");
|
|
});
|
|
|
|
it("send command routes to web provider", async () => {
|
|
const sendWeb = vi.spyOn(provider, "sendMessageWeb").mockResolvedValue();
|
|
await index.program.parseAsync(
|
|
[
|
|
"send",
|
|
"--to",
|
|
"+1555",
|
|
"--message",
|
|
"hi",
|
|
"--provider",
|
|
"web",
|
|
"--wait",
|
|
"0",
|
|
],
|
|
{ from: "user" },
|
|
);
|
|
expect(sendWeb).toHaveBeenCalled();
|
|
});
|
|
|
|
it("send command uses twilio path when provider=twilio", async () => {
|
|
const twilio = (await import("twilio")).default;
|
|
twilio._client.messages.create.mockResolvedValue({ sid: "SM1" });
|
|
const wait = vi.spyOn(index, "waitForFinalStatus").mockResolvedValue();
|
|
await index.program.parseAsync(
|
|
["send", "--to", "+1555", "--message", "hi", "--wait", "0"],
|
|
{ from: "user" },
|
|
);
|
|
expect(twilio._client.messages.create).toHaveBeenCalled();
|
|
expect(wait).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("send command supports dry-run and skips sending", async () => {
|
|
const twilio = (await import("twilio")).default;
|
|
const wait = vi.spyOn(index, "waitForFinalStatus").mockResolvedValue();
|
|
await index.program.parseAsync(
|
|
["send", "--to", "+1555", "--message", "hi", "--wait", "0", "--dry-run"],
|
|
{ from: "user" },
|
|
);
|
|
expect(twilio._client.messages.create).not.toHaveBeenCalled();
|
|
expect(wait).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("send command outputs JSON when requested", async () => {
|
|
const twilio = (await import("twilio")).default;
|
|
twilio._client.messages.create.mockResolvedValue({ sid: "SMJSON" });
|
|
const logSpy = vi.spyOn(defaultRuntime, "log");
|
|
await index.program.parseAsync(
|
|
["send", "--to", "+1555", "--message", "hi", "--wait", "0", "--json"],
|
|
{ from: "user" },
|
|
);
|
|
expect(logSpy).toHaveBeenCalledWith(
|
|
expect.stringContaining('"sid": "SMJSON"'),
|
|
);
|
|
});
|
|
|
|
it("login command calls web login", async () => {
|
|
const spy = vi.spyOn(providerWeb, "loginWeb").mockResolvedValue();
|
|
await index.program.parseAsync(["login"], { from: "user" });
|
|
expect(spy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("status command prints JSON", async () => {
|
|
const twilio = (await import("twilio")).default;
|
|
twilio._client.messages.list
|
|
.mockResolvedValueOnce([
|
|
{
|
|
sid: "1",
|
|
status: "delivered",
|
|
direction: "inbound",
|
|
dateCreated: new Date("2024-01-01T00:00:00Z"),
|
|
from: "a",
|
|
to: "b",
|
|
body: "hi",
|
|
errorCode: null,
|
|
errorMessage: null,
|
|
},
|
|
])
|
|
.mockResolvedValueOnce([
|
|
{
|
|
sid: "2",
|
|
status: "sent",
|
|
direction: "outbound-api",
|
|
dateCreated: new Date("2024-01-02T00:00:00Z"),
|
|
from: "b",
|
|
to: "a",
|
|
body: "yo",
|
|
errorCode: null,
|
|
errorMessage: null,
|
|
},
|
|
]);
|
|
const runtime = {
|
|
...defaultRuntime,
|
|
log: vi.fn(),
|
|
error: vi.fn(),
|
|
exit: ((code: number) => {
|
|
throw new Error(`exit ${code}`);
|
|
}) as (code: number) => never,
|
|
};
|
|
await statusCommand(
|
|
{ limit: "1", lookback: "10", json: true },
|
|
createDefaultDeps(),
|
|
runtime,
|
|
);
|
|
expect(runtime.log).toHaveBeenCalled();
|
|
});
|
|
});
|