Как протестировать Async Storage с помощью Jest?

Я создаю приложение с React Native. Я хочу свести к минимуму, как часто я общаюсь с базой данных, поэтому я активно использую AsyncStorage. Там много места для ошибок в переводе между БД и AsyncStorage. Поэтому я хочу убедиться, что AsyncStorage имеет данные, которые, как я полагаю, он делает, запуская автоматические тесты против него. Удивительно, но я не нашел никакой информации о том, как это сделать в Интернете. Мои попытки сделать это сами по себе не сработали.

Использование Jest:

it("can read asyncstorage", () => {
return AsyncStorage.getItem('foo').then(foo => {
  expect(foo).not.toBe("");
});  });

Этот метод завершился с ошибкой:

TypeError: RCTAsyncStorage.multiGet is not a function

Удаление возврата приведет к его немедленному запуску, не дожидаясь значения и неправильно пройти тест.

Я получил одну и ту же ошибку, когда пытался проверить ее с помощью ключевого слова wait:

it('can read asyncstorage', async () => {
this.foo = "";
await AsyncStorage.getItem('foo').then(foo => {
    this.foo = foo;
});
expect(foo).not.toBe(""); });

Любые предложения по успешному запуску утверждений против значений в AsyncStorage? Я предпочел бы продолжать использовать Jest, но если это можно сделать только с помощью некоторой альтернативной библиотеки тестирования, я открыт для этого.

Ответы

Ответ 1

Мой первоначальный ответ просто указал на то, как автор реакции-родной-простой-магазин занимался насмешкой. Я обновил свой ответ своим собственным издевательством, который удаляет отпечатки Джейсона с жестким кодированием.

Джейсон Мерино имеет простой простой подход к этому в 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']);
        });
    })
  }
}));

Мой собственный макет:

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

Ответ 2

Может быть, вы можете попробовать что-то вроде этого:

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

и внутри вашего тестового файла:

import MockStorage from './MockStorage';

const storageCache = {};
const AsyncStorage = new MockStorage(storageCache);

jest.setMock('AsyncStorage', AsyncStorage)

// ... do things

Ответ 3

Я думаю, что jest.setMock может быть в этом случае лучше, чем jest.mock поэтому мы можем использовать react-native без проблем просто насмешливых AsyncStorage так:

jest.setMock('AsyncStorage', {
  getItem: jest.fn(
    item =>
      new Promise((resolve, reject) => {
        resolve({ myMockObjectToReturn: 'myMockObjectToReturn' });
      })
  ),
});

Ответ 4

Для всех, кто видит этот вопрос в> 2019:

С февраля 2019 года AsyncStorage был перемещен в @ act -native-community/async-storage, что приводит к появлению этого предупреждения, если вы импортируете его из react-native:

Warning: Async Storage has been extracted from react-native core and will be removed in a future release.

Новый модуль включает в себя собственный макет, так что вам не нужно больше беспокоиться о написании своего собственного.

В соответствии с проектной документацией вы можете настроить его двумя различными способами:

С каталогом издевательств

  • В корневом каталоге вашего проекта создайте __mocks__/@react-native-community.
  • Внутри этой папки создайте файл async-storage.js.
  • Внутри этого файла экспортируйте макет Async Storage.
    export default from '@react-native-community/async-storage/jest/async-storage-mock'
    
    Jest должен по умолчанию издеваться над AsyncStorage во всех ваших тестах. Если это не так, попробуйте вызвать jest.mock(@react-native-community/async-storage) в верхней части тестового файла.

С установочным файлом Jest

  • В вашей конфигурации Jest (вероятно, в package.json или jest.config.js) добавьте расположение файла установки:
    "jest": {
      "setupFiles": ["./path/to/jestSetupFile.js"]
    }
    
  • Внутри вашего установочного файла настройте макет AsyncStorage:

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

Если вы используете TypeScript, использовать 2-й вариант (установочный файл Jest) гораздо проще, поскольку с 1-м вариантом (каталог mocks) он не будет автоматически связывать @types/react-native-community__async-storage с mock.

Ответ 5

Для кого-то еще, чтобы получить здесь, asyncStorage также нуждается в обратном вызове, некоторые библиотеки используют это