feat(housekeeping): deliver content vertical
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { HousekeepingCapabilityContext } from "../../../foundation/contracts";
|
||||
import { executeContentExternalMutation } from "./mutation-runtime-external";
|
||||
import type { ContentMutationFailure } from "./mutations";
|
||||
|
||||
const fsMocks = vi.hoisted(() => ({
|
||||
mkdir: vi.fn(),
|
||||
readFile: vi.fn(),
|
||||
unlink: vi.fn(),
|
||||
writeFile: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("node:fs/promises", () => fsMocks);
|
||||
vi.mock("drizzle-orm", () => ({ eq: vi.fn() }));
|
||||
vi.mock("@/lib/db", () => ({
|
||||
CameraWeb: {},
|
||||
EmulatorSettings: {},
|
||||
WebsiteSetting: {},
|
||||
db: {},
|
||||
}));
|
||||
vi.mock("@/lib/services/rcon", () => ({
|
||||
rcon: { updateConfig: vi.fn() },
|
||||
}));
|
||||
vi.mock("@/lib/services/site-settings", () => ({
|
||||
siteSettings: {
|
||||
get: vi.fn(),
|
||||
reload: vi.fn(),
|
||||
update: vi.fn(),
|
||||
},
|
||||
}));
|
||||
vi.mock("@/lib/services/staff-activity", () => ({
|
||||
logStaffActivity: vi.fn(),
|
||||
}));
|
||||
vi.mock("@/lib/admin/photo-files", () => ({
|
||||
tryRemoveLocalPhotoFile: vi.fn(),
|
||||
}));
|
||||
|
||||
const capability = {
|
||||
actor: { id: 42, username: "operator", rank: 7 },
|
||||
isSuperAdmin: false,
|
||||
has: () => true,
|
||||
hasAny: () => true,
|
||||
hasAll: () => true,
|
||||
} satisfies HousekeepingCapabilityContext;
|
||||
const context = {
|
||||
capability,
|
||||
correlationId: "external-runtime",
|
||||
legacy: false,
|
||||
};
|
||||
|
||||
describe("Content external mutation runtime", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("preserves media upload bytes, type, size, and canonical public URL", async () => {
|
||||
const file = new File(["image"], "photo.PNG", { type: "image/png" });
|
||||
const snapshot = await executeContentExternalMutation(
|
||||
"media.upload",
|
||||
{ file },
|
||||
context,
|
||||
);
|
||||
|
||||
expect(snapshot).toMatchObject({
|
||||
before: null,
|
||||
after: { size: file.size, type: "image/png" },
|
||||
output: { url: expect.stringMatching(/^\/api\/media\/.+[.]png$/u) },
|
||||
});
|
||||
expect(fsMocks.mkdir).toHaveBeenCalledTimes(1);
|
||||
expect(fsMocks.writeFile).toHaveBeenCalledWith(
|
||||
expect.stringContaining("storage"),
|
||||
expect.any(Buffer),
|
||||
);
|
||||
});
|
||||
|
||||
it("propagates a real storage failure before optimistic success", async () => {
|
||||
fsMocks.writeFile.mockRejectedValueOnce(new Error("disk offline"));
|
||||
const file = new File(["image"], "photo.png", { type: "image/png" });
|
||||
|
||||
await expect(
|
||||
executeContentExternalMutation("media.upload", { file }, context),
|
||||
).rejects.toThrow("disk offline");
|
||||
});
|
||||
|
||||
it("maps normalized media traversal to validation instead of dependency failure", async () => {
|
||||
await expect(
|
||||
executeContentExternalMutation(
|
||||
"media.delete",
|
||||
{ filename: "../private.txt" },
|
||||
context,
|
||||
),
|
||||
).rejects.toMatchObject({
|
||||
code: "VALIDATION",
|
||||
messageKey: "errors.housekeeping.validation",
|
||||
} satisfies Partial<ContentMutationFailure>);
|
||||
expect(fsMocks.unlink).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user