test: expand bridge unit coverage for payloads and errors
This commit is contained in:
+146
-1
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, mock, test } from "bun:test";
|
||||
import { KeePassDatabase } from "../../src/keepass";
|
||||
import { KeePassDatabase, openKeePassDatabase } from "../../src/keepass";
|
||||
|
||||
const spawnMock = mock(() => {
|
||||
throw new Error("spawn should be mocked per test");
|
||||
@@ -51,6 +51,57 @@ describe("KeePassDatabase", () => {
|
||||
await expect(db.listEntries()).rejects.toThrow("boom");
|
||||
});
|
||||
|
||||
test("throws on empty bridge output", async () => {
|
||||
spawnMock.mockImplementation(() => {
|
||||
const child = {
|
||||
stdin: { write: () => undefined, end: () => undefined },
|
||||
stdout: { on: (_event: string, cb: (chunk: Buffer | string) => void) => cb(" ") },
|
||||
stderr: { on: (_event: string, cb: (chunk: Buffer | string) => void) => cb("bridge failed") },
|
||||
on: (event: string, cb: (code?: number | null) => void) => {
|
||||
if (event === "close") queueMicrotask(() => cb(1));
|
||||
},
|
||||
};
|
||||
return child as never;
|
||||
});
|
||||
|
||||
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
|
||||
await expect(db.listEntries()).rejects.toThrow("bridge failed");
|
||||
});
|
||||
|
||||
test("throws on invalid JSON output", async () => {
|
||||
spawnMock.mockImplementation(() => {
|
||||
const child = {
|
||||
stdin: { write: () => undefined, end: () => undefined },
|
||||
stdout: { on: (_event: string, cb: (chunk: Buffer | string) => void) => cb("not json") },
|
||||
stderr: { on: () => undefined },
|
||||
on: (event: string, cb: (code?: number | null) => void) => {
|
||||
if (event === "close") queueMicrotask(() => cb(0));
|
||||
},
|
||||
};
|
||||
return child as never;
|
||||
});
|
||||
|
||||
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
|
||||
await expect(db.listEntries()).rejects.toThrow("Invalid JSON from Python bridge");
|
||||
});
|
||||
|
||||
test("throws on spawn error", async () => {
|
||||
spawnMock.mockImplementation(() => {
|
||||
const child = {
|
||||
stdin: { write: () => undefined, end: () => undefined },
|
||||
stdout: { on: () => undefined },
|
||||
stderr: { on: () => undefined },
|
||||
on: (event: string, cb: (error: Error) => void) => {
|
||||
if (event === "error") queueMicrotask(() => cb(new Error("spawn failed")));
|
||||
},
|
||||
};
|
||||
return child as never;
|
||||
});
|
||||
|
||||
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
|
||||
await expect(db.listEntries()).rejects.toThrow("spawn failed");
|
||||
});
|
||||
|
||||
test("createEntry forwards the create-entry command", async () => {
|
||||
mockSuccessfulBridgeResponse({ title: "New" });
|
||||
|
||||
@@ -78,4 +129,98 @@ describe("KeePassDatabase", () => {
|
||||
await expect(db.save()).resolves.toBeUndefined();
|
||||
expect(spawnMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("findEntries forwards the query payload", async () => {
|
||||
let payload = "";
|
||||
spawnMock.mockImplementation(() => {
|
||||
const child = {
|
||||
stdin: {
|
||||
write: (chunk: string) => {
|
||||
payload += chunk;
|
||||
},
|
||||
end: () => undefined,
|
||||
},
|
||||
stdout: { on: (_event: string, cb: (chunk: Buffer | string) => void) => cb(JSON.stringify({ ok: true, data: [] })) },
|
||||
stderr: { on: () => undefined },
|
||||
on: (event: string, cb: (code?: number | null) => void) => {
|
||||
if (event === "close") queueMicrotask(() => cb(0));
|
||||
},
|
||||
};
|
||||
return child as never;
|
||||
});
|
||||
|
||||
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
|
||||
await db.findEntries({ title: "abc", username: "u", url: "https://x", groupPath: "Folder" });
|
||||
|
||||
expect(JSON.parse(payload)).toMatchObject({
|
||||
command: "find-entries",
|
||||
path: "db.kdbx",
|
||||
password: "secret",
|
||||
query: { title: "abc", username: "u", url: "https://x", groupPath: "Folder" },
|
||||
});
|
||||
});
|
||||
|
||||
test("listGroups forwards the list-groups command", async () => {
|
||||
let payload = "";
|
||||
spawnMock.mockImplementation(() => {
|
||||
const child = {
|
||||
stdin: {
|
||||
write: (chunk: string) => {
|
||||
payload += chunk;
|
||||
},
|
||||
end: () => undefined,
|
||||
},
|
||||
stdout: { on: (_event: string, cb: (chunk: Buffer | string) => void) => cb(JSON.stringify({ ok: true, data: [] })) },
|
||||
stderr: { on: () => undefined },
|
||||
on: (event: string, cb: (code?: number | null) => void) => {
|
||||
if (event === "close") queueMicrotask(() => cb(0));
|
||||
},
|
||||
};
|
||||
return child as never;
|
||||
});
|
||||
|
||||
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
|
||||
await db.listGroups();
|
||||
|
||||
expect(JSON.parse(payload)).toMatchObject({
|
||||
command: "list-groups",
|
||||
path: "db.kdbx",
|
||||
password: "secret",
|
||||
});
|
||||
});
|
||||
|
||||
test("passes keyFile in the bridge payload", async () => {
|
||||
let payload = "";
|
||||
spawnMock.mockImplementation(() => {
|
||||
const child = {
|
||||
stdin: {
|
||||
write: (chunk: string) => {
|
||||
payload += chunk;
|
||||
},
|
||||
end: () => undefined,
|
||||
},
|
||||
stdout: { on: (_event: string, cb: (chunk: Buffer | string) => void) => cb(JSON.stringify({ ok: true, data: [] })) },
|
||||
stderr: { on: () => undefined },
|
||||
on: (event: string, cb: (code?: number | null) => void) => {
|
||||
if (event === "close") queueMicrotask(() => cb(0));
|
||||
},
|
||||
};
|
||||
return child as never;
|
||||
});
|
||||
|
||||
const db = new KeePassDatabase("db.kdbx", { password: "secret", keyFile: "keyfile.key" }, "python3", new URL("file:///tmp/bridge.py"));
|
||||
await db.listEntries();
|
||||
|
||||
expect(JSON.parse(payload)).toMatchObject({
|
||||
path: "db.kdbx",
|
||||
password: "secret",
|
||||
keyFile: "keyfile.key",
|
||||
command: "list-entries",
|
||||
});
|
||||
});
|
||||
|
||||
test("openKeePassDatabase returns a KeePassDatabase instance", () => {
|
||||
const db = openKeePassDatabase("db.kdbx", { password: "secret" });
|
||||
expect(db).toBeInstanceOf(KeePassDatabase);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user