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

18 KiB

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
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
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
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
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
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
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

    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

    {
      "scripts": {
        "test": "npx magnitude",
        "test:watch": "npx magnitude --watch"
      }
    }
    
  4. Create test data helpers

    // 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)