Files
hao-ai-lab-FastVideo/docs-site/tests/cookbook.spec.ts
T
William LinandClaude Opus 5.5 f9b2d4957b [docs] Put the PAN 2 cookbook under the pan family
The recipe moves to /cookbook/pan/pan2 and the family guide to /cookbook/pan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:31:55 +00:00

898 lines
51 KiB
TypeScript

import { expect, test, type Page } from "@playwright/test";
const route = "/FastVideo/cookbook/minimax-h3/fasth3-8step";
// The cookbook has no behavioral dependency on third-party scripts. Keep load
// deterministic when GitHub/Trendshift are slow or unreachable.
test.beforeEach(async ({ page }) => {
await page.route(/^https?:\/\/(?!127\.0\.0\.1|localhost)/, (request) => request.abort());
await page.route("**/assets/cookbook-config/capacity/hardware.json", (route) =>
route.fulfill({ path: "tests/fixtures/hardware.json", contentType: "application/json" }),
);
});
async function chooseHardware(page: Page, query: string) {
const search = page.getByLabel("Search hardware", { exact: true });
if ((await search.count()) === 0)
await page
.getByRole("button", { name: /Find or add|Choose hardware|Change hardware/ })
.first()
.click();
await search.fill(query);
await page
.getByRole("radio", { name: new RegExp(query, "i") })
.first()
.click();
}
async function settings(page: Page, section: string) {
await expect(page.locator(".recipe-matrix")).toBeVisible({ timeout: 30000 });
if (section === "Serving" || section === "Hardware") {
const advanced = page.locator(".matrix-advanced");
if ((await advanced.getAttribute("open")) === null) await advanced.locator("summary").first().click();
}
}
async function backend(page: Page, name: string) {
await page
.getByRole("group", { name: "Hardware backend", exact: true })
.getByRole("button", { name, exact: true })
.click();
}
async function chip(page: Page, group: string, name: string) {
await page.getByRole("group", { name: group, exact: true }).getByRole("button", { name, exact: true }).click();
}
async function output(page: Page, section: string) {
await page.getByRole("tablist", { name: "Output format" }).getByRole("tab", { name: section, exact: true }).click();
}
test("edits generate YAML and client instructions, invalid edits clear output, reset restores baseline", async ({
page,
}) => {
await page.goto(route);
await output(page, "config.yaml");
const yaml = page.getByLabel("Generated YAML", { exact: true });
await settings(page, "Serving");
await expect(page.getByLabel("Port", { exact: true })).toHaveValue("8000");
const baseline = await yaml.innerText();
await page.getByLabel("Port", { exact: true }).fill("9000");
await expect(yaml).toContainText('"port": 9000');
await output(page, "Commands");
await expect(page.getByLabel("Client command", { exact: true })).toContainText(":9000/");
await output(page, "config.yaml");
await settings(page, "Model");
await chip(page, "Offload VAE to CPU", "Off");
await expect(yaml).toContainText('"vae": false');
await expect(yaml).toContainText('"num_gpus": 4');
const downloadPromise = page.waitForEvent("download");
await page.getByRole("button", { name: "Download YAML", exact: false }).click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe("config.yaml");
const { readFile } = await import("node:fs/promises");
const downloaded = await readFile((await download.path())!, "utf8");
expect(downloaded).toContain('"port": 9000');
await settings(page, "Serving");
await page.getByLabel("Port", { exact: true }).fill("70000");
await expect(page.getByRole("button", { name: "Download YAML", exact: false })).toBeDisabled();
await expect(yaml).toHaveCount(0);
await expect(page.getByLabel("Port", { exact: true })).toHaveAttribute("aria-invalid", "true");
await page.getByRole("button", { name: "Reset changes", exact: true }).click();
await expect(yaml).toHaveText(baseline);
});
test("copy buttons use their own generated output", async ({ page, context }) => {
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
await page.goto(route);
await settings(page, "Serving");
await page.getByLabel("Port", { exact: true }).fill("9001");
await output(page, "config.yaml");
const yaml = await page.getByLabel("Generated YAML", { exact: true }).innerText();
await page.getByRole("button", { name: "Copy YAML", exact: true }).click();
await expect.poll(() => page.evaluate(() => navigator.clipboard.readText())).toBe(yaml);
await output(page, "Commands");
const server = await page.getByLabel("Server command", { exact: true }).innerText();
const launch = [
"(",
"set -e",
"cat > config.yaml <<'FASTVIDEO_CONFIG'",
yaml.trimEnd(),
"FASTVIDEO_CONFIG",
server,
")",
].join("\n");
await page.getByRole("button", { name: "Copy config + command", exact: true }).click();
await expect.poll(() => page.evaluate(() => navigator.clipboard.readText())).toBe(launch);
await page.locator(".recipe-request-code > summary").click();
const client = await page.getByLabel("Client command", { exact: true }).innerText();
expect(client).toContain(":9001/");
await page.getByRole("button", { name: "Copy request command", exact: true }).click();
await expect.poll(() => page.evaluate(() => navigator.clipboard.readText())).toBe(client);
expect(new Set([yaml, launch, client]).size).toBe(3);
});
test("deployment changes reset edits and support MLX and streaming", async ({ page }) => {
await page.goto(route);
await settings(page, "Serving");
await page.getByLabel("Port", { exact: true }).fill("9000");
await backend(page, "MLX");
await expect(page.getByLabel("Server command", { exact: true })).toContainText("mlx_server");
await settings(page, "Serving");
await expect(page.getByLabel("Port", { exact: true })).toHaveValue("8000");
await page.goto("/FastVideo/cookbook/ltx/ltx2-distilled");
await expect(page.locator(".recipe-matrix")).toBeVisible({ timeout: 30000 });
await expect(page.getByLabel("Client command", { exact: true })).toContainText("/health");
await page.locator(".recipe-request-code > summary").click();
await expect(page.getByText(/WebSocket URL:/)).toBeVisible();
await page.goto("/FastVideo/cookbook/wan/wan21-i2v");
await expect(page.locator(".recipe-matrix")).toBeVisible({ timeout: 30000 });
await expect(page.getByLabel("Client command", { exact: true })).toContainText("input_reference");
await expect(page.getByRole("heading", { level: 1 })).toHaveText("Wan2.1 I2V 14B");
});
test("runtime and hardware choices support browser back", async ({ page }) => {
await page.goto(route);
await expect(page.locator(".recipe-matrix")).toBeVisible({ timeout: 30000 });
await backend(page, "MLX");
await expect(page).toHaveURL(/deployment=fasth3-8step%2Fmlx-rest/);
await backend(page, "CUDA");
await expect(page).toHaveURL(/deployment=fasth3-8step%2Fcuda-rest/);
await page.goBack();
await expect(page).toHaveURL(/deployment=fasth3-8step%2Fmlx-rest/);
await expect(page.getByRole("button", { name: "MLX", exact: true })).toHaveAttribute("aria-pressed", "true");
await page.goForward();
await expect(page).toHaveURL(/deployment=fasth3-8step%2Fcuda-rest/);
await chooseHardware(page, "RTX 5090");
await expect(page).toHaveURL(/hardware=geforce-rtx-5090-32gb/);
await page.goBack();
await expect(page).not.toHaveURL(/hardware=/);
await page.goForward();
await expect(page).toHaveURL(/hardware=geforce-rtx-5090-32gb/);
});
test("failed loads offer retry without keeping stale commands", async ({ page }) => {
await page.route("**/recipes/fasth3-8step/cuda-rest.json", (route) =>
route.fulfill({ status: 503, body: "unavailable" }),
);
await page.goto(route);
await expect(page.getByRole("alert")).toContainText("HTTP 503");
await expect(page.getByLabel("Generated YAML", { exact: true })).toHaveCount(0);
await page.unroute("**/recipes/fasth3-8step/cuda-rest.json");
await page.getByRole("button", { name: "Retry loading recipes" }).click();
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML", { exact: true })).toBeVisible();
});
test("an obsolete deployment response cannot replace the selected deployment", async ({ page }) => {
let release!: () => void;
const gate = new Promise<void>((resolve) => {
release = resolve;
});
await page.route("**/recipes/fasth3-8step/mlx-rest.json", async (route) => {
await gate;
await route.continue().catch(() => {}); // The component may already have aborted the request.
});
await page.goto(route);
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML", { exact: true })).toBeVisible();
await backend(page, "MLX");
await backend(page, "CUDA");
release();
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText("FastVideo-FastH3-8-Step-V2");
await expect(
page.getByRole("group", { name: "Hardware backend" }).getByRole("button", { name: "CUDA", exact: true }),
).toHaveAttribute("aria-pressed", "true");
});
test("mobile layout stays within the viewport and controls work by keyboard", async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await page.goto(route);
await settings(page, "Serving");
const port = page.getByLabel("Port", { exact: true });
await port.focus();
await port.press("ControlOrMeta+A");
await port.press("9");
await port.press("0");
await port.press("0");
await port.press("1");
await expect(page.getByLabel("Client command", { exact: true })).toContainText(":9001/");
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
});
test("inherited values, explicit false, zero and null retain their meanings", async ({ page }) => {
await page.goto("/FastVideo/cookbook?deployment=fastwan21%2Fcuda-rest");
await output(page, "config.yaml");
const yaml = page.getByLabel("Generated YAML", { exact: true });
await expect(yaml).toBeVisible();
await expect(yaml).not.toContainText('"text_encoder":');
await settings(page, "Model");
await chip(page, "Offload text encoder to CPU", "Off");
await expect(yaml).toContainText('"text_encoder": false');
await page
.getByRole("button", {
name: "Use baseline for Offload text encoder to CPU",
exact: true,
})
.click();
await expect(yaml).not.toContainText('"text_encoder":');
await settings(page, "Request");
await page.getByLabel("Seed", { exact: true }).fill("0");
await expect(yaml).toContainText('"seed": 0');
await settings(page, "Serving");
await page.getByRole("button", { name: "Set Served model name to null", exact: true }).click();
await expect(yaml).toContainText('"served_model_name": null');
});
test("catalog discovery opens dedicated model recipes and filters by family and task", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
const cards = page.locator(".recipe-card");
await expect(cards).toHaveCount(39);
await expect(cards.first()).toContainText("FastH3 Omni v1");
await page.getByLabel("Model family", { exact: true }).selectOption("Wan");
await page.getByLabel("Search recipes").fill("Wan2.1 I2V");
await expect(cards).toHaveCount(1);
await cards.click();
await expect(page).toHaveURL(/cookbook\/wan\/wan21-i2v\/?$/);
await expect(page.getByLabel("Base model")).toHaveCount(0);
await page.getByRole("link", { name: "← All recipes", exact: true }).click();
await page.getByLabel("Search recipes").fill("FastWan2.1");
await page.locator(".recipe-card").click();
await expect(page).toHaveURL(/cookbook\/wan\/fastwan21\/?$/);
await expect(page.getByRole("heading", { level: 1 })).toHaveText("FastWan2.1 1.3B");
});
test("hardware preferences stay distinct from schema-backed GPU count and topology", async ({ page }) => {
await page.goto(route);
await chooseHardware(page, "RTX PRO 6000");
await expect(page).toHaveURL(/hardware=rtx-pro-6000-blackwell-workstation-96gb/);
await expect(page.locator(".hardware-selected")).toContainText("96 GB VRAM");
await settings(page, "Hardware");
await page.getByLabel("Tensor parallelism", { exact: true }).fill("2");
await page.getByRole("button", { name: "Use automatic parallelism" }).click();
await expect(page.getByLabel("Tensor parallelism", { exact: true })).toHaveValue("-1");
await page.getByLabel("GPU count", { exact: true }).fill("1");
await output(page, "config.yaml");
const yaml = page.getByLabel("Generated YAML", { exact: true });
await expect(yaml).toContainText('"num_gpus": 1');
await expect(yaml).not.toContainText('"hardware"');
await expect(page.getByText("Schema checks passed", { exact: true })).toBeVisible();
await expect(page.getByText("Memory not estimated", { exact: true })).toBeVisible();
await page.getByLabel("GPU count", { exact: true }).fill("0");
await expect(yaml).toHaveCount(0);
await expect(page.getByLabel("GPU count", { exact: true })).toHaveAttribute("aria-invalid", "true");
});
test("output tabs support keyboard navigation and precision chips use the backend schema", async ({ page }) => {
await page.goto(route);
const tabs = page.getByRole("tablist", { name: "Output format" });
await tabs.getByRole("tab", { name: "Commands", exact: true }).focus();
await page.keyboard.press("ArrowRight");
await expect(tabs.getByRole("tab", { name: "config.yaml", exact: true })).toHaveAttribute("aria-selected", "true");
await backend(page, "MLX");
await chip(page, "VAE compute precision", "bf16");
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText('"vae_dtype": "bf16"');
await expect(
page.getByRole("group", { name: "Hardware backend" }).getByRole("button", { name: "AMD", exact: true }),
).toHaveCount(0);
await page.goto("/FastVideo/cookbook");
await page.getByLabel("Search recipes").fill("does not exist");
await expect(page.getByRole("heading", { name: "No matching recipes" })).toBeVisible();
await page.getByRole("button", { name: "Clear filters" }).click();
await expect(page.locator(".recipe-card")).toHaveCount(39);
});
test("cookbook cards and controls remain readable in dark mode and reflow at 320px", async ({ page }) => {
await page.emulateMedia({ colorScheme: "dark" });
await page.goto("/FastVideo/cookbook");
await expect(page.locator(".recipe-card").first()).toBeVisible();
await page.setViewportSize({ width: 320, height: 900 });
await expect(page.locator(".recipe-card").first()).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
await page.goto(route);
await settings(page, "Serving");
await expect(page.getByLabel("Port", { exact: true })).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
await expect(page.getByRole("button", { name: "Download YAML", exact: false })).toBeEnabled();
});
test("image and audio models have logos and dedicated source recipe pages", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
await page.getByRole("button", { name: "Image", exact: true }).click();
await expect(page.locator(".recipe-card")).toHaveCount(5);
const card = page.locator(".recipe-card").filter({ hasText: "FLUX.2 Klein" });
await expect(card.locator("img")).toBeVisible();
await card.click();
await expect(page.getByRole("heading", { level: 1 })).toHaveText("FLUX.2 Klein 4B");
await expect(page.getByLabel("Inference command")).toContainText("flux");
await expect(
page.getByRole("group", { name: "Run mode" }).getByRole("button", { name: "Python SDK", exact: true }),
).toHaveAttribute("aria-pressed", "true");
await expect(page.getByRole("button", { name: "Serving", exact: true })).toHaveCount(0);
await page.getByLabel("Seed", { exact: true }).fill("0");
await expect(page.getByRole("button", { name: "Copy example + command", exact: true })).toBeEnabled();
await page.goto("/FastVideo/cookbook/qwen-image21");
const qwen = page.locator(".recipe-card").filter({ hasText: "Qwen-Image-2.1" });
await expect(qwen.locator("img")).toHaveAttribute("src", /\/qwen\.webp$/);
await qwen.click();
await expect(page.getByRole("heading", { level: 1 })).toHaveText("Qwen-Image-2.1");
await expect(page.getByRole("button", { name: "Serving", exact: true })).toHaveCount(0);
await page.getByLabel("Height", { exact: true }).fill("512");
await page.getByRole("tab", { name: "config.yaml", exact: true }).click();
const qwenConfig = page.getByLabel("Source example", { exact: true });
await expect(qwenConfig).toContainText("model_path: Qwen/Qwen-Image-2.1");
await expect(qwenConfig).toContainText("height: 512");
await expect(qwenConfig).toContainText("dit_layerwise: true");
await expect(page.getByRole("button", { name: "Download YAML", exact: true })).toBeEnabled();
await page
.getByRole("group", { name: "Recipe variant", exact: true })
.getByRole("button", { name: "Qwen-Image-2.1 references and editing", exact: true })
.click();
await page.getByRole("tab", { name: "Commands", exact: true }).click();
await expect(page.getByLabel("Inference command", { exact: true })).toContainText("--reference source.png");
await expect(page.getByRole("button", { name: "Copy example + command", exact: true })).toBeEnabled();
await page.goto("/FastVideo/cookbook");
await page.getByRole("button", { name: "Audio", exact: true }).click();
await expect(page.locator(".recipe-card")).toHaveCount(3);
await page.locator(".recipe-card").first().click();
await page.getByLabel("Audio duration", { exact: true }).fill("1.5");
await expect(page.getByRole("button", { name: "Copy example + command", exact: true })).toBeEnabled();
});
test("provider labels match FastVideo logos and CompactH3 is replaced by FastH3 Trim", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
const ownedCards = page.locator(".recipe-card").filter({ has: page.locator('img[src$="/fastvideo.webp"]') });
for (const card of await ownedCards.all()) await expect(card.locator(".recipe-card-kicker")).toHaveText("FastVideo");
await page.getByLabel("Search recipes").fill("FastH3 Trim");
await expect(page.locator(".recipe-card")).toHaveCount(1);
await page.locator(".recipe-card").click();
await expect(page.getByRole("heading", { level: 1 })).toHaveText("FastH3 Trim");
await expect(page.getByRole("link", { name: "View on Hugging Face ↗", exact: true })).toHaveAttribute(
"href",
/FastVideo-FastH3-Trim-8-Step-NVFP4/,
);
});
test("FastH3 Trim edits drive inference, serving, and complete copyable launch scripts", async ({ page }) => {
await page.addInitScript(() => {
Object.defineProperty(navigator, "clipboard", {
value: {
writeText: async (text: string) => {
(window as Window & { copiedCommand?: string }).copiedCommand = text;
},
},
});
});
await page.goto("/FastVideo/cookbook/minimax-h3/fasth3-trim");
await chooseHardware(page, "DGX Spark");
await expect(page).toHaveURL(/hardware=dgx-spark-gb10-128gb/);
await expect(page.getByText(/128 GB unified memory/)).toBeVisible();
await page.getByLabel("Prompt", { exact: true }).fill("A potter finishes a blue bowl.");
await page.getByLabel("Seed", { exact: true }).fill("0");
await page.getByRole("button", { name: "Copy config + command", exact: true }).click();
const script = await page.evaluate(() => (window as Window & { copiedCommand?: string }).copiedCommand);
expect(script).toContain("cat > config.yaml <<'FASTVIDEO_CONFIG'");
expect(script).toContain("FastVideo-FastH3-Trim-8-Step-NVFP4");
expect(script).toContain('"seed": 0');
expect(script).toContain("FASTVIDEO_VSA_TRITON=1");
expect(script).toContain("fastvideo serve --config config.yaml");
await page.locator(".recipe-request-code summary").click();
await expect(page.getByLabel("Client command", { exact: true })).toContainText("A potter finishes a blue bowl.");
await chip(page, "Run mode", "CLI");
await expect(page.getByLabel("Inference command", { exact: true })).toContainText("fastvideo generate");
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText("request:");
await expect(page.getByLabel("Generated YAML", { exact: true })).not.toContainText("server:");
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText("num_inference_steps: 9");
await chip(page, "Run mode", "Python SDK");
await output(page, "Commands");
await expect(page.getByLabel("SDK command", { exact: true })).toContainText("VideoGenerator.from_config");
await page.setViewportSize({ width: 390, height: 844 });
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true);
});
test("source-backed controls update the copied command without changing models", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3/models/minimax-h3-t2v");
await chip(page, "GPU count", "2");
await expect(page.getByLabel("Inference command", { exact: true })).toContainText("--num-gpus '2'");
});
test("Pika H3 Flex knobs select the tier, bucket, duration, task, and NVFP4 decoder", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3");
const pika = page.locator(".recipe-card").filter({ hasText: "Pika H3 Flex" });
await expect(pika.locator("img")).toHaveAttribute("src", /\/pika\.webp$/);
await expect(pika).toContainText("Pika");
await pika.click();
await expect(page).toHaveURL(/cookbook\/minimax-h3\/models\/pika-h3-flex-t2va$/);
const command = page.getByLabel("Inference command", { exact: true });
await expect(command).toContainText("FASTVIDEO_ATTENTION_BACKEND=FLASH_ATTN FASTVIDEO_FA4=1");
await chip(page, "Resolution", "480p");
await chip(page, "Aspect ratio", "9:16");
await chip(page, "Duration", "10 s (243 frames)");
await chip(page, "VAE decoder", "NVFP4 36L quality");
await expect(command).toContainText("--resolution '480p'");
await expect(command).toContainText("--aspect '9:16'");
await expect(command).toContainText("--duration '10'");
await expect(command).toContainText("--nvfp4-decoder './fasth3-nvfp4-vae/quality-36L/decoder-nvfp4.safetensors'");
await page
.getByRole("group", { name: "Recipe variant", exact: true })
.getByRole("button", { name: "Pika H3 Flex keyframes", exact: true })
.click();
await expect(command).toContainText("--task fl2va --offload resident");
await chip(page, "Task", "First frame (I2VA)");
await chip(page, "Memory", "Lazy load + offload");
await expect(command).toContainText("--task 'i2va'");
await expect(command).toContainText("--offload 'lazy'");
await expect(page.getByRole("button", { name: "Copy example + command", exact: true })).toBeEnabled();
});
test("Wan I2V requires an image for CLI and SDK examples without changing server defaults", async ({ page }) => {
await page.goto("/FastVideo/cookbook/wan/wan21-i2v");
await chip(page, "Run mode", "CLI");
await expect(page.getByRole("alert")).toContainText("Enter a source image path");
await expect(page.getByRole("button", { name: "Copy config + command", exact: true })).toBeDisabled();
await expect(page.getByRole("button", { name: "Download YAML", exact: true })).toBeDisabled();
await page.getByLabel("Source image path", { exact: true }).fill("/data/first-frame.png");
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText("image_path: /data/first-frame.png");
await expect(page.getByRole("button", { name: "Copy config + command", exact: true })).toBeEnabled();
await chip(page, "Run mode", "Python SDK");
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText("image_path: /data/first-frame.png");
await page.getByLabel("Source image path", { exact: true }).fill("");
await expect(page.getByRole("button", { name: "Copy YAML", exact: true })).toBeDisabled();
await expect(page.getByLabel("Generated YAML", { exact: true })).toHaveCount(0);
await chip(page, "Run mode", "Serving");
await expect(page.getByRole("button", { name: "Copy config + command", exact: true })).toBeEnabled();
await expect(page.getByLabel("Generated YAML", { exact: true })).not.toContainText("image_path");
});
test("source editors retain required model flags and preparation commands", async ({ page }) => {
await page.goto("/FastVideo/cookbook/wan/models/fastmetal-1-3b-mlx");
await expect(page.getByLabel("Height", { exact: true })).toHaveValue("480");
await expect(page.getByLabel("Inference command", { exact: true })).toContainText(
"hf download FastVideo/FastMetal-1.3B-QAD",
);
await expect(page.getByLabel("Inference command", { exact: true })).toContainText(
"--model-root ./FastMetal-1.3B-QAD",
);
await page.getByLabel("Seed", { exact: true }).fill("0");
await expect(page.getByLabel("Inference command", { exact: true })).toContainText("--seed '0'");
await page.getByRole("tab", { name: "Python example", exact: true }).click();
await expect(page.getByLabel("Source example", { exact: true })).toContainText("default=480");
});
test("source-backed serving pages expose their actual server settings", async ({ page }) => {
await page.goto("/FastVideo/cookbook/wan/models/wan22-t2v");
await chip(page, "Run mode", "Serving");
await page.locator(".matrix-advanced > summary").click();
await page.getByLabel("Port", { exact: true }).fill("9005");
await page.getByRole("button", { name: "Show request", exact: true }).click();
await expect(page.getByLabel("Client command", { exact: true })).toContainText(":9005/v1/videos/sync");
await page.getByRole("tab", { name: "config.yaml", exact: true }).click();
await expect(page.getByLabel("Source example", { exact: true })).toContainText("port: 9005");
await expect(page.getByLabel("Source example", { exact: true })).toContainText("Wan2.2-T2V-A14B");
await expect(page.getByRole("button", { name: "Copy config + command", exact: true })).toBeEnabled();
});
test("PAN 2 has a family card with the IFM logo and an editable serving deployment", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
await page.getByLabel("Search recipes").fill("PAN 2");
const pan2 = page.locator(".recipe-card");
await expect(pan2).toHaveCount(1);
await expect(pan2.locator("img")).toHaveAttribute("src", /\/ifm\.webp$/);
await expect(pan2.locator(".recipe-card-kicker")).toHaveText("IFM");
await pan2.click();
await expect(page).toHaveURL(/cookbook\/pan\/pan2$/);
await expect(page.locator(".recipe-matrix")).toBeVisible({ timeout: 30000 });
await expect(page.getByRole("heading", { level: 1 })).toHaveText("PAN 2");
await settings(page, "Serving");
await page.getByLabel("Port", { exact: true }).fill("9010");
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText(/"port": 9010/);
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText(/"model_path": "IFM\/PAN2"/);
await expect(page.getByLabel("Generated YAML", { exact: true })).toContainText(/"dit_layerwise": false/);
await expect(page.getByRole("button", { name: "Download YAML", exact: false })).toBeEnabled();
});
test("source model hardware preferences survive hydration and reload", async ({ page }) => {
const errors: string[] = [];
page.on("pageerror", (error) => errors.push(error.message));
await page.goto(
"/FastVideo/cookbook/flux/models/flux2-klein-t2i?hardware=custom&hwName=RTX+4090&hwType=dedicated&hwMemory=24&hwUnit=GB",
);
await expect(page.getByText("RTX 4090", { exact: true })).toBeVisible();
await expect(page.locator(".hardware-selected")).toContainText("24 GB VRAM");
await page.reload();
await expect(page.getByText("RTX 4090", { exact: true })).toBeVisible();
expect(errors).toEqual([]);
});
test("custom devices persist and no preview control can block generated YAML", async ({ page }) => {
await page.goto(route);
await page.getByRole("button", { name: "+ Find or add a GPU", exact: true }).click();
await page.getByRole("button", { name: "Can't find it? Add a device", exact: true }).click();
await page.getByLabel("Device name", { exact: true }).fill("RTX 4090");
await page.getByRole("combobox", { name: "Memory type", exact: true }).selectOption("dedicated");
await page.getByRole("spinbutton", { name: "Total memory", exact: true }).fill("24");
await page.getByRole("spinbutton", { name: "Usable memory (optional)", exact: true }).fill("32");
await expect(page.getByText("Usable memory cannot exceed total memory.", { exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Save device", exact: true })).toBeDisabled();
await page.getByRole("spinbutton", { name: "Usable memory (optional)", exact: true }).fill("22");
await page.getByRole("spinbutton", { name: "Host RAM (optional)", exact: true }).fill("64");
await page.getByRole("button", { name: "Save device", exact: true }).click();
await expect(page.getByText("RTX 4090", { exact: true })).toBeVisible();
await expect(page.locator(".hardware-selected")).toContainText("24 GB VRAM");
await expect(page.locator(".hardware-selected")).toContainText("Usable memory: 22 GB");
await expect(page.locator(".hardware-selected")).toContainText("Host RAM: 64 GB");
await expect(page).toHaveURL(/hardware=custom/);
await expect(page).toHaveURL(/hwName=RTX\+4090/);
await page.reload();
await expect(page.getByText("RTX 4090", { exact: true })).toBeVisible();
await expect(page.locator(".hardware-selected")).toContainText("24 GB VRAM");
await expect(page.locator(".component-plan")).toHaveCount(0);
await expect(page.getByRole("button", { name: "Download YAML", exact: true })).toBeEnabled();
await page.getByRole("button", { name: "Clear hardware", exact: true }).click();
await expect(page.getByText("RTX 4090", { exact: true })).toHaveCount(0);
await expect(page.getByText("No hardware selected.", { exact: true })).toBeVisible();
});
test("hardware is never preselected and a desktop card keeps the recipe GPU count", async ({ page }) => {
await page.goto(route);
await expect(page.locator(".hardware-picker")).toBeVisible({ timeout: 30000 });
await expect(page.getByText("No hardware selected.", { exact: true })).toBeVisible();
await output(page, "config.yaml");
const yaml = page.getByLabel("Generated YAML", { exact: true });
await expect(yaml).toContainText('"num_gpus": 4');
await chooseHardware(page, "RTX 5090");
await expect(page).toHaveURL(/hardware=geforce-rtx-5090-32gb/);
await expect(page.getByText(/GeForce RTX 5090 .*32 GB VRAM/)).toBeVisible();
await expect(yaml).toContainText('"num_gpus": 4');
await expect(yaml).not.toContainText('"hardware"');
await expect(page.getByText("Schema checks passed", { exact: true })).toBeVisible();
await page.getByRole("button", { name: "Clear hardware", exact: true }).click();
await expect(page.getByText("No hardware selected.", { exact: true })).toBeVisible();
});
test("lowering the GPU count resets parallelism that no longer fits", async ({ page }) => {
await page.goto(route);
await output(page, "config.yaml");
const yaml = page.getByLabel("Generated YAML", { exact: true });
await page.getByLabel("GPU count", { exact: true }).fill("2");
await expect(page.getByText("Parallelism set to automatic for 2 GPUs.")).toBeVisible();
await expect(yaml).toContainText('"num_gpus": 2');
await expect(yaml).toContainText('"sp_size": -1');
await expect(page.getByText("Schema checks passed", { exact: true })).toBeVisible();
});
test("browser back after a hardware-only change keeps the editor loaded", async ({ page }) => {
await page.goto(route);
await expect(page.getByRole("button", { name: "Download YAML", exact: true })).toBeEnabled();
await chooseHardware(page, "RTX 5090");
await expect(page).toHaveURL(/hardware=geforce-rtx-5090-32gb/);
await page.goBack();
await expect(page).not.toHaveURL(/hardware=/);
await expect(page.getByText("No hardware selected.", { exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Download YAML", exact: true })).toBeEnabled();
await expect(page.getByText("Loading deployment settings…")).toHaveCount(0);
});
test("hardware links resolve catalog aliases and non-CUDA devices are not CUDA targets", async ({ page }) => {
await page.goto(`${route}?hardware=5090`);
await expect(page.locator(".hardware-selected")).toContainText("RTX 5090");
await page.getByRole("button", { name: "Change hardware", exact: true }).click();
await page.getByLabel("Search hardware", { exact: true }).fill("Arc B580");
await expect(page.getByRole("radio", { name: /Arc B580/ })).toHaveCount(0);
});
test("recipe facts state validity and why memory has no estimate", async ({ page }) => {
await page.goto(route);
const facts = page.locator(".recipe-facts");
await expect(facts.getByText("Schema checks passed", { exact: true })).toBeVisible();
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
await page.getByRole("button", { name: "Details", exact: true }).click();
await expect(page.getByText(/Select a device to estimate memory/)).toBeVisible();
});
test("component defaults are selected and decoder choices stay consistent with copied YAML", async ({ page }) => {
await page.goto(route);
const decoder = page.getByRole("group", { name: "NVFP4 video decoder", exact: true });
await expect(decoder.getByRole("button", { name: "Original", exact: true })).toHaveAttribute("aria-pressed", "true");
await expect(
page
.getByRole("group", { name: "Text encoder", exact: true })
.getByRole("button", { name: "Bundled", exact: true }),
).toHaveAttribute("aria-pressed", "true");
await chip(page, "Video decoder", "taeh3");
await decoder.getByRole("button", { name: /8L/ }).click();
await expect(
page
.getByRole("group", { name: "Video decoder", exact: true })
.getByRole("button", { name: "h3-vae", exact: true }),
).toHaveAttribute("aria-pressed", "true");
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML")).toContainText('"video_decode_backend": "h3-vae"');
await expect(page.getByLabel("Generated YAML")).toContainText("fast-8L/decoder-nvfp4.safetensors");
await chip(page, "Video decoder", "taeh3");
await expect(page.getByLabel("Generated YAML")).toContainText('"h3_vae_nvfp4_decoder": null');
await expect(decoder.getByRole("button", { name: "Original", exact: true })).toHaveAttribute("aria-pressed", "true");
await page.getByRole("button", { name: "Reset changes", exact: true }).click();
await expect(page.getByLabel("Generated YAML")).not.toContainText("h3_vae_nvfp4_decoder");
});
test("failed memory metadata is visible and retry restores checkpoint data", async ({ page }) => {
await page.route("**/capacity/index.json", (route) => route.fulfill({ status: 503, body: "unavailable" }));
await page.goto(`${route}?hardware=custom&hwName=GPU&hwType=dedicated&hwMemory=80&hwUnit=GiB&hwBackend=cuda`);
await expect(page.getByText(/Memory data could not load/)).toBeVisible();
await expect(page.getByText(/Known checkpoint data/)).toHaveCount(0);
await page.unroute("**/capacity/index.json");
await page.getByRole("button", { name: "Retry memory data", exact: true }).click();
await expect(page.getByText(/Known checkpoint data: 137\.7 GiB. Device budget: 80\.0 GiB/)).toBeVisible();
await expect(page.getByText(/Memory data could not load/)).toHaveCount(0);
await expect(page.getByText("Weights fit", { exact: true })).toHaveCount(0);
});
test("host-only system RAM cannot produce a GPU weights fit verdict", async ({ page }) => {
await page.goto(`${route}?hardware=custom&hwName=Host&hwType=system&hwMemory=128&hwUnit=GB&hwBackend=cuda`);
const facts = page.locator(".recipe-facts");
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
await page.getByRole("button", { name: "Details", exact: true }).click();
await expect(facts.getByText(/Host-only system RAM is not GPU capacity/)).toBeVisible();
await expect(facts.getByText(/Resident weights need/)).toHaveCount(0);
await expect(page.getByRole("button", { name: "Download YAML", exact: false })).toBeEnabled();
});
test("TAEH3 stops using the bundled VAE weights in memory facts", async ({ page }) => {
await page.goto(`${route}?hardware=custom&hwName=GPU&hwType=dedicated&hwMemory=80&hwUnit=GB&hwBackend=cuda`);
const facts = page.locator(".recipe-facts");
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
await chip(page, "Video decoder", "taeh3");
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
await page.getByRole("button", { name: "Details", exact: true }).click();
await expect(facts.getByText(/Missing sizes for TAEH3 decoder/)).toBeVisible();
await expect(facts.getByText(/Resident weights need/)).toHaveCount(0);
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML")).toContainText('"video_decode_backend": "taeh3"');
await chip(page, "Video decoder", "h3-vae");
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
});
test("FastH3 keeps unmodeled quantization and decoder residency unknown", async ({ page }) => {
await page.goto(route);
await chooseHardware(page, "RTX 5090");
const facts = page.locator(".recipe-facts");
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
await page.getByRole("button", { name: "Details", exact: true }).click();
await expect(page.getByText(/Known checkpoint data: 137\.7 GiB. Device budget: 29\.8 GiB/)).toBeVisible();
await page
.getByRole("group", { name: "Transformer quantization", exact: true })
.getByRole("button", { name: "NVFP4", exact: true })
.click();
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
await expect(facts.getByText(/selected quantization and layer profile/)).toBeVisible();
await expect(facts.getByText(/Resident weights need/)).toHaveCount(0);
await page
.getByRole("group", { name: "NVFP4 video decoder", exact: true })
.getByRole("button", { name: /8L · fast/ })
.click();
await expect(facts.getByText("Memory not estimated", { exact: true })).toBeVisible();
await expect(facts.getByText(/VAE with the NVFP4 decoder and retained encoder/)).toBeVisible();
await expect(facts.getByText(/Resident weights need/)).toHaveCount(0);
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML")).toContainText('"transformer_quant": "NVFP4"');
await expect(page.getByLabel("Generated YAML")).toContainText("fast-8L/decoder-nvfp4.safetensors");
});
test("4-Step quantization and full-depth decoder swaps also stay unestimated", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3/fasth3-4step");
await chooseHardware(page, "RTX 5090");
const facts = page.locator(".recipe-facts");
await page.getByRole("button", { name: "Details", exact: true }).click();
await chip(page, "Transformer quantization", "FP8");
await expect(facts.getByText(/selected quantization and layer profile/)).toBeVisible();
await chip(page, "Transformer quantization", "Default");
await page
.getByRole("group", { name: "NVFP4 video decoder", exact: true })
.getByRole("button", { name: /36L/ })
.click();
await expect(facts.getByText(/VAE with the NVFP4 decoder and retained encoder/)).toBeVisible();
await expect(facts.getByText(/Resident weights need/)).toHaveCount(0);
});
test("the retired Preview route and deployment links keep their checkpoint", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3/fasth3-preview");
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML")).toContainText("FastVideo-Minimax-FastH3-Preview-v0.2");
await page.goto("/FastVideo/cookbook?deployment=fasth3-preview%2Fcuda-rest");
await expect(page).toHaveURL(/minimax-h3\/fasth3-preview/);
await output(page, "config.yaml");
await expect(page.getByLabel("Generated YAML")).toContainText("FastVideo-Minimax-FastH3-Preview-v0.2");
});
for (const [deployment, label, sequential, tileBatch] of [
["rtx5090-rest", "RTX 5090", true, "4"],
["rtx-pro6000-rest", "RTX PRO 6000", false, "8"],
["spark-rest", "DGX Spark", false, "12"],
["cuda-rest", "RTX 5090", true, "4"],
] as const) {
test(`Omni deployment link ${deployment} preserves its hardware baseline`, async ({ page }) => {
await page.goto(`/FastVideo/cookbook?deployment=fasth3-omniref%2F${deployment}`);
await expect(page).toHaveURL(/minimax-h3\/fasth3-omniref/);
await expect(page.getByRole("button", { name: label, exact: true })).toHaveAttribute("aria-pressed", "true");
await page.getByRole("button", { name: "Serving", exact: true }).click();
await output(page, "config.yaml");
const yaml = page.getByLabel("Generated YAML");
await expect(yaml).toContainText(`"h3_sequential_load": ${sequential}`);
await expect(yaml).toContainText('"layer_profile": "h3_dit_vsa"');
await output(page, "Commands");
await expect(page.getByLabel("Server command")).toContainText(`FASTVIDEO_H3_VAE_TILE_BATCH=${tileBatch}`);
if (deployment === "spark-rest")
await expect(page.getByLabel("Server command")).toContainText("FASTVIDEO_NVFP4_MM_BACKEND=cudnn");
});
}
test("packed FastH3 checkpoints keep their fixed precision", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3/fasth3-trim");
await page.getByRole("tab", { name: "config.yaml" }).click();
await expect(page.getByLabel("Generated YAML")).toContainText('"transformer_quant": "NVFP4"');
await expect(page.getByLabel("Generated YAML")).toContainText('"layer_profile": "h3_dit_vsa"');
await expect(page.getByText("Schema checks passed", { exact: true })).toBeVisible();
await expect(page.getByRole("group", { name: "Transformer quantization", exact: true })).toHaveCount(0);
});
test("MLX FastH3 stays unestimated and a GiB device keeps its unit", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3/fasth3-8step?deployment=fasth3-8step%2Fmlx-rest");
await page.getByRole("button", { name: "+ Find or add a Mac", exact: true }).click();
await page.getByLabel("Search hardware", { exact: true }).fill("M4 Max");
await page.getByRole("radio", { name: /Apple M4 Max 128 GB/ }).click();
await expect(page.getByText("Memory not estimated", { exact: true })).toBeVisible();
await page.getByRole("button", { name: "Details", exact: true }).click();
await expect(page.getByText(/MLX checkpoints use a different precision/)).toBeVisible();
await page.goto(
"/FastVideo/cookbook/minimax-h3/fasth3-8step?hardware=custom&hwName=Big&hwType=dedicated&hwMemory=80&hwUnit=GiB&hwBackend=cuda",
);
await expect(page.getByText(/Device budget: 80\.0 GiB/)).toBeVisible();
});
test("catalog lookup resolves aliases, variants, and unified memory without pooling", async ({ page }) => {
await page.goto(route);
await chooseHardware(page, "PRO 6000");
await expect(page).toHaveURL(/hardware=rtx-pro-6000-blackwell-workstation-96gb/);
await expect(page.locator(".hardware-selected")).toContainText("96 GB VRAM");
await expect(page.locator(".hardware-address-note")).toContainText("Per device, not a combined pool");
await page.getByRole("button", { name: "Clear hardware", exact: true }).click();
await page.getByRole("button", { name: "+ Find or add a GPU", exact: true }).click();
await page.getByLabel("Search hardware", { exact: true }).fill("GB10");
await page.getByRole("radio", { name: /DGX Spark/ }).click();
await expect(page.locator(".hardware-selected")).toContainText("128 GB unified memory");
await expect(page.locator(".hardware-selected")).toContainText("CUDA");
await expect(page.locator(".hardware-address-note")).toContainText("not dedicated VRAM");
await settings(page, "Hardware");
await page.getByLabel("GPU count", { exact: true }).fill("8");
await expect(page.getByText(/8 GPUs share unified memory/)).toBeVisible();
await expect(page.getByText(/its 128 GB is not multiplied/)).toBeVisible();
});
test("MLX lookup uses unified memory and a custom Mac stays reusable", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3/fasth3-8step?deployment=fasth3-8step%2Fmlx-rest");
await page.getByRole("button", { name: "+ Find or add a Mac", exact: true }).click();
await page.getByLabel("Search hardware", { exact: true }).fill("M4 Max");
await page.getByRole("radio", { name: /Apple M4 Max/ }).click();
await expect(page.locator(".hardware-selected")).toContainText("128 GB unified memory");
await expect(page.locator(".hardware-selected")).toContainText("Apple MLX");
await expect(page.locator(".hardware-selected")).toContainText("Usable memory: 96 GB");
await expect(page.locator(".hardware-address-note")).toContainText("not dedicated VRAM");
await expect(page.getByRole("button", { name: "Clear hardware", exact: true })).toBeVisible();
});
test("the directory filters by runtime without a hardware picker", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
await expect(page.locator(".recipe-directory .hardware-picker")).toHaveCount(0);
await page.getByLabel("Runtime", { exact: true }).selectOption("mlx");
await expect(page).toHaveURL(/runtime=mlx/);
const card = page.locator(".recipe-card").filter({ hasText: "FastMetal 1.3B" });
await expect(card).toBeVisible();
await expect(card).toHaveAttribute("href", /\/cookbook\/wan\/models\/[^?]+$/);
await expect(page.locator(".recipe-card").filter({ hasText: "FastWan2.1 1.3B" })).toHaveCount(0);
});
test("MLX Omni discovery and its original route expose the MLX launch command", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
await page.getByLabel("Runtime", { exact: true }).selectOption("mlx");
await page.getByLabel("Search recipes").fill("FastH3 Omni");
const cards = page.locator(".recipe-card");
await expect(cards).toHaveCount(1);
await expect(cards).toHaveAttribute("href", "/FastVideo/cookbook/minimax-h3/models/fasth3-omniref-mlx");
await cards.click();
await expect(page.getByLabel("Inference command")).toContainText("convert_minimax_h3_mlx.py");
await expect(page.getByLabel("Inference command")).toContainText("--mlx-checkpoint ./FastH3-OmniRef-MLX/int6");
await expect(page.getByLabel("Inference command")).not.toContainText("fastvideo serve");
await page.reload();
await expect(page.getByLabel("Inference command")).toContainText("--mlx-checkpoint ./FastH3-OmniRef-MLX/int6");
});
test("category counts match visible cards and exclude retired Preview", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
await expect(page.locator(".recipe-card")).toHaveCount(39);
for (const category of ["All models", "Video", "Image", "Audio", "World"]) {
const button = page.getByRole("button", { name: category, exact: true });
const count = Number(await button.locator(".recipe-filter-count").innerText());
await button.click();
await expect(page.locator(".recipe-card")).toHaveCount(count);
await expect(page.locator(".recipe-card").filter({ hasText: "FastH3 Preview V0.2" })).toHaveCount(0);
}
});
test("task discovery filters the directory and round-trips through the URL", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
await page.getByLabel("Task", { exact: true }).selectOption("Image to video");
await expect(page).toHaveURL(/task=Image\+to\+video/);
await expect(page.locator(".recipe-card").filter({ hasText: "Wan2.1 I2V 14B" })).toBeVisible();
await expect(page.locator(".recipe-card").filter({ hasText: "FastWan2.1 1.3B" })).toHaveCount(0);
await page.reload();
await expect(page.getByLabel("Task", { exact: true })).toHaveValue("Image to video");
await page.getByLabel("Task", { exact: true }).selectOption("All tasks");
await expect(page).not.toHaveURL(/task=/);
});
test("directory filters round-trip through the URL", async ({ page }) => {
await page.goto("/FastVideo/cookbook?category=Image&runtime=cuda");
await expect(page.getByRole("button", { name: "Image", exact: true })).toHaveAttribute("aria-pressed", "true");
await expect(page.getByLabel("Runtime", { exact: true })).toHaveValue("cuda");
await expect(page.locator(".recipe-card")).toHaveCount(5);
await page.reload();
await expect(page.getByRole("button", { name: "Image", exact: true })).toHaveAttribute("aria-pressed", "true");
await expect(page.getByLabel("Runtime", { exact: true })).toHaveValue("cuda");
await expect(page.locator(".recipe-card")).toHaveCount(5);
});
test("a saved target missing from the catalog stays visible and clearable", async ({ page }) => {
await page.goto(`${route}?hardware=retired-gpu`);
await expect(page.getByText(/The saved device \(retired-gpu\) is not in this catalog/)).toBeVisible();
await page.getByRole("button", { name: "Clear hardware", exact: true }).click();
await expect(page).not.toHaveURL(/hardware=/);
await expect(page.getByText("No hardware selected.", { exact: true })).toBeVisible();
});
test("catalog search renders one plain no-results message", async ({ page }) => {
await page.goto(route);
await page.getByRole("button", { name: "+ Find or add a GPU", exact: true }).click();
await page.getByLabel("Search hardware", { exact: true }).fill("no-such-device");
await expect(page.getByText("No matching devices.", { exact: true })).toHaveCount(1);
await page.getByRole("button", { name: "Can't find it? Add a device", exact: true }).click();
await expect(page.getByLabel("Device name", { exact: true })).toBeVisible();
});
test("hardware lookup closes with Escape and returns focus", async ({ page }) => {
await page.goto(route);
await page.getByRole("button", { name: "+ Find or add a GPU", exact: true }).click();
await expect(page.getByLabel("Search hardware", { exact: true })).toBeFocused();
await page.keyboard.press("Escape");
await expect(page.getByLabel("Search hardware", { exact: true })).toHaveCount(0);
await expect(page.getByRole("button", { name: "+ Find or add a GPU", exact: true })).toBeFocused();
});
test("WebSocket deployments expose only the serving interface", async ({ page }) => {
await page.goto("/FastVideo/cookbook/ltx/ltx2-distilled");
const modes = page.getByRole("group", { name: "Run mode" });
await expect(modes.getByRole("button")).toHaveCount(1);
await expect(modes.getByRole("button", { name: "Serving", exact: true })).toHaveAttribute("aria-pressed", "true");
await expect(modes.getByRole("button", { name: "Python SDK", exact: true })).toHaveCount(0);
await expect(modes.getByRole("button", { name: "CLI", exact: true })).toHaveCount(0);
await expect(page.getByText(/Only serving is recorded for it/)).toBeVisible();
});
test("video-to-video deployments expose only the serving interface", async ({ page }) => {
await page.goto("/FastVideo/cookbook/minimax-h3/open-h3-regenerate-2k");
const modes = page.getByRole("group", { name: "Run mode" });
await expect(modes.getByRole("button")).toHaveCount(1);
await expect(modes.getByRole("button", { name: "Serving", exact: true })).toHaveAttribute("aria-pressed", "true");
await expect(page.getByText(/Send it to the server as video_reference/)).toBeVisible();
});
test("Open-H3-Regenerate-2K is discoverable as a video upscale with its serving page", async ({ page }) => {
await page.goto("/FastVideo/cookbook");
await page.getByLabel("Task", { exact: true }).selectOption("Video upscale");
const card = page.locator(".recipe-card").filter({ hasText: "Open-H3-Regenerate-2K" });
await expect(card).toHaveCount(1);
await card.click();
await expect(page).toHaveURL(/cookbook\/minimax-h3\/open-h3-regenerate-2k\/?$/);
await expect(page.getByRole("heading", { level: 1 })).toHaveText("Open-H3-Regenerate-2K");
});