1
0
forked from baron/baron-sso
Files
baron-sso/devfront/tests/devfront-client-claims-cache.spec.ts

371 lines
10 KiB
TypeScript

import { expect, test } from "@playwright/test";
import {
type ClientRelation,
type Consent,
installDevApiMock,
makeClient,
seedAuth,
} from "./helpers/devfront-fixtures";
import { installDevFrontStaticRoutes } from "./helpers/static-devfront";
const editRelations = [
{
relation: "config_editor",
subject: "User:playwright-user",
subjectType: "User",
subjectId: "playwright-user",
},
{
relation: "admins",
subject: "User:playwright-user",
subjectType: "User",
subjectId: "playwright-user",
},
{
relation: "config_editor",
subject: "User:admin-user",
subjectType: "User",
subjectId: "admin-user",
},
{
relation: "config_editor",
subject: "User:undefined",
subjectType: "User",
subjectId: "undefined",
},
{
relation: "config_editor",
subject: "User:",
subjectType: "User",
subjectId: "",
},
] satisfies ClientRelation[];
test.describe("DevFront RP claim cache", () => {
test.beforeEach(async ({ page }) => {
await installDevFrontStaticRoutes(page);
await seedAuth(page, "super_admin");
});
test("keeps saved RP claim value visible after saving", async ({ page }) => {
const state = {
clients: [
makeClient("client-claims", {
name: "Claims app",
metadata: {
id_token_claims: [
{
namespace: "rp_claims",
key: "old_claim",
value: "A",
valueType: "text",
readPermission: "admin_only",
writePermission: "admin_only",
},
],
},
}),
],
consents: [] as Consent[],
relations: {
"client-claims": editRelations,
},
auditLogsByCursor: undefined,
mockRole: "super_admin",
};
await installDevApiMock(page, state);
await page.goto("http://devfront.test/clients/client-claims/settings");
const claimKeyInput = page
.getByPlaceholder(/e\.g\. locale|예: locale/i)
.first();
await expect(claimKeyInput).toHaveValue("old_claim");
await expect(claimKeyInput).toBeEnabled();
await claimKeyInput.fill("new_claim");
await page.getByRole("button", { name: /^저장$|^Save$/i }).click();
await expect
.poll(
() =>
(
state.clients[0]?.metadata?.id_token_claims as
| Array<{ key?: string }>
| undefined
)?.[0]?.key,
)
.toBe("new_claim");
await expect(claimKeyInput).toHaveValue("new_claim");
});
test("adds supported scopes and custom claim keys from the scope picker including offline_access", async ({
page,
}) => {
const state = {
clients: [
makeClient("client-claims", {
name: "Claims app",
metadata: {
structured_scopes: [
{
id: "scope-openid",
name: "openid",
description: "OIDC",
mandatory: true,
},
],
id_token_claims: [
{
namespace: "rp_claims",
key: "employee_code",
value: "E001",
valueType: "text",
readPermission: "admin_only",
writePermission: "admin_only",
},
],
},
}),
],
consents: [] as Consent[],
relations: {
"client-claims": editRelations,
},
auditLogsByCursor: undefined,
mockRole: "super_admin",
};
await installDevApiMock(page, state);
await page.goto("http://devfront.test/clients/client-claims/settings");
await page
.getByRole("button", { name: /스코프 추가|Scope 추가|Add Scope/i })
.click();
await expect(
page.getByText("offline_access", { exact: true }),
).toBeVisible();
await expect(
page.getByRole("button", { name: /employee_code/ }),
).toBeVisible();
await page.getByRole("button", { name: /employee_code/ }).click();
await page.getByRole("button", { name: /^저장$|^Save$/i }).click();
await expect
.poll(() =>
(
state.clients[0]?.metadata?.structured_scopes as
| Array<{ name?: string }>
| undefined
)?.some((scope) => scope.name === "employee_code"),
)
.toBe(true);
});
test("forces read permission on when write permission is enabled", async ({
page,
}) => {
const state = {
clients: [
makeClient("client-claims", {
name: "Claims app",
metadata: {
id_token_claims: [
{
namespace: "rp_claims",
key: "locale",
value: "ko",
valueType: "text",
readPermission: "admin_only",
writePermission: "admin_only",
},
],
},
}),
],
consents: [] as Consent[],
relations: {
"client-claims": editRelations,
},
auditLogsByCursor: undefined,
mockRole: "super_admin",
};
await installDevApiMock(page, state);
await page.goto("http://devfront.test/clients/client-claims/settings");
const readSwitch = page
.getByRole("switch", { name: /사용자 읽기|Allow user read/i })
.first();
const writeSwitch = page
.getByRole("switch", { name: /사용자 쓰기|Allow user write/i })
.first();
await expect(readSwitch).toHaveAttribute("aria-checked", "false");
await expect(writeSwitch).toHaveAttribute("aria-checked", "false");
await expect(readSwitch).toBeEnabled();
await expect(writeSwitch).toBeEnabled();
await writeSwitch.click();
await expect(readSwitch).toHaveAttribute("aria-checked", "true");
await expect(writeSwitch).toHaveAttribute("aria-checked", "true");
await page.getByRole("button", { name: /^저장$|^Save$/i }).click();
await expect
.poll(
() =>
(
state.clients[0]?.metadata?.id_token_claims as
| Array<{
readPermission?: string;
writePermission?: string;
}>
| undefined
)?.[0],
)
.toMatchObject({
readPermission: "user_and_admin",
writePermission: "user_and_admin",
});
});
test("blocks saving an RP claim default value that does not match the selected value type", async ({
page,
}) => {
const state = {
clients: [
makeClient("client-claims", {
name: "Claims app",
metadata: {
id_token_claims: [
{
namespace: "rp_claims",
key: "profile",
value: "{}",
valueType: "text",
readPermission: "admin_only",
writePermission: "admin_only",
},
],
},
}),
],
consents: [] as Consent[],
relations: {
"client-claims": editRelations,
},
auditLogsByCursor: undefined,
mockRole: "super_admin",
};
await installDevApiMock(page, state);
await page.goto("http://devfront.test/clients/client-claims/settings");
await page
.getByLabel(/Claim 값 타입|Claim value type/i)
.first()
.selectOption("object");
await page
.locator('textarea[placeholder="{\\"key\\": \\"value\\"}"]')
.fill("not-json");
await expect(
page.getByRole("button", { name: /^저장$|^Save$/i }),
).toBeDisabled();
expect(
(
state.clients[0]?.metadata?.id_token_claims as
| Array<{ valueType?: string; value?: string }>
| undefined
)?.[0],
).toMatchObject({
value: "{}",
valueType: "text",
});
});
test("saves a float RP claim default value and blocks decimal values for integer number claims", async ({
page,
}) => {
const state = {
clients: [
makeClient("client-claims", {
name: "Claims app",
metadata: {
id_token_claims: [
{
namespace: "rp_claims",
key: "ratio",
value: "0",
valueType: "text",
readPermission: "admin_only",
writePermission: "admin_only",
},
],
},
}),
],
consents: [] as Consent[],
relations: {
"client-claims": editRelations,
},
auditLogsByCursor: undefined,
mockRole: "super_admin",
};
await installDevApiMock(page, state);
await page.goto("http://devfront.test/clients/client-claims/settings");
await page
.getByLabel(/Claim 값 타입|Claim value type/i)
.first()
.selectOption("float");
await page
.getByPlaceholder(/기본값을 입력하세요|Enter the default value/i)
.first()
.fill("3.14");
await page.getByRole("button", { name: /^저장$|^Save$/i }).click();
await expect
.poll(
() =>
(
state.clients[0]?.metadata?.id_token_claims as
| Array<{ valueType?: string; value?: string }>
| undefined
)?.[0],
)
.toMatchObject({
value: "3.14",
valueType: "float",
});
const valueTypeSelect = page
.getByLabel(/Claim 값 타입|Claim value type/i)
.first();
await expect(valueTypeSelect).toHaveValue("float");
await expect(
page.getByRole("button", { name: /^저장$|^Save$/i }),
).toBeEnabled();
await valueTypeSelect.selectOption("number");
await expect(valueTypeSelect).toHaveValue("number");
const defaultValueInput = page
.getByPlaceholder(/기본값을 입력하세요|Enter the default value/i)
.first();
await expect(defaultValueInput).toHaveAttribute("inputmode", "numeric");
await defaultValueInput.fill("3.14");
await expect(
page.getByText(/Claim 기본값이 타입과 맞지 않습니다|does not match/i),
).toBeVisible();
await expect(
page.getByRole("button", { name: /^저장$|^Save$/i }),
).toBeDisabled();
});
});