@pie-lib/test-utils 0.22.1 → 0.22.2-next.164
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/CHANGELOG.md +6 -64
- package/README.md +463 -0
- package/lib/index.js +255 -23
- package/lib/index.js.map +1 -1
- package/lib/keyboard.js +173 -0
- package/lib/keyboard.js.map +1 -0
- package/lib/web-components.js +248 -0
- package/lib/web-components.js.map +1 -0
- package/package.json +13 -5
- package/src/__tests__/index.test.js +88 -41
- package/src/__tests__/keyboard.test.js +116 -0
- package/src/index.js +132 -11
- package/src/keyboard.js +126 -0
- package/src/web-components.js +200 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,129 +7,71 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
|
|
7
7
|
|
|
8
8
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
10
|
# [0.22.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.18.0...@pie-lib/test-utils@0.22.0) (2025-10-16)
|
|
15
11
|
|
|
16
12
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
14
|
# [0.21.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.18.0...@pie-lib/test-utils@0.21.0) (2025-10-16)
|
|
23
15
|
|
|
24
16
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
25
17
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
18
|
# [0.20.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.18.0...@pie-lib/test-utils@0.20.0) (2025-10-16)
|
|
31
19
|
|
|
32
20
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
33
21
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
22
|
# [0.19.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.18.0...@pie-lib/test-utils@0.19.0) (2025-10-16)
|
|
39
23
|
|
|
40
24
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
41
25
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
26
|
# [0.18.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.2.33...@pie-lib/test-utils@0.18.0) (2025-09-25)
|
|
47
27
|
|
|
48
|
-
|
|
49
28
|
### Bug Fixes
|
|
50
29
|
|
|
51
|
-
|
|
52
|
-
|
|
30
|
+
- fixed pie-lib/icons import [PD-5126](<[dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f)>)
|
|
53
31
|
|
|
54
32
|
### Features
|
|
55
33
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
34
|
+
- split pie-toolbox into multiple packages [PD-5126](<[7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2)>)
|
|
61
35
|
|
|
62
36
|
# [0.17.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.16.0...@pie-lib/test-utils@0.17.0) (2025-09-18)
|
|
63
37
|
|
|
64
38
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
65
39
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
40
|
# [0.16.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.15.0...@pie-lib/test-utils@0.16.0) (2025-09-18)
|
|
71
41
|
|
|
72
42
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
73
43
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
44
|
# [0.15.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.2.33...@pie-lib/test-utils@0.15.0) (2025-09-18)
|
|
79
45
|
|
|
80
|
-
|
|
81
46
|
### Bug Fixes
|
|
82
47
|
|
|
83
|
-
|
|
84
|
-
|
|
48
|
+
- fixed pie-lib/icons import [PD-5126](<[dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f)>)
|
|
85
49
|
|
|
86
50
|
### Features
|
|
87
51
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
52
|
+
- split pie-toolbox into multiple packages [PD-5126](<[7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2)>)
|
|
93
53
|
|
|
94
54
|
# [0.14.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.13.0...@pie-lib/test-utils@0.14.0) (2025-09-17)
|
|
95
55
|
|
|
96
56
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
97
57
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
58
|
# [0.13.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.12.0...@pie-lib/test-utils@0.13.0) (2025-09-17)
|
|
103
59
|
|
|
104
60
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
105
61
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
62
|
# [0.12.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.11.1...@pie-lib/test-utils@0.12.0) (2025-09-17)
|
|
111
63
|
|
|
112
64
|
**Note:** Version bump only for package @pie-lib/test-utils
|
|
113
65
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
66
|
## [0.11.1](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.2.33...@pie-lib/test-utils@0.11.1) (2025-08-11)
|
|
119
67
|
|
|
120
|
-
|
|
121
68
|
### Bug Fixes
|
|
122
69
|
|
|
123
|
-
|
|
124
|
-
|
|
70
|
+
- fixed pie-lib/icons import [PD-5126](<[dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f)>)
|
|
125
71
|
|
|
126
72
|
### Features
|
|
127
73
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
74
|
+
- split pie-toolbox into multiple packages [PD-5126](<[7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2)>)
|
|
133
75
|
|
|
134
76
|
# [0.11.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.2.33...@pie-lib/test-utils@0.11.0) (2025-08-07)
|
|
135
77
|
|
package/README.md
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
# @pie-lib/test-utils
|
|
2
|
+
|
|
3
|
+
Testing utilities for pie-lib packages with React Testing Library and MUI support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
This package is typically used as a dev dependency:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
yarn add -D @pie-lib/test-utils
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- ✅ React Testing Library utilities
|
|
16
|
+
- ✅ MUI Theme Provider wrapper for tests
|
|
17
|
+
- ✅ Multiple provider composition
|
|
18
|
+
- ✅ Custom theme creation for testing
|
|
19
|
+
- ✅ All RTL exports in one place
|
|
20
|
+
- ✅ userEvent and jest-dom matchers included
|
|
21
|
+
- ✅ Keyboard helpers for keyCode-based components
|
|
22
|
+
- ✅ Web component testing utilities (light DOM only)
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic Rendering with MUI Theme
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
import { renderWithTheme, screen } from '@pie-lib/test-utils';
|
|
30
|
+
import { Button } from '@mui/material';
|
|
31
|
+
|
|
32
|
+
test('renders a button', () => {
|
|
33
|
+
renderWithTheme(<Button>Click me</Button>);
|
|
34
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Custom Theme
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import { renderWithTheme, createTestTheme } from '@pie-lib/test-utils';
|
|
42
|
+
|
|
43
|
+
test('renders with dark theme', () => {
|
|
44
|
+
const darkTheme = createTestTheme({
|
|
45
|
+
palette: { mode: 'dark' }
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
renderWithTheme(<MyComponent />, { theme: darkTheme });
|
|
49
|
+
// ... assertions
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Multiple Providers
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
import { renderWithProviders } from '@pie-lib/test-utils';
|
|
57
|
+
|
|
58
|
+
test('renders with multiple providers', () => {
|
|
59
|
+
const ReduxProvider = ({ children }) => (
|
|
60
|
+
<Provider store={store}>{children}</Provider>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
renderWithProviders(<MyComponent />, {
|
|
64
|
+
providers: [ReduxProvider]
|
|
65
|
+
});
|
|
66
|
+
// ... assertions
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### User Interactions
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
import { renderWithTheme, screen, userEvent } from '@pie-lib/test-utils';
|
|
74
|
+
|
|
75
|
+
test('handles button click', async () => {
|
|
76
|
+
const onClick = jest.fn();
|
|
77
|
+
const user = userEvent.setup();
|
|
78
|
+
|
|
79
|
+
renderWithTheme(<Button onClick={onClick}>Click</Button>);
|
|
80
|
+
|
|
81
|
+
await user.click(screen.getByRole('button'));
|
|
82
|
+
expect(onClick).toHaveBeenCalledTimes(1);
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Keyboard Interactions
|
|
87
|
+
|
|
88
|
+
**NEW:** Helper functions for testing keyboard events, especially useful for legacy components checking `event.keyCode`:
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
import { render, screen, pressKey, Keys, typeAndSubmit } from '@pie-lib/test-utils';
|
|
92
|
+
|
|
93
|
+
test('submits on Enter key', async () => {
|
|
94
|
+
const onSubmit = jest.fn();
|
|
95
|
+
render(<SearchInput onSubmit={onSubmit} />);
|
|
96
|
+
|
|
97
|
+
const input = screen.getByRole('textbox');
|
|
98
|
+
await typeAndSubmit(input, 'search term');
|
|
99
|
+
|
|
100
|
+
expect(onSubmit).toHaveBeenCalledWith('search term');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('handles Escape key', () => {
|
|
104
|
+
const onCancel = jest.fn();
|
|
105
|
+
render(<Modal onCancel={onCancel} />);
|
|
106
|
+
|
|
107
|
+
const modal = screen.getByRole('dialog');
|
|
108
|
+
pressKey(modal, Keys.ESCAPE);
|
|
109
|
+
|
|
110
|
+
expect(onCancel).toHaveBeenCalled();
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Async Operations
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
import { renderWithTheme, screen, waitFor } from '@pie-lib/test-utils';
|
|
118
|
+
|
|
119
|
+
test('loads data', async () => {
|
|
120
|
+
renderWithTheme(<AsyncComponent />);
|
|
121
|
+
|
|
122
|
+
// Wait for element to appear
|
|
123
|
+
const element = await screen.findByText('Loaded');
|
|
124
|
+
expect(element).toBeInTheDocument();
|
|
125
|
+
|
|
126
|
+
// Or use waitFor
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(screen.getByText('Loaded')).toBeInTheDocument();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Web Component Testing
|
|
134
|
+
|
|
135
|
+
**Note:** Utilities for testing custom elements with **light DOM** (no Shadow DOM). Standard React Testing Library queries work directly on these components.
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
import { renderWebComponent, dispatchCustomEvent, screen } from '@pie-lib/test-utils';
|
|
139
|
+
|
|
140
|
+
test('interacts with web component', async () => {
|
|
141
|
+
const element = await renderWebComponent('my-custom-element', {
|
|
142
|
+
'data-testid': 'my-element',
|
|
143
|
+
value: '42'
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Query using standard RTL queries (light DOM)
|
|
147
|
+
const button = screen.getByRole('button');
|
|
148
|
+
await user.click(button);
|
|
149
|
+
|
|
150
|
+
// Dispatch custom events
|
|
151
|
+
dispatchCustomEvent(element, 'value-changed', { newValue: '100' });
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## API Reference
|
|
156
|
+
|
|
157
|
+
### React Component Rendering
|
|
158
|
+
|
|
159
|
+
### `renderWithTheme(ui, options)`
|
|
160
|
+
|
|
161
|
+
Renders a component wrapped with MUI ThemeProvider.
|
|
162
|
+
|
|
163
|
+
**Parameters:**
|
|
164
|
+
- `ui` - React component to render
|
|
165
|
+
- `options.theme` - Custom MUI theme (optional, defaults to Material-UI default)
|
|
166
|
+
- `options...` - Additional options passed to RTL's `render()`
|
|
167
|
+
|
|
168
|
+
**Returns:** RTL render result
|
|
169
|
+
|
|
170
|
+
### `renderWithProviders(ui, options)`
|
|
171
|
+
|
|
172
|
+
Renders a component with MUI ThemeProvider and additional custom providers.
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
- `ui` - React component to render
|
|
176
|
+
- `options.theme` - Custom MUI theme (optional)
|
|
177
|
+
- `options.providers` - Array of provider components to wrap (optional)
|
|
178
|
+
- `options...` - Additional options passed to RTL's `render()`
|
|
179
|
+
|
|
180
|
+
**Returns:** RTL render result
|
|
181
|
+
|
|
182
|
+
### `createTestTheme(themeOptions)`
|
|
183
|
+
|
|
184
|
+
Creates a MUI theme for testing.
|
|
185
|
+
|
|
186
|
+
**Parameters:**
|
|
187
|
+
- `themeOptions` - MUI theme configuration object
|
|
188
|
+
|
|
189
|
+
**Returns:** MUI theme object
|
|
190
|
+
|
|
191
|
+
### `waitForRemoval(callback)`
|
|
192
|
+
|
|
193
|
+
Alias for `waitForElementToBeRemoved` from RTL.
|
|
194
|
+
|
|
195
|
+
### Re-exports
|
|
196
|
+
|
|
197
|
+
This package re-exports everything from:
|
|
198
|
+
- `@testing-library/react` (render, screen, waitFor, etc.)
|
|
199
|
+
- `@testing-library/user-event` (as `userEvent`)
|
|
200
|
+
- `@testing-library/jest-dom` (for TypeScript support)
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Keyboard Helpers API
|
|
205
|
+
|
|
206
|
+
### `Keys`
|
|
207
|
+
|
|
208
|
+
Constants for common keyboard key codes:
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
import { Keys } from '@pie-lib/test-utils';
|
|
212
|
+
|
|
213
|
+
Keys.ENTER // 13
|
|
214
|
+
Keys.ESCAPE // 27
|
|
215
|
+
Keys.SPACE // 32
|
|
216
|
+
Keys.TAB // 9
|
|
217
|
+
Keys.ARROW_DOWN // 40
|
|
218
|
+
Keys.ARROW_UP // 38
|
|
219
|
+
// ... and more
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### `pressKey(element, keyCode, type, options)`
|
|
223
|
+
|
|
224
|
+
Simulate keyboard event with keyCode (useful for legacy components):
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
import { pressKey, Keys } from '@pie-lib/test-utils';
|
|
228
|
+
|
|
229
|
+
// Press Enter
|
|
230
|
+
pressKey(input, Keys.ENTER);
|
|
231
|
+
|
|
232
|
+
// Press Escape with keyup event
|
|
233
|
+
pressKey(dialog, Keys.ESCAPE, 'keyup');
|
|
234
|
+
|
|
235
|
+
// Press Ctrl+Enter
|
|
236
|
+
pressKey(input, Keys.ENTER, 'keydown', { ctrlKey: true });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Why?** `userEvent.type()` with `{Enter}` doesn't work well with components checking `event.keyCode`.
|
|
240
|
+
|
|
241
|
+
### `typeAndSubmit(element, text)`
|
|
242
|
+
|
|
243
|
+
Type text and press Enter (common pattern):
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
import { typeAndSubmit } from '@pie-lib/test-utils';
|
|
247
|
+
|
|
248
|
+
await typeAndSubmit(input, 'search query');
|
|
249
|
+
// Types "search query" and presses Enter
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### `clearAndType(element, text)`
|
|
253
|
+
|
|
254
|
+
Clear input and type new text:
|
|
255
|
+
|
|
256
|
+
```javascript
|
|
257
|
+
import { clearAndType } from '@pie-lib/test-utils';
|
|
258
|
+
|
|
259
|
+
await clearAndType(input, 'new value');
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `navigateWithKeys(element, steps, direction)`
|
|
263
|
+
|
|
264
|
+
Navigate with arrow keys:
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
import { navigateWithKeys } from '@pie-lib/test-utils';
|
|
268
|
+
|
|
269
|
+
// Navigate down 3 items
|
|
270
|
+
navigateWithKeys(listbox, 3, 'vertical');
|
|
271
|
+
|
|
272
|
+
// Navigate left 2 items
|
|
273
|
+
navigateWithKeys(tabs, -2, 'horizontal');
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Web Component Helpers API
|
|
279
|
+
|
|
280
|
+
**Note:** These utilities are for **light DOM web components only** (no Shadow DOM). For Shadow DOM components, use standard DOM queries or other testing libraries.
|
|
281
|
+
|
|
282
|
+
### `waitForCustomElement(tagName, timeout)`
|
|
283
|
+
|
|
284
|
+
Wait for custom element to be defined:
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
import { waitForCustomElement } from '@pie-lib/test-utils';
|
|
288
|
+
|
|
289
|
+
await waitForCustomElement('my-component');
|
|
290
|
+
await waitForCustomElement('pie-chart', 5000); // 5 second timeout
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### `renderWebComponent(tagName, attributes, properties, container)`
|
|
294
|
+
|
|
295
|
+
Render web component and wait for it to be ready:
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
import { renderWebComponent } from '@pie-lib/test-utils';
|
|
299
|
+
|
|
300
|
+
const element = await renderWebComponent('pie-chart',
|
|
301
|
+
{ type: 'bar', 'data-testid': 'chart' }, // attributes
|
|
302
|
+
{ onDataChange: jest.fn() } // properties
|
|
303
|
+
);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### `dispatchCustomEvent(element, eventName, detail, options)`
|
|
307
|
+
|
|
308
|
+
Dispatch custom event on element:
|
|
309
|
+
|
|
310
|
+
```javascript
|
|
311
|
+
import { dispatchCustomEvent } from '@pie-lib/test-utils';
|
|
312
|
+
|
|
313
|
+
dispatchCustomEvent(chart, 'data-changed', { value: [1, 2, 3] });
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### `waitForEvent(element, eventName, timeout)`
|
|
317
|
+
|
|
318
|
+
Wait for custom event to be fired:
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
import { waitForEvent } from '@pie-lib/test-utils';
|
|
322
|
+
|
|
323
|
+
const promise = waitForEvent(component, 'ready');
|
|
324
|
+
component.initialize();
|
|
325
|
+
const event = await promise;
|
|
326
|
+
expect(event.detail).toEqual({ initialized: true });
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### `isCustomElementDefined(tagName)`
|
|
330
|
+
|
|
331
|
+
Check if a custom element is defined:
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
import { isCustomElementDefined } from '@pie-lib/test-utils';
|
|
335
|
+
|
|
336
|
+
if (isCustomElementDefined('pie-chart')) {
|
|
337
|
+
// Element is ready to use
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### `createCustomElement(tagName, props)`
|
|
342
|
+
|
|
343
|
+
Create and configure a custom element:
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
import { createCustomElement } from '@pie-lib/test-utils';
|
|
347
|
+
|
|
348
|
+
const chart = createCustomElement('pie-chart', {
|
|
349
|
+
data: [1, 2, 3],
|
|
350
|
+
type: 'bar'
|
|
351
|
+
});
|
|
352
|
+
document.body.appendChild(chart);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Migration from Enzyme
|
|
356
|
+
|
|
357
|
+
### Before (Enzyme)
|
|
358
|
+
|
|
359
|
+
```javascript
|
|
360
|
+
import { shallow } from 'enzyme';
|
|
361
|
+
|
|
362
|
+
const wrapper = shallow(<Component />);
|
|
363
|
+
expect(wrapper.find('button')).toHaveLength(1);
|
|
364
|
+
wrapper.find('button').simulate('click');
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### After (React Testing Library)
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
import { renderWithTheme, screen, userEvent } from '@pie-lib/test-utils';
|
|
371
|
+
|
|
372
|
+
renderWithTheme(<Component />);
|
|
373
|
+
const button = screen.getByRole('button');
|
|
374
|
+
expect(button).toBeInTheDocument();
|
|
375
|
+
await userEvent.click(button);
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Query Priority
|
|
379
|
+
|
|
380
|
+
Use queries in this order (best to worst):
|
|
381
|
+
|
|
382
|
+
1. **getByRole** - Best for accessibility
|
|
383
|
+
2. **getByLabelText** - Good for form fields
|
|
384
|
+
3. **getByPlaceholderText** - Forms when label not available
|
|
385
|
+
4. **getByText** - Non-interactive content
|
|
386
|
+
5. **getByDisplayValue** - Current form values
|
|
387
|
+
6. **getByAltText** - Images
|
|
388
|
+
7. **getByTitle** - When other options don't work
|
|
389
|
+
8. **getByTestId** - Last resort
|
|
390
|
+
|
|
391
|
+
## Common Patterns
|
|
392
|
+
|
|
393
|
+
### Testing Forms
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
import { renderWithTheme, screen, userEvent } from '@pie-lib/test-utils';
|
|
397
|
+
|
|
398
|
+
test('submits form', async () => {
|
|
399
|
+
const onSubmit = jest.fn();
|
|
400
|
+
const user = userEvent.setup();
|
|
401
|
+
|
|
402
|
+
renderWithTheme(<LoginForm onSubmit={onSubmit} />);
|
|
403
|
+
|
|
404
|
+
await user.type(screen.getByLabelText('Username'), 'user123');
|
|
405
|
+
await user.type(screen.getByLabelText('Password'), 'pass123');
|
|
406
|
+
await user.click(screen.getByRole('button', { name: /submit/i }));
|
|
407
|
+
|
|
408
|
+
expect(onSubmit).toHaveBeenCalledWith({
|
|
409
|
+
username: 'user123',
|
|
410
|
+
password: 'pass123'
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Testing Conditional Rendering
|
|
416
|
+
|
|
417
|
+
```javascript
|
|
418
|
+
test('shows error message', async () => {
|
|
419
|
+
renderWithTheme(<Component />);
|
|
420
|
+
|
|
421
|
+
// Initially not present
|
|
422
|
+
expect(screen.queryByText('Error')).not.toBeInTheDocument();
|
|
423
|
+
|
|
424
|
+
// Trigger error
|
|
425
|
+
await userEvent.click(screen.getByRole('button'));
|
|
426
|
+
|
|
427
|
+
// Now appears
|
|
428
|
+
expect(await screen.findByText('Error occurred')).toBeInTheDocument();
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Testing with Custom Props
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
const defaultProps = {
|
|
436
|
+
title: 'Test',
|
|
437
|
+
onChange: jest.fn()
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
test('renders with defaults', () => {
|
|
441
|
+
renderWithTheme(<Component {...defaultProps} />);
|
|
442
|
+
expect(screen.getByText('Test')).toBeInTheDocument();
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test('renders with overrides', () => {
|
|
446
|
+
renderWithTheme(<Component {...defaultProps} title="Override" />);
|
|
447
|
+
expect(screen.getByText('Override')).toBeInTheDocument();
|
|
448
|
+
});
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Tips
|
|
452
|
+
|
|
453
|
+
1. **Use `screen` queries** - More readable than destructuring from render
|
|
454
|
+
2. **Prefer `findBy` for async** - Built-in waiting
|
|
455
|
+
3. **Use `queryBy` for non-existence** - Won't throw if not found
|
|
456
|
+
4. **Test behavior, not implementation** - Don't test internal state
|
|
457
|
+
5. **Use `userEvent` over `fireEvent`** - More realistic interactions
|
|
458
|
+
|
|
459
|
+
## Learn More
|
|
460
|
+
|
|
461
|
+
- [React Testing Library Docs](https://testing-library.com/react)
|
|
462
|
+
- [Common Mistakes](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|
|
463
|
+
- [MUI Testing Guide](https://mui.com/material-ui/guides/testing/)
|