From a9a905a429e5f4d9bf16737513ca46c87a7618c4 Mon Sep 17 00:00:00 2001 From: Ernie Hsiung Date: Wed, 3 Sep 2025 10:44:30 -0700 Subject: [PATCH] feat: remove components-demo page and fix E2E tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DELETE: Remove entire /components-demo page (342 lines of unused demo code) - REWRITE: E2E tests now focus on actual user journeys instead of demo elements - FIX: Remove components-demo references from documentation ## E2E Test Improvements: - Test real user scenarios: writing journal entries, responsive functionality - Test button enable/disable states with actual user input - Test theme toggle functionality across screen sizes - Test for horizontal overflow and touch accessibility - Remove all demo-specific element selectors that were breaking tests ## Benefits: - Removed 342 lines of unmaintained demo code - E2E tests now test actual app functionality instead of fake demo elements - Tests focus on user value: journaling, AI reflection, responsive design - Aligns with "simplified, standard-first" architecture philosophy 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- README.md | 3 +- e2e/responsive-validation.spec.ts | 318 ++++++++------------------- e2e/responsive.spec.ts | 237 ++++++--------------- src/app/components-demo/page.tsx | 342 ------------------------------ 4 files changed, 153 insertions(+), 747 deletions(-) delete mode 100644 src/app/components-demo/page.tsx diff --git a/README.md b/README.md index 787f496..bd04675 100644 --- a/README.md +++ b/README.md @@ -157,8 +157,7 @@ src/ ├── app/ │ ├── api/ │ │ └── reflect/ # AI processing endpoint -│ ├── components-demo/ # Component showcase page -│ └── page.tsx # Main application page +│ │ └── page.tsx # Main application page ├── components/ │ ├── ui/ # UI components (buttons, inputs, etc.) │ └── __tests__/ # Component unit tests diff --git a/e2e/responsive-validation.spec.ts b/e2e/responsive-validation.spec.ts index 9e9fae5..83aa566 100644 --- a/e2e/responsive-validation.spec.ts +++ b/e2e/responsive-validation.spec.ts @@ -1,277 +1,127 @@ import { test, expect } from '@playwright/test' const breakpoints = { - mobile: { width: 375, height: 667, name: 'Mobile' }, - xs: { width: 480, height: 800, name: 'XS' }, - sm: { width: 640, height: 800, name: 'SM' }, - md: { width: 768, height: 1024, name: 'MD' }, - lg: { width: 1024, height: 768, name: 'LG' }, - xl: { width: 1280, height: 1024, name: 'XL' }, - '2xl': { width: 1536, height: 1024, name: '2XL' }, + mobile: 375, + xs: 480, + sm: 640, + md: 768, + lg: 1024, + xl: 1280, + '2xl': 1536, } -test.describe('Responsive Layout Validation', () => { - test.beforeEach(async ({ page }) => { - await page.goto('/') - }) - - for (const [key, viewport] of Object.entries(breakpoints)) { - test(`should render correctly at ${viewport.name} (${viewport.width}x${viewport.height})`, async ({ +test.describe('Journal App Responsive Validation', () => { + const testBreakpoints = [ + { name: 'Mobile', width: breakpoints.mobile, height: 667 }, + { name: 'XS', width: breakpoints.xs, height: 800 }, + { name: 'SM', width: breakpoints.sm, height: 800 }, + { name: 'MD', width: breakpoints.md, height: 1024 }, + { name: 'LG', width: breakpoints.lg, height: 768 }, + { name: 'XL', width: breakpoints.xl, height: 1024 }, + { name: '2XL', width: breakpoints['2xl'], height: 1024 }, + ] + + testBreakpoints.forEach(({ name, width, height }) => { + test(`should render correctly at ${name} (${width}x${height})`, async ({ page, }) => { - // Set viewport size - await page.setViewportSize({ - width: viewport.width, - height: viewport.height, - }) - - // Wait for layout to stabilize - await page.waitForLoadState('networkidle') - - // Check that main content is visible - await expect(page.locator('main')).toBeVisible() - await expect( - page.getByRole('heading', { name: 'Reflect App' }) - ).toBeVisible() - - // Verify no horizontal overflow - const bodyScrollWidth = await page.evaluate( - () => document.body.scrollWidth + await page.goto('/') + await page.setViewportSize({ width, height }) + + // Core app elements should be visible and functional + await expect(page.locator('h1')).toBeVisible() + await expect(page.getByTestId('journal-entry-input')).toBeVisible() + await expect(page.getByTestId('reflect-now-button')).toBeVisible() + + // Test actual user interaction + const input = page.getByTestId('journal-entry-input') + await input.fill( + 'This is a test entry to verify the app works at this screen size.' ) - const windowInnerWidth = await page.evaluate(() => window.innerWidth) - expect(bodyScrollWidth).toBeLessThanOrEqual(windowInnerWidth + 1) // Allow 1px tolerance - // Check that current breakpoint indicator is showing correctly - if (key === 'mobile') { - const mobileIndicator = page - .locator('.bg-destructive') - .filter({ hasText: /Mobile/ }) - await expect(mobileIndicator).toBeVisible() - } else if (key === 'xs') { - const xsIndicator = page - .locator('.bg-chart-1') - .filter({ hasText: /XS \(480px\+\)/ }) - await expect(xsIndicator).toBeVisible() - } else if (key === 'sm') { - const smIndicator = page - .locator('.bg-chart-2') - .filter({ hasText: /SM \(640px\+\)/ }) - await expect(smIndicator).toBeVisible() - } else if (key === 'md') { - const mdIndicator = page - .locator('.bg-chart-3') - .filter({ hasText: /MD \(768px\+\)/ }) - await expect(mdIndicator).toBeVisible() - } else if (key === 'lg') { - const lgIndicator = page - .locator('.bg-chart-4') - .filter({ hasText: /LG \(1024px\+\)/ }) - await expect(lgIndicator).toBeVisible() - } else if (key === 'xl') { - const xlIndicator = page - .locator('.bg-chart-5') - .filter({ hasText: /XL \(1280px\+\)/ }) - await expect(xlIndicator).toBeVisible() - } else if (key === '2xl') { - const x2xlIndicator = page - .locator('.bg-primary') - .filter({ hasText: /2XL \(1536px\+\)/ }) - await expect(x2xlIndicator).toBeVisible() - } + await expect(page.getByTestId('reflect-now-button')).toBeEnabled() - // Verify grid layout adapts correctly - const breakpointGrid = page.locator('[data-testid="breakpoint-grid"]') - await expect(breakpointGrid).toBeVisible() + // Clear input should work + await input.clear() + await expect(page.getByTestId('reflect-now-button')).toBeDisabled() - // Take screenshot for visual validation - await page.screenshot({ - path: `e2e/screenshots/responsive-${key}-${viewport.width}x${viewport.height}.png`, - fullPage: true, + // Theme toggle should be accessible + const themeToggle = page.getByTestId('theme-toggle-advanced') + await expect(themeToggle).toBeVisible() + + // No horizontal overflow + const hasHorizontalOverflow = await page.evaluate(() => { + return document.body.scrollWidth > document.body.clientWidth }) + expect(hasHorizontalOverflow).toBe(false) }) - } - - test('should handle smooth transitions between breakpoints', async ({ - page, - }) => { - // Start at mobile size - await page.setViewportSize({ width: 375, height: 667 }) - await page.waitForLoadState('networkidle') - - // Gradually increase width to test transitions - const testWidths = [480, 640, 768, 1024, 1280, 1536] - - for (const width of testWidths) { - await page.setViewportSize({ width, height: 800 }) - - // Wait for layout to stabilize after viewport change - await page.waitForLoadState('networkidle') - - // Wait for the appropriate breakpoint indicator to be visible - // This ensures the CSS transitions have completed - if (width >= 1536) { - await expect( - page.locator('.bg-primary').filter({ hasText: /2XL \(1536px\+\)/ }) - ).toBeVisible() - } else if (width >= 1280) { - await expect( - page.locator('.bg-chart-5').filter({ hasText: /XL \(1280px\+\)/ }) - ).toBeVisible() - } else if (width >= 1024) { - await expect( - page.locator('.bg-chart-4').filter({ hasText: /LG \(1024px\+\)/ }) - ).toBeVisible() - } else if (width >= 768) { - await expect( - page.locator('.bg-chart-3').filter({ hasText: /MD \(768px\+\)/ }) - ).toBeVisible() - } else if (width >= 640) { - await expect( - page.locator('.bg-chart-2').filter({ hasText: /SM \(640px\+\)/ }) - ).toBeVisible() - } else if (width >= 480) { - await expect( - page.locator('.bg-chart-1').filter({ hasText: /XS \(480px\+\)/ }) - ).toBeVisible() - } - - // Verify no layout breaks - const bodyScrollWidth = await page.evaluate( - () => document.body.scrollWidth - ) - const windowInnerWidth = await page.evaluate(() => window.innerWidth) - expect(bodyScrollWidth).toBeLessThanOrEqual(windowInnerWidth + 1) - - // Verify content is still visible - await expect( - page.getByRole('heading', { name: 'Reflect App' }) - ).toBeVisible() - } }) test('should maintain proper spacing and alignment at all breakpoints', async ({ page, }) => { - for (const [, viewport] of Object.entries(breakpoints)) { - await page.setViewportSize({ - width: viewport.width, - height: viewport.height, - }) - await page.waitForLoadState('networkidle') + await page.goto('/') - // Check header layout - const header = page.locator('header') - await expect(header).toBeVisible() + for (const { width, height } of testBreakpoints) { + await page.setViewportSize({ width, height }) - // Check that cards maintain proper spacing - const cards = page.locator('[data-testid="card"], .group') - const cardCount = await cards.count() + // Main container should be centered + const main = page.locator('main').first() + await expect(main).toBeVisible() - if (cardCount > 0) { - for (let i = 0; i < cardCount; i++) { - await expect(cards.nth(i)).toBeVisible() - } - } + // Elements should have proper spacing + const input = page.getByTestId('journal-entry-input') + const button = page.getByTestId('reflect-now-button') + + await expect(input).toBeVisible() + await expect(button).toBeVisible() - // Verify form elements are properly sized - const buttons = page.locator('button') - const buttonCount = await buttons.count() + // Button should be below input with proper spacing + const inputBox = await input.boundingBox() + const buttonBox = await button.boundingBox() - for (let i = 0; i < buttonCount; i++) { - const button = buttons.nth(i) - if (await button.isVisible()) { - const boundingBox = await button.boundingBox() - if (boundingBox) { - // Buttons should have reasonable touch target size on mobile (< 480px) - // Note: Some buttons might have borders/padding that affect rendered size - if (viewport.width < 480) { - expect(boundingBox.height).toBeGreaterThanOrEqual(36) - } else { - // At xs+ breakpoints, can be smaller - expect(boundingBox.height).toBeGreaterThanOrEqual(28) - } - } - } + if (inputBox && buttonBox) { + // Button should be below input (allowing for some margin) + expect(buttonBox.y).toBeGreaterThan(inputBox.y + inputBox.height - 10) } } }) test('should handle container behavior correctly', async ({ page }) => { - for (const [, viewport] of Object.entries(breakpoints)) { - await page.setViewportSize({ - width: viewport.width, - height: viewport.height, - }) - await page.waitForLoadState('networkidle') - - // Check container max-width behavior - const container = page.locator('.container').first() - const containerBoundingBox = await container.boundingBox() - - if (containerBoundingBox) { - // Container should never exceed viewport width - expect(containerBoundingBox.width).toBeLessThanOrEqual(viewport.width) + await page.goto('/') - // Container should be properly centered - const containerLeft = containerBoundingBox.x - const containerRight = containerLeft + containerBoundingBox.width - const viewportCenter = viewport.width / 2 - const containerCenter = (containerLeft + containerRight) / 2 + for (const { width, height } of testBreakpoints.slice(0, 4)) { + // Test smaller breakpoints + await page.setViewportSize({ width, height }) - // Allow some tolerance for centering - expect(Math.abs(containerCenter - viewportCenter)).toBeLessThanOrEqual( - 20 - ) - } + // Container should not exceed viewport width + const bodyWidth = await page.evaluate(() => document.body.scrollWidth) + expect(bodyWidth).toBeLessThanOrEqual(width + 1) // +1 for rounding } }) test('should handle theme toggle interactions across breakpoints', async ({ page, }) => { - for (const [, viewport] of Object.entries(breakpoints)) { - await page.setViewportSize({ - width: viewport.width, - height: viewport.height, - }) - await page.waitForLoadState('networkidle') - - // Find theme toggle buttons - const themeToggle = page.locator('[data-testid="theme-toggle"]').first() - const themeToggleAdvanced = page - .locator('[data-testid="theme-toggle-advanced"]') - .first() - - // Test basic theme toggle - if (await themeToggle.isVisible()) { - await themeToggle.click() - - // Wait for theme change by checking that toggle button is still responsive - // and that the page has finished any theme transitions - await page.waitForLoadState('networkidle') - - // Simple verification that the theme system is working - await expect(themeToggle).toBeVisible() - - // Verify the toggle button has theme-aware icons (Sun/Moon) visible - const sunIcon = themeToggle.locator('svg').first() - await expect(sunIcon).toBeVisible() - } + await page.goto('/') - // Test advanced theme toggle - if (await themeToggleAdvanced.isVisible()) { - await themeToggleAdvanced.click() + for (const { width, height } of [ + testBreakpoints[0], // Mobile + testBreakpoints[3], // MD + testBreakpoints[5], // XL + ]) { + await page.setViewportSize({ width, height }) - // Wait for any network activity to settle after theme change - await page.waitForLoadState('networkidle') + const themeToggle = page.getByTestId('theme-toggle-advanced') + await expect(themeToggle).toBeVisible() - // Verify button is still visible and functional - await expect(themeToggleAdvanced).toBeVisible() + // Should be clickable at all screen sizes + await themeToggle.click() + await expect(themeToggle).toBeVisible() - // Verify button contains valid theme text (Light, Dark, or System) - const buttonText = await themeToggleAdvanced.textContent() - expect(buttonText).toMatch(/\b(Light|Dark|System)\b/) - } + // App should remain functional after theme change + await expect(page.getByTestId('journal-entry-input')).toBeVisible() + await expect(page.getByTestId('reflect-now-button')).toBeVisible() } }) }) diff --git a/e2e/responsive.spec.ts b/e2e/responsive.spec.ts index 7d8f39e..d48f44b 100644 --- a/e2e/responsive.spec.ts +++ b/e2e/responsive.spec.ts @@ -10,207 +10,106 @@ const breakpoints = { '2xl': 1536, // --breakpoint-2xl: 96rem (1536px) } as const -test.describe('Responsive Design System', () => { +test.describe('Responsive Journal App', () => { test.beforeEach(async ({ page }) => { await page.goto('/') }) - test('displays correct breakpoint indicators at different screen sizes', async ({ - page, - }) => { - // Test mobile (below xs) - await page.setViewportSize({ width: breakpoints.mobile, height: 800 }) - await expect(page.locator('text=Mobile (< 480px)')).toBeVisible() - await expect(page.locator('text=XS (480px+)')).not.toBeVisible() - - // Test XS breakpoint - await page.setViewportSize({ width: breakpoints.xs, height: 800 }) - await expect(page.locator('text=Mobile (< 480px)')).not.toBeVisible() - await expect(page.locator('text=XS (480px+)')).toBeVisible() - await expect(page.locator('text=SM (640px+)')).not.toBeVisible() - - // Test SM breakpoint - await page.setViewportSize({ width: breakpoints.sm, height: 800 }) - await expect(page.locator('text=XS (480px+)')).not.toBeVisible() - await expect(page.locator('text=SM (640px+)')).toBeVisible() - await expect(page.locator('text=MD (768px+)')).not.toBeVisible() - - // Test MD breakpoint - await page.setViewportSize({ width: breakpoints.md, height: 800 }) - await expect(page.locator('text=SM (640px+)')).not.toBeVisible() - await expect(page.locator('text=MD (768px+)')).toBeVisible() - await expect(page.locator('text=LG (1024px+)')).not.toBeVisible() - - // Test LG breakpoint - await page.setViewportSize({ width: breakpoints.lg, height: 800 }) - await expect(page.locator('text=MD (768px+)')).not.toBeVisible() - await expect(page.locator('text=LG (1024px+)')).toBeVisible() - await expect(page.locator('text=XL (1280px+)')).not.toBeVisible() - - // Test XL breakpoint - await page.setViewportSize({ width: breakpoints.xl, height: 800 }) - await expect(page.locator('text=LG (1024px+)')).not.toBeVisible() - await expect(page.locator('text=XL (1280px+)')).toBeVisible() - await expect(page.locator('text=2XL (1536px+)')).not.toBeVisible() - - // Test 2XL breakpoint - await page.setViewportSize({ width: breakpoints['2xl'], height: 800 }) - await expect(page.locator('text=XL (1280px+)')).not.toBeVisible() - await expect(page.locator('text=2XL (1536px+)')).toBeVisible() - }) + test('journal app works at all screen sizes', async ({ page }) => { + const screenSizes = [ + breakpoints.mobile, + breakpoints.xs, + breakpoints.sm, + breakpoints.md, + breakpoints.lg, + breakpoints.xl, + breakpoints['2xl'], + ] + + for (const width of screenSizes) { + await page.setViewportSize({ width, height: 800 }) - test('header layout adapts responsively', async ({ page }) => { - // Mobile: should be stacked vertically - await page.setViewportSize({ width: breakpoints.mobile, height: 800 }) - const headerMobile = page.locator('header') - await expect(headerMobile).toHaveClass(/flex-col/) + // Core functionality should always work + await expect(page.locator('h1')).toBeVisible() + await expect(page.getByTestId('journal-entry-input')).toBeVisible() + await expect(page.getByTestId('reflect-now-button')).toBeVisible() - // XS and above: should be horizontal - await page.setViewportSize({ width: breakpoints.xs, height: 800 }) - const headerDesktop = page.locator('header') - await expect(headerDesktop).toHaveClass(/xs:flex-row/) + // Button should be disabled initially (no content) + await expect(page.getByTestId('reflect-now-button')).toBeDisabled() + } }) - test('grid layout adapts at different breakpoints', async ({ page }) => { - const breakpointGrid = page - .locator('[data-testid="breakpoint-grid"]') - .first() - - // Mobile: 1 column + test('user can write and reflect at mobile size', async ({ page }) => { await page.setViewportSize({ width: breakpoints.mobile, height: 800 }) - await expect(breakpointGrid).toHaveClass(/grid-cols-1/) - - // XS: 2 columns - await page.setViewportSize({ width: breakpoints.xs, height: 800 }) - await expect(breakpointGrid).toHaveClass(/xs:grid-cols-2/) - - // SM: 3 columns - await page.setViewportSize({ width: breakpoints.sm, height: 800 }) - await expect(breakpointGrid).toHaveClass(/sm:grid-cols-3/) - - // MD: 4 columns - await page.setViewportSize({ width: breakpoints.md, height: 800 }) - await expect(breakpointGrid).toHaveClass(/md:grid-cols-4/) - - // LG: 5 columns - await page.setViewportSize({ width: breakpoints.lg, height: 800 }) - await expect(breakpointGrid).toHaveClass(/lg:grid-cols-5/) - - // XL: 6 columns - await page.setViewportSize({ width: breakpoints.xl, height: 800 }) - await expect(breakpointGrid).toHaveClass(/xl:grid-cols-6/) - }) - test('main grid switches from 1 to 2 columns at lg breakpoint', async ({ - page, - }) => { - const mainGrid = page.locator('.grid').first() + // Type a journal entry + const journalInput = page.getByTestId('journal-entry-input') + await journalInput.fill( + 'Today was a challenging but rewarding day. I learned new things.' + ) - // Below LG: single column - await page.setViewportSize({ width: breakpoints.md, height: 800 }) + // Button should become enabled + await expect(page.getByTestId('reflect-now-button')).toBeEnabled() - // LG and above: 2 columns - await page.setViewportSize({ width: breakpoints.lg, height: 800 }) - await expect(mainGrid).toHaveClass(/lg:grid-cols-2/) + // User can click reflect (we won't test the AI call in this test) + const reflectButton = page.getByTestId('reflect-now-button') + await expect(reflectButton).toBeVisible() + await expect(reflectButton).toContainText('Reflect Now') }) - test('color palette grid adapts responsively', async ({ page }) => { - // SM: 2 columns - await page.setViewportSize({ width: breakpoints.sm, height: 800 }) - const colorGrid = page - .locator('text=Background Colors') - .locator('..') - .locator('..') - await expect(colorGrid).toHaveClass(/sm:grid-cols-2/) - - // LG: 3 columns - await page.setViewportSize({ width: breakpoints.lg, height: 800 }) - await expect(colorGrid).toHaveClass(/lg:grid-cols-3/) - }) - - test('container utility centers content properly', async ({ page }) => { - // Test container behavior at different breakpoints - const container = page.locator('.container').first() + test('theme toggle works responsively', async ({ page }) => { + const screenSizes = [breakpoints.mobile, breakpoints.md, breakpoints.lg] - for (const [name, width] of Object.entries(breakpoints)) { + for (const width of screenSizes) { await page.setViewportSize({ width, height: 800 }) - // Container should be centered - const containerBox = await container.boundingBox() - const pageWidth = await page.evaluate(() => window.innerWidth) + // Theme toggle should be accessible + const themeToggle = page.getByTestId('theme-toggle-advanced') + await expect(themeToggle).toBeVisible() - if (containerBox) { - // Check that container is roughly centered (allowing for padding) - const leftMargin = containerBox.x - const rightMargin = pageWidth - (containerBox.x + containerBox.width) - const marginDiff = Math.abs(leftMargin - rightMargin) + // Should be able to click it + await themeToggle.click() - // Margins should be roughly equal (within 20px tolerance for padding) - expect(marginDiff).toBeLessThan(20) - } + // Should show some indication of theme change + await expect(themeToggle).toBeVisible() } }) - test('spacing adapts at different breakpoints', async ({ page }) => { - // Mobile spacing should be smaller - await page.setViewportSize({ width: breakpoints.mobile, height: 800 }) - const main = page.locator('main') - await expect(main).toHaveClass(/p-4/) - - // XS spacing - await page.setViewportSize({ width: breakpoints.xs, height: 800 }) - await expect(main).toHaveClass(/xs:p-6/) - - // SM and above spacing - await page.setViewportSize({ width: breakpoints.sm, height: 800 }) - await expect(main).toHaveClass(/sm:p-8/) - }) - - test('typography scales responsively', async ({ page }) => { - const heading = page.locator('h1') - - // Mobile: smaller text - await page.setViewportSize({ width: breakpoints.mobile, height: 800 }) - await expect(heading).toHaveClass(/text-2xl/) - - // XS and above: larger text - await page.setViewportSize({ width: breakpoints.xs, height: 800 }) - await expect(heading).toHaveClass(/xs:text-3xl/) - }) + test('no horizontal overflow at any screen size', async ({ page }) => { + const screenSizes = [ + breakpoints.mobile, + breakpoints.xs, + breakpoints.sm, + breakpoints.md, + ] - test('no horizontal overflow at any breakpoint', async ({ page }) => { - // Test each breakpoint to ensure no horizontal scrolling - for (const [name, width] of Object.entries(breakpoints)) { + for (const width of screenSizes) { await page.setViewportSize({ width, height: 800 }) - // Check that page width doesn't exceed viewport - const scrollWidth = await page.evaluate( - () => document.documentElement.scrollWidth - ) - const clientWidth = await page.evaluate( - () => document.documentElement.clientWidth - ) + // Check for horizontal scrollbar + const scrollWidth = await page.evaluate(() => document.body.scrollWidth) + const clientWidth = await page.evaluate(() => document.body.clientWidth) - expect(scrollWidth).toBeLessThanOrEqual(clientWidth + 1) // Allow 1px tolerance + expect(scrollWidth).toBeLessThanOrEqual(clientWidth + 1) // +1 for rounding } }) - test('all interactive elements remain accessible on mobile', async ({ - page, - }) => { + test('interactive elements remain accessible on mobile', async ({ page }) => { await page.setViewportSize({ width: breakpoints.mobile, height: 800 }) - // Test theme toggles are clickable - await expect(page.getByTestId('theme-toggle')).toBeVisible() - await expect(page.getByTestId('theme-toggle-advanced')).toBeVisible() + // All key interactive elements should be large enough for touch + const interactiveElements = [ + page.getByTestId('journal-entry-input'), + page.getByTestId('reflect-now-button'), + page.getByTestId('theme-toggle-advanced'), + ] - // Test form elements are accessible - await expect(page.locator('input[type="email"]')).toBeVisible() - await expect(page.locator('textarea')).toBeVisible() - await expect(page.locator('button').first()).toBeVisible() + for (const element of interactiveElements) { + await expect(element).toBeVisible() - // Test feedback component is accessible - await expect(page.getByTestId('feedback-positive')).toBeVisible() - await expect(page.getByTestId('feedback-negative')).toBeVisible() + // Should be large enough for touch interaction (minimum 44px) + const box = await element.boundingBox() + expect(box?.height).toBeGreaterThanOrEqual(40) // Slightly less due to padding/margins + } }) }) diff --git a/src/app/components-demo/page.tsx b/src/app/components-demo/page.tsx deleted file mode 100644 index 2cdb068..0000000 --- a/src/app/components-demo/page.tsx +++ /dev/null @@ -1,342 +0,0 @@ -'use client' - -import { Button } from '@/components/ui/button' -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from '@/components/ui/card' -import { ErrorMessage } from '@/components/ui/error-message' -import { Feedback } from '@/components/ui/feedback' -import { Input } from '@/components/ui/input' -import { JournalEntryInput } from '@/components/ui/journal-entry-input' -import { Label } from '@/components/ui/label' -import { LoadingSpinner } from '@/components/ui/loading-spinner' -import { ReflectionDisplay } from '@/components/ui/reflection-display' -import { Textarea } from '@/components/ui/textarea' -import { ThemeToggle, ThemeToggleAdvanced } from '@/components/ui/theme-toggle' -import { usePageTracking } from '@/hooks/use-analytics' - -export default function ComponentsDemo() { - usePageTracking() - return ( -
-
-
-
-

- Reflect App - Components Demo -

-

- Responsive design & dark mode demo -

-
-
- - -
-
- -
- - - Form Components - - Testing form elements in both light and dark themes - - - -
- - -
-
- -