Files
app/plans/02-magnitude-tests-comprehensive.md
Albert b96159ec02 docs: Add comprehensive implementation plans for all todo items
Created detailed markdown plans for all items in todo.md:

1. 01-playwright-scaffolding.md - Base Playwright infrastructure
2. 02-magnitude-tests-comprehensive.md - Complete test coverage
3. 03-stream-ai-to-deepgram-tts.md - TTS latency optimization
4. 04-fix-galaxy-node-clicking.md - Galaxy navigation bugs
5. 05-dark-light-mode-theme.md - Dark/light mode with dynamic favicons
6. 06-fix-double-border-desktop.md - UI polish
7. 07-delete-backup-files.md - Code cleanup
8. 08-ai-transition-to-edit.md - Intelligent node creation flow
9. 09-umap-minimum-nodes-analysis.md - Technical analysis

Each plan includes:
- Detailed problem analysis
- Proposed solutions with code examples
- Manual Playwright MCP testing strategy
- Magnitude test specifications
- Implementation steps
- Success criteria

Ready to implement in sequence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 21:07:42 +00:00

570 lines
18 KiB
Markdown

# Plan: Add Comprehensive Magnitude Tests for All Features
**Priority:** CRITICAL - Must be done second (after Playwright scaffolding)
**Dependencies:** 01-playwright-scaffolding.md
**Affects:** Code quality, regression prevention, production confidence
## Overview
Create comprehensive Magnitude test coverage for ALL existing and new features. Every user flow must be tested fully, including both happy paths and unhappy paths.
## Current State
- No Magnitude tests exist
- No test coverage for critical flows (auth, chat, node creation, galaxy)
- No regression testing
- Production deployments lack confidence
## Test Coverage Required
### 1. Authentication Flow Tests
#### `tests/magnitude/auth.mag.ts`
**Happy Paths:**
- User can log in with valid Bluesky credentials
- User can log out successfully
- User session persists across page refreshes
- User can access protected routes after authentication
**Unhappy Paths:**
- Login fails with invalid credentials
- Login fails with non-existent handle
- Unauthenticated user redirected from protected routes
- Session expiry handled gracefully
```typescript
import { test } from 'magnitude-test';
test('User can log in with valid credentials', async (agent) => {
await agent.open('http://localhost:3000');
await agent.check('Login page is visible');
await agent.act('Click "Log in with Bluesky" button')
.data({
handle: process.env.TEST_USER_HANDLE,
password: process.env.TEST_USER_PASSWORD
});
await agent.check('User is redirected to Bluesky OAuth');
await agent.check('User is redirected back to Ponderants');
await agent.check('User sees authenticated interface');
await agent.check('Profile menu is visible');
});
test('Login fails with invalid credentials', async (agent) => {
await agent.open('http://localhost:3000');
await agent.act('Click "Log in with Bluesky" button')
.data({
handle: 'invalid-user.bsky.social',
password: 'wrongpassword'
});
await agent.check('Error message is displayed');
await agent.check('User remains on login page');
});
test('User session persists across refresh', async (agent) => {
// First login
await agent.open('http://localhost:3000');
await agent.act('Log in with valid credentials');
await agent.check('User is authenticated');
// Refresh page
await agent.act('Refresh the page');
await agent.check('User is still authenticated');
await agent.check('Profile menu is still visible');
});
test('User can log out', async (agent) => {
await agent.open('http://localhost:3000');
await agent.act('Log in with valid credentials');
await agent.check('User is authenticated');
await agent.act('Click profile menu');
await agent.act('Click "Log out" button');
await agent.check('User is redirected to login page');
await agent.check('Session is cleared');
});
```
### 2. Chat Interface Tests
#### `tests/magnitude/chat.mag.ts`
**Happy Paths:**
- User can send text message and receive AI response
- User can use voice input and receive AI response
- User can see typing indicator while AI is thinking
- User can create a node from conversation
- User can select AI persona
- Chat history persists
**Unhappy Paths:**
- Empty message submission is prevented
- Voice input fails gracefully without microphone permission
- AI error displays user-friendly message
- Network error handled with retry option
```typescript
import { test } from 'magnitude-test';
test('User can send message and receive AI response', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Type "What is the meaning of life?" into chat input');
await agent.act('Press Enter to send');
await agent.check('Message appears in chat history');
await agent.check('Typing indicator is visible');
await agent.check('AI response appears after typing indicator disappears');
await agent.check('Response contains thoughtful content');
});
test('User can use voice input', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Click microphone button');
await agent.check('Recording indicator is visible');
await agent.act('Speak "Hello, how are you?"');
await agent.act('Click microphone button to stop recording');
await agent.check('Transcribed text appears in chat');
await agent.check('AI response is generated');
});
test('User can create node from conversation', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Have a conversation about "quantum computing"');
await agent.check('At least 3 messages exchanged');
await agent.act('Click "Create Node" button');
await agent.check('Node editor opens with AI-generated draft');
await agent.check('Title is populated');
await agent.check('Body contains conversation insights');
});
test('Empty message submission is prevented', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Press Enter without typing anything');
await agent.check('No message is sent');
await agent.check('Send button remains disabled');
});
test('AI error displays user-friendly message', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
// Simulate network error by blocking API calls
await agent.act('Send a message while API is blocked');
await agent.check('Error notification appears');
await agent.check('Error message is user-friendly');
await agent.check('Retry option is available');
});
```
### 3. Node Creation and Publishing Tests
#### `tests/magnitude/nodes.mag.ts`
**Happy Paths:**
- User can create a simple node (title + body)
- Node is published to Bluesky as a post
- Node is published to Bluesky as a thread (long content)
- Node appears in local cache (SurrealDB)
- Embedding is generated for node
- Node can link to other existing nodes
- AI suggests relevant node links
- Node appears in galaxy after creation
**Unhappy Paths:**
- Node creation fails without title
- Node creation fails without body
- Bluesky API error handled gracefully
- Embedding generation failure doesn't block node creation
- Link suggestion failure doesn't block node creation
```typescript
import { test } from 'magnitude-test';
test('User can create a simple node', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Click "New Node" button');
await agent.check('Node editor opens');
await agent.act('Type "My First Thought" into title field');
await agent.act('Type "This is my first ponderant about philosophy" into body field');
await agent.act('Click "Publish" button');
await agent.check('Success notification appears');
await agent.check('Node is published to Bluesky');
await agent.check('Node appears in cache');
});
test('Long node is published as thread', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
const longBody = 'This is a very long thought that exceeds 300 graphemes. '.repeat(20);
await agent.act('Create new node');
await agent.act(`Type "Long Thought" into title`);
await agent.act(`Type long content into body`).data({ body: longBody });
await agent.act('Click "Publish" button');
await agent.check('Node is published as Bluesky thread');
await agent.check('Thread contains multiple posts');
await agent.check('First post contains link to detail page');
await agent.check('Thread indicators show (2/3), (3/3), etc.');
});
test('Node with emojis handles grapheme counting correctly', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
const emojiContent = '🎉 '.repeat(100) + 'Hello world! 👋 ';
await agent.act('Create new node');
await agent.act('Type "Emoji Test" into title');
await agent.act('Type emoji content into body').data({ body: emojiContent });
await agent.act('Click "Publish" button');
await agent.check('Node is published without exceeding 300 grapheme limit');
await agent.check('Emojis are counted as 1 grapheme each');
});
test('Node creation fails without title', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Create new node');
await agent.act('Type "Some body content" into body field');
await agent.act('Click "Publish" button without entering title');
await agent.check('Validation error appears');
await agent.check('Error message says "Title is required"');
await agent.check('Node is not published');
});
test('Node links to existing nodes', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
// Create first node
await agent.act('Create node titled "Philosophy Basics"');
await agent.check('First node is published');
// Create second node that links to first
await agent.act('Create new node titled "Advanced Philosophy"');
await agent.check('AI suggests linking to "Philosophy Basics"');
await agent.act('Accept suggested link');
await agent.act('Publish node');
await agent.check('Node is published with link');
await agent.check('Graph relationship exists in database');
});
```
### 4. Galaxy Visualization Tests
#### `tests/magnitude/galaxy.mag.ts`
**Happy Paths:**
- Galaxy loads and displays nodes with 3D coordinates
- User can rotate/zoom/pan the galaxy
- User can click on a node to view details
- Node detail modal displays correct information
- User can navigate from modal to chat
- User can navigate from modal to node detail page
- Empty state shows when no nodes exist
- UMAP calculation triggers automatically after 3rd node
**Unhappy Paths:**
- Galaxy handles zero nodes gracefully
- Galaxy handles nodes without coordinates
- WebGL not available fallback
- Node click on non-existent node handled
- Modal close doesn't break navigation
```typescript
import { test } from 'magnitude-test';
test('Galaxy loads and displays nodes', async (agent) => {
await agent.open('http://localhost:3000/galaxy');
await agent.act('Log in if needed');
// Ensure user has at least 3 nodes with embeddings
await agent.check('Galaxy canvas is visible');
await agent.check('3D nodes are rendered');
await agent.check('Can rotate the galaxy by dragging');
await agent.check('Can zoom with scroll wheel');
});
test('User can click on node to view details', async (agent) => {
await agent.open('http://localhost:3000/galaxy');
await agent.act('Log in if needed');
await agent.check('At least one node is visible');
await agent.act('Click on a node sphere');
await agent.check('Node detail modal opens');
await agent.check('Modal shows node title');
await agent.check('Modal shows node body');
await agent.check('Modal shows Bluesky post link');
});
test('Node detail modal navigation works', async (agent) => {
await agent.open('http://localhost:3000/galaxy');
await agent.act('Log in if needed');
await agent.act('Click on a node');
await agent.check('Modal is open');
await agent.act('Click "View Full Detail" button');
await agent.check('Navigated to /galaxy/[node-id] page');
await agent.check('URL contains node ID');
await agent.check('Page shows full node content');
});
test('Empty galaxy shows helpful message', async (agent) => {
// Use a new test user with no nodes
await agent.open('http://localhost:3000/galaxy');
await agent.act('Log in with empty account');
await agent.check('Empty state message is visible');
await agent.check('Message says "No thoughts yet"');
await agent.check('Button to create first node is visible');
});
test('UMAP calculation triggers after 3rd node', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in with empty account');
// Create 3 nodes
await agent.act('Create node 1: "First Thought"');
await agent.act('Create node 2: "Second Thought"');
await agent.act('Create node 3: "Third Thought"');
await agent.check('UMAP calculation started automatically');
await agent.act('Navigate to /galaxy');
await agent.check('All 3 nodes have 3D coordinates');
await agent.check('Nodes are positioned in 3D space');
});
test('Galaxy handles WebGL unavailable', async (agent) => {
await agent.open('http://localhost:3000/galaxy');
await agent.act('Log in if needed');
await agent.act('Disable WebGL in browser');
await agent.check('Fallback message is displayed');
await agent.check('Message explains WebGL requirement');
await agent.check('Link to enable WebGL provided');
});
```
### 5. Voice Feature Tests
#### `tests/magnitude/voice.mag.ts`
**Happy Paths:**
- User can start voice recording
- User can stop voice recording
- Voice is transcribed to text
- Transcribed text is sent to AI
- TTS plays AI response
- User can toggle TTS on/off
**Unhappy Paths:**
- Microphone permission denied
- Deepgram API error
- Network error during transcription
- TTS fails gracefully
```typescript
import { test } from 'magnitude-test';
test('User can record and transcribe voice', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Click microphone button');
await agent.check('Recording indicator shows');
await agent.check('Microphone permission granted');
await agent.act('Speak "What is artificial intelligence?"');
await agent.wait(2000);
await agent.act('Click microphone button to stop');
await agent.check('Recording stops');
await agent.check('Text is transcribed');
await agent.check('Transcribed text appears in chat input');
});
test('Microphone permission denied handled gracefully', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Deny microphone permission');
await agent.act('Click microphone button');
await agent.check('Error notification appears');
await agent.check('Error explains permission is needed');
await agent.check('Link to browser settings provided');
});
test('TTS plays AI response', async (agent) => {
await agent.open('http://localhost:3000/chat');
await agent.act('Log in if needed');
await agent.act('Enable TTS in settings');
await agent.act('Send message "Hello"');
await agent.check('AI responds with text');
await agent.check('TTS audio plays automatically');
await agent.check('Audio player controls are visible');
});
```
### 6. Integration Tests
#### `tests/magnitude/integration.mag.ts`
**Full user journeys:**
- Complete flow: Login → Chat → Create Node → View in Galaxy
- Complete flow: Login → Galaxy → View Node → Edit Node
- Complete flow: Login → Create 3 Nodes → UMAP → Explore Galaxy
```typescript
import { test } from 'magnitude-test';
test('Complete user journey: Login to Galaxy visualization', async (agent) => {
// 1. Login
await agent.open('http://localhost:3000');
await agent.act('Log in with valid credentials');
await agent.check('User is authenticated');
// 2. Chat with AI
await agent.act('Navigate to /chat');
await agent.act('Send message "Tell me about philosophy"');
await agent.check('AI responds');
// 3. Create node from conversation
await agent.act('Click "Create Node" button');
await agent.check('Node editor opens with AI draft');
await agent.act('Review and edit node content');
await agent.act('Click "Publish"');
await agent.check('Node is published to Bluesky');
await agent.check('Success notification appears');
// 4. View in galaxy
await agent.act('Navigate to /galaxy');
await agent.check('Galaxy canvas loads');
await agent.check('New node appears in galaxy');
await agent.act('Click on the new node');
await agent.check('Node details modal opens');
await agent.check('Content matches published node');
});
test('User creates 3 nodes and explores galaxy', async (agent) => {
await agent.open('http://localhost:3000');
await agent.act('Log in with empty account');
// Create 3 nodes
for (let i = 1; i <= 3; i++) {
await agent.act(`Create node titled "Thought ${i}"`);
await agent.check(`Node ${i} published successfully`);
}
// Check UMAP triggered
await agent.check('UMAP calculation started');
await agent.wait(5000); // Wait for UMAP to complete
// Explore galaxy
await agent.act('Navigate to /galaxy');
await agent.check('All 3 nodes have coordinates');
await agent.check('Nodes are spatially distributed');
await agent.act('Rotate galaxy to different angle');
await agent.act('Zoom in on cluster of nodes');
await agent.act('Click on each node to view details');
await agent.check('All node details accessible');
});
```
## Implementation Steps
1. **Create test directory structure**
```bash
mkdir -p tests/magnitude
```
2. **Create test files in order**
- `tests/magnitude/auth.mag.ts` - Authentication tests
- `tests/magnitude/chat.mag.ts` - Chat interface tests
- `tests/magnitude/nodes.mag.ts` - Node creation tests
- `tests/magnitude/galaxy.mag.ts` - Galaxy visualization tests
- `tests/magnitude/voice.mag.ts` - Voice feature tests
- `tests/magnitude/integration.mag.ts` - Full user journeys
3. **Update package.json**
```json
{
"scripts": {
"test": "npx magnitude",
"test:watch": "npx magnitude --watch"
}
}
```
4. **Create test data helpers**
```typescript
// tests/magnitude/helpers/data.ts
export const createTestNode = (index: number) => ({
title: `Test Node ${index}`,
body: `This is test content for node ${index}. It discusses various topics.`
});
```
5. **Run tests and fix issues**
- Run each test file individually first
- Fix failing tests
- Run full suite
- Ensure all tests pass
## Success Criteria
- ✅ All authentication flows tested (happy + unhappy paths)
- ✅ All chat interactions tested (text, voice, AI response)
- ✅ All node creation scenarios tested (simple, thread, emojis, links)
- ✅ All galaxy visualization features tested (load, click, navigate)
- ✅ All voice features tested (record, transcribe, TTS)
- ✅ Integration tests cover complete user journeys
- ✅ All tests pass reliably
- ✅ Test suite runs in CI/CD
- ✅ New features cannot be merged without tests
## Files to Create
1. `tests/magnitude/auth.mag.ts`
2. `tests/magnitude/chat.mag.ts`
3. `tests/magnitude/nodes.mag.ts`
4. `tests/magnitude/galaxy.mag.ts`
5. `tests/magnitude/voice.mag.ts`
6. `tests/magnitude/integration.mag.ts`
7. `tests/magnitude/helpers/data.ts`
## Files to Update
1. `package.json` - Add test scripts
2. `.github/workflows/test.yml` - Add CI test workflow (if exists)