web-dev-qa-db-fra.com

Comment tester le stockage async avec Jest?

Je construis une application avec React Native. Je souhaite réduire la fréquence de communication avec la base de données. J'utilise donc beaucoup AsyncStorage. Cependant, la traduction entre DB et AsyncStorage laisse beaucoup à désirer. Par conséquent, je veux m'assurer que AsyncStorage dispose des données dont je dispose en exécutant des tests automatisés. Étonnamment, je n'ai trouvé aucune information sur la façon de le faire en ligne. Mes tentatives pour le faire moi-même n'ont pas abouti. 

Utilisation de Jest: 

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

Cette méthode a échoué avec une erreur: 

TypeError: RCTAsyncStorage.multiGet is not a function

Si vous supprimez le retour, il fonctionnera instantanément sans attendre la valeur et passera le test de manière incorrecte. 

J'ai eu la même erreur quand j'ai essayé de le tester avec le mot-clé wait:

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

Des suggestions sur la façon d'exécuter avec succès des assertions par rapport aux valeurs dans AsyncStorage? Je préférerais continuer à utiliser Jest, mais si cela ne peut être fait qu'avec une autre bibliothèque de tests, je suis ouvert à cela. 

14
Brian Case

Ma réponse initiale venait de montrer comment l'auteur de react-native-simple-store avait géré les moqueries. J'ai mis à jour ma réponse avec mon propre moqueur qui supprime les réponses fictives codées en dur de Jason.

Jason Merino a une approche simple et agréable à cela dans 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']);
        });
    })
  }
}));

Ma propre maquette:

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

Peut-être que vous pouvez essayer quelque chose comme ça:

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

et dans votre fichier test :

import MockStorage from './MockStorage';

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

jest.setMock('AsyncStorage', AsyncStorage)

// ... do things
21
free-soul

Je pense que jest.setMock pourrait être dans ce cas meilleur que jest.mock afin que nous puissions utiliser react-native sans aucun problème en se moquant simplement de la AsyncStorage comme celle-ci:

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