feat(ai-character): 오디오 콘텐츠 폼 입력 UX 정렬
This commit is contained in:
@@ -106,7 +106,7 @@ test("desktop and tablet expose audio mutation and upload actions", async ({ pag
|
||||
}
|
||||
});
|
||||
|
||||
test("desktop create form exposes create settings and rejects raw invalid price", async ({ page }) => {
|
||||
test("desktop create form exposes P4-R10 native controls and conditional states without overflow", async ({ page }) => {
|
||||
// Given
|
||||
let createRequests = 0;
|
||||
page.on("request", (request) => {
|
||||
@@ -121,26 +121,150 @@ test("desktop create form exposes create settings and rejects raw invalid price"
|
||||
// When
|
||||
await page.goto("/ai-characters/101/audio-contents/new");
|
||||
|
||||
// Then
|
||||
// Then: free state
|
||||
await expect(page.getByRole("form", { name: "오디오 콘텐츠 생성 입력 화면" })).toBeVisible();
|
||||
await expect(page.getByLabel("구매 옵션")).toBeVisible();
|
||||
await expect(page.getByLabel("기간제")).toBeVisible();
|
||||
await expect(page.getByRole("group", { name: "구매 옵션" })).toHaveCount(0);
|
||||
await expect(page.getByLabel("미리듣기 생성")).toHaveCount(0);
|
||||
await expect(page.getByLabel("포인트 사용")).toHaveCount(0);
|
||||
await expect(page.getByLabel("미리듣기 시작")).toHaveCount(0);
|
||||
await expect(page.getByLabel("미리듣기 종료")).toHaveCount(0);
|
||||
await expect(page.getByLabel("예약 공개일")).toHaveCount(0);
|
||||
const priceInput = page.getByLabel("가격", { exact: true });
|
||||
await expect(priceInput).toHaveAttribute("type", "number");
|
||||
await expect(priceInput).toHaveAttribute("min", "0");
|
||||
await expect(priceInput).toHaveAttribute("step", "1");
|
||||
await expect(priceInput).toHaveValue("0");
|
||||
await priceInput.focus();
|
||||
await page.keyboard.press("ArrowDown");
|
||||
await expect(priceInput).toHaveValue("0");
|
||||
await page.keyboard.press("ArrowUp");
|
||||
await expect(priceInput).toHaveValue("1");
|
||||
await priceInput.fill("0");
|
||||
await expectNoHorizontalOverflow(page);
|
||||
|
||||
// When: tags commit through both keyboard separators
|
||||
const tagInput = page.getByLabel("태그", { exact: true });
|
||||
await tagInput.fill("상담");
|
||||
await tagInput.press("Enter");
|
||||
await tagInput.fill("힐링");
|
||||
await tagInput.press(",");
|
||||
|
||||
// Then
|
||||
await expect(tagInput).toHaveValue("");
|
||||
await expect(page.getByRole("button", { name: "태그 상담 삭제" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "태그 힐링 삭제" })).toBeVisible();
|
||||
expect(createRequests).toBe(0);
|
||||
|
||||
// When
|
||||
await page.getByRole("button", { name: "태그 상담 삭제" }).click();
|
||||
|
||||
// Then
|
||||
await expect(page.getByRole("button", { name: "태그 상담 삭제" })).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "태그 힐링 삭제" })).toBeVisible();
|
||||
|
||||
// When: a positive normalized price enables paid controls
|
||||
await priceInput.fill("1000");
|
||||
|
||||
// Then: paid state
|
||||
await expect(priceInput).toHaveValue("1000");
|
||||
const purchaseOptions = page.getByRole("group", { name: "구매 옵션" });
|
||||
await expect(purchaseOptions).toBeVisible();
|
||||
const bothRadio = page.getByRole("radio", { name: "구매/대여" });
|
||||
const buyOnlyRadio = page.getByRole("radio", { name: "구매 전용" });
|
||||
const rentOnlyRadio = page.getByRole("radio", { name: "대여 전용" });
|
||||
await expect(bothRadio).toHaveAttribute("type", "radio");
|
||||
await expect(buyOnlyRadio).toHaveAttribute("type", "radio");
|
||||
await expect(rentOnlyRadio).toHaveAttribute("type", "radio");
|
||||
await expect(bothRadio).toBeChecked();
|
||||
await rentOnlyRadio.focus();
|
||||
await page.keyboard.press("Space");
|
||||
await expect(rentOnlyRadio).toBeChecked();
|
||||
await expect(page.getByLabel("기간제")).toHaveCount(0);
|
||||
await expect(page.getByRole("checkbox", { name: "대여 전용" })).toHaveCount(0);
|
||||
await expect(page.getByLabel("언어 코드")).toHaveCount(0);
|
||||
await expect(page.getByLabel("성인 콘텐츠")).toBeVisible();
|
||||
await expect(page.getByLabel("미리듣기 생성")).toBeVisible();
|
||||
await expect(page.getByLabel("대여 전용")).toBeVisible();
|
||||
await expect(page.getByLabel("포인트 사용")).toBeVisible();
|
||||
await expect(page.getByLabel("댓글 허용")).toBeVisible();
|
||||
await expect(page.getByLabel("상세 정보 전체 공개")).toBeVisible();
|
||||
await expect(page.getByLabel("미리듣기 시작")).toBeVisible();
|
||||
await expect(page.getByLabel("미리듣기 종료")).toBeVisible();
|
||||
await expect(page.getByLabel("언어 코드")).toBeVisible();
|
||||
await expectNoHorizontalOverflow(page);
|
||||
|
||||
// When
|
||||
await page.getByLabel("가격").fill("-1");
|
||||
// When: preview is enabled
|
||||
const previewCheckbox = page.getByLabel("미리듣기 생성");
|
||||
await previewCheckbox.check();
|
||||
|
||||
// Then: preview duration offsets
|
||||
const previewStart = page.getByLabel("미리듣기 시작");
|
||||
const previewEnd = page.getByLabel("미리듣기 종료");
|
||||
await expect(previewStart).toHaveAttribute("type", "text");
|
||||
await expect(previewStart).toHaveAttribute("placeholder", "예: 00:00:30");
|
||||
await expect(previewStart).toHaveAttribute("pattern", "[0-9]{2}:[0-9]{2}:[0-9]{2}");
|
||||
await expect(previewStart).not.toHaveAttribute("step");
|
||||
await expect(previewEnd).toHaveAttribute("type", "text");
|
||||
await expect(previewEnd).toHaveAttribute("placeholder", "예: 01:00:05");
|
||||
await expect(previewEnd).toHaveAttribute("pattern", "[0-9]{2}:[0-9]{2}:[0-9]{2}");
|
||||
await expect(previewEnd).not.toHaveAttribute("step");
|
||||
await expectNoHorizontalOverflow(page);
|
||||
|
||||
// When / Then: unchecking preview clears the visible time controls
|
||||
await previewCheckbox.uncheck();
|
||||
await expect(previewStart).toHaveCount(0);
|
||||
await expect(previewEnd).toHaveCount(0);
|
||||
|
||||
// When: preview state is populated before returning to free
|
||||
await previewCheckbox.check();
|
||||
await page.getByLabel("포인트 사용").check();
|
||||
await previewStart.fill("00:00:30");
|
||||
await previewEnd.fill("01:00:05");
|
||||
|
||||
// Then: immediate mode has no datetime
|
||||
await expect(page.getByLabel("즉시 공개")).toBeChecked();
|
||||
await expect(page.getByLabel("예약 공개일")).toHaveCount(0);
|
||||
|
||||
// When: scheduled mode is selected
|
||||
await page.getByLabel("예약 공개").check();
|
||||
|
||||
// Then: exactly one native scheduled datetime is rendered
|
||||
const releaseDateTime = page.getByLabel("예약 공개일");
|
||||
await expect(releaseDateTime).toHaveCount(1);
|
||||
await expect(releaseDateTime).toHaveAttribute("type", "datetime-local");
|
||||
await releaseDateTime.fill("2026-08-05T12:00");
|
||||
await expectNoHorizontalOverflow(page);
|
||||
|
||||
// When / Then: immediate mode removes and clears the scheduled datetime
|
||||
await page.getByLabel("즉시 공개").check();
|
||||
await expect(releaseDateTime).toHaveCount(0);
|
||||
await page.getByLabel("예약 공개").check();
|
||||
await expect(page.getByLabel("예약 공개일")).toHaveValue("");
|
||||
await page.getByLabel("즉시 공개").check();
|
||||
|
||||
// When: returning to zero resets and hides paid state
|
||||
await priceInput.fill("0");
|
||||
|
||||
// Then
|
||||
await expect(purchaseOptions).toHaveCount(0);
|
||||
await expect(previewCheckbox).toHaveCount(0);
|
||||
await expect(page.getByLabel("포인트 사용")).toHaveCount(0);
|
||||
await expect(previewStart).toHaveCount(0);
|
||||
await expect(previewEnd).toHaveCount(0);
|
||||
await expectNoHorizontalOverflow(page);
|
||||
|
||||
// When: paid controls return
|
||||
await priceInput.fill("1");
|
||||
|
||||
// Then: their reset defaults are visible
|
||||
await expect(page.getByRole("radio", { name: "구매/대여" })).toBeChecked();
|
||||
await expect(page.getByRole("radio", { name: "대여 전용" })).not.toBeChecked();
|
||||
await expect(page.getByLabel("미리듣기 생성")).not.toBeChecked();
|
||||
await expect(page.getByLabel("포인트 사용")).not.toBeChecked();
|
||||
await expect(page.getByLabel("미리듣기 시작")).toHaveCount(0);
|
||||
await expect(page.getByLabel("미리듣기 종료")).toHaveCount(0);
|
||||
|
||||
// When: the preserved max boundary is exceeded
|
||||
await priceInput.fill("100000");
|
||||
await page.getByRole("button", { name: "생성" }).click();
|
||||
|
||||
// Then
|
||||
await expect(page.getByLabel("가격")).toHaveValue("-1");
|
||||
await expect(priceInput).toHaveValue("100000");
|
||||
await expect(page.getByText("가격은 0 이상 99,999 이하 정수 캔으로 입력하세요.")).toBeVisible();
|
||||
expect(createRequests).toBe(0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user