Files
brachnha-insight/tests/e2e/settings-full.spec.ts
Max 9b79856827 feat(ui): implement 'Twilight Velvet' dark theme and fix visibility issues
- Add 'Twilight Velvet' color palette to globals.css with OKLCH values
- Update SettingsPage headers, cards, and dialogs to use semantic theme variables
- Update HistoryCard, HistoryFeed, and DraftContent to support dark mode
- Update ProviderSelector and ProviderList to use custom card background (#2A2A3D)
- Add ThemeToggle component with improved visibility
- Ensure consistent use of 'bg-card', 'text-foreground', and 'text-muted-foreground'
2026-01-27 11:03:55 +07:00

118 lines
5.5 KiB
TypeScript

import { test, expect } from '../support/fixtures';
import { faker } from '@faker-js/faker';
test.describe('Settings Management (Story 4.1, 4.4)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/settings');
});
test('[P1] should configure a new LLM provider', async ({ page }) => {
// Mock validation request
await page.route('/api/llm', async route => {
const body = JSON.parse(route.request().postData() || '{}');
// Check if it's a validation request (has 'hello' message usually, see LLMService) or just success
await route.fulfill({
status: 200,
body: JSON.stringify({ success: true, data: { text: 'Validation success' } })
});
});
// GIVEN: User is on settings page
const providerName = `Custom Provider ${faker.number.int({ min: 1000 })}`;
const baseUrl = faker.internet.url();
const modelName = 'gpt-4-custom';
const apiKey = 'sk-test-key-' + faker.string.alphanumeric(10);
// WHEN: User clicks Add New Provider
await page.getByRole('button', { name: /add new provider/i }).click();
// THEN: Dialog should open
await expect(page.getByRole('dialog')).toBeVisible();
// WHEN: User fills in the form
await page.getByLabel('Provider Name').fill(providerName);
await page.getByLabel('Base URL').fill(baseUrl);
await page.getByLabel('Model Name').fill(modelName);
await page.getByPlaceholder('sk-...').fill(apiKey);
// WHEN: User saves (Button text depends on mode, usually "Save & Validate" or "Save as New Provider")
// "Save as New Provider" is likely for Add mode
await page.getByRole('button', { name: /save/i }).click();
// THEN: Dialog should close
await expect(page.getByRole('dialog')).toBeHidden();
// THEN: New provider should appear in the list
await expect(page.getByText(providerName)).toBeVisible();
await expect(page.getByText(modelName)).toBeVisible();
});
test('[P1] should switch active provider', async ({ page }) => {
// GIVEN: A provider exists (using the default one from store or we just add one)
// Since we don't inject store here (unless we want to refactor to do so),
// we might rely on default empty state and add one, OR we assume persistence from previous test if workers reused (not guaranteed).
// Best to add one first or inject state. Let's add one quickly via UI to be safe/independent.
const providerName = `Switch Test Provider ${faker.number.int()}`;
await page.getByRole('button', { name: /add new provider/i }).click();
await page.getByLabel('Provider Name').fill(providerName);
await page.getByLabel('Base URL').fill('https://api.example.com');
await page.getByLabel('Model Name').fill('gpt-test');
await page.getByPlaceholder('sk-...').fill('sk-test');
// Mock validation for this save too
await page.getByRole('button', { name: /save/i }).click();
// WHEN: User selects the new provider in the selector
// The selector uses radio behavior or clickable cards
await page.getByText(providerName).click();
// THEN: It should become active
// We check for the data-active attribute or visual indicator
// Based on test: closest('[data-active]')
const providerCard = page.getByText(providerName).locator('xpath=ancestor::*[contains(@data-active, "true") or contains(@data-active, "false")]').first();
await expect(providerCard).toHaveAttribute('data-active', 'true');
});
test('[P0] should enforce Key Storage Security (Obfuscation)', async ({ page }) => {
const secretKey = 'sk-secret-key-12345';
// Mock validation request
await page.route('/api/llm', async route => {
await route.fulfill({
status: 200,
body: JSON.stringify({ success: true, data: { text: 'Validation success' } })
});
});
// Open Modal
await page.getByRole('button', { name: /add new provider/i }).click();
// Fill Sensitive Data
await page.getByLabel('Provider Name').fill('Security Test');
await page.getByLabel('Base URL').fill('https://api.openai.com/v1');
await page.getByLabel('Model Name').fill('gpt-4');
await page.getByPlaceholder('sk-...').fill(secretKey);
await page.getByRole('button', { name: /save/i }).click();
await expect(page.getByRole('dialog')).toBeHidden();
// Verify key is NOT stored in plain text in localStorage
const settings = await page.evaluate(() => localStorage.getItem('test01-settings-storage'));
expect(settings).not.toBeNull();
expect(settings).not.toContain(secretKey); // Should be base64 encoded
});
test('[P2] should validate provider inputs', async ({ page }) => {
// WHEN: User clicks Add New Provider
await page.getByRole('button', { name: /add new provider/i }).click();
// WHEN: User tries to save empty form
await page.getByRole('button', { name: /save/i }).click();
// THEN: validation errors should appear (assuming HTML5 validation or UI errors)
// Since component uses Radix UI or similar, we might check for :invalid state or error messages
// For now, check that dialog is still open
await expect(page.getByRole('dialog')).toBeVisible();
});
});