diff --git a/test/feature/README.md b/test/feature/README.md
new file mode 100644
index 00000000..267cdb68
--- /dev/null
+++ b/test/feature/README.md
@@ -0,0 +1,158 @@
+# Feature Testing Examples
+
+## π Overview
+
+This folder contains integration test examples that focus on product features. These tests verify complete user scenarios rather than internal implementation details.
+
+## π― Why Feature Tests?
+
+Feature tests deliver higher ROI:
+
+### Feature Tests vs Unit Tests
+
+| Characteristic | Unit Tests | Feature Tests |
+|-----|---------|---------|
+| **Scope** | Single function/component | Full user scenario |
+| **Number of tests** | Many (one per function) | Few (one per feature) |
+| **Maintenance cost** | High (heavy churn during refactors) | Low (stable as long as behavior stays) |
+| **Execution speed** | Fast | Relatively slower |
+| **Bug discovery** | Internal logic issues | Real user experience issues |
+| **Refactor friendliness** | Low | High |
+
+### Example Comparison
+
+**Unit-test style** (needs multiple tests):
+```typescript
+// β Requires dedicated tests per function
+it('handleInputChange should update state', ...)
+it('validateMessage should reject empty input', ...)
+it('sendMessage should call the API', ...)
+it('clearInput should reset the field', ...)
+```
+
+**Feature-test style** (one test covers the flow):
+```typescript
+// β
One test verifies the full flow
+it('user can type and send a message', () => {
+ // User types text
+ // Clicks the send button
+ // Validates the message appears in the UI
+ // Confirms the input box is cleared
+})
+```
+
+## β
Testing Best Practices
+
+### 1. Assert user-facing behavior, not implementation details
+
+```typescript
+// β Wrong: assert internal state
+expect(component.state.messages).toHaveLength(1)
+
+// β
Correct: assert what the user sees
+expect(screen.getByText('Hello')).toBeInTheDocument()
+```
+
+### 2. Query only what a user can perceive
+
+```typescript
+// β Wrong: use test IDs
+screen.getByTestId('message-list')
+
+// β
Correct: use roles or visible text
+screen.getByRole('list')
+screen.getByText('Messages')
+```
+
+### 3. Cover the entire workflow
+
+```typescript
+// β Wrong: test each handler separately
+it('handleInput works', ...)
+it('handleSubmit works', ...)
+
+// β
Correct: cover the whole user scenario
+it('user can type and send a message', ...)
+```
+
+### 4. Use descriptive test names
+
+```typescript
+// β Wrong: vague names
+it('test 1', ...)
+it('works', ...)
+
+// β
Correct: describe expected behavior
+it('disables send button when the input is empty', ...)
+it('clears the input after sending a message', ...)
+```
+
+### 5. Avoid excessive mocking
+
+```typescript
+// β Wrong: mock everything
+vi.mock('./MessageList')
+vi.mock('./InputBox')
+vi.mock('./SendButton')
+
+// β
Correct: mock only external dependencies
+vi.mock('@/api/http') // API calls
+vi.mock('electron') // Electron APIs
+// Let other components run normally
+```
+
+## π‘ Test Strategy Guidance
+
+Consider this split:
+
+1. **Core features** (80% effort) β cover with feature tests
+ - User sign-in/sign-up
+ - Message sending
+ - File upload
+ - Task management
+
+2. **Utility helpers** (15% effort) β cover with unit tests
+ - Data formatting
+ - Validation helpers
+ - Calculation helpers
+
+3. **Edge cases** (5% effort) β add as needed
+ - Extreme inputs
+ - Concurrency scenarios
+ - Performance tests
+
+## β FAQ
+
+### Q: How do I debug a failing feature test?
+
+A:
+1. Inspect the test output to identify the failing assertion
+2. Call `screen.debug()` to print the current DOM
+3. Check whether you need `waitFor` for pending async work
+4. Gradually simplify the test until you isolate the minimal failing scenario
+
+### Q: What if the tests run too slowly?
+
+A:
+1. Use `npm run test:watch` to run only changed tests
+2. Temporarily focus with `it.only`
+3. Review any unnecessary `waitFor` timeouts
+4. Consider splitting very large tests into smaller ones
+
+### Q: How do I test flows that require authentication?
+
+A:
+1. Mock the logged-in state in `beforeEach`
+2. Stub `authStore` to return an authenticated user
+3. Or create a `setupLoggedInUser()` helper
+
+## π Takeaway
+
+Keep this principle in mind:
+
+> **Tests should exercise your app the way a user would**
+>
+> If a test must understand internal implementation, it is likely over-specified.
+>
+> Focus on what users can see and do.
+
diff --git a/test/feature/SendFirstMessage.feature.test.tsx b/test/feature/SendFirstMessage.feature.test.tsx
new file mode 100644
index 00000000..faabd342
--- /dev/null
+++ b/test/feature/SendFirstMessage.feature.test.tsx
@@ -0,0 +1,239 @@
+/**
+ * Feature Testing Sample Documentation
+ *
+ * ============================================================================
+ * What is Integration/Feature Testing?
+ * ============================================================================
+ *
+ * Feature tests focus on what users can see and do, rather than how the code is implemented.
+ *
+ * ## Feature Tests vs Unit Tests
+ *
+ * ### Unit Tests
+ * - Validate the internal logic of a single function or component
+ * - Example: ensure `calculateTotal(price, quantity)` returns the correct product
+ * - Pros: fast, isolated, precise failure signals
+ * - Cons: cannot guarantee the entire feature works correctly
+ *
+ * ### Feature Tests
+ * - Validate end-to-end user scenarios
+ * - Example: βuser enters price and quantity, clicks Calculate, and sees the totalβ
+ * - Pros: mirrors real usage, one test covers multiple code paths
+ * - Cons: comparatively slower, failures take longer to debug
+ *
+ * ## Why lean on feature tests?
+ *
+ * Feature tests deliver higher ROI:
+ *
+ * 1. **Fewer tests overall**: one feature test can replace several unit tests
+ * 2. **Refactor friendly**: internal changes rarely require test updates
+ * 3. **Higher confidence**: confirms real user journeys keep working
+ * 4. **Lower maintenance**: fewer tests means less upkeep
+ *
+ * ============================================================================
+ * Below is a feature-test example
+ * ============================================================================
+ */
+
+import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
+import { render, screen } from '@testing-library/react'
+import { BrowserRouter } from 'react-router-dom'
+import ChatBox from '../../../src/components/ChatBox/index'
+
+// Import necessary mocks
+import '../../../test/mocks/proxy.mock'
+import '../../../test/mocks/authStore.mock'
+import '../../../test/mocks/sse.mock'
+
+import { useProjectStore } from '../../../src/store/projectStore'
+
+// Mock Electron IPC
+(global as any).ipcRenderer = {
+ invoke: vi.fn((channel) => {
+ if (channel === 'get-system-language') return Promise.resolve('en')
+ if (channel === 'get-browser-port') return Promise.resolve(9222)
+ if (channel === 'get-env-path') return Promise.resolve('/path/to/env')
+ if (channel === 'mcp-list') return Promise.resolve({})
+ if (channel === 'get-file-list') return Promise.resolve([])
+ return Promise.resolve()
+ }),
+}
+
+// Mock window.electronAPI
+Object.defineProperty(window, 'electronAPI', {
+ value: {
+ uploadLog: vi.fn().mockResolvedValue(undefined),
+ selectFile: vi.fn().mockResolvedValue({ success: false }),
+ },
+ writable: true,
+})
+
+const TestWrapper = ({ children }: { children: React.ReactNode }) => (
+ {children}
+)
+
+describe('Feature test example: chat experience', () => {
+ /**
+ * beforeEach runs before every spec
+ * Purpose: reset application state so each test starts clean
+ */
+ beforeEach(() => {
+ vi.clearAllMocks()
+
+ // Reset the project store
+ const projectStore = useProjectStore.getState()
+ projectStore.getAllProjects().forEach(project => {
+ projectStore.removeProject(project.id)
+ })
+
+ // Seed an initial project (mirrors the state when the app boots)
+ const projectId = projectStore.createProject(
+ 'Feature Test Project',
+ 'Testing user message flow'
+ )
+ expect(projectId).toBeDefined()
+ })
+
+ afterEach(() => {
+ vi.clearAllMocks()
+ })
+
+ /**
+ * Test 1: verify the initial UI
+ *
+ * This spec ensures:
+ * - Users see the welcome copy on launch
+ * - The input field renders correctly
+ *
+ * Acts as a smoke test for the base layout.
+ */
+ it('displays the welcome screen and input', async () => {
+ // 1. Render the component (akin to opening the app)
+ render(
+
+
+
+ )
+
+ // 2. Assert the welcome text is visible
+ expect(screen.getByText(/layout.welcome-to-eigent/i)).toBeInTheDocument()
+ expect(screen.getByText(/layout.how-can-i-help-you/i)).toBeInTheDocument()
+
+ // 3. Confirm the textarea exists so the user can type
+ const textarea = screen.getByPlaceholderText('chat.ask-placeholder')
+ expect(textarea).toBeInTheDocument()
+ })
+
+ /**
+ * Test 2: validate the send button state
+ *
+ * This spec asserts:
+ * - When the input is empty, the send button stays disabled to block empty submissions
+ *
+ * Captures a critical UX behavior.
+ */
+ it('disables the send button when the input is empty', async () => {
+ // 1. Render the component
+ render(
+
+
+
+ )
+
+ // 2. Find the send button (via its icon)
+ const buttons = screen.getAllByRole('button')
+ const sendButton = buttons.find(btn =>
+ btn.querySelector('svg.lucide-arrow-right')
+ )
+
+ expect(sendButton).toBeInTheDocument()
+
+ // 3. Assert the button is disabled
+ // Note: we do not care why it is disabled (privacy gate, empty input, etc.);
+ // we only care that the observable behavior matches expectations.
+ expect(sendButton).toBeDisabled()
+ })
+
+ /**
+ * Test 3: verify legal links
+ *
+ * This spec ensures:
+ * - Privacy Policy and Terms of Use links render
+ * - Each link points to the correct URL
+ * - Each link opens in a new tab
+ */
+ it('shows Terms of Use and Privacy Policy links', async () => {
+ render(
+
+
+
+ )
+
+ // Locate the anchor elements
+ const termsLink = screen.getByRole('link', { name: /layout.terms-of-use/i })
+ const privacyLink = screen.getByRole('link', { name: /layout.privacy-policy/i })
+
+ // Verify link attributes
+ expect(termsLink).toBeInTheDocument()
+ expect(termsLink).toHaveAttribute('href', 'https://www.eigent.ai/terms-of-use')
+ expect(termsLink).toHaveAttribute('target', '_blank')
+
+ expect(privacyLink).toBeInTheDocument()
+ expect(privacyLink).toHaveAttribute('href', 'https://www.eigent.ai/privacy-policy')
+ expect(privacyLink).toHaveAttribute('target', '_blank')
+ })
+})
+
+/**
+ * ============================================================================
+ * Testing best-practice recap
+ * ============================================================================
+ *
+ * 1. **Exercise user behavior, not implementation details**
+ * β Wrong: expect(component.state.messages).toHaveLength(1)
+ * β
Correct: expect(screen.getByText('Hello')).toBeInTheDocument()
+ *
+ * 2. **Query elements the way users perceive them**
+ * β Wrong: screen.getByTestId('message-list')
+ * β
Correct: screen.getByText('Messages') or screen.getByRole('list')
+ *
+ * 3. **Assert full user flows**
+ * β Wrong: test handleInput, handleSubmit, addMessage separately
+ * β
Correct: test the flow βuser types a message and sends itβ
+ *
+ * 4. **Pick descriptive test names**
+ * β Wrong: it('test 1', ...)
+ * β
Correct: it('disables the send button when the input is empty', ...)
+ *
+ * 5. **Avoid over-mocking**
+ * - Mock only external dependencies (APIs, Electron APIs)
+ * - Keep application functions/components real
+ * - Let as much code run as possible
+ *
+ * ============================================================================
+ * How to extend these tests
+ * ============================================================================
+ *
+ * Suggested follow-up feature tests:
+ *
+ * 1. Full message-send journey
+ * - User types copy
+ * - Clicks the send button or presses Ctrl+Enter
+ * - Message appears in the chat history
+ * - Input resets to empty
+ *
+ * 2. File upload flow
+ * - User clicks the attachment button
+ * - Chooses a file
+ * - File appears in the attachment list
+ *
+ * 3. Error-handling path
+ * - Simulate an API error
+ * - Confirm the user-facing error surface renders
+ *
+ * 4. Task state transitions
+ * - Task moves from pending to running
+ * - UI reflects the correct state changes
+ *
+ * Remember: each spec should cover a complete user scenario.
+ */
diff --git a/test/mocks/proxy.mock.ts b/test/mocks/proxy.mock.ts
index 5a52e166..03950ee6 100644
--- a/test/mocks/proxy.mock.ts
+++ b/test/mocks/proxy.mock.ts
@@ -34,12 +34,13 @@ const mockImplementation = {
if (url.includes('/api/providers')) {
return Promise.resolve({ items: [] })
}
- // Mock privacy settings
+ // Mock privacy settings - all required fields must be true
if (url.includes('/api/user/privacy')) {
return Promise.resolve({
- dataCollection: true,
- analytics: true,
- marketing: true
+ take_screenshot: true,
+ access_local_software: true,
+ access_your_address: true,
+ password_storage: true
})
}
// Mock configs