feat: improve Korean neural voice quality for v0.1.1

This commit is contained in:
oz
2026-10-14 07:15:07 +00:00
parent 1c0069c367
commit a92b2ba1e9
161 changed files with 13727 additions and 454 deletions
+11 -26
View File
@@ -13,10 +13,7 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
page.on("request", (request) => {
if (!request.url().startsWith("http://127.0.0.1:4173"))
external.push(request.url());
if (
request.url().endsWith(".wav") &&
!request.url().endsWith("intro.wav")
)
if (request.url().endsWith(".wav") && !request.url().endsWith("intro.wav"))
audioPath = new URL(request.url()).pathname;
});
page.on("pageerror", (error) => errors.push(error.message));
@@ -32,19 +29,13 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
).toBe(true);
await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({
path: `.agent/evidence/release-${info.project.name}-home.png`,
path: `.agent/evidence-v0.1.1/${info.project.name}-home.png`,
fullPage: true,
});
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual(
[],
);
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
await page.emulateMedia({ reducedMotion: "reduce" });
await page
.getByRole("button", { name: "게임 시작 · 소리 듣기" })
.click();
await expect(
page.getByRole("button", { name: /듣는 중/ }),
).toBeDisabled();
await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
await expect(page.getByRole("button", { name: /듣는 중/ })).toBeDisabled();
await expect(page.locator(".sound-wave.active i").first()).toHaveCSS(
"animation-name",
"none",
@@ -76,12 +67,10 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
).toBe(true);
await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({
path: `.agent/evidence/release-${info.project.name}-game.png`,
path: `.agent/evidence-v0.1.1/${info.project.name}-game.png`,
fullPage: true,
});
expect(
(await new AxeBuilder({ page }).analyze()).violations,
).toEqual([]);
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
await page.getByRole("button", { name: /다시 듣기/ }).click();
await expect(target).toBeVisible();
}
@@ -110,12 +99,10 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
).toBe(true);
await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({
path: `.agent/evidence/release-${info.project.name}-results.png`,
path: `.agent/evidence-v0.1.1/${info.project.name}-results.png`,
fullPage: true,
});
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual(
[],
);
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
await page.getByRole("button", { name: "다시 시작" }).click();
await expect(
page.getByRole("button", { name: "게임 시작 · 소리 듣기" }),
@@ -129,15 +116,13 @@ test("오디오 HTTP 실패를 화면에 표시하고 재시도한다", async ({
route.fulfill({ status: 404, body: "missing" }),
);
await page.goto("/");
await page
.getByRole("button", { name: "게임 시작 · 소리 듣기" })
.click();
await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
await expect(page.getByRole("alert")).toContainText(
"소리를 재생하지 못했어요",
);
await page.unroute("**/audio/*.wav");
await page.getByRole("button", { name: "다시 시도" }).click();
// 재시도는 안내부터 재생한다. 최대 8.1205 + 10.1725 + 시작·전환 0.4초에
// 재시도는 안내부터 재생한다. v0.1.1 최대 7.056 + 11.256 + 시작·전환 0.4초에
// 로드·디코드·병렬 브라우저 스케줄링 여유를 더해 이 assertion만 30초로 제한한다.
await expect(page.getByRole("group", { name: "답 선택" })).toBeVisible({
timeout: 30_000,
+17 -29
View File
@@ -19,9 +19,7 @@ test("전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된
.soft(control.y + control.height)
.toBeLessThanOrEqual(bounds.y + bounds.height);
};
await expectInside(
page.getByRole("region", { name: "나의 소리 탐험 준비" }),
);
await expectInside(page.getByRole("region", { name: "나의 소리 탐험 준비" }));
const start = page.getByRole("button", {
name: "게임 시작 · 소리 듣기",
});
@@ -53,14 +51,10 @@ test("전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된
test("난이도 설명은 모바일에서도 보인다", async ({ page }) => {
await page.goto("/");
await page
.getByRole("button", { name: "게임 시작 · 소리 듣기" })
.click();
await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
// DOM에만 설명을 남기고 모바일 CSS로 숨기면 컴포넌트 검증은 통과하므로
// 실제 화면에서 난이도 배지와 쉬운 설명을 모두 읽을 수 있는지 확인한다.
await expect
.soft(page.locator(".db-note"))
.toBeVisible({ timeout: 1000 });
await expect.soft(page.locator(".db-note")).toBeVisible({ timeout: 1000 });
await expect
.soft(page.getByText("1단계 · SNR +6 dB"))
.toBeVisible({ timeout: 1000 });
@@ -86,17 +80,13 @@ test("한국어 제목은 단어 중간에서 줄바꿈하지 않는다", async
})),
);
const homeHeadings = await wordBreaks();
expect
.soft(homeHeadings)
.toEqual(
homeHeadings.map((heading) => ({
...heading,
wordBreak: "keep-all",
})),
);
await page
.getByRole("button", { name: "게임 시작 · 소리 듣기" })
.click();
expect.soft(homeHeadings).toEqual(
homeHeadings.map((heading) => ({
...heading,
wordBreak: "keep-all",
})),
);
await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
const question = page.getByRole("heading", {
name: createQuestions(42, "mixed")[0]!.pattern.question,
});
@@ -105,18 +95,16 @@ test("한국어 제목은 단어 중간에서 줄바꿈하지 않는다", async
// 이미지 안으로 들어오는 Chrome 캡처 아티팩트를 방지한다. 초점은 유지한다.
await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({
path: `.agent/evidence/release-${info.project.name}-heading.png`,
path: `.agent/evidence-v0.1.1/${info.project.name}-heading.png`,
fullPage: true,
});
const gameHeadings = await wordBreaks();
expect
.soft(gameHeadings)
.toEqual(
gameHeadings.map((heading) => ({
...heading,
wordBreak: "keep-all",
})),
);
expect.soft(gameHeadings).toEqual(
gameHeadings.map((heading) => ({
...heading,
wordBreak: "keep-all",
})),
);
expect(
await question.evaluate(
(heading) => heading.scrollWidth <= heading.clientWidth,