import { describe, it, expect } from 'vitest';
import { formatNoteAsMarkdown, generateFilename } from '../noteFormatter.js';
import type { SessionNote } from '../../types/session.js';
describe('noteFormatter', () => {
describe('generateFilename', () => {
it('should generate filename with date, time, and project', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:45.000Z',
projectName: 'My Test Project',
};
const filename = generateFilename(note);
expect(filename).toMatch(/^2025-01-15_\d{2}-\d{2}-\d{2}_my-test-project\.md$/);
});
it('should include topic in filename when provided', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:45.000Z',
projectName: 'project',
topic: 'Auth Feature',
};
const filename = generateFilename(note);
expect(filename).toContain('-auth-feature');
expect(filename).toMatch(/\.md$/);
});
it('should handle missing project name', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:45.000Z',
};
const filename = generateFilename(note);
expect(filename).toContain('session');
expect(filename).toMatch(/^2025-01-15_\d{2}-\d{2}-\d{2}_session\.md$/);
});
it('should sanitize special characters in project name', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:45.000Z',
projectName: 'My @Awesome# Project!',
};
const filename = generateFilename(note);
expect(filename).toContain('my-awesome-project');
expect(filename).not.toMatch(/[@#!]/);
});
it('should sanitize special characters in topic', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:45.000Z',
projectName: 'project',
topic: 'Fix: Bug #123',
};
const filename = generateFilename(note);
expect(filename).toContain('-fix-bug-123');
});
it('should remove leading/trailing dashes', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:45.000Z',
projectName: '---project---',
};
const filename = generateFilename(note);
expect(filename).toContain('_project');
expect(filename).not.toMatch(/_-+-/);
});
});
describe('formatNoteAsMarkdown', () => {
it('should format basic note structure', () => {
const note: SessionNote = {
summary: 'Implemented authentication',
timestamp: '2025-01-15T10:30:00.000Z',
projectName: 'web-app',
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('# web-app');
expect(markdown).toContain('## Summary');
expect(markdown).toContain('Implemented authentication');
});
it('should include topic as h2 when provided', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
projectName: 'project',
topic: 'User Authentication',
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('## User Authentication');
});
it('should format metadata section', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
workingDirectory: '/home/user/project',
tags: ['auth', 'security'],
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('**Working Directory**: `/home/user/project`');
expect(markdown).toContain('**Tags**: #auth, #security');
});
it('should include pattern and complexity indicators', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
analysis: {
pattern: 'bug-fix',
patternConfidence: 0.9,
complexity: 'complex',
keyFiles: [],
fileCount: 75,
},
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('**Pattern**: 🐛 Bug Fix');
expect(markdown).toContain('**Complexity**: 🔴 Complex');
});
it('should format commands section', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
commands: [
{
command: 'npm install',
description: 'Install dependencies',
},
{
command: 'npm test',
description: 'Run tests',
output: 'All tests passed',
},
],
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('## Commands Executed');
expect(markdown).toContain('### Install dependencies');
expect(markdown).toContain('```bash\nnpm install\n```');
expect(markdown).toContain('### Run tests');
expect(markdown).toContain('<details>');
expect(markdown).toContain('<summary>Output</summary>');
expect(markdown).toContain('All tests passed');
});
it('should format file changes by type', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
fileChanges: [
{ path: 'src/new.ts', type: 'created', description: 'New module' },
{ path: 'src/existing.ts', type: 'modified', description: 'Updated logic' },
{ path: 'src/old.ts', type: 'deleted', description: 'Removed deprecated code' },
],
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('## File Changes');
expect(markdown).toContain('### Created Files');
expect(markdown).toContain('- `src/new.ts` - New module');
expect(markdown).toContain('### Modified Files');
expect(markdown).toContain('- `src/existing.ts` - Updated logic');
expect(markdown).toContain('### Deleted Files');
expect(markdown).toContain('- `src/old.ts` - Removed deprecated code');
});
it('should include diff in modified files', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
fileChanges: [
{
path: 'src/file.ts',
type: 'modified',
diff: '+ added line\n- removed line',
},
],
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('<details>');
expect(markdown).toContain('<summary>Changes</summary>');
expect(markdown).toContain('```diff');
expect(markdown).toContain('+ added line');
});
it('should format code snippets', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
codeSnippets: [
{
language: 'typescript',
code: 'const x = 42;',
description: 'Variable declaration',
filePath: 'src/test.ts',
},
{
language: 'python',
code: 'print("hello")',
},
],
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('## Code Snippets');
expect(markdown).toContain('### Variable declaration');
expect(markdown).toContain('*From: `src/test.ts`*');
expect(markdown).toContain('```typescript');
expect(markdown).toContain('const x = 42;');
expect(markdown).toContain('```python');
expect(markdown).toContain('print("hello")');
});
it('should handle empty sections gracefully', () => {
const note: SessionNote = {
summary: 'Minimal note',
timestamp: '2025-01-15T10:30:00.000Z',
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).not.toContain('## Commands Executed');
expect(markdown).not.toContain('## File Changes');
expect(markdown).not.toContain('## Code Snippets');
expect(markdown).toContain('## Summary');
expect(markdown).toContain('Minimal note');
});
it('should use default title when no project name', () => {
const note: SessionNote = {
summary: 'Test',
timestamp: '2025-01-15T10:30:00.000Z',
};
const markdown = formatNoteAsMarkdown(note);
expect(markdown).toContain('# Claude Code Session');
});
});
});