snapshot of https://github.com/ueberdosis/tiptap.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
Verify / Install node dependencies (push) Failing after 2s
Verify / Build packages (push) Has been skipped
Verify / Check linting & formatting (push) Has been skipped
Verify / Run unit tests (push) Has been skipped
Verify / Run e2e tests (shard 1/4) (push) Has been skipped
Verify / Run e2e tests (shard 2/4) (push) Has been skipped
Verify / Run e2e tests (shard 3/4) (push) Has been skipped
Verify / Run e2e tests (shard 4/4) (push) Has been skipped
Publish / Resolve publish config (push) Failing after 2s
Publish / Send notification to Slack (push) Has been skipped
Publish / Send failure notification to Slack (push) Failing after 8s
Verify / Merge e2e reports (push) Has been skipped
Publish / Build (push) Has been skipped
Publish / Bump Versions OR Release to Registry (push) Has been skipped
Some checks failed
Verify / Install node dependencies (push) Failing after 2s
Verify / Build packages (push) Has been skipped
Verify / Check linting & formatting (push) Has been skipped
Verify / Run unit tests (push) Has been skipped
Verify / Run e2e tests (shard 1/4) (push) Has been skipped
Verify / Run e2e tests (shard 2/4) (push) Has been skipped
Verify / Run e2e tests (shard 3/4) (push) Has been skipped
Verify / Run e2e tests (shard 4/4) (push) Has been skipped
Publish / Resolve publish config (push) Failing after 2s
Publish / Send notification to Slack (push) Has been skipped
Publish / Send failure notification to Slack (push) Failing after 8s
Verify / Merge e2e reports (push) Has been skipped
Publish / Build (push) Has been skipped
Publish / Bump Versions OR Release to Registry (push) Has been skipped
This commit is contained in:
127
packages/markdown/tests/integration/mixed-html.test.ts
Normal file
127
packages/markdown/tests/integration/mixed-html.test.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
|
||||
import { Document } from '@tiptap/extension-document'
|
||||
import { HardBreak } from '@tiptap/extension-hard-break'
|
||||
import { Heading } from '@tiptap/extension-heading'
|
||||
import { Italic } from '@tiptap/extension-italic'
|
||||
import { Paragraph } from '@tiptap/extension-paragraph'
|
||||
import { Text } from '@tiptap/extension-text'
|
||||
import { MarkdownManager } from '@tiptap/markdown'
|
||||
import { beforeEach, describe, expect, it } from 'vite-plus/test'
|
||||
|
||||
describe('MarkdownManager Mixed Markdown + HTML', () => {
|
||||
let manager: MarkdownManager
|
||||
const basicExtensions = [Document, Paragraph, Text, Heading, Italic, HardBreak]
|
||||
|
||||
beforeEach(() => {
|
||||
manager = new MarkdownManager({ extensions: basicExtensions })
|
||||
})
|
||||
|
||||
it('parses heading with inline HTML <em> as italic', () => {
|
||||
const md = '## hello <em>world</em>'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
expect(doc.type).toBe('doc')
|
||||
expect(Array.isArray(doc.content)).toBe(true)
|
||||
const heading = doc.content![0]
|
||||
expect(heading.type).toBe('heading')
|
||||
// Find the text node that contains 'world'
|
||||
const textNodes = heading.content!.flatMap((n: any) =>
|
||||
n.type === 'text' ? [n] : n.content || [],
|
||||
)
|
||||
const worldNode = textNodes.find((n: any) => n.text && n.text.includes('world'))
|
||||
// Use a function-call assertion to avoid the "no-unused-expressions" lint error
|
||||
expect(worldNode).not.toBe(undefined)
|
||||
// The italic mark should be present
|
||||
expect(Array.isArray(worldNode!.marks)).toBe(true)
|
||||
const hasItalic = worldNode!.marks.some((m: any) => m.type === 'italic')
|
||||
expect(hasItalic).toBe(true)
|
||||
})
|
||||
|
||||
it('parses standalone inline HTML <em>world</em> as italic', () => {
|
||||
const md = '<em>world</em>'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
expect(doc.type).toBe('doc')
|
||||
// Inline HTML typically produces a paragraph wrapper
|
||||
const paragraph = doc.content![0]
|
||||
expect(paragraph.type).toBe('paragraph')
|
||||
const textNode = paragraph.content![0]
|
||||
expect(textNode.text).toBe('world')
|
||||
expect(Array.isArray(textNode.marks)).toBe(true)
|
||||
const hasItalic = (textNode.marks || []).some((m: any) => m.type === 'italic')
|
||||
expect(hasItalic).toBe(true)
|
||||
})
|
||||
|
||||
it('parses markdown italic next to HTML italic correctly', () => {
|
||||
const md = '*a* <em>b</em> *c*'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
expect(doc.type).toBe('doc')
|
||||
const para = doc.content![0]
|
||||
expect(para.type).toBe('paragraph')
|
||||
|
||||
// Collect texts and their mark states
|
||||
const runs = para.content!.map((n: any) => ({ text: n.text, marks: n.marks || [] }))
|
||||
// Expect there to be runs containing a, b, c
|
||||
const texts = runs.map(r => (r.text || '').trim())
|
||||
expect(texts).toContain('a')
|
||||
expect(texts).toContain('b')
|
||||
expect(texts).toContain('c')
|
||||
;['a', 'b', 'c'].forEach(letter => {
|
||||
const node = runs.find(r => (r.text || '').trim() === letter)
|
||||
expect(node).not.toBe(undefined)
|
||||
const hasItalic = ((node as any).marks || []).some((m: any) => m.type === 'italic')
|
||||
expect(hasItalic).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('parses an unclosed inline HTML tag without nesting a paragraph', () => {
|
||||
const md = '<b>123'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
expect(doc.content).toEqual([{ type: 'paragraph', content: [{ type: 'text', text: '123' }] }])
|
||||
})
|
||||
|
||||
it('parses an unclosed inline HTML tag and keeps the surrounding text', () => {
|
||||
const md = 'a <b> b'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
// The dropped tag leaves both of the spaces around it.
|
||||
expect(doc.content).toEqual([{ type: 'paragraph', content: [{ type: 'text', text: 'a b' }] }])
|
||||
})
|
||||
|
||||
it('parses an empty inline HTML element without nesting a paragraph', () => {
|
||||
const md = 'a <span></span> b'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
expect(doc.content).toEqual([{ type: 'paragraph', content: [{ type: 'text', text: 'a b' }] }])
|
||||
})
|
||||
|
||||
it('parses inline HTML for a block element as its inline content', () => {
|
||||
const md = 'a <h1>title</h1> b'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
expect(doc.content).toEqual([
|
||||
{ type: 'paragraph', content: [{ type: 'text', text: 'a title b' }] },
|
||||
])
|
||||
})
|
||||
|
||||
it('parses inline HTML for an inline node and keeps the node', () => {
|
||||
const md = 'a <br> b'
|
||||
const doc = manager.parse(md)
|
||||
|
||||
expect(doc.content).toEqual([
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [
|
||||
{ type: 'text', text: 'a ' },
|
||||
{ type: 'hardBreak' },
|
||||
{ type: 'text', text: ' b' },
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user