feat: add useApiSettings hook for managing API settings, including providers, endpoints, cache, and model pools

- Implemented hooks for CRUD operations on providers and endpoints.
- Added cache management hooks for cache stats and settings.
- Introduced model pool management hooks for high availability and load balancing.
- Created localization files for English and Chinese translations of API settings.
This commit is contained in:
catlog22
2026-02-01 23:14:55 +08:00
parent b76424feef
commit e5252f8a77
27 changed files with 4370 additions and 201 deletions

View File

@@ -442,4 +442,573 @@ test.describe('[CodexLens Manager] - CodexLens Management Tests', () => {
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
// ========================================
// Search Tab Tests
// ========================================
test.describe('[CodexLens Manager] - Search Tab Tests', () => {
test('L4.19 - should navigate to Search tab', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
// Click Search tab
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Verify tab is active
await expect(searchTab).toHaveAttribute('data-state', 'active');
// Verify search content is visible
const searchContent = page.getByText(/Search/i).or(
page.getByPlaceholder(/Search query/i)
);
const contentVisible = await searchContent.isVisible().catch(() => false);
if (contentVisible) {
await expect(searchContent.first()).toBeVisible();
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.20 - should display all search UI elements', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Verify search type selector exists
const searchTypeSelector = page.getByLabel(/Search Type/i).or(
page.getByRole('combobox', { name: /Search Type/i })
).or(page.getByText(/Search Type/i));
const typeVisible = await searchTypeSelector.isVisible().catch(() => false);
if (typeVisible) {
await expect(searchTypeSelector.first()).toBeVisible();
}
// Verify search mode selector exists
const searchModeSelector = page.getByLabel(/Search Mode/i).or(
page.getByRole('combobox', { name: /Search Mode/i })
).or(page.getByText(/Search Mode/i));
const modeVisible = await searchModeSelector.isVisible().catch(() => false);
if (modeVisible) {
await expect(searchModeSelector.first()).toBeVisible();
}
// Verify query input field exists
const queryInput = page.getByPlaceholder(/Search query/i).or(
page.getByLabel(/Query/i)
).or(page.getByRole('textbox', { name: /query/i }));
const inputVisible = await queryInput.isVisible().catch(() => false);
if (inputVisible) {
await expect(queryInput.first()).toBeVisible();
}
// Verify search button exists
const searchButton = page.getByRole('button', { name: /Search/i });
const buttonVisible = await searchButton.isVisible().catch(() => false);
if (buttonVisible) {
await expect(searchButton.first()).toBeVisible();
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.21 - should show search type options', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Click on search type selector to open dropdown
const searchTypeSelector = page.getByLabel(/Search Type/i).or(
page.getByRole('combobox', { name: /Search Type/i })
);
const typeVisible = await searchTypeSelector.isVisible().catch(() => false);
if (typeVisible) {
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
// Check for expected search type options
const searchTypes = ['Content Search', 'File Search', 'Symbol Search'];
for (const type of searchTypes) {
const option = page.getByRole('option', { name: new RegExp(type, 'i') });
const optionVisible = await option.isVisible().catch(() => false);
if (optionVisible) {
await expect(option).toBeVisible();
}
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.22 - should show search mode options for Content Search', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Select Content Search first
const searchTypeSelector = page.getByLabel(/Search Type/i).or(
page.getByRole('combobox', { name: /Search Type/i })
);
const typeVisible = await searchTypeSelector.isVisible().catch(() => false);
if (typeVisible) {
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
const contentOption = page.getByRole('option', { name: /Content Search/i });
const contentVisible = await contentOption.isVisible().catch(() => false);
if (contentVisible) {
await contentOption.click();
// Click on search mode selector to open dropdown
const searchModeSelector = page.getByLabel(/Search Mode/i).or(
page.getByRole('combobox', { name: /Search Mode/i })
);
const modeVisible = await searchModeSelector.isVisible().catch(() => false);
if (modeVisible) {
await searchModeSelector.first().click();
await page.waitForTimeout(300);
// Check for expected search mode options
const searchModes = ['Semantic', 'Exact', 'Fuzzy'];
for (const mode of searchModes) {
const option = page.getByRole('option', { name: new RegExp(mode, 'i') });
const optionVisible = await option.isVisible().catch(() => false);
if (optionVisible) {
await expect(option).toBeVisible();
}
}
}
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.23 - should hide search mode for Symbol Search', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Select Symbol Search
const searchTypeSelector = page.getByLabel(/Search Type/i).or(
page.getByRole('combobox', { name: /Search Type/i })
);
const typeVisible = await searchTypeSelector.isVisible().catch(() => false);
if (typeVisible) {
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
const symbolOption = page.getByRole('option', { name: /Symbol Search/i });
const symbolVisible = await symbolOption.isVisible().catch(() => false);
if (symbolVisible) {
await symbolOption.click();
await page.waitForTimeout(300);
// Verify search mode selector is hidden or removed
const searchModeSelector = page.getByLabel(/Search Mode/i).or(
page.getByRole('combobox', { name: /Search Mode/i })
);
const modeVisible = await searchModeSelector.isVisible().catch(() => false);
// Search mode should not be visible for Symbol Search
expect(modeVisible).toBe(false);
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.24 - should disable search button with empty query', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Verify search button is disabled with empty query
const searchButton = page.getByRole('button', { name: /Search/i });
const buttonVisible = await searchButton.isVisible().catch(() => false);
if (buttonVisible) {
// Check if button is disabled when query is empty
const isDisabled = await searchButton.first().isDisabled().catch(() => false);
if (isDisabled) {
await expect(searchButton.first()).toBeDisabled();
} else {
// If not disabled, check for validation on click
const queryInput = page.getByPlaceholder(/Search query/i).or(
page.getByLabel(/Query/i)
);
const inputVisible = await queryInput.isVisible().catch(() => false);
if (inputVisible) {
// Ensure input is empty
const inputValue = await queryInput.first().inputValue();
expect(inputValue || '').toBe('');
// Try clicking search button
await searchButton.first().click();
await page.waitForTimeout(300);
// Check for error message
const errorMessage = page.getByText(/required|enter a query|empty query/i);
const errorVisible = await errorMessage.isVisible().catch(() => false);
if (errorVisible) {
await expect(errorMessage).toBeVisible();
}
}
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.25 - should enable search button with valid query', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Enter query text
const queryInput = page.getByPlaceholder(/Search query/i).or(
page.getByLabel(/Query/i)
);
const inputVisible = await queryInput.isVisible().catch(() => false);
if (inputVisible) {
await queryInput.first().fill('test query');
await page.waitForTimeout(300);
// Verify search button is enabled
const searchButton = page.getByRole('button', { name: /Search/i });
const buttonVisible = await searchButton.isVisible().catch(() => false);
if (buttonVisible) {
const isEnabled = await searchButton.first().isEnabled().catch(() => true);
expect(isEnabled).toBe(true);
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.26 - should show loading state during search', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Enter query text
const queryInput = page.getByPlaceholder(/Search query/i).or(
page.getByLabel(/Query/i)
);
const inputVisible = await queryInput.isVisible().catch(() => false);
if (inputVisible) {
await queryInput.first().fill('test query');
await page.waitForTimeout(300);
// Click search button
const searchButton = page.getByRole('button', { name: /Search/i });
const buttonVisible = await searchButton.isVisible().catch(() => false);
if (buttonVisible) {
// Set up route handler to delay response
await page.route('**/api/codexlens/search**', async (route) => {
// Delay response to observe loading state
await new Promise(resolve => setTimeout(resolve, 1000));
route.continue();
});
await searchButton.first().click();
// Check for loading indicator
const loadingIndicator = page.getByText(/Searching|Loading/i).or(
page.getByRole('button', { name: /Search/i }).filter({ hasText: /Searching|Loading/i })
).or(page.locator('[aria-busy="true"]'));
// Wait briefly to see if loading state appears
await page.waitForTimeout(200);
const loadingVisible = await loadingIndicator.isVisible().catch(() => false);
// Clean up route
await page.unroute('**/api/codexlens/search**');
// Loading state may or may not be visible depending on speed
if (loadingVisible) {
await expect(loadingIndicator.first()).toBeVisible();
}
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.27 - should display search results', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Select Content Search
const searchTypeSelector = page.getByLabel(/Search Type/i).or(
page.getByRole('combobox', { name: /Search Type/i })
);
const typeVisible = await searchTypeSelector.isVisible().catch(() => false);
if (typeVisible) {
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
const contentOption = page.getByRole('option', { name: /Content Search/i });
const contentVisible = await contentOption.isVisible().catch(() => false);
if (contentVisible) {
await contentOption.click();
// Enter query text
const queryInput = page.getByPlaceholder(/Search query/i).or(
page.getByLabel(/Query/i)
);
const inputVisible = await queryInput.isVisible().catch(() => false);
if (inputVisible) {
await queryInput.first().fill('test');
await page.waitForTimeout(300);
// Click search button
const searchButton = page.getByRole('button', { name: /Search/i });
const buttonVisible = await searchButton.isVisible().catch(() => false);
if (buttonVisible) {
await searchButton.first().click();
// Wait for results
await page.waitForTimeout(2000);
// Check for results area
const resultsArea = page.getByText(/Results|No results|Found/i).or(
page.locator('[data-testid="search-results"]')
).or(page.locator('.search-results'));
const resultsVisible = await resultsArea.isVisible().catch(() => false);
if (resultsVisible) {
await expect(resultsArea.first()).toBeVisible();
}
}
}
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.28 - should handle search between different types', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Start with Content Search
const searchTypeSelector = page.getByLabel(/Search Type/i).or(
page.getByRole('combobox', { name: /Search Type/i })
);
const typeVisible = await searchTypeSelector.isVisible().catch(() => false);
if (typeVisible) {
// Select Content Search
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
const contentOption = page.getByRole('option', { name: /Content Search/i });
const contentVisible = await contentOption.isVisible().catch(() => false);
if (contentVisible) {
await contentOption.click();
}
// Verify mode selector is visible
const searchModeSelector = page.getByLabel(/Search Mode/i).or(
page.getByRole('combobox', { name: /Search Mode/i })
);
let modeVisible = await searchModeSelector.isVisible().catch(() => false);
expect(modeVisible).toBe(true);
// Switch to Symbol Search
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
const symbolOption = page.getByRole('option', { name: /Symbol Search/i });
const symbolVisible = await symbolOption.isVisible().catch(() => false);
if (symbolVisible) {
await symbolOption.click();
}
// Verify mode selector is hidden
modeVisible = await searchModeSelector.isVisible().catch(() => false);
expect(modeVisible).toBe(false);
// Switch to File Search
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
const fileOption = page.getByRole('option', { name: /File Search/i });
const fileVisible = await fileOption.isVisible().catch(() => false);
if (fileVisible) {
await fileOption.click();
}
// Verify mode selector is visible again
modeVisible = await searchModeSelector.isVisible().catch(() => false);
expect(modeVisible).toBe(true);
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.29 - should handle empty search results gracefully', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Enter a unique query that likely has no results
const queryInput = page.getByPlaceholder(/Search query/i).or(
page.getByLabel(/Query/i)
);
const inputVisible = await queryInput.isVisible().catch(() => false);
if (inputVisible) {
await queryInput.first().fill('nonexistent-unique-query-xyz-123');
await page.waitForTimeout(300);
// Click search button
const searchButton = page.getByRole('button', { name: /Search/i });
const buttonVisible = await searchButton.isVisible().catch(() => false);
if (buttonVisible) {
await searchButton.first().click();
// Wait for results
await page.waitForTimeout(2000);
// Check for empty state message
const emptyState = page.getByText(/No results|Found 0|No matches/i);
const emptyVisible = await emptyState.isVisible().catch(() => false);
if (emptyVisible) {
await expect(emptyState.first()).toBeVisible();
}
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
test('L4.30 - should handle search mode selection', async ({ page }) => {
const monitoring = setupEnhancedMonitoring(page);
await page.goto('/settings/codexlens', { waitUntil: 'networkidle' as const });
const searchTab = page.getByRole('tab', { name: /Search/i });
const searchTabVisible = await searchTab.isVisible().catch(() => false);
if (searchTabVisible) {
await searchTab.click();
// Ensure we're on Content or File Search (which have modes)
const searchTypeSelector = page.getByLabel(/Search Type/i).or(
page.getByRole('combobox', { name: /Search Type/i })
);
const typeVisible = await searchTypeSelector.isVisible().catch(() => false);
if (typeVisible) {
await searchTypeSelector.first().click();
await page.waitForTimeout(300);
const contentOption = page.getByRole('option', { name: /Content Search/i });
const contentVisible = await contentOption.isVisible().catch(() => false);
if (contentVisible) {
await contentOption.click();
}
// Try different search modes
const searchModes = ['Semantic', 'Exact'];
for (const mode of searchModes) {
const searchModeSelector = page.getByLabel(/Search Mode/i).or(
page.getByRole('combobox', { name: /Search Mode/i })
);
const modeVisible = await searchModeSelector.isVisible().catch(() => false);
if (modeVisible) {
await searchModeSelector.first().click();
await page.waitForTimeout(300);
const modeOption = page.getByRole('option', { name: new RegExp(mode, 'i') });
const optionVisible = await modeOption.isVisible().catch(() => false);
if (optionVisible) {
await modeOption.click();
await page.waitForTimeout(300);
// Verify selection
await expect(searchModeSelector.first()).toContainText(mode, { timeout: 2000 }).catch(() => {
// Selection may or may not be reflected in selector text
});
}
}
}
}
}
monitoring.assertClean({ allowWarnings: true });
monitoring.stop();
});
});
});