Repository: capricorn86/happy-dom
Pull request #640 (2022-10-25 23:45:15)

#639@patch: Element.innerHTML should be able to handle other types th…
…an string.


Patch:
diff --git a/packages/happy-dom/src/xml-parser/XMLParser.ts b/packages/happy-dom/src/xml-parser/XMLParser.ts
index 98ed92be..9cb8e787 100755
--- a/packages/happy-dom/src/xml-parser/XMLParser.ts
+++ b/packages/happy-dom/src/xml-parser/XMLParser.ts
@@ -42,76 +42,80 @@ export default class XMLParser {
 		let lastTextIndex = 0;
 		let match: RegExpExecArray;
 
-		while ((match = markupRegexp.exec(data))) {
-			const tagName = match[2].toLowerCase();
-			const isStartTag = !match[1];
+		if (data !== null && data !== undefined) {
+			data = String(data);
 
-			if (parent && match.index !== lastTextIndex) {
-				const text = data.substring(lastTextIndex, match.index);
-				this.appendTextAndCommentNodes(document, parent, text);
-			}
-
-			if (isStartTag) {
-				const namespaceURI =
-					tagName === 'svg'
-						? NamespaceURI.svg
-						: (<IElement>parent).namespaceURI || NamespaceURI.html;
-				const newElement = document.createElementNS(namespaceURI, tagName);
-
-				// Scripts are not allowed to be executed when they are parsed using innerHTML, outerHTML, replaceWith() etc.
-				// However, they are allowed to be executed when document.write() is used.
-				// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement
-				if (tagName === 'script') {
-					(<HTMLScriptElement>newElement)._evaluateScript = evaluateScripts;
-				}
+			while ((match = markupRegexp.exec(data))) {
+				const tagName = match[2].toLowerCase();
+				const isStartTag = !match[1];
 
-				// An assumption that the same rule should be applied for the HTMLLinkElement is made here.
-				if (tagName === 'link') {
-					(<HTMLLinkElement>newElement)._evaluateCSS = evaluateScripts;
+				if (parent && match.index !== lastTextIndex) {
+					const text = data.substring(lastTextIndex, match.index);
+					this.appendTextAndCommentNodes(document, parent, text);
 				}
 
-				this.setAttributes(newElement, match[3]);
+				if (isStartTag) {
+					const namespaceURI =
+						tagName === 'svg'
+							? NamespaceURI.svg
+							: (<IElement>parent).namespaceURI || NamespaceURI.html;
+					const newElement = document.createElementNS(namespaceURI, tagName);
+
+					// Scripts are not allowed to be executed when they are parsed using innerHTML, outerHTML, replaceWith() etc.
+					// However, they are allowed to be executed when document.write() is used.
+					// See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement
+					if (tagName === 'script') {
+						(<HTMLScriptElement>newElement)._evaluateScript = evaluateScripts;
+					}
 
-				if (!match[4] && !VoidElements.includes(tagName)) {
-					// Some elements are not allowed to be nested (e.g. "<a><a></a></a>" is not allowed.).
-					// Therefore we will auto-close the tag.
-					if (parentUnnestableTagName === tagName) {
-						stack.pop();
-						parent = <Element>parent.parentNode || root;
+					// An assumption that the same rule should be applied for the HTMLLinkElement is made here.
+					if (tagName === 'link') {
+						(<HTMLLinkElement>newElement)._evaluateCSS = evaluateScripts;
 					}
 
-					parent = <Element>parent.appendChild(newElement);
-					parentUnnestableTagName = this.getUnnestableTagName(parent);
-					stack.push(parent);
-				} else {
-					parent.appendChild(newElement);
-				}
-				lastTextIndex = markupRegexp.lastIndex;
-
-				// Tags which contain non-parsed content
-				// For example: <script> JavaScript should not be parsed
-				if (ChildLessElements.includes(tagName)) {
-					let childLessMatch = null;
-					while ((childLessMatch = markupRegexp.exec(data))) {
-						if (childLessMatch[2].toLowerCase() === tagName && childLessMatch[1]) {
-							markupRegexp.lastIndex -= childLessMatch[0].length;
-							break;
+					this.setAttributes(newElement, match[3]);
+
+					if (!match[4] && !VoidElements.includes(tagName)) {
+						// Some elements are not allowed to be nested (e.g. "<a><a></a></a>" is not allowed.).
+						// Therefore we will auto-close the tag.
+						if (parentUnnestableTagName === tagName) {
+							stack.pop();
+							parent = <Element>parent.parentNode || root;
+						}
+
+						parent = <Element>parent.appendChild(newElement);
+						parentUnnestableTagName = this.getUnnestableTagName(parent);
+						stack.push(parent);
+					} else {
+						parent.appendChild(newElement);
+					}
+					lastTextIndex = markupRegexp.lastIndex;
+
+					// Tags which contain non-parsed content
+					// For example: <script> JavaScript should not be parsed
+					if (ChildLessElements.includes(tagName)) {
+						let childLessMatch = null;
+						while ((childLessMatch = markupRegexp.exec(data))) {
+							if (childLessMatch[2].toLowerCase() === tagName && childLessMatch[1]) {
+								markupRegexp.lastIndex -= childLessMatch[0].length;
+								break;
+							}
 						}
 					}
-				}
-			} else {
-				stack.pop();
-				parent = stack[stack.length - 1] || root;
-				parentUnnestableTagName = this.getUnnestableTagName(parent);
+				} else {
+					stack.pop();
+					parent = stack[stack.length - 1] || root;
+					parentUnnestableTagName = this.getUnnestableTagName(parent);
 
-				lastTextIndex = markupRegexp.lastIndex;
+					lastTextIndex = markupRegexp.lastIndex;
+				}
 			}
-		}
 
-		// Text after last element
-		if ((!match && data.length > 0) || (match && lastTextIndex !== match.index)) {
-			const text = data.substring(lastTextIndex);
-			this.appendTextAndCommentNodes(document, parent || root, text);
+			// Text after last element
+			if ((!match && data.length > 0) || (match && lastTextIndex !== match.index)) {
+				const text = data.substring(lastTextIndex);
+				this.appendTextAndCommentNodes(document, parent || root, text);
+			}
 		}
 
 		return root;


Test patch:
diff --git a/packages/happy-dom/test/xml-parser/XMLParser.test.ts b/packages/happy-dom/test/xml-parser/XMLParser.test.ts
index e1448b65..f30c525f 100644
--- a/packages/happy-dom/test/xml-parser/XMLParser.test.ts
+++ b/packages/happy-dom/test/xml-parser/XMLParser.test.ts
@@ -396,5 +396,19 @@ describe('XMLParser', () => {
 
 			expect((<IHTMLElement>root.children[0]).innerText).toBe(`console.log('hello')`);
 		});
+
+		it('Handles different value types.', () => {
+			const root1 = XMLParser.parse(window.document, null);
+			expect(new XMLSerializer().serializeToString(root1)).toBe('');
+
+			const root2 = XMLParser.parse(window.document, undefined);
+			expect(new XMLSerializer().serializeToString(root2)).toBe('');
+
+			const root3 = XMLParser.parse(window.document, <string>(<unknown>1000));
+			expect(new XMLSerializer().serializeToString(root3)).toBe('1000');
+
+			const root4 = XMLParser.parse(window.document, <string>(<unknown>false));
+			expect(new XMLSerializer().serializeToString(root4)).toBe('false');
+		});
 	});
 });