ferns-ui 1.10.0 → 1.11.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.
Files changed (69) hide show
  1. package/dist/Accordion.js +1 -1
  2. package/dist/Accordion.js.map +1 -1
  3. package/dist/Accordion.test.d.ts +1 -0
  4. package/dist/Accordion.test.js +71 -0
  5. package/dist/Accordion.test.js.map +1 -0
  6. package/dist/AddressField.test.d.ts +1 -0
  7. package/dist/AddressField.test.js +65 -0
  8. package/dist/AddressField.test.js.map +1 -0
  9. package/dist/Avatar.js +2 -2
  10. package/dist/Avatar.js.map +1 -1
  11. package/dist/Avatar.test.d.ts +1 -0
  12. package/dist/Avatar.test.js +131 -0
  13. package/dist/Avatar.test.js.map +1 -0
  14. package/dist/Badge.d.ts +1 -1
  15. package/dist/Badge.js +3 -3
  16. package/dist/Badge.js.map +1 -1
  17. package/dist/Badge.test.d.ts +1 -0
  18. package/dist/Badge.test.js +76 -0
  19. package/dist/Badge.test.js.map +1 -0
  20. package/dist/Box.test.d.ts +1 -0
  21. package/dist/Box.test.js +528 -0
  22. package/dist/Box.test.js.map +1 -0
  23. package/dist/Common.d.ts +100 -1
  24. package/dist/Common.js.map +1 -1
  25. package/dist/DateTimeField.js +15 -2
  26. package/dist/DateTimeField.js.map +1 -1
  27. package/dist/InfoModalIcon.js +1 -1
  28. package/dist/InfoModalIcon.js.map +1 -1
  29. package/dist/Slider.d.ts +3 -0
  30. package/dist/Slider.js +94 -0
  31. package/dist/Slider.js.map +1 -0
  32. package/dist/Text.js +2 -0
  33. package/dist/Text.js.map +1 -1
  34. package/dist/TextField.test.js +9 -9
  35. package/dist/TextField.test.js.map +1 -1
  36. package/dist/Tooltip.js +2 -0
  37. package/dist/Tooltip.js.map +1 -1
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +1 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/setupTests.js +40 -2
  42. package/dist/setupTests.js.map +1 -1
  43. package/dist/test-utils.js.map +1 -1
  44. package/package.json +2 -1
  45. package/src/Accordion.test.tsx +104 -0
  46. package/src/Accordion.tsx +1 -0
  47. package/src/AddressField.test.tsx +89 -0
  48. package/src/Avatar.test.tsx +163 -0
  49. package/src/Avatar.tsx +2 -0
  50. package/src/Badge.test.tsx +116 -0
  51. package/src/Badge.tsx +3 -1
  52. package/src/Box.test.tsx +665 -0
  53. package/src/Common.ts +114 -1
  54. package/src/DateTimeField.tsx +15 -2
  55. package/src/InfoModalIcon.tsx +1 -0
  56. package/src/Slider.tsx +205 -0
  57. package/src/Text.tsx +2 -0
  58. package/src/TextField.test.tsx +59 -71
  59. package/src/Tooltip.tsx +2 -0
  60. package/src/__snapshots__/Accordion.test.tsx.snap +120 -0
  61. package/src/__snapshots__/AddressField.test.tsx.snap +464 -0
  62. package/src/__snapshots__/Avatar.test.tsx.snap +78 -0
  63. package/src/__snapshots__/Badge.test.tsx.snap +44 -0
  64. package/src/__snapshots__/Box.test.tsx.snap +159 -0
  65. package/src/__snapshots__/TextArea.test.tsx.snap +12 -0
  66. package/src/__snapshots__/TextField.test.tsx.snap +38 -1
  67. package/src/index.tsx +1 -0
  68. package/src/setupTests.ts +45 -2
  69. package/src/test-utils.tsx +1 -0
