Skip to content

Commit 1e102e0

Browse files
committed
CU-868ffcgaz PR#169 fixes
1 parent 4ca9341 commit 1e102e0

24 files changed

+221
-139
lines changed

__mocks__/expo-location.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ export const getCurrentPositionAsync = jest.fn().mockResolvedValue({
4343
});
4444

4545
export const watchPositionAsync = jest.fn().mockImplementation((options, callback) => {
46-
const interval = setInterval(() => {
46+
let timeoutId: ReturnType<typeof setTimeout> | null = null;
47+
let hasTimedOut = false;
48+
49+
// Use setTimeout for a one-shot callback to avoid timer leaks
50+
timeoutId = setTimeout(() => {
51+
hasTimedOut = true;
52+
timeoutId = null;
4753
callback({
4854
coords: {
4955
latitude: 40.7128,
@@ -56,10 +62,16 @@ export const watchPositionAsync = jest.fn().mockImplementation((options, callbac
5662
},
5763
timestamp: Date.now(),
5864
});
59-
}, 1000);
65+
}, 100); // Shorter delay for faster tests
6066

6167
return Promise.resolve({
62-
remove: () => clearInterval(interval),
68+
remove: () => {
69+
if (timeoutId && !hasTimedOut) {
70+
clearTimeout(timeoutId);
71+
timeoutId = null;
72+
}
73+
// Safe no-op if timeout already fired
74+
},
6375
});
6476
});
6577

jest-setup.ts

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,47 @@ jest.mock('expo-audio', () => ({
3535
}));
3636

3737
// Mock the host component names function to prevent testing library errors
38-
jest.mock('@testing-library/react-native/build/helpers/host-component-names', () => ({
39-
getHostComponentNames: jest.fn(() => ({
40-
text: 'Text',
41-
view: 'View',
42-
scrollView: 'ScrollView',
43-
touchable: 'TouchableOpacity',
44-
switch: 'Switch',
45-
textInput: 'TextInput',
46-
})),
47-
configureHostComponentNamesIfNeeded: jest.fn(),
48-
isHostText: jest.fn((element) => element?.type === 'Text' || element?._fiber?.type === 'Text' || (typeof element === 'object' && element?.props?.children && typeof element.props.children === 'string')),
49-
isHostTextInput: jest.fn((element) => element?.type === 'TextInput' || element?._fiber?.type === 'TextInput'),
50-
isHostImage: jest.fn((element) => element?.type === 'Image' || element?._fiber?.type === 'Image'),
51-
isHostSwitch: jest.fn((element) => element?.type === 'Switch' || element?._fiber?.type === 'Switch'),
52-
isHostScrollView: jest.fn((element) => element?.type === 'ScrollView' || element?._fiber?.type === 'ScrollView'),
53-
isHostModal: jest.fn((element) => element?.type === 'Modal' || element?._fiber?.type === 'Modal'),
54-
}));
38+
// Check if the internal module exists (for pre-v13 compatibility)
39+
try {
40+
require.resolve('@testing-library/react-native/build/helpers/host-component-names');
41+
// If the internal module exists, mock it (pre-v13)
42+
jest.mock('@testing-library/react-native/build/helpers/host-component-names', () => ({
43+
getHostComponentNames: jest.fn(() => ({
44+
text: 'Text',
45+
view: 'View',
46+
scrollView: 'ScrollView',
47+
touchable: 'TouchableOpacity',
48+
switch: 'Switch',
49+
textInput: 'TextInput',
50+
})),
51+
configureHostComponentNamesIfNeeded: jest.fn(),
52+
isHostText: jest.fn((element) => element?.type === 'Text' || element?._fiber?.type === 'Text' || (typeof element === 'object' && element?.props?.children && typeof element.props.children === 'string')),
53+
isHostTextInput: jest.fn((element) => element?.type === 'TextInput' || element?._fiber?.type === 'TextInput'),
54+
isHostImage: jest.fn((element) => element?.type === 'Image' || element?._fiber?.type === 'Image'),
55+
isHostSwitch: jest.fn((element) => element?.type === 'Switch' || element?._fiber?.type === 'Switch'),
56+
isHostScrollView: jest.fn((element) => element?.type === 'ScrollView' || element?._fiber?.type === 'ScrollView'),
57+
isHostModal: jest.fn((element) => element?.type === 'Modal' || element?._fiber?.type === 'Modal'),
58+
}));
59+
} catch (error) {
60+
// Module doesn't exist (v13+), try to use the public API if available
61+
try {
62+
const { configureHostComponentNames } = require('@testing-library/react-native');
63+
// Configure host component names using the public API (v13+)
64+
if (configureHostComponentNames) {
65+
configureHostComponentNames({
66+
text: 'Text',
67+
view: 'View',
68+
scrollView: 'ScrollView',
69+
touchable: 'TouchableOpacity',
70+
switch: 'Switch',
71+
textInput: 'TextInput',
72+
});
73+
}
74+
} catch (publicApiError) {
75+
// If neither internal nor public API is available, log a warning but continue
76+
console.warn('Unable to configure host component names for @testing-library/react-native. Tests may fail if they rely on component type detection.');
77+
}
78+
}
5579

5680
// Global mocks for common problematic modules
5781
jest.mock('@notifee/react-native', () => {

src/app/(app)/_layout.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,12 @@ export default function TabLayout() {
232232
<Sidebar />
233233
</View>
234234
) : (
235-
<Drawer isOpen={isOpen} onClose={() => setIsOpen(false)}>
235+
<Drawer isOpen={isOpen} onClose={() => setIsOpen(false)} {...({} as any)}>
236236
<DrawerBackdrop onPress={() => setIsOpen(false)} />
237237
<DrawerContent className="w-4/5 bg-white p-1 dark:bg-gray-900">
238238
<DrawerBody>
239239
<Sidebar />
240240
</DrawerBody>
241-
<DrawerFooter>
242-
<Button onPress={() => setIsOpen(false)} className="w-full bg-primary-600">
243-
<ButtonText>Close</ButtonText>
244-
</Button>
245-
</DrawerFooter>
246241
</DrawerContent>
247242
</Drawer>
248243
)}

src/app/login/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export default function Login() {
6868
setIsErrorModalVisible(false);
6969
}}
7070
size="full"
71+
{...({} as any)}
7172
>
7273
<ModalBackdrop />
7374
<ModalContent className="m-4 w-full max-w-3xl rounded-2xl">

src/components/calls/full-screen-image-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ const FullScreenImageModal: React.FC<FullScreenImageModalProps> = ({ isOpen, onC
117117
});
118118

119119
return (
120-
<Modal isOpen={isOpen} onClose={onClose} size="full">
120+
<Modal isOpen={isOpen} onClose={onClose} size="full" {...({} as any)}>
121121
<ModalBackdrop onPress={onClose} className="bg-black/90" />
122122
<ModalContent className="flex size-full items-center justify-center border-0 bg-transparent p-0 shadow-none">
123123
<StatusBar hidden />

src/components/notifications/NotificationInbox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ export const NotificationInbox = ({ isOpen, onClose }: NotificationInboxProps) =
314314
</Animated.View>
315315

316316
{/* Delete Confirmation Modal */}
317-
<Modal isOpen={showDeleteConfirmModal} onClose={() => setShowDeleteConfirmModal(false)}>
317+
<Modal isOpen={showDeleteConfirmModal} onClose={() => setShowDeleteConfirmModal(false)} {...({} as any)}>
318318
<ModalBackdrop />
319319
<ModalContent>
320320
<ModalHeader>

src/components/push-notification/push-notification-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const PushNotificationModal: React.FC = () => {
104104
const typeText = getNotificationTypeText(notification.type);
105105

106106
return (
107-
<Modal isOpen={isOpen} onClose={handleClose} size="md">
107+
<Modal isOpen={isOpen} onClose={handleClose} size="md" {...({} as any)}>
108108
<ModalBackdrop />
109109
<ModalContent className="mx-4">
110110
<ModalHeader className="pb-4">

src/components/roles/roles-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export const RolesModal: React.FC<RolesModalProps> = ({ isOpen, onClose }) => {
7575
}, [activeUnit, pendingAssignments, onClose]);
7676

7777
return (
78-
<Modal isOpen={isOpen} onClose={onClose} size="full">
78+
<Modal isOpen={isOpen} onClose={onClose} size="full" {...({} as any)}>
7979
<ModalBackdrop />
8080
<ModalContent className="m-4 w-full max-w-3xl rounded-2xl">
8181
<ModalHeader>

src/components/settings/__tests__/server-url-bottom-sheet-simple.test.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
// Mock Platform first, before any other imports
2-
jest.mock('react-native/Libraries/Utilities/Platform', () => ({
3-
OS: 'ios',
4-
select: jest.fn().mockImplementation((obj) => obj.ios || obj.default),
5-
}));
6-
71
import { render, screen } from '@testing-library/react-native';
82
import React from 'react';
93

src/components/settings/__tests__/unit-selection-bottom-sheet-simple.test.tsx

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
1-
// Mock react-i18next first
1+
// Mock react-i18next
22
jest.mock('react-i18next', () => ({
33
useTranslation: () => ({
4-
t: jest.fn((key: string, options?: any) => {
5-
const translations: { [key: string]: string } = {
6-
'settings.select_unit': 'Select Unit',
7-
'settings.current_unit': 'Current Unit',
8-
'settings.no_units_available': 'No units available',
9-
'common.cancel': 'Cancel',
10-
'settings.unit_selected_successfully': `${options?.unitName || 'Unit'} selected successfully`,
11-
'settings.unit_selection_failed': 'Failed to select unit. Please try again.',
12-
};
13-
return translations[key] || key;
14-
}),
4+
t: (key: string, options?: any) => key,
155
}),
166
}));
177

@@ -90,12 +80,6 @@ jest.mock('@/stores/toast/store', () => ({
9080
useToastStore: jest.fn(),
9181
}));
9282

93-
jest.mock('react-i18next', () => ({
94-
useTranslation: () => ({
95-
t: (key: string) => key,
96-
}),
97-
}));
98-
9983
// Mock lucide icons to avoid SVG issues in tests
10084
jest.mock('lucide-react-native', () => ({
10185
Check: 'Check',

0 commit comments

Comments
 (0)