diff --git a/test/customElements/renderCustomElements.test.ts b/test/customElements/renderCustomElements.test.ts index cf66f6f..41fb86e 100644 --- a/test/customElements/renderCustomElements.test.ts +++ b/test/customElements/renderCustomElements.test.ts @@ -1,152 +1,164 @@ +// test/customElements/renderCustomElements.test.ts // @vitest-environment nuxt -import { describe, it, expect, vi } from 'vitest' +import { describe, it, expect } from 'vitest' +import { mountSuspended } from '@nuxt/test-utils/runtime' +import { defineComponent } from 'vue' import { useDrupalCe } from '../../src/runtime/composables/useDrupalCe' -// useDrupalCe uses Nuxt's module system with '#app' and '#imports' virtual modules. -// For unit testing, we need to mock these, but we want to use real Vue features for what we're testing - -// Mock #app which provides Nuxt's app utilities (not used by renderCustomElements) -vi.mock('#app', () => ({ - callWithNuxt: vi.fn(), // Used by other parts of useDrupalCe -})) - -// Create a mock Vue app with component registry -const mockComponents = new Map() - -// Define test components -const TestComponent = { - props: { - foo: String - }, - template: '
Test
' -} - -const AnotherComponent = { - props: { - baz: String - }, - template: '
Another
' -} - -// Register components in our mock registry -mockComponents.set('TestComponent', TestComponent) -mockComponents.set('AnotherComponent', AnotherComponent) - -// Mock #imports which provides composables and Vue utilities -vi.mock('#imports', () => ({ - h: (name: string) => ({ - name, - __isComponent: true // some marker to identify it's a component - }), - useNuxtApp: () => ({ - vueApp: { - component: (name) => mockComponents.get(name) - } - }), - // Mock the rest that's only used by other parts of useDrupalCe - useRuntimeConfig: () => ({ - public: { drupalCe: {} }, - drupalCe: {} - }), - ref: vi.fn(), - computed: vi.fn(), -})) - describe('renderCustomElements', () => { const { renderCustomElements } = useDrupalCe() - it('handles null input', () => { - const result = renderCustomElements(null) - expect(result).toBe(null) + // Define reusable test components + const TestComponent = defineComponent({ + props: { + foo: String + }, + template: '
Test Component: {{ foo || "" }}
' }) - it('handles undefined input', () => { - const result = renderCustomElements(undefined) - expect(result).toBe(null) + const AnotherComponent = defineComponent({ + props: { + bar: String + }, + template: '
Another Component: {{ bar }}
' }) - it('handles empty object input', () => { - const result = renderCustomElements({}) - expect(result).toBe(null) - }) + describe('basic input handling', () => { + const NullRenderer = defineComponent({ + setup() { + return { component: renderCustomElements(null) } + }, + template: '' + }) - it('handles plain string input', () => { - const result = renderCustomElements('Hello World') - expect(result).toMatchObject({ - template: '
', - data: expect.any(Function) + it('should return null for empty inputs', () => { + expect(renderCustomElements(null)).toBe(null) + expect(renderCustomElements(undefined)).toBe(null) + expect(renderCustomElements({})).toBe(null) }) - expect(result.data().content).toBe('Hello World') - }) - it('handles HTML string input', () => { - const htmlString = '

Hello World

' - const result = renderCustomElements(htmlString) - expect(result).toMatchObject({ - template: '
', - data: expect.any(Function) + it('should render nothing when component is null', async () => { + const wrapper = await mountSuspended(NullRenderer) + expect(wrapper.html()).toBe('') }) - expect(result.data().content).toBe(htmlString) }) - it('handles single custom element object', () => { - const customElement = { - element: 'test-component', - props: { foo: 'bar' } - } - const result = renderCustomElements(customElement) - expect(result).toBeTruthy() - expect(result.type).toBe(TestComponent) - }) + describe('string rendering', () => { + it('should render plain text', async () => { + const TextRenderer = defineComponent({ + setup() { + return { component: renderCustomElements('Hello World') } + }, + template: '' + }) + const wrapper = await mountSuspended(TextRenderer) + expect(wrapper.text()).toBe('Hello World') + }) - it('handles array of custom elements', () => { - const customElements = [ - { - element: 'test-component', - props: { foo: 'bar' } - }, - 'Plain text element', - { - element: 'another-component', - props: { baz: 'qux' } - } - ] - const result = renderCustomElements(customElements) - expect(Array.isArray(result)).toBe(true) - expect(result).toHaveLength(3) + it('should render HTML string preserving markup', async () => { + const htmlString = '

