feat: add write support for KeePass entries and groups

This commit is contained in:
2026-05-10 00:19:42 +02:00
parent 89ba04d61a
commit da0b396bf8
7 changed files with 221 additions and 39 deletions
+43 -25
View File
@@ -9,33 +9,23 @@ mock.module("node:child_process", () => ({
spawn: spawnMock,
}));
function mockSuccessfulBridgeResponse(data: unknown) {
spawnMock.mockImplementation(() => {
const child = {
stdin: { write: () => undefined, 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;
});
}
describe("KeePassDatabase", () => {
test("listEntries parses successful bridge response", async () => {
spawnMock.mockImplementation(() => {
const listeners: Record<string, ((chunk: Buffer | string) => void)[]> = {};
const child = {
stdin: {
write: () => undefined,
end: () => {
listeners.close?.forEach((cb) => cb(Buffer.from("")));
},
},
stdout: {
on: (event: string, cb: (chunk: Buffer | string) => void) => {
listeners[event] ??= [];
listeners[event].push(cb);
if (event === "data") {
cb(JSON.stringify({ ok: true, data: [{ title: "Entry" }] }));
}
},
},
stderr: { on: () => undefined },
on: (event: string, cb: (code?: number | null) => void) => {
if (event === "close") queueMicrotask(() => cb(0));
},
};
return child as never;
});
mockSuccessfulBridgeResponse([{ title: "Entry" }]);
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
const entries = await db.listEntries();
@@ -60,4 +50,32 @@ describe("KeePassDatabase", () => {
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
await expect(db.listEntries()).rejects.toThrow("boom");
});
test("createEntry forwards the create-entry command", async () => {
mockSuccessfulBridgeResponse({ title: "New" });
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
const created = await db.createEntry({ title: "New" });
expect(created).toEqual({ title: "New" });
expect(spawnMock).toHaveBeenCalled();
});
test("createGroup forwards the create-group command", async () => {
mockSuccessfulBridgeResponse({ name: "Folder", path: "" });
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
const created = await db.createGroup({ name: "Folder" });
expect(created).toEqual({ name: "Folder", path: "" });
expect(spawnMock).toHaveBeenCalled();
});
test("save forwards the save command", async () => {
mockSuccessfulBridgeResponse(null);
const db = new KeePassDatabase("db.kdbx", { password: "secret" }, "python3", new URL("file:///tmp/bridge.py"));
await expect(db.save()).resolves.toBeUndefined();
expect(spawnMock).toHaveBeenCalled();
});
});