Files
CompanySite/tests/portfolio.spec.ts
T
Clintchiz d402256547
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped
First Init
2026-03-21 16:46:46 +05:30

135 lines
5.1 KiB
TypeScript

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