Fix live camera analysis loop
这个提交包含在:
@@ -40,6 +40,21 @@ test("live camera page exposes camera startup controls", async ({ page }) => {
|
||||
await expect(page.getByTestId("live-camera-start-button")).toBeVisible();
|
||||
});
|
||||
|
||||
test("live camera starts analysis and produces scores", async ({ page }) => {
|
||||
await installAppMocks(page, { authenticated: true });
|
||||
|
||||
await page.goto("/live-camera");
|
||||
await page.getByRole("button", { name: "下一步" }).click();
|
||||
await page.getByRole("button", { name: "下一步" }).click();
|
||||
await page.getByRole("button", { name: "下一步" }).click();
|
||||
await page.getByRole("button", { name: /启用摄像头/ }).click();
|
||||
|
||||
await expect(page.getByTestId("live-camera-analyze-button")).toBeVisible();
|
||||
await page.getByTestId("live-camera-analyze-button").click();
|
||||
|
||||
await expect(page.getByTestId("live-camera-score-overall")).toBeVisible();
|
||||
});
|
||||
|
||||
test("recorder flow archives a session and exposes it in videos", async ({ page }) => {
|
||||
await installAppMocks(page, { authenticated: true, videos: [] });
|
||||
|
||||
|
||||
@@ -322,6 +322,54 @@ export async function installAppMocks(
|
||||
};
|
||||
|
||||
await page.addInitScript(() => {
|
||||
const buildFakeLandmarks = () => {
|
||||
const points = Array.from({ length: 33 }, () => ({
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
z: 0,
|
||||
visibility: 0.99,
|
||||
}));
|
||||
|
||||
points[0] = { x: 0.5, y: 0.15, z: 0, visibility: 0.99 };
|
||||
points[11] = { x: 0.42, y: 0.28, z: 0, visibility: 0.99 };
|
||||
points[12] = { x: 0.58, y: 0.28, z: 0, visibility: 0.99 };
|
||||
points[13] = { x: 0.36, y: 0.42, z: 0, visibility: 0.99 };
|
||||
points[14] = { x: 0.64, y: 0.42, z: 0, visibility: 0.99 };
|
||||
points[15] = { x: 0.3, y: 0.54, z: 0, visibility: 0.99 };
|
||||
points[16] = { x: 0.7, y: 0.52, z: 0, visibility: 0.99 };
|
||||
points[23] = { x: 0.45, y: 0.58, z: 0, visibility: 0.99 };
|
||||
points[24] = { x: 0.55, y: 0.58, z: 0, visibility: 0.99 };
|
||||
points[25] = { x: 0.44, y: 0.76, z: 0, visibility: 0.99 };
|
||||
points[26] = { x: 0.56, y: 0.76, z: 0, visibility: 0.99 };
|
||||
points[27] = { x: 0.42, y: 0.94, z: 0, visibility: 0.99 };
|
||||
points[28] = { x: 0.58, y: 0.94, z: 0, visibility: 0.99 };
|
||||
|
||||
return points;
|
||||
};
|
||||
|
||||
class FakePose {
|
||||
callback = null;
|
||||
|
||||
constructor(_config: unknown) {}
|
||||
|
||||
setOptions() {}
|
||||
|
||||
onResults(callback: (results: { poseLandmarks: ReturnType<typeof buildFakeLandmarks> }) => void) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
async send() {
|
||||
this.callback?.({ poseLandmarks: buildFakeLandmarks() });
|
||||
}
|
||||
|
||||
close() {}
|
||||
}
|
||||
|
||||
Object.defineProperty(window, "__TEST_MEDIAPIPE_FACTORY__", {
|
||||
configurable: true,
|
||||
value: async () => ({ Pose: FakePose }),
|
||||
});
|
||||
|
||||
Object.defineProperty(HTMLMediaElement.prototype, "play", {
|
||||
configurable: true,
|
||||
value: async () => undefined,
|
||||
|
||||
在新工单中引用
屏蔽一个用户