@stencil/vitest 1.1.21 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import './testing/matchers.js';
2
2
  import './testing/snapshot-serializer.js';
3
3
  export { h } from '@stencil/core';
4
- export { render } from './testing/render.js';
4
+ export { render, waitForStable } from './testing/render.js';
5
5
  export { serializeHtml, prettifyHtml, SerializeOptions } from './testing/html-serializer.js';
6
6
  export type { RenderOptions, RenderResult } from './types.js';
7
7
  //# sourceMappingURL=core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AACA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kCAAkC,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAC7F,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AACA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kCAAkC,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAC7F,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
package/dist/core.js CHANGED
@@ -2,5 +2,5 @@
2
2
  import './testing/matchers.js';
3
3
  import './testing/snapshot-serializer.js';
4
4
  export { h } from '@stencil/core';
5
- export { render } from './testing/render.js';
5
+ export { render, waitForStable } from './testing/render.js';
6
6
  export { serializeHtml, prettifyHtml } from './testing/html-serializer.js';
@@ -1,8 +1,26 @@
1
1
  import type { RenderResult } from '../types.js';
2
2
  interface RenderOptions {
3
+ /**
4
+ * Whether to clear existing stage containers before rendering. Defaults to true.
5
+ */
3
6
  clearStage?: boolean;
7
+ /**
8
+ * Attributes to set on the stage container element. Defaults to { class: 'stencil-component-stage' }.
9
+ */
4
10
  stageAttrs?: Record<string, string>;
11
+ /**
12
+ * Wait for the component to be fully rendered before returning.
13
+ * In browser mode, this polls until the element has dimensions.
14
+ * Defaults to true.
15
+ */
16
+ waitForReady?: boolean;
5
17
  }
18
+ /**
19
+ * Poll until element has dimensions (is rendered/visible in real browser).
20
+ * Accepts either an Element or a CSS selector string.
21
+ * If a selector is provided, waits for the element to appear in the DOM first.
22
+ */
23
+ export declare function waitForStable(elementOrSelector: Element | string, timeout?: number): Promise<void>;
6
24
  /**
7
25
  * Render using Stencil's render
8
26
  */
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/testing/render.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,aAAa,CAAC;AAE1D,UAAU,aAAa;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAKD;;GAEG;AACH,wBAAsB,MAAM,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,CAAC,GAAG,GAAG,EACvE,KAAK,EAAE,GAAG,EACV,OAAO,GAAE,aAGR,GACA,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAkI7B"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/testing/render.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,aAAa,CAAC;AAE1D,UAAU,aAAa;IACrB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAyBD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,iBAAiB,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCtG;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,CAAC,GAAG,GAAG,EACvE,KAAK,EAAE,GAAG,EACV,OAAO,GAAE,aAGR,GACA,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CA6I7B"}
@@ -1,6 +1,59 @@
1
1
  import { render as stencilRender } from '@stencil/core';
2
2
  // Track event spies
3
3
  const eventSpies = new WeakMap();
4
+ /**
5
+ * Detect if we're running in a real browser vs a mock DOM environment
6
+ */
7
+ function isRealBrowser() {
8
+ if (typeof window === 'undefined')
9
+ return false;
10
+ if (!navigator.webdriver)
11
+ return false;
12
+ const ua = navigator?.userAgent ?? '';
13
+ if (ua.includes('jsdom'))
14
+ return false;
15
+ if ('happyDOM' in window)
16
+ return false;
17
+ if ('__stencil_mock_doc__' in window)
18
+ return false;
19
+ if (typeof process !== 'undefined' && process.versions?.node) {
20
+ return false;
21
+ }
22
+ return true;
23
+ }
24
+ /**
25
+ * Poll until element has dimensions (is rendered/visible in real browser).
26
+ * Accepts either an Element or a CSS selector string.
27
+ * If a selector is provided, waits for the element to appear in the DOM first.
28
+ */
29
+ export async function waitForStable(elementOrSelector, timeout = 5000) {
30
+ if (!isRealBrowser()) {
31
+ console.warn('[waitForStable] Only works in real browser environments');
32
+ return;
33
+ }
34
+ const start = Date.now();
35
+ // Resolve element from selector if needed
36
+ let element = typeof elementOrSelector === 'string' ? null : elementOrSelector;
37
+ // If an Element was passed, verify it's in the DOM
38
+ if (element && !document.contains(element)) {
39
+ console.warn('[waitForStable] Element is not attached to the DOM');
40
+ }
41
+ while (Date.now() - start < timeout) {
42
+ // If we have a selector, try to find the element
43
+ if (typeof elementOrSelector === 'string' && !element) {
44
+ element = document.querySelector(elementOrSelector);
45
+ }
46
+ // If we have an element, check if it has dimensions
47
+ if (element) {
48
+ const rect = element.getBoundingClientRect();
49
+ if (rect.width > 0 && rect.height > 0) {
50
+ return;
51
+ }
52
+ }
53
+ await new Promise((r) => requestAnimationFrame(r));
54
+ }
55
+ // Don't throw on timeout - element might be intentionally zero-sized or not found
56
+ }
4
57
  /**
5
58
  * Render using Stencil's render
6
59
  */
