Repository navigation
feat(mail): --columns, --format flags + centralized column definitions #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
9ac29d9
3744e08
838ccab
ba10dfe
7664ddc
a92e27f
a8a6bf5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| import { describe, expect, it } from "bun:test"; | ||
| import { SafeJSON } from "@app/utils/json"; | ||
| import { runTool, stripAnsi } from "./helpers"; | ||
|
|
||
| describe("tools macos mail", () => { | ||
| describe("help", () => { | ||
| it("--help exits 0", async () => { | ||
| const r = await runTool(["macos", "mail", "--help"]); | ||
| expect(r.exitCode).toBe(0); | ||
| }); | ||
|
|
||
| it("list --help exits 0 and mentions --columns, --format, --limit", async () => { | ||
| const r = await runTool(["macos", "mail", "list", "--help"]); | ||
| expect(r.exitCode).toBe(0); | ||
| const out = stripAnsi(r.stdout); | ||
|
|
||
| expect(out).toContain("--columns"); | ||
| expect(out).toContain("--format"); | ||
| expect(out).toContain("--limit"); | ||
| }); | ||
|
|
||
| it("search --help exits 0 and mentions --columns, --format", async () => { | ||
| const r = await runTool(["macos", "mail", "search", "--help"]); | ||
| expect(r.exitCode).toBe(0); | ||
| const out = stripAnsi(r.stdout); | ||
|
|
||
| expect(out).toContain("--columns"); | ||
| expect(out).toContain("--format"); | ||
| }); | ||
| }); | ||
|
|
||
| describe("list --help column names", () => { | ||
| const ALL_COLUMNS = [ | ||
| "date", | ||
| "from", | ||
| "fromEmail", | ||
| "to", | ||
| "toEmail", | ||
| "cc", | ||
| "subject", | ||
| "mailbox", | ||
| "account", | ||
| "read", | ||
| "flagged", | ||
| "size", | ||
| "attachments", | ||
| ]; | ||
|
|
||
| it("list --help output contains all column names", async () => { | ||
| const r = await runTool(["macos", "mail", "list", "--help"]); | ||
| const out = stripAnsi(r.stdout); | ||
|
|
||
| for (const col of ALL_COLUMNS) { | ||
| expect(out).toContain(col); | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| describe("invalid column", () => { | ||
| it("list --columns invalid_col should warn about unknown column", async () => { | ||
| const r = await runTool(["macos", "mail", "list", "--columns", "invalid_col"]); | ||
| const combined = stripAnsi(r.stdout + r.stderr); | ||
| expect(combined).toContain("Unknown column"); | ||
| }); | ||
| }); | ||
|
|
||
| describe("format flag", () => { | ||
| it("list --format json --limit 1 accepts the format flag", async () => { | ||
| const r = await runTool(["macos", "mail", "list", "--format", "json", "--limit", "1"], 30_000); | ||
|
|
||
| // If mail DB is accessible, we get valid JSON output. | ||
| // If not (e.g. no Full Disk Access), we still verify the flags are accepted | ||
| // by checking it doesn't fail with "unknown option". | ||
| const combined = stripAnsi(r.stdout + r.stderr); | ||
| expect(combined).not.toContain("unknown option"); | ||
|
|
||
| if (r.exitCode === 0 && r.stdout.trim().length > 0) { | ||
| // The output contains clack spinner control sequences mixed with JSON. | ||
| // Find the line that starts with '[' and collect until the matching ']'. | ||
| const lines = r.stdout.split("\n"); | ||
| const startIdx = lines.findIndex((l) => l.trim() === "["); | ||
| const endIdx = lines.findLastIndex((l) => l.trim() === "]"); | ||
|
|
||
| if (startIdx !== -1 && endIdx > startIdx) { | ||
| const jsonStr = lines.slice(startIdx, endIdx + 1).join("\n"); | ||
| const parsed = SafeJSON.parse(jsonStr); | ||
| expect(Array.isArray(parsed)).toBe(true); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method used to extract the JSON object from the command's stdout is quite brittle. It relies on the opening // The output can contain clack spinner control sequences mixed with JSON.
// Find the first '[' and last ']' to extract the JSON array string.
const stdout = r.stdout;
const startIdx = stdout.indexOf("[");
const endIdx = stdout.lastIndexOf("]");
if (startIdx !== -1 && endIdx > startIdx) {
const jsonStr = stdout.substring(startIdx, endIdx + 1);
const parsed = SafeJSON.parse(jsonStr);
expect(Array.isArray(parsed)).toBe(true);
} |
||
| } | ||
| }, 30_000); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
ALL_COLUMNSarray is missing thebodyandrelevancecolumns, which are defined insrc/macos/lib/mail/columns.ts. This means the test "list --help output contains all column names" isn't verifying that all available columns are mentioned in the help output.