import { describe, expect, it } from 'vitest' import { getMarkdown, parseMarkdownToStructure } from '../packages/markdown-parser/src/index' /** * Integration tests for multiple plugins working together. * * These tests verify that: * 1. fixHtmlInline and fixIndentedCodeBlock work correctly together * 2. fixHtmlInline and fixLinkTokens work correctly together * 3. All plugins maintain correct behavior in streaming scenarios */ describe('integration tests for multiple plugins', () => { const md = getMarkdown() describe('fixHtmlInline + fixIndentedCodeBlock', () => { it('should handle custom tags with indented content correctly', () => { // This test combines custom tag handling with indented code block conversion const markdown = ` This is indented text that should not be a code block This is also indented text ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // First node should be html_block with custom tag expect(result[0].type).toBe('html_block') expect((result[0] as any).tag).toBe('custom') // Second node should be paragraph (indented text converted to paragraph) expect(result[1].type).toBe('paragraph') }) it('should handle HTML entities in indented lines within custom tags', () => { const markdown = ` Processing... ✖ Error occurred ✔ Success message ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // First node: html_block with thinking tag expect(result[0].type).toBe('html_block') expect((result[0] as any).tag).toBe('thinking') // Second node: paragraph (indented HTML entity converted to paragraph) expect(result[1].type).toBe('paragraph') expect(result[1].children?.[0].type).toBe('text') expect(result[1].children?.[0].content).toContain('✔') }) it('should handle mixed content with code and paragraphs', () => { const markdown = ` const x = 1 const y = 2 This is just text ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // First node: html_block with step tag expect(result[0].type).toBe('html_block') expect((result[0] as any).tag).toBe('step') // Check we have the expected nodes expect(result.length).toBeGreaterThanOrEqual(2) }) }) describe('fixHtmlInline + fixLinkTokens', () => { it('should handle links within custom tags', () => { const markdown = ` Check out https://example.com for more info See also [link](https://example.com/page) ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // First node: html_block with note tag expect(result[0].type).toBe('html_block') expect((result[0] as any).tag).toBe('note') // Second node should be paragraph with link expect(result[1].type).toBe('paragraph') }) it('should handle autolinks and custom tags together', () => { const markdown = ` Visit for details Visit ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // First node: html_block with info tag expect(result[0].type).toBe('html_block') // Second node - might be code_block because it starts with "Visit <" // which could be interpreted as a code pattern expect(result[1]).toBeDefined() }) }) describe('streaming scenarios with multiple plugins', () => { it('should handle incomplete custom tag followed by indented content', () => { // Simulate streaming: custom tag without closing const markdown = `This is streaming content` const result = parseMarkdownToStructure(markdown, md, { final: false }) // Should create a node (exact structure depends on plugin handling) expect(result.length).toBeGreaterThan(0) }) it('should handle complete custom tag with trailing indented content', () => { const markdown = ` Important note This is indented text with code keyword const code = here ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // First node: html_block with note tag expect(result[0].type).toBe('html_block') // Check that we have the expected number of nodes // The "code" keyword might make it a code_block expect(result.length).toBeGreaterThanOrEqual(2) }) it('should handle nested custom tags with HTML entities', () => { const markdown = ` ✖ Error ✔ Success ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // First node: html_block with outer tag expect(result[0].type).toBe('html_block') expect((result[0] as any).tag).toBe('outer') // Second node: paragraph (indented HTML entity) expect(result[1].type).toBe('paragraph') expect(result[1].children?.[0].content).toContain('✔') }) }) describe('complex real-world scenarios', () => { it('should handle AI streaming output with multiple custom tags', () => { const markdown = ` uid:b238ea9cb1a44ae489247aed335a0248 已收到您关于xxx的组织机构画像的任务请求,我将按照以下步骤执行该任务: - 匹配并确认目标组织机构 - 构建组织机构画像管理数据 # 匹配信息和确认组织机构 ## 深度思考 - 好的,我现在需要处理用户的输入:"生成x的织机构画像"。 ✖ 该机构没有关联机构数据匹配,无法进行机构画像生成。 ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // Verify structure expect(result.length).toBeGreaterThanOrEqual(4) // First node: paragraph containing html_block expect(result[0].type).toBe('paragraph') expect(result[0].children?.[0].type).toBe('html_block') // Second node: html_block expect(result[1].type).toBe('html_block') expect((result[1] as any).tag).toBe('taskplan') // Third node: html_block expect(result[2].type).toBe('html_block') expect((result[2] as any).tag).toBe('analysissteps') // Fourth node: paragraph (not code_block!) expect(result[3].type).toBe('paragraph') expect(result[3].children?.[0].type).toBe('text') expect(result[3].children?.[0].content).toContain('✖') }) it('should handle markdown content mixed with custom tags', () => { const markdown = ` # Heading This is custom content ## Subheading Indented content here Regular paragraph with **bold** text. ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // Verify heading is parsed correctly expect(result[0].type).toBe('heading') // Custom tag should be html_block const customNode = result.find((n: any) => n.tag === 'custom') expect(customNode).toBeDefined() expect(customNode.type).toBe('html_block') // Regular paragraph should exist expect(result.some((n: any) => n.type === 'paragraph')).toBe(true) }) it('should handle code fences alongside custom tags', () => { const markdown = ` Processing data... \`\`\`javascript const x = 1; console.log(x); \`\`\` This is indented text const y = 2; ` const result = parseMarkdownToStructure(markdown, md, { final: true }) // Custom tag expect(result[0].type).toBe('html_block') expect((result[0] as any).tag).toBe('thinking') // The code fence and indented content should be processed // We just verify we have multiple nodes expect(result.length).toBeGreaterThan(1) }) }) })