@pie-lib/test-utils 0.36.0-mui-update.0 → 1.0.0-next.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/CHANGELOG.md CHANGED
@@ -3,7 +3,7 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- # [0.36.0-mui-update.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.35.0-mui-update.0...@pie-lib/test-utils@0.36.0-mui-update.0) (2025-12-29)
6
+ # [1.0.0-next.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.22.2-next.0...@pie-lib/test-utils@1.0.0-next.0) (2026-01-19)
7
7
 
8
8
  **Note:** Version bump only for package @pie-lib/test-utils
9
9
 
@@ -11,7 +11,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
11
11
 
12
12
 
13
13
 
14
- # [0.35.0-mui-update.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.34.0-mui-update.0...@pie-lib/test-utils@0.35.0-mui-update.0) (2025-12-29)
14
+ ## [0.22.2-next.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.36.0-mui-update.0...@pie-lib/test-utils@0.22.2-next.0) (2026-01-19)
15
15
 
16
16
  **Note:** Version bump only for package @pie-lib/test-utils
17
17
 
@@ -19,168 +19,75 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
19
19
 
20
20
 
21
21
 
22
- # [0.34.0-mui-update.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.33.0-mui-update.0...@pie-lib/test-utils@0.34.0-mui-update.0) (2025-12-17)
23
-
24
- **Note:** Version bump only for package @pie-lib/test-utils
25
-
26
-
27
-
28
-
29
-
30
- # [0.33.0-mui-update.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.32.0-mui-update.0...@pie-lib/test-utils@0.33.0-mui-update.0) (2025-12-17)
31
-
32
- **Note:** Version bump only for package @pie-lib/test-utils
33
-
34
-
35
-
36
-
37
-
38
- # [0.32.0-mui-update.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.31.0-mui-update.0...@pie-lib/test-utils@0.32.0-mui-update.0) (2025-12-11)
39
-
40
- **Note:** Version bump only for package @pie-lib/test-utils
41
-
42
-
43
-
44
-
45
-
46
- # [0.31.0-mui-update.0](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.30.0-mui-update.0...@pie-lib/test-utils@0.31.0-mui-update.0) (2025-12-02)
47
-
48
-
49
- ### Features
50
-
51
- * sync latest changes from dev ([c936e9c](https://github.com/pie-framework/pie-lib/commit/c936e9c7f9e095e7d9b9805ac2bf72bd271e05f1))
52
-
53
-
54
-
55
-
56
-
57
22
  ## [0.22.1](https://github.com/pie-framework/pie-lib/compare/@pie-lib/test-utils@0.18.0...@pie-lib/test-utils@0.22.1) (2025-10-22)
58
23
 
59
24
  **Note:** Version bump only for package @pie-lib/test-utils
60
25
 
61
-
62
-
63
-
64
-
65
26
  # [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)
66
27
 
67
28
  **Note:** Version bump only for package @pie-lib/test-utils
68
29
 
69
-
70
-
71
-
72
-
73
30
  # [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)
74
31
 
75
32
  **Note:** Version bump only for package @pie-lib/test-utils
76
33
 
77
-
78
-
79
-
80
-
81
34
  # [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)
82
35
 
83
36
  **Note:** Version bump only for package @pie-lib/test-utils
84
37
 
85
-
86
-
87
-
88
-
89
38
  # [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)
90
39
 
91
40
  **Note:** Version bump only for package @pie-lib/test-utils
92
41
 
93
-
94
-
95
-
96
-
97
42
  # [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)
98
43
 
99
-
100
44
  ### Bug Fixes
101
45
 
102
- * fixed pie-lib/icons import [PD-5126] ([dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f))
103
-
46
+ - fixed pie-lib/icons import [PD-5126](<[dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f)>)
104
47
 
105
48
  ### Features
106
49
 
107
- * split pie-toolbox into multiple packages [PD-5126] ([7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2))
108
-
109
-
110
-
111
-
50
+ - split pie-toolbox into multiple packages [PD-5126](<[7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2)>)
112
51
 
113
52
  # [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)
114
53
 
115
54
  **Note:** Version bump only for package @pie-lib/test-utils
116
55
 
117
-
118
-
119
-
120
-
121
56
  # [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)
122
57
 
123
58
  **Note:** Version bump only for package @pie-lib/test-utils
124
59
 
125
-
126
-
127
-
128
-
129
60
  # [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)
130
61
 
131
-
132
62
  ### Bug Fixes
133
63
 
134
- * fixed pie-lib/icons import [PD-5126] ([dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f))
135
-
64
+ - fixed pie-lib/icons import [PD-5126](<[dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f)>)
136
65
 
137
66
  ### Features
138
67
 
139
- * split pie-toolbox into multiple packages [PD-5126] ([7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2))
140
-
141
-
142
-
143
-
68
+ - split pie-toolbox into multiple packages [PD-5126](<[7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2)>)
144
69
 
145
70
  # [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)
146
71
 
147
72
  **Note:** Version bump only for package @pie-lib/test-utils
148
73
 
149
-
150
-
151
-
152
-
153
74
  # [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)
154
75
 
155
76
  **Note:** Version bump only for package @pie-lib/test-utils
156
77
 
157
-
158
-
159
-
160
-
161
78
  # [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)
162
79
 
163
80
  **Note:** Version bump only for package @pie-lib/test-utils
164
81
 
165
-
166
-
167
-
168
-
169
82
  ## [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)
170
83
 
171
-
172
84
  ### Bug Fixes
173
85
 
174
- * fixed pie-lib/icons import [PD-5126] ([dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f))
175
-
86
+ - fixed pie-lib/icons import [PD-5126](<[dcb506c](https://github.com/pie-framework/pie-lib/commit/dcb506c914a177f6d88bf73247a023bfe71dac1f)>)
176
87
 
177
88
  ### Features
178
89
 
179
- * split pie-toolbox into multiple packages [PD-5126] ([7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2))
180
-
181
-
182
-
183
-
90
+ - split pie-toolbox into multiple packages [PD-5126](<[7d55a25](https://github.com/pie-framework/pie-lib/commit/7d55a2552d084cd3d0d5c00dc77411b2ced2f5e2)>)
184
91
 
185
92
  # [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)
186
93
 
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/)