First Init
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
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
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
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();
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user