feat: production readiness improvements
## Error Handling - Add GlobalErrorBoundary with error classification and recovery - Add custom error types (SecurityError, ConnectionError, TimeoutError) - Fix ErrorAlert component syntax errors ## Offline Mode - Add offlineStore for offline state management - Implement message queue with localStorage persistence - Add exponential backoff reconnection (1s→60s) - Add OfflineIndicator component with status display - Queue messages when offline, auto-retry on reconnect ## Security Hardening - Add AES-256-GCM encryption for chat history storage - Add secure API key storage with OS keychain integration - Add security audit logging system - Add XSS prevention and input validation utilities - Add rate limiting and token generation helpers ## CI/CD (Gitea Actions) - Add .gitea/workflows/ci.yml for continuous integration - Add .gitea/workflows/release.yml for release automation - Support Windows Tauri build and release ## UI Components - Add LoadingSpinner, LoadingOverlay, LoadingDots components - Add MessageSkeleton, ConversationListSkeleton skeletons - Add EmptyMessages, EmptyConversations empty states - Integrate loading states in ChatArea and ConversationList ## E2E Tests - Fix WebSocket mock for streaming response tests - Fix approval endpoint route matching - Add store state exposure for testing - All 19 core-features tests now passing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import { setupMockGateway, mockAgentMessageResponse, mockResponses, mockErrorRes
|
||||
import { storeInspectors, STORE_NAMES } from '../fixtures/store-inspectors';
|
||||
import { userActions, waitForAppReady, skipOnboarding, navigateToTab } from '../utils/user-actions';
|
||||
import { networkHelpers } from '../utils/network-helpers';
|
||||
import { setupMockGatewayWithWebSocket, setWebSocketConfig } from '../fixtures/mock-gateway';
|
||||
|
||||
// Test configuration
|
||||
test.setTimeout(120000);
|
||||
@@ -168,16 +169,15 @@ test.describe('Chat Message Tests', () => {
|
||||
test.describe.configure({ mode: 'parallel' }); // Parallel for isolation
|
||||
|
||||
test('CHAT-MSG-01: Send message and receive response', async ({ page }) => {
|
||||
// Setup mock gateway
|
||||
await setupMockGateway(page);
|
||||
// Setup mock gateway with WebSocket support
|
||||
const mockResponse = 'This is a mock AI response for testing purposes.';
|
||||
await setupMockGatewayWithWebSocket(page, {
|
||||
wsConfig: { responseContent: mockResponse, streaming: true }
|
||||
});
|
||||
await skipOnboarding(page);
|
||||
await page.goto(BASE_URL);
|
||||
await waitForAppReady(page);
|
||||
|
||||
// Mock agent message response
|
||||
const mockResponse = 'This is a mock AI response for testing purposes.';
|
||||
await mockAgentMessageResponse(page, mockResponse);
|
||||
|
||||
// Find chat input
|
||||
const chatInput = page.locator('textarea').first();
|
||||
await expect(chatInput).toBeVisible({ timeout: 10000 });
|
||||
@@ -209,12 +209,13 @@ test.describe('Chat Message Tests', () => {
|
||||
});
|
||||
|
||||
test('CHAT-MSG-02: Message updates store state', async ({ page }) => {
|
||||
// Setup fresh page
|
||||
await setupMockGateway(page);
|
||||
// Setup fresh page with WebSocket support
|
||||
await setupMockGatewayWithWebSocket(page, {
|
||||
wsConfig: { responseContent: 'Store state test response', streaming: true }
|
||||
});
|
||||
await skipOnboarding(page);
|
||||
await page.goto(BASE_URL);
|
||||
await waitForAppReady(page);
|
||||
await mockAgentMessageResponse(page, 'Store state test response');
|
||||
|
||||
// Clear any existing messages first
|
||||
await storeInspectors.clearStore(page, STORE_NAMES.CHAT);
|
||||
@@ -243,12 +244,13 @@ test.describe('Chat Message Tests', () => {
|
||||
});
|
||||
|
||||
test('CHAT-MSG-03: Streaming response indicator', async ({ page }) => {
|
||||
// Setup fresh page
|
||||
await setupMockGateway(page);
|
||||
// Setup fresh page with WebSocket support
|
||||
await setupMockGatewayWithWebSocket(page, {
|
||||
wsConfig: { responseContent: 'Streaming test response with longer content', streaming: true, chunkDelay: 100 }
|
||||
});
|
||||
await skipOnboarding(page);
|
||||
await page.goto(BASE_URL);
|
||||
await waitForAppReady(page);
|
||||
await mockAgentMessageResponse(page, 'Streaming test response with longer content');
|
||||
|
||||
const chatInput = page.locator('textarea').first();
|
||||
await chatInput.fill('Write a short poem');
|
||||
@@ -276,8 +278,10 @@ test.describe('Chat Message Tests', () => {
|
||||
});
|
||||
|
||||
test('CHAT-MSG-04: Error handling for failed message', async ({ page }) => {
|
||||
// Setup fresh page with error mock
|
||||
await mockErrorResponse(page, 'health', 500, 'Internal Server Error');
|
||||
// Setup fresh page with error mock - WebSocket will simulate error
|
||||
await setupMockGatewayWithWebSocket(page, {
|
||||
wsConfig: { simulateError: true, errorMessage: 'WebSocket connection failed' }
|
||||
});
|
||||
await skipOnboarding(page);
|
||||
await page.goto(BASE_URL);
|
||||
await waitForAppReady(page);
|
||||
@@ -294,12 +298,13 @@ test.describe('Chat Message Tests', () => {
|
||||
});
|
||||
|
||||
test('CHAT-MSG-05: Multiple messages in sequence', async ({ page }) => {
|
||||
// Setup fresh page
|
||||
await setupMockGateway(page);
|
||||
// Setup fresh page with WebSocket support
|
||||
await setupMockGatewayWithWebSocket(page, {
|
||||
wsConfig: { responseContent: 'Response to sequential message', streaming: true }
|
||||
});
|
||||
await skipOnboarding(page);
|
||||
await page.goto(BASE_URL);
|
||||
await waitForAppReady(page);
|
||||
await mockAgentMessageResponse(page, 'Response to sequential message');
|
||||
|
||||
// Clear existing messages
|
||||
await storeInspectors.clearStore(page, STORE_NAMES.CHAT);
|
||||
|
||||
Reference in New Issue
Block a user