@umituz/react-native-splash 1.7.1 → 1.8.1

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 (33) hide show
  1. package/package.json +11 -36
  2. package/src/presentation/components/SplashErrorBoundary.tsx +13 -18
  3. package/src/presentation/components/SplashLoading.tsx +0 -8
  4. package/src/presentation/components/SplashLogo.tsx +0 -10
  5. package/src/presentation/components/SplashTypography.tsx +0 -6
  6. package/lib/__tests__/mocks/expoLinearGradient.js +0 -7
  7. package/lib/__tests__/mocks/reactNative.js +0 -16
  8. package/lib/__tests__/setup.ts +0 -57
  9. package/lib/__tests__/utils/testUtils.tsx +0 -86
  10. package/lib/domain/entities/SplashOptions.ts +0 -74
  11. package/lib/index.ts +0 -31
  12. package/lib/presentation/components/SplashDecorations.tsx +0 -56
  13. package/lib/presentation/components/SplashErrorBoundary.tsx +0 -63
  14. package/lib/presentation/components/SplashLoading.tsx +0 -74
  15. package/lib/presentation/components/SplashLogo.tsx +0 -80
  16. package/lib/presentation/components/SplashScreen.tsx +0 -175
  17. package/lib/presentation/components/SplashTypography.tsx +0 -72
  18. package/lib/presentation/hooks/useSplash.ts +0 -70
  19. package/lib/presentation/utils/splashGradient.utils.ts +0 -47
  20. package/lib/types/expo-linear-gradient.d.ts +0 -12
  21. package/src/__tests__/SplashScreen.test.tsx +0 -161
  22. package/src/__tests__/accessibility/Accessibility.test.tsx +0 -264
  23. package/src/__tests__/basic/Basic.test.tsx +0 -106
  24. package/src/__tests__/basic/Simple.test.tsx +0 -32
  25. package/src/__tests__/edge-cases/EdgeCases.test.tsx +0 -446
  26. package/src/__tests__/integration/SplashScreen.integration.test.tsx +0 -200
  27. package/src/__tests__/mocks/expoLinearGradient.js +0 -7
  28. package/src/__tests__/mocks/reactNative.js +0 -16
  29. package/src/__tests__/performance/Performance.test.tsx +0 -297
  30. package/src/__tests__/setup.ts +0 -57
  31. package/src/__tests__/useSplash.test.tsx +0 -123
  32. package/src/__tests__/utils/testUtils.tsx +0 -86
  33. package/src/__tests__/visual/VisualRegression.test.tsx +0 -338
