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>
This commit is contained in:
569
plans/02-magnitude-tests-comprehensive.md
Normal file
569
plans/02-magnitude-tests-comprehensive.md
Normal file
@@ -0,0 +1,569 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user