Repository: jestjs/jest (TypeScript)

Issue:
[Bug]: Jest fails to serialize custom elements with anonymous constructors
### Version

latest

### Steps to reproduce

Reproduction here:

https://github.com/testing-library/dom-testing-library/issues/1191#issue-1465496571

```js
class MyElement extends HTMLElement {}
window.customElements.define("my-element", class extends MyElement {})
window.customElements.get("my-element").name // => ""

export default () => <my-element></my-element>

test("Render app", () => {
  render(<App />)
  snapshot()
})
```

### Expected behavior

Should properly serialize a custom element to HTML tags

### Actual behavior

Renders the entire JS object

https://github.com/KonnorRogers/shoelace-nextjs-lazy/blob/main/app/__snapshots__/page.test.tsx.snap

### Additional context

The `test` function in pretty-format expects the constructor to have a name

https://github.com/jestjs/jest/blob/c54bccd657fb4cf060898717c09f633b4da3eec4/packages/pretty-format/src/plugins/DOMElement.ts#L49-L50

```diff
- export const test: NewPlugin['test'] = (val: any) =>
-  val?.constructor?.name && testNode(val);
+ export const test: NewPlugin['test'] = (val: any) =>
+  val?.constructor && testNode(val);
```

### Environment

```shell
System:
    OS: macOS 14.4
    CPU: (8) arm64 Apple M1 Pro
  Binaries:
    Node: 20.9.0 - ~/.asdf/installs/nodejs/20.9.0/bin/node
    Yarn: 4.0.1 - ~/.asdf/installs/nodejs/20.9.0/bin/yarn
    npm: 10.1.0 - ~/.asdf/plugins/nodejs/shims/npm
    pnpm: 9.1.1 - ~/.asdf/installs/nodejs/20.9.0/bin/pnpm
  npmPackages:
    jest: ^29.7.0 => 29.7.0
```



Hints:

Patch:
diff --git a/packages/pretty-format/src/plugins/DOMElement.ts b/packages/pretty-format/src/plugins/DOMElement.ts
--- a/packages/pretty-format/src/plugins/DOMElement.ts
+++ b/packages/pretty-format/src/plugins/DOMElement.ts
@@ -30,16 +30,21 @@ const testHasAttribute = (val: any) => {
   }
 };
 
+const isCustomElement = (val: any) => {
+  const tagName = val?.tagName;
+  return (
+    (typeof tagName === 'string' && tagName.includes('-')) ||
+    testHasAttribute(val)
+  );
+};
+
 const testNode = (val: any) => {
   const constructorName = val.constructor.name;
-  const {nodeType, tagName} = val;
-  const isCustomElement =
-    (typeof tagName === 'string' && tagName.includes('-')) ||
-    testHasAttribute(val);
+  const {nodeType} = val;
 
   return (
     (nodeType === ELEMENT_NODE &&
-      (ELEMENT_REGEXP.test(constructorName) || isCustomElement)) ||
+      (ELEMENT_REGEXP.test(constructorName) || isCustomElement(val))) ||
     (nodeType === TEXT_NODE && constructorName === 'Text') ||
     (nodeType === COMMENT_NODE && constructorName === 'Comment') ||
     (nodeType === FRAGMENT_NODE && constructorName === 'DocumentFragment')
@@ -47,7 +52,7 @@ const testNode = (val: any) => {
 };
 
 export const test: NewPlugin['test'] = (val: any) =>
-  val?.constructor?.name && testNode(val);
+  (val?.constructor?.name || isCustomElement(val)) && testNode(val);
 
 type HandledType = Element | Text | Comment | DocumentFragment;
 


Test patch:
diff --git a/packages/pretty-format/src/__tests__/DOMElement.test.ts b/packages/pretty-format/src/__tests__/DOMElement.test.ts
--- a/packages/pretty-format/src/__tests__/DOMElement.test.ts
+++ b/packages/pretty-format/src/__tests__/DOMElement.test.ts
@@ -357,12 +357,14 @@ Testing.`;
     customElements.define('custom-paragraph', CustomParagraphElement, {
       extends: 'p',
     });
+    customElements.define('anonymous-element', class extends HTMLElement {});
 
     const parent = document.createElement('div');
     parent.innerHTML = [
       '<custom-element></custom-element>',
       '<custom-extended-element></custom-extended-element>',
       '<p is="custom-paragraph"></p>',
+      '<anonymous-element></anonymous-element>',
     ].join('');
 
     expect(parent).toPrettyPrintTo(
@@ -373,6 +375,7 @@ Testing.`;
         '  <p',
         '    is="custom-paragraph"',
         '  />',
+        '  <anonymous-element />',
         '</div>',
       ].join('\n'),
     );