import { test, expect } from '@playwright/test'; test.describe('Portfolio Filter Tests', () => { test.beforeEach(async ({ page }) => { await page.goto('/portfolio'); }); test('portfolio page loads with projects', async ({ page }) => { // Check for portfolio grid/container const portfolioContainer = page.locator('[class*="portfolio"], [class*="grid"], [class*="projects"]').first(); await expect(portfolioContainer).toBeVisible(); // Check for project cards const projects = page.locator('[class*="project"], [class*="card"], article').filter({ hasText: /./ }); const count = await projects.count(); expect(count).toBeGreaterThan(0); }); test('filter buttons are present', async ({ page }) => { // Look for filter buttons const filterButtons = page.locator('button[data-filter], button[data-category], [role="tab"], .filter-btn, [class*="filter"]').filter({ hasText: /./ }); const count = await filterButtons.count(); if (count > 0) { // Check that "All" filter exists const allButton = page.locator('button, [role="tab"]').filter({ hasText: /all/i }).first(); await expect(allButton).toBeVisible(); } }); test('filter functionality works', async ({ page }) => { // Find filter buttons const filterButtons = page.locator('button[data-filter], button[data-category], [role="tab"], .filter-btn').filter({ hasText: /./ }); const buttonCount = await filterButtons.count(); if (buttonCount > 1) { // Get initial project count const initialProjects = page.locator('[class*="project"], [class*="card"], [data-category]').filter({ hasText: /./ }); const initialCount = await initialProjects.count(); // Click on a specific category (not "All") const categoryButton = filterButtons.nth(1); await categoryButton.click(); // Wait for filter animation await page.waitForTimeout(500); // Projects should be filtered (count may change) const filteredProjects = page.locator('[class*="project"], [class*="card"], [data-category]:visible').filter({ hasText: /./ }); const filteredCount = await filteredProjects.count(); // Either the count changed or stays same (if all match) expect(filteredCount).toBeGreaterThanOrEqual(0); // Click "All" to reset const allButton = page.locator('button, [role="tab"]').filter({ hasText: /all/i }).first(); if (await allButton.isVisible()) { await allButton.click(); await page.waitForTimeout(500); const resetProjects = page.locator('[class*="project"], [class*="card"]').filter({ hasText: /./ }); const resetCount = await resetProjects.count(); expect(resetCount).toBe(initialCount); } } }); test('active filter state updates', async ({ page }) => { const filterButtons = page.locator('button[data-filter], button[data-category], [role="tab"]').filter({ hasText: /./ }); const buttonCount = await filterButtons.count(); if (buttonCount > 1) { // Click second filter button const secondButton = filterButtons.nth(1); await secondButton.click(); // Check for active state (aria-selected, active class, etc.) const hasActiveState = await secondButton.evaluate((el) => { return el.classList.contains('active') || el.getAttribute('aria-selected') === 'true' || el.getAttribute('data-active') === 'true' || el.classList.contains('bg-cyan-500') || el.classList.contains('text-white'); }); expect(hasActiveState).toBeTruthy(); } }); test('project cards have required content', async ({ page }) => { const projectCards = page.locator('[class*="project"], [class*="card"], article').filter({ hasText: /./ }).first(); if (await projectCards.isVisible()) { // Check for image const hasImage = await projectCards.locator('img').count() > 0; // Check for title const hasTitle = await projectCards.locator('h2, h3, h4, [class*="title"]').count() > 0; expect(hasImage || hasTitle).toBeTruthy(); } }); }); test.describe('Portfolio Responsive Tests', () => { const viewports = [ { name: 'mobile', width: 375, height: 667 }, { name: 'tablet', width: 768, height: 1024 }, { name: 'desktop', width: 1920, height: 1080 }, ]; for (const viewport of viewports) { test(`portfolio grid adapts to ${viewport.name}`, async ({ page }) => { await page.setViewportSize({ width: viewport.width, height: viewport.height }); await page.goto('/portfolio'); // Grid should be visible const grid = page.locator('[class*="grid"], [class*="portfolio"]').first(); await expect(grid).toBeVisible(); // Check grid columns based on viewport const gridStyle = await grid.evaluate((el) => { const style = window.getComputedStyle(el); return { display: style.display, gridTemplateColumns: style.gridTemplateColumns, }; }); // Should use grid or flex for layout expect(['grid', 'flex'].includes(gridStyle.display) || gridStyle.gridTemplateColumns).toBeTruthy(); }); } });