diff --git a/frontend/e2e/document-management.spec.ts b/frontend/e2e/document-management.spec.ts index 8ecad7e..33ba328 100644 --- a/frontend/e2e/document-management.spec.ts +++ b/frontend/e2e/document-management.spec.ts @@ -5,12 +5,12 @@ import { TestHelpers } from './utils/test-helpers'; test.describe('Document Management', () => { let helpers: TestHelpers; - test.beforeEach(async ({ adminPage }) => { - helpers = new TestHelpers(adminPage); + test.beforeEach(async ({ authenticatedPage }) => { + helpers = new TestHelpers(authenticatedPage); await helpers.navigateToPage('/documents'); }); - test('should display document list', async ({ adminPage: page }) => { + test('should display document list', async ({ authenticatedPage: page }) => { // The documents page should be visible with title and description // Use more flexible selectors for headings - based on artifact, it's h4 const documentsHeading = page.locator('h4:has-text("Documents")'); @@ -86,7 +86,7 @@ test.describe('Document Management', () => { console.log('Document list page test completed successfully'); }); - test.skip('should navigate to document details', async ({ dynamicAdminPage: page }) => { + test.skip('should navigate to document details', async ({ authenticatedPage: page }) => { // Click on first document if available const firstDocument = page.locator('.MuiCard-root').first(); @@ -103,7 +103,7 @@ test.describe('Document Management', () => { } }); - test.skip('should display document metadata', async ({ dynamicAdminPage: page }) => { + test.skip('should display document metadata', async ({ authenticatedPage: page }) => { const firstDocument = page.locator('.MuiCard-root').first(); if (await firstDocument.isVisible()) { @@ -117,7 +117,7 @@ test.describe('Document Management', () => { } }); - test.skip('should allow document download', async ({ dynamicAdminPage: page }) => { + test.skip('should allow document download', async ({ authenticatedPage: page }) => { const firstDocument = page.locator('[data-testid="document-item"], .document-item, .document-card').first(); if (await firstDocument.isVisible()) { @@ -139,7 +139,7 @@ test.describe('Document Management', () => { } }); - test.skip('should allow document deletion', async ({ dynamicAdminPage: page }) => { + test.skip('should allow document deletion', async ({ authenticatedPage: page }) => { const firstDocument = page.locator('[data-testid="document-item"], .document-item, .document-card').first(); if (await firstDocument.isVisible()) { @@ -163,7 +163,7 @@ test.describe('Document Management', () => { } }); - test.skip('should filter documents by type', async ({ dynamicAdminPage: page }) => { + test.skip('should filter documents by type', async ({ authenticatedPage: page }) => { // Look for filter controls const filterDropdown = page.locator('[data-testid="type-filter"], select[name="type"], .type-filter'); if (await filterDropdown.isVisible()) { @@ -180,7 +180,7 @@ test.describe('Document Management', () => { } }); - test.skip('should sort documents', async ({ dynamicAdminPage: page }) => { + test.skip('should sort documents', async ({ authenticatedPage: page }) => { const sortDropdown = page.locator('[data-testid="sort"], select[name="sort"], .sort-dropdown'); if (await sortDropdown.isVisible()) { await sortDropdown.selectOption('date-desc'); @@ -192,7 +192,7 @@ test.describe('Document Management', () => { } }); - test.skip('should display OCR status', async ({ dynamicAdminPage: page }) => { + test.skip('should display OCR status', async ({ authenticatedPage: page }) => { const firstDocument = page.locator('.MuiCard-root').first(); if (await firstDocument.isVisible()) { @@ -207,7 +207,7 @@ test.describe('Document Management', () => { } }); - test.skip('should search within document content', async ({ dynamicAdminPage: page }) => { + test.skip('should search within document content', async ({ authenticatedPage: page }) => { const firstDocument = page.locator('.MuiCard-root').first(); if (await firstDocument.isVisible()) { @@ -230,7 +230,7 @@ test.describe('Document Management', () => { } }); - test.skip('should paginate document list', async ({ dynamicAdminPage: page }) => { + test.skip('should paginate document list', async ({ authenticatedPage: page }) => { // Look for pagination controls const nextPageButton = page.locator('[data-testid="next-page"], button:has-text("Next"), .pagination-next'); if (await nextPageButton.isVisible()) { @@ -246,7 +246,7 @@ test.describe('Document Management', () => { } }); - test('should show document thumbnails'.skip, async ({ dynamicAdminPage: page }) => { + test('should show document thumbnails'.skip, async ({ authenticatedPage: page }) => { // Check for document thumbnails in list view const documentThumbnails = page.locator('[data-testid="document-thumbnail"], .thumbnail, .document-preview'); if (await documentThumbnails.first().isVisible()) { diff --git a/frontend/e2e/fixtures/auth.ts b/frontend/e2e/fixtures/auth.ts index 92209d6..718fedd 100644 --- a/frontend/e2e/fixtures/auth.ts +++ b/frontend/e2e/fixtures/auth.ts @@ -15,9 +15,9 @@ export const TEST_CREDENTIALS = { } as const; export const TIMEOUTS = { - login: 10000, - navigation: 10000, - api: 5000 + login: 15000, + navigation: 15000, + api: 8000 } as const; export interface AuthFixture { @@ -67,7 +67,7 @@ export class AuthHelper { const isWebKit = browserName.includes('WebKit') && !browserName.includes('Chrome'); if (isWebKit) { console.log('WebKit browser detected - adding extra wait time'); - await this.page.waitForTimeout(3000); + await this.page.waitForTimeout(5000); } // Clear any existing content and fill the fields @@ -79,41 +79,62 @@ export class AuthHelper { // WebKit needs extra time for form validation if (isWebKit) { - await this.page.waitForTimeout(2000); + await this.page.waitForTimeout(3000); } - // Wait for login API response before clicking submit - const loginPromise = this.page.waitForResponse(response => - response.url().includes('/auth/login') && response.status() === 200, - { timeout: TIMEOUTS.login } - ); - // Click submit button - look for the sign in button specifically const signInButton = this.page.locator('button[type="submit"]:has-text("Sign in")'); await signInButton.waitFor({ state: 'visible', timeout: TIMEOUTS.login }); - await signInButton.click(); - try { - const response = await loginPromise; + if (isWebKit) { + // WebKit-specific approach: don't wait for API response, just click and wait for navigation + await signInButton.click(); - // Wait for navigation to dashboard with more flexible URL pattern - await this.page.waitForURL(/.*\/dashboard.*/, { timeout: TIMEOUTS.navigation }); + // WebKit needs more time before checking navigation + await this.page.waitForTimeout(2000); + + // Wait for navigation with longer timeout for WebKit + await this.page.waitForURL(/.*\/dashboard.*/, { timeout: 25000 }); console.log(`Successfully navigated to: ${this.page.url()}`); - // Wait for dashboard content to load - be more flexible about the welcome message + // Wait for dashboard content to load with extra time for WebKit await this.page.waitForFunction(() => { return document.querySelector('h4') !== null && (document.querySelector('h4')?.textContent?.includes('Welcome') || document.querySelector('[role="main"]') !== null); - }, { timeout: TIMEOUTS.navigation }); + }, { timeout: 20000 }); - } catch (error) { - // Take a screenshot for debugging - await this.page.screenshot({ - path: `test-results/login-failure-${credentials.username}-${Date.now()}.png`, - fullPage: true - }); - throw error; + } else { + // Standard approach for other browsers + const loginPromise = this.page.waitForResponse(response => + response.url().includes('/auth/login') && response.status() === 200, + { timeout: TIMEOUTS.login } + ); + + await signInButton.click(); + + try { + const response = await loginPromise; + + // Wait for navigation to dashboard with more flexible URL pattern + await this.page.waitForURL(/.*\/dashboard.*/, { timeout: TIMEOUTS.navigation }); + console.log(`Successfully navigated to: ${this.page.url()}`); + + // Wait for dashboard content to load - be more flexible about the welcome message + await this.page.waitForFunction(() => { + return document.querySelector('h4') !== null && + (document.querySelector('h4')?.textContent?.includes('Welcome') || + document.querySelector('[role="main"]') !== null); + }, { timeout: TIMEOUTS.navigation }); + + } catch (error) { + // Take a screenshot for debugging + await this.page.screenshot({ + path: `test-results/login-failure-${credentials.username}-${Date.now()}.png`, + fullPage: true + }); + throw error; + } } } diff --git a/frontend/e2e/ocr-multiple-languages.spec.ts b/frontend/e2e/ocr-multiple-languages.spec.ts index 584360b..c553d81 100644 --- a/frontend/e2e/ocr-multiple-languages.spec.ts +++ b/frontend/e2e/ocr-multiple-languages.spec.ts @@ -35,12 +35,12 @@ const OCR_LANGUAGES = { test.describe('OCR Multiple Languages', () => { let helpers: TestHelpers; - test.beforeEach(async ({ adminPage }) => { - helpers = new TestHelpers(adminPage); + test.beforeEach(async ({ dynamicAdminPage }) => { + helpers = new TestHelpers(dynamicAdminPage); await helpers.navigateToPage('/settings'); }); - test('should display OCR language selector in settings', async ({ adminPage: page }) => { + test('should display OCR language selector in settings', async ({ dynamicAdminPage: page }) => { // Navigate to settings page await page.goto('/settings'); await helpers.waitForLoadingToComplete(); @@ -77,7 +77,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should select multiple OCR languages', async ({ adminPage: page }) => { + test('should select multiple OCR languages', async ({ dynamicAdminPage: page }) => { await page.goto('/settings'); await helpers.waitForLoadingToComplete(); @@ -126,7 +126,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should upload Spanish document and process with Spanish OCR', async ({ adminPage: page }) => { + test('should upload Spanish document and process with Spanish OCR', async ({ dynamicAdminPage: page }) => { // First set language to Spanish using the multi-language selector await page.goto('/settings'); await helpers.waitForLoadingToComplete(); @@ -203,7 +203,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should upload English document and process with English OCR', async ({ adminPage: page }) => { + test('should upload English document and process with English OCR', async ({ dynamicAdminPage: page }) => { // First set language to English using the multi-language selector await page.goto('/settings'); await helpers.waitForLoadingToComplete(); @@ -280,7 +280,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should validate OCR results contain expected language-specific content', async ({ adminPage: page }) => { + test('should validate OCR results contain expected language-specific content', async ({ dynamicAdminPage: page }) => { await page.goto('/documents'); await helpers.waitForLoadingToComplete(); @@ -325,7 +325,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should retry failed OCR with different language', async ({ adminPage: page }) => { + test('should retry failed OCR with different language', async ({ dynamicAdminPage: page }) => { await page.goto('/documents'); await helpers.waitForLoadingToComplete(); @@ -371,7 +371,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should handle mixed language document', async ({ adminPage: page }) => { + test('should handle mixed language document', async ({ dynamicAdminPage: page }) => { // Upload mixed language document await page.goto('/upload'); await helpers.waitForLoadingToComplete(); @@ -425,7 +425,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should persist language preference across sessions', async ({ adminPage: page }) => { + test('should persist language preference across sessions', async ({ dynamicAdminPage: page }) => { // Set language to Spanish await page.goto('/settings'); await helpers.waitForLoadingToComplete(); @@ -466,7 +466,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should display available languages from API', async ({ adminPage: page }) => { + test('should display available languages from API', async ({ dynamicAdminPage: page }) => { // Navigate to settings and check API call for languages const languagesPromise = helpers.waitForApiCall('/api/ocr/languages', TIMEOUTS.medium); @@ -500,7 +500,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should handle bulk operations with multiple languages', async ({ adminPage: page }) => { + test('should handle bulk operations with multiple languages', async ({ dynamicAdminPage: page }) => { await page.goto('/documents'); await helpers.waitForLoadingToComplete(); @@ -555,7 +555,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should handle OCR language errors gracefully', async ({ adminPage: page }) => { + test('should handle OCR language errors gracefully', async ({ dynamicAdminPage: page }) => { await page.goto('/settings'); await helpers.waitForLoadingToComplete(); @@ -584,7 +584,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should upload document with multiple languages selected', async ({ adminPage: page }) => { + test('should upload document with multiple languages selected', async ({ dynamicAdminPage: page }) => { // First set multiple languages in settings await page.goto('/settings'); await helpers.waitForLoadingToComplete(); @@ -671,7 +671,7 @@ test.describe('OCR Multiple Languages', () => { } }); - test('should retry failed OCR with multiple languages', async ({ adminPage: page }) => { + test('should retry failed OCR with multiple languages', async ({ dynamicAdminPage: page }) => { await page.goto('/documents'); await helpers.waitForLoadingToComplete(); diff --git a/frontend/e2e/sources.spec.ts b/frontend/e2e/sources.spec.ts index 7cc3770..5cacc1c 100644 --- a/frontend/e2e/sources.spec.ts +++ b/frontend/e2e/sources.spec.ts @@ -238,11 +238,9 @@ test.describe('Source Management', () => { console.log('No toast notification found'); } - // Source should be removed from list - if (sourceName) { - await expect(page.locator(`:has-text("${sourceName}")`)).not.toBeVisible({ timeout: 10000 }); - console.log(`Source '${sourceName}' successfully deleted`); - } + // Source should be removed from list - check for empty state + await expect(page.locator('h5:has-text("No Sources Configured")')).toBeVisible({ timeout: 10000 }); + console.log('Source successfully deleted - no sources remaining'); } else { console.log('No delete button found - test will pass but delete was not performed'); } diff --git a/frontend/e2e/utils/test-auth-helper.ts b/frontend/e2e/utils/test-auth-helper.ts index 5b53c24..088dc78 100644 --- a/frontend/e2e/utils/test-auth-helper.ts +++ b/frontend/e2e/utils/test-auth-helper.ts @@ -20,10 +20,10 @@ export interface E2ETestUser { } export const E2E_TIMEOUTS = { - login: 10000, - navigation: 10000, - api: 5000, - userCreation: 15000, + login: 15000, + navigation: 15000, + api: 8000, + userCreation: 20000, } as const; /** @@ -148,7 +148,7 @@ export class E2ETestAuthHelper { const isWebKit = browserName.includes('WebKit') && !browserName.includes('Chrome'); if (isWebKit) { console.log('WebKit browser detected - adding extra wait time'); - await this.page.waitForTimeout(3000); + await this.page.waitForTimeout(5000); } // Clear any existing content and fill the fields @@ -160,32 +160,53 @@ export class E2ETestAuthHelper { // WebKit needs extra time for form validation if (isWebKit) { - await this.page.waitForTimeout(2000); + await this.page.waitForTimeout(3000); } - // Wait for login API response before clicking submit - const loginPromise = this.page.waitForResponse(response => - response.url().includes('/auth/login') && response.status() === 200, - { timeout: E2E_TIMEOUTS.login } - ); - // Click submit button - look for the sign in button specifically const signInButton = this.page.locator('button[type="submit"]:has-text("Sign in")'); await signInButton.waitFor({ state: 'visible', timeout: E2E_TIMEOUTS.login }); - await signInButton.click(); - const response = await loginPromise; - - // Wait for navigation to dashboard with more flexible URL pattern - await this.page.waitForURL(/.*\/dashboard.*/, { timeout: E2E_TIMEOUTS.navigation }); - console.log(`Successfully navigated to: ${this.page.url()}`); - - // Wait for dashboard content to load - be more flexible about the welcome message - await this.page.waitForFunction(() => { - return document.querySelector('h4') !== null && - (document.querySelector('h4')?.textContent?.includes('Welcome') || - document.querySelector('[role="main"]') !== null); - }, { timeout: E2E_TIMEOUTS.navigation }); + if (isWebKit) { + // WebKit-specific approach: don't wait for API response, just click and wait for navigation + await signInButton.click(); + + // WebKit needs more time before checking navigation + await this.page.waitForTimeout(2000); + + // Wait for navigation with longer timeout for WebKit + await this.page.waitForURL(/.*\/dashboard.*/, { timeout: 25000 }); + console.log(`Successfully navigated to: ${this.page.url()}`); + + // Wait for dashboard content to load with extra time for WebKit + await this.page.waitForFunction(() => { + return document.querySelector('h4') !== null && + (document.querySelector('h4')?.textContent?.includes('Welcome') || + document.querySelector('[role="main"]') !== null); + }, { timeout: 20000 }); + + } else { + // Standard approach for other browsers + const loginPromise = this.page.waitForResponse(response => + response.url().includes('/auth/login') && response.status() === 200, + { timeout: E2E_TIMEOUTS.login } + ); + + await signInButton.click(); + + const response = await loginPromise; + + // Wait for navigation to dashboard with more flexible URL pattern + await this.page.waitForURL(/.*\/dashboard.*/, { timeout: E2E_TIMEOUTS.navigation }); + console.log(`Successfully navigated to: ${this.page.url()}`); + + // Wait for dashboard content to load - be more flexible about the welcome message + await this.page.waitForFunction(() => { + return document.querySelector('h4') !== null && + (document.querySelector('h4')?.textContent?.includes('Welcome') || + document.querySelector('[role="main"]') !== null); + }, { timeout: E2E_TIMEOUTS.navigation }); + } console.log(`Login as ${credentials.username} completed successfully`); return true; diff --git a/frontend/e2e/webdav-workflow-dynamic.spec.ts b/frontend/e2e/webdav-workflow-dynamic.spec.ts index 21eb84a..6ae5ed8 100644 --- a/frontend/e2e/webdav-workflow-dynamic.spec.ts +++ b/frontend/e2e/webdav-workflow-dynamic.spec.ts @@ -5,16 +5,16 @@ import { TestHelpers } from './utils/test-helpers'; test.describe('WebDAV Workflow (Dynamic Auth)', () => { let helpers: TestHelpers; - test.beforeEach(async ({ dynamicAdminPage }) => { - helpers = new TestHelpers(dynamicAdminPage); + test.beforeEach(async ({ authenticatedPage }) => { + helpers = new TestHelpers(authenticatedPage); await helpers.navigateToPage('/sources'); }); - test('should create and configure WebDAV source with dynamic admin', async ({ dynamicAdminPage: page, testAdmin }) => { + test('should create and configure WebDAV source with dynamic admin', async ({ authenticatedPage: page }) => { // Increase timeout for this test as WebDAV operations can be slow test.setTimeout(60000); - console.log(`Running WebDAV test with dynamic admin: ${testAdmin.credentials.username}`); + console.log('Running WebDAV test with authenticated admin'); // Navigate to sources page await page.goto('/sources'); @@ -141,7 +141,7 @@ test.describe('WebDAV Workflow (Dynamic Auth)', () => { if (nameInput) { await nameInput.clear(); - await nameInput.fill(`Test WebDAV Source - ${testAdmin.credentials.username}`); + await nameInput.fill('Test WebDAV Source - admin'); console.log('Filled name input'); } else { console.log('Warning: Could not find name input field'); @@ -339,11 +339,11 @@ test.describe('WebDAV Workflow (Dynamic Auth)', () => { console.log('Warning: Could not find source items - list may be empty or using different selectors'); } - console.log(`✅ WebDAV source creation test completed by dynamic admin: ${testAdmin.credentials.username}`); + console.log('✅ WebDAV source creation test completed by authenticated admin'); }); - test('should test WebDAV connection with dynamic admin', async ({ dynamicAdminPage: page, testAdmin }) => { - console.log(`Testing WebDAV connection with dynamic admin: ${testAdmin.credentials.username}`); + test('should test WebDAV connection with dynamic admin', async ({ authenticatedPage: page }) => { + console.log('Testing WebDAV connection with authenticated admin'); // This test assumes a WebDAV source exists from the previous test or setup await page.goto('/sources'); @@ -376,6 +376,6 @@ test.describe('WebDAV Workflow (Dynamic Auth)', () => { console.log('Connection status:', statusText); } - console.log(`✅ WebDAV connection test completed by dynamic admin: ${testAdmin.credentials.username}`); + console.log('✅ WebDAV connection test completed by authenticated admin'); }); }); \ No newline at end of file diff --git a/frontend/e2e/webdav-workflow.spec.ts b/frontend/e2e/webdav-workflow.spec.ts index 9239392..eca2c38 100644 --- a/frontend/e2e/webdav-workflow.spec.ts +++ b/frontend/e2e/webdav-workflow.spec.ts @@ -5,12 +5,12 @@ import { TestHelpers } from './utils/test-helpers'; test.describe('WebDAV Workflow', () => { let helpers: TestHelpers; - test.beforeEach(async ({ adminPage }) => { - helpers = new TestHelpers(adminPage); + test.beforeEach(async ({ authenticatedPage }) => { + helpers = new TestHelpers(authenticatedPage); await helpers.navigateToPage('/sources'); }); - test('should create and configure WebDAV source', async ({ adminPage: page }) => { + test('should create and configure WebDAV source', async ({ authenticatedPage: page }) => { // Increase timeout for this test as WebDAV operations can be slow // This addresses the timeout issues with Material-UI Select components test.setTimeout(60000); @@ -223,7 +223,7 @@ test.describe('WebDAV Workflow', () => { } }); - test('should test WebDAV connection', async ({ adminPage: page }) => { + test('should test WebDAV connection', async ({ authenticatedPage: page }) => { // This test assumes a WebDAV source exists from the previous test or setup await page.goto('/sources'); await helpers.waitForLoadingToComplete(); @@ -256,7 +256,7 @@ test.describe('WebDAV Workflow', () => { } }); - test('should initiate WebDAV sync', async ({ adminPage: page }) => { + test('should initiate WebDAV sync', async ({ authenticatedPage: page }) => { await page.goto('/sources'); await helpers.waitForLoadingToComplete(); @@ -287,7 +287,7 @@ test.describe('WebDAV Workflow', () => { } }); - test('should show WebDAV sync history', async ({ adminPage: page }) => { + test('should show WebDAV sync history', async ({ authenticatedPage: page }) => { await page.goto('/sources'); await helpers.waitForLoadingToComplete(); @@ -310,7 +310,7 @@ test.describe('WebDAV Workflow', () => { } }); - test('should handle WebDAV source deletion', async ({ adminPage: page }) => { + test('should handle WebDAV source deletion', async ({ authenticatedPage: page }) => { await page.goto('/sources'); await helpers.waitForLoadingToComplete();