import { test, expect } from "@playwright/test"; test.describe("YouTube Web App E2E Tests", () => { test.beforeEach(async ({ page }) => { // Go to home page for tests that need it await page.goto("http://localhost:5173"); }); test("should visit the home page", async ({ page }) => { await expect(page).toHaveTitle(/YouTube/); const searchInput = page.locator( 'input[placeholder="Enter YouTube URL or search query..."]', ); await expect(searchInput).toBeVisible(); }); test("should search for a video", async ({ page }) => { const searchInput = page.locator( 'input[placeholder="Enter YouTube URL or search query..."]', ); await searchInput.fill("test video"); await page.keyboard.press("Enter"); await page.waitForTimeout(2000); const searchForm = page.locator( 'form:has(input[placeholder="Enter YouTube URL or search query..."])', ); await expect(searchForm).toBeVisible(); }); test("should display search results", async ({ page }) => { const searchInput = page.locator( 'input[placeholder="Enter YouTube URL or search query..."]', ); await searchInput.fill("test"); await page.keyboard.press("Enter"); // Wait for search button to be disabled (search in progress) await page.waitForSelector('button[disabled]:has-text("Searching...")', { timeout: 10000, }); // Wait for search to complete (button reappears enabled) await page.waitForSelector('button:has-text("Search")', { timeout: 30000, }); // Wait for search results to appear await page.waitForSelector("h2:has-text('Search Results')", { state: "visible", timeout: 10000, }); await expect(page.locator("h2:has-text('Search Results')")).toBeVisible(); }); test("should navigate to queue page", async ({ page }) => { // Mock queue API call await page.route("**/api/queue", (route) => { route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ queue: [], total: 0 }), }); }); await page.goto("http://localhost:5173/queue"); await expect(page).toHaveURL("http://localhost:5173/queue"); await expect(page.locator("text=Download Queue")).toBeVisible(); }); test("should navigate to archive page", async ({ page }) => { // Go to archive page - the API is mocked by the running Flask server await page.goto("http://localhost:5173/archive"); await expect(page).toHaveURL("http://localhost:5173/archive"); // Wait for the main container to appear await page.waitForSelector(".max-w-7xl", { timeout: 15000 }); // Verify the page has the archive heading await expect(page.locator("h1:has-text('Video Archive')")).toBeVisible({ timeout: 10000, }); }); test("should click on a search result card and display video information", async ({ page, }) => { // Search for "test video" const searchInput = page.locator( 'input[placeholder="Enter YouTube URL or search query..."]', ); await searchInput.fill("test video"); await page.keyboard.press("Enter"); // Wait for search button to be disabled (search in progress) await page.waitForSelector('button[disabled]:has-text("Searching...")', { timeout: 10000, }); // Wait for search to complete (button reappears enabled) await page.waitForSelector('button:has-text("Search")', { timeout: 30000, }); // Wait for search results to appear await page.waitForSelector("h2:has-text('Search Results')", { state: "visible", timeout: 10000, }); // Wait for search result cards to appear await page.waitForSelector(".bg-slate-800.rounded-xl", { timeout: 10000, }); // Get the first search result card and click it // Use a more specific selector that targets search result cards by their structure // Cards contain thumbnail (aspect-video), title, channel, and views await page.waitForSelector(".aspect-video img", { timeout: 10000 }); // Count only the result cards (not other elements with similar classes) const resultCards = page.locator(".grid.grid-cols-1 .bg-slate-800"); const cardCount = await resultCards.count(); if (cardCount > 0) { await resultCards.first().click(); // Wait for navigation to complete by checking URL change await page.waitForFunction( () => { const url = window.location.href; return url.includes("/results"); }, { timeout: 10000 }, ); // Wait for video information to be displayed await page.waitForSelector("h1.text-2xl", { timeout: 10000 }); // Verify video information elements are visible await expect(page.locator("h1.text-2xl")).toBeVisible({ timeout: 10000, }); await expect(page.locator("text=Channel")).toBeVisible({ timeout: 10000, }); await expect(page.locator("text=Download Options")).toBeVisible({ timeout: 10000, }); } else { console.log("No search results found - test skipped clicking"); } }); });