2026-03-31 17:39:27 -05:00

153 lines
5.0 KiB
TypeScript

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");
}
});
});