diff --git a/packages/happy-dom/src/nodes/node/Node.ts b/packages/happy-dom/src/nodes/node/Node.ts
index e87276f6..bd3e21f8 100644
--- a/packages/happy-dom/src/nodes/node/Node.ts
+++ b/packages/happy-dom/src/nodes/node/Node.ts
@@ -471,14 +471,20 @@ export default class Node extends EventTarget {
* @returns Appended node.
*/
public [PropertySymbol.appendChild](node: Node, disableValidations = false): Node {
+ if (node[PropertySymbol.proxy]) {
+ node = node[PropertySymbol.proxy];
+ }
+
+ const self = this[PropertySymbol.proxy] || this;
+
if (!disableValidations) {
- if (node === this) {
+ if (node === self) {
throw new this[PropertySymbol.window].DOMException(
"Failed to execute 'appendChild' on 'Node': Not possible to append a node as a child of itself."
);
}
- if (NodeUtility.isInclusiveAncestor(node, this, true)) {
+ if (NodeUtility.isInclusiveAncestor(node, self, true)) {
throw new this[PropertySymbol.window].DOMException(
"Failed to execute 'appendChild' on 'Node': The new node is a parent of the node to insert to.",
DOMExceptionNameEnum.domException
@@ -501,7 +507,7 @@ export default class Node extends EventTarget {
node[PropertySymbol.parentNode][PropertySymbol.removeChild](node);
}
- node[PropertySymbol.parentNode] = this[PropertySymbol.proxy] || this;
+ node[PropertySymbol.parentNode] = self;
node[PropertySymbol.clearCache]();
@@ -522,7 +528,7 @@ export default class Node extends EventTarget {
this[PropertySymbol.reportMutation](
new MutationRecord({
- target: this,
+ target: self,
type: MutationTypeEnum.childList,
addedNodes: [node]
})
@@ -538,6 +544,10 @@ export default class Node extends EventTarget {
* @returns Removed node.
*/
public [PropertySymbol.removeChild](node: Node): Node {
+ if (node[PropertySymbol.proxy]) {
+ node = node[PropertySymbol.proxy];
+ }
+
node[PropertySymbol.parentNode] = null;
node[PropertySymbol.clearCache]();
@@ -578,7 +588,7 @@ export default class Node extends EventTarget {
this[PropertySymbol.reportMutation](
new MutationRecord({
- target: this,
+ target: this[PropertySymbol.proxy] || this,
type: MutationTypeEnum.childList,
removedNodes: [node]
})
@@ -600,18 +610,28 @@ export default class Node extends EventTarget {
referenceNode: Node | null,
disableValidations = false
): Node {
+ if (newNode[PropertySymbol.proxy]) {
+ newNode = newNode[PropertySymbol.proxy];
+ }
+
+ if (referenceNode && referenceNode[PropertySymbol.proxy]) {
+ referenceNode = referenceNode[PropertySymbol.proxy];
+ }
+
if (newNode === referenceNode) {
return newNode;
}
+ const self = this[PropertySymbol.proxy] || this;
+
if (!disableValidations) {
- if (newNode === this) {
+ if (newNode === self) {
throw new this[PropertySymbol.window].DOMException(
"Failed to execute 'insertBefore' on 'Node': Not possible to insert a node as a child of itself."
);
}
- if (NodeUtility.isInclusiveAncestor(newNode, this, true)) {
+ if (NodeUtility.isInclusiveAncestor(newNode, self, true)) {
throw new this[PropertySymbol.window].DOMException(
"Failed to execute 'insertBefore' on 'Node': The new node is a parent of the node to insert to.",
DOMExceptionNameEnum.domException
@@ -649,7 +669,7 @@ export default class Node extends EventTarget {
newNode[PropertySymbol.parentNode][PropertySymbol.removeChild](newNode);
}
- newNode[PropertySymbol.parentNode] = this[PropertySymbol.proxy] || this;
+ newNode[PropertySymbol.parentNode] = self;
newNode[PropertySymbol.clearCache]();
@@ -687,7 +707,7 @@ export default class Node extends EventTarget {
this[PropertySymbol.reportMutation](
new MutationRecord({
- target: this,
+ target: self,
type: MutationTypeEnum.childList,
addedNodes: [newNode]
})
diff --git a/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts b/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts
index 4dfb655f..fd3f6fca 100644
--- a/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts
+++ b/packages/happy-dom/test/nodes/html-form-element/HTMLFormElement.test.ts
@@ -1197,6 +1197,102 @@ describe('HTMLFormElement', () => {
});
});
+ describe('remove()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.remove();
+
+ expect(document.body.children[0].children.length).toBe(0);
+ });
+ });
+
+ describe('replaceWith()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.replaceWith(document.createElement('div'));
+
+ expect(document.body.children[0].children[0].tagName).toBe('DIV');
+ });
+ });
+
+ describe('before()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.before(document.createElement('div'));
+
+ expect(document.body.children[0].children[0].tagName).toBe('DIV');
+ });
+ });
+
+ describe('after()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.after(document.createElement('div'));
+
+ expect(document.body.children[0].children[1].tagName).toBe('DIV');
+ });
+ });
+
+ describe('append()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.append(document.createElement('div'));
+
+ expect(form.children[0].tagName).toBe('DIV');
+ });
+ });
+
+ describe('prepend()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.prepend(document.createElement('div'));
+
+ expect(form.children[0].tagName).toBe('DIV');
+ });
+ });
+
+ describe('replaceChildren()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.replaceChildren(document.createElement('div'));
+
+ expect(form.children[0].tagName).toBe('DIV');
+ });
+ });
+
+ describe('insertAdjacentElement()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const form = document.querySelector('form');
+
+ form.insertAdjacentElement('beforebegin', document.createElement('div'));
+
+ expect(document.body.children[0].children[0].tagName).toBe('DIV');
+ });
+ });
+
for (const method of ['checkValidity', 'reportValidity']) {
describe(`${method}()`, () => {
it('Validates the form.', () => {
diff --git a/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts b/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts
index 3c26379f..7a189934 100644
--- a/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts
+++ b/packages/happy-dom/test/nodes/html-select-element/HTMLSelectElement.test.ts
@@ -606,6 +606,105 @@ describe('HTMLSelectElement', () => {
});
});
+ describe('remove()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+
+ select.remove();
+
+ expect(document.body.children[0].children.length).toBe(0);
+ });
+ });
+
+ describe('replaceWith()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+
+ select.replaceWith(document.createElement('div'));
+
+ expect(document.body.children[0].children[0].tagName).toBe('DIV');
+ });
+ });
+
+ describe('before()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+
+ select.before(document.createElement('div'));
+
+ expect(document.body.children[0].children[0].tagName).toBe('DIV');
+ });
+ });
+
+ describe('after()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+
+ select.after(document.createElement('div'));
+
+ expect(document.body.children[0].children[1].tagName).toBe('DIV');
+ });
+ });
+
+ describe('append()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+ const newOption = document.createElement('option');
+
+ select.append(newOption);
+
+ expect(select.children[1]).toBe(newOption);
+ });
+ });
+
+ describe('prepend()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+ const newOption = document.createElement('option');
+
+ select.prepend(newOption);
+
+ expect(select.children[0]).toBe(newOption);
+ });
+ });
+
+ describe('replaceChildren()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+ const newOption = document.createElement('option');
+
+ select.replaceChildren(newOption);
+
+ expect(select.children[0]).toBe(newOption);
+ });
+ });
+
+ describe('insertAdjacentElement()', () => {
+ it('Sets "parentNode" of child elements to the proxy and not the original element.', () => {
+ document.body.innerHTML = '';
+
+ const select = document.querySelector('select');
+
+ select.insertAdjacentElement('beforebegin', document.createElement('div'));
+
+ expect(document.body.children[0].children[0].tagName).toBe('DIV');
+ });
+ });
+
describe('setCustomValidity()', () => {
it('Returns validation message.', () => {
element.setCustomValidity('Error message');