Repository: capricorn86/happy-dom
Pull request #96 (2020-10-06 23:09:38)

#93@minor: Support for Node.replaceWith()


Patch:
diff --git a/packages/happy-dom/src/nodes/basic/node/Node.ts b/packages/happy-dom/src/nodes/basic/node/Node.ts
index 01f7639d..81f94cfd 100644
--- a/packages/happy-dom/src/nodes/basic/node/Node.ts
+++ b/packages/happy-dom/src/nodes/basic/node/Node.ts
@@ -5,6 +5,7 @@ import MutationRecord from '../../../mutation-observer/MutationRecord';
 import MutationTypeConstant from '../../../mutation-observer/MutationType';
 import MutationObserverListener from '../../../mutation-observer/MutationListener';
 import Event from '../../../event/Event';
+import HTMLParser from '../../../html-parser/HTMLParser';
 
 const CLONE_REFERENCE_PROPERTIES = [
 	'ownerDocument',
@@ -421,6 +422,37 @@ export default class Node extends EventTarget {
 		return oldChild;
 	}
 
+	/**
+	 * The Node.replaceWith() method replaces this Node in the children list of its parent with a set of Node or DOMString objects.
+	 *
+	 * @param nodes List of Node or DOMString.
+	 */
+	public replaceWith(...nodes: Node[] | string[]): void {
+		const parent = this.parentNode;
+
+		if (!parent) {
+			return;
+		}
+
+		const index = parent.childNodes.indexOf(this);
+
+		parent.removeChild(this);
+
+		for (let i = nodes.length - 1; i >= 0; i--) {
+			const node = nodes[i];
+
+			if (typeof node === 'string') {
+				parent.childNodes.splice(
+					index,
+					0,
+					...HTMLParser.parse(this.ownerDocument, node).childNodes
+				);
+			} else {
+				parent.childNodes.splice(index, 0, node);
+			}
+		}
+	}
+
 	/**
 	 * @override
 	 */


Test patch:
diff --git a/packages/happy-dom/test/nodes/basic/node/Node.test.ts b/packages/happy-dom/test/nodes/basic/node/Node.test.ts
index fc54e807..fbe60cf1 100644
--- a/packages/happy-dom/test/nodes/basic/node/Node.test.ts
+++ b/packages/happy-dom/test/nodes/basic/node/Node.test.ts
@@ -402,6 +402,37 @@ describe('Node', () => {
 		});
 	});
 
+	describe('replaceWith()', () => {
+		test('Replaces a node another node.', () => {
+			const parent = document.createElement('div');
+			const newChild = document.createElement('span');
+			newChild.className = 'child4';
+			parent.innerHTML =
+				'<span class="child1"></span><span class="child2"></span><span class="child3"></span>';
+
+			parent.children[2].replaceWith(newChild);
+			expect(parent.innerHTML).toBe(
+				'<span class="child1"></span><span class="child2"></span><span class="child4"></span>'
+			);
+		});
+
+		test('Replaces a node with a mixed list of Node and DOMString (string).', () => {
+			const parent = document.createElement('div');
+			const newChildrenParent = document.createElement('div');
+			const newChildrenHtml =
+				'<span class="child4"></span><span class="child5"></span><span class="child6"></span>';
+			newChildrenParent.innerHTML =
+				'<span class="child7"></span><span class="child8"></span><span class="child9"></span>';
+			parent.innerHTML =
+				'<span class="child1"></span><span class="child2"></span><span class="child3"></span>';
+
+			parent.children[2].replaceWith(...[newChildrenHtml, ...newChildrenParent.children]);
+			expect(parent.innerHTML).toBe(
+				'<span class="child1"></span><span class="child2"></span><span class="child4"></span><span class="child5"></span><span class="child6"></span><span class="child7"></span><span class="child8"></span><span class="child9"></span>'
+			);
+		});
+	});
+
 	describe('dispatchEvent()', () => {
 		test('Dispatches an event that is set to not bubble.', () => {
 			const child = document.createElement('span');