Files
infra/tools/grimmory-mcp/test/client.test.js
T
DmitryandClaude Opus 5 c676be81ec Capture current Ansible control plane state
Commit the accumulated infrastructure work that was living only in the
working tree: monitoring stack, emergency access/bot, gyro allocator,
grimmory, adguard, backup audit and the OpenCode agent definitions.

Also ignore Python bytecode, local archives and Nix/direnv artifacts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTocXkGUUazHdKKd3r9k71
2026-08-26 21:39:28 +03:00

103 lines
3.3 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { GrimmoryClient, query, unwrap } from "../src/client.js";
test("unwrap handles Grimmory API response envelope", () => {
assert.deepEqual(unwrap({ status: 200, data: { id: 7 } }), { id: 7 });
assert.deepEqual(unwrap([1, 2]), [1, 2]);
});
test("query repeats array values and skips empty values", () => {
assert.equal(
query({ page: 0, status: ["READING", "READ"], search: "" }),
"page=0&status=READING&status=READ",
);
});
test("libraries falls back to the current user on the v3.2.4 endpoint bug", async () => {
const responses = [
new Response(JSON.stringify({ message: "broken" }), { status: 500 }),
new Response(JSON.stringify({ data: { assignedLibraries: [{ id: 3 }] } })),
];
const client = new GrimmoryClient({
baseUrl: "https://example.test",
username: "ada",
passwordFile: "/unused",
fetchImpl: async () => responses.shift(),
});
client.accessToken = "test";
assert.deepEqual(await client.libraries(), [{ id: 3 }]);
});
test("springPage supports the nested Spring page metadata", async () => {
let request = 0;
const client = new GrimmoryClient({
baseUrl: "https://example.test",
username: "ada",
passwordFile: "/unused",
fetchImpl: async () => {
const page = request++;
return new Response(
JSON.stringify({
data: {
content: page === 0 ? Array.from({ length: 100 }, (_, id) => id) : [100],
page: { number: page, totalPages: 2 },
},
}),
);
},
});
client.accessToken = "test";
assert.equal((await client.springPage("/sessions")).length, 101);
assert.equal(request, 2);
});
test("allBooks follows nested pagination and rejects missing metadata", async () => {
let request = 0;
const client = new GrimmoryClient({
baseUrl: "https://example.test",
username: "ada",
passwordFile: "/unused",
fetchImpl: async () => {
const page = request++;
return new Response(JSON.stringify({ data: {
content: page === 0 ? Array.from({ length: 50 }, (_, id) => ({ id })) : [{ id: 50 }],
page: { number: page, totalPages: 2 },
} }));
},
});
client.accessToken = "test";
assert.equal((await client.allBooks()).length, 51);
assert.equal(request, 2);
});
test("concurrent first requests share one login", async () => {
let logins = 0;
const client = new GrimmoryClient({
baseUrl: "https://example.test",
username: "ada",
passwordFile: "/unused",
fetchImpl: async () => new Response(JSON.stringify({ data: { ok: true } })),
});
client.login = async () => {
logins += 1;
await new Promise((resolve) => setTimeout(resolve, 10));
client.accessToken = "test";
};
await Promise.all([client.request("/one"), client.request("/two")]);
assert.equal(logins, 1);
});
test("springPage rejects missing pagination metadata on a full page", async () => {
const client = new GrimmoryClient({
baseUrl: "https://example.test",
username: "ada",
passwordFile: "/unused",
fetchImpl: async () => new Response(JSON.stringify({ data: {
content: Array.from({ length: 100 }, (_, id) => ({ id })),
} })),
});
client.accessToken = "test";
await assert.rejects(() => client.springPage("/sessions"), /no pagination metadata/);
});