jest test fails after installing react-native-async-storage
Asked Answered
N

7

12

In my react native project, I have recently installed node module react-native-async-storage as I received warnings about the native package from 'react-native' being deprecated and moved out to an individual module.

After installing the @react-native-community/async-storage my jest test is failing.

first with following error: unexpected token at position 0

in file:

persistence.js

import AsyncStorage from '@react-native-community/async-storage';

storeData = async ({ key, value }) => {
  try {
    await AsyncStorage.setItem(key, value);
  } catch (error) {
    // Error saving data
  }
}

retrieveData = async (key) => {
  try {
    const value = await AsyncStorage.getItem(key);
    if (value !== null) {
      // Our data is fetched successfully
      return value;
    }
  } catch (error) {
    // Error retrieving data
  }
}

module.exports = {
  storeData,
  retrieveData
}

So I assume this is related to some babel configuration, since i encountered something similar last time i installed a package from the @react-native-community

So, to the transformIgnorePatterns in my package.json I added following:

  "jest": {
    "preset": "react-native",
    "transformIgnorePatterns": [
      "node_modules/(?!react-native|@react-native-community/async-storage|native-base-shoutem-theme|@shoutem/animation|@shoutem/ui|tcomb-form-native)"
    ]
  }

But now I'm getting a new error. @RNCommunity/AsyncStorage: NativeModule.RCTAsyncStorage is null.

I'm pasting the screenshot to show my project dir so that you can get an idea about which config files a have available to mess with. enter image description here

As I can see most related topic are about mocking the asyncStorage function I've tried to do so, without any luck. I added following to my one and only tests file:

import MockAsyncStorage from 'mock-async-storage';

beforeAll(() => { 
  const mockImpl = new MockAsyncStorage()
  jest.mock('AsyncStorage', () => mockImpl)
  snapshot = renderer.create(<App />);
})

afterAll(() => {
  jest.unmock('AsyncStorage')
});

Still no cigar. I have tried adding a setupFilesAfterEnv.js with configurations as other answer suggests, also didn't do the trick.

Nata answered 29/3, 2019 at 13:49 Comment(0)
N
17

I found a way of mocking the @react-native-community/async-storage

in root of my project, (same dir as __test__ dir), I created a dir structure like this:

__mocks__/@react-native-community/async-storage/index.js

in index.js I mocked the following functions:

let cache = {};
export default {
  setItem: (key, value) => {
    return new Promise((resolve, reject) => {
      return (typeof key !== 'string' || typeof value !== 'string')
        ? reject(new Error('key and value must be string'))
        : resolve(cache[key] = value);
    });
  },
  getItem: (key, value) => {
    return new Promise((resolve) => {
      return cache.hasOwnProperty(key)
        ? resolve(cache[key])
        : resolve(null);
    });
  },
  removeItem: (key) => {
    return new Promise((resolve, reject) => {
      return cache.hasOwnProperty(key)
        ? resolve(delete cache[key])
        : reject('No such key!');
    });
  },
  clear: (key) => {
    return new Promise((resolve, reject) => resolve(cache = {}));
  },

  getAllKeys: (key) => {
    return new Promise((resolve, reject) => resolve(Object.keys(cache)));
  },
}

in my test file i added this:

beforeAll(() => { 
  jest.mock('@react-native-community/async-storage');
})

Screenshot of dir structure: enter image description here

This did the trick. I found inspiration here: https://github.com/react-native-community/react-native-async-storage/issues/39

Nata answered 1/4, 2019 at 8:55 Comment(0)
M
28

async-storage has published instructions on how to solve this issue.

Here is a shorten version:

  1. In your project root directory, create __mocks__/@react-native-community directory.
  2. Inside that folder, create a async-storage.js file.
  3. Copy paste the following inside that file:
export default from '@react-native-community/async-storage/jest/async-storage-mock'
  1. Enjoy!

I hope it can help others.

Mizzle answered 7/6, 2019 at 15:13 Comment(5)
Link is 404 unfortunatelyMessenger
@typewriter Thanks. I have updated the linkMizzle
It's __mocks__/ with two underscores, not one. The instructions might have updated since you posted this, of course. But just fyi @FrancoisNadeauEstriol
@MattFletcher Thanks. I don't believe the docs changed, tt was a mark-up issue with what I wrote.Mizzle
Looks like the documentation and the code are not at the same page.Lisette
N
17

I found a way of mocking the @react-native-community/async-storage

in root of my project, (same dir as __test__ dir), I created a dir structure like this:

__mocks__/@react-native-community/async-storage/index.js

in index.js I mocked the following functions:

let cache = {};
export default {
  setItem: (key, value) => {
    return new Promise((resolve, reject) => {
      return (typeof key !== 'string' || typeof value !== 'string')
        ? reject(new Error('key and value must be string'))
        : resolve(cache[key] = value);
    });
  },
  getItem: (key, value) => {
    return new Promise((resolve) => {
      return cache.hasOwnProperty(key)
        ? resolve(cache[key])
        : resolve(null);
    });
  },
  removeItem: (key) => {
    return new Promise((resolve, reject) => {
      return cache.hasOwnProperty(key)
        ? resolve(delete cache[key])
        : reject('No such key!');
    });
  },
  clear: (key) => {
    return new Promise((resolve, reject) => resolve(cache = {}));
  },

  getAllKeys: (key) => {
    return new Promise((resolve, reject) => resolve(Object.keys(cache)));
  },
}

