fix: version neural audio requests for v0.1.1
This commit is contained in:
+74
-27
@@ -1,6 +1,7 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import AxeBuilder from "@axe-core/playwright";
|
||||
import { WORDS } from "../../src/content";
|
||||
import { isAudioRequest } from "./audio-requests";
|
||||
|
||||
// 실제 WAV를 디코드하고 Web Audio의 ended를 기다린다. 모의 엔진을 사용한
|
||||
// 컴포넌트 검증과 달리 배포 산출물·자동 재생 정책·레이아웃을 함께 확인한다.
|
||||
@@ -10,11 +11,14 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
|
||||
const external: string[] = [];
|
||||
const errors: string[] = [];
|
||||
let audioPath = "";
|
||||
const audioUrls: URL[] = [];
|
||||
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"))
|
||||
audioPath = new URL(request.url()).pathname;
|
||||
const url = new URL(request.url());
|
||||
if (url.origin !== "http://127.0.0.1:4173") external.push(request.url());
|
||||
if (isAudioRequest(url)) {
|
||||
audioUrls.push(url);
|
||||
if (url.pathname !== "/audio/intro.wav") audioPath = url.pathname;
|
||||
}
|
||||
});
|
||||
page.on("pageerror", (error) => errors.push(error.message));
|
||||
await page.goto("/");
|
||||
@@ -29,12 +33,17 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
|
||||
).toBe(true);
|
||||
await page.evaluate(() => window.scrollTo(0, 0));
|
||||
await page.screenshot({
|
||||
path: `.agent/evidence-v0.1.1/${info.project.name}-home.png`,
|
||||
path: info.outputPath("home.png"),
|
||||
fullPage: true,
|
||||
});
|
||||
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
|
||||
await expect.poll(() => audioUrls.length).toBe(2);
|
||||
expect(audioUrls.map((url) => url.searchParams.get("v"))).toEqual([
|
||||
"0.1.1",
|
||||
"0.1.1",
|
||||
]);
|
||||
await expect(page.getByRole("button", { name: /듣는 중/ })).toBeDisabled();
|
||||
await expect(page.locator(".sound-wave.active i").first()).toHaveCSS(
|
||||
"animation-name",
|
||||
@@ -67,7 +76,7 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
|
||||
).toBe(true);
|
||||
await page.evaluate(() => window.scrollTo(0, 0));
|
||||
await page.screenshot({
|
||||
path: `.agent/evidence-v0.1.1/${info.project.name}-game.png`,
|
||||
path: info.outputPath("game.png"),
|
||||
fullPage: true,
|
||||
});
|
||||
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
|
||||
@@ -99,7 +108,7 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
|
||||
).toBe(true);
|
||||
await page.evaluate(() => window.scrollTo(0, 0));
|
||||
await page.screenshot({
|
||||
path: `.agent/evidence-v0.1.1/${info.project.name}-results.png`,
|
||||
path: info.outputPath("results.png"),
|
||||
fullPage: true,
|
||||
});
|
||||
expect((await new AxeBuilder({ page }).analyze()).violations).toEqual([]);
|
||||
@@ -107,28 +116,66 @@ test("실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부
|
||||
await expect(
|
||||
page.getByRole("button", { name: "게임 시작 · 소리 듣기" }),
|
||||
).toBeVisible();
|
||||
expect(new Set(audioUrls.map((url) => url.searchParams.get("v")))).toEqual(
|
||||
new Set(["0.1.1"]),
|
||||
);
|
||||
expect(
|
||||
audioUrls.filter((url) => url.pathname !== "/audio/intro.wav"),
|
||||
).toHaveLength(11);
|
||||
expect(external).toEqual([]);
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
|
||||
test("오디오 HTTP 실패를 화면에 표시하고 재시도한다", async ({ page }) => {
|
||||
await page.route("**/audio/*.wav", (route) =>
|
||||
route.fulfill({ status: 404, body: "missing" }),
|
||||
);
|
||||
await page.goto("/");
|
||||
await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
|
||||
await expect(page.getByRole("alert")).toContainText(
|
||||
"소리를 재생하지 못했어요",
|
||||
);
|
||||
await page.unroute("**/audio/*.wav");
|
||||
await page.getByRole("button", { name: "다시 시도" }).click();
|
||||
// 재시도는 안내부터 재생한다. v0.1.1 최대 7.056 + 11.256 + 시작·전환 0.4초에
|
||||
// 로드·디코드·병렬 브라우저 스케줄링 여유를 더해 이 assertion만 30초로 제한한다.
|
||||
await expect(page.getByRole("group", { name: "답 선택" })).toBeVisible({
|
||||
timeout: 30_000,
|
||||
for (const failed of ["intro", "target"]) {
|
||||
test(`${failed} WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const audioUrls: string[] = [];
|
||||
const missing: string[] = [];
|
||||
page.on("request", (request) => {
|
||||
if (isAudioRequest(new URL(request.url()))) audioUrls.push(request.url());
|
||||
});
|
||||
const matchesFailure = (url: URL) =>
|
||||
isAudioRequest(url) &&
|
||||
(failed === "intro"
|
||||
? url.pathname === "/audio/intro.wav"
|
||||
: url.pathname !== "/audio/intro.wav");
|
||||
await page.route(matchesFailure, (route) => {
|
||||
missing.push(route.request().url());
|
||||
return route.fulfill({ status: 404, body: "missing" });
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
|
||||
await expect(page.getByRole("alert")).toContainText(
|
||||
"소리를 재생하지 못했어요",
|
||||
);
|
||||
expect(missing).toHaveLength(1);
|
||||
expect(new URL(missing[0]!).searchParams.get("v")).toBe("0.1.1");
|
||||
expect(audioUrls).toHaveLength(2);
|
||||
await page.unroute(matchesFailure);
|
||||
await page.getByRole("button", { name: "다시 시도" }).click();
|
||||
// 안내 7.056 + 최대 목표 11.256초와 로드·디코드 여유를 포함한다.
|
||||
await expect(page.getByRole("group", { name: "답 선택" })).toBeVisible({
|
||||
timeout: 30_000,
|
||||
});
|
||||
expect(audioUrls).toHaveLength(4);
|
||||
expect(audioUrls.slice(2).sort()).toEqual(audioUrls.slice(0, 2).sort());
|
||||
expect(
|
||||
new Set(audioUrls.map((url) => new URL(url).searchParams.get("v"))),
|
||||
).toEqual(new Set(["0.1.1"]));
|
||||
const targetPath = audioUrls
|
||||
.map((url) => new URL(url).pathname)
|
||||
.find((path) => path !== "/audio/intro.wav")!;
|
||||
const answer = WORDS.find((word) =>
|
||||
targetPath.endsWith(`-${word.id}.wav`),
|
||||
)!.answer;
|
||||
await page.getByRole("button", { name: new RegExp(answer) }).click();
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "정답이에요!" }),
|
||||
).toBeVisible();
|
||||
await page.getByRole("button", { name: "처음으로" }).click();
|
||||
await expect(
|
||||
page.getByRole("button", { name: "게임 시작 · 소리 듣기" }),
|
||||
).toBeFocused();
|
||||
});
|
||||
await page.getByRole("button", { name: "처음으로" }).click();
|
||||
await expect(
|
||||
page.getByRole("button", { name: "게임 시작 · 소리 듣기" }),
|
||||
).toBeFocused();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user