첫 커밋: 로컬 프로젝트 업로드
This commit is contained in:
239
baron-sso/devfront/tests/devfront-role-switch-report.spec.ts
Normal file
239
baron-sso/devfront/tests/devfront-role-switch-report.spec.ts
Normal file
@@ -0,0 +1,239 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import {
|
||||
type AuditLog,
|
||||
type Consent,
|
||||
installDevApiMock,
|
||||
makeClient,
|
||||
seedAuth,
|
||||
} from "./helpers/devfront-fixtures";
|
||||
import { captureEvidence } from "./helpers/evidence";
|
||||
|
||||
const appNamePlaceholder = /My Awesome Application|예: 멋진 애플리케이션/i;
|
||||
|
||||
test.describe("DevFront role report", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
page.on("dialog", async (dialog) => {
|
||||
await dialog.accept();
|
||||
});
|
||||
});
|
||||
|
||||
test("user can enter and sees empty RP list", async ({ page }, testInfo) => {
|
||||
await seedAuth(page, "user");
|
||||
await installDevApiMock(page, {
|
||||
clients: [],
|
||||
consents: [] as Consent[],
|
||||
auditLogs: [] as AuditLog[],
|
||||
});
|
||||
|
||||
await page.goto("/clients");
|
||||
await expect(
|
||||
page.getByText(/조회 가능한 RP가 없습니다|No RPs are available/i),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("heading", {
|
||||
name: /^연동 앱$|^Connected Application$/i,
|
||||
}),
|
||||
).toBeVisible();
|
||||
await captureEvidence(page, testInfo, "role-user-empty-rps");
|
||||
});
|
||||
|
||||
test("user sees developer request entry point on overview", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await seedAuth(page, "user");
|
||||
await installDevApiMock(page, {
|
||||
clients: [],
|
||||
consents: [] as Consent[],
|
||||
auditLogs: [] as AuditLog[],
|
||||
auditLogsByCursor: undefined,
|
||||
developerRequests: [],
|
||||
});
|
||||
|
||||
await page.goto("/");
|
||||
await expect(
|
||||
page.getByText(
|
||||
/대시보드는 개발자 권한이 있어야 볼 수 있습니다|개발자 권한 신청을 검토 중입니다./,
|
||||
),
|
||||
).toBeVisible();
|
||||
const requestBtn = page.getByRole("button", {
|
||||
name: /개발자 권한 신청/,
|
||||
});
|
||||
await expect(requestBtn).toBeVisible();
|
||||
await requestBtn.click();
|
||||
await expect(page).toHaveURL(/\/developer-requests$/);
|
||||
await captureEvidence(page, testInfo, "role-user-overview-request-entry");
|
||||
});
|
||||
|
||||
test("user with approved developer request sees overview without CTA", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await seedAuth(page, "user");
|
||||
await installDevApiMock(page, {
|
||||
clients: [],
|
||||
consents: [] as Consent[],
|
||||
auditLogs: [] as AuditLog[],
|
||||
auditLogsByCursor: undefined,
|
||||
developerRequests: [
|
||||
{
|
||||
id: "req-approved",
|
||||
userId: "playwright-user",
|
||||
userName: "Playwright User",
|
||||
name: "Playwright User",
|
||||
userEmail: "playwright@example.com",
|
||||
organization: "Tenant A",
|
||||
reason: "Need access",
|
||||
status: "approved",
|
||||
createdAt: "2026-05-29T00:00:00.000Z",
|
||||
updatedAt: "2026-05-29T00:00:00.000Z",
|
||||
approvedAt: "2026-05-29T00:10:00.000Z",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await page.goto("/");
|
||||
await expect(
|
||||
page.getByRole("heading", { name: /운영 현황/ }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("button", { name: /개발자 권한 신청/ }),
|
||||
).toHaveCount(0);
|
||||
await captureEvidence(page, testInfo, "role-user-overview-approved");
|
||||
});
|
||||
|
||||
test("rp_admin sees only assigned Gitea app and its logs", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await seedAuth(page, "rp_admin");
|
||||
const state = {
|
||||
clients: [makeClient("gitea-client", { name: "Gitea" })],
|
||||
consents: [] as Consent[],
|
||||
auditLogs: [
|
||||
{
|
||||
event_id: "evt-rp-1",
|
||||
timestamp: "2026-03-04T01:00:00.000Z",
|
||||
user_id: "rp-admin-user",
|
||||
event_type: "CLIENT_UPDATE",
|
||||
status: "success" as const,
|
||||
ip_address: "127.0.0.1",
|
||||
user_agent: "playwright",
|
||||
details: JSON.stringify({
|
||||
action: "UPDATE_CLIENT",
|
||||
target_id: "gitea-client",
|
||||
tenant_id: "tenant-a",
|
||||
}),
|
||||
},
|
||||
] as AuditLog[],
|
||||
};
|
||||
await installDevApiMock(page, state);
|
||||
|
||||
await page.goto("/clients");
|
||||
await expect(
|
||||
page.getByRole("link", { name: "Gitea", exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("cell", { name: "gitea-client" }),
|
||||
).toBeVisible();
|
||||
await captureEvidence(page, testInfo, "role-rp-admin-clients");
|
||||
|
||||
await page.goto("/audit-logs");
|
||||
await expect(page.getByText("UPDATE_CLIENT")).toBeVisible();
|
||||
await expect(page.getByText("gitea-client")).toBeVisible();
|
||||
await captureEvidence(page, testInfo, "role-rp-admin-audit");
|
||||
});
|
||||
|
||||
test("tenant_admin can manage tenant apps and see tenant logs", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await seedAuth(page, "tenant_admin");
|
||||
const state = {
|
||||
clients: [
|
||||
makeClient("tenant-a-app-1", { name: "Tenant A CRM" }),
|
||||
makeClient("tenant-a-app-2", { name: "Tenant A ERP" }),
|
||||
],
|
||||
consents: [] as Consent[],
|
||||
auditLogs: [] as AuditLog[],
|
||||
auditLogsByCursor: undefined,
|
||||
};
|
||||
await installDevApiMock(page, state);
|
||||
|
||||
await page.goto("/clients");
|
||||
await expect(page.getByText("Tenant A CRM")).toBeVisible();
|
||||
await expect(page.getByText("Tenant A ERP")).toBeVisible();
|
||||
await captureEvidence(page, testInfo, "role-tenant-admin-clients");
|
||||
|
||||
await page.goto("/clients/tenant-a-app-1/settings");
|
||||
await page
|
||||
.getByPlaceholder(appNamePlaceholder)
|
||||
.fill("Tenant A CRM Updated");
|
||||
|
||||
const updatePromise = page.waitForResponse(
|
||||
(r) =>
|
||||
r.url().includes("/api/v1/dev/clients") &&
|
||||
r.request().method() === "PUT",
|
||||
);
|
||||
await page.getByRole("button", { name: /^저장$|^Save$/i }).click();
|
||||
await updatePromise;
|
||||
|
||||
await page.goto("/audit-logs");
|
||||
await expect(page.getByText("UPDATE_CLIENT")).toBeVisible({
|
||||
timeout: 30000,
|
||||
});
|
||||
await expect(page.getByText("tenant-a-app-1")).toBeVisible();
|
||||
await captureEvidence(page, testInfo, "role-tenant-admin-audit");
|
||||
});
|
||||
|
||||
test("super_admin sees all and can generate log entries", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await seedAuth(page, "super_admin");
|
||||
const state = {
|
||||
clients: [
|
||||
makeClient("tenant-a-app", { name: "Tenant A App" }),
|
||||
makeClient("tenant-b-app", { name: "Tenant B App" }),
|
||||
],
|
||||
consents: [] as Consent[],
|
||||
auditLogs: [] as AuditLog[],
|
||||
auditLogsByCursor: undefined,
|
||||
};
|
||||
await installDevApiMock(page, state);
|
||||
|
||||
await page.goto("/clients");
|
||||
await expect(page.getByText("Tenant A App")).toBeVisible();
|
||||
await expect(page.getByText("Tenant B App")).toBeVisible();
|
||||
await captureEvidence(page, testInfo, "role-super-admin-clients");
|
||||
|
||||
await page.goto("/clients/new");
|
||||
await page
|
||||
.getByPlaceholder(appNamePlaceholder)
|
||||
.fill("Super Admin Created App");
|
||||
await page
|
||||
.getByPlaceholder(/https:\/\/app\.example\.com\/callback/i)
|
||||
.fill("https://super-admin.example.com/callback");
|
||||
|
||||
const createPromise = page.waitForResponse(
|
||||
(r) =>
|
||||
r.url().includes("/api/v1/dev/clients") &&
|
||||
r.request().method() === "POST",
|
||||
);
|
||||
await page.getByRole("button", { name: /앱 생성|Create/i }).click();
|
||||
await createPromise;
|
||||
await expect(page).toHaveURL(/\/clients\/client-\d+\/settings$/);
|
||||
await expect
|
||||
.poll(() =>
|
||||
state.auditLogs.some((item) => {
|
||||
try {
|
||||
return JSON.parse(item.details)?.action === "CREATE_CLIENT";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
)
|
||||
.toBe(true);
|
||||
|
||||
await page.goto("/audit-logs");
|
||||
await expect(page.getByText("CREATE_CLIENT")).toBeVisible({
|
||||
timeout: 30000,
|
||||
});
|
||||
await captureEvidence(page, testInfo, "role-super-admin-audit");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user