diff --git a/src/tests/integration/auto-generation.test.ts b/src/tests/integration/auto-generation.test.ts deleted file mode 100644 index 57605c1..0000000 --- a/src/tests/integration/auto-generation.test.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import fs from 'fs/promises'; -import path from 'path'; -import { fileURLToPath } from 'url'; - -// Temporarily modify process.env type for testing -interface TestProcessEnv { - NODE_ENV?: string; - [key: string]: string | undefined; -} - -// Mock file watcher and processing pipeline -const mockFileWatcher = vi.fn(); -const mockMarkdownProcessor = vi.fn(); -const mockDatabaseSync = vi.fn(); - -describe('Auto-Generation Integration Test', () => { - const testBlogDir = path.join(process.cwd(), 'test-blog'); - const testPostPath = path.join(testBlogDir, 'test-post.md'); - - beforeEach(async () => { - // Create test directory - await fs.mkdir(testBlogDir, { recursive: true }); - vi.clearAllMocks(); - }); - - afterEach(async () => { - // Cleanup test directory - await fs.rm(testBlogDir, { recursive: true, force: true }); - }); - - describe('File Change Detection and Processing', () => { - it('should detect new markdown file and trigger processing', async () => { - // Simulate file watcher initialization - mockFileWatcher.mockImplementation((dir, callback) => { - // Return watcher instance - return { - on: vi.fn((event, handler) => { - if (event === 'add') { - setTimeout(() => handler(testPostPath), 100); - } - }), - close: vi.fn(), - }; - }); - - const watcher = mockFileWatcher(testBlogDir, async (filePath: string) => { - await mockMarkdownProcessor(filePath); - }); - - // Create new markdown file - const content = `--- -title: Test Post -author: Test Author -showToc: true ---- - -# Test Post - -This is a test post content.`; - - await fs.writeFile(testPostPath, content); - - // Wait for file watcher to trigger - await new Promise((resolve) => setTimeout(resolve, 200)); - - expect(mockFileWatcher).toHaveBeenCalledWith( - testBlogDir, - expect.any(Function) - ); - }); - - it('should process markdown changes within 1 second', async () => { - const startTime = Date.now(); - - mockMarkdownProcessor.mockResolvedValue({ - html: '

Test Post

', - metadata: { title: 'Test Post' }, - toc: [], - }); - - const content = `# Test Post\n\nContent`; - await fs.writeFile(testPostPath, content); - - // Simulate immediate processing - const result = await mockMarkdownProcessor(testPostPath); - const processingTime = Date.now() - startTime; - - expect(processingTime).toBeLessThan(1000); - expect(result).toHaveProperty('html'); - }); - - it('should debounce rapid file changes', async () => { - let callCount = 0; - const debouncedProcessor = vi.fn(() => { - callCount++; - }); - - // Simulate debounce logic - let timeout: NodeJS.Timeout; - const debounce = (fn: (...args: unknown[]) => unknown, delay: number) => { - return (...args: unknown[]) => { - clearTimeout(timeout); - timeout = setTimeout(() => fn(...args), delay); - }; - }; - - const processWithDebounce = debounce(debouncedProcessor, 500); - - // Rapid file changes - for (let i = 0; i < 5; i++) { - await fs.writeFile(testPostPath, `# Test Post\n\nVersion ${i}`); - processWithDebounce(testPostPath); - await new Promise((resolve) => setTimeout(resolve, 100)); - } - - // Wait for debounce to complete - await new Promise((resolve) => setTimeout(resolve, 600)); - - // Should only process once after debounce - expect(callCount).toBe(1); - }); - - it('should sync processed content to IndexedDB', async () => { - mockMarkdownProcessor.mockResolvedValue({ - html: '

Processed

', - metadata: { - title: 'Processed Post', - slug: 'processed-post', - }, - }); - - mockDatabaseSync.mockResolvedValue({ - success: true, - id: 'post-123', - }); - - // Process and sync - const processed = await mockMarkdownProcessor(testPostPath); - const synced = await mockDatabaseSync(processed); - - expect(synced.success).toBe(true); - expect(synced).toHaveProperty('id'); - }); - - it('should handle file deletion', async () => { - // Create file first - await fs.writeFile(testPostPath, '# Post'); - - // Mock deletion handler - const onDelete = vi.fn(); - - // Delete file - await fs.unlink(testPostPath); - - // Simulate watcher detecting deletion - onDelete(testPostPath); - - expect(onDelete).toHaveBeenCalledWith(testPostPath); - }); - - it('should ignore non-markdown files', async () => { - const nonMdPath = path.join(testBlogDir, 'image.png'); - - const shouldProcess = (filePath: string) => { - return path.extname(filePath) === '.md'; - }; - - expect(shouldProcess(nonMdPath)).toBe(false); - expect(shouldProcess(testPostPath)).toBe(true); - }); - - it('should handle errors gracefully', async () => { - mockMarkdownProcessor.mockRejectedValue(new Error('Processing failed')); - - const errorHandler = vi.fn(); - - try { - await mockMarkdownProcessor('invalid.md'); - } catch (error) { - errorHandler(error); - } - - expect(errorHandler).toHaveBeenCalled(); - }); - - it('should maintain metadata during processing', async () => { - const originalMetadata = { - title: 'Original Title', - author: 'Original Author', - tags: ['test', 'blog'], - showToc: true, - }; - - mockMarkdownProcessor.mockResolvedValue({ - html: '

Content