@@ -0,0 +1,665 @@
1
+ import {act, fireEvent} from "@testing-library/react-native";
2
+ import React from "react";
3
+
4
+ import {Box} from "./Box";
5
+ import {Text} from "./Text";
6
+ import {renderWithTheme} from "./test-utils";
7
+
8
+ // Mock the mediaQueryLargerThan function
9
+ jest.mock("./MediaQuery", () => ({
10
+ mediaQueryLargerThan: jest.fn(() => false),
11
+ }));
12
+
13
+ describe("Box", () => {
14
+ describe("basic rendering", () => {
15
+ it("should render with default props", () => {
16
+ const {root} = renderWithTheme(<Box />);
17
+ expect(root).toBeTruthy();
18
+ });
19
+
20
+ it("should render children", () => {
21
+ const {getByText} = renderWithTheme(
22
+ <Box>
23
+ <Text>Test Content</Text>
24
+ </Box>
25
+ );
26
+ expect(getByText("Test Content")).toBeTruthy();
27
+ });
28
+
29
+ it("should apply testID", () => {
30
+ const {getByTestId} = renderWithTheme(<Box testID="test-box" />);
31
+ expect(getByTestId("test-box")).toBeTruthy();
32
+ });
33
+ });
34
+
35
+ describe("layout props", () => {
36
+ it("should apply direction prop", () => {
37
+ const {root} = renderWithTheme(<Box direction="column" />);
38
+ const view = root.findByType("View");
39
+ expect(view.props.style).toMatchObject({
40
+ flexDirection: "column",
41
+ display: "flex"
42
+ });
43
+ });
44
+
45
+ it("should apply responsive direction props", () => {
46
+ const {root} = renderWithTheme(<Box smDirection="row" />);
47
+ expect(root).toBeTruthy();
48
+ });
49
+
50
+ it("should apply flex grow", () => {
51
+ const {root} = renderWithTheme(<Box flex="grow" />);
52
+ const view = root.findByType("View");
53
+ expect(view.props.style).toMatchObject({
54
+ flexGrow: 1,
55
+ flexShrink: 1,
56
+ display: "flex"
57
+ });
58
+ });
59
+
60
+ it("should apply flex shrink", () => {
61
+ const {root} = renderWithTheme(<Box flex="shrink" />);
62
+ const view = root.findByType("View");
63
+ expect(view.props.style).toMatchObject({
64
+ flexShrink: 1,
65
+ display: "flex"
66
+ });
67
+ });
68
+
69
+ it("should apply flex none", () => {
70
+ const {root} = renderWithTheme(<Box flex="none" />);
71
+ const view = root.findByType("View");
72
+ expect(view.props.style).toMatchObject({
73
+ flex: 0,
74
+ display: "flex"
75
+ });
76
+ });
77
+
78
+ it("should apply justifyContent", () => {
79
+ const {root} = renderWithTheme(<Box justifyContent="center" />);
80
+ const view = root.findByType("View");
81
+ expect(view.props.style).toMatchObject({
82
+ justifyContent: "center"
83
+ });
84
+ });
85
+
86
+ it("should apply alignItems", () => {
87
+ const {root} = renderWithTheme(<Box alignItems="center" />);
88
+ const view = root.findByType("View");
89
+ expect(view.props.style).toMatchObject({
90
+ alignItems: "center"
91
+ });
92
+ });
93
+
94
+ it("should apply alignContent", () => {
95
+ const {root} = renderWithTheme(<Box alignContent="center" />);
96
+ const view = root.findByType("View");
97
+ expect(view.props.style).toMatchObject({
98
+ alignContent: "center"
99
+ });
100
+ });
101
+
102
+ it("should apply alignSelf", () => {
103
+ const {root} = renderWithTheme(<Box alignSelf="center" />);
104
+ const view = root.findByType("View");
105
+ expect(view.props.style).toMatchObject({
106
+ alignSelf: "center"
107
+ });
108
+ });
109
+
110
+ it("should apply wrap", () => {
111
+ const {root} = renderWithTheme(<Box wrap />);
112
+ const view = root.findByType("View");
113
+ expect(view.props.style).toMatchObject({
114
+ flexWrap: "wrap",
115
+ alignItems: "flex-start"
116
+ });
117
+ });
118
+
119
+ it("should apply gap", () => {
120
+ const {root} = renderWithTheme(<Box gap={4} />);
121
+ const view = root.findByType("View");
122
+ expect(view.props.style).toMatchObject({
123
+ gap: 16
124
+ });
125
+ });
126
+ });
127
+
128
+ describe("spacing props", () => {
129
+ it("should apply padding", () => {
130
+ const {root} = renderWithTheme(<Box padding={4} />);
131
+ const view = root.findByType("View");
132
+ expect(view.props.style).toMatchObject({
133
+ padding: 16
134
+ });
135
+ });
136
+
137
+ it("should apply paddingX", () => {
138
+ const {root} = renderWithTheme(<Box paddingX={2} />);
139
+ const view = root.findByType("View");
140
+ expect(view.props.style).toMatchObject({
141
+ paddingLeft: 8,
142
+ paddingRight: 8
143
+ });
144
+ });
145
+
146
+ it("should apply paddingY", () => {
147
+ const {root} = renderWithTheme(<Box paddingY={3} />);
148
+ const view = root.findByType("View");
149
+ expect(view.props.style).toMatchObject({
150
+ paddingTop: 12,
151
+ paddingBottom: 12
152
+ });
153
+ });
154
+
155
+ it("should apply margin", () => {
156
+ const {root} = renderWithTheme(<Box margin={4} />);
157
+ const view = root.findByType("View");
158
+ expect(view.props.style).toMatchObject({
159
+ margin: 16
160
+ });
161
+ });
162
+
163
+ it("should apply marginTop", () => {
164
+ const {root} = renderWithTheme(<Box marginTop={2} />);
165
+ const view = root.findByType("View");
166
+ expect(view.props.style).toMatchObject({
167
+ marginTop: 8
168
+ });
169
+ });
170
+
171
+ it("should apply marginBottom", () => {
172
+ const {root} = renderWithTheme(<Box marginBottom={2} />);
173
+ const view = root.findByType("View");
174
+ expect(view.props.style).toMatchObject({
175
+ marginBottom: 8
176
+ });
177
+ });
178
+
179
+ it("should apply marginLeft", () => {
180
+ const {root} = renderWithTheme(<Box marginLeft={2} />);
181
+ const view = root.findByType("View");
182
+ expect(view.props.style).toMatchObject({
183
+ marginLeft: 8
184
+ });
185
+ });
186
+
187
+ it("should apply marginRight", () => {
188
+ const {root} = renderWithTheme(<Box marginRight={2} />);
189
+ const view = root.findByType("View");
190
+ expect(view.props.style).toMatchObject({
191
+ marginRight: 8
192
+ });
193
+ });
194
+ });
195
+
196
+ describe("sizing props", () => {
197
+ it("should apply width", () => {
198
+ const {root} = renderWithTheme(<Box width={100} />);
199
+ const view = root.findByType("View");
200
+ expect(view.props.style).toMatchObject({
201
+ width: 100
202
+ });
203
+ });
204
+
205
+ it("should apply height", () => {
206
+ const {root} = renderWithTheme(<Box height={100} />);
207
+ const view = root.findByType("View");
208
+ expect(view.props.style).toMatchObject({
209
+ height: 100
210
+ });
211
+ });
212
+
213
+ it("should apply string width", () => {
214
+ const {root} = renderWithTheme(<Box width="50%" />);
215
+ const view = root.findByType("View");
216
+ expect(view.props.style).toMatchObject({
217
+ width: "50%"
218
+ });
219
+ });
220
+
221
+ it("should apply string height", () => {
222
+ const {root} = renderWithTheme(<Box height="50%" />);
223
+ const view = root.findByType("View");
224
+ expect(view.props.style).toMatchObject({
225
+ height: "50%"
226
+ });
227
+ });
228
+ });
229
+
230
+ describe("position props", () => {
231
+ it("should apply position absolute", () => {
232
+ const {root} = renderWithTheme(<Box position="absolute" />);
233
+ const view = root.findByType("View");
234
+ expect(view.props.style).toMatchObject({
235
+ position: "absolute"
236
+ });
237
+ });
238
+
239
+ it("should apply top", () => {
240
+ const {root} = renderWithTheme(<Box top />);
241
+ const view = root.findByType("View");
242
+ expect(view.props.style).toMatchObject({
243
+ top: 0
244
+ });
245
+ });
246
+
247
+ it("should apply bottom", () => {
248
+ const {root} = renderWithTheme(<Box bottom />);
249
+ const view = root.findByType("View");
250
+ expect(view.props.style).toMatchObject({
251
+ bottom: 0
252
+ });
253
+ });
254
+
255
+ it("should apply left", () => {
256
+ const {root} = renderWithTheme(<Box left />);
257
+ const view = root.findByType("View");
258
+ expect(view.props.style).toMatchObject({
259
+ left: 0
260
+ });
261
+ });
262
+
263
+ it("should apply right", () => {
264
+ const {root} = renderWithTheme(<Box right />);
265
+ const view = root.findByType("View");
266
+ expect(view.props.style).toMatchObject({
267
+ right: 0
268
+ });
269
+ });
270
+
271
+ it("should apply zIndex", () => {
272
+ const {root} = renderWithTheme(<Box zIndex={10} />);
273
+ const view = root.findByType("View");
274
+ expect(view.props.style).toMatchObject({
275
+ zIndex: 10
276
+ });
277
+ });
278
+ });
279
+
280
+ describe("color and surface props", () => {
281
+ it("should apply background color", () => {
282
+ const {root} = renderWithTheme(<Box color="primary" />);
283
+ const view = root.findByType("View");
284
+ expect(view.props.style.backgroundColor).toBeDefined();
285
+ });
286
+ });
287
+
288
+ describe("border props", () => {
289
+ it("should apply border", () => {
290
+ const {root} = renderWithTheme(<Box border="default" />);
291
+ const view = root.findByType("View");
292
+ expect(view.props.style.borderColor).toBeDefined();
293
+ expect(view.props.style.borderWidth).toBe(1);
294
+ });
295
+
296
+ it("should apply borderTop", () => {
297
+ const {root} = renderWithTheme(<Box borderTop="default" />);
298
+ const view = root.findByType("View");
299
+ expect(view.props.style.borderTopColor).toBeDefined();
300
+ expect(view.props.style.borderTopWidth).toBe(1);
301
+ });
302
+
303
+ it("should apply borderBottom", () => {
304
+ const {root} = renderWithTheme(<Box borderBottom="default" />);
305
+ const view = root.findByType("View");
306
+ expect(view.props.style.borderBottomColor).toBeDefined();
307
+ expect(view.props.style.borderBottomWidth).toBe(1);
308
+ });
309
+
310
+ it("should apply borderLeft", () => {
311
+ const {root} = renderWithTheme(<Box borderLeft="default" />);
312
+ const view = root.findByType("View");
313
+ expect(view.props.style.borderLeftColor).toBeDefined();
314
+ expect(view.props.style.borderLeftWidth).toBe(1);
315
+ });
316
+
317
+ it("should apply borderRight", () => {
318
+ const {root} = renderWithTheme(<Box borderRight="default" />);
319
+ const view = root.findByType("View");
320
+ expect(view.props.style.borderRightColor).toBeDefined();
321
+ expect(view.props.style.borderRightWidth).toBe(1);
322
+ });
323
+
324
+ it("should adjust width for border", () => {
325
+ const {root} = renderWithTheme(<Box border="default" width={100} />);
326
+ const view = root.findByType("View");
327
+ expect(view.props.style.width).toBe(104); // 100 + 2*2 for border
328
+ });
329
+
330
+ it("should adjust height for border", () => {
331
+ const {root} = renderWithTheme(<Box border="default" height={100} />);
332
+ const view = root.findByType("View");
333
+ expect(view.props.style.height).toBe(104); // 100 + 2*2 for border
334
+ });
335
+ });
336
+
337
+ describe("rounding props", () => {
338
+ it("should apply rounding", () => {
339
+ const {root} = renderWithTheme(<Box rounding="md" />);
340
+ const view = root.findByType("View");
341
+ expect(view.props.style.borderRadius).toBe(4);
342
+ });
343
+
344
+ it("should apply circle rounding with width", () => {
345
+ const {root} = renderWithTheme(<Box rounding="circle" width={50} />);
346
+ const view = root.findByType("View");
347
+ expect(view.props.style.borderRadius).toBe(50);
348
+ });
349
+
350
+ it("should apply circle rounding with height", () => {
351
+ const {root} = renderWithTheme(<Box rounding="circle" height={50} />);
352
+ const view = root.findByType("View");
353
+ expect(view.props.style.borderRadius).toBe(50);
354
+ });
355
+
356
+ it("should warn when using circle without dimensions", () => {
357
+ const consoleSpy = jest.spyOn(console, "warn").mockImplementation();
358
+ renderWithTheme(<Box rounding="circle" />);
359
+ expect(consoleSpy).toHaveBeenCalledWith("Cannot use Box rounding='circle' without height or width.");
360
+ consoleSpy.mockRestore();
361
+ });
362
+ });
363
+
364
+ describe("display props", () => {
365
+ it("should apply display none", () => {
366
+ const {root} = renderWithTheme(<Box display="none" />);
367
+ const view = root.findByType("View");
368
+ expect(view.props.style).toMatchObject({
369
+ display: "none"
370
+ });
371
+ });
372
+
373
+ it("should apply display flex", () => {
374
+ const {root} = renderWithTheme(<Box display="flex" />);
375
+ const view = root.findByType("View");
376
+ expect(view.props.style).toMatchObject({
377
+ flex: undefined
378
+ });
379
+ });
380
+
381
+ it("should apply display block", () => {
382
+ const {root} = renderWithTheme(<Box display="block" />);
383
+ const view = root.findByType("View");
384
+ expect(view.props.style).toMatchObject({
385
+ flex: 0,
386
+ flexDirection: "row"
387
+ });
388
+ });
389
+ });
390
+
391
+ describe("overflow props", () => {
392
+ it("should apply overflow scroll", () => {
393
+ const {root} = renderWithTheme(<Box overflow="scroll" />);
394
+ const view = root.findByType("View");
395
+ expect(view.props.style).toMatchObject({
396
+ overflow: "scroll"
397
+ });
398
+ });
399
+
400
+ it("should apply overflow scrollY", () => {
401
+ const {root} = renderWithTheme(<Box overflow="scrollY" />);
402
+ const view = root.findByType("View");
403
+ expect(view.props.style).toMatchObject({
404
+ overflow: "scroll"
405
+ });
406
+ });
407
+
408
+ it("should apply overflow hidden", () => {
409
+ const {root} = renderWithTheme(<Box overflow="hidden" />);
410
+ const view = root.findByType("View");
411
+ expect(view.props.style).toMatchObject({
412
+ overflow: "hidden"
413
+ });
414
+ });
415
+ });
416
+
417
+ describe("shadow props", () => {
418
+ it("should apply shadow", () => {
419
+ const {root} = renderWithTheme(<Box shadow />);
420
+ const view = root.findByType("View");
421
+ expect(view.props.style).toBeDefined();
422
+ });
423
+ });
424
+
425
+ describe("clickable behavior", () => {
426
+ it("should render as Pressable when onClick is provided", () => {
427
+ const mockOnClick = jest.fn();
428
+ const {root} = renderWithTheme(
429
+ <Box onClick={mockOnClick} accessibilityLabel="Click me" accessibilityHint="Tap to trigger action">
430
+ <Text>Clickable content</Text>
431
+ </Box>
432
+ );
433
+
434
+ expect(root).toBeTruthy();
435
+ // Just verify the component renders without error when onClick is provided
436
+ });
437
+
438
+ it("should call onClick when pressed", async () => {
439
+ const mockOnClick = jest.fn();
440
+ const {getByTestId} = renderWithTheme(
441
+ <Box
442
+ onClick={mockOnClick}
443
+ testID="clickable-box"
444
+ accessibilityLabel="Click me"
445
+ accessibilityHint="Tap to trigger action"
446
+ />
447
+ );
448
+
449
+ const pressable = getByTestId("clickable-box-clickable");
450
+ await act(async () => {
451
+ fireEvent.press(pressable);
452
+ });
453
+
454
+ expect(mockOnClick).toHaveBeenCalledTimes(1);
455
+ });
456
+
457
+ it("should apply accessibility props to Pressable", () => {
458
+ const mockOnClick = jest.fn();
459
+ const {getByTestId} = renderWithTheme(
460
+ <Box
461
+ onClick={mockOnClick}
462
+ testID="accessible-box"
463
+ accessibilityLabel="Click me"
464
+ accessibilityHint="Tap to trigger action"
465
+ />
466
+ );
467
+
468
+ const pressable = getByTestId("accessible-box-clickable");
469
+ expect(pressable).toBeTruthy();
470
+ // Basic check that accessibility props are being applied
471
+ expect(pressable.props).toBeDefined();
472
+ });
473
+ });
474
+
475
+ describe("scroll behavior", () => {
476
+ it("should render ScrollView when scroll is enabled", () => {
477
+ const {root} = renderWithTheme(<Box scroll />);
478
+ expect(root).toBeTruthy();
479
+ // Just verify the component renders without error when scroll is enabled
480
+ });
481
+
482
+ it("should enable horizontal scrolling when overflow is scrollX", () => {
483
+ const {root} = renderWithTheme(<Box scroll overflow="scrollX" />);
484
+ expect(root).toBeTruthy();
485
+ // Just verify the component renders without error when horizontal scroll is enabled
486
+ });
487
+
488
+ it("should call onScroll callback", () => {
489
+ const mockOnScroll = jest.fn();
490
+ const {root} = renderWithTheme(<Box scroll onScroll={mockOnScroll} />);
491
+ expect(root).toBeTruthy();
492
+ // Just verify the component renders without error when onScroll is provided
493
+ });
494
+ });
495
+
496
+ describe("keyboard avoidance", () => {
497
+ it("should render KeyboardAvoidingView when avoidKeyboard is enabled", () => {
498
+ const {root} = renderWithTheme(<Box avoidKeyboard />);
499
+ expect(root).toBeTruthy();
500
+ // Just verify the component renders without error when avoidKeyboard is enabled
501
+ });
502
+
503
+ it("should apply keyboard offset", () => {
504
+ const {root} = renderWithTheme(<Box avoidKeyboard keyboardOffset={20} />);
505
+ expect(root).toBeTruthy();
506
+ // Just verify the component renders without error when keyboard offset is provided
507
+ });
508
+ });
509
+
510
+ describe("hover events", () => {
511
+ it("should call onHoverStart", async () => {
512
+ const mockOnHoverStart = jest.fn();
513
+ const {getByTestId} = renderWithTheme(
514
+ <Box onHoverStart={mockOnHoverStart} testID="hover-box" />
515
+ );
516
+
517
+ const view = getByTestId("hover-box");
518
+ await act(async () => {
519
+ fireEvent(view, "pointerEnter");
520
+ });
521
+
522
+ expect(mockOnHoverStart).toHaveBeenCalledTimes(1);
523
+ });
524
+
525
+ it("should call onHoverEnd", async () => {
526
+ const mockOnHoverEnd = jest.fn();
527
+ const {getByTestId} = renderWithTheme(
528
+ <Box onHoverEnd={mockOnHoverEnd} testID="hover-box" />
529
+ );
530
+
531
+ const view = getByTestId("hover-box");
532
+ await act(async () => {
533
+ fireEvent(view, "pointerLeave");
534
+ });
535
+
536
+ expect(mockOnHoverEnd).toHaveBeenCalledTimes(1);
537
+ });
538
+ });
539
+
540
+ describe("ref forwarding", () => {
541
+ it("should expose scrollToEnd method", () => {
542
+ const ref = React.createRef<any>();
543
+ renderWithTheme(<Box ref={ref} scroll />);
544
+
545
+ expect(ref.current).toBeTruthy();
546
+ expect(typeof ref.current.scrollToEnd).toBe("function");
547
+ });
548
+
549
+ it("should expose scrollTo method", () => {
550
+ const ref = React.createRef<any>();
551
+ renderWithTheme(<Box ref={ref} scroll />);
552
+
553
+ expect(ref.current).toBeTruthy();
554
+ expect(typeof ref.current.scrollTo).toBe("function");
555
+ });
556
+ });
557
+
558
+ describe("dangerous inline styles", () => {
559
+ it("should apply dangerouslySetInlineStyle", () => {
560
+ const {root} = renderWithTheme(
561
+ <Box dangerouslySetInlineStyle={{ __style: { backgroundColor: "red" } }} />
562
+ );
563
+ const view = root.findByType("View");
564
+ expect(view.props.style).toMatchObject({
565
+ backgroundColor: "red"
566
+ });
567
+ });
568
+ });
569
+
570
+ describe("warnings", () => {
571
+ it("should warn when using wrap and alignItems together", () => {
572
+ const consoleSpy = jest.spyOn(console, "warn").mockImplementation();
573
+ renderWithTheme(<Box wrap alignItems="center" />);
574
+ expect(consoleSpy).toHaveBeenCalledWith("React Native doesn't support wrap and alignItems together.");
575
+ consoleSpy.mockRestore();
576
+ });
577
+ });
578
+
579
+ describe("edge cases", () => {
580
+ it("should handle undefined children", () => {
581
+ const {root} = renderWithTheme(<Box>{undefined}</Box>);
582
+ expect(root).toBeTruthy();
583
+ });
584
+
585
+ it("should handle null children", () => {
586
+ const {root} = renderWithTheme(<Box>{null}</Box>);
587
+ expect(root).toBeTruthy();
588
+ });
589
+
590
+ it("should handle multiple children", () => {
591
+ const {getByText} = renderWithTheme(
592
+ <Box>
593
+ <Text>First</Text>
594
+ <Text>Second</Text>
595
+ </Box>
596
+ );
597
+ expect(getByText("First")).toBeTruthy();
598
+ expect(getByText("Second")).toBeTruthy();
599
+ });
600
+
601
+ it("should handle zero values", () => {
602
+ const {root} = renderWithTheme(<Box padding={0} margin={0} gap={0} />);
603
+ const view = root.findByType("View");
604
+ expect(view.props.style).toMatchObject({
605
+ padding: 0,
606
+ margin: 0,
607
+ gap: 0
608
+ });
609
+ });
610
+ });
611
+
612
+ describe("snapshots", () => {
613
+ it("should match snapshot with default props", () => {
614
+ const component = renderWithTheme(<Box />);
615
+ expect(component.toJSON()).toMatchSnapshot();
616
+ });
617
+
618
+ it("should match snapshot with layout props", () => {
619
+ const component = renderWithTheme(
620
+ <Box
621
+ direction="column"
622
+ flex="grow"
623
+ justifyContent="center"
624
+ alignItems="center"
625
+ padding={4}
626
+ margin={2}
627
+ />
628
+ );
629
+ expect(component.toJSON()).toMatchSnapshot();
630
+ });
631
+
632
+ it("should match snapshot with clickable props", () => {
633
+ const component = renderWithTheme(
634
+ <Box
635
+ onClick={jest.fn()}
636
+ accessibilityLabel="Click me"
637
+ accessibilityHint="Tap to trigger action"
638
+ />
639
+ );
640
+ expect(component.toJSON()).toMatchSnapshot();
641
+ });
642
+
643
+ it("should match snapshot with scroll enabled", () => {
644
+ const component = renderWithTheme(<Box scroll />);
645
+ expect(component.toJSON()).toMatchSnapshot();
646
+ });
647
+
648
+ it("should match snapshot with keyboard avoidance", () => {
649
+ const component = renderWithTheme(<Box avoidKeyboard />);
650
+ expect(component.toJSON()).toMatchSnapshot();
651
+ });
652
+
653
+ it("should match snapshot with border and rounding", () => {
654
+ const component = renderWithTheme(
655
+ <Box
656
+ border="default"
657
+ rounding="md"
658
+ color="primary"
659
+ shadow
660
+ />
661
+ );
662
+ expect(component.toJSON()).toMatchSnapshot();
663
+ });
664
+ });
665
+ });