@umituz/react-native-settings 4.20.62 → 4.21.2
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/package.json +6 -61
- package/src/domains/feedback/domain/entities/FeedbackEntity.ts +8 -8
- package/src/domains/gamification/components/AchievementCard.tsx +142 -0
- package/src/domains/gamification/components/AchievementItem.tsx +182 -0
- package/src/domains/gamification/components/AchievementToast.tsx +122 -0
- package/src/domains/gamification/components/GamificationScreen/AchievementsList.tsx +84 -0
- package/src/domains/gamification/components/GamificationScreen/Header.tsx +29 -0
- package/src/domains/gamification/components/GamificationScreen/StatsGrid.tsx +51 -0
- package/src/domains/gamification/components/GamificationScreen/index.tsx +111 -0
- package/src/domains/gamification/components/GamificationScreen/styles.ts +43 -0
- package/src/domains/gamification/components/GamificationScreen/types.ts +77 -0
- package/src/domains/gamification/components/GamificationScreenWrapper.tsx +4 -4
- package/src/domains/gamification/components/GamificationSettingsItem.tsx +1 -1
- package/src/domains/gamification/components/LevelProgress.tsx +129 -0
- package/src/domains/gamification/components/PointsBadge.tsx +60 -0
- package/src/domains/gamification/components/StatsCard.tsx +89 -0
- package/src/domains/gamification/components/StreakDisplay.tsx +119 -0
- package/src/domains/gamification/components/index.ts +13 -0
- package/src/domains/gamification/examples/gamification.config.example.ts +1 -1
- package/src/domains/gamification/hooks/useGamification.ts +91 -0
- package/src/domains/gamification/index.ts +46 -19
- package/src/domains/gamification/store/gamificationStore.ts +162 -0
- package/src/domains/gamification/types/index.ts +95 -23
- package/src/domains/gamification/types/settings.ts +28 -0
- package/src/domains/gamification/utils/calculations.ts +85 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -51
- package/.github/ISSUE_TEMPLATE/documentation.md +0 -52
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -63
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -84
- package/AI_AGENT_GUIDELINES.md +0 -367
- package/ARCHITECTURE.md +0 -246
- package/CHANGELOG.md +0 -67
- package/CODE_OF_CONDUCT.md +0 -75
- package/CONTRIBUTING.md +0 -107
- package/DOCUMENTATION_MIGRATION.md +0 -319
- package/DOCUMENTATION_TEMPLATE.md +0 -155
- package/SECURITY.md +0 -98
- package/SETTINGS_SCREEN_GUIDE.md +0 -185
- package/TESTING.md +0 -358
- package/src/__tests__/integration.test.tsx +0 -371
- package/src/__tests__/performance.test.tsx +0 -369
- package/src/__tests__/setup.test.tsx +0 -20
- package/src/__tests__/setup.ts +0 -154
- package/src/domains/about/__tests__/integration.test.tsx +0 -328
- package/src/domains/about/__tests__/types.d.ts +0 -5
- package/src/domains/about/domain/entities/__tests__/AppInfo.test.ts +0 -93
- package/src/domains/about/infrastructure/repositories/__tests__/AboutRepository.test.ts +0 -153
- package/src/domains/about/presentation/components/__tests__/AboutContent.simple.test.tsx +0 -178
- package/src/domains/about/presentation/components/__tests__/AboutContent.test.tsx +0 -293
- package/src/domains/about/presentation/components/__tests__/AboutHeader.test.tsx +0 -201
- package/src/domains/about/presentation/components/__tests__/AboutSettingItem.test.tsx +0 -71
- package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.simple.test.tsx +0 -229
- package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.test.tsx +0 -240
- package/src/domains/about/presentation/screens/__tests__/AboutScreen.simple.test.tsx +0 -199
- package/src/domains/about/presentation/screens/__tests__/AboutScreen.test.tsx +0 -366
- package/src/domains/about/utils/__tests__/index.test.ts +0 -408
- package/src/domains/appearance/__tests__/components/AppearanceScreen.test.tsx +0 -195
- package/src/domains/appearance/__tests__/hooks/index.test.tsx +0 -232
- package/src/domains/appearance/__tests__/integration/index.test.tsx +0 -207
- package/src/domains/appearance/__tests__/services/appearanceService.test.ts +0 -299
- package/src/domains/appearance/__tests__/setup.ts +0 -88
- package/src/domains/appearance/__tests__/stores/appearanceStore.test.tsx +0 -175
- package/src/domains/cloud-sync/presentation/components/__tests__/CloudSyncSetting.test.tsx +0 -78
- package/src/domains/legal/__tests__/ContentValidationService.test.ts +0 -195
- package/src/domains/legal/__tests__/StyleCacheService.test.ts +0 -110
- package/src/domains/legal/__tests__/UrlHandlerService.test.ts +0 -71
- package/src/domains/legal/__tests__/setup.ts +0 -82
- package/src/presentation/components/__tests__/SettingsErrorBoundary.test.tsx +0 -186
- package/src/presentation/screens/__tests__/SettingsScreen.test.tsx +0 -322
- package/src/presentation/screens/hooks/__tests__/useFeatureDetection.test.tsx +0 -261
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple test for AboutScreen component
|
|
3
|
-
*/
|
|
4
|
-
import React from 'react';
|
|
5
|
-
import { AboutScreen } from '../AboutScreen';
|
|
6
|
-
import { AppInfo, AboutConfig } from '../../domain/entities/AppInfo';
|
|
7
|
-
|
|
8
|
-
describe('AboutScreen', () => {
|
|
9
|
-
const mockAppInfo: AppInfo = {
|
|
10
|
-
name: 'Test App',
|
|
11
|
-
version: '1.0.0',
|
|
12
|
-
description: 'Test Description',
|
|
13
|
-
developer: 'Test Developer',
|
|
14
|
-
contactEmail: 'test@example.com',
|
|
15
|
-
websiteUrl: 'https://example.com',
|
|
16
|
-
websiteDisplay: 'example.com',
|
|
17
|
-
moreAppsUrl: 'https://apps.example.com',
|
|
18
|
-
privacyPolicyUrl: 'https://example.com/privacy',
|
|
19
|
-
termsOfServiceUrl: 'https://example.com/terms',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const mockConfig: AboutConfig = {
|
|
23
|
-
appInfo: mockAppInfo,
|
|
24
|
-
actions: {
|
|
25
|
-
onEmailPress: jest.fn(),
|
|
26
|
-
onWebsitePress: jest.fn(),
|
|
27
|
-
onPrivacyPress: jest.fn(),
|
|
28
|
-
onTermsPress: jest.fn(),
|
|
29
|
-
onMoreAppsPress: jest.fn(),
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
it('should render without crashing', () => {
|
|
34
|
-
const element = React.createElement(AboutScreen, { config: mockConfig });
|
|
35
|
-
expect(element).toBeTruthy();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should render app info after loading', () => {
|
|
39
|
-
const element = React.createElement(AboutScreen, { config: mockConfig });
|
|
40
|
-
expect(element).toBeTruthy();
|
|
41
|
-
expect(mockConfig.appInfo.name).toBe('Test App');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should render error state when initialization fails', () => {
|
|
45
|
-
const invalidConfig = null as unknown;
|
|
46
|
-
|
|
47
|
-
const element = React.createElement(AboutScreen, { config: invalidConfig });
|
|
48
|
-
expect(element).toBeTruthy();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should render no app info message when app info is null', () => {
|
|
52
|
-
const emptyConfig: AboutConfig = {
|
|
53
|
-
appInfo: null as unknown,
|
|
54
|
-
actions: {},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const element = React.createElement(AboutScreen, { config: emptyConfig });
|
|
58
|
-
expect(element).toBeTruthy();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should not render header when showHeader is false', () => {
|
|
62
|
-
const element = React.createElement(AboutScreen, { config: mockConfig, showHeader: false });
|
|
63
|
-
expect(element).toBeTruthy();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should render custom header component when provided', () => {
|
|
67
|
-
const CustomHeader = () => React.createElement('div', { testID: 'custom-header' }, 'Custom Header');
|
|
68
|
-
|
|
69
|
-
const element = React.createElement(AboutScreen, {
|
|
70
|
-
config: mockConfig,
|
|
71
|
-
headerComponent: React.createElement(CustomHeader)
|
|
72
|
-
});
|
|
73
|
-
expect(element).toBeTruthy();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should render custom footer component when provided', () => {
|
|
77
|
-
const CustomFooter = () => React.createElement('div', { testID: 'custom-footer' }, 'Custom Footer');
|
|
78
|
-
|
|
79
|
-
const element = React.createElement(AboutScreen, {
|
|
80
|
-
config: mockConfig,
|
|
81
|
-
footerComponent: React.createElement(CustomFooter)
|
|
82
|
-
});
|
|
83
|
-
expect(element).toBeTruthy();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should apply custom container style', () => {
|
|
87
|
-
const customStyle = { backgroundColor: 'red' };
|
|
88
|
-
|
|
89
|
-
const element = React.createElement(AboutScreen, {
|
|
90
|
-
config: mockConfig,
|
|
91
|
-
containerStyle: customStyle,
|
|
92
|
-
testID: 'screen'
|
|
93
|
-
});
|
|
94
|
-
expect(element).toBeTruthy();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('should apply custom header style', () => {
|
|
98
|
-
const customStyle = { backgroundColor: 'blue' };
|
|
99
|
-
|
|
100
|
-
const element = React.createElement(AboutScreen, {
|
|
101
|
-
config: mockConfig,
|
|
102
|
-
headerStyle: customStyle
|
|
103
|
-
});
|
|
104
|
-
expect(element).toBeTruthy();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should apply custom title style', () => {
|
|
108
|
-
const customStyle = { color: 'green' } as React.CSSProperties;
|
|
109
|
-
|
|
110
|
-
const element = React.createElement(AboutScreen, {
|
|
111
|
-
config: mockConfig,
|
|
112
|
-
titleStyle: customStyle
|
|
113
|
-
});
|
|
114
|
-
expect(element).toBeTruthy();
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should apply custom version style', () => {
|
|
118
|
-
const customStyle = { color: 'purple' };
|
|
119
|
-
|
|
120
|
-
const element = React.createElement(AboutScreen, {
|
|
121
|
-
config: mockConfig,
|
|
122
|
-
versionStyle: customStyle
|
|
123
|
-
});
|
|
124
|
-
expect(element).toBeTruthy();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should handle empty config', () => {
|
|
128
|
-
const emptyConfig: AboutConfig = {
|
|
129
|
-
appInfo: {
|
|
130
|
-
name: '',
|
|
131
|
-
version: '',
|
|
132
|
-
description: '',
|
|
133
|
-
developer: '',
|
|
134
|
-
contactEmail: '',
|
|
135
|
-
websiteUrl: '',
|
|
136
|
-
websiteDisplay: '',
|
|
137
|
-
moreAppsUrl: '',
|
|
138
|
-
privacyPolicyUrl: '',
|
|
139
|
-
termsOfServiceUrl: '',
|
|
140
|
-
},
|
|
141
|
-
actions: {},
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const element = React.createElement(AboutScreen, { config: emptyConfig });
|
|
145
|
-
expect(element).toBeTruthy();
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('should handle config with only required fields', () => {
|
|
149
|
-
const minimalConfig: AboutConfig = {
|
|
150
|
-
appInfo: {
|
|
151
|
-
name: 'Minimal App',
|
|
152
|
-
version: '1.0.0',
|
|
153
|
-
description: '',
|
|
154
|
-
developer: '',
|
|
155
|
-
contactEmail: '',
|
|
156
|
-
websiteUrl: '',
|
|
157
|
-
websiteDisplay: '',
|
|
158
|
-
moreAppsUrl: '',
|
|
159
|
-
privacyPolicyUrl: '',
|
|
160
|
-
termsOfServiceUrl: '',
|
|
161
|
-
},
|
|
162
|
-
actions: {},
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
const element = React.createElement(AboutScreen, { config: minimalConfig });
|
|
166
|
-
expect(element).toBeTruthy();
|
|
167
|
-
expect(minimalConfig.appInfo.name).toBe('Minimal App');
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('should handle special characters in text', () => {
|
|
171
|
-
const configWithSpecialChars: AboutConfig = {
|
|
172
|
-
appInfo: {
|
|
173
|
-
...mockAppInfo,
|
|
174
|
-
name: 'App & Special <Chars>',
|
|
175
|
-
description: 'Description with "quotes" and \'apostrophes\'',
|
|
176
|
-
},
|
|
177
|
-
actions: {},
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const element = React.createElement(AboutScreen, { config: configWithSpecialChars });
|
|
181
|
-
expect(element).toBeTruthy();
|
|
182
|
-
expect(configWithSpecialChars.appInfo.name).toBe('App & Special <Chars>');
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
it('should handle very long text', () => {
|
|
186
|
-
const configWithLongText: AboutConfig = {
|
|
187
|
-
appInfo: {
|
|
188
|
-
...mockAppInfo,
|
|
189
|
-
name: 'A'.repeat(100),
|
|
190
|
-
description: 'B'.repeat(500),
|
|
191
|
-
},
|
|
192
|
-
actions: {},
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const element = React.createElement(AboutScreen, { config: configWithLongText });
|
|
196
|
-
expect(element).toBeTruthy();
|
|
197
|
-
expect(configWithLongText.appInfo.name.length).toBe(100);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for AboutScreen component
|
|
3
|
-
*/
|
|
4
|
-
import React from 'react';
|
|
5
|
-
import { View, Text, TextStyle } from 'react-native';
|
|
6
|
-
import { render, waitFor, fireEvent } from '@testing-library/react';
|
|
7
|
-
import { AboutScreen } from '../AboutScreen';
|
|
8
|
-
import { AboutConfig } from '../../../domain/entities/AppInfo';
|
|
9
|
-
|
|
10
|
-
// Mock console methods
|
|
11
|
-
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation();
|
|
12
|
-
const mockConsoleError = jest.spyOn(console, 'error').mockImplementation();
|
|
13
|
-
|
|
14
|
-
describe('AboutScreen', () => {
|
|
15
|
-
const mockConfig: AboutConfig = {
|
|
16
|
-
appInfo: {
|
|
17
|
-
name: 'Test App',
|
|
18
|
-
version: '1.0.0',
|
|
19
|
-
description: 'Test Description',
|
|
20
|
-
developer: 'Test Developer',
|
|
21
|
-
contactEmail: 'test@example.com',
|
|
22
|
-
websiteUrl: 'https://example.com',
|
|
23
|
-
websiteDisplay: 'example.com',
|
|
24
|
-
moreAppsUrl: 'https://apps.example.com',
|
|
25
|
-
},
|
|
26
|
-
actions: {
|
|
27
|
-
onEmailPress: jest.fn(),
|
|
28
|
-
onWebsitePress: jest.fn(),
|
|
29
|
-
onMoreAppsPress: jest.fn(),
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
jest.clearAllMocks();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
mockConsoleLog.mockClear();
|
|
39
|
-
mockConsoleError.mockClear();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('Rendering', () => {
|
|
43
|
-
it('should render loading state initially', () => {
|
|
44
|
-
const { getByText } = render(
|
|
45
|
-
<AboutScreen config={mockConfig} />
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
expect(getByText('Loading...')).toBeTruthy();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should render app info after loading', async () => {
|
|
52
|
-
const { getByText, queryByText } = render(
|
|
53
|
-
<AboutScreen config={mockConfig} />
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
// Wait for loading to complete
|
|
57
|
-
await waitFor(() => {
|
|
58
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Check for app info
|
|
62
|
-
expect(getByText('Test App')).toBeTruthy();
|
|
63
|
-
expect(getByText('Version 1.0.0')).toBeTruthy();
|
|
64
|
-
expect(getByText('Test Description')).toBeTruthy();
|
|
65
|
-
expect(getByText('Test Developer')).toBeTruthy();
|
|
66
|
-
expect(getByText('test@example.com')).toBeTruthy();
|
|
67
|
-
expect(getByText('example.com')).toBeTruthy();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should render error state when initialization fails', async () => {
|
|
71
|
-
const invalidConfig = null as unknown;
|
|
72
|
-
|
|
73
|
-
const { getByText, queryByText } = render(
|
|
74
|
-
<AboutScreen config={invalidConfig} />
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
await waitFor(() => {
|
|
78
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
expect(getByText('No app information available')).toBeTruthy();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should render no app info message when app info is null', async () => {
|
|
85
|
-
const emptyConfig: AboutConfig = {
|
|
86
|
-
appInfo: {},
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const { getByText, queryByText } = render(
|
|
90
|
-
<AboutScreen config={emptyConfig} />
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
await waitFor(() => {
|
|
94
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// With empty appInfo, it should show empty name and default version
|
|
98
|
-
expect(getByText('Version 1.0.0')).toBeTruthy();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should not render header when showHeader is false', async () => {
|
|
102
|
-
const { queryByText } = render(
|
|
103
|
-
<AboutScreen config={mockConfig} showHeader={false} />
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
await waitFor(() => {
|
|
107
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
expect(queryByText('Test App')).toBeFalsy();
|
|
111
|
-
expect(queryByText('Version 1.0.0')).toBeFalsy();
|
|
112
|
-
expect(queryByText('Test Description')).toBeFalsy();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should render custom header component when provided', async () => {
|
|
116
|
-
const CustomHeader = () => <View testID="custom-header"><Text>Custom Header</Text></View>;
|
|
117
|
-
|
|
118
|
-
const { getByTestId, queryByText } = render(
|
|
119
|
-
<AboutScreen config={mockConfig} headerComponent={<CustomHeader />} />
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
await waitFor(() => {
|
|
123
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
expect(getByTestId('custom-header')).toBeTruthy();
|
|
127
|
-
expect(queryByText('Test App')).toBeFalsy(); // Default header should not render
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('should render custom footer component when provided', async () => {
|
|
131
|
-
const CustomFooter = () => <View testID="custom-footer"><Text>Custom Footer</Text></View>;
|
|
132
|
-
|
|
133
|
-
const { getByTestId } = render(
|
|
134
|
-
<AboutScreen config={mockConfig} footerComponent={<CustomFooter />} />
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
await waitFor(() => {
|
|
138
|
-
expect(getByTestId('custom-footer')).toBeTruthy();
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
describe('Custom Styles', () => {
|
|
144
|
-
it('should apply custom container style', async () => {
|
|
145
|
-
const customStyle = { backgroundColor: 'red' };
|
|
146
|
-
|
|
147
|
-
const { queryByText, container } = render(
|
|
148
|
-
<AboutScreen config={mockConfig} containerStyle={customStyle} testID="screen" />
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
await waitFor(() => {
|
|
152
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Test that custom container style is applied (component renders without error)
|
|
156
|
-
expect(container).toBeTruthy();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('should apply custom header style', async () => {
|
|
160
|
-
const customStyle = { backgroundColor: 'blue' };
|
|
161
|
-
|
|
162
|
-
const { getByText, queryByText } = render(
|
|
163
|
-
<AboutScreen config={mockConfig} headerStyle={customStyle} />
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
await waitFor(() => {
|
|
167
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const header = getByText('Test App');
|
|
171
|
-
// Check that header renders with custom style (component renders without error)
|
|
172
|
-
expect(header).toBeTruthy();
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('should apply custom title style', async () => {
|
|
176
|
-
const customStyle: TextStyle = { color: 'green' };
|
|
177
|
-
|
|
178
|
-
const { getByText, queryByText } = render(
|
|
179
|
-
<AboutScreen config={mockConfig} titleStyle={customStyle} />
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
await waitFor(() => {
|
|
183
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
const title = getByText('Test App');
|
|
187
|
-
// Check that title renders with custom style (component renders without error)
|
|
188
|
-
expect(title).toBeTruthy();
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it('should apply custom version style', async () => {
|
|
192
|
-
const customStyle = { color: 'purple' };
|
|
193
|
-
|
|
194
|
-
const { getByText, queryByText } = render(
|
|
195
|
-
<AboutScreen config={mockConfig} versionStyle={customStyle} />
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
await waitFor(() => {
|
|
199
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
const version = getByText('Version 1.0.0');
|
|
203
|
-
// Check that version renders with custom style (component renders without error)
|
|
204
|
-
expect(version).toBeTruthy();
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
describe('Interactions', () => {
|
|
209
|
-
it('should call action handlers when items are pressed', async () => {
|
|
210
|
-
const { getByTestId } = render(
|
|
211
|
-
<AboutScreen config={mockConfig} />
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
await waitFor(() => {
|
|
215
|
-
expect(getByTestId('email-item')).toBeTruthy();
|
|
216
|
-
expect(getByTestId('website-item')).toBeTruthy();
|
|
217
|
-
expect(getByTestId('more-apps-item')).toBeTruthy();
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
// Test interactions
|
|
221
|
-
fireEvent.click(getByTestId('email-item'));
|
|
222
|
-
fireEvent.click(getByTestId('website-item'));
|
|
223
|
-
fireEvent.click(getByTestId('more-apps-item'));
|
|
224
|
-
|
|
225
|
-
expect(mockConfig.actions!.onEmailPress).toHaveBeenCalledTimes(1);
|
|
226
|
-
expect(mockConfig.actions!.onWebsitePress).toHaveBeenCalledTimes(1);
|
|
227
|
-
expect(mockConfig.actions!.onMoreAppsPress).toHaveBeenCalledTimes(1);
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
describe('Performance', () => {
|
|
232
|
-
it('should memoize render functions', async () => {
|
|
233
|
-
const { rerender } = render(
|
|
234
|
-
<AboutScreen config={mockConfig} />
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
// Wait for initial render
|
|
238
|
-
await waitFor(() => {
|
|
239
|
-
expect(() => { }).not.toThrow();
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Re-render with same props
|
|
243
|
-
rerender(
|
|
244
|
-
<AboutScreen config={mockConfig} />
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
// Should not throw and should render correctly
|
|
248
|
-
await waitFor(() => {
|
|
249
|
-
expect(() => {
|
|
250
|
-
rerender(
|
|
251
|
-
<AboutScreen config={mockConfig} />
|
|
252
|
-
);
|
|
253
|
-
}).not.toThrow();
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('should handle rapid prop changes', async () => {
|
|
258
|
-
const { rerender } = render(
|
|
259
|
-
<AboutScreen config={mockConfig} />
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
// Rapid prop changes
|
|
263
|
-
for (let i = 0; i < 5; i++) {
|
|
264
|
-
const newConfig = {
|
|
265
|
-
...mockConfig,
|
|
266
|
-
appInfo: { ...mockConfig.appInfo, name: `App ${i}` }
|
|
267
|
-
};
|
|
268
|
-
rerender(<AboutScreen config={newConfig} />);
|
|
269
|
-
|
|
270
|
-
await waitFor(() => {
|
|
271
|
-
expect(() => { }).not.toThrow();
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
expect(() => {
|
|
276
|
-
rerender(
|
|
277
|
-
<AboutScreen config={{ ...mockConfig, appInfo: { ...mockConfig.appInfo, name: 'Final App' } }} />
|
|
278
|
-
);
|
|
279
|
-
}).not.toThrow();
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
describe('Edge Cases', () => {
|
|
284
|
-
it('should handle empty config', async () => {
|
|
285
|
-
const emptyConfig: AboutConfig = {
|
|
286
|
-
appInfo: {},
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
const { getByText, queryByText } = render(
|
|
290
|
-
<AboutScreen config={emptyConfig} />
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
await waitFor(() => {
|
|
294
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
// With empty appInfo, it should show empty name and default version
|
|
298
|
-
expect(getByText('Version 1.0.0')).toBeTruthy();
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should handle config with only required fields', async () => {
|
|
302
|
-
const minimalConfig: AboutConfig = {
|
|
303
|
-
appInfo: {
|
|
304
|
-
name: 'Minimal App',
|
|
305
|
-
version: '1.0.0',
|
|
306
|
-
},
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
const { getByText, queryByText } = render(
|
|
310
|
-
<AboutScreen config={minimalConfig} />
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
await waitFor(() => {
|
|
314
|
-
expect(queryByText('Loading...')).toBeFalsy();
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
expect(getByText('Minimal App')).toBeTruthy();
|
|
318
|
-
expect(getByText('Version 1.0.0')).toBeTruthy();
|
|
319
|
-
expect(queryByText('Test Developer')).toBeFalsy();
|
|
320
|
-
expect(queryByText('test@example.com')).toBeFalsy();
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it('should handle special characters in text', async () => {
|
|
324
|
-
const configWithSpecialChars: AboutConfig = {
|
|
325
|
-
appInfo: {
|
|
326
|
-
name: 'Test & App <script>',
|
|
327
|
-
version: '1.0.0',
|
|
328
|
-
description: 'Description with émojis 🎉 and ñ',
|
|
329
|
-
developer: 'Developer & Co.',
|
|
330
|
-
},
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
const { getByText } = render(
|
|
334
|
-
<AboutScreen config={configWithSpecialChars} />
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
await waitFor(() => {
|
|
338
|
-
expect(getByText('Test & App <script>')).toBeTruthy();
|
|
339
|
-
expect(getByText('Description with émojis 🎉 and ñ')).toBeTruthy();
|
|
340
|
-
expect(getByText('Developer & Co.')).toBeTruthy();
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it('should handle very long text', async () => {
|
|
345
|
-
const longName = 'A'.repeat(100);
|
|
346
|
-
const longDescription = 'B'.repeat(200);
|
|
347
|
-
|
|
348
|
-
const configWithLongText: AboutConfig = {
|
|
349
|
-
appInfo: {
|
|
350
|
-
name: longName,
|
|
351
|
-
version: '1.0.0',
|
|
352
|
-
description: longDescription,
|
|
353
|
-
},
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
const { getByText } = render(
|
|
357
|
-
<AboutScreen config={configWithLongText} />
|
|
358
|
-
);
|
|
359
|
-
|
|
360
|
-
await waitFor(() => {
|
|
361
|
-
expect(getByText(longName)).toBeTruthy();
|
|
362
|
-
expect(getByText(longDescription)).toBeTruthy();
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
});
|
|
366
|
-
});
|