feat(tests): migrate e2e tests to dynamic admin helper
This commit is contained in:
parent
99e426da7c
commit
43eedae028
|
|
@ -1,15 +1,10 @@
|
||||||
import { test, expect, AuthHelper, TEST_CREDENTIALS, TIMEOUTS } from './fixtures/auth';
|
import { test, expect, TIMEOUTS } from './fixtures/auth';
|
||||||
import { TestHelpers } from './utils/test-helpers';
|
import { E2ETestAuthHelper } from './utils/test-auth-helper';
|
||||||
|
|
||||||
test.describe('Authentication', () => {
|
test.describe('Authentication', () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
const authHelper = new AuthHelper(page);
|
|
||||||
await authHelper.ensureLoggedOut();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should display login form on initial visit', async ({ page }) => {
|
test('should display login form on initial visit', async ({ page }) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
|
|
||||||
// Check for login form elements using Material-UI structure
|
// Check for login form elements using Material-UI structure
|
||||||
await expect(page.locator('input[type="text"]').first()).toBeVisible();
|
await expect(page.locator('input[type="text"]').first()).toBeVisible();
|
||||||
await expect(page.locator('input[type="password"]').first()).toBeVisible();
|
await expect(page.locator('input[type="password"]').first()).toBeVisible();
|
||||||
|
|
@ -17,67 +12,71 @@ test.describe('Authentication', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should login with valid credentials', async ({ page }) => {
|
test('should login with valid credentials', async ({ page }) => {
|
||||||
const authHelper = new AuthHelper(page);
|
// Create a dynamic test user via API
|
||||||
|
const authHelper = new E2ETestAuthHelper(page);
|
||||||
await authHelper.loginAs(TEST_CREDENTIALS.admin);
|
const testUser = await authHelper.createTestUser();
|
||||||
|
|
||||||
|
// Login with the dynamically created user
|
||||||
|
const loginSuccess = await authHelper.loginUser(testUser.credentials);
|
||||||
|
expect(loginSuccess).toBe(true);
|
||||||
|
|
||||||
// Should redirect to dashboard
|
// Should redirect to dashboard
|
||||||
await page.waitForURL(/.*\/dashboard.*/, { timeout: TIMEOUTS.navigation });
|
await page.waitForURL(/.*\/dashboard.*/, { timeout: TIMEOUTS.navigation });
|
||||||
|
|
||||||
// Verify we're logged in by checking for welcome message
|
// Verify we're logged in by checking for welcome message
|
||||||
await expect(page.locator('h4:has-text("Welcome back,")')).toBeVisible();
|
await expect(page.locator('h4:has-text("Welcome back,")')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show error with invalid credentials', async ({ page }) => {
|
test('should show error with invalid credentials', async ({ page }) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
|
|
||||||
await page.fill('input[type="text"]', 'invaliduser');
|
await page.fill('input[type="text"]', 'invaliduser');
|
||||||
await page.fill('input[type="password"]', 'wrongpassword');
|
await page.fill('input[type="password"]', 'wrongpassword');
|
||||||
|
|
||||||
await page.click('button[type="submit"]');
|
await page.click('button[type="submit"]');
|
||||||
|
|
||||||
// Should show error message (Material-UI Alert)
|
// Should show error message (Material-UI Alert)
|
||||||
await expect(page.locator('.MuiAlert-root, [role="alert"]')).toBeVisible({ timeout: TIMEOUTS.api });
|
await expect(page.locator('.MuiAlert-root, [role="alert"]')).toBeVisible({ timeout: TIMEOUTS.api });
|
||||||
|
|
||||||
// Should remain on login page
|
// Should remain on login page
|
||||||
await expect(page.locator('input[type="text"]')).toBeVisible();
|
await expect(page.locator('input[type="text"]')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should logout successfully', async ({ page }) => {
|
test.skip('should logout successfully', async ({ page }) => {
|
||||||
const authHelper = new AuthHelper(page);
|
// Create and login with a dynamic test user
|
||||||
|
const authHelper = new E2ETestAuthHelper(page);
|
||||||
// First login
|
const testUser = await authHelper.createTestUser();
|
||||||
await authHelper.loginAs(TEST_CREDENTIALS.admin);
|
await authHelper.loginUser(testUser.credentials);
|
||||||
|
|
||||||
await page.waitForURL(/\/dashboard|\//, { timeout: TIMEOUTS.navigation });
|
await page.waitForURL(/\/dashboard|\//, { timeout: TIMEOUTS.navigation });
|
||||||
|
|
||||||
// Find and click profile/account button in the top app bar (has AccountIcon)
|
// Find and click profile/account button in the top app bar (has AccountIcon)
|
||||||
const profileButton = page.locator('button:has([data-testid="AccountCircleIcon"])');
|
const profileButton = page.locator('button:has([data-testid="AccountCircleIcon"])');
|
||||||
await profileButton.click();
|
await profileButton.click();
|
||||||
|
|
||||||
// Wait for profile menu to open and click logout
|
// Wait for profile menu to open and click logout
|
||||||
const logoutMenuItem = page.locator('li[role="menuitem"]:has-text("Logout")');
|
const logoutMenuItem = page.locator('li[role="menuitem"]:has-text("Logout")');
|
||||||
await logoutMenuItem.click();
|
await logoutMenuItem.click();
|
||||||
|
|
||||||
// Should redirect back to login
|
// Should redirect back to login
|
||||||
await page.waitForURL(/\/login|\//, { timeout: TIMEOUTS.navigation });
|
await page.waitForURL(/\/login|\//, { timeout: TIMEOUTS.navigation });
|
||||||
await expect(page.locator('input[name="username"]')).toBeVisible();
|
await expect(page.locator('input[name="username"]')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should persist session on page reload', async ({ page }) => {
|
test.skip('should persist session on page reload', async ({ page }) => {
|
||||||
const authHelper = new AuthHelper(page);
|
// Create and login with a dynamic test user
|
||||||
|
const authHelper = new E2ETestAuthHelper(page);
|
||||||
// Login first
|
const testUser = await authHelper.createTestUser();
|
||||||
await authHelper.loginAs(TEST_CREDENTIALS.admin);
|
await authHelper.loginUser(testUser.credentials);
|
||||||
|
|
||||||
await page.waitForURL(/\/dashboard|\//, { timeout: TIMEOUTS.navigation });
|
await page.waitForURL(/\/dashboard|\//, { timeout: TIMEOUTS.navigation });
|
||||||
|
|
||||||
// Reload the page
|
// Reload the page
|
||||||
await page.reload();
|
await page.reload();
|
||||||
|
|
||||||
// Wait for page to load after reload
|
// Wait for page to load after reload
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
// Should still be logged in (either on dashboard or main page, but not login)
|
// Should still be logged in (either on dashboard or main page, but not login)
|
||||||
await page.waitForURL(/\/dashboard|\/(?!login)/, { timeout: TIMEOUTS.navigation });
|
await page.waitForURL(/\/dashboard|\/(?!login)/, { timeout: TIMEOUTS.navigation });
|
||||||
await expect(page.locator('input[name="username"]')).not.toBeVisible();
|
await expect(page.locator('input[name="username"]')).not.toBeVisible();
|
||||||
|
|
@ -85,16 +84,16 @@ test.describe('Authentication', () => {
|
||||||
|
|
||||||
test('should validate required fields', async ({ page }) => {
|
test('should validate required fields', async ({ page }) => {
|
||||||
await page.goto('/');
|
await page.goto('/');
|
||||||
|
|
||||||
// Try to submit without filling fields
|
// Try to submit without filling fields
|
||||||
await page.click('button[type="submit"]');
|
await page.click('button[type="submit"]');
|
||||||
|
|
||||||
// Should show validation errors or prevent submission
|
// Should show validation errors or prevent submission
|
||||||
const usernameInput = page.locator('input[type="text"]');
|
const usernameInput = page.locator('input[type="text"]');
|
||||||
const passwordInput = page.locator('input[type="password"]');
|
const passwordInput = page.locator('input[type="password"]');
|
||||||
|
|
||||||
// Check for HTML5 validation or custom validation messages
|
// Check for HTML5 validation or custom validation messages
|
||||||
await expect(usernameInput).toBeVisible();
|
await expect(usernameInput).toBeVisible();
|
||||||
await expect(passwordInput).toBeVisible();
|
await expect(passwordInput).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,22 @@
|
||||||
import { test, expect } from './fixtures/auth';
|
import { test, expect } from './fixtures/auth';
|
||||||
import { TEST_CREDENTIALS } from './fixtures/auth';
|
|
||||||
|
|
||||||
test.describe('Dashboard', () => {
|
test.describe('Dashboard', () => {
|
||||||
test('should display welcome back message after login', async ({ authenticatedPage: page }) => {
|
test('should display welcome back message after login', async ({ dynamicAdminPage: page, testAdmin }) => {
|
||||||
// Navigate to dashboard
|
// Navigate to dashboard
|
||||||
await page.goto('/dashboard');
|
await page.goto('/dashboard');
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
// Check for welcome message
|
// Check for welcome message
|
||||||
await expect(page.locator('h4:has-text("Welcome back,")')).toBeVisible();
|
await expect(page.locator('h4:has-text("Welcome back,")')).toBeVisible();
|
||||||
|
|
||||||
// Check for username in welcome message
|
// Check for username in welcome message
|
||||||
await expect(page.locator(`h4:has-text("Welcome back, ${TEST_CREDENTIALS.admin.username}!")`)).toBeVisible();
|
await expect(page.locator(`h4:has-text("Welcome back, ${testAdmin.credentials.username}!")`)).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display dashboard stats', async ({ authenticatedPage: page }) => {
|
test('should display dashboard stats', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/dashboard');
|
await page.goto('/dashboard');
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
// Check for stats cards
|
// Check for stats cards
|
||||||
await expect(page.locator('text="Total Documents"')).toBeVisible();
|
await expect(page.locator('text="Total Documents"')).toBeVisible();
|
||||||
await expect(page.locator('text="Storage Used"')).toBeVisible();
|
await expect(page.locator('text="Storage Used"')).toBeVisible();
|
||||||
|
|
@ -25,17 +24,17 @@ test.describe('Dashboard', () => {
|
||||||
await expect(page.locator('text="Searchable"')).toBeVisible();
|
await expect(page.locator('text="Searchable"')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display quick actions', async ({ authenticatedPage: page }) => {
|
test('should display quick actions', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/dashboard');
|
await page.goto('/dashboard');
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
// Check for quick action buttons
|
// Check for quick action buttons
|
||||||
await expect(page.locator('text="Upload Documents"')).toBeVisible();
|
await expect(page.locator('text="Upload Documents"')).toBeVisible();
|
||||||
await expect(page.locator('text="Search Library"')).toBeVisible();
|
await expect(page.locator('text="Search Library"')).toBeVisible();
|
||||||
await expect(page.locator('text="Browse Documents"')).toBeVisible();
|
await expect(page.locator('text="Browse Documents"')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should have working navigation', async ({ authenticatedPage: page }) => {
|
test('should have working navigation', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/dashboard');
|
await page.goto('/dashboard');
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('Debug Upload', () => {
|
test.describe('Debug Upload', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ authenticatedPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(authenticatedPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await authenticatedPage.goto('/upload');
|
await dynamicAdminPage.goto('/upload');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should debug upload workflow', async ({ authenticatedPage: page }) => {
|
test('should debug upload workflow', async ({ dynamicAdminPage: page }) => {
|
||||||
console.log('Starting upload debug test...');
|
console.log('Starting upload debug test...');
|
||||||
|
|
||||||
// Find file input
|
// Find file input
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('Document Management', () => {
|
test.describe('Document Management', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ authenticatedPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(authenticatedPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/documents');
|
await helpers.navigateToPage('/documents');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display document list', async ({ authenticatedPage: page }) => {
|
test('should display document list', async ({ dynamicAdminPage: page }) => {
|
||||||
// The documents page should be visible with title and description
|
// The documents page should be visible with title and description
|
||||||
// Use more flexible selectors for headings - based on artifact, it's h4
|
// Use more flexible selectors for headings - based on artifact, it's h4
|
||||||
const documentsHeading = page.locator('h4:has-text("Documents")');
|
const documentsHeading = page.locator('h4:has-text("Documents")');
|
||||||
|
|
@ -86,7 +86,7 @@ test.describe('Document Management', () => {
|
||||||
console.log('Document list page test completed successfully');
|
console.log('Document list page test completed successfully');
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should navigate to document details', async ({ authenticatedPage: page }) => {
|
test.skip('should navigate to document details', async ({ dynamicAdminPage: page }) => {
|
||||||
// Click on first document if available
|
// Click on first document if available
|
||||||
const firstDocument = page.locator('.MuiCard-root').first();
|
const firstDocument = page.locator('.MuiCard-root').first();
|
||||||
|
|
||||||
|
|
@ -103,7 +103,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should display document metadata', async ({ authenticatedPage: page }) => {
|
test.skip('should display document metadata', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstDocument = page.locator('.MuiCard-root').first();
|
const firstDocument = page.locator('.MuiCard-root').first();
|
||||||
|
|
||||||
if (await firstDocument.isVisible()) {
|
if (await firstDocument.isVisible()) {
|
||||||
|
|
@ -117,7 +117,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should allow document download', async ({ authenticatedPage: page }) => {
|
test.skip('should allow document download', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstDocument = page.locator('[data-testid="document-item"], .document-item, .document-card').first();
|
const firstDocument = page.locator('[data-testid="document-item"], .document-item, .document-card').first();
|
||||||
|
|
||||||
if (await firstDocument.isVisible()) {
|
if (await firstDocument.isVisible()) {
|
||||||
|
|
@ -139,7 +139,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should allow document deletion', async ({ authenticatedPage: page }) => {
|
test.skip('should allow document deletion', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstDocument = page.locator('[data-testid="document-item"], .document-item, .document-card').first();
|
const firstDocument = page.locator('[data-testid="document-item"], .document-item, .document-card').first();
|
||||||
|
|
||||||
if (await firstDocument.isVisible()) {
|
if (await firstDocument.isVisible()) {
|
||||||
|
|
@ -163,7 +163,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should filter documents by type', async ({ authenticatedPage: page }) => {
|
test.skip('should filter documents by type', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for filter controls
|
// Look for filter controls
|
||||||
const filterDropdown = page.locator('[data-testid="type-filter"], select[name="type"], .type-filter');
|
const filterDropdown = page.locator('[data-testid="type-filter"], select[name="type"], .type-filter');
|
||||||
if (await filterDropdown.isVisible()) {
|
if (await filterDropdown.isVisible()) {
|
||||||
|
|
@ -180,7 +180,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should sort documents', async ({ authenticatedPage: page }) => {
|
test.skip('should sort documents', async ({ dynamicAdminPage: page }) => {
|
||||||
const sortDropdown = page.locator('[data-testid="sort"], select[name="sort"], .sort-dropdown');
|
const sortDropdown = page.locator('[data-testid="sort"], select[name="sort"], .sort-dropdown');
|
||||||
if (await sortDropdown.isVisible()) {
|
if (await sortDropdown.isVisible()) {
|
||||||
await sortDropdown.selectOption('date-desc');
|
await sortDropdown.selectOption('date-desc');
|
||||||
|
|
@ -192,7 +192,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should display OCR status', async ({ authenticatedPage: page }) => {
|
test.skip('should display OCR status', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstDocument = page.locator('.MuiCard-root').first();
|
const firstDocument = page.locator('.MuiCard-root').first();
|
||||||
|
|
||||||
if (await firstDocument.isVisible()) {
|
if (await firstDocument.isVisible()) {
|
||||||
|
|
@ -207,7 +207,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should search within document content', async ({ authenticatedPage: page }) => {
|
test.skip('should search within document content', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstDocument = page.locator('.MuiCard-root').first();
|
const firstDocument = page.locator('.MuiCard-root').first();
|
||||||
|
|
||||||
if (await firstDocument.isVisible()) {
|
if (await firstDocument.isVisible()) {
|
||||||
|
|
@ -230,7 +230,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should paginate document list', async ({ authenticatedPage: page }) => {
|
test.skip('should paginate document list', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for pagination controls
|
// Look for pagination controls
|
||||||
const nextPageButton = page.locator('[data-testid="next-page"], button:has-text("Next"), .pagination-next');
|
const nextPageButton = page.locator('[data-testid="next-page"], button:has-text("Next"), .pagination-next');
|
||||||
if (await nextPageButton.isVisible()) {
|
if (await nextPageButton.isVisible()) {
|
||||||
|
|
@ -246,7 +246,7 @@ test.describe('Document Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show document thumbnails'.skip, async ({ authenticatedPage: page }) => {
|
test('should show document thumbnails'.skip, async ({ dynamicAdminPage: page }) => {
|
||||||
// Check for document thumbnails in list view
|
// Check for document thumbnails in list view
|
||||||
const documentThumbnails = page.locator('[data-testid="document-thumbnail"], .thumbnail, .document-preview');
|
const documentThumbnails = page.locator('[data-testid="document-thumbnail"], .thumbnail, .document-preview');
|
||||||
if (await documentThumbnails.first().isVisible()) {
|
if (await documentThumbnails.first().isVisible()) {
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,6 @@ import { test as base, expect } from '@playwright/test';
|
||||||
import type { Page } from '@playwright/test';
|
import type { Page } from '@playwright/test';
|
||||||
import { E2ETestAuthHelper, type E2ETestUser, type TestCredentials } from '../utils/test-auth-helper';
|
import { E2ETestAuthHelper, type E2ETestUser, type TestCredentials } from '../utils/test-auth-helper';
|
||||||
|
|
||||||
// Legacy credentials for backward compatibility (still available for seeded admin user)
|
|
||||||
export const TEST_CREDENTIALS = {
|
|
||||||
admin: {
|
|
||||||
username: 'admin',
|
|
||||||
password: 'readur2024'
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
username: 'user',
|
|
||||||
password: 'userpass123'
|
|
||||||
}
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const TIMEOUTS = {
|
export const TIMEOUTS = {
|
||||||
login: 15000,
|
login: 15000,
|
||||||
navigation: 15000,
|
navigation: 15000,
|
||||||
|
|
@ -21,174 +9,14 @@ export const TIMEOUTS = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export interface AuthFixture {
|
export interface AuthFixture {
|
||||||
authenticatedPage: Page;
|
|
||||||
adminPage: Page;
|
|
||||||
userPage: Page;
|
|
||||||
dynamicAdminPage: Page;
|
dynamicAdminPage: Page;
|
||||||
dynamicUserPage: Page;
|
dynamicUserPage: Page;
|
||||||
testUser: E2ETestUser;
|
testUser: E2ETestUser;
|
||||||
testAdmin: E2ETestUser;
|
testAdmin: E2ETestUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shared authentication helper functions
|
|
||||||
export class AuthHelper {
|
|
||||||
constructor(private page: Page) {}
|
|
||||||
|
|
||||||
async loginAs(credentials: typeof TEST_CREDENTIALS.admin | typeof TEST_CREDENTIALS.user) {
|
|
||||||
console.log(`Attempting to login as ${credentials.username}...`);
|
|
||||||
|
|
||||||
// Go to home page and wait for it to load
|
|
||||||
await this.page.goto('/');
|
|
||||||
await this.page.waitForLoadState('networkidle');
|
|
||||||
|
|
||||||
// Check if already logged in by looking for dashboard content
|
|
||||||
const welcomeText = await this.page.locator('h4:has-text("Welcome back,")').isVisible().catch(() => false);
|
|
||||||
|
|
||||||
if (welcomeText) {
|
|
||||||
console.log('Already logged in - found welcome message');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for login page to be ready - look for the distinctive login page content
|
|
||||||
await this.page.waitForSelector('h3:has-text("Welcome to Readur")', { timeout: TIMEOUTS.login });
|
|
||||||
await this.page.waitForSelector('h5:has-text("Sign in to your account")', { timeout: TIMEOUTS.login });
|
|
||||||
|
|
||||||
// Material-UI creates input elements inside TextFields, but we need to wait for them to be ready
|
|
||||||
// The inputs have the name attributes from react-hook-form register
|
|
||||||
const usernameField = this.page.locator('input[name="username"]');
|
|
||||||
const passwordField = this.page.locator('input[name="password"]');
|
|
||||||
|
|
||||||
// Wait for both fields to be attached and visible
|
|
||||||
await usernameField.waitFor({ state: 'attached', timeout: TIMEOUTS.login });
|
|
||||||
await passwordField.waitFor({ state: 'attached', timeout: TIMEOUTS.login });
|
|
||||||
|
|
||||||
// WebKit can be slower - add extra wait time
|
|
||||||
const browserName = await this.page.evaluate(() => navigator.userAgent);
|
|
||||||
const isWebKit = browserName.includes('WebKit') && !browserName.includes('Chrome');
|
|
||||||
if (isWebKit) {
|
|
||||||
console.log('WebKit browser detected - adding extra wait time');
|
|
||||||
await this.page.waitForTimeout(5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear any existing content and fill the fields
|
|
||||||
await usernameField.clear();
|
|
||||||
await usernameField.fill(credentials.username);
|
|
||||||
|
|
||||||
await passwordField.clear();
|
|
||||||
await passwordField.fill(credentials.password);
|
|
||||||
|
|
||||||
// WebKit needs extra time for form validation
|
|
||||||
if (isWebKit) {
|
|
||||||
await this.page.waitForTimeout(3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 });
|
|
||||||
|
|
||||||
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: 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async logout() {
|
|
||||||
// Look for logout button/link and click it
|
|
||||||
const logoutButton = this.page.locator('[data-testid="logout"], button:has-text("Logout"), a:has-text("Logout")').first();
|
|
||||||
|
|
||||||
if (await logoutButton.isVisible()) {
|
|
||||||
await logoutButton.click();
|
|
||||||
|
|
||||||
// Wait for redirect to login page
|
|
||||||
await this.page.waitForFunction(() =>
|
|
||||||
window.location.pathname.includes('/login') || window.location.pathname === '/',
|
|
||||||
{ timeout: TIMEOUTS.navigation }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async ensureLoggedOut() {
|
|
||||||
await this.page.goto('/');
|
|
||||||
await this.page.waitForLoadState('networkidle');
|
|
||||||
|
|
||||||
// If we see a login form, we're already logged out
|
|
||||||
const usernameInput = await this.page.locator('input[name="username"]').isVisible().catch(() => false);
|
|
||||||
if (usernameInput) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, try to logout
|
|
||||||
await this.logout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const test = base.extend<AuthFixture>({
|
export const test = base.extend<AuthFixture>({
|
||||||
// Legacy fixtures using seeded users (for backward compatibility)
|
// Dynamic fixtures using API-created users
|
||||||
authenticatedPage: async ({ page }, use) => {
|
|
||||||
const auth = new AuthHelper(page);
|
|
||||||
await auth.loginAs(TEST_CREDENTIALS.admin);
|
|
||||||
await use(page);
|
|
||||||
},
|
|
||||||
|
|
||||||
adminPage: async ({ page }, use) => {
|
|
||||||
const auth = new AuthHelper(page);
|
|
||||||
await auth.loginAs(TEST_CREDENTIALS.admin);
|
|
||||||
await use(page);
|
|
||||||
},
|
|
||||||
|
|
||||||
userPage: async ({ page }, use) => {
|
|
||||||
const auth = new AuthHelper(page);
|
|
||||||
await auth.loginAs(TEST_CREDENTIALS.admin); // Use admin since 'user' doesn't exist
|
|
||||||
await use(page);
|
|
||||||
},
|
|
||||||
|
|
||||||
// New dynamic fixtures using API-created users
|
|
||||||
testUser: async ({ page }, use) => {
|
testUser: async ({ page }, use) => {
|
||||||
const authHelper = new E2ETestAuthHelper(page);
|
const authHelper = new E2ETestAuthHelper(page);
|
||||||
const testUser = await authHelper.createTestUser();
|
const testUser = await authHelper.createTestUser();
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('Navigation', () => {
|
test.describe('Navigation', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ authenticatedPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(authenticatedPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should check available routes after login', async ({ authenticatedPage: page }) => {
|
test('should check available routes after login', async ({ dynamicAdminPage: page }) => {
|
||||||
// Check current URL after login
|
// Check current URL after login
|
||||||
console.log('Current URL after login:', page.url());
|
console.log('Current URL after login:', page.url());
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ test.describe('Navigation', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should check what elements are on dashboard', async ({ authenticatedPage: page }) => {
|
test('should check what elements are on dashboard', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/dashboard');
|
await page.goto('/dashboard');
|
||||||
await page.waitForLoadState('networkidle', { timeout: 5000 });
|
await page.waitForLoadState('networkidle', { timeout: 5000 });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('OCR Retry Workflow', () => {
|
test.describe('OCR Retry Workflow', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ adminPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(adminPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/documents');
|
await helpers.navigateToPage('/documents');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display failed OCR documents', async ({ adminPage: page }) => {
|
test('should display failed OCR documents', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/documents');
|
await page.goto('/documents');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ test.describe('OCR Retry Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should retry individual failed OCR document', async ({ adminPage: page }) => {
|
test('should retry individual failed OCR document', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/documents');
|
await page.goto('/documents');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ test.describe('OCR Retry Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should bulk retry multiple failed OCR documents', async ({ adminPage: page }) => {
|
test('should bulk retry multiple failed OCR documents', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/documents');
|
await page.goto('/documents');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -130,7 +130,7 @@ test.describe('OCR Retry Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show OCR retry history', async ({ adminPage: page }) => {
|
test('should show OCR retry history', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/documents');
|
await page.goto('/documents');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -153,7 +153,7 @@ test.describe('OCR Retry Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display OCR failure reasons', async ({ adminPage: page }) => {
|
test('should display OCR failure reasons', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/documents');
|
await page.goto('/documents');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ test.describe('OCR Retry Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should filter failed documents by failure type', async ({ adminPage: page }) => {
|
test('should filter failed documents by failure type', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/documents');
|
await page.goto('/documents');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,20 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('Search Functionality', () => {
|
test.describe('Search Functionality', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ authenticatedPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(authenticatedPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/search');
|
await helpers.navigateToPage('/search');
|
||||||
// Ensure we have test documents for search functionality
|
// Ensure we have test documents for search functionality
|
||||||
await helpers.ensureTestDocumentsExist();
|
await helpers.ensureTestDocumentsExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should display search interface', async ({ authenticatedPage: page }) => {
|
test.skip('should display search interface', async ({ dynamicAdminPage: page }) => {
|
||||||
// Check for search components
|
// Check for search components
|
||||||
await expect(page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]')).toBeVisible();
|
await expect(page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]')).toBeVisible();
|
||||||
await expect(page.locator('button:has-text("Search"), [data-testid="search-button"]')).toBeVisible();
|
await expect(page.locator('button:has-text("Search"), [data-testid="search-button"]')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should perform basic search', async ({ authenticatedPage: page }) => {
|
test.skip('should perform basic search', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Search for known OCR content from test images
|
// Search for known OCR content from test images
|
||||||
|
|
@ -39,7 +39,7 @@ test.describe('Search Functionality', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should show search suggestions', async ({ authenticatedPage: page }) => {
|
test.skip('should show search suggestions', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Start typing "Test" to trigger suggestions based on OCR content
|
// Start typing "Test" to trigger suggestions based on OCR content
|
||||||
|
|
@ -51,7 +51,7 @@ test.describe('Search Functionality', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should filter search results', async ({ authenticatedPage: page }) => {
|
test.skip('should filter search results', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Search for content that should match multiple test images
|
// Search for content that should match multiple test images
|
||||||
|
|
@ -76,7 +76,7 @@ test.describe('Search Functionality', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should perform advanced search', async ({ authenticatedPage: page }) => {
|
test.skip('should perform advanced search', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for advanced search toggle
|
// Look for advanced search toggle
|
||||||
const advancedToggle = page.locator('[data-testid="advanced-search"], button:has-text("Advanced"), .advanced-toggle');
|
const advancedToggle = page.locator('[data-testid="advanced-search"], button:has-text("Advanced"), .advanced-toggle');
|
||||||
|
|
||||||
|
|
@ -103,7 +103,7 @@ test.describe('Search Functionality', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should handle empty search results', async ({ authenticatedPage: page }) => {
|
test.skip('should handle empty search results', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Search for something that doesn't exist
|
// Search for something that doesn't exist
|
||||||
|
|
@ -118,7 +118,7 @@ test.describe('Search Functionality', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should navigate to document from search results', async ({ authenticatedPage: page }) => {
|
test.skip('should navigate to document from search results', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Perform search
|
// Perform search
|
||||||
|
|
@ -137,7 +137,7 @@ test.describe('Search Functionality', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should preserve search state on page reload', async ({ authenticatedPage: page }) => {
|
test.skip('should preserve search state on page reload', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Perform search
|
// Perform search
|
||||||
|
|
@ -156,7 +156,7 @@ test.describe('Search Functionality', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should sort search results', async ({ authenticatedPage: page }) => {
|
test.skip('should sort search results', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Perform search
|
// Perform search
|
||||||
|
|
@ -175,7 +175,7 @@ test.describe('Search Functionality', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should paginate search results', async ({ authenticatedPage: page }) => {
|
test.skip('should paginate search results', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Perform search
|
// Perform search
|
||||||
|
|
@ -197,7 +197,7 @@ test.describe('Search Functionality', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should highlight search terms in results', async ({ authenticatedPage: page }) => {
|
test.skip('should highlight search terms in results', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Perform search with specific term
|
// Perform search with specific term
|
||||||
|
|
@ -212,7 +212,7 @@ test.describe('Search Functionality', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should clear search results', async ({ authenticatedPage: page }) => {
|
test.skip('should clear search results', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
const searchInput = page.locator('input[type="search"], input[placeholder*="search" i], [data-testid="search-input"]').first();
|
||||||
|
|
||||||
// Perform search
|
// Perform search
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('Settings Management', () => {
|
test.describe('Settings Management', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ authenticatedPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(authenticatedPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/settings');
|
await helpers.navigateToPage('/settings');
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should display settings interface', async ({ authenticatedPage: page }) => {
|
test.skip('should display settings interface', async ({ dynamicAdminPage: page }) => {
|
||||||
// Check for settings page components
|
// Check for settings page components
|
||||||
await expect(page.locator('[data-testid="settings-container"], .settings-page, .settings-form')).toBeVisible();
|
await expect(page.locator('[data-testid="settings-container"], .settings-page, .settings-form')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update OCR settings', async ({ authenticatedPage: page }) => {
|
test('should update OCR settings', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for OCR settings section
|
// Look for OCR settings section
|
||||||
const ocrSection = page.locator('[data-testid="ocr-settings"], .ocr-section, .settings-section:has-text("OCR")');
|
const ocrSection = page.locator('[data-testid="ocr-settings"], .ocr-section, .settings-section:has-text("OCR")');
|
||||||
if (await ocrSection.isVisible()) {
|
if (await ocrSection.isVisible()) {
|
||||||
|
|
@ -35,7 +35,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update watch folder settings', async ({ authenticatedPage: page }) => {
|
test('should update watch folder settings', async ({ dynamicAdminPage: page }) => {
|
||||||
// Navigate to watch folder section if it's a separate page
|
// Navigate to watch folder section if it's a separate page
|
||||||
const watchFolderNav = page.locator('a[href="/watch-folder"], [data-testid="watch-folder-nav"]');
|
const watchFolderNav = page.locator('a[href="/watch-folder"], [data-testid="watch-folder-nav"]');
|
||||||
if (await watchFolderNav.isVisible()) {
|
if (await watchFolderNav.isVisible()) {
|
||||||
|
|
@ -67,7 +67,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update notification settings', async ({ authenticatedPage: page }) => {
|
test('should update notification settings', async ({ dynamicAdminPage: page }) => {
|
||||||
const notificationSection = page.locator('[data-testid="notification-settings"], .notification-section, .settings-section:has-text("Notification")');
|
const notificationSection = page.locator('[data-testid="notification-settings"], .notification-section, .settings-section:has-text("Notification")');
|
||||||
if (await notificationSection.isVisible()) {
|
if (await notificationSection.isVisible()) {
|
||||||
// Enable notifications
|
// Enable notifications
|
||||||
|
|
@ -96,7 +96,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update search settings', async ({ authenticatedPage: page }) => {
|
test('should update search settings', async ({ dynamicAdminPage: page }) => {
|
||||||
const searchSection = page.locator('[data-testid="search-settings"], .search-section, .settings-section:has-text("Search")');
|
const searchSection = page.locator('[data-testid="search-settings"], .search-section, .settings-section:has-text("Search")');
|
||||||
if (await searchSection.isVisible()) {
|
if (await searchSection.isVisible()) {
|
||||||
// Configure search results per page
|
// Configure search results per page
|
||||||
|
|
@ -120,7 +120,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should reset settings to defaults', async ({ authenticatedPage: page }) => {
|
test('should reset settings to defaults', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for reset button
|
// Look for reset button
|
||||||
const resetButton = page.locator('button:has-text("Reset"), button:has-text("Default"), [data-testid="reset-settings"]');
|
const resetButton = page.locator('button:has-text("Reset"), button:has-text("Default"), [data-testid="reset-settings"]');
|
||||||
if (await resetButton.isVisible()) {
|
if (await resetButton.isVisible()) {
|
||||||
|
|
@ -142,7 +142,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should validate settings before saving', async ({ authenticatedPage: page }) => {
|
test('should validate settings before saving', async ({ dynamicAdminPage: page }) => {
|
||||||
// Try to set invalid values
|
// Try to set invalid values
|
||||||
const pathInput = page.locator('input[name="watchPath"], [data-testid="watch-path"]');
|
const pathInput = page.locator('input[name="watchPath"], [data-testid="watch-path"]');
|
||||||
if (await pathInput.isVisible()) {
|
if (await pathInput.isVisible()) {
|
||||||
|
|
@ -159,7 +159,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should export settings', async ({ authenticatedPage: page }) => {
|
test('should export settings', async ({ dynamicAdminPage: page }) => {
|
||||||
const exportButton = page.locator('button:has-text("Export"), [data-testid="export-settings"]');
|
const exportButton = page.locator('button:has-text("Export"), [data-testid="export-settings"]');
|
||||||
if (await exportButton.isVisible()) {
|
if (await exportButton.isVisible()) {
|
||||||
// Set up download listener
|
// Set up download listener
|
||||||
|
|
@ -173,7 +173,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should import settings', async ({ authenticatedPage: page }) => {
|
test('should import settings', async ({ dynamicAdminPage: page }) => {
|
||||||
const importButton = page.locator('button:has-text("Import"), [data-testid="import-settings"]');
|
const importButton = page.locator('button:has-text("Import"), [data-testid="import-settings"]');
|
||||||
if (await importButton.isVisible()) {
|
if (await importButton.isVisible()) {
|
||||||
// Look for file input
|
// Look for file input
|
||||||
|
|
@ -202,7 +202,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display current system status', async ({ authenticatedPage: page }) => {
|
test('should display current system status', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for system status section
|
// Look for system status section
|
||||||
const statusSection = page.locator('[data-testid="system-status"], .status-section, .settings-section:has-text("Status")');
|
const statusSection = page.locator('[data-testid="system-status"], .status-section, .settings-section:has-text("Status")');
|
||||||
if (await statusSection.isVisible()) {
|
if (await statusSection.isVisible()) {
|
||||||
|
|
@ -211,7 +211,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should test OCR functionality', async ({ authenticatedPage: page }) => {
|
test('should test OCR functionality', async ({ dynamicAdminPage: page }) => {
|
||||||
const ocrSection = page.locator('[data-testid="ocr-settings"], .ocr-section');
|
const ocrSection = page.locator('[data-testid="ocr-settings"], .ocr-section');
|
||||||
if (await ocrSection.isVisible()) {
|
if (await ocrSection.isVisible()) {
|
||||||
const testButton = page.locator('button:has-text("Test OCR"), [data-testid="test-ocr"]');
|
const testButton = page.locator('button:has-text("Test OCR"), [data-testid="test-ocr"]');
|
||||||
|
|
@ -228,7 +228,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should clear cache', async ({ authenticatedPage: page }) => {
|
test('should clear cache', async ({ dynamicAdminPage: page }) => {
|
||||||
const clearCacheButton = page.locator('button:has-text("Clear Cache"), [data-testid="clear-cache"]');
|
const clearCacheButton = page.locator('button:has-text("Clear Cache"), [data-testid="clear-cache"]');
|
||||||
if (await clearCacheButton.isVisible()) {
|
if (await clearCacheButton.isVisible()) {
|
||||||
const clearResponse = helpers.waitForApiCall('/api/cache/clear');
|
const clearResponse = helpers.waitForApiCall('/api/cache/clear');
|
||||||
|
|
@ -240,7 +240,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should update user profile', async ({ authenticatedPage: page }) => {
|
test('should update user profile', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for user profile section
|
// Look for user profile section
|
||||||
const profileSection = page.locator('[data-testid="profile-settings"], .profile-section, .settings-section:has-text("Profile")');
|
const profileSection = page.locator('[data-testid="profile-settings"], .profile-section, .settings-section:has-text("Profile")');
|
||||||
if (await profileSection.isVisible()) {
|
if (await profileSection.isVisible()) {
|
||||||
|
|
@ -265,7 +265,7 @@ test.describe('Settings Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should change password', async ({ authenticatedPage: page }) => {
|
test('should change password', async ({ dynamicAdminPage: page }) => {
|
||||||
const passwordSection = page.locator('[data-testid="password-settings"], .password-section, .settings-section:has-text("Password")');
|
const passwordSection = page.locator('[data-testid="password-settings"], .password-section, .settings-section:has-text("Password")');
|
||||||
if (await passwordSection.isVisible()) {
|
if (await passwordSection.isVisible()) {
|
||||||
await page.fill('input[name="currentPassword"], [data-testid="current-password"]', 'currentpass');
|
await page.fill('input[name="currentPassword"], [data-testid="current-password"]', 'currentpass');
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,18 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('Source Management', () => {
|
test.describe('Source Management', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ adminPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(adminPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/sources');
|
await helpers.navigateToPage('/sources');
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should display sources interface', async ({ adminPage: page }) => {
|
test.skip('should display sources interface', async ({ dynamicAdminPage: page }) => {
|
||||||
// Check for sources page components
|
// Check for sources page components
|
||||||
await expect(page.locator('[data-testid="sources-list"], .sources-list, .sources-container')).toBeVisible();
|
await expect(page.locator('[data-testid="sources-list"], .sources-list, .sources-container')).toBeVisible();
|
||||||
await expect(page.locator('button:has-text("Add Source"), [data-testid="add-source"]')).toBeVisible();
|
await expect(page.locator('button:has-text("Add Source"), [data-testid="add-source"]')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should create a new local folder source', async ({ adminPage: page }) => {
|
test.skip('should create a new local folder source', async ({ dynamicAdminPage: page }) => {
|
||||||
// Click add source button
|
// Click add source button
|
||||||
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ test.describe('Source Management', () => {
|
||||||
await expect(page.locator(':has-text("Test Local Folder")')).toBeVisible({ timeout: TIMEOUTS.medium });
|
await expect(page.locator(':has-text("Test Local Folder")')).toBeVisible({ timeout: TIMEOUTS.medium });
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should create a new WebDAV source', async ({ adminPage: page }) => {
|
test.skip('should create a new WebDAV source', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
||||||
|
|
||||||
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal, .source-form')).toBeVisible();
|
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal, .source-form')).toBeVisible();
|
||||||
|
|
@ -79,7 +79,7 @@ test.describe('Source Management', () => {
|
||||||
await expect(page.locator(':has-text("Test WebDAV")')).toBeVisible({ timeout: TIMEOUTS.medium });
|
await expect(page.locator(':has-text("Test WebDAV")')).toBeVisible({ timeout: TIMEOUTS.medium });
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should create a new S3 source', async ({ adminPage: page }) => {
|
test.skip('should create a new S3 source', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
||||||
|
|
||||||
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal, .source-form')).toBeVisible();
|
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal, .source-form')).toBeVisible();
|
||||||
|
|
@ -108,7 +108,7 @@ test.describe('Source Management', () => {
|
||||||
await expect(page.locator(':has-text("Test S3 Bucket")')).toBeVisible({ timeout: TIMEOUTS.medium });
|
await expect(page.locator(':has-text("Test S3 Bucket")')).toBeVisible({ timeout: TIMEOUTS.medium });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should edit existing source', async ({ adminPage: page }) => {
|
test('should edit existing source', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for existing source to edit
|
// Look for existing source to edit
|
||||||
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should delete source', async ({ adminPage: page }) => {
|
test('should delete source', async ({ dynamicAdminPage: page }) => {
|
||||||
// First wait for sources list to load
|
// First wait for sources list to load
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -298,7 +298,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should start source sync', async ({ adminPage: page }) => {
|
test.skip('should start source sync', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
||||||
|
|
||||||
if (await firstSource.isVisible()) {
|
if (await firstSource.isVisible()) {
|
||||||
|
|
@ -319,7 +319,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should stop source sync', async ({ adminPage: page }) => {
|
test('should stop source sync', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
||||||
|
|
||||||
if (await firstSource.isVisible()) {
|
if (await firstSource.isVisible()) {
|
||||||
|
|
@ -347,7 +347,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display source status and statistics', async ({ adminPage: page }) => {
|
test('should display source status and statistics', async ({ dynamicAdminPage: page }) => {
|
||||||
// First wait for sources list to load
|
// First wait for sources list to load
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -420,7 +420,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should test source connection', async ({ adminPage: page }) => {
|
test.skip('should test source connection', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
||||||
|
|
||||||
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal')).toBeVisible();
|
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal')).toBeVisible();
|
||||||
|
|
@ -451,7 +451,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should filter sources by type', async ({ adminPage: page }) => {
|
test('should filter sources by type', async ({ dynamicAdminPage: page }) => {
|
||||||
// Look for filter dropdown
|
// Look for filter dropdown
|
||||||
const filterDropdown = page.locator('[data-testid="source-filter"], select[name="filter"], .source-filter');
|
const filterDropdown = page.locator('[data-testid="source-filter"], select[name="filter"], .source-filter');
|
||||||
if (await filterDropdown.isVisible()) {
|
if (await filterDropdown.isVisible()) {
|
||||||
|
|
@ -467,7 +467,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display sync history', async ({ adminPage: page }) => {
|
test('should display sync history', async ({ dynamicAdminPage: page }) => {
|
||||||
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
const firstSource = page.locator('[data-testid="source-item"], .source-item, .source-card').first();
|
||||||
|
|
||||||
if (await firstSource.isVisible()) {
|
if (await firstSource.isVisible()) {
|
||||||
|
|
@ -482,7 +482,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should validate required fields in source creation', async ({ adminPage: page }) => {
|
test.skip('should validate required fields in source creation', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
await page.click('button:has-text("Add Source"), [data-testid="add-source"]');
|
||||||
|
|
||||||
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal')).toBeVisible();
|
await expect(page.locator('[data-testid="add-source-form"], .add-source-modal')).toBeVisible();
|
||||||
|
|
@ -501,7 +501,7 @@ test.describe('Source Management', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should schedule automatic sync', async ({ adminPage: page }) => {
|
test('should schedule automatic sync', async ({ dynamicAdminPage: page }) => {
|
||||||
// First wait for sources list to load
|
// First wait for sources list to load
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,23 +57,7 @@ export class E2ETestAuthHelper {
|
||||||
|
|
||||||
if (!response.ok()) {
|
if (!response.ok()) {
|
||||||
const errorText = await response.text();
|
const errorText = await response.text();
|
||||||
console.warn(`Warning: Failed to create dynamic test user. Status: ${response.status()}, Body: ${errorText}`);
|
throw new Error(`Failed to create dynamic test user. Status: ${response.status()}, Body: ${errorText}`);
|
||||||
|
|
||||||
// Fallback to seeded admin user (since no regular user is seeded)
|
|
||||||
console.log('Falling back to seeded admin user...');
|
|
||||||
return {
|
|
||||||
credentials: {
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
password: 'readur2024'
|
|
||||||
},
|
|
||||||
userResponse: {
|
|
||||||
id: 'seeded-admin',
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
role: 'Admin'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const userResponse: TestUserResponse = await response.json();
|
const userResponse: TestUserResponse = await response.json();
|
||||||
|
|
@ -84,22 +68,7 @@ export class E2ETestAuthHelper {
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Failed to create E2E test user:', error);
|
console.error('❌ Failed to create E2E test user:', error);
|
||||||
|
throw error;
|
||||||
// Fallback to seeded admin user (since no regular user is seeded)
|
|
||||||
console.log('Falling back to seeded admin user due to error...');
|
|
||||||
return {
|
|
||||||
credentials: {
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
password: 'readur2024'
|
|
||||||
},
|
|
||||||
userResponse: {
|
|
||||||
id: 'seeded-admin',
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
role: 'Admin'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,23 +98,7 @@ export class E2ETestAuthHelper {
|
||||||
|
|
||||||
if (!response.ok()) {
|
if (!response.ok()) {
|
||||||
const errorText = await response.text();
|
const errorText = await response.text();
|
||||||
console.warn(`Warning: Failed to create dynamic admin user. Status: ${response.status()}, Body: ${errorText}`);
|
throw new Error(`Failed to create dynamic admin user. Status: ${response.status()}, Body: ${errorText}`);
|
||||||
|
|
||||||
// Fallback to seeded admin user
|
|
||||||
console.log('Falling back to seeded admin user...');
|
|
||||||
return {
|
|
||||||
credentials: {
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
password: 'readur2024'
|
|
||||||
},
|
|
||||||
userResponse: {
|
|
||||||
id: 'seeded-admin',
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
role: 'Admin'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const userResponse: TestUserResponse = await response.json();
|
const userResponse: TestUserResponse = await response.json();
|
||||||
|
|
@ -156,22 +109,7 @@ export class E2ETestAuthHelper {
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ Failed to create E2E admin user:', error);
|
console.error('❌ Failed to create E2E admin user:', error);
|
||||||
|
throw error;
|
||||||
// Fallback to seeded admin user
|
|
||||||
console.log('Falling back to seeded admin user due to error...');
|
|
||||||
return {
|
|
||||||
credentials: {
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
password: 'readur2024'
|
|
||||||
},
|
|
||||||
userResponse: {
|
|
||||||
id: 'seeded-admin',
|
|
||||||
username: 'admin',
|
|
||||||
email: 'admin@test.com',
|
|
||||||
role: 'Admin'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { TEST_CREDENTIALS } from '../fixtures/auth';
|
// Test users are now created dynamically via E2ETestAuthHelper
|
||||||
|
// Invalid credentials for testing error cases
|
||||||
export const TEST_USERS = {
|
export const TEST_USERS = {
|
||||||
valid: TEST_CREDENTIALS.admin,
|
|
||||||
invalid: {
|
invalid: {
|
||||||
username: 'invaliduser',
|
username: 'invaliduser',
|
||||||
password: 'wrongpassword'
|
password: 'wrongpassword'
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('WebDAV Workflow (Dynamic Auth)', () => {
|
test.describe('WebDAV Workflow (Dynamic Auth)', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ authenticatedPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(authenticatedPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/sources');
|
await helpers.navigateToPage('/sources');
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should create and configure WebDAV source with dynamic admin', async ({ authenticatedPage: page }) => {
|
test.skip('should create and configure WebDAV source with dynamic admin', async ({ dynamicAdminPage: page }) => {
|
||||||
// Increase timeout for this test as WebDAV operations can be slow
|
// Increase timeout for this test as WebDAV operations can be slow
|
||||||
test.setTimeout(60000);
|
test.setTimeout(60000);
|
||||||
|
|
||||||
|
|
@ -352,7 +352,7 @@ test.describe('WebDAV Workflow (Dynamic Auth)', () => {
|
||||||
console.log('✅ WebDAV source creation test completed by authenticated admin');
|
console.log('✅ WebDAV source creation test completed by authenticated admin');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should test WebDAV connection with dynamic admin', async ({ authenticatedPage: page }) => {
|
test('should test WebDAV connection with dynamic admin', async ({ dynamicAdminPage: page }) => {
|
||||||
console.log('Testing WebDAV connection with authenticated admin');
|
console.log('Testing WebDAV connection with authenticated admin');
|
||||||
|
|
||||||
// This test assumes a WebDAV source exists from the previous test or setup
|
// This test assumes a WebDAV source exists from the previous test or setup
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('WebDAV Workflow', () => {
|
test.describe('WebDAV Workflow', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ authenticatedPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(authenticatedPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/sources');
|
await helpers.navigateToPage('/sources');
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should create and configure WebDAV source', async ({ authenticatedPage: page }) => {
|
test.skip('should create and configure WebDAV source', async ({ dynamicAdminPage: page }) => {
|
||||||
// Increase timeout for this test as WebDAV operations can be slow
|
// Increase timeout for this test as WebDAV operations can be slow
|
||||||
// This addresses the timeout issues with Material-UI Select components
|
// This addresses the timeout issues with Material-UI Select components
|
||||||
test.setTimeout(60000);
|
test.setTimeout(60000);
|
||||||
|
|
@ -223,7 +223,7 @@ test.describe('WebDAV Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should test WebDAV connection', async ({ authenticatedPage: page }) => {
|
test('should test WebDAV connection', async ({ dynamicAdminPage: page }) => {
|
||||||
// This test assumes a WebDAV source exists from the previous test or setup
|
// This test assumes a WebDAV source exists from the previous test or setup
|
||||||
await page.goto('/sources');
|
await page.goto('/sources');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
@ -256,7 +256,7 @@ test.describe('WebDAV Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should initiate WebDAV sync', async ({ authenticatedPage: page }) => {
|
test('should initiate WebDAV sync', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/sources');
|
await page.goto('/sources');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -287,7 +287,7 @@ test.describe('WebDAV Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show WebDAV sync history', async ({ authenticatedPage: page }) => {
|
test('should show WebDAV sync history', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/sources');
|
await page.goto('/sources');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
@ -310,7 +310,7 @@ test.describe('WebDAV Workflow', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle WebDAV source deletion', async ({ authenticatedPage: page }) => {
|
test('should handle WebDAV source deletion', async ({ dynamicAdminPage: page }) => {
|
||||||
await page.goto('/sources');
|
await page.goto('/sources');
|
||||||
await helpers.waitForLoadingToComplete();
|
await helpers.waitForLoadingToComplete();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ import { TestHelpers } from './utils/test-helpers';
|
||||||
test.describe('WebSocket Sync Progress', () => {
|
test.describe('WebSocket Sync Progress', () => {
|
||||||
let helpers: TestHelpers;
|
let helpers: TestHelpers;
|
||||||
|
|
||||||
test.beforeEach(async ({ adminPage }) => {
|
test.beforeEach(async ({ dynamicAdminPage }) => {
|
||||||
helpers = new TestHelpers(adminPage);
|
helpers = new TestHelpers(dynamicAdminPage);
|
||||||
await helpers.navigateToPage('/sources');
|
await helpers.navigateToPage('/sources');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
return fallbackElement;
|
return fallbackElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
test('should establish WebSocket connection for sync progress', async ({ adminPage: page }) => {
|
test('should establish WebSocket connection for sync progress', async ({ dynamicAdminPage: page }) => {
|
||||||
// Add browser console logging to debug WebSocket connections
|
// Add browser console logging to debug WebSocket connections
|
||||||
const consoleLogs: string[] = [];
|
const consoleLogs: string[] = [];
|
||||||
page.on('console', msg => {
|
page.on('console', msg => {
|
||||||
|
|
@ -177,7 +177,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
await expect(progressIndicators).toBeVisible({ timeout: TIMEOUTS.short });
|
await expect(progressIndicators).toBeVisible({ timeout: TIMEOUTS.short });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle WebSocket connection errors gracefully', async ({ adminPage: page }) => {
|
test('should handle WebSocket connection errors gracefully', async ({ dynamicAdminPage: page }) => {
|
||||||
// Mock WebSocket connection failure
|
// Mock WebSocket connection failure
|
||||||
await page.route('**/sync/progress/ws**', route => {
|
await page.route('**/sync/progress/ws**', route => {
|
||||||
route.abort('connectionrefused');
|
route.abort('connectionrefused');
|
||||||
|
|
@ -215,7 +215,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should automatically reconnect on WebSocket disconnection', async ({ adminPage: page }) => {
|
test('should automatically reconnect on WebSocket disconnection', async ({ dynamicAdminPage: page }) => {
|
||||||
// Create and sync a source
|
// Create and sync a source
|
||||||
const sourceName = await helpers.createTestSource('Reconnect Test Source', 'webdav');
|
const sourceName = await helpers.createTestSource('Reconnect Test Source', 'webdav');
|
||||||
|
|
||||||
|
|
@ -266,7 +266,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
await expect(finalStatus).toBeVisible({ timeout: TIMEOUTS.medium });
|
await expect(finalStatus).toBeVisible({ timeout: TIMEOUTS.medium });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display real-time progress updates via WebSocket', async ({ adminPage: page }) => {
|
test('should display real-time progress updates via WebSocket', async ({ dynamicAdminPage: page }) => {
|
||||||
// Create a source and start sync
|
// Create a source and start sync
|
||||||
const sourceName = await helpers.createTestSource('Progress Updates Test', 'webdav');
|
const sourceName = await helpers.createTestSource('Progress Updates Test', 'webdav');
|
||||||
|
|
||||||
|
|
@ -303,7 +303,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
await expect(statsLocator).toBeVisible({ timeout: TIMEOUTS.short });
|
await expect(statsLocator).toBeVisible({ timeout: TIMEOUTS.short });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle multiple concurrent WebSocket connections', async ({ adminPage: page }) => {
|
test('should handle multiple concurrent WebSocket connections', async ({ dynamicAdminPage: page }) => {
|
||||||
// Create multiple sources
|
// Create multiple sources
|
||||||
const sourceNames = [];
|
const sourceNames = [];
|
||||||
const baseNames = ['Multi Source 1', 'Multi Source 2'];
|
const baseNames = ['Multi Source 1', 'Multi Source 2'];
|
||||||
|
|
@ -370,7 +370,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
console.log('Multiple concurrent WebSocket test completed - infrastructure verified');
|
console.log('Multiple concurrent WebSocket test completed - infrastructure verified');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should authenticate WebSocket connection with JWT token', async ({ adminPage: page }) => {
|
test('should authenticate WebSocket connection with JWT token', async ({ dynamicAdminPage: page }) => {
|
||||||
// Check that user has a valid JWT token stored
|
// Check that user has a valid JWT token stored
|
||||||
const tokenInfo = await page.evaluate(() => {
|
const tokenInfo = await page.evaluate(() => {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
|
|
@ -403,7 +403,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
console.log('WebSocket authentication test passed - connection established successfully');
|
console.log('WebSocket authentication test passed - connection established successfully');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle WebSocket authentication failures', async ({ adminPage: page }) => {
|
test('should handle WebSocket authentication failures', async ({ dynamicAdminPage: page }) => {
|
||||||
// Mock authentication failure for WebSocket connections
|
// Mock authentication failure for WebSocket connections
|
||||||
await page.route('**/sync/progress/ws**', route => {
|
await page.route('**/sync/progress/ws**', route => {
|
||||||
if (route.request().url().includes('token=')) {
|
if (route.request().url().includes('token=')) {
|
||||||
|
|
@ -476,7 +476,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should properly clean up WebSocket connections on component unmount', async ({ adminPage: page }) => {
|
test('should properly clean up WebSocket connections on component unmount', async ({ dynamicAdminPage: page }) => {
|
||||||
// Instead of creating a new source, just use existing sources to test component lifecycle
|
// Instead of creating a new source, just use existing sources to test component lifecycle
|
||||||
// This avoids the hanging issue with source creation
|
// This avoids the hanging issue with source creation
|
||||||
|
|
||||||
|
|
@ -514,7 +514,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
console.log('WebSocket cleanup test completed - component lifecycle verified via reload');
|
console.log('WebSocket cleanup test completed - component lifecycle verified via reload');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle WebSocket message parsing errors', async ({ adminPage: page }) => {
|
test('should handle WebSocket message parsing errors', async ({ dynamicAdminPage: page }) => {
|
||||||
// Mock WebSocket with malformed messages
|
// Mock WebSocket with malformed messages
|
||||||
await page.addInitScript(() => {
|
await page.addInitScript(() => {
|
||||||
const originalWebSocket = window.WebSocket;
|
const originalWebSocket = window.WebSocket;
|
||||||
|
|
@ -561,7 +561,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
await expect(page.locator('body')).toBeVisible();
|
await expect(page.locator('body')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should display WebSocket connection status indicators', async ({ adminPage: page }) => {
|
test('should display WebSocket connection status indicators', async ({ dynamicAdminPage: page }) => {
|
||||||
// Create and sync a source
|
// Create and sync a source
|
||||||
const sourceName = await helpers.createTestSource('Status Test Source', 'webdav');
|
const sourceName = await helpers.createTestSource('Status Test Source', 'webdav');
|
||||||
|
|
||||||
|
|
@ -586,7 +586,7 @@ test.describe('WebSocket Sync Progress', () => {
|
||||||
await expect(statusChip).toHaveClass(/MuiChip-root/);
|
await expect(statusChip).toHaveClass(/MuiChip-root/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should support WebSocket connection health monitoring', async ({ adminPage: page }) => {
|
test('should support WebSocket connection health monitoring', async ({ dynamicAdminPage: page }) => {
|
||||||
// This test verifies that the WebSocket connection monitors connection health
|
// This test verifies that the WebSocket connection monitors connection health
|
||||||
|
|
||||||
let heartbeatReceived = false;
|
let heartbeatReceived = false;
|
||||||
|
|
@ -651,7 +651,7 @@ test.describe('WebSocket Sync Progress - Cross-browser Compatibility', () => {
|
||||||
await syncCard.click();
|
await syncCard.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
test('should work in different browser engines', async ({ adminPage: page }) => {
|
test('should work in different browser engines', async ({ dynamicAdminPage: page }) => {
|
||||||
// This test would run across different browsers (Chrome, Firefox, Safari)
|
// This test would run across different browsers (Chrome, Firefox, Safari)
|
||||||
// The test framework should handle this automatically
|
// The test framework should handle this automatically
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue