feat: add recent furni resync client contract
This commit is contained in:
1 parent
cf563f3550
commit
88ac5ac1ba
2 files changed
+95
No files matched your search
@@ -0,0 +1,46 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import {
|
||||||
|
RECENT_FURNI_RESYNC_URL,
|
||||||
|
requestRecentFurniResync,
|
||||||
|
} from "./recent-furni-resync";
|
||||||
|
|
||||||
|
describe("requestRecentFurniResync", () => {
|
||||||
|
it("posts to the fixed seven-day resync endpoint and normalizes the result", async () => {
|
||||||
|
const fetcher = vi.fn(async () =>
|
||||||
|
Response.json({
|
||||||
|
ok: true,
|
||||||
|
mode: "days",
|
||||||
|
days: 7,
|
||||||
|
examined: 4,
|
||||||
|
resynced: 3,
|
||||||
|
failed: 1,
|
||||||
|
rconOk: false,
|
||||||
|
errors: [{ classname: "chair", message: "invalid entry" }],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(requestRecentFurniResync(fetcher)).resolves.toEqual({
|
||||||
|
examined: 4,
|
||||||
|
resynced: 3,
|
||||||
|
failed: 1,
|
||||||
|
rconOk: false,
|
||||||
|
errors: [{ classname: "chair", message: "invalid entry" }],
|
||||||
|
});
|
||||||
|
expect(RECENT_FURNI_RESYNC_URL).toBe(
|
||||||
|
"/api/admin/import/furni/resync?days=7",
|
||||||
|
);
|
||||||
|
expect(fetcher).toHaveBeenCalledWith(RECENT_FURNI_RESYNC_URL, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws the API error when the request fails", async () => {
|
||||||
|
const fetcher = vi.fn(async () =>
|
||||||
|
Response.json({ error: "Forbidden" }, { status: 403 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(requestRecentFurniResync(fetcher)).rejects.toThrow(
|
||||||
|
"Forbidden",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export const RECENT_FURNI_RESYNC_URL = "/api/admin/import/furni/resync?days=7";
|
||||||
|
|
||||||
|
export interface RecentFurniResyncError {
|
||||||
|
classname: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RecentFurniResyncResult {
|
||||||
|
examined: number;
|
||||||
|
resynced: number;
|
||||||
|
failed: number;
|
||||||
|
rconOk: boolean;
|
||||||
|
errors: RecentFurniResyncError[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdminFetcher = (
|
||||||
|
input: RequestInfo | URL,
|
||||||
|
init?: RequestInit,
|
||||||
|
) => Promise<Response>;
|
||||||
|
|
||||||
|
export async function requestRecentFurniResync(
|
||||||
|
fetcher: AdminFetcher,
|
||||||
|
): Promise<RecentFurniResyncResult> {
|
||||||
|
const response = await fetcher(RECENT_FURNI_RESYNC_URL, { method: "POST" });
|
||||||
|
const payload = (await response.json()) as Record<string, unknown>;
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
typeof payload.error === "string" ? payload.error : "Furni resync failed",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errors = Array.isArray(payload.errors)
|
||||||
|
? payload.errors.filter(
|
||||||
|
(value): value is RecentFurniResyncError =>
|
||||||
|
typeof value === "object" &&
|
||||||
|
value !== null &&
|
||||||
|
typeof (value as RecentFurniResyncError).classname === "string" &&
|
||||||
|
typeof (value as RecentFurniResyncError).message === "string",
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
examined: Number(payload.examined) || 0,
|
||||||
|
resynced: Number(payload.resynced) || 0,
|
||||||
|
failed: Number(payload.failed) || 0,
|
||||||
|
rconOk: payload.rconOk === true,
|
||||||
|
errors,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in new issue
Block a user