ionic-team / stencil

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
https://stenciljs.com
Other
12.52k stars 782 forks source link

bug: Errors when using testing-library/dom #5619

Open angelo-v opened 6 months ago

angelo-v commented 6 months ago

Prerequisites

Stencil Version

4.14.0

Current Behavior

Following up on https://github.com/ionic-team/stencil/issues/5252#issuecomment-1948923905: When using testing-library/dom with stencil errors occur when using getByRole and getByLabelText

getByRole

Right-hand side of 'instanceof' is not an object

getByLabelText:

TestingLibraryElementError: Found a label with the text of: Test, however no form control was found associated to that label. Make sure you're using the "for" attribute or "aria-labelledby" attribute correctly.

Expected Behavior

Both methods should find the respective element without errors

System Info

@testing-library/dom: 9.3.4
@testing-library/jest-dom: 6.4.2
▶ npx stencil info

      System: node 21.6.1
    Compiler: [...]/node_modules/@stencil/core/compiler/stencil.js
       Build: 1711981251
     Stencil: 4.14.0 🚡
  TypeScript: 5.4.3
      Rollup: 2.56.3
      Parse5: 7.1.2
      jQuery: 4.0.0-pre
      Terser: 5.30.0

Steps to Reproduce

see repo

Code Reproduction URL

https://github.com/angelo-v/stencil-testing-library-dom-error/blob/8cc444465b5db82efd6ec7a71c00a7b60f8e08e4/src/components/my-component/my-component.spec.ts

Additional Information

No response

christian-bromann commented 6 months ago

@angelo-v thanks for raising the issue and for providing a reproducible example. I looked into this and it seems that Stencils Mock Doc component doesn't have SVGElement as a global accessible class. This can be patched by adding it to the setupGlobal method:

diff --git a/src/mock-doc/global.ts b/src/mock-doc/global.ts
index ba535ea51..ebb82aa03 100644
--- a/src/mock-doc/global.ts
+++ b/src/mock-doc/global.ts
@@ -10,6 +10,7 @@ import {
   MockMetaElement,
   MockScriptElement,
   MockStyleElement,
+  MockSVGElement,
   MockTemplateElement,
   MockTitleElement,
   MockUListElement,
@@ -147,6 +148,7 @@ const WINDOW_PROPS = [
   'Event',
   'Element',
   'HTMLElement',
+  'SVGElement',
   'Node',
   'NodeList',
   'FocusEvent',
@@ -179,4 +181,6 @@ const GLOBAL_CONSTRUCTORS: [string, any][] = [
   ['HTMLTemplateElement', MockTemplateElement],
   ['HTMLTitleElement', MockTitleElement],
   ['HTMLUListElement', MockUListElement],
+
+  ['SVGElement', MockSVGElement],
 ];

However this will still fail as Testing Library verifies if given nodes are instanceof HTMLElement or SVGElement. For some reasons the instances fetched from Testing Library and the virtual DOM are not and instance of these classes, e.g. their mocked representations.

I will label this issue to move it into our backlog so we can take a look at this at some point. In the meantime I recommend to take a look at some alternatives we provide for testing Stencil components: via WebdriverIO or via Playwright.

angelo-v commented 5 months ago

I will label this issue to move it into our backlog so we can take a look at this at some point. In the meantime I recommend to take a look at some alternatives we provide for testing Stencil components: via WebdriverIO or via Playwright.

Thanks for adding this to your backlog. Being able to test with testing-library is an important level in my testing pyramid. I am already using playwright at an e2e level. It might also be suitable for integration level. But for unit testing I try to only render a single component and test the dom from a user perspective using testing library. For now I will have to stick with native dom operations like querySelector, which does it's job but is not as readable and user-centered as the testing-library approach.