Files
my-protfolio/e2e/project-case-study.spec.ts
Amirhossein Khalili 24cd86ede7
Some checks failed
Test and deploy / Verify production build (push) Has been cancelled
Test and deploy / Deploy production (push) Has been cancelled
feat: add route-backed project case studies
2026-09-09 22:00:57 +03:30

79 lines
4.0 KiB
TypeScript

import { expect, test } from '@playwright/test';
const caseStudyPath = '/projects/qlockify';
async function expectDrawerOpen(page: import('@playwright/test').Page) {
const dialog = page.locator('dialog[open]');
await expect(dialog).toHaveAttribute('data-state', 'open');
await expect(dialog).toBeVisible();
return dialog;
}
test('a card CTA opens a route-backed drawer and restores the portfolio', async ({ page }) => {
await page.goto('/', { waitUntil: 'domcontentloaded' });
await page.evaluate(() => {
window.scrollTo({ top: document.body.scrollHeight * 0.35, behavior: 'instant' });
});
const card = page.getByRole('article', { name: 'Qlockify' });
const cta = card.getByRole('link', { name: 'View case study' });
await cta.focus();
const portfolioScroll = await page.evaluate(() => window.scrollY);
await cta.press('Enter');
await expect(page).toHaveURL(new RegExp(`${caseStudyPath}$`));
const dialog = await expectDrawerOpen(page);
await expect(dialog.getByRole('heading', { name: 'Qlockify', level: 1 })).toBeFocused();
await expect(card.getByRole('link', { name: /Open the live Qlockify/ })).toHaveAttribute('target', '_blank');
await expect(card.getByRole('link', { name: /Open the live Qlockify/ })).toHaveAttribute('rel', 'noopener noreferrer');
await page.keyboard.press('Escape');
await expect(page).toHaveURL(/\/$/);
await expect(page.locator('dialog[open]')).toHaveCount(0);
await expect(cta).toBeFocused();
await expect.poll(async () => Math.abs(await page.evaluate(() => window.scrollY) - portfolioScroll))
.toBeLessThan((page.viewportSize()?.height ?? 800) / 2);
});
test('a shared route opens over the portfolio and adjacent navigation replaces history', async ({ page }) => {
await page.goto(caseStudyPath, { waitUntil: 'domcontentloaded' });
const dialog = await expectDrawerOpen(page);
await expect(page.getByRole('region', { name: 'Products I\'ve Brought to Life' })).toBeAttached();
const historyLength = await page.evaluate(() => history.length);
await dialog.getByRole('link', { name: /Next project Guilan ACE/ }).click();
await expect(page).toHaveURL(/\/projects\/guilan-ace$/);
await expect(dialog.getByRole('heading', { name: 'Guilan ACE', level: 1 })).toBeVisible();
expect(await page.evaluate(() => history.length)).toBe(historyLength);
await dialog.getByRole('button', { name: 'Close case study' }).click();
await expect(page).toHaveURL(/\/$/);
});
test('copy feedback, focus containment, and the localized RTL route work', async ({ page, context }) => {
await context.grantPermissions(['clipboard-read', 'clipboard-write']);
await page.goto('/fa/projects/qlockify', { waitUntil: 'domcontentloaded' });
const dialog = await expectDrawerOpen(page);
await expect(page.locator('html')).toHaveAttribute('dir', 'rtl');
await expect(dialog.getByRole('heading', { name: 'Qlockify', level: 1 })).toBeFocused();
await dialog.getByRole('button', { name: 'کپی پیوند' }).click();
await expect(dialog.getByText('پیوند کپی شد', { exact: true }).first()).toBeVisible();
expect(await page.evaluate(() => navigator.clipboard.readText())).toMatch(/\/fa\/projects\/qlockify$/);
await page.keyboard.press('Tab');
expect(await page.evaluate(() => document.activeElement?.closest('dialog') !== null)).toBe(true);
});
test('the drawer stays bottom-anchored with its own scrolling surface', async ({ page }) => {
await page.goto(caseStudyPath, { waitUntil: 'domcontentloaded' });
const dialog = await expectDrawerOpen(page);
const sheet = dialog.locator(':scope > div');
const scrollArea = sheet.locator(':scope > div:last-child');
const box = await sheet.boundingBox();
const viewport = page.viewportSize();
expect(box).not.toBeNull();
expect(viewport).not.toBeNull();
expect(Math.abs((box?.y ?? 0) + (box?.height ?? 0) - (viewport?.height ?? 0))).toBeLessThanOrEqual(2);
expect(await page.locator('html').evaluate((element) => getComputedStyle(element).overflow)).toBe('hidden');
expect(await scrollArea.evaluate((element) => element.scrollHeight > element.clientHeight)).toBe(true);
});