From fd011802bb61ece9eda415e6b7b114d588a7fc95 Mon Sep 17 00:00:00 2001 From: Radomir Drndarski Date: Wed, 8 Dec 2021 17:29:59 +0100 Subject: [PATCH] Added unit tests to cover exception handling in secure-storage; Fixed a minor issue --- src/lib/secure-storage/index.test.tsx | 34 ++++++++++++ src/lib/secure-storage/storage.test.tsx | 72 +++++++++++++++++++++++++ src/lib/secure-storage/storage.ts | 2 +- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/lib/secure-storage/index.test.tsx create mode 100644 src/lib/secure-storage/storage.test.tsx diff --git a/src/lib/secure-storage/index.test.tsx b/src/lib/secure-storage/index.test.tsx new file mode 100644 index 00000000..b2d1d46e --- /dev/null +++ b/src/lib/secure-storage/index.test.tsx @@ -0,0 +1,34 @@ +import { mocked } from 'ts-jest/utils' + +import { setItem, getItem } from './storage' +const { saveObject, getObject } = jest.requireActual('./index') + +jest.mock('./storage', () => ({ + setItem: jest.fn(), + getItem: jest.fn(), +})) + +const getItemMocked = mocked(getItem) +const setItemMocked = mocked(setItem) + +describe('storage', () => { + afterEach(() => { + getItemMocked.mockClear() + setItemMocked.mockClear() + }) + + it('saveObject to reject when exception occurs in setItem', async () => { + setItemMocked.mockRejectedValueOnce('setItem error') + await expect(saveObject('foo', 'bar')).rejects.toEqual('setItem error') + }) + + it('getObject to return null when exception occurs in getItem', async () => { + getItemMocked.mockRejectedValueOnce('getItem error') + await expect(getObject('foo')).resolves.toBeNull() + }) + + it('getObject to return null when exception occurs in JSON.parse', async () => { + getItemMocked.mockResolvedValueOnce('bad json') + await expect(getObject('foo')).resolves.toBeNull() + }) +}) diff --git a/src/lib/secure-storage/storage.test.tsx b/src/lib/secure-storage/storage.test.tsx new file mode 100644 index 00000000..01ed21b5 --- /dev/null +++ b/src/lib/secure-storage/storage.test.tsx @@ -0,0 +1,72 @@ +import { writeAsStringAsync, readAsStringAsync } from 'expo-file-system' +import { getItemAsync, setItemAsync } from 'expo-secure-store' +import { mocked } from 'ts-jest/utils' +const { setItem, getItem } = jest.requireActual('./storage') + +jest.mock('expo-file-system', () => ({ + writeAsStringAsync: jest.fn(), + getInfoAsync: jest.fn().mockReturnValue({ exists: true }), + readAsStringAsync: jest.fn(), +})) + +jest.mock('expo-secure-store', () => ({ + getItemAsync: jest.fn(), + setItemAsync: jest.fn(), +})) + +global.crypto = { + getRandomValues: jest.fn().mockReturnValue(new Uint8Array(32)), +} + +const writeAsStringAsyncMocked = mocked(writeAsStringAsync) +const readAsStringAsyncMocked = mocked(readAsStringAsync) +const getItemAsyncMocked = mocked(getItemAsync) +const setItemAsyncMocked = mocked(setItemAsync) + +describe('storage', () => { + afterEach(() => { + writeAsStringAsyncMocked.mockClear() + readAsStringAsyncMocked.mockClear() + getItemAsyncMocked.mockClear() + setItemAsyncMocked.mockClear() + }) + + it('setItem to reject when exception occurs in readAsStringAsync', async () => { + readAsStringAsyncMocked.mockRejectedValueOnce('readAsStringAsync error') + await expect(setItem('foo', 'bar')).rejects.toEqual( + 'readAsStringAsync error' + ) + }) + + it('setItem to reject when exception occurs in setItemAsync', async () => { + setItemAsyncMocked.mockRejectedValueOnce('setItemAsync error') + readAsStringAsyncMocked.mockReturnValueOnce(null) + await expect(setItem('foo', 'bar')).rejects.toEqual('setItemAsync error') + }) + + it('setItem to reject when exception occurs in writeAsStringAsync', async () => { + setItemAsyncMocked.mockResolvedValueOnce() + readAsStringAsyncMocked.mockReturnValueOnce(null) + writeAsStringAsyncMocked.mockRejectedValueOnce('writeAsStringAsync error') + await expect(setItem('foo', 'bar')).rejects.toEqual( + 'writeAsStringAsync error' + ) + }) + + it('getItem to reject when exception occurs in readAsStringAsync', async () => { + readAsStringAsyncMocked.mockRejectedValueOnce('readAsStringAsync error') + await expect(getItem('foo')).rejects.toEqual('readAsStringAsync error') + }) + + it('getItem to reject when getItemAsync returns null', async () => { + readAsStringAsyncMocked.mockResolvedValueOnce('encrypted_storage_key') + getItemAsyncMocked.mockResolvedValueOnce(null) + await expect(getItem('foo')).rejects.toEqual('Storage key not found') + }) + + it('getItem to reject when exception occurs in getItemAsyncMocked', async () => { + readAsStringAsyncMocked.mockResolvedValueOnce('encrypted_storage_key') + getItemAsyncMocked.mockRejectedValueOnce('getItemAsync error') + await expect(getItem('foo')).rejects.toEqual('getItemAsync error') + }) +}) diff --git a/src/lib/secure-storage/storage.ts b/src/lib/secure-storage/storage.ts index f9d3533f..2865adca 100644 --- a/src/lib/secure-storage/storage.ts +++ b/src/lib/secure-storage/storage.ts @@ -51,7 +51,7 @@ const getDecryptedStorage = async () => { const encryptedStorage = await FileSystem.readAsStringAsync( storageFileNameURI ) - if (encryptedStorage.length === 0) { + if (!encryptedStorage || encryptedStorage.length === 0) { return {} }