Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions __mocks__/expo-keep-awake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const activateKeepAwakeAsync = jest.fn().mockResolvedValue(undefined);
export const deactivateKeepAwake = jest.fn().mockResolvedValue(undefined);
export const useKeepAwake = jest.fn();
28 changes: 28 additions & 0 deletions __mocks__/expo-localization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const getLocales = jest.fn().mockReturnValue([
{
languageCode: 'en',
languageTag: 'en-US',
regionCode: 'US',
textDirection: 'ltr',
digitGroupingSeparator: ',',
decimalSeparator: '.',
measurementSystem: 'imperial',
currencyCode: 'USD',
currencySymbol: '$',
isRTL: false,
},
]);

export const getCalendars = jest.fn().mockReturnValue([
{
calendar: 'gregorian',
timeZone: 'America/New_York',
uses24HourClock: false,
firstWeekday: 1,
},
]);

export const locale = 'en-US';
export const locales = ['en-US'];
export const timezone = 'America/New_York';
export const isRTL = false;
7 changes: 7 additions & 0 deletions __mocks__/react-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export const Linking = {
openURL: jest.fn().mockResolvedValue(undefined),
};

export const I18nManager = {
allowRTL: jest.fn(),
forceRTL: jest.fn(),
isRTL: false,
};
Comment on lines +37 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== I18nManager usage and API members =="
rg -n -C2 '\bI18nManager\b|\bswapLeftAndRightInRTL\b' --type ts --type tsx

echo
echo "== __mocks__/react-native.ts excerpt =="
sed -n '30,80p' __mocks__/react-native.ts

echo
echo "== jest-setup.ts excerpt =="
sed -n '318,336p' jest-setup.ts

Repository: Resgrid/Responder

Length of output: 145


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== __mocks__/react-native.ts (lines 30-80) =="
cat -n __mocks__/react-native.ts | sed -n '30,80p'

echo
echo "== jest-setup.ts (searching for I18nManager) =="
grep -n -A5 'I18nManager' jest-setup.ts || echo "Not found in jest-setup.ts"

echo
echo "== Search for swapLeftAndRightInRTL usage =="
rg -n 'swapLeftAndRightInRTL' || echo "No matches found"

echo
echo "== Search for I18nManager usage across codebase =="
rg -n 'I18nManager' -t ts || echo "No matches in .ts files"

Repository: Resgrid/Responder

Length of output: 2370


Add swapLeftAndRightInRTL to keep I18nManager mock API consistent.

The I18nManager mock at lines 37-41 is missing swapLeftAndRightInRTL, which is defined in jest-setup.ts and actively used in src/app/login/__tests__/login-form.test.tsx. This API surface mismatch can cause undefined behavior if tests import from __mocks__/react-native.ts instead of relying on the jest-setup definition.

