[Bug] "Configure" window superimposed on underlying UI elements #14

This commit is contained in:
Bob Roberts 2025-12-02 16:10:07 -06:00
parent 559205e7c0
commit 295a95d4ae
8 changed files with 167 additions and 2 deletions

View file

@ -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');
}
});
});

View file

@ -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');
}
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

View file

@ -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,
},
});

View file

@ -97,11 +97,18 @@ export default function ProjectSetup({
];
return (
<div className="fixed inset-0 flex items-center justify-center z-50 p-4 bg-dark-navy">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 flex items-center justify-center z-50 p-4 bg-black/50 backdrop-blur-sm"
onClick={onClose}
>
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
onClick={(e) => 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({
</AnimatePresence>
</div>
</motion.div>
</div>
</motion.div>
);
}

View file

@ -0,0 +1,4 @@
{
"status": "passed",
"failedTests": []
}