Initial commit: Brachnha Insight project setup

- Next.js 14+ with App Router and TypeScript
- Tailwind CSS and ShadCN UI styling
- Zustand state management
- Dexie.js for IndexedDB (local-first data)
- Auth.js v5 for authentication
- BMAD framework integration

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Max
2026-01-26 12:28:43 +07:00
commit 3fbbb1a93b
812 changed files with 150531 additions and 0 deletions

77
tests/e2e/chat.spec.ts Normal file
View File

@@ -0,0 +1,77 @@
import { test, expect } from '../support/fixtures';
test.describe('Chat Interface (Story 1.2)', () => {
test.beforeEach(async ({ page }) => {
// GIVEN: User is on the homepage
await page.goto('/');
});
test('[P0] should allow user to send a message', async ({ page }) => {
// GIVEN: Input field is visible
const input = page.getByTestId('chat-input');
const sendButton = page.getByTestId('send-button');
// WHEN: User types "Hello" and clicks send
await input.fill('Hello World');
await sendButton.click();
// THEN: Input should be cleared
await expect(input).toHaveValue('');
// THEN: Message should appear in the chat
// We look for the bubble with the specific text
// Note: The app might render markdown, so exact text match usually works
await expect(page.getByTestId('chat-bubble-user')).toContainText('Hello World');
});
test('[P0] should display AI typing indicator', async ({ page }) => {
// This test relies on the simulation delay added in the store
// WHEN: User sends a message
await page.getByTestId('chat-input').fill('Tell me a story');
await page.getByTestId('send-button').click();
// THEN: Typing indicator should appear immediately (before AI response)
const indicator = page.getByTestId('typing-indicator');
await expect(indicator).toBeVisible();
// THEN: Typing indicator should disappear eventually (after response)
// The delay is simulated as 1000-2000ms in the store
await expect(indicator).toBeHidden({ timeout: 5000 });
// THEN: AI response should appear
await expect(page.getByTestId('chat-bubble-ai')).toBeVisible();
});
test('[P0] should persist messages across reload', async ({ page }) => {
// GIVEN: User sends a message
const uniqueMessage = `Persistence Test ${Date.now()}`;
await page.getByTestId('chat-input').fill(uniqueMessage);
await page.getByTestId('send-button').click();
// Wait for message to appear
await expect(page.getByText(uniqueMessage)).toBeVisible();
// WHEN: Page is reloaded
await page.reload();
// THEN: Message should still be visible
await expect(page.getByText(uniqueMessage)).toBeVisible();
});
test('[P1] should adapt to mobile viewport', async ({ page }) => {
// GIVEN: Mobile viewport
await page.setViewportSize({ width: 375, height: 667 });
// WHEN: Page loads
await page.goto('/');
// THEN: Important elements are visible
await expect(page.getByTestId('chat-input')).toBeVisible();
await expect(page.getByTestId('send-button')).toBeVisible();
// Check elements fit within width (approximate check)
const inputBox = await page.getByTestId('chat-input').boundingBox();
expect(inputBox?.width).toBeLessThan(375); // Should have padding
});
});