diff --git a/src/plugin/__tests__/obsidian-stubs-html.test.ts b/src/plugin/__tests__/obsidian-stubs-html.test.ts
index 82e30645..d62ab065 100644
--- a/src/plugin/__tests__/obsidian-stubs-html.test.ts
+++ b/src/plugin/__tests__/obsidian-stubs-html.test.ts
@@ -1,6 +1,6 @@
// src/plugin/__tests__/obsidian-stubs-html.test.ts
import { describe, it, expect } from 'vitest'
-import { htmlToMarkdown, MarkdownRenderer } from '../obsidian-stubs'
+import { htmlToMarkdown, sanitizeHTMLToDom, MarkdownRenderer } from '../obsidian-stubs'
// Realm-identity: htmlToMarkdown must be the same function reference whether
// imported via the ESM `obsidian-compat` virtual module path or the CJS
// `loader/plugin-api-global` shim. Drift here means plugins loaded by
@@ -386,6 +386,415 @@ describe('htmlToMarkdown', () => {
})
})
+describe('sanitizeHTMLToDom', () => {
+ describe('basic functionality', () => {
+ it('returns a DocumentFragment', () => {
+ const result = sanitizeHTMLToDom('
hello
')
+ expect(result).toBeInstanceOf(DocumentFragment)
+ })
+
+ it('preserves safe HTML content', () => {
+ const result = sanitizeHTMLToDom('Hello world
')
+ const div = document.createElement('div')
+ div.appendChild(result)
+ expect(div.innerHTML).toBe('Hello world
')
+ })
+
+ it('handles empty string input', () => {
+ const result = sanitizeHTMLToDom('')
+ expect(result).toBeInstanceOf(DocumentFragment)
+ expect(result.childNodes.length).toBe(0)
+ })
+
+ it('handles null input defensively', () => {
+ // @ts-expect-error testing runtime guard for null
+ const result = sanitizeHTMLToDom(null)
+ expect(result).toBeInstanceOf(DocumentFragment)
+ expect(result.childNodes.length).toBe(0)
+ })
+
+ it('handles undefined input defensively', () => {
+ // @ts-expect-error testing runtime guard for undefined
+ const result = sanitizeHTMLToDom(undefined)
+ expect(result).toBeInstanceOf(DocumentFragment)
+ expect(result.childNodes.length).toBe(0)
+ })
+ })
+
+ describe('dangerous element removal', () => {
+ it('removes script elements', () => {
+ const result = sanitizeHTMLToDom('before
after
')
+ const div = document.createElement('div')
+ div.appendChild(result)
+ expect(div.innerHTML).toBe('before
after
')
+ expect(div.querySelector('script')).toBeNull()
+ })
+
+ it('removes style elements', () => {
+ const result = sanitizeHTMLToDom('text
')
+ const div = document.createElement('div')
+ div.appendChild(result)
+ expect(div.innerHTML).toBe('text
')
+ expect(div.querySelector('style')).toBeNull()
+ })
+
+ it('removes iframe elements', () => {
+ const result = sanitizeHTMLToDom('safe
')
+ const div = document.createElement('div')
+ div.appendChild(result)
+ expect(div.querySelector('iframe')).toBeNull()
+ })
+
+ it('removes object elements', () => {
+ const result = sanitizeHTMLToDom('text
')
+ const div = document.createElement('div')
+ div.appendChild(result)
+ expect(div.querySelector('object')).toBeNull()
+ })
+
+ it('removes embed elements', () => {
+ const result = sanitizeHTMLToDom('