diff --git a/frontend/e2e/configure-modal.spec.ts b/frontend/e2e/configure-modal.spec.ts new file mode 100644 index 0000000..4919135 --- /dev/null +++ b/frontend/e2e/configure-modal.spec.ts @@ -0,0 +1,81 @@ +import { test, expect } from '@playwright/test'; + +test.describe('Configure Modal (Issue #14)', () => { + test('Configure modal has proper backdrop overlay', async ({ page }) => { + // Navigate to the app + await page.goto('/app'); + + // Wait for page to load + await page.waitForLoadState('networkidle'); + + // Check if there are any projects listed + const projectCards = page.locator('[class*="card"]').filter({ hasText: /Configure|Settings/ }); + + // If no projects, check that we see the "No projects" message or create project button + const noProjectsMessage = page.getByText('No projects yet'); + const hasNoProjects = await noProjectsMessage.isVisible().catch(() => false); + + if (hasNoProjects) { + console.log('No projects found - skipping configure modal test'); + return; + } + + // Find and click the Settings/Configure button on first project + const settingsButton = page.locator('button').filter({ has: page.locator('svg') }).first(); + + // Look for a settings icon button + const configureButton = page.locator('[title="Setup project"], [title="Configure"]').first(); + + if (await configureButton.isVisible()) { + await configureButton.click(); + + // Wait for modal to appear + await page.waitForTimeout(500); + + // Check that the modal backdrop exists with proper styling + const backdrop = page.locator('.fixed.inset-0').filter({ has: page.locator('.card') }); + + // Verify backdrop has semi-transparent background (bg-black/50) + const backdropElement = backdrop.first(); + if (await backdropElement.isVisible()) { + const bgClass = await backdropElement.getAttribute('class'); + + // Check for semi-transparent background class + expect(bgClass).toContain('bg-black/50'); + + // Verify clicking outside closes the modal + await backdropElement.click({ position: { x: 10, y: 10 } }); + + // Modal should be closed + await expect(backdrop).not.toBeVisible({ timeout: 2000 }); + + console.log('✅ Configure modal has proper backdrop and closes on outside click'); + } + } else { + console.log('No configure button found'); + } + }); + + test('Configure modal can be closed with X button', async ({ page }) => { + await page.goto('/app'); + await page.waitForLoadState('networkidle'); + + // Find configure/settings button + const configureButton = page.locator('[title="Setup project"]').first(); + + if (await configureButton.isVisible().catch(() => false)) { + await configureButton.click(); + await page.waitForTimeout(500); + + // Find and click the close button (X) + const closeButton = page.locator('button').filter({ hasText: '✕' }); + await closeButton.click(); + + // Verify modal is closed + const modal = page.locator('.fixed.inset-0').filter({ has: page.locator('.card') }); + await expect(modal).not.toBeVisible({ timeout: 2000 }); + + console.log('✅ Configure modal closes with X button'); + } + }); +}); diff --git a/frontend/e2e/screenshot-test.spec.ts b/frontend/e2e/screenshot-test.spec.ts new file mode 100644 index 0000000..c85790a --- /dev/null +++ b/frontend/e2e/screenshot-test.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; + +test('Take screenshot of configure modal', async ({ page }) => { + // Navigate to the app + await page.goto('/app'); + await page.waitForLoadState('networkidle'); + await page.waitForTimeout(1000); + + // Take screenshot of projects page + await page.screenshot({ path: 'e2e/screenshots/projects-page.png', fullPage: true }); + + // Click on a project in the sidebar to select it + const projectItem = page.locator('text=diatrak').first(); + if (await projectItem.isVisible()) { + await projectItem.click(); + await page.waitForTimeout(1000); + + // Take screenshot after selecting project + await page.screenshot({ path: 'e2e/screenshots/project-selected.png', fullPage: true }); + + // Now look for Configure button + const configureButton = page.getByRole('button', { name: /Configure/i }); + const configVisible = await configureButton.isVisible().catch(() => false); + console.log(`Configure button visible: ${configVisible}`); + + if (configVisible) { + await configureButton.click(); + await page.waitForTimeout(500); + + // Take screenshot of the modal + await page.screenshot({ path: 'e2e/screenshots/configure-modal.png', fullPage: true }); + + // Check if backdrop has correct class + const backdrop = page.locator('.bg-black\\/50'); + const backdropVisible = await backdrop.isVisible().catch(() => false); + console.log(`Backdrop with bg-black/50 visible: ${backdropVisible}`); + + expect(backdropVisible).toBe(true); + } else { + // Try looking for Settings icon button + const settingsBtn = page.locator('[title*="Setup"], button:has(svg)').filter({ hasText: '' }); + console.log(`Settings buttons found: ${await settingsBtn.count()}`); + } + } else { + console.log('No project found to click'); + } +}); diff --git a/frontend/e2e/screenshots/configure-modal.png b/frontend/e2e/screenshots/configure-modal.png new file mode 100644 index 0000000..9d7b378 Binary files /dev/null and b/frontend/e2e/screenshots/configure-modal.png differ diff --git a/frontend/e2e/screenshots/project-selected.png b/frontend/e2e/screenshots/project-selected.png new file mode 100644 index 0000000..81cfd6d Binary files /dev/null and b/frontend/e2e/screenshots/project-selected.png differ diff --git a/frontend/e2e/screenshots/projects-page.png b/frontend/e2e/screenshots/projects-page.png new file mode 100644 index 0000000..d5952d1 Binary files /dev/null and b/frontend/e2e/screenshots/projects-page.png differ diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts new file mode 100644 index 0000000..f450d61 --- /dev/null +++ b/frontend/playwright.config.ts @@ -0,0 +1,26 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: 'html', + use: { + baseURL: 'http://localhost:5173', + trace: 'on-first-retry', + screenshot: 'only-on-failure', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + webServer: { + command: 'npm run dev', + url: 'http://localhost:5173', + reuseExistingServer: true, + }, +}); diff --git a/frontend/src/components/ProjectSetup.tsx b/frontend/src/components/ProjectSetup.tsx index 7f6c8ee..ef6e8fd 100644 --- a/frontend/src/components/ProjectSetup.tsx +++ b/frontend/src/components/ProjectSetup.tsx @@ -97,11 +97,18 @@ export default function ProjectSetup({ ]; return ( -
+ e.stopPropagation()} className="card w-full max-w-4xl max-h-[90vh] overflow-hidden flex flex-col" > {/* Header */} @@ -158,7 +165,7 @@ export default function ProjectSetup({
- + ); } diff --git a/frontend/test-results/.last-run.json b/frontend/test-results/.last-run.json new file mode 100644 index 0000000..cbcc1fb --- /dev/null +++ b/frontend/test-results/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} \ No newline at end of file