운영 화면과 회기 리뷰 UI 갱신
This commit is contained in:
parent
e7ebb38177
commit
3a9f70a97b
18 changed files with 2210 additions and 137 deletions
|
|
@ -29,6 +29,17 @@ interface UserPreferencesResponse {
|
|||
};
|
||||
}
|
||||
|
||||
interface UserSupportTicketsResponse {
|
||||
source: "database";
|
||||
durable: boolean;
|
||||
tickets: Array<{
|
||||
ticket_id: string;
|
||||
status: string;
|
||||
subject: string;
|
||||
resolution_note: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface AdminEngineConfigResponse {
|
||||
engine_mode: string;
|
||||
engine_url: string;
|
||||
|
|
@ -214,6 +225,9 @@ async function expectNoSettingsControlClipping(page: Page) {
|
|||
".vg-set__field",
|
||||
".vg-set__control-block",
|
||||
".vg-set__opt",
|
||||
".vg-set__tickets",
|
||||
".vg-set__ticket",
|
||||
".vg-set__ticket-note",
|
||||
".vg-set__voice",
|
||||
".vg-set__range-row",
|
||||
".vg-set__seg",
|
||||
|
|
@ -405,27 +419,39 @@ async function openSettings(page: Page, options: { admin?: boolean } = {}) {
|
|||
const voicePresetsPromise = page.waitForResponse(
|
||||
isApiResponse("GET", "/users/me/voice-presets"),
|
||||
);
|
||||
const supportTicketsPromise = page.waitForResponse(
|
||||
isApiResponse("GET", "/users/support-tickets"),
|
||||
);
|
||||
const engineConfigPromise = options.admin
|
||||
? page.waitForResponse(isApiResponse("GET", "/admin/engine-config"))
|
||||
: null;
|
||||
|
||||
await page.goto("/settings");
|
||||
|
||||
const [profileResponse, preferencesResponse, voicePresetsResponse, engineConfigResponse] =
|
||||
const [
|
||||
profileResponse,
|
||||
preferencesResponse,
|
||||
voicePresetsResponse,
|
||||
supportTicketsResponse,
|
||||
engineConfigResponse,
|
||||
] =
|
||||
await Promise.all([
|
||||
profilePromise,
|
||||
preferencesPromise,
|
||||
voicePresetsPromise,
|
||||
supportTicketsPromise,
|
||||
engineConfigPromise,
|
||||
]);
|
||||
|
||||
await expectResponseOk(profileResponse);
|
||||
await expectResponseOk(preferencesResponse);
|
||||
await expectResponseOk(voicePresetsResponse);
|
||||
await expectResponseOk(supportTicketsResponse);
|
||||
if (engineConfigResponse) await expectResponseOk(engineConfigResponse);
|
||||
|
||||
const profile = (await profileResponse.json()) as UserProfileResponse;
|
||||
const preferences = (await preferencesResponse.json()) as UserPreferencesResponse;
|
||||
const supportTickets = (await supportTicketsResponse.json()) as UserSupportTicketsResponse;
|
||||
const engineConfig = engineConfigResponse
|
||||
? ((await engineConfigResponse.json()) as AdminEngineConfigResponse)
|
||||
: null;
|
||||
|
|
@ -433,7 +459,7 @@ async function openSettings(page: Page, options: { admin?: boolean } = {}) {
|
|||
await expect(page).toHaveURL(/\/settings$/);
|
||||
await expect(page.locator(".vg-set")).toBeVisible();
|
||||
|
||||
return { profile, preferences, engineConfig };
|
||||
return { profile, preferences, supportTickets, engineConfig };
|
||||
}
|
||||
|
||||
test.describe("settings page", () => {
|
||||
|
|
@ -580,6 +606,55 @@ test.describe("settings page", () => {
|
|||
expect(preferences.notifications.product_news).toBe(nextProductNews);
|
||||
});
|
||||
|
||||
test("learner sees only own support ticket status and resolution note", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const learnerName = `Settings Ticket Learner ${testInfo.project.name}`;
|
||||
const learnerEmail = await signInAs(page, "learner", testInfo, learnerName);
|
||||
const subject = `설정 티켓 상태 ${slugFor(testInfo)}`;
|
||||
const hiddenBody = `설정 화면에는 보이면 안 되는 문의 본문 ${slugFor(testInfo)}`;
|
||||
const create = await page.request.post("/api/users/support-tickets", {
|
||||
data: {
|
||||
category: "session_review",
|
||||
priority: "high",
|
||||
subject,
|
||||
body: hiddenBody,
|
||||
source_path: "/settings",
|
||||
},
|
||||
});
|
||||
await expectResponseOk(create);
|
||||
const created = (await create.json()) as { ticket_id: string };
|
||||
|
||||
await signInAs(
|
||||
page,
|
||||
"admin",
|
||||
testInfo,
|
||||
`Settings Ticket Admin ${testInfo.project.name}`,
|
||||
`settings.ticket.admin.${slugFor(testInfo)}@twentyoz.kr`,
|
||||
);
|
||||
const resolutionNote = `재처리 완료 ${slugFor(testInfo)}`;
|
||||
const patch = await page.request.patch(`/api/admin/tickets/${created.ticket_id}`, {
|
||||
data: {
|
||||
status: "resolved",
|
||||
assigned_group: "서비스 운영자",
|
||||
resolution_note: resolutionNote,
|
||||
},
|
||||
});
|
||||
await expectResponseOk(patch);
|
||||
|
||||
await signInAs(page, "learner", testInfo, learnerName, learnerEmail);
|
||||
const { supportTickets } = await openSettings(page);
|
||||
expect(supportTickets.tickets.some((ticket) => ticket.ticket_id === created.ticket_id)).toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
const support = page.locator("#set-support");
|
||||
await expect(support).toContainText(subject);
|
||||
await expect(support).toContainText("해결");
|
||||
await expect(support).toContainText(resolutionNote);
|
||||
await expect(support).not.toContainText(hiddenBody);
|
||||
});
|
||||
|
||||
test("admin sees and updates the AI engine settings panel @single-run", async ({ page }, testInfo) => {
|
||||
const displayName = `Settings Admin ${testInfo.project.name}`;
|
||||
const email = await signInAs(page, "admin", testInfo, displayName);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue