forked from baron/baron-sso
custom claim 타입보정 UI. 대표테넌트 노출 보정
This commit is contained in:
@@ -126,6 +126,26 @@ async function setInputValue(input: HTMLInputElement, value: string) {
|
||||
await flush();
|
||||
}
|
||||
|
||||
async function setTextareaValue(textarea: HTMLTextAreaElement, value: string) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(
|
||||
HTMLTextAreaElement.prototype,
|
||||
"value",
|
||||
);
|
||||
descriptor?.set?.call(textarea, value);
|
||||
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
await flush();
|
||||
}
|
||||
|
||||
async function setSelectValue(select: HTMLSelectElement, value: string) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(
|
||||
HTMLSelectElement.prototype,
|
||||
"value",
|
||||
);
|
||||
descriptor?.set?.call(select, value);
|
||||
select.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
await flush();
|
||||
}
|
||||
|
||||
async function renderPage() {
|
||||
const container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
@@ -229,4 +249,225 @@ describe("ClientGeneralPage RP claims", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("forces user read permission on when user write permission is enabled for RP claims", async () => {
|
||||
const { container } = await renderPage();
|
||||
|
||||
const switches = Array.from(
|
||||
container.querySelectorAll<HTMLButtonElement>('[role="switch"]'),
|
||||
);
|
||||
const readSwitch = switches.find((button) =>
|
||||
/Read|읽기/.test(button.getAttribute("aria-label") ?? ""),
|
||||
);
|
||||
const writeSwitch = switches.find((button) =>
|
||||
/Write|쓰기/.test(button.getAttribute("aria-label") ?? ""),
|
||||
);
|
||||
|
||||
expect(readSwitch).toBeDefined();
|
||||
expect(writeSwitch).toBeDefined();
|
||||
expect(readSwitch?.getAttribute("aria-checked")).toBe("false");
|
||||
expect(writeSwitch?.getAttribute("aria-checked")).toBe("false");
|
||||
|
||||
await act(async () => {
|
||||
writeSwitch?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
await flush();
|
||||
|
||||
expect(readSwitch?.getAttribute("aria-checked")).toBe("true");
|
||||
expect(writeSwitch?.getAttribute("aria-checked")).toBe("true");
|
||||
|
||||
const saveButton = Array.from(container.querySelectorAll("button")).find(
|
||||
(button) =>
|
||||
button.textContent?.includes("저장") ||
|
||||
button.textContent?.includes("Save"),
|
||||
);
|
||||
expect(saveButton).toBeDefined();
|
||||
|
||||
await act(async () => {
|
||||
saveButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
await flush();
|
||||
|
||||
expect(updateClientMock).toHaveBeenCalledWith(
|
||||
"client-claims",
|
||||
expect.objectContaining({
|
||||
metadata: expect.objectContaining({
|
||||
id_token_claims: [
|
||||
expect.objectContaining({
|
||||
readPermission: "user_and_admin",
|
||||
writePermission: "user_and_admin",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps nullable and default value as separate RP claim settings", async () => {
|
||||
const { container } = await renderPage();
|
||||
|
||||
expect(container.textContent).toContain("Nullable");
|
||||
expect(container.textContent).toContain("Default Value");
|
||||
expect(container.textContent).not.toContain("Nullable/default");
|
||||
expect(container.textContent).toContain(
|
||||
"RP 전용 확장 claim을 구분해서 관리합니다",
|
||||
);
|
||||
});
|
||||
|
||||
it("blocks saving a number RP claim default value that is not numeric", async () => {
|
||||
const { container } = await renderPage();
|
||||
|
||||
const valueTypeSelect = container.querySelector<HTMLSelectElement>(
|
||||
'select[aria-label="Claim 값 타입"]',
|
||||
);
|
||||
expect(valueTypeSelect).not.toBeNull();
|
||||
await setSelectValue(valueTypeSelect as HTMLSelectElement, "number");
|
||||
|
||||
const saveButton = Array.from(container.querySelectorAll("button")).find(
|
||||
(button) =>
|
||||
button.textContent?.includes("저장") ||
|
||||
button.textContent?.includes("Save"),
|
||||
);
|
||||
expect(saveButton).toBeDefined();
|
||||
|
||||
await act(async () => {
|
||||
saveButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
await flush();
|
||||
|
||||
expect(updateClientMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("blocks saving a number RP claim default value that is not an integer", async () => {
|
||||
const { container } = await renderPage();
|
||||
|
||||
const valueTypeSelect = container.querySelector<HTMLSelectElement>(
|
||||
'select[aria-label="Claim 값 타입"]',
|
||||
);
|
||||
expect(valueTypeSelect).not.toBeNull();
|
||||
await setSelectValue(valueTypeSelect as HTMLSelectElement, "number");
|
||||
|
||||
const defaultValueInput = container.querySelector<HTMLInputElement>(
|
||||
'input[placeholder="Enter the default value"]',
|
||||
);
|
||||
expect(defaultValueInput).not.toBeNull();
|
||||
await setInputValue(defaultValueInput as HTMLInputElement, "3.14");
|
||||
|
||||
expect(container.textContent).toContain(
|
||||
"Claim 기본값이 타입과 맞지 않습니다",
|
||||
);
|
||||
|
||||
const saveButton = Array.from(container.querySelectorAll("button")).find(
|
||||
(button) =>
|
||||
button.textContent?.includes("저장") ||
|
||||
button.textContent?.includes("Save"),
|
||||
);
|
||||
expect(saveButton).toBeDefined();
|
||||
|
||||
await act(async () => {
|
||||
saveButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
await flush();
|
||||
|
||||
expect(updateClientMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("saves a float RP claim default value", async () => {
|
||||
const { container } = await renderPage();
|
||||
|
||||
const valueTypeSelect = container.querySelector<HTMLSelectElement>(
|
||||
'select[aria-label="Claim 값 타입"]',
|
||||
);
|
||||
expect(valueTypeSelect).not.toBeNull();
|
||||
expect(
|
||||
valueTypeSelect?.querySelector('option[value="float"]'),
|
||||
).not.toBeNull();
|
||||
await setSelectValue(valueTypeSelect as HTMLSelectElement, "float");
|
||||
|
||||
const defaultValueInput = container.querySelector<HTMLInputElement>(
|
||||
'input[placeholder="Enter the default value"]',
|
||||
);
|
||||
expect(defaultValueInput).not.toBeNull();
|
||||
expect(defaultValueInput?.getAttribute("inputmode")).toBe("decimal");
|
||||
await setInputValue(defaultValueInput as HTMLInputElement, "3.14");
|
||||
|
||||
const saveButton = Array.from(container.querySelectorAll("button")).find(
|
||||
(button) =>
|
||||
button.textContent?.includes("저장") ||
|
||||
button.textContent?.includes("Save"),
|
||||
);
|
||||
expect(saveButton).toBeDefined();
|
||||
|
||||
await act(async () => {
|
||||
saveButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
await flush();
|
||||
|
||||
expect(updateClientMock).toHaveBeenCalledWith(
|
||||
"client-claims",
|
||||
expect.objectContaining({
|
||||
metadata: expect.objectContaining({
|
||||
id_token_claims: [
|
||||
expect.objectContaining({
|
||||
value: "3.14",
|
||||
valueType: "float",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("renders constrained default value controls for boolean and date RP claims", async () => {
|
||||
const { container } = await renderPage();
|
||||
|
||||
const valueTypeSelect = container.querySelector<HTMLSelectElement>(
|
||||
'select[aria-label="Claim 값 타입"]',
|
||||
);
|
||||
expect(valueTypeSelect).not.toBeNull();
|
||||
|
||||
await setSelectValue(valueTypeSelect as HTMLSelectElement, "boolean");
|
||||
const booleanDefaultSelect = Array.from(
|
||||
container.querySelectorAll<HTMLSelectElement>("select"),
|
||||
).find((select) =>
|
||||
Array.from(select.options).some((option) => option.value === "false"),
|
||||
);
|
||||
expect(booleanDefaultSelect).toBeDefined();
|
||||
|
||||
await setSelectValue(valueTypeSelect as HTMLSelectElement, "date");
|
||||
expect(container.querySelector('input[type="date"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
it("blocks saving an object RP claim default value that is not a JSON object", async () => {
|
||||
const { container } = await renderPage();
|
||||
|
||||
const valueTypeSelect = container.querySelector<HTMLSelectElement>(
|
||||
'select[aria-label="Claim 값 타입"]',
|
||||
);
|
||||
expect(valueTypeSelect).not.toBeNull();
|
||||
await setSelectValue(valueTypeSelect as HTMLSelectElement, "object");
|
||||
|
||||
const defaultValueInput = container.querySelector<HTMLTextAreaElement>(
|
||||
'textarea[placeholder="{\\"key\\": \\"value\\"}"]',
|
||||
);
|
||||
expect(defaultValueInput).not.toBeNull();
|
||||
await setTextareaValue(
|
||||
defaultValueInput as HTMLTextAreaElement,
|
||||
"not-json",
|
||||
);
|
||||
|
||||
const saveButton = Array.from(container.querySelectorAll("button")).find(
|
||||
(button) =>
|
||||
button.textContent?.includes("저장") ||
|
||||
button.textContent?.includes("Save"),
|
||||
);
|
||||
expect(saveButton).toBeDefined();
|
||||
|
||||
await act(async () => {
|
||||
saveButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
await flush();
|
||||
|
||||
expect(updateClientMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user