@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,299 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Appearance Service Tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { AppearanceService, appearanceService } from '../../infrastructure/services/appearanceService';
|
|
6
|
-
import type { ThemeMode, CustomThemeColors } from '../../types';
|
|
7
|
-
|
|
8
|
-
// Mock dependencies
|
|
9
|
-
jest.mock('../../infrastructure/stores/appearanceStore');
|
|
10
|
-
jest.mock('../../infrastructure/storage/appearanceStorage');
|
|
11
|
-
jest.mock('@umituz/react-native-design-system', () => ({
|
|
12
|
-
useTheme: {
|
|
13
|
-
getState: jest.fn(() => ({
|
|
14
|
-
setThemeMode: jest.fn(),
|
|
15
|
-
})),
|
|
16
|
-
},
|
|
17
|
-
useDesignSystemTheme: {
|
|
18
|
-
getState: jest.fn(() => ({
|
|
19
|
-
setThemeMode: jest.fn(),
|
|
20
|
-
setCustomColors: jest.fn(),
|
|
21
|
-
})),
|
|
22
|
-
},
|
|
23
|
-
}));
|
|
24
|
-
|
|
25
|
-
const mockAppearanceStore = require('../../infrastructure/stores/appearanceStore').useAppearanceStore;
|
|
26
|
-
const mockAppearanceStorage = require('../../infrastructure/storage/appearanceStorage').AppearanceStorage;
|
|
27
|
-
const mockUseTheme = require('@umituz/react-native-design-system').useTheme;
|
|
28
|
-
const mockUseDesignSystemTheme = require('@umituz/react-native-design-system').useDesignSystemTheme;
|
|
29
|
-
|
|
30
|
-
describe('AppearanceService', () => {
|
|
31
|
-
let service: AppearanceService;
|
|
32
|
-
let mockGetState: jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
33
|
-
let mockSetSettings: jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
34
|
-
let mockSetInitialized: jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
35
|
-
let mockUpdateThemeMode: jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
36
|
-
let mockUpdateCustomColors: jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
37
|
-
let mockResetState: jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
38
|
-
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
jest.clearAllMocks();
|
|
41
|
-
|
|
42
|
-
service = appearanceService;
|
|
43
|
-
|
|
44
|
-
mockGetState = mockAppearanceStore.getState as jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
45
|
-
mockSetSettings = mockAppearanceStore.getState as jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
46
|
-
mockSetInitialized = mockAppearanceStore.getState as jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
47
|
-
mockUpdateThemeMode = mockAppearanceStore.getState as jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
48
|
-
mockUpdateCustomColors = mockAppearanceStore.getState as jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
49
|
-
mockResetState = mockAppearanceStore.getState as jest.MockedFunction<typeof mockAppearanceStore.getState>;
|
|
50
|
-
|
|
51
|
-
// Setup mock implementations
|
|
52
|
-
mockGetState.mockReturnValue({
|
|
53
|
-
settings: { themeMode: 'dark' as ThemeMode },
|
|
54
|
-
isInitialized: false,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
mockSetSettings.mockReturnValue({} as any);
|
|
58
|
-
mockSetInitialized.mockReturnValue({} as any);
|
|
59
|
-
mockUpdateThemeMode.mockReturnValue({} as any);
|
|
60
|
-
mockUpdateCustomColors.mockReturnValue({} as any);
|
|
61
|
-
mockResetState.mockReturnValue({} as any);
|
|
62
|
-
|
|
63
|
-
mockAppearanceStorage.getSettings.mockResolvedValue(null);
|
|
64
|
-
mockAppearanceStorage.setSettings.mockResolvedValue();
|
|
65
|
-
mockAppearanceStorage.clear.mockResolvedValue();
|
|
66
|
-
|
|
67
|
-
mockUseTheme.getState.mockReturnValue({
|
|
68
|
-
setThemeMode: jest.fn(),
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
mockUseDesignSystemTheme.getState.mockReturnValue({
|
|
72
|
-
setThemeMode: jest.fn(),
|
|
73
|
-
setCustomColors: jest.fn(),
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
afterEach(() => {
|
|
78
|
-
jest.restoreAllMocks();
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
describe('initialize', () => {
|
|
82
|
-
it('should initialize with saved settings', async () => {
|
|
83
|
-
const savedSettings = { themeMode: 'light' as ThemeMode };
|
|
84
|
-
mockAppearanceStorage.getSettings.mockResolvedValue(savedSettings);
|
|
85
|
-
|
|
86
|
-
await service.initialize();
|
|
87
|
-
|
|
88
|
-
expect(mockAppearanceStorage.getSettings).toHaveBeenCalled();
|
|
89
|
-
expect(mockSetSettings).toHaveBeenCalledWith(savedSettings);
|
|
90
|
-
expect(mockSetInitialized).toHaveBeenCalledWith(true);
|
|
91
|
-
expect(mockUseTheme.getState().setThemeMode).toHaveBeenCalledWith('light');
|
|
92
|
-
expect(mockUseDesignSystemTheme.getState().setThemeMode).toHaveBeenCalledWith('light');
|
|
93
|
-
expect(mockUseDesignSystemTheme.getState().setCustomColors).toHaveBeenCalledWith(undefined);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should initialize with default settings when no saved settings', async () => {
|
|
97
|
-
mockAppearanceStorage.getSettings.mockResolvedValue(null);
|
|
98
|
-
|
|
99
|
-
await service.initialize();
|
|
100
|
-
|
|
101
|
-
expect(mockSetSettings).toHaveBeenCalledWith({ themeMode: 'dark' });
|
|
102
|
-
expect(mockSetInitialized).toHaveBeenCalledWith(true);
|
|
103
|
-
expect(mockUseTheme.getState().setThemeMode).toHaveBeenCalledWith('dark');
|
|
104
|
-
expect(mockUseDesignSystemTheme.getState().setThemeMode).toHaveBeenCalledWith('dark');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should handle initialization errors gracefully', async () => {
|
|
108
|
-
const error = new Error('Init failed');
|
|
109
|
-
mockAppearanceStorage.getSettings.mockRejectedValue(error);
|
|
110
|
-
|
|
111
|
-
await service.initialize();
|
|
112
|
-
|
|
113
|
-
expect(mockSetSettings).toHaveBeenCalledWith({ themeMode: 'dark' });
|
|
114
|
-
expect(mockSetInitialized).toHaveBeenCalledWith(true);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should prevent multiple initializations', async () => {
|
|
118
|
-
const savedSettings = { themeMode: 'light' as ThemeMode };
|
|
119
|
-
mockAppearanceStorage.getSettings.mockResolvedValue(savedSettings);
|
|
120
|
-
|
|
121
|
-
const promise1 = service.initialize();
|
|
122
|
-
const promise2 = service.initialize();
|
|
123
|
-
|
|
124
|
-
await Promise.all([promise1, promise2]);
|
|
125
|
-
|
|
126
|
-
expect(mockAppearanceStorage.getSettings).toHaveBeenCalledTimes(1);
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
describe('getThemeMode', () => {
|
|
131
|
-
it('should return current theme mode', () => {
|
|
132
|
-
mockGetState.mockReturnValue({
|
|
133
|
-
settings: { themeMode: 'light' as ThemeMode },
|
|
134
|
-
isInitialized: true,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const result = service.getThemeMode();
|
|
138
|
-
|
|
139
|
-
expect(result).toBe('light');
|
|
140
|
-
expect(mockGetState).toHaveBeenCalled();
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
describe('setThemeMode', () => {
|
|
145
|
-
it('should set theme mode and sync with design system', async () => {
|
|
146
|
-
const newMode: ThemeMode = 'light';
|
|
147
|
-
mockGetState.mockReturnValue({
|
|
148
|
-
settings: { themeMode: 'dark' as ThemeMode },
|
|
149
|
-
isInitialized: true,
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
await service.setThemeMode(newMode);
|
|
153
|
-
|
|
154
|
-
expect(mockUpdateThemeMode).toHaveBeenCalledWith(newMode);
|
|
155
|
-
expect(mockAppearanceStorage.setSettings).toHaveBeenCalledWith({
|
|
156
|
-
themeMode: newMode,
|
|
157
|
-
});
|
|
158
|
-
expect(mockUseTheme.getState().setThemeMode).toHaveBeenCalledWith(newMode);
|
|
159
|
-
expect(mockUseDesignSystemTheme.getState().setThemeMode).toHaveBeenCalledWith(newMode);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('should handle setThemeMode errors', async () => {
|
|
163
|
-
const error = new Error('Set theme failed');
|
|
164
|
-
mockAppearanceStorage.setSettings.mockRejectedValue(error);
|
|
165
|
-
|
|
166
|
-
await expect(service.setThemeMode('light')).rejects.toThrow(error);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('toggleTheme', () => {
|
|
171
|
-
it('should toggle between light and dark', async () => {
|
|
172
|
-
mockGetState.mockReturnValue({
|
|
173
|
-
settings: { themeMode: 'light' as ThemeMode },
|
|
174
|
-
isInitialized: true,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
await service.toggleTheme();
|
|
178
|
-
|
|
179
|
-
expect(mockUpdateThemeMode).toHaveBeenCalledWith('dark');
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('should toggle from dark to light', async () => {
|
|
183
|
-
mockGetState.mockReturnValue({
|
|
184
|
-
settings: { themeMode: 'dark' as ThemeMode },
|
|
185
|
-
isInitialized: true,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
await service.toggleTheme();
|
|
189
|
-
|
|
190
|
-
expect(mockUpdateThemeMode).toHaveBeenCalledWith('light');
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
describe('getCustomColors', () => {
|
|
195
|
-
it('should return current custom colors', () => {
|
|
196
|
-
const customColors: CustomThemeColors = { primary: '#FF0000' };
|
|
197
|
-
mockGetState.mockReturnValue({
|
|
198
|
-
settings: { themeMode: 'dark', customColors },
|
|
199
|
-
isInitialized: true,
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
const result = service.getCustomColors();
|
|
203
|
-
|
|
204
|
-
expect(result).toEqual(customColors);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('should return undefined when no custom colors', () => {
|
|
208
|
-
mockGetState.mockReturnValue({
|
|
209
|
-
settings: { themeMode: 'dark' },
|
|
210
|
-
isInitialized: true,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
const result = service.getCustomColors();
|
|
214
|
-
|
|
215
|
-
expect(result).toBeUndefined();
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe('setCustomColors', () => {
|
|
220
|
-
it('should set custom colors and sync with design system', async () => {
|
|
221
|
-
const newColors: CustomThemeColors = { primary: '#FF0000' };
|
|
222
|
-
const currentColors = { secondary: '#00FF00' };
|
|
223
|
-
mockGetState.mockReturnValue({
|
|
224
|
-
settings: { themeMode: 'dark', customColors: currentColors },
|
|
225
|
-
isInitialized: true,
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
await service.setCustomColors(newColors);
|
|
229
|
-
|
|
230
|
-
expect(mockUpdateCustomColors).toHaveBeenCalledWith({
|
|
231
|
-
...currentColors,
|
|
232
|
-
...newColors,
|
|
233
|
-
});
|
|
234
|
-
expect(mockAppearanceStorage.setSettings).toHaveBeenCalledWith({
|
|
235
|
-
themeMode: 'dark',
|
|
236
|
-
customColors: { ...currentColors, ...newColors },
|
|
237
|
-
});
|
|
238
|
-
expect(mockUseDesignSystemTheme.getState().setCustomColors).toHaveBeenCalledWith({
|
|
239
|
-
...currentColors,
|
|
240
|
-
...newColors,
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it('should handle setCustomColors errors', async () => {
|
|
245
|
-
const error = new Error('Set colors failed');
|
|
246
|
-
mockAppearanceStorage.setSettings.mockRejectedValue(error);
|
|
247
|
-
|
|
248
|
-
await expect(service.setCustomColors({ primary: '#FF0000' })).rejects.toThrow(error);
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
describe('resetCustomColors', () => {
|
|
253
|
-
it('should reset custom colors', async () => {
|
|
254
|
-
mockGetState.mockReturnValue({
|
|
255
|
-
settings: { themeMode: 'dark', customColors: { primary: '#FF0000' } },
|
|
256
|
-
isInitialized: true,
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
await service.resetCustomColors();
|
|
260
|
-
|
|
261
|
-
expect(mockUpdateCustomColors).toHaveBeenCalledWith(undefined);
|
|
262
|
-
expect(mockAppearanceStorage.setSettings).toHaveBeenCalledWith({
|
|
263
|
-
themeMode: 'dark',
|
|
264
|
-
customColors: undefined,
|
|
265
|
-
});
|
|
266
|
-
expect(mockUseDesignSystemTheme.getState().setCustomColors).toHaveBeenCalledWith(undefined);
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
describe('reset', () => {
|
|
271
|
-
it('should reset all settings', async () => {
|
|
272
|
-
mockGetState.mockReturnValue({
|
|
273
|
-
settings: { themeMode: 'light', customColors: { primary: '#FF0000' } },
|
|
274
|
-
isInitialized: true,
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
await service.reset();
|
|
278
|
-
|
|
279
|
-
expect(mockAppearanceStorage.clear).toHaveBeenCalled();
|
|
280
|
-
expect(mockResetState).toHaveBeenCalled();
|
|
281
|
-
expect(mockUseTheme.getState().setThemeMode).toHaveBeenCalledWith('dark');
|
|
282
|
-
expect(mockUseDesignSystemTheme.getState().setThemeMode).toHaveBeenCalledWith('dark');
|
|
283
|
-
expect(mockUseDesignSystemTheme.getState().setCustomColors).toHaveBeenCalledWith(undefined);
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
describe('isInitialized', () => {
|
|
288
|
-
it('should return initialization status', () => {
|
|
289
|
-
mockGetState.mockReturnValue({
|
|
290
|
-
settings: { themeMode: 'dark' },
|
|
291
|
-
isInitialized: true,
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
const result = service.isInitialized();
|
|
295
|
-
|
|
296
|
-
expect(result).toBe(true);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
});
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Jest Setup File
|
|
3
|
-
*
|
|
4
|
-
* Global test setup for React Native Appearance package
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import 'react-native-gesture-handler/jestSetup';
|
|
8
|
-
|
|
9
|
-
// Mock console methods for testing
|
|
10
|
-
if (__DEV__) {
|
|
11
|
-
global.console = {
|
|
12
|
-
...console,
|
|
13
|
-
// Suppress specific console warnings in tests
|
|
14
|
-
warn: jest.fn(),
|
|
15
|
-
error: jest.fn(),
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Mock performance API for testing
|
|
20
|
-
if (typeof performance === 'undefined') {
|
|
21
|
-
global.performance = {
|
|
22
|
-
now: jest.fn(() => Date.now()),
|
|
23
|
-
mark: jest.fn(),
|
|
24
|
-
measure: jest.fn(),
|
|
25
|
-
getEntriesByName: jest.fn(() => []),
|
|
26
|
-
getEntriesByType: jest.fn(() => []),
|
|
27
|
-
clearMarks: jest.fn(),
|
|
28
|
-
clearMeasures: jest.fn(),
|
|
29
|
-
clearResourceTimings: jest.fn(),
|
|
30
|
-
} as any;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Mock React Native modules
|
|
34
|
-
jest.mock('react-native', () => {
|
|
35
|
-
const RN = jest.requireActual('react-native');
|
|
36
|
-
return {
|
|
37
|
-
...RN,
|
|
38
|
-
Platform: {
|
|
39
|
-
OS: 'ios',
|
|
40
|
-
select: jest.fn((obj) => obj.ios),
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Mock design system theme
|
|
46
|
-
jest.mock('@umituz/react-native-design-system', () => ({
|
|
47
|
-
useTheme: jest.fn(() => ({
|
|
48
|
-
setThemeMode: jest.fn(),
|
|
49
|
-
})),
|
|
50
|
-
useDesignSystemTheme: jest.fn(() => ({
|
|
51
|
-
setThemeMode: jest.fn(),
|
|
52
|
-
setCustomColors: jest.fn(),
|
|
53
|
-
})),
|
|
54
|
-
}));
|
|
55
|
-
|
|
56
|
-
// Mock storage
|
|
57
|
-
jest.mock('@umituz/react-native-storage', () => ({
|
|
58
|
-
storageRepository: {
|
|
59
|
-
getItem: jest.fn(() => ({
|
|
60
|
-
success: true,
|
|
61
|
-
data: null,
|
|
62
|
-
})),
|
|
63
|
-
setItem: jest.fn(() => ({
|
|
64
|
-
success: true,
|
|
65
|
-
})),
|
|
66
|
-
removeItem: jest.fn(() => ({
|
|
67
|
-
success: true,
|
|
68
|
-
})),
|
|
69
|
-
},
|
|
70
|
-
unwrap: jest.fn((result, defaultValue) =>
|
|
71
|
-
result.success ? result.data : defaultValue
|
|
72
|
-
),
|
|
73
|
-
}));
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Mock localization
|
|
78
|
-
jest.mock('@umituz/react-native-localization', () => ({
|
|
79
|
-
useLocalization: jest.fn(() => ({
|
|
80
|
-
t: jest.fn((key) => key),
|
|
81
|
-
})),
|
|
82
|
-
}));
|
|
83
|
-
|
|
84
|
-
// Global test utilities
|
|
85
|
-
(globalThis as any).__TEST__ = true;
|
|
86
|
-
|
|
87
|
-
// Mock timers
|
|
88
|
-
jest.useFakeTimers();
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Appearance Store Tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { renderHook, act } from '@testing-library/react-native';
|
|
6
|
-
import { useAppearanceStore } from '../../infrastructure/stores/appearanceStore';
|
|
7
|
-
import type { AppearanceSettings, ThemeMode, CustomThemeColors } from '../../types';
|
|
8
|
-
|
|
9
|
-
// Mock design system theme
|
|
10
|
-
jest.mock('@umituz/react-native-design-system', () => ({
|
|
11
|
-
useTheme: {
|
|
12
|
-
getState: jest.fn(() => ({
|
|
13
|
-
setThemeMode: jest.fn(),
|
|
14
|
-
})),
|
|
15
|
-
},
|
|
16
|
-
useDesignSystemTheme: {
|
|
17
|
-
getState: jest.fn(() => ({
|
|
18
|
-
setThemeMode: jest.fn(),
|
|
19
|
-
setCustomColors: jest.fn(),
|
|
20
|
-
})),
|
|
21
|
-
},
|
|
22
|
-
}));
|
|
23
|
-
|
|
24
|
-
const mockUseTheme = require('@umituz/react-native-design-system').useTheme;
|
|
25
|
-
const mockUseDesignSystemTheme = require('@umituz/react-native-design-system').useDesignSystemTheme;
|
|
26
|
-
|
|
27
|
-
describe('useAppearanceStore', () => {
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
jest.clearAllMocks();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
jest.restoreAllMocks();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should initialize with default settings', () => {
|
|
37
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
38
|
-
|
|
39
|
-
expect(result.current).toEqual({
|
|
40
|
-
settings: {
|
|
41
|
-
themeMode: 'dark',
|
|
42
|
-
},
|
|
43
|
-
isInitialized: false,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
expect(typeof result.current.setSettings).toBe('function');
|
|
47
|
-
expect(typeof result.current.setInitialized).toBe('function');
|
|
48
|
-
expect(typeof result.current.updateThemeMode).toBe('function');
|
|
49
|
-
expect(typeof result.current.updateCustomColors).toBe('function');
|
|
50
|
-
expect(typeof result.current.resetState).toBe('function');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should update settings correctly', () => {
|
|
54
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
55
|
-
|
|
56
|
-
const newSettings: AppearanceSettings = {
|
|
57
|
-
themeMode: 'light',
|
|
58
|
-
customColors: { primary: '#FF0000' },
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
act(() => {
|
|
62
|
-
result.current.setSettings(newSettings);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
expect(result.current.settings).toEqual(newSettings);
|
|
66
|
-
expect(mockUseTheme.getState().setThemeMode).not.toHaveBeenCalled();
|
|
67
|
-
expect(mockUseDesignSystemTheme.getState().setThemeMode).not.toHaveBeenCalled();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should update theme mode correctly', () => {
|
|
71
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
72
|
-
|
|
73
|
-
act(() => {
|
|
74
|
-
result.current.updateThemeMode('light');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(result.current.settings.themeMode).toBe('light');
|
|
78
|
-
expect(mockUseTheme.getState().setThemeMode).not.toHaveBeenCalled();
|
|
79
|
-
expect(mockUseDesignSystemTheme.getState().setThemeMode).not.toHaveBeenCalled();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should not update theme mode if same value', () => {
|
|
83
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
84
|
-
|
|
85
|
-
act(() => {
|
|
86
|
-
result.current.updateThemeMode('dark'); // Default is dark
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
expect(result.current.settings.themeMode).toBe('dark');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should update custom colors correctly', () => {
|
|
93
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
94
|
-
|
|
95
|
-
const newColors: CustomThemeColors = { primary: '#FF0000' };
|
|
96
|
-
|
|
97
|
-
act(() => {
|
|
98
|
-
result.current.updateCustomColors(newColors);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
expect(result.current.settings.customColors).toEqual(newColors);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should not update custom colors if same value', () => {
|
|
105
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
106
|
-
|
|
107
|
-
const newColors: CustomThemeColors = { primary: '#FF0000' };
|
|
108
|
-
|
|
109
|
-
act(() => {
|
|
110
|
-
result.current.updateCustomColors(newColors);
|
|
111
|
-
result.current.updateCustomColors(newColors); // Second call with same value
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Should only be called once due to optimization
|
|
115
|
-
expect(mockUseDesignSystemTheme.getState().setCustomColors).toHaveBeenCalledTimes(1);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should reset state correctly', () => {
|
|
119
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
120
|
-
|
|
121
|
-
const customColors: CustomThemeColors = { primary: '#FF0000' };
|
|
122
|
-
|
|
123
|
-
act(() => {
|
|
124
|
-
result.current.updateCustomColors(customColors);
|
|
125
|
-
result.current.setInitialized(true);
|
|
126
|
-
result.current.resetState();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
expect(result.current.settings).toEqual({
|
|
130
|
-
themeMode: 'dark',
|
|
131
|
-
});
|
|
132
|
-
expect(result.current.isInitialized).toBe(false);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('should not reset if already at default', () => {
|
|
136
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
137
|
-
|
|
138
|
-
act(() => {
|
|
139
|
-
result.current.resetState();
|
|
140
|
-
result.current.resetState(); // Second call
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// Should only be called once due to optimization
|
|
144
|
-
expect(mockUseTheme.getState().setThemeMode).toHaveBeenCalledTimes(1);
|
|
145
|
-
expect(mockUseDesignSystemTheme.getState().setThemeMode).toHaveBeenCalledTimes(1);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('should handle setInitialized correctly', () => {
|
|
149
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
150
|
-
|
|
151
|
-
act(() => {
|
|
152
|
-
result.current.setInitialized(true);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
expect(result.current.isInitialized).toBe(true);
|
|
156
|
-
|
|
157
|
-
act(() => {
|
|
158
|
-
result.current.setInitialized(true); // Second call with same value
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Should not be called again due to optimization
|
|
162
|
-
expect(result.current.isInitialized).toBe(true);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('should handle setInitialized changes correctly', () => {
|
|
166
|
-
const { result } = renderHook(() => useAppearanceStore());
|
|
167
|
-
|
|
168
|
-
act(() => {
|
|
169
|
-
result.current.setInitialized(false);
|
|
170
|
-
result.current.setInitialized(true);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
expect(result.current.isInitialized).toBe(true);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for CloudSyncSetting Component
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import { render, fireEvent } from '@testing-library/react-native';
|
|
7
|
-
import { CloudSyncSetting } from '../CloudSyncSetting';
|
|
8
|
-
|
|
9
|
-
// Mock lucide-react-native
|
|
10
|
-
jest.mock('lucide-react-native', () => ({
|
|
11
|
-
Cloud: 'Cloud',
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
// Mock SettingsItemCard component
|
|
15
|
-
jest.mock('../../../../../presentation/components/SettingsItemCard', () => {
|
|
16
|
-
const React = require('react');
|
|
17
|
-
const { View, Text } = require('react-native');
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
SettingsItemCard: ({ icon, title, description, onPress, testID, showSwitch, switchValue, onSwitchChange, disabled }: any) => (
|
|
21
|
-
React.createElement(View, {
|
|
22
|
-
testID: testID || 'setting-item',
|
|
23
|
-
onTouchEnd: onPress,
|
|
24
|
-
style: { padding: 16 }
|
|
25
|
-
}, [
|
|
26
|
-
React.createElement(Text, { key: 'title' }, title || ''),
|
|
27
|
-
description && React.createElement(Text, { key: 'description' }, description),
|
|
28
|
-
showSwitch && React.createElement(Text, { key: 'switch' }, switchValue ? 'ON' : 'OFF'),
|
|
29
|
-
])
|
|
30
|
-
),
|
|
31
|
-
};
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('CloudSyncSetting', () => {
|
|
35
|
-
it('renders with default props', () => {
|
|
36
|
-
const { getByText } = render(<CloudSyncSetting />);
|
|
37
|
-
|
|
38
|
-
expect(getByText('cloud_sync')).toBeTruthy();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('renders with custom title', () => {
|
|
42
|
-
const { getByText } = render(<CloudSyncSetting title="Custom Sync" />);
|
|
43
|
-
|
|
44
|
-
expect(getByText('Custom Sync')).toBeTruthy();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('shows syncing state when isSyncing is true', () => {
|
|
48
|
-
const { getByText } = render(<CloudSyncSetting isSyncing={true} />);
|
|
49
|
-
|
|
50
|
-
expect(getByText('syncing')).toBeTruthy();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('displays custom description when provided', () => {
|
|
54
|
-
const { getByText } = render(
|
|
55
|
-
<CloudSyncSetting description="Custom description" />
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
expect(getByText('Custom description')).toBeTruthy();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('shows last synced time when provided', () => {
|
|
62
|
-
const lastSynced = new Date(Date.now() - 5 * 60 * 1000); // 5 minutes ago
|
|
63
|
-
const { getByText } = render(<CloudSyncSetting lastSynced={lastSynced} />);
|
|
64
|
-
|
|
65
|
-
expect(getByText('last_synced_5m_ago')).toBeTruthy();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('handles onPress callback', () => {
|
|
69
|
-
const mockOnPress = jest.fn();
|
|
70
|
-
const { getByTestId } = render(
|
|
71
|
-
<CloudSyncSetting onPress={mockOnPress} />
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
const pressable = getByTestId('setting-item');
|
|
75
|
-
fireEvent.press(pressable);
|
|
76
|
-
expect(mockOnPress).toHaveBeenCalled();
|
|
77
|
-
});
|
|
78
|
-
});
|