Skip to content

Commit

Permalink
fix(useAsyncStorage): make more robust
Browse files Browse the repository at this point in the history
  • Loading branch information
pke committed Mar 29, 2022
1 parent 54f5c9a commit b75dd11
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ buck-out/

# builds by bob
lib/
coverage
84 changes: 84 additions & 0 deletions __tests__/useAsyncStorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @format
*/
/* eslint-disable no-shadow */
import { renderHook, act } from '@testing-library/react-hooks';

import AsyncStorage, { useAsyncStorage } from '../src';

afterEach(AsyncStorage.clear);

function expectStableCallbacks(result: any, rerender: () => void) {
const previousFunctions = Object.values(result.current).filter(
(item) => typeof item === 'function'
);
rerender();
const nowFunctions = Object.values(result.current).filter(
(item) => typeof item === 'function'
);
expect(nowFunctions).toHaveLength(previousFunctions.length);
expect(nowFunctions).toEqual(previousFunctions);
}

describe('useAsyncStorage', () => {
it('should export only stable output', async () => {
const { result, rerender } = renderHook(() => useAsyncStorage('key'));
expect(result.error).toBeUndefined();
expectStableCallbacks(result, rerender);
});

it('can read/write data to/from storage', async () => {
const newData = Math.floor(Math.random() * 1000).toString();
const { result } = renderHook(() => useAsyncStorage('key'));

await result.current.setItem(newData);

const data = await result.current.getItem();

expect(data).toBe(newData);
});

it('can remove from storage', async () => {
await AsyncStorage.setItem('key', 'value');
const { result } = renderHook(() => useAsyncStorage('key'));
await act(() => result.current.removeItem());
expect(await AsyncStorage.getItem('key')).toBeNull();
});

it.skip('should throw when mergeItem is not supported', async () => {
const { result } = renderHook(() => useAsyncStorage('key'));
const mergeItem = AsyncStorage.mergeItem;
delete AsyncStorage.mergeItem;
expect(result.current.mergeItem({})).rejects.toThrow();
AsyncStorage.mergeItem = mergeItem;
});

it('can use merge with current data in storage', async () => {
let originalPerson = {
name: 'Jerry',
age: 21,
characteristics: {
hair: 'black',
eyes: 'green',
},
};

const { result } = renderHook(() => useAsyncStorage('person'));

await result.current.setItem(JSON.stringify(originalPerson));

originalPerson.name = 'Harry';
originalPerson.characteristics.hair = 'red';
// @ts-expect-error
originalPerson.characteristics.shoeSize = 40;

await result.current.mergeItem(JSON.stringify(originalPerson));

const currentPerson = await result.current.getItem();
const person = JSON.parse(currentPerson);

expect(person).toHaveProperty('name', 'Harry');
expect(person.characteristics).toHaveProperty('hair', 'red');
expect(person.characteristics).toHaveProperty('shoeSize', 40);
});
});
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
"@react-native-community/eslint-config": "^3.0.0",
"@semantic-release/changelog": "^6.0.0",
"@semantic-release/git": "^10.0.0",
"@testing-library/react-hooks": "^7.0.2",
"@types/jest": "^27.4.1",
"@types/react": "^17.0.0",
"@types/react-native": "^0.64.0",
"concurrently": "^6.4.0",
Expand All @@ -99,10 +101,10 @@
"npm/chalk": "^4.1.2"
},
"jest": {
"preset": "react-native",
"setupFiles": [
"./example/jest.setup.js"
]
],
"restoreMocks": true
},
"detox": {
"test-runner": "jest",
Expand Down
36 changes: 29 additions & 7 deletions src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
import React from 'react';
import AsyncStorage from './AsyncStorage';
import type { AsyncStorageHook } from './types';

export function useAsyncStorage(key: string): AsyncStorageHook {
return {
getItem: (...args) => AsyncStorage.getItem(key, ...args),
setItem: (...args) => AsyncStorage.setItem(key, ...args),
mergeItem: (...args) =>
export function useAsyncStorage(key: string) {
const getItem = React.useCallback(
(...args) => AsyncStorage.getItem(key, ...args),
[key]
);

const setItem = React.useCallback(
//@ts-ignore
(...args) => AsyncStorage.setItem(key, ...args),
[key]
);

const mergeItem = React.useCallback(
(...args) =>
//@ts-ignore
AsyncStorage.mergeItem?.(key, ...args) ??
Promise.reject('Not implemented'),
removeItem: (...args) => AsyncStorage.removeItem(key, ...args),
[key]
);

const removeItem = React.useCallback(
(...args) => AsyncStorage.removeItem(key, ...args),
[key]
);

return {
getItem,
setItem,
mergeItem,
removeItem,
};
}
100 changes: 100 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,13 @@
dependencies:
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.12.5":
version "7.17.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941"
integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==
dependencies:
regenerator-runtime "^0.13.4"

"@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.3.3", "@babel/template@^7.8.6":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
Expand Down Expand Up @@ -2275,6 +2282,17 @@
dependencies:
"@sinonjs/commons" "^1.7.0"

"@testing-library/react-hooks@^7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-7.0.2.tgz#3388d07f562d91e7f2431a4a21b5186062ecfee0"
integrity sha512-dYxpz8u9m4q1TuzfcUApqi8iFfR6R0FaMbr2hjZJy1uC8z+bO/K4v8Gs9eogGKYQop7QsrBTFkv/BCF7MzD2Cg==
dependencies:
"@babel/runtime" "^7.12.5"
"@types/react" ">=16.9.0"
"@types/react-dom" ">=16.9.0"
"@types/react-test-renderer" ">=16.9.0"
react-error-boundary "^3.1.0"

"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
Expand Down Expand Up @@ -2357,6 +2375,14 @@
dependencies:
"@types/istanbul-lib-report" "*"

"@types/jest@^27.4.1":
version "27.4.1"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.1.tgz#185cbe2926eaaf9662d340cc02e548ce9e11ab6d"
integrity sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==
dependencies:
jest-matcher-utils "^27.0.0"
pretty-format "^27.0.0"

"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8":
version "7.0.9"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
Expand Down Expand Up @@ -2402,13 +2428,27 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df"
integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==

"@types/react-dom@>=16.9.0":
version "17.0.11"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466"
integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==
dependencies:
"@types/react" "*"

"@types/react-native@^0.64.0":
version "0.64.19"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.64.19.tgz#2b888c082ad293fa0fa6ae34c5e9457cfb38e50a"
integrity sha512-bT62QhaPvOKFGmlfURIC98ILjUDoIFrc2Bn5EzL3qciZrT91vHwkxFOkuEyQJy+DWaHCa2z3IrtIEJywkGu/Bg==
dependencies:
"@types/react" "*"

"@types/react-test-renderer@>=16.9.0":
version "17.0.1"
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3120f7d1c157fba9df0118dae20cb0297ee0e06b"
integrity sha512-3Fi2O6Zzq/f3QR9dRnlnHso9bMl7weKCviFmfF6B4LS1Uat6Hkm15k0ZAQuDz+UBq6B3+g+NM6IT2nr5QgPzCw==
dependencies:
"@types/react" "*"

"@types/react@*", "@types/react@^17.0.0":
version "17.0.37"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959"
Expand All @@ -2418,6 +2458,15 @@
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/react@>=16.9.0":
version "17.0.39"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce"
integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/retry@^0.12.0":
version "0.12.1"
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.1.tgz#d8f1c0d0dc23afad6dc16a9e993a0865774b4065"
Expand Down Expand Up @@ -2922,6 +2971,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.3.0:
dependencies:
color-convert "^2.0.1"

ansi-styles@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==

ansicolors@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
Expand Down Expand Up @@ -4991,6 +5045,11 @@ diff-sequences@^26.6.2:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==

diff-sequences@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==

diff@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
Expand Down Expand Up @@ -7559,6 +7618,16 @@ jest-diff@^26.6.2:
jest-get-type "^26.3.0"
pretty-format "^26.6.2"

jest-diff@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def"
integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==
dependencies:
chalk "^4.0.0"
diff-sequences "^27.5.1"
jest-get-type "^27.5.1"
pretty-format "^27.5.1"

jest-docblock@^26.0.0:
version "26.0.0"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5"
Expand Down Expand Up @@ -7607,6 +7676,11 @@ jest-get-type@^26.3.0:
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==

jest-get-type@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==

jest-haste-map@^26.5.2, jest-haste-map@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa"
Expand Down Expand Up @@ -7670,6 +7744,16 @@ jest-matcher-utils@^26.6.2:
jest-get-type "^26.3.0"
pretty-format "^26.6.2"

jest-matcher-utils@^27.0.0:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab"
integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==
dependencies:
chalk "^4.0.0"
jest-diff "^27.5.1"
jest-get-type "^27.5.1"
pretty-format "^27.5.1"

jest-message-util@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07"
Expand Down Expand Up @@ -10847,6 +10931,15 @@ pretty-format@^26.4.0, pretty-format@^26.5.2, pretty-format@^26.6.2:
ansi-styles "^4.0.0"
react-is "^17.0.1"

pretty-format@^27.0.0, pretty-format@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
dependencies:
ansi-regex "^5.0.1"
ansi-styles "^5.0.0"
react-is "^17.0.1"

proc-log@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-1.0.0.tgz#0d927307401f69ed79341e83a0b2c9a13395eb77"
Expand Down Expand Up @@ -11136,6 +11229,13 @@ react-dom@17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"

react-error-boundary@^3.1.0:
version "3.1.4"
resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==
dependencies:
"@babel/runtime" "^7.12.5"

react-error-overlay@^6.0.9:
version "6.0.9"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
Expand Down

0 comments on commit b75dd11

Please sign in to comment.