🔧 Proposed fix
 export const I18nManager = {
   allowRTL: jest.fn(),
   forceRTL: jest.fn(),
+  swapLeftAndRightInRTL: jest.fn(),
   isRTL: false,
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const I18nManager = {
allowRTL: jest.fn(),
forceRTL: jest.fn(),
isRTL: false,
};
export const I18nManager = {
allowRTL: jest.fn(),
forceRTL: jest.fn(),
swapLeftAndRightInRTL: jest.fn(),
isRTL: false,
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__mocks__/react-native.ts` around lines 37 - 41, The I18nManager mock is
missing the swapLeftAndRightInRTL property used in jest-setup.ts and
src/app/login/__tests__/login-form.test.tsx; update the I18nManager export in
__mocks__/react-native.ts to include swapLeftAndRightInRTL (as a jest.fn() or
boolean as appropriate for the mock) so the mock API matches the real
I18nManager and the tests that call swapLeftAndRightInRTL do not get undefined.


export const useColorScheme = jest.fn().mockReturnValue('light');

export const useWindowDimensions = jest.fn().mockReturnValue({
Expand All @@ -60,4 +66,5 @@ export default {
Text,
StyleSheet,
useColorScheme,
I18nManager,
};
8 changes: 8 additions & 0 deletions jest-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,14 @@ jest.mock('react-native', () => {
removeEventListener: jest.fn(),
},

// I18nManager
I18nManager: {
allowRTL: jest.fn(),
forceRTL: jest.fn(),
swapLeftAndRightInRTL: jest.fn(),
isRTL: false,
},

// NativeEventEmitter
NativeEventEmitter: class {
addListener = jest.fn();
Expand Down
33 changes: 33 additions & 0 deletions src/app/login/__tests__/login-form.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,28 @@ jest.mock('@/components/ui/text', () => {
};
});

jest.mock('@/components/ui/select', () => {
const React = jest.requireActual('react');
const mockView = (name: string) =>
React.forwardRef(({ children, ...props }: any, ref: any) =>
React.createElement('div', { ...props, ref, testID: name }, children)
);
return {
Select: React.forwardRef(({ children, onValueChange, selectedValue, ...props }: any, ref: any) =>
React.createElement('div', { ...props, ref, testID: 'select' }, children)
),
SelectTrigger: mockView('select-trigger'),
SelectInput: mockView('select-input'),
SelectIcon: mockView('select-icon'),
SelectPortal: mockView('select-portal'),
SelectBackdrop: mockView('select-backdrop'),
SelectContent: mockView('select-content'),
SelectDragIndicator: mockView('select-drag-indicator'),
SelectDragIndicatorWrapper: mockView('select-drag-indicator-wrapper'),
SelectItem: mockView('select-item'),
};
});

// Mock React Native components
jest.mock('react-native', () => {
const ReactNative = jest.requireActual('react-native');
Expand All @@ -126,6 +148,12 @@ jest.mock('react-native', () => {
Keyboard: {
dismiss: jest.fn(),
},
I18nManager: {
allowRTL: jest.fn(),
forceRTL: jest.fn(),
swapLeftAndRightInRTL: jest.fn(),
isRTL: false,
},
};
});

Expand All @@ -134,6 +162,7 @@ jest.mock('lucide-react-native', () => ({
AlertTriangle: jest.fn(() => 'AlertTriangle'),
EyeIcon: jest.fn(() => 'EyeIcon'),
EyeOffIcon: jest.fn(() => 'EyeOffIcon'),
GlobeIcon: jest.fn(() => 'GlobeIcon'),
}));

// Mock nativewind
Expand All @@ -147,6 +176,10 @@ jest.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
initReactI18next: {
type: '3rdParty',
init: jest.fn(),
},
}));

// Mock react-hook-form
Expand Down
5 changes: 1 addition & 4 deletions src/app/login/login-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,7 @@ export const LoginForm = ({ onSubmit = () => {}, isLoading = false, error = unde
{/* Language Selector */}
<View className="mt-4 w-full flex-row items-center justify-center gap-2">
<GlobeIcon size={16} className="text-gray-500" />
<Select
onValueChange={(val) => setLanguage(val as Language)}
selectedValue={language ?? 'en'}
>
<Select onValueChange={(val) => setLanguage(val as Language)} selectedValue={language ?? 'en'}>
<SelectTrigger className="border-0 bg-transparent">
<SelectInput placeholder={t('login.select_language')} className="text-xs text-gray-500" />
<SelectIcon as={GlobeIcon} className="mr-1 text-gray-500" />
Expand Down
14 changes: 7 additions & 7 deletions src/translations/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@
"password": "كلمة المرور",
"password_incorrect": "كانت كلمة المرور غير صحيحة",
"password_placeholder": "أدخل كلمة المرور الخاصة بك",
"select_language": "اللغة",
"sso": {
"back": "رجوع",
"change_department": "تغيير المستخدم",
Expand All @@ -598,7 +599,6 @@
"username_placeholder": "أدخل اسم المستخدم أو بريدك الإلكتروني",
"username_required": "اسم المستخدم مطلوب"
},
"select_language": "اللغة",
"title": "تسجيل الدخول",
"username": "اسم المستخدم",
"username_placeholder": "أدخل اسم المستخدم الخاص بك"
Expand Down Expand Up @@ -809,20 +809,17 @@
"background_location": "الموقع في الخلفية",
"contact_us": "اتصل بنا",
"english": "إنجليزي",
"french": "فرنسي",
"german": "ألماني",
"italian": "إيطالي",
"polish": "بولندي",
"swedish": "سويدي",
"ukrainian": "أوكراني",
"enter_password": "أدخل كلمة المرور الخاصة بك",
"enter_server_url": "أدخل عنوان URL لواجهة برمجة تطبيقات Resgrid (مثال: https://api.resgrid.com)",
"enter_username": "أدخل اسم المستخدم الخاص بك",
"environment": "البيئة",
"french": "فرنسي",
"general": "عام",
"generale": "عام",
"german": "ألماني",
"github": "جيثب",
"help_center": "مركز المساعدة",
"italian": "إيطالي",
"keep_alive": "إبقاء الجهاز نشطاً",
"keep_alive_warning": "تحذير: تفعيل إبقاء الجهاز نشطاً سيمنع جهازك من الدخول في وضع السكون وقد يزيد بشكل كبير من استنزاف البطارية.",
"keep_screen_on": "إبقاء الشاشة مضاءة",
Expand All @@ -843,6 +840,7 @@
"notifications_description": "تفعيل الإشعارات لتلقي التنبيهات والتحديثات",
"notifications_enable": "تفعيل الإشعارات",
"password": "كلمة المرور",
"polish": "بولندي",
"preferences": "التفضيلات",
"privacy": "سياسة الخصوصية",
"privacy_policy": "سياسة الخصوصية",
Expand All @@ -859,6 +857,7 @@
"status_page": "حالة النظام",
"support": "الدعم",
"support_us": "ادعمنا",
"swedish": "سويدي",
"terms": "شروط الخدمة",
"theme": {
"dark": "مظلم",
Expand All @@ -867,6 +866,7 @@
"title": "المظهر"
},
"title": "الإعدادات",
"ukrainian": "أوكراني",
"unit_selection": "اختيار الوحدة",
"username": "اسم المستخدم",
"version": "الإصدار",
Expand Down
14 changes: 7 additions & 7 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@
"password": "Password",
"password_incorrect": "Password was incorrect",
"password_placeholder": "Enter your password",
"select_language": "Language",
"sso": {
"back": "Back",
"change_department": "Change username",
Expand All @@ -598,7 +599,6 @@
"username_placeholder": "Enter your username or email",
"username_required": "Username is required"
},
"select_language": "Language",
"title": "Login",
"username": "Username",
"username_placeholder": "Enter your username"
Expand Down Expand Up @@ -809,20 +809,17 @@
"background_location": "Background Location",
"contact_us": "Contact Us",
"english": "English",
"french": "French",
"german": "German",
"italian": "Italian",
"polish": "Polish",
"swedish": "Swedish",
"ukrainian": "Ukrainian",
"enter_password": "Enter your password",
"enter_server_url": "Enter Resgrid API URL (e.g., https://api.resgrid.com)",
"enter_username": "Enter your username",
"environment": "Environment",
"french": "French",
"general": "General",
"generale": "General",
"german": "German",
"github": "Github",
"help_center": "Help Center",
"italian": "Italian",
"keep_alive": "Keep Alive",
"keep_alive_warning": "Warning: Enabling keep alive will prevent your device from sleeping and may significantly increase battery drain.",
"keep_screen_on": "Keep Screen On",
Expand All @@ -843,6 +840,7 @@
"notifications_description": "Enable notifications to receive alerts and updates",
"notifications_enable": "Enable Notifications",
"password": "Password",
"polish": "Polish",
"preferences": "Preferences",
"privacy": "Privacy Policy",
"privacy_policy": "Privacy Policy",
Expand All @@ -859,6 +857,7 @@
"status_page": "System Status",
"support": "Support",
"support_us": "Support Us",
"swedish": "Swedish",
"terms": "Terms of Service",
"theme": {
"dark": "Dark",
Expand All @@ -867,6 +866,7 @@
"title": "Theme"
},
"title": "Settings",
"ukrainian": "Ukrainian",
"unit_selection": "Unit Selection",
"username": "Username",
"version": "Version",
Expand Down
14 changes: 7 additions & 7 deletions src/translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@
"password": "Contraseña",
"password_incorrect": "La contraseña era incorrecta",
"password_placeholder": "Introduce tu contraseña",
"select_language": "Idioma",
"sso": {
"back": "Atrás",
"change_department": "Cambiar usuario",
Expand All @@ -598,7 +599,6 @@
"username_placeholder": "Introduce tu usuario o correo",
"username_required": "El usuario es obligatorio"
},
"select_language": "Idioma",
"title": "Iniciar sesión",
"username": "Nombre de usuario",
"username_placeholder": "Introduce tu nombre de usuario"
Expand Down Expand Up @@ -809,20 +809,17 @@
"background_location": "Ubicación en segundo plano",
"contact_us": "Contáctanos",
"english": "Inglés",
"french": "Francés",
"german": "Alemán",
"italian": "Italiano",
"polish": "Polaco",
"swedish": "Sueco",
"ukrainian": "Ucraniano",
"enter_password": "Introduce tu contraseña",
"enter_server_url": "Introduce la URL de la API de Resgrid (ej: https://api.resgrid.com)",
"enter_username": "Introduce tu nombre de usuario",
"environment": "Entorno",
"french": "Francés",
"general": "General",
"generale": "General",
"german": "Alemán",
"github": "Github",
"help_center": "Centro de ayuda",
"italian": "Italiano",
"keep_alive": "Mantener Activo",
"keep_alive_warning": "Advertencia: Habilitar mantener activo evitará que su dispositivo entre en suspensión y puede aumentar significativamente el consumo de batería.",
"keep_screen_on": "Mantener pantalla encendida",
Expand All @@ -843,6 +840,7 @@
"notifications_description": "Habilitar notificaciones para recibir alertas y actualizaciones",
"notifications_enable": "Habilitar Notificaciones",
"password": "Contraseña",
"polish": "Polaco",
"preferences": "Preferencias",
"privacy": "Política de privacidad",
"privacy_policy": "Política de privacidad",
Expand All @@ -859,6 +857,7 @@
"status_page": "Estado del sistema",
"support": "Soporte",
"support_us": "Apóyanos",
"swedish": "Sueco",
"terms": "Términos de servicio",
"theme": {
"dark": "Oscuro",
Expand All @@ -867,6 +866,7 @@
"title": "Tema"
},
"title": "Configuración",
"ukrainian": "Ucraniano",
"unit_selection": "Selección de unidad",
"username": "Nombre de usuario",
"version": "Versión",
Expand Down
2 changes: 1 addition & 1 deletion src/translations/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"selection_error_message": "Nie można zapisać preferowanego urządzenia",
"selection_error_title": "Błąd wyboru",
"supports_mic_control": "Sterowanie mikrofonem",
"tap_scan_to_find_devices": "Naciśnij „Skanuj", aby znaleźć urządzenia audio Bluetooth",
"tap_scan_to_find_devices": "Naciśnij \u201eSkanuj\u201d, aby znaleźć urządzenia audio Bluetooth",
"unknown_device": "Nieznane urządzenie"
},
"calendar": {
Expand Down
Loading