I am struggling getting my jest spec to work with AsyncStorage
. I followed the guide on Jest integration with Async Storage and used the guidance for setting up the mocks directory. This makes my project structure look like so…
.
My async-storage.js
has the following contents…
export * from "@react-native-async-storage/async-storage/jest/async-storage-mock";
The spec I am trying to test is checking that I redirect the user to a certain page based on the values retrieved from storage. This is how the spec is set up (please excuse that it is the nicest looking right now – just trying to get the tests to work for now!)…
import { render, waitFor } from "@testing-library/react-native";
import AsyncStorage from "@react-native-async-storage/async-storage/jest/async-storage-mock";
import { useRouter } from "expo-router";
import Index from "@/src/app/index";
jest.mock("expo-router", () => ({
useNavigation: jest.fn(),
useFocusEffect: jest.fn().mockImplementation((callback) => callback()),
useRouter: jest.fn()
}));
describe("Index page", () => {
const mockRouter = {
replace: jest.fn()
}
;(useRouter as jest.Mock).mockReturnValue(mockRouter)
async function asyncOperationOnAsyncStorage(firstTime: string){
await AsyncStorage.setItem("firstTime", firstTime)
await AsyncStorage.getItem("firstTime")
}
it("renders successfully", async () => {
render(<Index />);
});
it("redirects to 'First Launch' page when the user opens the app for the first time", async () => {
await asyncOperationOnAsyncStorage("");
render(<Index />);
await waitFor(() => {
expect(mockRouter.replace).toHaveBeenCalledWith("/first-launch");
})
})
it("redirects to 'Login' page when it is not the user's first time using the app", async () => {
await asyncOperationOnAsyncStorage("DONE");
render(<Index />);
await waitFor(() => {
expect(mockRouter.replace).toHaveBeenCalledWith("/login");
})
})
The index page is coded up like so…
import { View, Text } from 'react-native';
import { useFocusEffect, useRouter } from "expo-router";
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useCallback } from 'react';
export default function Index() {
const router = useRouter();
const handleRedirect = async () => {
try {
const firstTime = await AsyncStorage.getItem("firstTime");
if (firstTime !== "DONE") {
router.replace("/first-launch");
else {
router.replace("/login");
}
} catch (error) {
console.log("Cannot retrieve data from storage", error);
router.replace("/first-launch");
}
}
useFocusEffect(
useCallback(() => {
handleRedirect()
}, [handleRedirect])
);
return (
<View>
<Text>Redirecting...</Text>
</View>
);
}
I thought I had my async set up right, but whenever I run the tests, I get this error in the console…
Cannot retrieve data from storage TypeError: Cannot read properties of undefined (reading 'getItem')
This implies that the spec fails when performing async’s getItem
when running my index
‘s handleRedirect()
function. This error does not occur when I run the app, so I assume I must not have set up my Jest and Async Storage integration right – but I have no clue where I went wrong!
Thank you in advance for any help!
The problem seems to be resolved now. The fix was to change my async-storage.js
to…
import AsyncStorage from "@react-native-async-storage/async-storage/jest/async-storage-mock";
export default AsyncStorage;
…And then change my import for AsyncStorage
on my index
spec file to be import AsyncStorage from "@react-native-async-storage/async-storage/jest/async-storage-mock";