@trackunit/react-vite-test-setup 0.0.49-alpha-df0e8d549b3.0 → 0.0.50

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/index.cjs.js CHANGED
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ var react = require('@testing-library/react');
4
+ var vitest = require('vitest');
3
5
  require('vitest-canvas-mock');
4
6
  var failOnConsole = require('vitest-fail-on-console');
5
7
  var jsxRuntime = require('react/jsx-runtime');
6
- var vitest = require('vitest');
7
8
  require('@testing-library/jest-dom/vitest');
8
- var react$1 = require('@testing-library/react');
9
9
  var util = require('util');
10
- var react = require('react');
10
+ var react$1 = require('react');
11
11
  var reactI18next = require('react-i18next');
12
12
  var polyfill = require('@js-temporal/polyfill');
13
13
  var web = require('@react-spring/web');
@@ -32,6 +32,66 @@ function _interopNamespaceDefault(e) {
32
32
 
33
33
  var reactI18next__namespace = /*#__PURE__*/_interopNamespaceDefault(reactI18next);
34
34
 
35
+ // Tracks the decorators we've installed so repeated `setupReactTestingLibrary()`
36
+ // calls don't stack the decorator on top of itself.
37
+ const reliableAsyncWrappers = new WeakSet();
38
+ /**
39
+ * Makes React Testing Library's async utilities (`waitFor`, `findBy*`,
40
+ * `waitForElementToBeRemoved`) poll in real wall-clock time even though
41
+ * `setupTimeAndLanguage` collapses the global `setTimeout`/`setInterval` to fire
42
+ * at 0ms.
43
+ *
44
+ * Every RTL async utility funnels through the configurable `asyncWrapper`:
45
+ * `@testing-library/react` installs an `act`-based one on import, and
46
+ * `@testing-library/dom`'s `waitFor` — plus `findBy*` and
47
+ * `waitForElementToBeRemoved`, which build on the module-internal `waitFor` —
48
+ * run their poll/timeout loop inside it. We decorate that single seam: for the
49
+ * duration of each async-utility call we temporarily restore the real timers
50
+ * (`globalThis.ORG_setTimeout`/`ORG_setInterval`), then put the collapsed 0ms
51
+ * timers back in a `finally`. Timers stay instant everywhere else, so debounces
52
+ * and animations still resolve immediately and the suite does not slow down.
53
+ *
54
+ * Guards:
55
+ * - Delegates unchanged when fake timers are active (`vi.isFakeTimers()`), so
56
+ * opt-in fake-timer tests keep RTL's fake-timer path.
57
+ * - No-ops the timer swap when `ORG_setTimeout` is absent (projects that don't
58
+ * collapse timers), leaving behaviour unchanged there.
59
+ * - Idempotent: repeated calls don't stack decorators.
60
+ *
61
+ * Must run after RTL's `act` wrapper is installed, i.e. from
62
+ * `setupReactTestingLibrary()`.
63
+ */
64
+ const configureReliableAsyncUtils = () => {
65
+ const originalAsyncWrapper = react.getConfig().asyncWrapper;
66
+ if (reliableAsyncWrappers.has(originalAsyncWrapper)) {
67
+ return;
68
+ }
69
+ const reliableAsyncWrapper = async (cb) => {
70
+ const orgSetTimeout = globalThis.ORG_setTimeout;
71
+ const orgSetInterval = globalThis.ORG_setInterval;
72
+ // Preserve fake-timer tests, and don't touch projects that never collapsed
73
+ // timers in the first place.
74
+ if (vitest.vi.isFakeTimers() || orgSetTimeout === undefined) {
75
+ return originalAsyncWrapper(cb);
76
+ }
77
+ const collapsedSetTimeout = global.setTimeout;
78
+ const collapsedSetInterval = global.setInterval;
79
+ global.setTimeout = orgSetTimeout;
80
+ if (orgSetInterval !== undefined) {
81
+ global.setInterval = orgSetInterval;
82
+ }
83
+ try {
84
+ return await originalAsyncWrapper(cb);
85
+ }
86
+ finally {
87
+ global.setTimeout = collapsedSetTimeout;
88
+ global.setInterval = collapsedSetInterval;
89
+ }
90
+ };
91
+ reliableAsyncWrappers.add(reliableAsyncWrapper);
92
+ react.configure({ asyncWrapper: reliableAsyncWrapper });
93
+ };
94
+
35
95
  /**
36
96
  * Sets up a mock implementation for HTML Canvas API in testing environments.
37
97
  *
@@ -599,13 +659,13 @@ const setupTranslations = () => {
599
659
  }
600
660
  return Object.keys(reactNodes).map((key, i) => {
601
661
  const child = reactNodes[key];
602
- const isElement = react.isValidElement(child);
662
+ const isElement = react$1.isValidElement(child);
603
663
  if (typeof child === "string") {
604
664
  return child;
605
665
  }
606
666
  if (hasChildren(child)) {
607
667
  const inner = renderNodes(getChildren(child));
608
- return react.cloneElement(child, { ...child.props, key: i }, inner);
668
+ return react$1.cloneElement(child, { ...child.props, key: i }, inner);
609
669
  }
610
670
  if (typeof child === "object" && !isElement) {
611
671
  return Object.keys(child).reduce((str, childKey) => `${str}${child[childKey]}`, "");
@@ -741,7 +801,7 @@ const installPostMessagePolyfill = () => {
741
801
  * @returns {Promise<void>} - Returns a promise that resolves after the wait time.
742
802
  */
743
803
  const flushPromisesInAct = (waitTimeInMS = 0) => {
744
- return react$1.act(() => {
804
+ return react.act(() => {
745
805
  return new Promise(resolve => {
746
806
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
747
807
  if (global.ORG_setTimeout) {
@@ -764,7 +824,7 @@ vitest.afterEach(async () => {
764
824
  // `vi.useRealTimers()` is a no-op when no fake timers are installed.
765
825
  vitest.vi.useRealTimers();
766
826
  vitest.vi.clearAllMocks();
767
- react$1.cleanup();
827
+ react.cleanup();
768
828
  await flushPromisesInAct();
769
829
  });
770
830
  const setupResponseForTanstackRouter = () => {
@@ -973,6 +1033,11 @@ const setupReactTestingLibrary = () => {
973
1033
  setupResizeObserver();
974
1034
  setupIntersectionObserver();
975
1035
  installPostMessagePolyfill();
1036
+ // Make RTL's async utilities (waitFor/findBy*/waitForElementToBeRemoved) wait
1037
+ // in real wall-clock time despite the 0ms timer collapse from
1038
+ // `setupTimeAndLanguage`. Runs last so RTL's `act` asyncWrapper is already
1039
+ // installed before we decorate it. See `configureReliableAsyncUtils`.
1040
+ configureReliableAsyncUtils();
976
1041
  };
977
1042
 
978
1043
  /**
@@ -1292,6 +1357,7 @@ const setupTanstackReactRouter = () => {
1292
1357
  }));
1293
1358
  };
1294
1359
 
1360
+ exports.configureReliableAsyncUtils = configureReliableAsyncUtils;
1295
1361
  exports.createMockClickEvent = createMockClickEvent;
1296
1362
  exports.createMockMapboxMap = createMockMapboxMap;
1297
1363
  exports.setupAllMocks = setupAllMocks;
package/index.esm.js CHANGED
@@ -1,9 +1,9 @@
1
+ import { getConfig, configure, cleanup, act } from '@testing-library/react';
2
+ import { vi, beforeEach, afterEach } from 'vitest';
1
3
  import 'vitest-canvas-mock';
2
4
  import failOnConsole from 'vitest-fail-on-console';
3
5
  import { jsx, Fragment } from 'react/jsx-runtime';
4
- import { vi, beforeEach, afterEach } from 'vitest';
5
6
  import '@testing-library/jest-dom/vitest';
6
- import { cleanup, act } from '@testing-library/react';
7
7
  import { TextEncoder, TextDecoder } from 'util';
8
8
  import { isValidElement, cloneElement } from 'react';
9
9
  import * as reactI18next from 'react-i18next';
@@ -11,6 +11,66 @@ import { Temporal } from '@js-temporal/polyfill';
11
11
  import { Globals } from '@react-spring/web';
12
12
  import { WritableStream, TransformStream } from 'web-streams-polyfill';
13
13
 
14
+ // Tracks the decorators we've installed so repeated `setupReactTestingLibrary()`
15
+ // calls don't stack the decorator on top of itself.
16
+ const reliableAsyncWrappers = new WeakSet();
17
+ /**
18
+ * Makes React Testing Library's async utilities (`waitFor`, `findBy*`,
19
+ * `waitForElementToBeRemoved`) poll in real wall-clock time even though
20
+ * `setupTimeAndLanguage` collapses the global `setTimeout`/`setInterval` to fire
21
+ * at 0ms.
22
+ *
23
+ * Every RTL async utility funnels through the configurable `asyncWrapper`:
24
+ * `@testing-library/react` installs an `act`-based one on import, and
25
+ * `@testing-library/dom`'s `waitFor` — plus `findBy*` and
26
+ * `waitForElementToBeRemoved`, which build on the module-internal `waitFor` —
27
+ * run their poll/timeout loop inside it. We decorate that single seam: for the
28
+ * duration of each async-utility call we temporarily restore the real timers
29
+ * (`globalThis.ORG_setTimeout`/`ORG_setInterval`), then put the collapsed 0ms
30
+ * timers back in a `finally`. Timers stay instant everywhere else, so debounces
31
+ * and animations still resolve immediately and the suite does not slow down.
32
+ *
33
+ * Guards:
34
+ * - Delegates unchanged when fake timers are active (`vi.isFakeTimers()`), so
35
+ * opt-in fake-timer tests keep RTL's fake-timer path.
36
+ * - No-ops the timer swap when `ORG_setTimeout` is absent (projects that don't
37
+ * collapse timers), leaving behaviour unchanged there.
38
+ * - Idempotent: repeated calls don't stack decorators.
39
+ *
40
+ * Must run after RTL's `act` wrapper is installed, i.e. from
41
+ * `setupReactTestingLibrary()`.
42
+ */
43
+ const configureReliableAsyncUtils = () => {
44
+ const originalAsyncWrapper = getConfig().asyncWrapper;
45
+ if (reliableAsyncWrappers.has(originalAsyncWrapper)) {
46
+ return;
47
+ }
48
+ const reliableAsyncWrapper = async (cb) => {
49
+ const orgSetTimeout = globalThis.ORG_setTimeout;
50
+ const orgSetInterval = globalThis.ORG_setInterval;
51
+ // Preserve fake-timer tests, and don't touch projects that never collapsed
52
+ // timers in the first place.
53
+ if (vi.isFakeTimers() || orgSetTimeout === undefined) {
54
+ return originalAsyncWrapper(cb);
55
+ }
56
+ const collapsedSetTimeout = global.setTimeout;
57
+ const collapsedSetInterval = global.setInterval;
58
+ global.setTimeout = orgSetTimeout;
59
+ if (orgSetInterval !== undefined) {
60
+ global.setInterval = orgSetInterval;
61
+ }
62
+ try {
63
+ return await originalAsyncWrapper(cb);
64
+ }
65
+ finally {
66
+ global.setTimeout = collapsedSetTimeout;
67
+ global.setInterval = collapsedSetInterval;
68
+ }
69
+ };
70
+ reliableAsyncWrappers.add(reliableAsyncWrapper);
71
+ configure({ asyncWrapper: reliableAsyncWrapper });
72
+ };
73
+
14
74
  /**
15
75
  * Sets up a mock implementation for HTML Canvas API in testing environments.
16
76
  *
@@ -952,6 +1012,11 @@ const setupReactTestingLibrary = () => {
952
1012
  setupResizeObserver();
953
1013
  setupIntersectionObserver();
954
1014
  installPostMessagePolyfill();
1015
+ // Make RTL's async utilities (waitFor/findBy*/waitForElementToBeRemoved) wait
1016
+ // in real wall-clock time despite the 0ms timer collapse from
1017
+ // `setupTimeAndLanguage`. Runs last so RTL's `act` asyncWrapper is already
1018
+ // installed before we decorate it. See `configureReliableAsyncUtils`.
1019
+ configureReliableAsyncUtils();
955
1020
  };
956
1021
 
957
1022
  /**
@@ -1271,4 +1336,4 @@ const setupTanstackReactRouter = () => {
1271
1336
  }));
1272
1337
  };
1273
1338
 
1274
- export { createMockClickEvent, createMockMapboxMap, setupAllMocks, setupBasicMocks, setupCanvasMock, setupDefaultMocks, setupFailOnConsole, setupGoogleMaps, setupHelmetMock, setupIntersectionObserver, setupMapbox, setupMatchMediaMock, setupReactTestingLibrary, setupReactVirtualizedAutoSizer, setupResizeObserver, setupTanstackReactRouter, setupTanstackReactVirtual, setupTimeAndLanguage, setupTimeZone, setupTranslations, setupWebStreams };
1339
+ export { configureReliableAsyncUtils, createMockClickEvent, createMockMapboxMap, setupAllMocks, setupBasicMocks, setupCanvasMock, setupDefaultMocks, setupFailOnConsole, setupGoogleMaps, setupHelmetMock, setupIntersectionObserver, setupMapbox, setupMatchMediaMock, setupReactTestingLibrary, setupReactVirtualizedAutoSizer, setupResizeObserver, setupTanstackReactRouter, setupTanstackReactVirtual, setupTimeAndLanguage, setupTimeZone, setupTranslations, setupWebStreams };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@trackunit/react-vite-test-setup",
3
3
  "description": "Test setup utilities for React applications",
4
- "version": "0.0.49-alpha-df0e8d549b3.0",
4
+ "version": "0.0.50",
5
5
  "repository": "https://github.com/Trackunit/manager",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
7
7
  "engines": {
@@ -0,0 +1,31 @@
1
+ declare global {
2
+ var ORG_setTimeout: typeof setTimeout | undefined;
3
+ var ORG_setInterval: typeof setInterval | undefined;
4
+ }
5
+ /**
6
+ * Makes React Testing Library's async utilities (`waitFor`, `findBy*`,
7
+ * `waitForElementToBeRemoved`) poll in real wall-clock time even though
8
+ * `setupTimeAndLanguage` collapses the global `setTimeout`/`setInterval` to fire
9
+ * at 0ms.
10
+ *
11
+ * Every RTL async utility funnels through the configurable `asyncWrapper`:
12
+ * `@testing-library/react` installs an `act`-based one on import, and
13
+ * `@testing-library/dom`'s `waitFor` — plus `findBy*` and
14
+ * `waitForElementToBeRemoved`, which build on the module-internal `waitFor` —
15
+ * run their poll/timeout loop inside it. We decorate that single seam: for the
16
+ * duration of each async-utility call we temporarily restore the real timers
17
+ * (`globalThis.ORG_setTimeout`/`ORG_setInterval`), then put the collapsed 0ms
18
+ * timers back in a `finally`. Timers stay instant everywhere else, so debounces
19
+ * and animations still resolve immediately and the suite does not slow down.
20
+ *
21
+ * Guards:
22
+ * - Delegates unchanged when fake timers are active (`vi.isFakeTimers()`), so
23
+ * opt-in fake-timer tests keep RTL's fake-timer path.
24
+ * - No-ops the timer swap when `ORG_setTimeout` is absent (projects that don't
25
+ * collapse timers), leaving behaviour unchanged there.
26
+ * - Idempotent: repeated calls don't stack decorators.
27
+ *
28
+ * Must run after RTL's `act` wrapper is installed, i.e. from
29
+ * `setupReactTestingLibrary()`.
30
+ */
31
+ export declare const configureReliableAsyncUtils: () => void;
package/src/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./configureReliableAsyncUtils";
1
2
  export * from "./setupAllMocks";
2
3
  export * from "./setupBasicMocks";
3
4
  export * from "./setupCanvasMock";