// The channel video-list filter chips are multi-select and combine as an // intersection: selecting Transcribed + Partial shows only videos that are // BOTH transcribed and still carry a leftover .part download. This is how you // find an already-transcribed video whose audio download was left partial. import { rename, writeFile } from "node:fs/promises"; import { test, expect } from "@playwright/test"; import { channelVideos, generateReport, resetData, resolvePath, } from "./helpers"; const CHANNEL = "test-transcribe"; const DATA = `test-transcripts/channels/${CHANNEL}/data`; // A non-empty whisper transcript so the video reads as transcribed (and isn't // flagged untranscribable for being empty). const WHISPER = JSON.stringify({ transcription: [{ text: "hello" }] }); async function seedThreeStates() { await resetData("one-transcribe-channel-with-audio"); // vidA: transcribed AND partial — has a whisper transcript and a leftover // .part, with no finalized audio. await writeFile(resolvePath(`${DATA}/vidA/transcript.json`), WHISPER); await rename( resolvePath(`${DATA}/vidA/audio.m4a`), resolvePath(`${DATA}/vidA/audio.m4a.part`), ); // vidB: transcribed only — keeps its finalized audio. await writeFile(resolvePath(`${DATA}/vidB/transcript.json`), WHISPER); // vidC: partial only — a .part and no transcript. await rename( resolvePath(`${DATA}/vidC/audio.m4a`), resolvePath(`${DATA}/vidC/audio.m4a.part`), ); } test("Transcribed + Partial filters intersect to the both-states video", async ({ page, }) => { await seedThreeStates(); await generateReport(page, CHANNEL); await page.goto(channelVideos(CHANNEL)); const list = page.getByLabel("videos", { exact: true }); // All three visible by default. await expect(list.getByLabel(/^open vid[ABC]$/)).toHaveCount(3); // Transcribed alone: vidA + vidB (vidA is transcribed even though its status // is partial_download). await page.getByRole("button", { name: "Transcribed", exact: true }).click(); await expect(list.getByLabel("open vidA")).toBeVisible(); await expect(list.getByLabel("open vidB")).toBeVisible(); await expect(list.getByLabel("open vidC")).toBeHidden(); // Add Partial: intersection is vidA only. await page.getByRole("button", { name: "Partial", exact: true }).click(); await expect(list.getByLabel("open vidA")).toBeVisible(); await expect(list.getByLabel("open vidB")).toBeHidden(); await expect(list.getByLabel("open vidC")).toBeHidden(); // URL carries both filters, and a reload preserves the selection. await expect .poll(() => (new URL(page.url()).searchParams.get("filter") ?? "").split(",").sort(), ) .toEqual(["partial", "transcribed"]); await page.reload(); const listAfter = page.getByLabel("videos", { exact: true }); await expect(listAfter.getByLabel("open vidA")).toBeVisible(); await expect(listAfter.getByLabel(/^open vid[ABC]$/)).toHaveCount(1); await expect( page.getByRole("button", { name: "Transcribed", exact: true }), ).toHaveAttribute("aria-pressed", "true"); await expect(page.getByRole("button", { name: "Partial", exact: true })).toHaveAttribute( "aria-pressed", "true", ); // All clears back to the full list. await page.getByRole("button", { name: "All", exact: true }).click(); await expect(page.getByLabel("videos", { exact: true }).getByLabel(/^open vid[ABC]$/)).toHaveCount( 3, ); });