/**
* @vitest-environment jsdom
*/
import { mount } from '@vue/test-utils'
import { beforeEach, describe, expect, it } from 'vitest'
import { defineComponent, h } from 'vue'
// Import Vue 2 components
import HtmlBlockNode from '../packages/markstream-vue2/src/components/HtmlBlockNode/HtmlBlockNode.vue'
import HtmlInlineNode from '../packages/markstream-vue2/src/components/HtmlInlineNode/HtmlInlineNode.vue'
import { setCustomComponents } from '../packages/markstream-vue2/src/utils/nodeComponents'
import { flushAll } from './setup/flush-all'
// Mock custom components
const TestComponent = defineComponent({
name: 'TestComponent',
props: ['dataType', 'active'],
setup(props, { slots }) {
return () => h(
'div',
{
'class': 'test-component',
'data-type': props.dataType,
'data-active': props.active,
},
slots.default?.() || 'Test Component',
)
},
})
const NestedComponent = defineComponent({
name: 'NestedComponent',
setup(_, { slots }) {
return () => h('div', { class: 'nested-component' }, slots.default?.())
},
})
describe('vue 2 - HtmlBlockNode Custom Components Integration', () => {
const testId = 'test-vue2-html-block'
beforeEach(() => {
setCustomComponents(testId, {
testcomp: TestComponent,
nestedcomp: NestedComponent,
})
})
it('should render custom component in HTML block', () => {
const wrapper = mount(HtmlBlockNode, {
props: {
node: {
content: 'Content',
loading: false,
},
customId: testId,
},
})
expect(wrapper.find('.test-component').exists()).toBe(true)
expect(wrapper.find('.test-component').attributes('data-type')).toBe('block')
expect(wrapper.html()).toContain('Content')
})
it('should render nested custom components', () => {
const wrapper = mount(HtmlBlockNode, {
props: {
node: {
content: 'Outer Nested End',
loading: false,
},
customId: testId,
},
})
expect(wrapper.find('.test-component').exists()).toBe(true)
expect(wrapper.find('.nested-component').exists()).toBe(true)
expect(wrapper.html()).toContain('Outer')
expect(wrapper.html()).toContain('Nested')
expect(wrapper.html()).toContain('End')
})
it('should render deeply nested custom components', () => {
const wrapper = mount(HtmlBlockNode, {
props: {
node: {
content: `
Level 1
Level 2
Level 3
`,
loading: false,
},
customId: testId,
},
})
expect(wrapper.find('.test-component').exists()).toBe(true)
expect(wrapper.findAll('.test-component').length).toBeGreaterThan(0)
expect(wrapper.findAll('.nested-component').length).toBeGreaterThan(0)
expect(wrapper.html()).toContain('Level 1')
expect(wrapper.html()).toContain('Level 2')
expect(wrapper.html()).toContain('Level 3')
})
it('should render mixed standard HTML and custom components', () => {
const wrapper = mount(HtmlBlockNode, {
props: {
node: {
content: '
',
loading: false,
},
customId: testId,
},
})
expect(wrapper.find('.standard').exists()).toBe(true)
expect(wrapper.find('.test-component').exists()).toBe(true)
expect(wrapper.find('p').exists()).toBe(true)
})
it('should use v-html when no custom components are present', () => {
const wrapper = mount(HtmlBlockNode, {
props: {
node: {
content: 'Pure HTML
',
loading: false,
},
customId: testId,
},
})
expect(wrapper.find('.standard').exists()).toBe(true)
expect(wrapper.html()).toContain('Pure HTML')
})
it('should sanitize raw HTML fallback content in blocks', async () => {
const wrapper = mount(HtmlBlockNode, {
props: {
node: {
content: '',
loading: false,
},
customId: testId,
},
})
await flushAll()
const img = wrapper.find('img')
const link = wrapper.find('a')
expect(img.exists()).toBe(true)
expect(img.attributes('onerror')).toBeUndefined()
expect(link.exists()).toBe(true)
expect(link.attributes('href')).toBeUndefined()
expect(link.attributes('title')).toBe('ok')
expect(wrapper.html()).not.toContain('