From 397c14d590a3a9475fac58f46fa924619fef9467 Mon Sep 17 00:00:00 2001 From: Torpenn Date: Sun, 13 Oct 2024 23:17:48 +0200 Subject: [PATCH] feat: add AsyncStorage package and helpers --- components/shared/business/AsyncStorage.ts | 21 ++++++ .../business/__tests__/AsyncStorage-test.js | 64 +++++++++++++++++++ package-lock.json | 34 ++++++++++ package.json | 1 + 4 files changed, 120 insertions(+) create mode 100644 components/shared/business/AsyncStorage.ts create mode 100644 components/shared/business/__tests__/AsyncStorage-test.js diff --git a/components/shared/business/AsyncStorage.ts b/components/shared/business/AsyncStorage.ts new file mode 100644 index 0000000..f456d33 --- /dev/null +++ b/components/shared/business/AsyncStorage.ts @@ -0,0 +1,21 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; + +export const saveUserSettings = async (key: string, value: string) => { + try { + await AsyncStorage.setItem(key, value); + } catch (e) { + throw new Error('Failed to load the data from AsyncStorage'); + } +}; + +export const loadUserSettings = async (key: string) => { + try { + const value = await AsyncStorage.getItem(key); + + if (value !== null) { + return value; + } + } catch (e) { + throw new Error('Failed to load the data from AsyncStorage'); + } +}; diff --git a/components/shared/business/__tests__/AsyncStorage-test.js b/components/shared/business/__tests__/AsyncStorage-test.js new file mode 100644 index 0000000..fff529b --- /dev/null +++ b/components/shared/business/__tests__/AsyncStorage-test.js @@ -0,0 +1,64 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { saveUserSettings, loadUserSettings } from '../AsyncStorage'; + +// Mock de AsyncStorage +jest.mock('@react-native-async-storage/async-storage', () => ({ + setItem: jest.fn(), + getItem: jest.fn(), +})); + +describe('UserSettings functions', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('saveUserSettings', () => { + test('should save data to AsyncStorage', async () => { + const key = 'theme'; + const value = 'dark'; + + await saveUserSettings(key, value); + + expect(AsyncStorage.setItem).toHaveBeenCalledWith(key, value); + }); + + test('should throw an error if AsyncStorage.setItem fails', async () => { + AsyncStorage.setItem.mockRejectedValueOnce(new Error('AsyncStorage error')); + + await expect(saveUserSettings('theme', 'dark')).rejects.toThrow( + 'Failed to load the data from AsyncStorage' + ); + }); + }); + + describe('loadUserSettings', () => { + test('should load data from AsyncStorage', async () => { + const key = 'theme'; + const value = 'dark'; + + AsyncStorage.getItem.mockResolvedValueOnce(value); + + const result = await loadUserSettings(key); + + expect(result).toBe(value); + + expect(AsyncStorage.getItem).toHaveBeenCalledWith(key); + }); + + test('should return null if the value does not exist in AsyncStorage', async () => { + AsyncStorage.getItem.mockResolvedValueOnce(null); + + const result = await loadUserSettings('nonexistent_key'); + + expect(result).toBeUndefined(); + }); + + test('should throw an error if AsyncStorage.getItem fails', async () => { + AsyncStorage.getItem.mockRejectedValueOnce(new Error('AsyncStorage error')); + + await expect(loadUserSettings('theme')).rejects.toThrow( + 'Failed to load the data from AsyncStorage' + ); + }); + }); +}); diff --git a/package-lock.json b/package-lock.json index 78781bf..f963a94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@emotion/native": "^11.11.0", "@emotion/react": "^11.13.3", "@expo/vector-icons": "^14.0.2", + "@react-native-async-storage/async-storage": "^2.0.0", "@react-native-picker/picker": "2.7.5", "@react-navigation/native": "^6.0.2", "@testing-library/react-native": "^12.7.2", @@ -5085,6 +5086,18 @@ "react": "^16.8 || ^17.0 || ^18.0" } }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.0.0.tgz", + "integrity": "sha512-af6H9JjfL6G/PktBfUivvexoiFKQTJGQCtSWxMdivLzNIY94mu9DdiY0JqCSg/LyPCLGKhHPUlRQhNvpu3/KVA==", + "license": "MIT", + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.65 <1.0" + } + }, "node_modules/@react-native-community/cli": { "version": "13.6.9", "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-13.6.9.tgz", @@ -14133,6 +14146,15 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -17793,6 +17815,18 @@ "integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA==", "license": "BSD-2-Clause" }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", diff --git a/package.json b/package.json index 2c39fac..dc59615 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@emotion/native": "^11.11.0", "@emotion/react": "^11.13.3", "@expo/vector-icons": "^14.0.2", + "@react-native-async-storage/async-storage": "^2.0.0", "@react-native-picker/picker": "2.7.5", "@react-navigation/native": "^6.0.2", "@testing-library/react-native": "^12.7.2",