Repository: capricorn86/happy-dom (ts)

Issue:
Node.isEqualNode()
**Is your feature request related to a problem? Please describe.**
I wanted to compare two happy-dom nodes in my tests, however the library does not implement the standard
[Node.isEqualNode](https://developer.mozilla.org/en-US/docs/Web/API/Node/isEqualNode) browser method.

Instead I noticed there is a static function (`nodeEquals`) that implements this functionality in `NodeUtility`.

The issue is I did not realise this functionality was available  in the library until I dug through the source 
code, and I had to do this import in order to use it:
```js
import NodeUtility from "happy-dom/lib/nodes/node/NodeUtility"
```

**Describe the solution you'd like**
I was wondering if there was some design choice behind this that I haven't considered, or whether it
would be possible to add the method to the `INode` type, the same way it works in browsers?


**Additional context**
I am actually using happy-dom to test a web framework I am developing, and it involves comparing
generated HTML trees, hence the above.

The official implementation makes this tricky sometimes because of [whitespace between nodes](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace). I have
actually implemented a wrapper function around `nodeEquals` which first strips the two node trees of
any text nodes only containing whitespace. This makes comparison between two node trees more
meaningful in a test environment for generated HTML.

I'm not sure if the above function would have any use in `NodeUtilities` as well?

---

Happy to put in a pull request if any of the above seems desirable.


Pull request description:
#656@minor: Rename `nodeEquals` to `isEqualNode`.
Fixes #656.

Not sure if this is something you want to include. I'm just trying to help with this issue.

Here's the link to the spec: https://dom.spec.whatwg.org/#concept-node-equals

If you think I should change anything in the PR, let me know! I assigned the `minor` label, but I'll leave that to you to decide if it's correct. Cheers 🍻 !

Patch:
diff --git a/packages/happy-dom/src/nodes/node/Node.ts b/packages/happy-dom/src/nodes/node/Node.ts
index de1b6634..2d75e98e 100644
--- a/packages/happy-dom/src/nodes/node/Node.ts
+++ b/packages/happy-dom/src/nodes/node/Node.ts
@@ -623,7 +623,7 @@ export default class Node extends EventTarget implements INode {
 					/**
 					 * 5.2.1.1. If attr equals attr1, then return the result of adding DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC and DOCUMENT_POSITION_PRECEDING.
 					 */
-					if (NodeUtility.nodeEquals(<IAttr>attr, attr1)) {
+					if (NodeUtility.isEqualNode(<IAttr>attr, attr1)) {
 						return (
 							Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node.DOCUMENT_POSITION_PRECEDING
 						);
@@ -632,7 +632,7 @@ export default class Node extends EventTarget implements INode {
 					/**
 					 * 5.2.1.2. If attr equals attr2, then return the result of adding DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC and DOCUMENT_POSITION_FOLLOWING.
 					 */
-					if (NodeUtility.nodeEquals(<IAttr>attr, attr2)) {
+					if (NodeUtility.isEqualNode(<IAttr>attr, attr2)) {
 						return (
 							Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | Node.DOCUMENT_POSITION_FOLLOWING
 						);
diff --git a/packages/happy-dom/src/nodes/node/NodeUtility.ts b/packages/happy-dom/src/nodes/node/NodeUtility.ts
index 0cafdcf0..6da4c590 100644
--- a/packages/happy-dom/src/nodes/node/NodeUtility.ts
+++ b/packages/happy-dom/src/nodes/node/NodeUtility.ts
@@ -167,7 +167,7 @@ export default class NodeUtility {
 						(typeof attrA === 'number' && typeof attrB === 'number' && attrA === attrB) ||
 						(typeof attrA === 'object' &&
 							typeof attrB === 'object' &&
-							NodeUtility.nodeEquals(attrA, attrB))
+							NodeUtility.isEqualNode(attrA, attrB))
 					);
 				})
 			) {
@@ -185,7 +185,7 @@ export default class NodeUtility {
 	 * @param nodeA Node A.
 	 * @param nodeB Node B.
 	 */
-	public static nodeEquals(nodeA: INode, nodeB: INode): boolean {
+	public static isEqualNode(nodeA: INode, nodeB: INode): boolean {
 		if (nodeA.nodeType !== nodeB.nodeType) {
 			return false;
 		}
@@ -266,7 +266,7 @@ export default class NodeUtility {
 			const childNodeA = nodeA.childNodes[i];
 			const childNodeB = nodeB.childNodes[i];
 
-			if (!NodeUtility.nodeEquals(childNodeA, childNodeB)) {
+			if (!NodeUtility.isEqualNode(childNodeA, childNodeB)) {
 				return false;
 			}
 		}


Test patch:
diff --git a/packages/happy-dom/test/nodes/node/NodeUtility.test.ts b/packages/happy-dom/test/nodes/node/NodeUtility.test.ts
index 305c247e..d6f685cf 100644
--- a/packages/happy-dom/test/nodes/node/NodeUtility.test.ts
+++ b/packages/happy-dom/test/nodes/node/NodeUtility.test.ts
@@ -147,12 +147,12 @@ describe('NodeUtility', () => {
 		});
 	});
 
-	describe('nodeEquals()', () => {
+	describe('isEqualNode()', () => {
 		it('Returns false if element are not of same node type', () => {
 			const element = document.createElement('div');
 			const comment = document.createComment('foo');
 
-			expect(NodeUtility.nodeEquals(element, comment)).toEqual(false);
+			expect(NodeUtility.isEqualNode(element, comment)).toEqual(false);
 		});
 
 		describe('w/ document type node', () => {
@@ -168,28 +168,28 @@ describe('NodeUtility', () => {
 				const doctype1 = implementation.createDocumentType('html1', 'foo', 'bar');
 				const doctype2 = implementation.createDocumentType('html2', 'foo', 'bar');
 
-				expect(NodeUtility.nodeEquals(doctype1, doctype2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(doctype1, doctype2)).toEqual(false);
 			});
 
 			it('Returns false if public id are different', () => {
 				const doctype1 = implementation.createDocumentType('html', 'foo1', 'bar');
 				const doctype2 = implementation.createDocumentType('html', 'foo2', 'bar');
 
-				expect(NodeUtility.nodeEquals(doctype1, doctype2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(doctype1, doctype2)).toEqual(false);
 			});
 
 			it('Returns false if system id are different', () => {
 				const doctype1 = implementation.createDocumentType('html', 'foo', 'bar1');
 				const doctype2 = implementation.createDocumentType('html', 'foo', 'bar2');
 
-				expect(NodeUtility.nodeEquals(doctype1, doctype2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(doctype1, doctype2)).toEqual(false);
 			});
 
 			it('Returns true if doctype are equals', () => {
 				const doctype1 = implementation.createDocumentType('html', 'foo', 'bar');
 				const doctype2 = implementation.createDocumentType('html', 'foo', 'bar');
 
-				expect(NodeUtility.nodeEquals(doctype1, doctype2)).toEqual(true);
+				expect(NodeUtility.isEqualNode(doctype1, doctype2)).toEqual(true);
 			});
 		});
 
@@ -198,14 +198,14 @@ describe('NodeUtility', () => {
 				const element1 = document.createElement('span');
 				const element2 = document.createElement('div');
 
-				expect(NodeUtility.nodeEquals(element1, element2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(element1, element2)).toEqual(false);
 			});
 
 			it('Returns false if namespace URI are different', () => {
 				const element1 = document.createElementNS('ns1', 'span');
 				const element2 = document.createElementNS('ns2', 'span');
 
-				expect(NodeUtility.nodeEquals(element1, element2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(element1, element2)).toEqual(false);
 			});
 
 			it('Returns false if prefix are different', () => {
@@ -215,7 +215,7 @@ describe('NodeUtility', () => {
 				element1.prefix = 'prefix1';
 				element2.prefix = 'prefix2';
 
-				expect(NodeUtility.nodeEquals(element1, element2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(element1, element2)).toEqual(false);
 			});
 
 			it('Returns false if attributes list length are different', () => {
@@ -225,7 +225,7 @@ describe('NodeUtility', () => {
 
 				element1.setAttributeNode(attrFoo);
 
-				expect(NodeUtility.nodeEquals(element1, element2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(element1, element2)).toEqual(false);
 			});
 
 			it('Returns false if element attributes are not equal', () => {
@@ -238,7 +238,7 @@ describe('NodeUtility', () => {
 				element1.setAttributeNode(attrFoo);
 				element2.setAttributeNode(attrBar);
 
-				expect(NodeUtility.nodeEquals(element1, element2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(element1, element2)).toEqual(false);
 			});
 
 			it('Returns false if element does not have same amount of children', () => {
@@ -253,7 +253,7 @@ describe('NodeUtility', () => {
 				element1.appendChild(child2);
 				element2.appendChild(child3);
 
-				expect(NodeUtility.nodeEquals(element1, element2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(element1, element2)).toEqual(false);
 			});
 
 			it("Returns false if element's children are not equals", () => {
@@ -270,7 +270,7 @@ describe('NodeUtility', () => {
 				element2.appendChild(child3);
 				element2.appendChild(child4);
 
-				expect(NodeUtility.nodeEquals(element1, element2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(element1, element2)).toEqual(false);
 			});
 		});
 
@@ -279,14 +279,14 @@ describe('NodeUtility', () => {
 				const attr1 = document.createAttribute('foo1');
 				const attr2 = document.createAttribute('foo2');
 
-				expect(NodeUtility.nodeEquals(attr1, attr2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(attr1, attr2)).toEqual(false);
 			});
 
 			it('Returns false if namespace URI are different', () => {
 				const attr1 = document.createAttributeNS('ns1', 'foo');
 				const attr2 = document.createAttributeNS('ns2', 'foo');
 
-				expect(NodeUtility.nodeEquals(attr1, attr2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(attr1, attr2)).toEqual(false);
 			});
 
 			it('Returns false if value are different', () => {
@@ -296,7 +296,7 @@ describe('NodeUtility', () => {
 				attr1.value = 'bar1';
 				attr2.value = 'bar2';
 
-				expect(NodeUtility.nodeEquals(attr1, attr2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(attr1, attr2)).toEqual(false);
 			});
 
 			it('Returns true if elements are equal', () => {
@@ -305,7 +305,7 @@ describe('NodeUtility', () => {
 				attr1.value = 'bar';
 				attr2.value = 'bar';
 
-				expect(NodeUtility.nodeEquals(attr1, attr2)).toEqual(true);
+				expect(NodeUtility.isEqualNode(attr1, attr2)).toEqual(true);
 			});
 		});
 
@@ -314,21 +314,21 @@ describe('NodeUtility', () => {
 				const instruction1 = document.createProcessingInstruction('target1', 'foo');
 				const instruction2 = document.createProcessingInstruction('target2', 'foo');
 
-				expect(NodeUtility.nodeEquals(instruction1, instruction2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(instruction1, instruction2)).toEqual(false);
 			});
 
 			it('Returns false if data are different', () => {
 				const instruction1 = document.createProcessingInstruction('target', 'foo1');
 				const instruction2 = document.createProcessingInstruction('target', 'foo2');
 
-				expect(NodeUtility.nodeEquals(instruction1, instruction2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(instruction1, instruction2)).toEqual(false);
 			});
 
 			it('Returns true if processing instructions are equal', () => {
 				const instruction1 = document.createProcessingInstruction('target', 'foo');
 				const instruction2 = document.createProcessingInstruction('target', 'foo');
 
-				expect(NodeUtility.nodeEquals(instruction1, instruction2)).toEqual(true);
+				expect(NodeUtility.isEqualNode(instruction1, instruction2)).toEqual(true);
 			});
 		});
 
@@ -337,14 +337,14 @@ describe('NodeUtility', () => {
 				const comment1 = document.createComment('foo1');
 				const comment2 = document.createComment('foo2');
 
-				expect(NodeUtility.nodeEquals(comment1, comment2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(comment1, comment2)).toEqual(false);
 			});
 
 			it('Returns true if comments are equal', () => {
 				const comment1 = document.createComment('foo');
 				const comment2 = document.createComment('foo');
 
-				expect(NodeUtility.nodeEquals(comment1, comment2)).toEqual(true);
+				expect(NodeUtility.isEqualNode(comment1, comment2)).toEqual(true);
 			});
 		});
 
@@ -353,14 +353,14 @@ describe('NodeUtility', () => {
 				const textNode1 = document.createTextNode('foo1');
 				const textNode2 = document.createTextNode('foo2');
 
-				expect(NodeUtility.nodeEquals(textNode1, textNode2)).toEqual(false);
+				expect(NodeUtility.isEqualNode(textNode1, textNode2)).toEqual(false);
 			});
 
 			it('Returns true if text nodes are equal', () => {
 				const textNode1 = document.createTextNode('foo');
 				const textNode2 = document.createTextNode('foo');
 
-				expect(NodeUtility.nodeEquals(textNode1, textNode2)).toEqual(true);
+				expect(NodeUtility.isEqualNode(textNode1, textNode2)).toEqual(true);
 			});
 		});
 	});