', - metadata: originalMetadata, - preserved: true, - }); - - const result = await mockMarkdownProcessor(testPostPath); - - expect(result.metadata).toEqual(originalMetadata); - expect(result.metadata.showToc).toBe(true); - }); - }); - - describe('Hot Reload in Development', () => { - it('should trigger hot reload on content change', async () => { - const hotReloadTrigger = vi.fn(); - - // Simulate development environment - const oldEnv = process.env.NODE_ENV; - (process.env as TestProcessEnv).NODE_ENV = 'development'; - - // File change triggers hot reload - await fs.writeFile(testPostPath, '# Updated Content'); - hotReloadTrigger('change', testPostPath); - - expect(hotReloadTrigger).toHaveBeenCalledWith('change', testPostPath); - - // Cleanup - (process.env as TestProcessEnv).NODE_ENV = oldEnv; - }); - - it('should not trigger hot reload in production', async () => { - const hotReloadTrigger = vi.fn(); - - // Simulate production environment - const oldEnv = process.env.NODE_ENV; - (process.env as TestProcessEnv).NODE_ENV = 'production'; - - const shouldHotReload = () => { - return process.env.NODE_ENV === 'development'; - }; - - expect(shouldHotReload()).toBe(false); - - // Cleanup - (process.env as TestProcessEnv).NODE_ENV = oldEnv; - }); - }); - - describe('Batch Processing', () => { - it('should handle multiple file changes efficiently', async () => { - const files = ['post1.md', 'post2.md', 'post3.md']; - - const batchProcessor = vi.fn(async (filePaths: string[]) => { - return filePaths.map((fp) => ({ - path: fp, - processed: true, - })); - }); - - const results = await batchProcessor(files); - - expect(results).toHaveLength(3); - expect(results.every((r) => r.processed)).toBe(true); - }); - }); -}); diff --git a/src/tests/integration/enhanced-processing.test.ts b/src/tests/integration/enhanced-processing.test.ts deleted file mode 100644 index c12c6ce..0000000 --- a/src/tests/integration/enhanced-processing.test.ts +++ /dev/null @@ -1,637 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; - -// Type definitions for enhanced processing -interface RemarkResult { - ast?: { type: string; children: unknown[] }; - processed: boolean; - content?: string; - plugins?: PluginConfig[]; -} - -interface RehypeResult { - html: string; - processed?: boolean; - sanitized?: boolean; - removed?: string[]; -} - -interface PluginConfig { - name: string; - enabled: boolean; -} - -interface SyntaxHighlightResult { - html: string; - language: string; - highlighted: boolean; - supported?: boolean; - fallback?: string; -} - -interface TocEntry { - level: number; - text: string; - id: string; - children?: TocEntry[]; -} - -interface TocResult { - toc: TocEntry[] | null; - html?: string; - skipped?: boolean; - reason?: string; - maxDepth?: number; -} - -interface TocOptions { - showToc: boolean; - maxDepth?: number; -} - -interface ValidationError { - path: string; - message: string; -} - -interface ValidationResult { - valid: boolean; - data?: unknown; - errors: ValidationError[]; - transformed?: boolean; -} - -interface FileInfo { - path: string; - modified: string; - hash: string; -} - -interface PostInfo { - id: string; - content: string; -} - -interface CacheResult { - html?: string; - processed?: boolean; - cached: boolean; - hash?: string; - cacheHit?: boolean; -} - -interface ProcessingResult { - post: string; - success: boolean; - error?: string; - processed?: boolean; - fallback?: string; -} - -// Mock enhanced processing services -const mockRemarkProcessor = vi.fn(); -const mockRehypeProcessor = vi.fn(); -const mockSyntaxHighlighter = vi.fn(); -const mockTocGenerator = vi.fn(); -const mockZodValidator = vi.fn(); -const mockCacheManager = vi.fn(); - -describe('Enhanced Processing Integration Test', () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - describe('Remark/Rehype Processing Pipeline', () => { - it('should process markdown through remark/rehype pipeline', async () => { - const markdown = `# Title - -This is a **bold** paragraph with *italic* text. - -## Section 1 - -Content with [link](https://example.com). - -\`\`\`javascript -const hello = () => { - console.log('Hello World'); -}; -\`\`\``; - - mockRemarkProcessor.mockResolvedValue({ - ast: { type: 'root', children: [] }, - processed: true, - }); - - mockRehypeProcessor.mockResolvedValue({ - html: '

Title

This is a bold paragraph...

', - processed: true, - }); - - const remarkResult = await mockRemarkProcessor(markdown); - const rehypeResult = await mockRehypeProcessor(remarkResult); - - expect(remarkResult.processed).toBe(true); - expect(rehypeResult.processed).toBe(true); - expect(rehypeResult.html).toContain('

'); - }); - - it('should apply custom remark plugins', async () => { - const plugins = [ - { name: 'remark-gfm', enabled: true }, - { name: 'remark-emoji', enabled: true }, - { name: 'remark-footnotes', enabled: true }, - ]; - - mockRemarkProcessor.mockImplementation( - async ( - content: string, - opts?: { plugins?: PluginConfig[] } - ): Promise => { - return { - processed: true, - content: content.replace(':smile:', '😊'), - plugins: opts?.plugins || [], - }; - } - ); - - const result = await mockRemarkProcessor(':smile:', { plugins }); - - expect(result.content).toBe('😊'); - expect(result.plugins).toEqual(plugins); - }); - - it('should sanitize HTML output', async () => { - const unsafeMarkdown = ` - -# Safe Content - -`; - - mockRehypeProcessor.mockResolvedValue({ - html: '

Safe Content

', - sanitized: true, - removed: ['