Project Files
src / __tests__ / accounts.test.ts
import { describe, it, expect } from "vitest";
import { getConfiguredAccounts, resolveAccount } from "../accounts";
function makeCfg(overrides: Record<string, string | number> = {}) {
const defaults: Record<string, string | number> = {
account1Label: "Personal",
account1ImapHost: "imap.gmail.com",
account1ImapPort: 993,
account1User: "personal@gmail.com",
account1Password: "pass1",
account1SmtpHost: "smtp.gmail.com",
account1SmtpPort: 587,
account2Label: "Work",
account2ImapHost: "outlook.office365.com",
account2ImapPort: 993,
account2User: "work@company.com",
account2Password: "pass2",
account2SmtpHost: "smtp-mail.outlook.com",
account2SmtpPort: 587,
account3Label: "",
account3ImapHost: "",
account3ImapPort: 993,
account3User: "",
account3Password: "",
account3SmtpHost: "",
account3SmtpPort: 587,
};
const merged = { ...defaults, ...overrides };
return { get: (key: string) => merged[key] ?? "" };
}
// ── getConfiguredAccounts ────────────────────────────────────────────────────
describe("getConfiguredAccounts", () => {
it("returns both configured accounts", () => {
const accounts = getConfiguredAccounts(makeCfg());
expect(accounts).toHaveLength(2);
expect(accounts[0].label).toBe("Personal");
expect(accounts[1].label).toBe("Work");
});
it("returns empty array when nothing configured", () => {
const cfg = { get: () => "" };
expect(getConfiguredAccounts(cfg)).toHaveLength(0);
});
it("skips account with missing host", () => {
const accounts = getConfiguredAccounts(makeCfg({ account1ImapHost: "" }));
expect(accounts).toHaveLength(1);
expect(accounts[0].label).toBe("Work");
});
it("skips account with missing user", () => {
const accounts = getConfiguredAccounts(makeCfg({ account2User: "" }));
expect(accounts).toHaveLength(1);
expect(accounts[0].label).toBe("Personal");
});
it("skips account with missing password", () => {
const accounts = getConfiguredAccounts(makeCfg({ account1Password: "" }));
expect(accounts).toHaveLength(1);
expect(accounts[0].slot).toBe(2);
});
it("sets smtp to null when smtpHost is blank", () => {
const accounts = getConfiguredAccounts(makeCfg({ account1SmtpHost: "" }));
expect(accounts[0].smtp).toBeNull();
});
it("includes smtp when smtpHost is set", () => {
const accounts = getConfiguredAccounts(makeCfg());
expect(accounts[0].smtp).not.toBeNull();
expect(accounts[0].smtp?.host).toBe("smtp.gmail.com");
});
it("uses 'Account N' as label when label is blank", () => {
const accounts = getConfiguredAccounts(makeCfg({ account1Label: "" }));
expect(accounts[0].label).toBe("Account 1");
});
it("correctly maps imap config fields", () => {
const accounts = getConfiguredAccounts(makeCfg());
expect(accounts[0].imap).toEqual({
host: "imap.gmail.com",
port: 993,
user: "personal@gmail.com",
password: "pass1",
});
});
});
// ── resolveAccount ───────────────────────────────────────────────────────────
describe("resolveAccount", () => {
it("blank returns first account", () => {
expect(resolveAccount(makeCfg(), "").label).toBe("Personal");
});
it('"1" returns account 1', () => {
expect(resolveAccount(makeCfg(), "1").label).toBe("Personal");
});
it('"2" returns account 2', () => {
expect(resolveAccount(makeCfg(), "2").label).toBe("Work");
});
it("label match is case-insensitive", () => {
expect(resolveAccount(makeCfg(), "work").label).toBe("Work");
expect(resolveAccount(makeCfg(), "PERSONAL").label).toBe("Personal");
});
it('"default" returns first account', () => {
expect(resolveAccount(makeCfg(), "default").label).toBe("Personal");
});
it("throws for unconfigured slot", () => {
expect(() => resolveAccount(makeCfg(), "3")).toThrow("Account 3 is not configured");
});
it("throws for unknown label", () => {
expect(() => resolveAccount(makeCfg(), "Nonexistent")).toThrow("not found");
});
it("throws when no accounts configured", () => {
const cfg = { get: () => "" };
expect(() => resolveAccount(cfg, "")).toThrow("No email accounts configured");
});
it("error message lists available accounts", () => {
expect(() => resolveAccount(makeCfg(), "Ghost")).toThrow("1 (Personal)");
});
});