Files
frontend/frontend/tests/visual/mobile.spec.ts
2026-01-29 21:05:41 -03:00

116 lines
3.7 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { setupPreviewState } from './utils';
test.describe('Mobile Preview Visual Tests', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/tool');
await page.waitForLoadState('networkidle');
});
test('mobile preview - light mode', async ({ page }) => {
await setupPreviewState(page, { mode: 'mobile', theme: 'light' });
const ytCard = page.locator('.yt-card').first();
// Take screenshot for visual comparison
await expect(ytCard).toHaveScreenshot('mobile-light-card.png', {
threshold: 0.02,
maxDiffPixels: 100,
});
});
test('mobile preview - dark mode', async ({ page }) => {
await setupPreviewState(page, { mode: 'mobile', theme: 'dark' });
// Verify dark mode
const isDark = await page.evaluate(() =>
document.documentElement.classList.contains('dark')
);
expect(isDark).toBe(true);
const ytCard = page.locator('.yt-card').first();
await expect(ytCard).toHaveScreenshot('mobile-dark-card.png', {
threshold: 0.02,
maxDiffPixels: 100,
});
});
test('mobile preview - full-width thumbnail', async ({ page }) => {
await setupPreviewState(page, { mode: 'mobile', theme: 'light' });
const ytCard = page.locator('.yt-card').first();
const thumbnail = ytCard.locator('[style*="aspect-ratio"]').first();
const thumbnailStyles = await thumbnail.evaluate((el) => {
const computed = window.getComputedStyle(el);
return {
width: computed.width,
borderRadius: computed.borderRadius,
aspectRatio: computed.aspectRatio,
};
});
// Mobile thumbnail should be full width with 0px radius
expect(thumbnailStyles.borderRadius).toBe('0px');
expect(thumbnailStyles.aspectRatio).toContain('16');
});
test('mobile preview - avatar 36x36', async ({ page }) => {
await setupPreviewState(page, { mode: 'mobile', theme: 'light' });
const ytCard = page.locator('.yt-card').first();
const avatar = ytCard.locator('[style*="36px"]').first();
const avatarStyles = await avatar.evaluate((el) => {
const computed = window.getComputedStyle(el);
return {
width: computed.width,
height: computed.height,
borderRadius: computed.borderRadius,
};
});
expect(avatarStyles.width).toBe('36px');
expect(avatarStyles.height).toBe('36px');
expect(avatarStyles.borderRadius).toBe('50%');
});
test('mobile preview - metadata below thumbnail', async ({ page }) => {
await setupPreviewState(page, { mode: 'mobile', theme: 'light' });
const ytCard = page.locator('.yt-card').first();
// Verify layout structure: thumbnail first, then metadata
const children = await ytCard.locator('> div').all();
expect(children.length).toBeGreaterThanOrEqual(2);
// First child should be the thumbnail container (has aspect-ratio)
const firstChild = children[0];
const hasAspectRatio = await firstChild.evaluate((el) =>
el.getAttribute('style')?.includes('aspect-ratio')
);
expect(hasAspectRatio).toBe(true);
});
test('mobile preview - typography sizes', async ({ page }) => {
await setupPreviewState(page, { mode: 'mobile', theme: 'light' });
const ytCard = page.locator('.yt-card').first();
const title = ytCard.locator('h3').first();
const titleStyles = await title.evaluate((el) => {
const computed = window.getComputedStyle(el);
return {
fontSize: computed.fontSize,
fontWeight: computed.fontWeight,
lineHeight: computed.lineHeight,
};
});
expect(titleStyles.fontSize).toBe('14px');
expect(titleStyles.fontWeight).toBe('500');
expect(titleStyles.lineHeight).toBe('20px');
});
});