@@ -1,446 +0,0 @@
1
- /**
2
- * Edge Case Tests - Error Scenarios and Edge Cases
3
- */
4
-
5
- import React from 'react';
6
- import { render, fireEvent, act, createErrorComponent } from '../utils/testUtils';
7
- import { SplashScreen } from '../../presentation/components/SplashScreen';
8
- import { useSplash } from '../../presentation/hooks/useSplash';
9
-
10
- describe('Edge Case Tests', () => {
11
- beforeEach(() => {
12
- jest.useFakeTimers();
13
- });
14
-
15
- afterEach(() => {
16
- jest.useRealTimers();
17
- });
18
-
19
- describe('Empty and Null Props', () => {
20
- it('handles empty string props', () => {
21
- const props = {
22
- appName: '',
23
- tagline: '',
24
- loadingText: '',
25
- visible: true,
26
- };
27
-
28
- const { container } = render(<SplashScreen {...props} />);
29
-
30
- // Should render without crashing
31
- expect(container).toBeTruthy();
32
- });
33
-
34
- it('handles null props', () => {
35
- const props = {
36
- appName: null,
37
- tagline: null,
38
- loadingText: null,
39
- visible: true,
40
- };
41
-
42
- const { container } = render(<SplashScreen {...props} />);
43
-
44
- // Should render without crashing
45
- expect(container).toBeTruthy();
46
- });
47
-
48
- it('handles undefined props', () => {
49
- const props = {
50
- appName: undefined,
51
- tagline: undefined,
52
- loadingText: undefined,
53
- visible: true,
54
- };
55
-
56
- const { container } = render(<SplashScreen {...props} />);
57
-
58
- // Should render without crashing
59
- expect(container).toBeTruthy();
60
- });
61
-
62
- it('handles missing props object', () => {
63
- const { container } = render(<SplashScreen />);
64
-
65
- // Should render with defaults
66
- expect(container).toBeTruthy();
67
- });
68
- });
69
-
70
- describe('Invalid Props', () => {
71
- it('handles invalid gradient colors', () => {
72
- const props = {
73
- appName: 'Test App',
74
- gradientColors: ['invalid-color', 'another-invalid'],
75
- visible: true,
76
- };
77
-
78
- const { container } = render(<SplashScreen {...props} />);
79
-
80
- // Should render without crashing
81
- expect(container).toBeTruthy();
82
- });
83
-
84
- it('handles empty gradient colors array', () => {
85
- const props = {
86
- appName: 'Test App',
87
- gradientColors: [],
88
- visible: true,
89
- };
90
-
91
- const { container } = render(<SplashScreen {...props} />);
92
-
93
- // Should render without crashing
94
- expect(container).toBeTruthy();
95
- });
96
-
97
- it('handles single color in gradient', () => {
98
- const props = {
99
- appName: 'Test App',
100
- gradientColors: ['#FF0000'],
101
- visible: true,
102
- };
103
-
104
- const { container } = render(<SplashScreen {...props} />);
105
-
106
- // Should render without crashing
107
- expect(container).toBeTruthy();
108
- });
109
-
110
- it('handles negative minimum display time', () => {
111
- const props = {
112
- appName: 'Test App',
113
- minimumDisplayTime: -1000,
114
- visible: true,
115
- };
116
-
117
- const { container } = render(<SplashScreen {...props} />);
118
-
119
- // Should render without crashing
120
- expect(container).toBeTruthy();
121
- });
122
-
123
- it('handles very large minimum display time', () => {
124
- const props = {
125
- appName: 'Test App',
126
- minimumDisplayTime: Number.MAX_SAFE_INTEGER,
127
- visible: true,
128
- };
129
-
130
- const { container } = render(<SplashScreen {...props} />);
131
-
132
- // Should render without crashing
133
- expect(container).toBeTruthy();
134
- });
135
- });
136
-
137
- describe('Error Scenarios', () => {
138
- it('handles renderLogo function throwing error', () => {
139
- const props = {
140
- appName: 'Test App',
141
- renderLogo: createErrorComponent('Logo error'),
142
- visible: true,
143
- };
144
-
145
- const { getByText } = render(<SplashScreen {...props} />);
146
-
147
- // Should show error boundary fallback
148
- expect(getByText('Something went wrong')).toBeTruthy();
149
- });
150
-
151
- it('handles renderContent function throwing error', () => {
152
- const props = {
153
- appName: 'Test App',
154
- renderContent: createErrorComponent('Content error'),
155
- visible: true,
156
- };
157
-
158
- const { getByText } = render(<SplashScreen {...props} />);
159
-
160
- // Should show error boundary fallback
161
- expect(getByText('Something went wrong')).toBeTruthy();
162
- });
163
-
164
- it('handles renderFooter function throwing error', () => {
165
- const props = {
166
- appName: 'Test App',
167
- renderFooter: createErrorComponent('Footer error'),
168
- visible: true,
169
- };
170
-
171
- const { getByText } = render(<SplashScreen {...props} />);
172
-
173
- // Should show error boundary fallback
174
- expect(getByText('Something went wrong')).toBeTruthy();
175
- });
176
-
177
- it('handles onReady callback throwing error', () => {
178
- const props = {
179
- appName: 'Test App',
180
- onReady: () => {
181
- throw new Error('Callback error');
182
- },
183
- visible: true,
184
- };
185
-
186
- const { getByText } = render(<SplashScreen {...props} />);
187
-
188
- act(() => {
189
- jest.advanceTimersByTime(1500);
190
- });
191
-
192
- // Should still render without crashing
193
- expect(getByText('Test App')).toBeTruthy();
194
- });
195
-
196
- it('handles async onReady callback rejection', async () => {
197
- const props = {
198
- appName: 'Test App',
199
- onReady: async () => {
200
- throw new Error('Async callback error');
201
- },
202
- visible: true,
203
- };
204
-
205
- const { getByText } = render(<SplashScreen {...props} />);
206
-
207
- await act(async () => {
208
- jest.advanceTimersByTime(1500);
209
- });
210
-
211
- // Should still render without crashing
212
- expect(getByText('Test App')).toBeTruthy();
213
- });
214
- });
215
-
216
- describe('useSplash Hook Edge Cases', () => {
217
- it('handles multiple markReady calls', () => {
218
- const onReady = jest.fn();
219
- const TestComponent = () => {
220
- const { markReady } = useSplash({ onReady });
221
-
222
- React.useEffect(() => {
223
- markReady();
224
- markReady();
225
- markReady();
226
- }, []);
227
-
228
- return <div>Test</div>;
229
- };
230
-
231
- render(<TestComponent />);
232
-
233
- // Should only call onReady once
234
- expect(onReady).toHaveBeenCalledTimes(1);
235
- });
236
-
237
- it('handles markReady after unmount', () => {
238
- const onReady = jest.fn();
239
- const TestComponent = () => {
240
- const { markReady } = useSplash({ onReady });
241
-
242
- React.useEffect(() => {
243
- const timer = setTimeout(markReady, 1000);
244
- return () => clearTimeout(timer);
245
- }, []);
246
-
247
- return <div>Test</div>;
248
- };
249
-
250
- const { unmount } = render(<TestComponent />);
251
-
252
- // Unmount before timer completes
253
- unmount();
254
-
255
- act(() => {
256
- jest.advanceTimersByTime(1000);
257
- });
258
-
259
- // Should not call onReady after unmount
260
- expect(onReady).not.toHaveBeenCalled();
261
- });
262
-
263
- it('handles zero minimum display time', () => {
264
- const TestComponent = () => {
265
- const { isVisible, markReady } = useSplash({
266
- minimumDisplayTime: 0,
267
- autoHide: true,
268
- });
269
-
270
- React.useEffect(() => {
271
- markReady();
272
- }, []);
273
-
274
- return isVisible ? <div>Visible</div> : <div>Hidden</div>;
275
- };
276
-
277
- const { getByText } = render(<TestComponent />);
278
-
279
- // Should hide immediately
280
- expect(getByText('Hidden')).toBeTruthy();
281
- });
282
- });
283
-
284
- describe('Memory and Performance Edge Cases', () => {
285
- it('handles very long app names', () => {
286
- const longName = 'A'.repeat(1000);
287
- const props = {
288
- appName: longName,
289
- visible: true,
290
- };
291
-
292
- const { getByText } = render(<SplashScreen {...props} />);
293
-
294
- expect(getByText(longName)).toBeTruthy();
295
- });
296
-
297
- it('handles very long taglines', () => {
298
- const longTagline = 'B'.repeat(2000);
299
- const props = {
300
- appName: 'Test App',
301
- tagline: longTagline,
302
- visible: true,
303
- };
304
-
305
- const { getByText } = render(<SplashScreen {...props} />);
306
-
307
- expect(getByText(longTagline)).toBeTruthy();
308
- });
309
-
310
- it('handles many gradient colors', () => {
311
- const manyColors = Array.from({ length: 100 }, (_, i) =>
312
- `#${i.toString(16).padStart(6, '0')}`
313
- );
314
-
315
- const props = {
316
- appName: 'Test App',
317
- gradientColors: manyColors,
318
- visible: true,
319
- };
320
-
321
- const { container } = render(<SplashScreen {...props} />);
322
-
323
- expect(container).toBeTruthy();
324
- });
325
- });
326
-
327
- describe('Component Lifecycle Edge Cases', () => {
328
- it('handles rapid prop changes', () => {
329
- const { rerender } = render(
330
- <SplashScreen appName="App 1" visible={true} />
331
- );
332
-
333
- // Rapidly change props
334
- for (let i = 2; i <= 100; i++) {
335
- rerender(<SplashScreen appName={`App ${i}`} visible={i % 2 === 0} />);
336
- }
337
-
338
- // Should not crash
339
- expect(true).toBe(true);
340
- });
341
-
342
- it('handles visibility toggle during timer', () => {
343
- const onReady = jest.fn();
344
- const { rerender } = render(
345
- <SplashScreen
346
- appName="Test App"
347
- visible={true}
348
- minimumDisplayTime={2000}
349
- onReady={onReady}
350
- />
351
- );
352
-
353
- // Hide before timer completes
354
- rerender(<SplashScreen appName="Test App" visible={false} />);
355
-
356
- act(() => {
357
- jest.advanceTimersByTime(2000);
358
- });
359
-
360
- // Should not call onReady when hidden
361
- expect(onReady).not.toHaveBeenCalled();
362
- });
363
-
364
- it('handles component unmount during timer', () => {
365
- const onReady = jest.fn();
366
- const { unmount } = render(
367
- <SplashScreen
368
- appName="Test App"
369
- visible={true}
370
- minimumDisplayTime={2000}
371
- onReady={onReady}
372
- />
373
- );
374
-
375
- // Unmount before timer completes
376
- unmount();
377
-
378
- act(() => {
379
- jest.advanceTimersByTime(2000);
380
- });
381
-
382
- // Should not call onReady after unmount
383
- expect(onReady).not.toHaveBeenCalled();
384
- });
385
- });
386
-
387
- describe('Localization Edge Cases', () => {
388
- it('handles missing localization keys', () => {
389
- const props = {
390
- appName: undefined,
391
- tagline: undefined,
392
- loadingText: undefined,
393
- visible: true,
394
- };
395
-
396
- const { container } = render(<SplashScreen {...props} />);
397
-
398
- // Should render with empty fallbacks
399
- expect(container).toBeTruthy();
400
- });
401
-
402
- it('handles special characters in text', () => {
403
- const props = {
404
- appName: 'App with émojis 🎉 and spéci@l ch@rs!',
405
- tagline: 'Tàglîne wïth äccénts & spëcial chars',
406
- visible: true,
407
- };
408
-
409
- const { getByText } = render(<SplashScreen {...props} />);
410
-
411
- expect(getByText('App with émojis 🎉 and spéci@l ch@rs!')).toBeTruthy();
412
- expect(getByText('Tàglîne wïth äccénts & spëcial chars')).toBeTruthy();
413
- });
414
- });
415
-
416
- describe('Theme Edge Cases', () => {
417
- it('handles invalid color values', () => {
418
- const props = {
419
- appName: 'Test App',
420
- textColor: 'not-a-color',
421
- iconColor: 'also-not-a-color',
422
- decorationColor: 'definitely-not-a-color',
423
- visible: true,
424
- };
425
-
426
- const { container } = render(<SplashScreen {...props} />);
427
-
428
- // Should render without crashing
429
- expect(container).toBeTruthy();
430
- });
431
-
432
- it('handles transparent colors', () => {
433
- const props = {
434
- appName: 'Test App',
435
- textColor: 'transparent',
436
- backgroundColor: 'transparent',
437
- visible: true,
438
- };
439
-
440
- const { container } = render(<SplashScreen {...props} />);
441
-
442
- // Should render without crashing
443
- expect(container).toBeTruthy();
444
- });
445
- });
446
- });
@@ -1,200 +0,0 @@
1
- /**
2
- * Integration Tests - Complete Splash Screen Flow
3
- */
4
-
5
- import React from 'react';
6
- import { render, fireEvent, act } from '../utils/testUtils';
7
- import { SplashScreen } from '../../presentation/components/SplashScreen';
8
- import { useSplash } from '../../presentation/hooks/useSplash';
9
-
10
- describe('SplashScreen Integration Tests', () => {
11
- const defaultProps = {
12
- appName: 'Integration Test App',
13
- tagline: 'Testing complete flow',
14
- visible: true,
15
- };
16
-
17
- beforeEach(() => {
18
- jest.useFakeTimers();
19
- });
20
-
21
- afterEach(() => {
22
- jest.useRealTimers();
23
- });
24
-
25
- it('completes full splash screen lifecycle', async () => {
26
- const onReady = jest.fn();
27
- const props = { ...defaultProps, onReady };
28
-
29
- const { getByText, queryByText, rerender } = render(<SplashScreen {...props} />);
30
-
31
- // Initial render
32
- expect(getByText('Integration Test App')).toBeTruthy();
33
- expect(getByText('Testing complete flow')).toBeTruthy();
34
- expect(getByText('Loading...')).toBeTruthy();
35
-
36
- // Wait for minimum display time
37
- act(() => {
38
- jest.advanceTimersByTime(1500);
39
- });
40
-
41
- expect(onReady).toHaveBeenCalledTimes(1);
42
-
43
- // Hide splash screen
44
- rerender(<SplashScreen {...props} visible={false} />);
45
-
46
- expect(queryByText('Integration Test App')).toBeFalsy();
47
- });
48
-
49
- it('handles custom render functions throughout lifecycle', () => {
50
- const CustomLogo = () => <div testID="custom-logo">Custom Logo</div>;
51
- const CustomContent = () => <div testID="custom-content">Custom Content</div>;
52
- const CustomFooter = () => <div testID="custom-footer">Custom Footer</div>;
53
-
54
- const props = {
55
- ...defaultProps,
56
- renderLogo: () => <CustomLogo />,
57
- renderContent: () => <CustomContent />,
58
- renderFooter: () => <CustomFooter />,
59
- };
60
-
61
- const { getByTestId } = render(<SplashScreen {...props} />);
62
-
63
- expect(getByTestId('custom-logo')).toBeTruthy();
64
- expect(getByTestId('custom-content')).toBeTruthy();
65
- expect(getByTestId('custom-footer')).toBeTruthy();
66
- });
67
-
68
- it('integrates with useSplash hook properly', () => {
69
- const TestComponent = () => {
70
- const { isVisible, markReady } = useSplash({
71
- minimumDisplayTime: 1000,
72
- });
73
-
74
- return (
75
- <SplashScreen
76
- {...defaultProps}
77
- visible={isVisible}
78
- onReady={markReady}
79
- />
80
- );
81
- };
82
-
83
- const { getByText, queryByText } = render(<TestComponent />);
84
-
85
- expect(getByText('Integration Test App')).toBeTruthy();
86
-
87
- act(() => {
88
- jest.advanceTimersByTime(1000);
89
- });
90
-
91
- // Should auto-hide after markReady is called
92
- act(() => {
93
- jest.advanceTimersByTime(1000);
94
- });
95
-
96
- expect(queryByText('Integration Test App')).toBeFalsy();
97
- });
98
-
99
- it('handles gradient and color theming integration', () => {
100
- const props = {
101
- ...defaultProps,
102
- gradientColors: ['#FF0000', '#00FF00', '#0000FF'],
103
- textColor: '#FFFFFF',
104
- iconColor: '#FFFF00',
105
- decorationColor: 'rgba(255, 255, 255, 0.1)',
106
- };
107
-
108
- const { getByTestId } = render(<SplashScreen {...props} />);
109
-
110
- expect(getByTestId('linear-gradient')).toBeTruthy();
111
- });
112
-
113
- it('manages error states across components', () => {
114
- const ErrorComponent = () => {
115
- throw new Error('Test error');
116
- };
117
-
118
- const props = {
119
- ...defaultProps,
120
- renderLogo: () => <ErrorComponent />,
121
- };
122
-
123
- const { getByText } = render(<SplashScreen {...props} />);
124
-
125
- // Should show error boundary fallback
126
- expect(getByText('Something went wrong')).toBeTruthy();
127
- });
128
-
129
- it('handles responsive design with safe areas', () => {
130
- const props = {
131
- ...defaultProps,
132
- showLoading: true,
133
- };
134
-
135
- const { getByText } = render(<SplashScreen {...props} />);
136
-
137
- // Should render with proper spacing for safe areas
138
- expect(getByText('Integration Test App')).toBeTruthy();
139
- expect(getByText('Loading...')).toBeTruthy();
140
- });
141
-
142
- it('maintains performance during complex scenarios', async () => {
143
- const ComplexComponent = () => {
144
- const [count, setCount] = React.useState(0);
145
-
146
- React.useEffect(() => {
147
- const interval = setInterval(() => {
148
- setCount(c => c + 1);
149
- }, 100);
150
-
151
- return () => clearInterval(interval);
152
- }, []);
153
-
154
- return (
155
- <SplashScreen
156
- {...defaultProps}
157
- renderContent={() => <div>Count: {count}</div>}
158
- />
159
- );
160
- };
161
-
162
- const { measureRenderTime } = require('../utils/testUtils');
163
- const renderTime = await measureRenderTime(<ComplexComponent />);
164
-
165
- // Should render within reasonable time
166
- expect(renderTime).toBeLessThan(100); // 100ms
167
- });
168
-
169
- it('handles localization integration', () => {
170
- const props = {
171
- appName: undefined, // Will use localization
172
- tagline: undefined, // Will use localization
173
- loadingText: undefined, // Will use localization
174
- };
175
-
176
- const { getByText } = render(<SplashScreen {...props} />);
177
-
178
- // Should show fallback text from localization mock
179
- expect(getByText('')).toBeTruthy(); // Empty fallback
180
- });
181
-
182
- it('manages memory correctly during mount/unmount cycles', () => {
183
- const { trackMemoryUsage } = require('../utils/testUtils');
184
- const memoryTracker = trackMemoryUsage();
185
-
186
- const { unmount } = render(<SplashScreen {...defaultProps} />);
187
-
188
- // Force garbage collection if available
189
- if (global.gc) {
190
- global.gc();
191
- }
192
-
193
- const memoryIncrease = memoryTracker.getMemoryIncrease();
194
-
195
- // Memory increase should be minimal
196
- expect(memoryIncrease).toBeLessThan(1024 * 1024); // 1MB
197
-
198
- unmount();
199
- });
200
- });
@@ -1,7 +0,0 @@
1
- /**
2
- * Expo Linear Gradient Mock
3
- */
4
-
5
- module.exports = {
6
- LinearGradient: ({ children, testID }) => ({ type: 'LinearGradient', props: { testID }, children }),
7
- };
@@ -1,16 +0,0 @@
1
- /**
2
- * React Native Mocks
3
- */
4
-
5
- const React = require('react');
6
-
7
- module.exports = {
8
- View: ({ children, testID, style }) => React.createElement('View', { testID, style }, children),
9
- Text: ({ children, testID, style }) => React.createElement('Text', { testID, style }, children),
10
- StyleSheet: {
11
- create: jest.fn((styles) => styles),
12
- flatten: jest.fn((style) => style)
13
- },
14
- Dimensions: { get: jest.fn(() => ({ width: 375, height: 667 })) },
15
- LinearGradient: ({ children, testID, style }) => React.createElement('LinearGradient', { testID, style }, children),
16
- };