@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 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
- * fixed pie-lib/icons import [PD-5126] ([dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f))
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
- * split pie-toolbox into multiple packages [PD-5126] ([7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2))
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
- * fixed pie-lib/icons import [PD-5126] ([dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f))
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
- * split pie-toolbox into multiple packages [PD-5126] ([7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2))
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
- * fixed pie-lib/icons import [PD-5126] ([dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f))
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
- * split pie-toolbox into multiple packages [PD-5126] ([7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2))
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/)