How to test Async Storage with Jest?
For everyone who sees this question in > 2019:
Since Nov 2020, AsyncStorage was renamed back to @react-native-async-storage/async-storage", which causes this warning to appear if you're importing it from react-native
:
Warning: Async Storage has been extracted from react-native core and will be removed in a future release.
The new module includes its own mock, so you don't have to worry about writing your own anymore.
Per the project's documentation, you can set it up in 2 different ways:
##With mocks directory
- In your project root directory, create a
__mocks__/@react-native-community
directory. - Inside that folder, create async-storage.js file.
- Inside that file, export Async Storage mock.
export default from '@react-native-async-storage/async-storage/jest/async-storage-mock'
Jest should then mock AsyncStorage
by default in all your tests. If it doesn't, try calling jest.mock(@react-native-async-storage/async-storage)
at the top of your test file.
With Jest setup file
- In your Jest config (probably in
package.json
orjest.config.js
) add the setup file's location:"jest": { "setupFiles": ["./path/to/jestSetupFile.js"]}
- Inside your setup file, set up the AsyncStorage mock:
import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';jest.mock('@react-native-community/async-storage', () => mockAsyncStorage);
If you're using TypeScript, using the 2nd option (Jest setup file) is way easier, since with the 1st one (mocks directory) it won't associate @types/react-native-community__async-storage
with the mock automatically.
May be you can try something like this:
mockStorage.js
export default class MockStorage { constructor(cache = {}) { this.storageCache = cache; } setItem = jest.fn((key, value) => { return new Promise((resolve, reject) => { return (typeof key !== 'string' || typeof value !== 'string') ? reject(new Error('key and value must be string')) : resolve(this.storageCache[key] = value); }); }); getItem = jest.fn((key) => { return new Promise((resolve) => { return this.storageCache.hasOwnProperty(key) ? resolve(this.storageCache[key]) : resolve(null); }); }); removeItem = jest.fn((key) => { return new Promise((resolve, reject) => { return this.storageCache.hasOwnProperty(key) ? resolve(delete this.storageCache[key]) : reject('No such key!'); }); }); clear = jest.fn((key) => { return new Promise((resolve, reject) => resolve(this.storageCache = {})); }); getAllKeys = jest.fn((key) => { return new Promise((resolve, reject) => resolve(Object.keys(this.storageCache))); });}
and inside your test file:
import MockStorage from './MockStorage';const storageCache = {};const AsyncStorage = new MockStorage(storageCache);jest.setMock('AsyncStorage', AsyncStorage)// ... do things
My original answer just pointed at how the author of react-native-simple-store had dealt with the mocking. I've updated my answer with my own mocking that removes Jason's hard-coded mock responses.
Jason Merino has a nice simple approach to this in https://github.com/jasonmerino/react-native-simple-store/blob/master/tests/index-test.js#L31-L64
jest.mock('react-native', () => ({AsyncStorage: { setItem: jest.fn(() => { return new Promise((resolve, reject) => { resolve(null); }); }), multiSet: jest.fn(() => { return new Promise((resolve, reject) => { resolve(null); }); }), getItem: jest.fn(() => { return new Promise((resolve, reject) => { resolve(JSON.stringify(getTestData())); }); }), multiGet: jest.fn(() => { return new Promise((resolve, reject) => { resolve(multiGetTestData()); }); }), removeItem: jest.fn(() => { return new Promise((resolve, reject) => { resolve(null); }); }), getAllKeys: jest.fn(() => { return new Promise((resolve) => { resolve(['one', 'two', 'three']); }); }) }}));
My own mock:
const items = {};jest.mock('react-native', () => ({AsyncStorage: { setItem: jest.fn((item, value) => { return new Promise((resolve, reject) => { items[item] = value; resolve(value); }); }), multiSet: jest.fn((item, value) => { return new Promise((resolve, reject) => { items[item] = value; resolve(value); }); }), getItem: jest.fn((item, value) => { return new Promise((resolve, reject) => { resolve(items[item]); }); }), multiGet: jest.fn((item) => { return new Promise((resolve, reject) => { resolve(items[item]); }); }), removeItem: jest.fn((item) => { return new Promise((resolve, reject) => { resolve(delete items[item]); }); }), getAllKeys: jest.fn((items) => { return new Promise((resolve) => { resolve(items.keys()); }); }) }}));