첫 커밋: 로컬 프로젝트 업로드
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import type { ClientSummary, DevAuditLog } from "../../lib/devApi";
|
||||
import {
|
||||
buildRecentClientChangeDetails,
|
||||
buildRecentClientChanges,
|
||||
getRecentClientActionLabel,
|
||||
} from "./recentClientChanges";
|
||||
|
||||
function makeClient(id: string, name = id): ClientSummary {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
type: "private",
|
||||
status: "active",
|
||||
createdAt: "2026-05-27T00:00:00.000Z",
|
||||
redirectUris: [],
|
||||
scopes: [],
|
||||
};
|
||||
}
|
||||
|
||||
function makeAuditLog(
|
||||
eventId: string,
|
||||
timestamp: string,
|
||||
action: string,
|
||||
targetId: string,
|
||||
details: Record<string, unknown>,
|
||||
): DevAuditLog {
|
||||
return {
|
||||
event_id: eventId,
|
||||
timestamp,
|
||||
user_id: "actor-1",
|
||||
event_type: "AUDIT",
|
||||
status: "success",
|
||||
ip_address: "127.0.0.1",
|
||||
user_agent: "vitest",
|
||||
details: JSON.stringify({
|
||||
action,
|
||||
target_id: targetId,
|
||||
...details,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
describe("recent client changes", () => {
|
||||
beforeEach(() => {
|
||||
window.localStorage.clear();
|
||||
window.history.replaceState({}, "", "/");
|
||||
});
|
||||
|
||||
function mockLocale(locale: "ko" | "en") {
|
||||
window.localStorage.clear();
|
||||
window.history.replaceState({}, "", `/${locale}`);
|
||||
}
|
||||
|
||||
it("translates action labels and relation details by locale", () => {
|
||||
mockLocale("en");
|
||||
|
||||
expect(getRecentClientActionLabel("CREATE_CLIENT")).toBe("App creation");
|
||||
expect(getRecentClientActionLabel("UPDATE_CLIENT")).toBe(
|
||||
"Settings changes",
|
||||
);
|
||||
expect(getRecentClientActionLabel("UPDATE_CLIENT_STATUS")).toBe(
|
||||
"Status changes",
|
||||
);
|
||||
expect(getRecentClientActionLabel("ROTATE_SECRET")).toBe(
|
||||
"Client secret rotation",
|
||||
);
|
||||
expect(getRecentClientActionLabel("ADD_RELATION")).toBe("Add Relationship");
|
||||
expect(getRecentClientActionLabel("REMOVE_RELATION")).toBe(
|
||||
"Remove Relationship",
|
||||
);
|
||||
expect(getRecentClientActionLabel("DELETE_CLIENT")).toBe("App deletion");
|
||||
expect(getRecentClientActionLabel("OTHER_ACTION")).toBe("OTHER_ACTION");
|
||||
|
||||
expect(
|
||||
buildRecentClientChangeDetails("ROTATE_SECRET", {
|
||||
after: {},
|
||||
}),
|
||||
).toEqual([{ label: "Client Secret", value: "Secret Rotated" }]);
|
||||
|
||||
expect(
|
||||
buildRecentClientChangeDetails("ADD_RELATION", {
|
||||
after: {
|
||||
relation: "admins",
|
||||
subject: "User:1",
|
||||
},
|
||||
}),
|
||||
).toEqual([
|
||||
{ label: "Relation", value: "admins" },
|
||||
{ label: "Subject", value: "User:1" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("builds recent client changes with sorting, filtering, and detail slicing", () => {
|
||||
mockLocale("ko");
|
||||
|
||||
const clients = [
|
||||
makeClient("client-a", "Alpha"),
|
||||
makeClient("client-b", ""),
|
||||
];
|
||||
const auditLogs = [
|
||||
makeAuditLog(
|
||||
"evt-1",
|
||||
"2026-05-27T07:00:00.000Z",
|
||||
"CREATE_CLIENT",
|
||||
"client-a",
|
||||
{
|
||||
after: { name: "Alpha", type: "private", status: "active" },
|
||||
},
|
||||
),
|
||||
makeAuditLog(
|
||||
"evt-2",
|
||||
"2026-05-27T08:00:00.000Z",
|
||||
"UPDATE_CLIENT",
|
||||
"client-a",
|
||||
{
|
||||
before: {
|
||||
name: "Alpha old",
|
||||
status: "inactive",
|
||||
sameField: "same",
|
||||
oldField: "old-value",
|
||||
},
|
||||
after: {
|
||||
name: "Alpha new",
|
||||
status: "active",
|
||||
sameField: "same",
|
||||
newField: "new-value",
|
||||
},
|
||||
},
|
||||
),
|
||||
makeAuditLog(
|
||||
"evt-3",
|
||||
"2026-05-27T09:00:00.000Z",
|
||||
"UPDATE_CLIENT_STATUS",
|
||||
"client-a",
|
||||
{
|
||||
before: { status: "inactive" },
|
||||
after: { status: "active" },
|
||||
},
|
||||
),
|
||||
makeAuditLog(
|
||||
"evt-4",
|
||||
"2026-05-27T10:00:00.000Z",
|
||||
"ADD_RELATION",
|
||||
"client-b",
|
||||
{
|
||||
after: {
|
||||
relation: "audit_viewer",
|
||||
subject: "User:89692983-f512-4d96-845d-ac6123d08b95",
|
||||
},
|
||||
},
|
||||
),
|
||||
makeAuditLog(
|
||||
"evt-5",
|
||||
"2026-05-27T11:00:00.000Z",
|
||||
"REMOVE_RELATION",
|
||||
"client-b",
|
||||
{
|
||||
before: {
|
||||
relation: "admins",
|
||||
subject: "User:89692983-f512-4d96-845d-ac6123d08b95",
|
||||
},
|
||||
},
|
||||
),
|
||||
makeAuditLog(
|
||||
"evt-6",
|
||||
"2026-05-27T12:00:00.000Z",
|
||||
"ROTATE_SECRET",
|
||||
"client-a",
|
||||
{
|
||||
after: {},
|
||||
},
|
||||
),
|
||||
makeAuditLog(
|
||||
"evt-7",
|
||||
"2026-05-27T13:00:00.000Z",
|
||||
"DELETE_CLIENT",
|
||||
"client-a",
|
||||
{
|
||||
before: {
|
||||
name: "Alpha",
|
||||
status: "inactive",
|
||||
},
|
||||
},
|
||||
),
|
||||
makeAuditLog(
|
||||
"evt-8",
|
||||
"2026-05-27T14:00:00.000Z",
|
||||
"UNSUPPORTED_ACTION",
|
||||
"client-a",
|
||||
{
|
||||
after: { name: "Ignored" },
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
const changes = buildRecentClientChanges(auditLogs, clients);
|
||||
|
||||
expect(changes).toHaveLength(7);
|
||||
expect(changes[0]).toMatchObject({
|
||||
eventId: "evt-7",
|
||||
clientName: "Alpha",
|
||||
actionLabel: "앱 삭제",
|
||||
});
|
||||
expect(changes[1]).toMatchObject({
|
||||
eventId: "evt-6",
|
||||
clientName: "Alpha",
|
||||
actionLabel: "클라이언트 시크릿 재발급",
|
||||
detailLabels: [
|
||||
{
|
||||
label: "클라이언트 시크릿",
|
||||
value: "Client Secret이 재발급되었습니다.",
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(changes[2]).toMatchObject({
|
||||
eventId: "evt-5",
|
||||
clientName: "client-b",
|
||||
actionLabel: "관계 삭제",
|
||||
detailLabels: [
|
||||
{ label: "관계", value: "admins" },
|
||||
{
|
||||
label: "주체",
|
||||
value: "User:89692983-f512-4d96-845d-ac6123d08b95",
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(changes[4]).toMatchObject({
|
||||
eventId: "evt-3",
|
||||
actionLabel: "상태 변경",
|
||||
clientName: "Alpha",
|
||||
detailLabels: [{ value: "inactive → active" }],
|
||||
});
|
||||
expect(changes[5]).toMatchObject({
|
||||
eventId: "evt-2",
|
||||
actionLabel: "설정 변경",
|
||||
detailLabels: [
|
||||
{ label: "애플리케이션", value: "Alpha old → Alpha new" },
|
||||
{ label: "상태", value: "inactive → active" },
|
||||
{ label: "oldField", value: "old-value" },
|
||||
],
|
||||
});
|
||||
expect(changes[6]).toMatchObject({
|
||||
eventId: "evt-1",
|
||||
actionLabel: "앱 생성",
|
||||
detailLabels: [
|
||||
{ label: "애플리케이션", value: "Alpha" },
|
||||
{ label: "유형", value: "private" },
|
||||
{ label: "상태", value: "active" },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user