153 lines
5.0 KiB
TypeScript
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");
|
|
}
|
|
});
|
|
});
|