安装react-native-async-storage后,Jest测试失败

12
在我的React Native项目中,我最近安装了节点模块react-native-async-storage,因为我收到了关于' react-native '的本地包已被弃用并移动到单独模块的警告。 安装了@react-native-community/async-storage后,我的jest测试失败了。 首先是以下错误:在位置0处出现意外标记;在文件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
}

我认为这与某些 Babel 配置有关,因为上次我从 @react-native-community 安装包时也遇到过类似的情况。

因此,在我的 package.json 中的 transformIgnorePatterns 中添加以下内容:

  "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)"
    ]
  }

但现在我遇到了一个新的错误。@RNCommunity/AsyncStorage: NativeModule.RCTAsyncStorage is null.

我贴了一张截图展示我的项目目录,这样你就能知道我可以使用哪些配置文件来解决问题了。 enter image description here

我发现大部分相关主题都是关于模拟asyncStorage函数,我试着这样做,但没有成功。我在唯一的测试文件中添加了以下内容:

import MockAsyncStorage from 'mock-async-storage';

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

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

依然没有成功。我尝试了添加一个setupFilesAfterEnv.js文件,并按照其他答案的建议进行配置,但也没有起作用。

Translated:

还是没有成功。我尝试添加了一个setupFilesAfterEnv.js文件,像其他答案建议的那样进行配置,但这并没有解决问题。

7个回答

28

async-storage已经发布了关于如何解决该问题的说明

以下是简化版本:

  1. 在项目根目录下创建__mocks__/@react-native-community文件夹。
  2. 在该文件夹内创建一个async-storage.js文件。
  3. 将以下内容复制粘贴到该文件中:
export default from '@react-native-community/async-storage/jest/async-storage-mock'
  1. 享受吧!

希望它能帮助他人。


2
链接不幸是404。 - Typewriter
@typewriter 谢谢。我已更新[链接](https://react-native-community.github.io/async-storage/docs/advanced/jest) - Francois Nadeau
1
这是双下划线 __mocks__/,不是单下划线。当然,指令可能会在你发布此内容后更新。但只是提供信息。@FrancoisNadeau - Matt Fletcher
1
@MattFletcher 谢谢。我不认为文档有变化,这只是我写的标记问题。 - Francois Nadeau
看起来文档和代码不在同一页上。 - AleX_

17

我找到了一种嘲弄@react-native-community/async-storage的方法。

在我的项目根目录中(与__test__目录相同),我创建了以下目录结构:

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

在index.js中,我嘲弄了以下函数:

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)));
  },
}

在我的测试文件中,我添加了这个:

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

目录结构截图: enter image description here

这个解决了问题。我从这里得到了灵感:https://github.com/react-native-community/react-native-async-storage/issues/39


7
你可以将此添加到你的测试文件中。
jest.mock("@react-native-community/async-storage", () =>
  require("@react-native-community/async-storage/jest/async-storage-mock"),
);

例如

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", () => {
    ...
  });
});

6

您需要将以下这段代码添加到您的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(),
};

嘿! :) 我的 setupTestFrameworkScriptFile 文件在哪里?它位于哪里? - Rasmus Puls
如果您现在使用的是 Jest 24,可以查看此链接 https://jestjs.io/docs/en/configuration 来设置 setupFilesAfterEnv。 - tbergq
没能成功,但是我看到的错误是 @RNCommunity/AsyncStorage: NativeModule.RCTAsyncStorage is null. 这个错误听起来跟你所说的 RNCAsyncStorage 有点不一样。我的模块是这样导入的:import AsyncStorage from '@react-native-community/async-storage'; - Rasmus Puls
1
如果您检查源代码,可以看到错误来自于: const {NativeModules} = require('react-native');const RCTAsyncStorage = NativeModules.RNC_AsyncSQLiteDBStorage || NativeModules.RNCAsyncStorage;if (!RCTAsyncStorage) { throw new Error(`@RNCommunity/AsyncStorage: NativeModule.RCTAsyncStorage is null.因此,在测试中模拟其中任何一个即可。https://github.com/react-native-community/react-native-async-storage/blob/master/lib/AsyncStorage.js - tbergq
好的,说得有道理。但是我确认了我正在使用jst 24+版本,并按照文档指定的方式将setupFilesAfterEnv添加到根目录中。但似乎在npm testyarn test上没有运行。所以最终我回到了__mock__方法,这最终起作用了。 - Rasmus Puls

2

查看团队的文档(来自Francois Nadeau提供的答案),我能够将“使用jest setup.js文件进行模拟”选项的行更改为以下内容,并解决了完全相同的问题。

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

请注意路径已更改。

2

编辑 忽略我的回答,只需按照以下步骤操作: https://github.com/react-native-community/async-storage/blob/LEGACY/docs/Jest-integration.md

感谢@Krizzo

另一个基于@Rasmus Puls的Jest版本,但带有jest函数-应添加到您的jest模拟文件中。

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)));
    }),
  }
});

1
嘿,不使用Async Storage存储库中提供的存储引擎有什么原因吗? - Krzysztof Borowy

0

我必须修改已发布解决方案

  1. 在您的项目根目录中创建__mocks__/@react-native-async-storage目录。
  2. 在该文件夹内创建async-storage.js文件。
  3. 在该文件中粘贴以下内容:
export * as default from '@react-native-async-storage/async-storage/jest/async-storage-mock'

注意:当我使用原始解决方案(即export default from '@...)时,我遇到了一个ts1005编译错误,它抱怨缺少分号。我使用的是Typescript 4.9,所以这可能会导致原始解决方案出现问题。

对我来说它起作用了:export default '@react-native-async-storage/async-storage/jest/async-storage-mock'; - Fábio BC Souza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接