anu-verzum 1.21.7 → 1.22.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/README.md +34 -6
- package/dist/core/components/AnulyticsProvider.d.ts +3 -0
- package/dist/core/components/AnulyticsProvider.js +10 -2
- package/dist/core/components/History.d.ts +3 -0
- package/dist/core/components/History.js +10 -2
- package/dist/core/components/Intl.d.ts +3 -0
- package/dist/core/components/Intl.js +13 -2
- package/dist/core/elements.d.ts +1 -1
- package/dist/core/reconciler.d.ts +5 -0
- package/dist/core/reconciler.js +41 -2
- package/dist/testing/__tests__/smoke.test.d.ts +1 -0
- package/dist/testing/__tests__/smoke.test.js +180 -0
- package/dist/testing/act.d.ts +4 -0
- package/dist/testing/act.js +42 -0
- package/dist/testing/cleanup.d.ts +3 -0
- package/dist/testing/cleanup.js +32 -0
- package/dist/testing/events/fireEvent.d.ts +17 -0
- package/dist/testing/events/fireEvent.js +45 -0
- package/dist/testing/events/userEvent.d.ts +12 -0
- package/dist/testing/events/userEvent.js +67 -0
- package/dist/testing/globals.d.js +1 -0
- package/dist/testing/index.d.ts +9 -0
- package/dist/testing/index.js +109 -0
- package/dist/testing/queries/byAltText.d.ts +2 -0
- package/dist/testing/queries/byAltText.js +15 -0
- package/dist/testing/queries/byLabelText.d.ts +2 -0
- package/dist/testing/queries/byLabelText.js +47 -0
- package/dist/testing/queries/byPlaceholderText.d.ts +2 -0
- package/dist/testing/queries/byPlaceholderText.js +15 -0
- package/dist/testing/queries/byRole.d.ts +2 -0
- package/dist/testing/queries/byRole.js +73 -0
- package/dist/testing/queries/byTestId.d.ts +2 -0
- package/dist/testing/queries/byTestId.js +11 -0
- package/dist/testing/queries/byText.d.ts +2 -0
- package/dist/testing/queries/byText.js +27 -0
- package/dist/testing/queries/byTitle.d.ts +2 -0
- package/dist/testing/queries/byTitle.js +15 -0
- package/dist/testing/queries/index.d.ts +2 -0
- package/dist/testing/queries/index.js +43 -0
- package/dist/testing/queries/queryBuilder.d.ts +2 -0
- package/dist/testing/queries/queryBuilder.js +36 -0
- package/dist/testing/render.d.ts +3 -0
- package/dist/testing/render.js +46 -0
- package/dist/testing/types.d.ts +59 -0
- package/dist/testing/types.js +5 -0
- package/dist/testing/waitFor.d.ts +3 -0
- package/dist/testing/waitFor.js +41 -0
- package/dist/testing/wrappers.d.ts +17 -0
- package/dist/testing/wrappers.js +46 -0
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h3>@author: <strong>Anubis-programmer</strong></h3>
|
|
6
6
|
<h3>@license: <strong>MIT</strong></h3>
|
|
7
|
-
<h3>@version: <strong>1.
|
|
7
|
+
<h3>@version: <strong>1.22.0</strong></h3>
|
|
8
8
|
|
|
9
9
|
<br>
|
|
10
10
|
|
|
@@ -17,6 +17,7 @@ A lightweight React-inspired UI library for building component-based web applica
|
|
|
17
17
|
- Client-side routing over the History API
|
|
18
18
|
- Context API, i18n (Intl), feature flags, and built-in event analytics (Anulytics)
|
|
19
19
|
- Ships with TypeScript declaration files — no `@types` package needed
|
|
20
|
+
- Built-in testing companion — **Anu Testing Library (ATL)** shipped as `anu-verzum/testing`
|
|
20
21
|
|
|
21
22
|
<br>
|
|
22
23
|
<hr>
|
|
@@ -188,16 +189,43 @@ The following types are exported from `anu-verzum` for use in consumer projects:
|
|
|
188
189
|
#### Library development scripts
|
|
189
190
|
|
|
190
191
|
```bash
|
|
191
|
-
npm run clean
|
|
192
|
-
npm run build
|
|
193
|
-
npm run typecheck
|
|
194
|
-
npm run lint
|
|
195
|
-
npm run format
|
|
192
|
+
npm run clean # Delete dist/ entirely
|
|
193
|
+
npm run build # Clean, compile TypeScript sources to dist/, and emit .d.ts files
|
|
194
|
+
npm run typecheck # Type-check without emitting any output
|
|
195
|
+
npm run lint # Run ESLint on all source files
|
|
196
|
+
npm run format # Format all source files with Prettier
|
|
197
|
+
npm test # Run the Anu Testing Library test suite with Jest
|
|
198
|
+
npm run test:watch # Run Jest in interactive watch mode
|
|
199
|
+
npm run test:coverage # Run Jest and generate a coverage report
|
|
196
200
|
```
|
|
197
201
|
|
|
198
202
|
<br>
|
|
199
203
|
<hr>
|
|
200
204
|
|
|
205
|
+
<h2 id="testing">Testing</h2>
|
|
206
|
+
|
|
207
|
+
ANUVerzum ships a built-in testing library — **Anu Testing Library (ATL)** — importable as `anu-verzum/testing`. It mirrors the philosophy of Testing Library: query the DOM the way a user would (by role, text, label), fire events, and assert on real output — no component internals, no custom matchers.
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import Anu from 'anu-verzum';
|
|
211
|
+
import { render, fireEvent } from 'anu-verzum/testing';
|
|
212
|
+
|
|
213
|
+
const { getByText, getByRole } = render(<Counter />);
|
|
214
|
+
fireEvent.click(getByRole('button'));
|
|
215
|
+
expect(getByText('Count: 1')).toBeDefined();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
If TypeScript reports that `describe`, `test`, or `expect` are not found, your `tsconfig.json` likely has an explicit `"types"` list. Add `"jest"` to it — and `"node"` if tests reference `process.env`:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{ "compilerOptions": { "types": ["node", "jest"] } }
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
See **[USERS_MANUAL.md — Testing](./documentation/USERS_MANUAL.md#testing)** for the full API reference and usage guide.
|
|
225
|
+
|
|
226
|
+
<br>
|
|
227
|
+
<hr>
|
|
228
|
+
|
|
201
229
|
<h2>Documentation</h2>
|
|
202
230
|
|
|
203
231
|
Full usage documentation, API reference, and code examples:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.trackStateChange = exports.trackRouteChange = exports.trackEvent = exports.default = void 0;
|
|
6
|
+
exports.trackStateChange = exports.trackRouteChange = exports.trackEvent = exports.default = exports.__testing = void 0;
|
|
7
7
|
var _Component = require("./Component");
|
|
8
8
|
var _serverApi = _interopRequireDefault(require("../../server-api/server-api"));
|
|
9
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -218,4 +218,12 @@ class AnulyticsProvider extends _Component.Component {
|
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
-
var _default = exports.default = AnulyticsProvider;
|
|
221
|
+
var _default = exports.default = AnulyticsProvider;
|
|
222
|
+
const __testing = exports.__testing = {
|
|
223
|
+
reset() {
|
|
224
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
AnulyticsState.setAnulyticsInstanceExist(false);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.goTo = exports.default = void 0;
|
|
6
|
+
exports.goTo = exports.default = exports.__testing = void 0;
|
|
7
7
|
var _elements = require("../elements");
|
|
8
8
|
var _Component = require("./Component");
|
|
9
9
|
var _AnulyticsProvider = require("./AnulyticsProvider");
|
|
@@ -210,4 +210,12 @@ const History = {
|
|
|
210
210
|
getUrlParams,
|
|
211
211
|
getAllUrlParamNames
|
|
212
212
|
};
|
|
213
|
-
var _default = exports.default = History;
|
|
213
|
+
var _default = exports.default = History;
|
|
214
|
+
const __testing = exports.__testing = {
|
|
215
|
+
reset() {
|
|
216
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
instances.length = 0;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = void 0;
|
|
6
|
+
exports.default = exports.__testing = void 0;
|
|
7
7
|
var _elements = require("../elements");
|
|
8
8
|
var _Context = require("./Context");
|
|
9
9
|
const _Intl = (0, _Context.createContext)({});
|
|
@@ -168,4 +168,15 @@ const Intl = {
|
|
|
168
168
|
formatMessage,
|
|
169
169
|
Provider: IntlProvider
|
|
170
170
|
};
|
|
171
|
-
var _default = exports.default = Intl;
|
|
171
|
+
var _default = exports.default = Intl;
|
|
172
|
+
const __testing = exports.__testing = {
|
|
173
|
+
reset() {
|
|
174
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
__messagesContext = {
|
|
178
|
+
locale: undefined,
|
|
179
|
+
messages: {}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
};
|
package/dist/core/elements.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type Ref<T> = {
|
|
|
12
12
|
};
|
|
13
13
|
export type FunctionComponent<P extends Props = Props> = (props: P) => AnuElement<any, any> | AnuElement<any, any>[] | string | number | boolean | null | undefined;
|
|
14
14
|
export type ComponentConstructor<P extends Props = Props> = new (props: P, context?: Record<string, any>) => any;
|
|
15
|
-
export type ElementType = string | FunctionComponent | ComponentConstructor
|
|
15
|
+
export type ElementType = string | FunctionComponent<any> | ComponentConstructor<any>;
|
|
16
16
|
export type AnuElement<P = Props, T extends ElementType = ElementType> = {
|
|
17
17
|
type: T;
|
|
18
18
|
props: P;
|
|
@@ -2,3 +2,8 @@ import { AnuElement, Ref } from './elements';
|
|
|
2
2
|
export declare const createRef: <T = any>() => Ref<T>;
|
|
3
3
|
export declare const scheduleUpdate: (instance: any, partialState: Record<string, any>, partialStateCallback?: (prevState: any, prevProps: any) => any) => void;
|
|
4
4
|
export declare const render: (elements: AnuElement | AnuElement[], containerDom: Element) => void;
|
|
5
|
+
export declare const unmountComponentAtNode: (containerDom: Element) => void;
|
|
6
|
+
export declare const __testing: {
|
|
7
|
+
flushSync(): void;
|
|
8
|
+
resetGlobals(): void;
|
|
9
|
+
};
|
package/dist/core/reconciler.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.scheduleUpdate = exports.render = exports.createRef = void 0;
|
|
6
|
+
exports.unmountComponentAtNode = exports.scheduleUpdate = exports.render = exports.createRef = exports.__testing = void 0;
|
|
7
7
|
var _domUtils = require("./domUtils");
|
|
8
8
|
const HOST_COMPONENT = 'host';
|
|
9
9
|
const CLASS_COMPONENT = 'class';
|
|
@@ -446,4 +446,43 @@ const render = (elements, containerDom) => {
|
|
|
446
446
|
});
|
|
447
447
|
requestIdleCallback(performWork);
|
|
448
448
|
};
|
|
449
|
-
exports.render = render;
|
|
449
|
+
exports.render = render;
|
|
450
|
+
const unmountComponentAtNode = containerDom => {
|
|
451
|
+
if (!containerDom._rootContainerFiber) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
updateQueue.push({
|
|
455
|
+
from: HOST_ROOT,
|
|
456
|
+
dom: containerDom,
|
|
457
|
+
newProps: {
|
|
458
|
+
children: []
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
requestIdleCallback(performWork);
|
|
462
|
+
};
|
|
463
|
+
exports.unmountComponentAtNode = unmountComponentAtNode;
|
|
464
|
+
const __testing = exports.__testing = {
|
|
465
|
+
flushSync() {
|
|
466
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
const syncDeadline = {
|
|
470
|
+
didTimeout: false,
|
|
471
|
+
timeRemaining: () => 999
|
|
472
|
+
};
|
|
473
|
+
while (updateQueue.length > 0 || nextUnitOfWork != null) {
|
|
474
|
+
workLoop(syncDeadline);
|
|
475
|
+
}
|
|
476
|
+
nextUnitOfWork = null;
|
|
477
|
+
pendingCommit = null;
|
|
478
|
+
},
|
|
479
|
+
resetGlobals() {
|
|
480
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
updateQueue.length = 0;
|
|
484
|
+
componentLifecyclesQueue.length = 0;
|
|
485
|
+
nextUnitOfWork = null;
|
|
486
|
+
pendingCommit = null;
|
|
487
|
+
}
|
|
488
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _index = _interopRequireWildcard(require("../../index"));
|
|
4
|
+
var _index2 = require("../index");
|
|
5
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
6
|
+
class Counter extends _index.Component {
|
|
7
|
+
state = {
|
|
8
|
+
count: 0
|
|
9
|
+
};
|
|
10
|
+
render() {
|
|
11
|
+
return _index.default.createElement('div', {}, _index.default.createElement('p', {}, `Count: ${this.state.count}`), _index.default.createElement('button', {
|
|
12
|
+
onClick: () => this.setState({
|
|
13
|
+
count: this.state.count + 1
|
|
14
|
+
})
|
|
15
|
+
}, 'Increment'));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const Greeting = ({
|
|
19
|
+
name
|
|
20
|
+
}) => _index.default.createElement('h1', {}, `Hello, ${name}!`);
|
|
21
|
+
describe('render', () => {
|
|
22
|
+
test('renders a function component', () => {
|
|
23
|
+
const {
|
|
24
|
+
getByText
|
|
25
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
26
|
+
name: 'World'
|
|
27
|
+
}));
|
|
28
|
+
expect(getByText('Hello, World!')).toBeDefined();
|
|
29
|
+
});
|
|
30
|
+
test('renders a class component', () => {
|
|
31
|
+
const {
|
|
32
|
+
getByText
|
|
33
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
34
|
+
expect(getByText('Count: 0')).toBeDefined();
|
|
35
|
+
});
|
|
36
|
+
test('returns a container attached to document.body', () => {
|
|
37
|
+
const {
|
|
38
|
+
container
|
|
39
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
40
|
+
name: 'test'
|
|
41
|
+
}));
|
|
42
|
+
expect(document.body.contains(container)).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('queries', () => {
|
|
46
|
+
test('getByRole finds button', () => {
|
|
47
|
+
const {
|
|
48
|
+
getByRole
|
|
49
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
50
|
+
const btn = getByRole('button');
|
|
51
|
+
expect(btn).toBeDefined();
|
|
52
|
+
expect(btn.textContent).toBe('Increment');
|
|
53
|
+
});
|
|
54
|
+
test('getByRole with name option', () => {
|
|
55
|
+
const {
|
|
56
|
+
getByRole
|
|
57
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
58
|
+
const btn = getByRole('button', {
|
|
59
|
+
name: 'Increment'
|
|
60
|
+
});
|
|
61
|
+
expect(btn).toBeDefined();
|
|
62
|
+
});
|
|
63
|
+
test('queryByText returns null when not found', () => {
|
|
64
|
+
const {
|
|
65
|
+
queryByText
|
|
66
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
67
|
+
name: 'test'
|
|
68
|
+
}));
|
|
69
|
+
expect(queryByText('Not here')).toBeNull();
|
|
70
|
+
});
|
|
71
|
+
test('getByText throws when not found', () => {
|
|
72
|
+
const {
|
|
73
|
+
getByText
|
|
74
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
75
|
+
name: 'test'
|
|
76
|
+
}));
|
|
77
|
+
expect(() => getByText('Not here')).toThrow();
|
|
78
|
+
});
|
|
79
|
+
test('findByText resolves asynchronously', async () => {
|
|
80
|
+
const {
|
|
81
|
+
findByText
|
|
82
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
83
|
+
name: 'World'
|
|
84
|
+
}));
|
|
85
|
+
const el = await findByText('Hello, World!');
|
|
86
|
+
expect(el).toBeDefined();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('fireEvent', () => {
|
|
90
|
+
test('click triggers onClick and re-renders', () => {
|
|
91
|
+
const {
|
|
92
|
+
getByText,
|
|
93
|
+
getByRole
|
|
94
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
95
|
+
expect(getByText('Count: 0')).toBeDefined();
|
|
96
|
+
_index2.fireEvent.click(getByRole('button'));
|
|
97
|
+
expect(getByText('Count: 1')).toBeDefined();
|
|
98
|
+
});
|
|
99
|
+
test('multiple clicks accumulate', () => {
|
|
100
|
+
const {
|
|
101
|
+
getByText,
|
|
102
|
+
getByRole
|
|
103
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
104
|
+
_index2.fireEvent.click(getByRole('button'));
|
|
105
|
+
_index2.fireEvent.click(getByRole('button'));
|
|
106
|
+
_index2.fireEvent.click(getByRole('button'));
|
|
107
|
+
expect(getByText('Count: 3')).toBeDefined();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('userEvent', () => {
|
|
111
|
+
test('click fires full mouse event sequence', () => {
|
|
112
|
+
const {
|
|
113
|
+
getByText,
|
|
114
|
+
getByRole
|
|
115
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
116
|
+
_index2.userEvent.click(getByRole('button'));
|
|
117
|
+
expect(getByText('Count: 1')).toBeDefined();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('rerender', () => {
|
|
121
|
+
test('updates the component with new props', () => {
|
|
122
|
+
const {
|
|
123
|
+
getByText,
|
|
124
|
+
rerender
|
|
125
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
126
|
+
name: 'Alice'
|
|
127
|
+
}));
|
|
128
|
+
expect(getByText('Hello, Alice!')).toBeDefined();
|
|
129
|
+
rerender(_index.default.createElement(Greeting, {
|
|
130
|
+
name: 'Bob'
|
|
131
|
+
}));
|
|
132
|
+
expect(getByText('Hello, Bob!')).toBeDefined();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('waitFor', () => {
|
|
136
|
+
test('polls until assertion passes', async () => {
|
|
137
|
+
const {
|
|
138
|
+
getByText
|
|
139
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
140
|
+
name: 'World'
|
|
141
|
+
}));
|
|
142
|
+
await (0, _index2.waitFor)(() => {
|
|
143
|
+
expect(getByText('Hello, World!')).toBeDefined();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
test('rejects when assertion never passes', async () => {
|
|
147
|
+
const {
|
|
148
|
+
queryByText
|
|
149
|
+
} = (0, _index2.render)(_index.default.createElement(Greeting, {
|
|
150
|
+
name: 'World'
|
|
151
|
+
}));
|
|
152
|
+
await expect((0, _index2.waitFor)(() => {
|
|
153
|
+
expect(queryByText('MISSING')).not.toBeNull();
|
|
154
|
+
}, {
|
|
155
|
+
timeout: 100,
|
|
156
|
+
interval: 20
|
|
157
|
+
})).rejects.toThrow();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('act', () => {
|
|
161
|
+
test('flushes state updates synchronously', () => {
|
|
162
|
+
const {
|
|
163
|
+
getByText,
|
|
164
|
+
getByRole
|
|
165
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
166
|
+
(0, _index2.act)(() => {
|
|
167
|
+
_index2.fireEvent.click(getByRole('button'));
|
|
168
|
+
});
|
|
169
|
+
expect(getByText('Count: 1')).toBeDefined();
|
|
170
|
+
});
|
|
171
|
+
test('wraps async callbacks', async () => {
|
|
172
|
+
const {
|
|
173
|
+
getByText
|
|
174
|
+
} = (0, _index2.render)(_index.default.createElement(Counter, {}));
|
|
175
|
+
await (0, _index2.act)(async () => {
|
|
176
|
+
await Promise.resolve();
|
|
177
|
+
});
|
|
178
|
+
expect(getByText('Count: 0')).toBeDefined();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.uninstallSyncScheduler = exports.installSyncScheduler = exports.flushEffects = exports.act = void 0;
|
|
7
|
+
var _reconciler = require("../core/reconciler");
|
|
8
|
+
const FAKE_DEADLINE = {
|
|
9
|
+
didTimeout: false,
|
|
10
|
+
timeRemaining: () => 999
|
|
11
|
+
};
|
|
12
|
+
let _installed = false;
|
|
13
|
+
const installSyncScheduler = () => {
|
|
14
|
+
if (_installed) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
_installed = true;
|
|
18
|
+
window.requestIdleCallback = cb => {
|
|
19
|
+
cb(FAKE_DEADLINE);
|
|
20
|
+
return 0;
|
|
21
|
+
};
|
|
22
|
+
window.cancelIdleCallback = () => {};
|
|
23
|
+
};
|
|
24
|
+
exports.installSyncScheduler = installSyncScheduler;
|
|
25
|
+
const uninstallSyncScheduler = () => {
|
|
26
|
+
_installed = false;
|
|
27
|
+
};
|
|
28
|
+
exports.uninstallSyncScheduler = uninstallSyncScheduler;
|
|
29
|
+
const flushEffects = () => {
|
|
30
|
+
_reconciler.__testing.flushSync();
|
|
31
|
+
};
|
|
32
|
+
exports.flushEffects = flushEffects;
|
|
33
|
+
const act = callback => {
|
|
34
|
+
const result = callback();
|
|
35
|
+
if (result && typeof result.then === 'function') {
|
|
36
|
+
return result.then(() => {
|
|
37
|
+
_reconciler.__testing.flushSync();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
_reconciler.__testing.flushSync();
|
|
41
|
+
};
|
|
42
|
+
exports.act = act;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.setupAutoCleanup = exports.registerContainer = exports.cleanup = void 0;
|
|
7
|
+
var _reconciler = require("../core/reconciler");
|
|
8
|
+
var _History = require("../core/components/History");
|
|
9
|
+
var _Intl = require("../core/components/Intl");
|
|
10
|
+
var _AnulyticsProvider = require("../core/components/AnulyticsProvider");
|
|
11
|
+
const mountedContainers = new Set();
|
|
12
|
+
const registerContainer = container => {
|
|
13
|
+
mountedContainers.add(container);
|
|
14
|
+
};
|
|
15
|
+
exports.registerContainer = registerContainer;
|
|
16
|
+
const cleanup = () => {
|
|
17
|
+
mountedContainers.forEach(container => {
|
|
18
|
+
container.parentNode?.removeChild(container);
|
|
19
|
+
});
|
|
20
|
+
mountedContainers.clear();
|
|
21
|
+
_reconciler.__testing.resetGlobals();
|
|
22
|
+
_History.__testing.reset();
|
|
23
|
+
_Intl.__testing.reset();
|
|
24
|
+
_AnulyticsProvider.__testing.reset();
|
|
25
|
+
};
|
|
26
|
+
exports.cleanup = cleanup;
|
|
27
|
+
const setupAutoCleanup = () => {
|
|
28
|
+
if (typeof afterEach === 'function') {
|
|
29
|
+
afterEach(cleanup);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.setupAutoCleanup = setupAutoCleanup;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type EventInit = globalThis.EventInit & Record<string, any>;
|
|
2
|
+
export declare const fireEvent: {
|
|
3
|
+
(element: Element, eventName: string, init?: EventInit): boolean;
|
|
4
|
+
click(el: Element, init?: MouseEventInit): boolean;
|
|
5
|
+
dblclick(el: Element, init?: MouseEventInit): boolean;
|
|
6
|
+
change(el: Element, init?: globalThis.EventInit): boolean;
|
|
7
|
+
input(el: Element, init?: globalThis.EventInit): boolean;
|
|
8
|
+
focus(el: Element, init?: FocusEventInit): boolean;
|
|
9
|
+
blur(el: Element, init?: FocusEventInit): boolean;
|
|
10
|
+
keyDown(el: Element, init?: KeyboardEventInit): boolean;
|
|
11
|
+
keyUp(el: Element, init?: KeyboardEventInit): boolean;
|
|
12
|
+
keyPress(el: Element, init?: KeyboardEventInit): boolean;
|
|
13
|
+
submit(el: Element, init?: globalThis.EventInit): boolean;
|
|
14
|
+
mouseDown(el: Element, init?: MouseEventInit): boolean;
|
|
15
|
+
mouseUp(el: Element, init?: MouseEventInit): boolean;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.fireEvent = void 0;
|
|
7
|
+
var _act = require("../act");
|
|
8
|
+
const buildEvent = (eventName, init) => {
|
|
9
|
+
const opts = {
|
|
10
|
+
bubbles: true,
|
|
11
|
+
cancelable: true,
|
|
12
|
+
...init
|
|
13
|
+
};
|
|
14
|
+
if (/^(click|mouse|contextmenu|dblclick)/i.test(eventName)) {
|
|
15
|
+
return new MouseEvent(eventName, opts);
|
|
16
|
+
}
|
|
17
|
+
if (/^key/i.test(eventName)) {
|
|
18
|
+
return new KeyboardEvent(eventName, opts);
|
|
19
|
+
}
|
|
20
|
+
if (/^(focus|blur)/i.test(eventName)) {
|
|
21
|
+
return new FocusEvent(eventName, opts);
|
|
22
|
+
}
|
|
23
|
+
if (/^pointer/i.test(eventName)) {
|
|
24
|
+
return new PointerEvent(eventName, opts);
|
|
25
|
+
}
|
|
26
|
+
return new Event(eventName, opts);
|
|
27
|
+
};
|
|
28
|
+
const fireEvent = (element, eventName, init) => {
|
|
29
|
+
const dispatched = element.dispatchEvent(buildEvent(eventName, init));
|
|
30
|
+
(0, _act.flushEffects)();
|
|
31
|
+
return dispatched;
|
|
32
|
+
};
|
|
33
|
+
exports.fireEvent = fireEvent;
|
|
34
|
+
fireEvent.click = (el, init) => fireEvent(el, 'click', init);
|
|
35
|
+
fireEvent.dblclick = (el, init) => fireEvent(el, 'dblclick', init);
|
|
36
|
+
fireEvent.change = (el, init) => fireEvent(el, 'change', init);
|
|
37
|
+
fireEvent.input = (el, init) => fireEvent(el, 'input', init);
|
|
38
|
+
fireEvent.focus = (el, init) => fireEvent(el, 'focus', init);
|
|
39
|
+
fireEvent.blur = (el, init) => fireEvent(el, 'blur', init);
|
|
40
|
+
fireEvent.keyDown = (el, init) => fireEvent(el, 'keydown', init);
|
|
41
|
+
fireEvent.keyUp = (el, init) => fireEvent(el, 'keyup', init);
|
|
42
|
+
fireEvent.keyPress = (el, init) => fireEvent(el, 'keypress', init);
|
|
43
|
+
fireEvent.submit = (el, init) => fireEvent(el, 'submit', init);
|
|
44
|
+
fireEvent.mouseDown = (el, init) => fireEvent(el, 'mousedown', init);
|
|
45
|
+
fireEvent.mouseUp = (el, init) => fireEvent(el, 'mouseup', init);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const userEvent: {
|
|
2
|
+
click: (element: Element) => void;
|
|
3
|
+
dblclick: (element: Element) => void;
|
|
4
|
+
type: (element: HTMLInputElement | HTMLTextAreaElement, text: string) => void;
|
|
5
|
+
clear: (element: HTMLInputElement | HTMLTextAreaElement) => void;
|
|
6
|
+
change: (element: HTMLInputElement | HTMLSelectElement, value: string) => void;
|
|
7
|
+
submit: (form: HTMLFormElement) => void;
|
|
8
|
+
selectOption: (select: HTMLSelectElement, value: string) => void;
|
|
9
|
+
tab: (options?: {
|
|
10
|
+
shift?: boolean;
|
|
11
|
+
}) => void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.userEvent = void 0;
|
|
7
|
+
var _fireEvent = require("./fireEvent");
|
|
8
|
+
const userEvent = exports.userEvent = {
|
|
9
|
+
click: element => {
|
|
10
|
+
(0, _fireEvent.fireEvent)(element, 'mousedown');
|
|
11
|
+
(0, _fireEvent.fireEvent)(element, 'mouseup');
|
|
12
|
+
(0, _fireEvent.fireEvent)(element, 'click');
|
|
13
|
+
},
|
|
14
|
+
dblclick: element => {
|
|
15
|
+
(0, _fireEvent.fireEvent)(element, 'mousedown');
|
|
16
|
+
(0, _fireEvent.fireEvent)(element, 'mouseup');
|
|
17
|
+
(0, _fireEvent.fireEvent)(element, 'click');
|
|
18
|
+
(0, _fireEvent.fireEvent)(element, 'mousedown');
|
|
19
|
+
(0, _fireEvent.fireEvent)(element, 'mouseup');
|
|
20
|
+
(0, _fireEvent.fireEvent)(element, 'click');
|
|
21
|
+
(0, _fireEvent.fireEvent)(element, 'dblclick');
|
|
22
|
+
},
|
|
23
|
+
type: (element, text) => {
|
|
24
|
+
(0, _fireEvent.fireEvent)(element, 'focus');
|
|
25
|
+
for (const char of text) {
|
|
26
|
+
(0, _fireEvent.fireEvent)(element, 'keydown', {
|
|
27
|
+
key: char
|
|
28
|
+
});
|
|
29
|
+
(0, _fireEvent.fireEvent)(element, 'keypress', {
|
|
30
|
+
key: char
|
|
31
|
+
});
|
|
32
|
+
element.value += char;
|
|
33
|
+
(0, _fireEvent.fireEvent)(element, 'input');
|
|
34
|
+
(0, _fireEvent.fireEvent)(element, 'keyup', {
|
|
35
|
+
key: char
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
(0, _fireEvent.fireEvent)(element, 'change');
|
|
39
|
+
},
|
|
40
|
+
clear: element => {
|
|
41
|
+
(0, _fireEvent.fireEvent)(element, 'focus');
|
|
42
|
+
element.value = '';
|
|
43
|
+
(0, _fireEvent.fireEvent)(element, 'input');
|
|
44
|
+
(0, _fireEvent.fireEvent)(element, 'change');
|
|
45
|
+
},
|
|
46
|
+
change: (element, value) => {
|
|
47
|
+
element.value = value;
|
|
48
|
+
(0, _fireEvent.fireEvent)(element, 'input');
|
|
49
|
+
(0, _fireEvent.fireEvent)(element, 'change');
|
|
50
|
+
},
|
|
51
|
+
submit: form => {
|
|
52
|
+
(0, _fireEvent.fireEvent)(form, 'submit');
|
|
53
|
+
},
|
|
54
|
+
selectOption: (select, value) => {
|
|
55
|
+
select.value = value;
|
|
56
|
+
(0, _fireEvent.fireEvent)(select, 'change');
|
|
57
|
+
},
|
|
58
|
+
tab: (options = {}) => {
|
|
59
|
+
const focused = document.activeElement;
|
|
60
|
+
if (focused) {
|
|
61
|
+
(0, _fireEvent.fireEvent)(focused, 'keydown', {
|
|
62
|
+
key: 'Tab',
|
|
63
|
+
shiftKey: options.shift ?? false
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { render } from './render';
|
|
2
|
+
export { act, flushEffects, installSyncScheduler, uninstallSyncScheduler } from './act';
|
|
3
|
+
export { cleanup, setupAutoCleanup } from './cleanup';
|
|
4
|
+
export { waitFor, waitForElementToBeRemoved } from './waitFor';
|
|
5
|
+
export { fireEvent } from './events/fireEvent';
|
|
6
|
+
export { userEvent } from './events/userEvent';
|
|
7
|
+
export { renderWithStore, renderWithRouter, renderWithIntl, renderWithContext } from './wrappers';
|
|
8
|
+
export { buildQueries } from './queries/index';
|
|
9
|
+
export type { RenderOptions, RenderResult, BoundQueries, BoundQuery, ByRoleOptions, TextMatch, WaitForOptions, } from './types';
|