diff --git a/src/renderer/src/components/Preview/__tests__/utils.test.ts b/src/renderer/src/components/Preview/__tests__/utils.test.ts index c9722c33d4..d991322e0c 100644 --- a/src/renderer/src/components/Preview/__tests__/utils.test.ts +++ b/src/renderer/src/components/Preview/__tests__/utils.test.ts @@ -10,29 +10,39 @@ describe('renderSvgInShadowHost', () => { // Mock attachShadow Element.prototype.attachShadow = vi.fn().mockImplementation(function (this: HTMLElement) { - const shadowRoot = document.createElement('div') + // Check if a shadow root already exists to prevent re-creating it. + if (this.shadowRoot) { + return this.shadowRoot + } + + // Create a container that acts as the shadow root. + const shadowRootContainer = document.createElement('div') + shadowRootContainer.dataset.testid = 'shadow-root' + Object.defineProperty(this, 'shadowRoot', { - value: shadowRoot, + value: shadowRootContainer, writable: true, configurable: true }) - // Simple innerHTML copy for test verification - Object.defineProperty(shadowRoot, 'innerHTML', { - set(value) { - shadowRoot.textContent = value // A simplified mock + + // Mock essential methods like appendChild and innerHTML. + // JSDOM doesn't fully implement shadow DOM, so we simulate its behavior. + const originalInnerHTMLDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML') + Object.defineProperty(shadowRootContainer, 'innerHTML', { + set(value: string) { + // Clear existing content and parse the new HTML. + originalInnerHTMLDescriptor?.set?.call(this, '') + const template = document.createElement('template') + template.innerHTML = value + shadowRootContainer.append(...Array.from(template.content.childNodes)) }, get() { - return shadowRoot.textContent || '' + return originalInnerHTMLDescriptor?.get?.call(this) ?? '' }, configurable: true }) - shadowRoot.appendChild = vi.fn((node: T): T => { - shadowRoot.append(node) - return node - }) - - return shadowRoot as unknown as ShadowRoot + return shadowRootContainer as unknown as ShadowRoot }) }) @@ -57,7 +67,7 @@ describe('renderSvgInShadowHost', () => { expect(Element.prototype.attachShadow).not.toHaveBeenCalled() // Verify it works with the existing shadow root - expect(existingShadowRoot.appendChild).toHaveBeenCalled() + expect(existingShadowRoot.innerHTML).toContain(' { @@ -71,15 +81,26 @@ describe('renderSvgInShadowHost', () => { expect(shadowRoot?.querySelector('rect')).not.toBeNull() }) + it('should add the xmlns attribute if it is missing', () => { + const svgWithoutXmlns = '' + renderSvgInShadowHost(svgWithoutXmlns, hostElement) + + const svgElement = hostElement.shadowRoot?.querySelector('svg') + expect(svgElement).not.toBeNull() + expect(svgElement?.getAttribute('xmlns')).toBe('http://www.w3.org/2000/svg') + }) + it('should throw an error if the host element is not available', () => { expect(() => renderSvgInShadowHost('', null as any)).toThrow( 'Host element for SVG rendering is not available.' ) }) - it('should throw an error for invalid SVG content', () => { - const invalidSvg = '' // Malformed - expect(() => renderSvgInShadowHost(invalidSvg, hostElement)).toThrow(/SVG parsing error/) + it('should not throw an error for malformed SVG content due to HTML parser fallback', () => { + const invalidSvg = '' // Malformed, but fixable by the browser's HTML parser + expect(() => renderSvgInShadowHost(invalidSvg, hostElement)).not.toThrow() + // Also, assert that it successfully rendered something. + expect(hostElement.shadowRoot?.querySelector('svg')).not.toBeNull() }) it('should throw an error for non-SVG content', () => {