Spaces:
Running
Table of Contents Feature - Testing Guide
This guide provides instructions for testing the Table of Contents (TOC) feature implementation.
Overview
The TOC feature (User Story 5, Tasks T037-T052) adds a collapsible sidebar panel that displays document headings and enables quick navigation.
Features Implemented
Core Functionality
- Heading Extraction: Automatically extracts H1, H2, and H3 headings from rendered markdown
- Unique ID Generation: Uses slugify algorithm with duplicate handling (-2, -3, etc.)
- Smooth Scrolling: Respects
prefers-reduced-motionmedia query - State Persistence: Panel open/closed state saved to localStorage (
toc-panel-open) - Hierarchical Display: Headings indented by level (H1=0px, H2=12px, H3=24px)
- Empty State: Shows helpful message when no headings found
UI Components
- TOC Button: Added to NoteViewer toolbar (List icon + "TOC" text)
- Resizable Panel: Right sidebar with adjustable width (15-40% of viewer)
- Click Navigation: Click any heading to scroll to that section
Manual Testing Checklist
T051: Panel State Persistence
Goal: Verify TOC panel state persists after reload
- Open the application and view any note
- Click the "TOC" button to open the panel
- Verify the panel opens on the right side
- Refresh the browser (F5 or Cmd+R)
- Expected: TOC panel should still be open after reload
- Click "TOC" to close the panel
- Refresh the browser again
- Expected: TOC panel should remain closed after reload
localStorage Check:
- Open DevTools > Application > Local Storage
- Look for key
toc-panel-open - Value should be
truewhen open,falsewhen closed
T052: Performance Test (<500ms for 50 headings)
Goal: Verify TOC generation completes in <500ms for 50 headings
Test Document Creation: Create a test note with 50 headings (mix of H1, H2, H3):
# Heading 1
## Subheading 1.1
### Detail 1.1.1
### Detail 1.1.2
## Subheading 1.2
# Heading 2
## Subheading 2.1
...
(repeat pattern to reach 50 headings)
Performance Measurement:
- Open DevTools > Performance tab
- Start recording
- Navigate to the test note with 50 headings
- Wait for note to fully render
- Open the TOC panel
- Stop recording
- Expected: Total time from note load to TOC display < 500ms
Alternative - Console Timing:
Add temporary timing code to useTableOfContents.ts:
const extractHeadings = useCallback(() => {
const start = performance.now();
// ... existing code ...
const duration = performance.now() - start;
console.log(`TOC extraction took ${duration.toFixed(2)}ms for ${extracted.length} headings`);
}, []);
Additional Tests
Heading Navigation
- Create a note with multiple headings
- Open TOC panel
- Click various headings in the TOC
- Expected: Page smoothly scrolls to clicked heading
Duplicate Heading Handling
- Create a note with duplicate heading text:
# Introduction ## Introduction ### Introduction - Open TOC panel
- Inspect heading IDs (DevTools > Elements)
- Expected: IDs should be
introduction,introduction-2,introduction-3
Reduced Motion Support
- Enable reduced motion in OS settings:
- macOS: System Preferences > Accessibility > Display > Reduce motion
- Windows: Settings > Ease of Access > Display > Show animations
- Linux: Varies by desktop environment
- Open TOC and click a heading
- Expected: Scroll should be instant (no smooth animation)
Empty State
- Create a note with no headings (only body text)
- Open TOC panel
- Expected: Should show "No headings found" message
Panel Resize
- Open TOC panel
- Drag the resize handle between content and TOC
- Expected: Panel width adjusts smoothly between 15-40% of viewer
File Locations
Created Files
/home/wolfe/Projects/Document-MCP/frontend/src/hooks/useTableOfContents.ts- TOC state management hook/home/wolfe/Projects/Document-MCP/frontend/src/components/TableOfContents.tsx- TOC UI component
Modified Files
/home/wolfe/Projects/Document-MCP/frontend/src/lib/markdown.tsx- Added heading ID generation/home/wolfe/Projects/Document-MCP/frontend/src/components/NoteViewer.tsx- Integrated TOC panel
Technical Implementation Details
Heading Extraction Algorithm
The TOC uses a MutationObserver to detect when markdown is rendered:
- Observer watches
.prosecontainer for DOM changes - On mutation, queries for
h1, h2, h3elements - Extracts text content and existing IDs
- Builds heading array with
{ id, text, level }
Slugify Algorithm
Converts heading text to valid HTML IDs:
text.toLowerCase()
.replace(/\s+/g, '-') // spaces to hyphens
.replace(/[^\w-]/g, '') // remove special chars
Duplicate handling via global cache that increments on collision.
Scroll Behavior
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
element.scrollIntoView({
behavior: prefersReducedMotion ? 'auto' : 'smooth',
block: 'start'
});
Known Limitations
- Only H1-H3 supported: H4-H6 headings are not extracted (as per spec)
- Cache reset per note: Slug cache resets when switching notes to avoid ID conflicts
- Simple text extraction: Complex heading content (links, code) may not render perfectly in TOC
Troubleshooting
TOC Panel Not Showing
- Check browser console for errors
- Verify ResizablePanel components are imported correctly
- Ensure
toc-panel-openlocalStorage value is set
Headings Not Appearing
- Verify markdown is rendering (check for
.prosecontainer) - Check if headings have IDs in DevTools
- Look for MutationObserver errors in console
Scroll Not Working
- Verify heading IDs match TOC
idvalues - Check for JavaScript errors when clicking
- Ensure
scrollToHeadingfunction is connected
Success Criteria
All tasks (T037-T052) are complete when:
- β Hook and component files created and functional
- β Headings render with unique IDs
- β TOC panel toggles via toolbar button
- β Panel state persists across reloads
- β Clicking headings scrolls smoothly
- β Performance < 500ms for 50 headings
- β Empty state displays when no headings
- β Hierarchical indentation works correctly