Hello World

' + const HtmlRenderer = defineComponent({ + setup() { + return { component: renderCustomElements(htmlString) } + }, + template: '' + }) + const wrapper = await mountSuspended(HtmlRenderer) + expect(wrapper.html()).toContain(htmlString) + expect(wrapper.text()).toBe('Hello World') + }) + }) - // First component - expect(result[0].type).toBe(TestComponent) - expect(result[0].props).toMatchObject({ - foo: 'bar' + describe('custom element rendering', () => { + it('should render a single custom element', async () => { + const ComponentRenderer = defineComponent({ + components: { TestComponent }, + setup() { + return { component: renderCustomElements({ + element: 'test-component', + foo: 'bar' + })} + }, + template: '' + }) + const wrapper = await mountSuspended(ComponentRenderer) + expect(wrapper.text()).toBe('Test Component: bar') }) + }) - // Text element - expect(result[1]).toMatchObject({ - template: '
', - data: expect.any(Function) + describe('array handling', () => { + it('should render array of strings', async () => { + const StringArrayRenderer = defineComponent({ + setup() { + const content = ['Text 1', '

Text 2

'] + return { + components: content.map(item => renderCustomElements(item)) + } + }, + template: '
' + }) + const wrapper = await mountSuspended(StringArrayRenderer) + expect(wrapper.text()).toContain('Text 1') + expect(wrapper.text()).toContain('Text 2') + expect(wrapper.html()).toContain('

Text 2

') }) - expect(result[1].data().content).toBe('Plain text element') - // Third component - expect(result[2].type).toBe(AnotherComponent) - expect(result[2].props).toMatchObject({ - baz: 'qux' + it('should render array of custom elements', async () => { + const ElementArrayRenderer = defineComponent({ + components: { TestComponent, AnotherComponent }, + setup() { + const content = [ + { element: 'test-component', foo: 'one' }, + { element: 'another-component', bar: 'two' } + ] + return { + components: content.map(item => renderCustomElements(item)) + } + }, + template: '
' + }) + const wrapper = await mountSuspended(ElementArrayRenderer) + expect(wrapper.text()).toContain('Test Component: one') + expect(wrapper.text()).toContain('Another Component: two') }) }) - it('handles array with only string elements', () => { - const elements = ['Text 1', '

HTML text

'] - const result = renderCustomElements(elements) - expect(Array.isArray(result)).toBe(true) - expect(result).toHaveLength(2) + describe('edge cases', () => { + it('should handle malformed element objects', async () => { + const MalformedRenderer = defineComponent({ + components: { TestComponent }, + setup() { + return { component: renderCustomElements({ element: 'test-component' })} + }, + template: '' + }) + const wrapper = await mountSuspended(MalformedRenderer) + expect(wrapper.text()).toBe('Test Component:') + }) + + it('should handle nonexistent components', async () => { + const NonexistentRenderer = defineComponent({ + setup() { + return { component: renderCustomElements({ + element: 'nonexistent-component', + foo: 'bar' + })} + }, + template: '' + }) + const wrapper = await mountSuspended(NonexistentRenderer) + expect(wrapper.html()).toBe('') + }) - result.forEach((component, index) => { - expect(component).toMatchObject({ - template: '
', - data: expect.any(Function) + it('should handle empty arrays', async () => { + const EmptyArrayRenderer = defineComponent({ + setup() { + return { component: renderCustomElements([]) } + }, + template: '' }) - expect(component.data().content).toBe(elements[index]) + const wrapper = await mountSuspended(EmptyArrayRenderer) + expect(wrapper.html()).toBe('') }) }) })