개선관리 요구사항과 Google 로그인을 완료
This commit is contained in:
parent
cc0a15b7c6
commit
2a39636163
112 changed files with 10166 additions and 527 deletions
|
|
@ -30,6 +30,7 @@ interface AdminManagedUser {
|
|||
email: string;
|
||||
display_name: string;
|
||||
role: "learner" | "teacher" | "admin";
|
||||
learner_feedback_enabled: boolean;
|
||||
account_status: "pending" | "approved" | "suspended";
|
||||
affiliation: string;
|
||||
cohort_ids: string[];
|
||||
|
|
@ -676,7 +677,9 @@ async function expectCreateUserControlsFit(page: Page, viewportWidth: number) {
|
|||
|
||||
const clippedControls = await form.evaluate((element) => {
|
||||
const formRect = element.getBoundingClientRect();
|
||||
const controls = Array.from(element.querySelectorAll<HTMLElement>("input, select, button"));
|
||||
const controls = Array.from(
|
||||
element.querySelectorAll<HTMLElement>("input, select, output, button"),
|
||||
);
|
||||
|
||||
return controls
|
||||
.map((control) => {
|
||||
|
|
@ -1398,7 +1401,7 @@ test.describe("admin route", () => {
|
|||
await expectNoHorizontalOverflow(page);
|
||||
});
|
||||
|
||||
test("allows an admin to manage real server-known users", async ({ page }, testInfo) => {
|
||||
test("allows an admin to manage real server-known users", async ({ page, browser }, testInfo) => {
|
||||
test.setTimeout(60_000);
|
||||
await signInAsAdmin(page);
|
||||
|
||||
|
|
@ -1427,16 +1430,19 @@ test.describe("admin route", () => {
|
|||
await sessionHeader.getByRole("button").click();
|
||||
await expect(sessionHeader).toHaveAttribute("aria-sort", "descending");
|
||||
|
||||
await page.getByRole("tab", { name: "사용자 등록" }).click();
|
||||
await page.getByRole("tab", { name: "외부 연구참여자 사전등록" }).click();
|
||||
await page.getByLabel("새 사용자 이메일").fill(email);
|
||||
await page.getByLabel("새 사용자 표시 이름").fill(displayName);
|
||||
await page.getByLabel("새 사용자 역할").selectOption("learner");
|
||||
await page.getByLabel("새 사용자 승인 상태").selectOption("pending");
|
||||
await expect(page.getByLabel("새 사용자 승인 상태")).toHaveAttribute(
|
||||
"data-value",
|
||||
"pending",
|
||||
);
|
||||
await page.getByLabel("새 사용자 코호트").fill(`created-${testInfo.project.name}`);
|
||||
|
||||
const createPromise = page.waitForResponse(isAdminUserCreate);
|
||||
const reloadAfterCreatePromise = page.waitForResponse(isAdminUsersResponse);
|
||||
await page.getByRole("button", { name: "사용자 등록" }).click();
|
||||
await page.getByRole("button", { name: "연구참여자 사전등록" }).click();
|
||||
const createResponse = await createPromise;
|
||||
await expectResponseOk(createResponse);
|
||||
await expectResponseOk(await reloadAfterCreatePromise);
|
||||
|
|
@ -1461,17 +1467,54 @@ test.describe("admin route", () => {
|
|||
await expect(approvalCard).toContainText("승인 대기");
|
||||
await expectVisibleButtonsFit(page, ".vgops-approval__actions .vg-btn", "admin approval buttons");
|
||||
|
||||
const approvePromise = page.waitForResponse(isAdminUserPatch(created.user_id));
|
||||
await approvalCard.getByRole("button", { name: "승인" }).click();
|
||||
const approveResponse = await approvePromise;
|
||||
await expectResponseOk(approveResponse);
|
||||
const approved = (await approveResponse.json()) as AdminManagedUser;
|
||||
expect(approved).toMatchObject({
|
||||
user_id: created.user_id,
|
||||
email,
|
||||
account_status: "approved",
|
||||
const pendingContext = await browser.newContext({
|
||||
baseURL: String(testInfo.project.use.baseURL),
|
||||
});
|
||||
await expect(approvalCard).toHaveCount(0);
|
||||
try {
|
||||
const pendingPage = await pendingContext.newPage();
|
||||
const pendingLogin = await pendingPage.request.post("/api/auth/dev-login", {
|
||||
data: {
|
||||
email,
|
||||
role: "learner",
|
||||
display_name: displayName,
|
||||
},
|
||||
});
|
||||
await expectResponseOk(pendingLogin);
|
||||
expect(await pendingLogin.json()).toMatchObject({
|
||||
email,
|
||||
account_status: "pending",
|
||||
approval_required: true,
|
||||
});
|
||||
|
||||
const blockedPersonas = await pendingPage.request.get("/api/personas");
|
||||
expect(blockedPersonas.status()).toBe(403);
|
||||
expect(await blockedPersonas.json()).toMatchObject({ detail: "account_pending" });
|
||||
await pendingPage.goto("/learn");
|
||||
await expect(pendingPage).toHaveURL(/\/pending$/);
|
||||
|
||||
const approvePromise = page.waitForResponse(isAdminUserPatch(created.user_id));
|
||||
await approvalCard.getByRole("button", { name: "승인" }).click();
|
||||
const approveResponse = await approvePromise;
|
||||
await expectResponseOk(approveResponse);
|
||||
const approved = (await approveResponse.json()) as AdminManagedUser;
|
||||
expect(approved).toMatchObject({
|
||||
user_id: created.user_id,
|
||||
email,
|
||||
account_status: "approved",
|
||||
});
|
||||
await expect(approvalCard).toHaveCount(0);
|
||||
|
||||
const approvedMe = await pendingPage.request.get("/api/auth/me");
|
||||
await expectResponseOk(approvedMe);
|
||||
expect(await approvedMe.json()).toMatchObject({
|
||||
email,
|
||||
account_status: "approved",
|
||||
approval_required: false,
|
||||
});
|
||||
await expectResponseOk(await pendingPage.request.get("/api/personas"));
|
||||
} finally {
|
||||
await pendingContext.close();
|
||||
}
|
||||
|
||||
await page.getByRole("tab", { name: "사용자 목록" }).click();
|
||||
await page.getByLabel("사용자 검색").fill(email);
|
||||
|
|
@ -1484,6 +1527,7 @@ test.describe("admin route", () => {
|
|||
const nextName = `교수자 ${testInfo.project.name}`;
|
||||
const nameInput = card.getByLabel(`${email} 표시 이름`);
|
||||
const roleSelect = card.getByLabel(`${email} 역할`);
|
||||
const feedbackToggle = card.getByLabel(`${email} 학습자 AI 피드백`);
|
||||
const cohortInput = card.getByLabel(`${email} 코호트`);
|
||||
const saveButton = card.getByRole("button", { name: "저장" });
|
||||
const nextCohort = `cohort-${testInfo.project.name}`;
|
||||
|
|
@ -1492,6 +1536,9 @@ test.describe("admin route", () => {
|
|||
await page.evaluate(() => new Promise(requestAnimationFrame));
|
||||
await roleSelect.selectOption("teacher");
|
||||
await expect(roleSelect).toHaveValue("teacher");
|
||||
await expect(feedbackToggle).toBeChecked();
|
||||
await feedbackToggle.uncheck();
|
||||
await expect(feedbackToggle).not.toBeChecked();
|
||||
await cohortInput.fill(nextCohort);
|
||||
await expect(cohortInput).toHaveValue(nextCohort);
|
||||
await page.evaluate(() => new Promise(requestAnimationFrame));
|
||||
|
|
@ -1507,14 +1554,23 @@ test.describe("admin route", () => {
|
|||
email,
|
||||
display_name: nextName,
|
||||
role: "teacher",
|
||||
learner_feedback_enabled: false,
|
||||
account_status: "approved",
|
||||
cohort_ids: [nextCohort],
|
||||
});
|
||||
|
||||
await expect(nameInput).toHaveValue(nextName);
|
||||
await expect(card).toContainText("교수자");
|
||||
await expect(feedbackToggle).not.toBeChecked();
|
||||
await expect(cohortInput).toHaveValue(nextCohort);
|
||||
|
||||
const persistedUsersResponse = await page.request.get("/api/admin/users");
|
||||
await expectResponseOk(persistedUsersResponse);
|
||||
const persistedUsers = (await persistedUsersResponse.json()) as AdminUsersResponse;
|
||||
expect(
|
||||
persistedUsers.users.find((user) => user.user_id === created.user_id),
|
||||
).toMatchObject({ learner_feedback_enabled: false });
|
||||
|
||||
const deletePromise = page.waitForResponse(isAdminUserDelete(created.user_id));
|
||||
await card.getByRole("button", { name: "비활성화" }).click();
|
||||
const deleteResponse = await deletePromise;
|
||||
|
|
@ -1663,7 +1719,7 @@ test.describe("admin route", () => {
|
|||
await signInAsAdmin(page);
|
||||
|
||||
const users = await openAdminAndReadUsers(page);
|
||||
await page.getByRole("tab", { name: "사용자 등록" }).click();
|
||||
await page.getByRole("tab", { name: "외부 연구참여자 사전등록" }).click();
|
||||
const layout = await page.evaluate(() => {
|
||||
const form = document.querySelector<HTMLElement>(".vgops-user-create");
|
||||
if (!form) throw new Error("admin user create form was not rendered");
|
||||
|
|
@ -1702,7 +1758,7 @@ test.describe("admin route", () => {
|
|||
for (const width of [861, 900, 1024]) {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await openAdminAndReadUsers(page);
|
||||
await page.getByRole("tab", { name: "사용자 등록" }).click();
|
||||
await page.getByRole("tab", { name: "외부 연구참여자 사전등록" }).click();
|
||||
|
||||
await expectNoHorizontalOverflow(page);
|
||||
await expectCreateUserControlsFit(page, width);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue