Skip to content

Commit a7f0f15

Browse files
Chore/expo 54 (#140)
* chore: upgrade to expo 54 * fix: bottom sheet typescript * chore: update pnpm-lock.yaml to sync with package.json * fix: upgrade libraries * test: fix mmkv mock * chore: patch expo version * fix: expo doctor
1 parent 2c956c0 commit a7f0f15

10 files changed

Lines changed: 2211 additions & 1519 deletions

File tree

__mocks__/react-native-mmkv.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
const sharedMockStorage = new Map<string, string>();
2+
3+
const createMockStorage = () => {
4+
const mockGetString = jest.fn((key: string): string | undefined =>
5+
sharedMockStorage.get(key),
6+
);
7+
8+
const mockSet = jest.fn((key: string, value: string): void => {
9+
sharedMockStorage.set(key, value);
10+
});
11+
12+
const mockRemove = jest.fn((key: string): void => {
13+
sharedMockStorage.delete(key);
14+
});
15+
16+
return {
17+
getString: mockGetString,
18+
set: mockSet,
19+
remove: mockRemove,
20+
clearAll: jest.fn((): void => {
21+
sharedMockStorage.clear();
22+
}),
23+
getAllKeys: jest.fn(
24+
(): Array<string> => Array.from(sharedMockStorage.keys()),
25+
),
26+
contains: jest.fn((key: string): boolean => sharedMockStorage.has(key)),
27+
getNumber: jest.fn((key: string): number | undefined => {
28+
const value = sharedMockStorage.get(key);
29+
return value ? Number(value) : undefined;
30+
}),
31+
getBoolean: jest.fn((key: string): boolean | undefined => {
32+
const value = sharedMockStorage.get(key);
33+
if (value === undefined) {
34+
return undefined;
35+
}
36+
return value === 'true';
37+
}),
38+
setNumber: jest.fn((key: string, value: number): void => {
39+
sharedMockStorage.set(key, String(value));
40+
}),
41+
setBoolean: jest.fn((key: string, value: boolean): void => {
42+
sharedMockStorage.set(key, String(value));
43+
}),
44+
};
45+
};
46+
47+
export function createMMKV(_options?: { id?: string }) {
48+
return createMockStorage();
49+
}

__tests__/components/providers/auth.test.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,6 @@ import {
1313
useAuth,
1414
} from '../../../src/components/providers/auth';
1515

16-
// Mock MMKV Storage
17-
jest.mock('react-native-mmkv', () => {
18-
const mockStorage = new Map();
19-
return {
20-
MMKV: jest.fn().mockImplementation(() => ({
21-
set: (key: string, value: string) => mockStorage.set(key, value),
22-
getString: (key: string) => mockStorage.get(key) ?? null,
23-
delete: (key: string) => mockStorage.delete(key),
24-
})),
25-
};
26-
});
27-
2816
// Mock API client interceptors
2917
jest.mock('@/api', () => ({
3018
client: {

__tests__/lib/storage.test.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
import { type MMKV } from 'react-native-mmkv';
2-
31
import { getItem, removeItem, setItem, storage } from '@/lib/storage';
42

53
const TEST_VALUE = 123;
64
const TEST_NUMBER = 42;
75

86
// Mock react-native-mmkv
9-
jest.mock('react-native-mmkv', () => ({
10-
MMKV: jest.fn().mockImplementation(() => ({
11-
getString: jest.fn(),
12-
set: jest.fn(),
13-
delete: jest.fn(),
14-
})),
15-
}));
16-
7+
// Note: The mock is already set up globally in jest-setup.ts
8+
// We just need to cast the storage to access jest mock functions
179
function setupMockStorage() {
18-
const mockStorage = storage as jest.Mocked<MMKV>;
10+
const mockStorage = storage as unknown as {
11+
getString: jest.Mock;
12+
set: jest.Mock;
13+
remove: jest.Mock;
14+
};
1915
jest.clearAllMocks();
2016
return mockStorage;
2117
}
2218

2319
describe('storage utilities', () => {
24-
let mockStorage: jest.Mocked<MMKV>;
20+
let mockStorage: {
21+
getString: jest.Mock;
22+
set: jest.Mock;
23+
remove: jest.Mock;
24+
};
2525

2626
beforeEach(() => {
2727
mockStorage = setupMockStorage();
@@ -83,10 +83,10 @@ describe('storage utilities', () => {
8383
});
8484

8585
describe('removeItem', () => {
86-
it('should delete the key from storage', async () => {
86+
it('should remove the key from storage', async () => {
8787
await removeItem('test-key');
8888

89-
expect(mockStorage.delete).toHaveBeenCalledWith('test-key');
89+
expect(mockStorage.remove).toHaveBeenCalledWith('test-key');
9090
});
9191
});
9292
});

app.config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-lines-per-function */
12
import type { ConfigContext, ExpoConfig } from '@expo/config';
23
import type { AppIconBadgeConfig } from 'app-icon-badge/types';
34

@@ -61,6 +62,14 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
6162
bundler: 'metro',
6263
},
6364
plugins: [
65+
[
66+
'expo-build-properties',
67+
{
68+
ios: {
69+
deploymentTarget: '16.0',
70+
},
71+
},
72+
],
6473
[
6574
'expo-splash-screen',
6675
{

jest-setup.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ import '@testing-library/react-native/extend-expect';
55
global.window = {};
66
// @ts-ignore
77
global.window = global;
8+
9+
jest.mock('react-native-mmkv');

package.json

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -61,51 +61,54 @@
6161
"e2e-test": "maestro test .maestro/ -e APP_ID=com.obytes.development"
6262
},
6363
"dependencies": {
64-
"@expo/metro-runtime": "^5.0.5",
64+
"@expo/metro-runtime": "^6.1.2",
6565
"@gorhom/bottom-sheet": "^5.0.5",
6666
"@hookform/resolvers": "^3.9.0",
6767
"@lukemorales/query-key-factory": "^1.3.4",
68-
"@shopify/flash-list": "1.7.6",
68+
"@shopify/flash-list": "2.0.2",
6969
"@tanstack/react-query": "^5.52.1",
7070
"@testing-library/react-hooks": "^8.0.1",
7171
"app-icon-badge": "^0.1.2",
7272
"axios": "^1.7.5",
7373
"dayjs": "^1.11.13",
74-
"expo": "~53.0.23",
75-
"expo-constants": "~17.1.7",
76-
"expo-crypto": "^14.1.5",
77-
"expo-dev-client": "~5.2.4",
78-
"expo-font": "~13.3.2",
79-
"expo-image": "~2.4.0",
80-
"expo-linking": "~7.1.7",
81-
"expo-localization": "~16.1.6",
82-
"expo-router": "~5.1.7",
83-
"expo-splash-screen": "~0.30.10",
84-
"expo-status-bar": "~2.2.3",
85-
"expo-system-ui": "~5.0.11",
74+
"expo": "~54.0.32",
75+
"expo-build-properties": "^1.0.10",
76+
"expo-constants": "~18.0.13",
77+
"expo-crypto": "^15.0.8",
78+
"expo-dev-client": "~6.0.20",
79+
"expo-font": "~14.0.11",
80+
"expo-image": "~3.0.11",
81+
"expo-linking": "~8.0.11",
82+
"expo-localization": "~17.0.8",
83+
"expo-router": "~6.0.22",
84+
"expo-splash-screen": "~31.0.13",
85+
"expo-status-bar": "~3.0.9",
86+
"expo-system-ui": "~6.0.9",
8687
"i18next": "^23.14.0",
8788
"lodash.memoize": "^4.1.2",
8889
"moti": "^0.29.0",
8990
"nativewind": "^4.1.21",
90-
"react": "19.0.0",
91-
"react-dom": "19.0.0",
91+
"react": "19.1.0",
92+
"react-dom": "19.1.0",
9293
"react-error-boundary": "^4.0.13",
9394
"react-hook-form": "^7.53.0",
9495
"react-i18next": "^15.0.1",
95-
"react-native": "0.79.5",
96+
"react-native": "0.81.5",
9697
"react-native-edge-to-edge": "^1.6.0",
9798
"react-native-flash-message": "^0.4.2",
98-
"react-native-gesture-handler": "~2.24.0",
99-
"react-native-keyboard-controller": "^1.17.4",
100-
"react-native-mmkv": "~3.1.0",
101-
"react-native-reanimated": "~3.17.5",
99+
"react-native-gesture-handler": "~2.28.0",
100+
"react-native-keyboard-controller": "^1.18.5",
101+
"react-native-mmkv": "~4.0.1",
102+
"react-native-nitro-modules": "^0.31.10",
103+
"react-native-reanimated": "~4.1.5",
102104
"react-native-restart": "0.0.27",
103-
"react-native-safe-area-context": "5.4.0",
104-
"react-native-screens": "^4.11.1",
105-
"react-native-svg": "~15.11.2",
105+
"react-native-safe-area-context": "5.6.2",
106+
"react-native-screens": "^4.16.0",
107+
"react-native-svg": "~15.12.1",
106108
"react-native-url-polyfill": "^2.0.0",
107-
"react-native-web": "~0.20.0",
108-
"react-native-webview": "13.13.5",
109+
"react-native-web": "~0.21.2",
110+
"react-native-webview": "13.15.0",
111+
"react-native-worklets": "0.5.1",
109112
"react-query-kit": "^3.3.0",
110113
"tailwind-variants": "^0.2.1",
111114
"zod": "^3.23.8",
@@ -118,15 +121,15 @@
118121
"@dev-plugins/react-query": "^0.0.7",
119122
"@eslint/eslintrc": "^3.3.1",
120123
"@eslint/js": "^9.28.0",
121-
"@expo/config": "~11.0.10",
124+
"@expo/config": "~12.0.13",
122125
"@tanstack/eslint-plugin-query": "^5.62.1",
123126
"@testing-library/jest-dom": "^6.5.0",
124127
"@testing-library/react-native": "^12.7.2",
125128
"@types/i18n-js": "^3.8.9",
126129
"@types/invariant": "^2.2.37",
127-
"@types/jest": "^29.5.12",
130+
"@types/jest": "^29.5.14",
128131
"@types/lodash.memoize": "^4.1.9",
129-
"@types/react": "~19.0.14",
132+
"@types/react": "~19.1.17",
130133
"@typescript-eslint/eslint-plugin": "^8.34.0",
131134
"@typescript-eslint/parser": "^8.34.0",
132135
"babel-plugin-module-resolver": "^5.0.2",
@@ -151,14 +154,14 @@
151154
"husky": "^9.1.5",
152155
"jest": "^29.7.0",
153156
"jest-environment-jsdom": "^29.7.0",
154-
"jest-expo": "~53.0.10",
157+
"jest-expo": "~54.0.16",
155158
"jest-junit": "^16.0.0",
156159
"lint-staged": "^15.2.9",
157160
"np": "^10.0.7",
158161
"prettier": "^3.3.3",
159162
"tailwindcss": "3.4.4",
160163
"ts-jest": "^29.1.2",
161-
"typescript": "^5.8.3",
164+
"typescript": "^5.9.3",
162165
"typescript-eslint": "^8.34.0"
163166
},
164167
"repository": {

0 commit comments

Comments
 (0)