in my test file i added this:

beforeAll(() => { 
  jest.mock('@react-native-community/async-storage');
})

Screenshot of dir structure: enter image description here

This did the trick. I found inspiration here: https://github.com/react-native-community/react-native-async-storage/issues/39

Nata answered 1/4, 2019 at 8:55 Comment(0)
V
7

You can add this to your test file.

jest.mock("@react-native-community/async-storage", () =>
  require("@react-native-community/async-storage/jest/async-storage-mock"),
);

For example

import React from "react";

jest.mock("@react-native-community/async-storage", () =>
  require("@react-native-community/async-storage/jest/async-storage-mock"),
);

describe("Example test", () => {
  it("should work", () => {
    ...
  });
});
Vitta answered 26/11, 2020 at 11:23 Comment(0)
T
6

You need to add this piece of code to your setupTestFrameworkScriptFile

    import { NativeModules } from 'react-native';
NativeModules.RNCAsyncStorage = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  removeItem: jest.fn(),
  mergeItem: jest.fn(),
  clear: jest.fn(),
  getAllKeys: jest.fn(),
  flushGetRequests: jest.fn(),
  multiGet: jest.fn(),
  multiSet: jest.fn(),
  multiRemove: jest.fn(),
  multiMerge: jest.fn(),
};
Thyratron answered 29/3, 2019 at 16:5 Comment(5)
Hey! :) Which file is my setupTestFrameworkScriptFile? Where is it located ?Nata
See this link jestjs.io/docs/en/configuration, if you are now on jest 24 it should be setupFilesAfterEnvThyratron
Did not work, but the error I am seeing is about @RNCommunity/AsyncStorage: NativeModule.RCTAsyncStorage is null. which sounds a little different from the RNCAsyncStorage that you are referring to. My module is imported like this: import AsyncStorage from '@react-native-community/async-storage';Nata
Well, if you check the source code, you can see the error comes from: const {NativeModules} = require('react-native'); const RCTAsyncStorage = NativeModules.RNC_AsyncSQLiteDBStorage || NativeModules.RNCAsyncStorage; if (!RCTAsyncStorage) { throw new Error(`@RNCommunity/AsyncStorage: NativeModule.RCTAsyncStorage is null. So mocking any of those two in your test should do it. github.com/react-native-community/react-native-async-storage/…Thyratron
Well, good point. But I confirmed that I was on jst 24+ and added the setupFilesAfterEnv to the root, as the doc specifies. Didn't seem to run on npm test or yarn test. So In the end I went back to the mock method. which at last worked.Nata
D
2

Edit Ignore my answer, just do this instead: https://github.com/react-native-community/async-storage/blob/LEGACY/docs/Jest-integration.md

Thanks @Krizzo

Another Jest version based on @Rasmus Puls's but with jest functions - to be added to your jest mocks file.

jest.mock('@react-native-community/async-storage', () => { 
  let cache = {};
  return {
    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(cache[key] = value);
      });
    }),
    getItem: jest.fn((key, value) => {
      return new Promise((resolve) => {
        return cache.hasOwnProperty(key)
          ? resolve(cache[key])
          : resolve(null);
      });
    }),
    removeItem: jest.fn((key) => {
      return new Promise((resolve, reject) => {
        return cache.hasOwnProperty(key)
          ? resolve(delete cache[key])
          : reject('No such key!');
      });
    }),
    clear: jest.fn((key) => {
      return new Promise((resolve, reject) => resolve(cache = {}));
    }),
    getAllKeys: jest.fn((key) => {
      return new Promise((resolve, reject) => resolve(Object.keys(cache)));
    }),
  }
});
Dogberry answered 20/8, 2019 at 11:13 Comment(1)
Hey, any reason why not to use one provided in the Async Storage's repo?Gonocyte
L
2

Looking at the documentation by the team, (from the answer provided by Francois Nadeau) I was able to change the lines for 'mocking with jest setup.js file' option to below and resolved the exact same issue.

import mockAsyncStorage from '@react-native-community/async-storage/jest/async-storage-mock';
jest.mock('@react-native-community/async-storage', () => mockAsyncStorage);

Please note that the paths are changed.

Lisette answered 29/6, 2021 at 21:6 Comment(0)
D
0

I had to alter the published solution:

  1. In your project root directory, create __mocks__/@react-native-async-storage directory.
  2. Inside that folder, create async-storage.js file.
  3. Inside that file, paste the following:
export * as default from '@react-native-async-storage/async-storage/jest/async-storage-mock'

Note: I was getting a ts1005 compile error that complained about a missing semicolon when I used the original solution (i.e. export default from '@...). I'm on Typescript 4.9, so that may be causing problems for me with the original solution.

Desquamate answered 24/3, 2023 at 19:14 Comment(1)
for me it worked: export default '@react-native-async-storage/async-storage/jest/async-storage-mock';Colorblind

© 2022 - 2025 — McMap. All rights reserved.