@@ -8,7 +61,6 @@ export async function render(vnode, options = {
8
61
  clearStage: true,
9
62
  stageAttrs: { class: 'stencil-component-stage' },
10
63
  }) {
11
- // Use Stencil's render which handles VNodes properly in the browser
12
64
  const container = document.createElement('div');
13
65
  Object.entries(options.stageAttrs || {}).forEach(([key, value]) => {
14
66
  container.setAttribute(key, value);
@@ -19,6 +71,7 @@ export async function render(vnode, options = {
19
71
  existingStages.forEach((stage) => stage.remove());
20
72
  }
21
73
  document.body.appendChild(container);
74
+ // Use Stencil's render which handles VNodes properly in the browser
22
75
  await stencilRender(vnode, container);
23
76
  // Get the rendered element
24
77
  const element = container.firstElementChild;
@@ -29,6 +82,7 @@ export async function render(vnode, options = {
29
82
  if (typeof element.componentOnReady === 'function') {
30
83
  await element.componentOnReady();
31
84
  }
85
+ // Define waitForChanges first so we can use it in the ready check
32
86
  function waitForChanges(documentElement = element) {
33
87
  return new Promise((resolve) => {
34
88
  // Wait for Stencil's RAF-based update cycle
@@ -39,16 +93,15 @@ export async function render(vnode, options = {
39
93
  const waitComponentOnReady = (elm, promises) => {
40
94
  if (!elm)
41
95
  return;
42
- if ('shadowRoot' in elm) {
96
+ if ('shadowRoot' in elm && elm.shadowRoot) {
43
97
  waitComponentOnReady(elm.shadowRoot, promises);
44
98
  }
45
99
  const children = elm.children;
46
100
  const len = children.length;
47
101
  for (let i = 0; i < len; i++) {
48
102
  const childElm = children[i];
49
- const childStencilElm = childElm;
50
- if (childElm.tagName.includes('-') && typeof childStencilElm.componentOnReady === 'function') {
51
- promises.push(childStencilElm.componentOnReady().then(() => { }));
103
+ if (childElm.tagName.includes('-') && typeof childElm.componentOnReady === 'function') {
104
+ promises.push(childElm.componentOnReady().then(() => { }));
52
105
  }
53
106
  waitComponentOnReady(childElm, promises);
54
107
  }
@@ -61,6 +114,15 @@ export async function render(vnode, options = {
61
114
  });
62
115
  });
63
116
  }
117
+ // Wait for component to be fully rendered if requested (default: true)
118
+ if (options.waitForReady !== false) {
119
+ if (isRealBrowser()) {
120
+ // In real browser, poll until element has dimensions
121
+ await waitForStable(element);
122
+ }
123
+ // Always wait for Stencil's update cycle to complete
124
+ await waitForChanges();
125
+ }
64
126
  const setProps = async (newProps) => {
65
127
  Object.entries(newProps).forEach(([key, value]) => {
66
128
  element[key] = value;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/stenciljs/vitest"
6
6
  },
7
- "version": "1.1.21",
7
+ "version": "1.3.0",
8
8
  "description": "First-class testing utilities for Stencil design systems with Vitest",
9
9
  "license": "MIT",
10
10
  "type": "module",
@@ -97,7 +97,7 @@
97
97
  "dependencies": {
98
98
  "jiti": "^2.6.1",
99
99
  "local-pkg": "^1.1.2",
100
- "vitest-environment-stencil": "1.1.21"
100
+ "vitest-environment-stencil": "1.3.0"
101
101
  },
102
102
  "devDependencies": {
103
103
  "@eslint/js": "^9.39.2",