web-dev-qa-db-fra.com

Comment est-ce que je traite avec Local Storage dans les tests de plaisanterie

Je continue à avoir "le stockage local n'est pas défini" dans les tests Jest, ce qui est logique mais quelles sont mes options? Frapper les murs de briques.

90
Chiedo

Excellente solution de @chiedo

Cependant, nous utilisons la syntaxe ES2015 et j’ai pensé que c’était un peu plus propre de l’écrire de cette façon.

class LocalStorageMock {
  constructor() {
    this.store = {};
  }

  clear() {
    this.store = {};
  }

  getItem(key) {
    return this.store[key] || null;
  }

  setItem(key, value) {
    this.store[key] = value.toString();
  }

  removeItem(key) {
    delete this.store[key];
  }
};

global.localStorage = new LocalStorageMock;

109
nickcan

Vous l'avez compris avec l'aide de: https://groups.google.com/forum/#!topic/jestjs/9EPhuNWVYTg

Configurez un fichier avec le contenu suivant:

var localStorageMock = (function() {
  var store = {};
  return {
    getItem: function(key) {
      return store[key];
    },
    setItem: function(key, value) {
      store[key] = value.toString();
    },
    clear: function() {
      store = {};
    },
    removeItem: function(key) {
      delete store[key];
    }
  };
})();
Object.defineProperty(window, 'localStorage', { value: localStorageMock });

Ensuite, vous ajoutez la ligne suivante à votre package.json sous vos configurations Jest

"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",

73
Chiedo

Si vous utilisez create-react-app, il existe une solution simple et expliquée dans la documentation .

Créez src/setupTests.js et mettez ceci dedans:

const localStorageMock = {
  getItem: jest.fn(),
  setItem: jest.fn(),
  clear: jest.fn()
};
global.localStorage = localStorageMock;

Tom Mertz contribution dans un commentaire ci-dessous:

Vous pouvez ensuite tester que les fonctions de votre localStorageMock sont utilisées en effectuant quelque chose comme:

expect(localStorage.getItem).toBeCalledWith('token')
// or
expect(localStorage.getItem.mock.calls.length).toBe(1)

à l'intérieur de vos tests si vous voulez vous assurer qu'il s'appelle. Découvrez https://facebook.github.io/jest/docs/en/mock-functions.html } _

40
c4k

ou vous prenez juste un faux paquet comme ceci:

https://www.npmjs.com/package/jest-localstorage-mock

il gère non seulement la fonctionnalité de stockage, mais vous permet également de vérifier si le magasin a été appelé.

12
Aligertor

Une meilleure alternative qui gère les valeurs undefined (elle n'a pas toString()) et renvoie null si la valeur n'existe pas. Testé avec react v15, redux et redux-auth-wrapper 

class LocalStorageMock {
  constructor() {
    this.store = {}
  }

  clear() {
    this.store = {}
  }

  getItem(key) {
    return this.store[key] || null
  }

  setItem(key, value) {
    this.store[key] = value
  }

  removeItem(key) {
    delete this.store[key]
  }
}

global.localStorage = new LocalStorageMock
11
Dmitriy

Actuellement (janvier 19), le stockage local ne peut pas être moqué ni épié comme le ferait une blague, comme vous le feriez habituellement, et comme indiqué dans la documentation de création-réaction-application. Cela est dû aux modifications apportées dans jsdom. Vous pouvez lire à ce sujet ici https://github.com/facebook/jest/issues/6798 et ici https://github.com/jsdom/jsdom/issues/2318 .

Pour contourner le problème, vous pouvez également espionner le prototype:

// does not work:
jest.spyOn(localStorage, "setItem");
localStorage.setItem = jest.fn();

// works:
jest.spyOn(window.localStorage.__proto__, 'setItem');
window.localStorage.__proto__.setItem = jest.fn();

// assertions as usual:
expect(localStorage.setItem).toHaveBeenCalled();
6
Bastian Stein

Comme @ ck4 a suggéré documentation explique clairement l'utilisation de localStorage en plaisanterie. Cependant, les fonctions fictives n’exécutaient aucune des méthodes localStorage

Vous trouverez ci-dessous un exemple détaillé du composant my react qui utilise des méthodes abstraites pour écrire et lire des données,

//file: storage.js
const key = 'ABC';
export function readFromStore (){
    return JSON.parse(localStorage.getItem(key));
}
export function saveToStore (value) {
    localStorage.setItem(key, JSON.stringify(value));
}

export default { readFromStore, saveToStore };

Erreur:

TypeError: _setupLocalStorage2.default.setItem is not a function

Réparer:
Ajouter ci-dessous une fonction fictive pour plaisanterie (chemin: .jest/mocks/setUpStore.js

let mockStorage = {};

module.exports = window.localStorage = {
  setItem: (key, val) => Object.assign(mockStorage, {[key]: val}),
  getItem: (key) => mockStorage[key],
  clear: () => mockStorage = {}
};

Snippet est référencé depuis ici

1
Mad-D
    describe('getToken', () => {
    const Auth = new AuthService();
    const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Ik1yIEpvc2VwaCIsImlkIjoiNWQwYjk1Mzg2NTVhOTQ0ZjA0NjE5ZTA5IiwiZW1haWwiOiJ0cmV2X2pvc0Bob3RtYWlsLmNvbSIsInByb2ZpbGVVc2VybmFtZSI6Ii9tcmpvc2VwaCIsInByb2ZpbGVJbWFnZSI6Ii9Eb3Nlbi10LUdpci1sb29rLWN1dGUtbnVrZWNhdDMxNnMtMzExNzAwNDYtMTI4MC04MDAuanBnIiwiaWF0IjoxNTYyMzE4NDA0LCJleHAiOjE1OTM4NzYwMDR9.YwU15SqHMh1nO51eSa0YsOK-YLlaCx6ijceOKhZfQZc';
    beforeEach(() => {
        global.localStorage = jest.fn().mockImplementation(() => {
            return {
                getItem: jest.fn().mockReturnValue(token)
            }
        });
    });
    it('should get the token from localStorage', () => {

        const result  = Auth.getToken();
        expect(result).toEqual(token);

    });
});

Créer une maquette et l'ajouter à l'objet global

1
Trevor Joseph

Riffé quelques autres réponses ici pour le résoudre pour un projet avec TypeScript. J'ai créé un LocalStorageMock comme ceci:

export class LocalStorageMock {

    private store = {}

    clear() {
        this.store = {}
    }

    getItem(key: string) {
        return this.store[key] || null
    }

    setItem(key: string, value: string) {
        this.store[key] = value
    }

    removeItem(key: string) {
        delete this.store[key]
    }
}

Ensuite, j'ai créé une classe LocalStorageWrapper que j'utilise pour tous les accès au stockage local de l'application au lieu d'accéder directement à la variable de stockage local global. Facilite la mise en place de la maquette dans l'emballage pour les tests.

1
CorayThan

J'ai trouvé cette solution de github

var localStorageMock = (function() {
  var store = {};

  return {
    getItem: function(key) {
        return store[key] || null;
    },
    setItem: function(key, value) {
        store[key] = value.toString();
    },
    clear: function() {
        store = {};
    }
  }; 
})();

Object.defineProperty(window, 'localStorage', {
 value: localStorageMock
});

Vous pouvez insérer ce code dans vos setupTests et cela devrait fonctionner correctement.

Je l'ai testé dans un projet avec typesctipt.

1
Carlos Huamani

Si vous recherchez une maquette et non un talon, voici la solution que j'utilise:

export const localStorageMock = {
   getItem: jest.fn().mockImplementation(key => localStorageItems[key]),
   setItem: jest.fn().mockImplementation((key, value) => {
       localStorageItems[key] = value;
   }),
   clear: jest.fn().mockImplementation(() => {
       localStorageItems = {};
   }),
   removeItem: jest.fn().mockImplementation((key) => {
       localStorageItems[key] = undefined;
   }),
};

export let localStorageItems = {}; // eslint-disable-line import/no-mutable-exports

J'exporte les éléments de stockage pour une initialisation facile. C'EST À DIRE. Je peux facilement le définir sur un objet

Dans les versions les plus récentes de Jest + JSDom, il n'est pas possible de le définir, mais le stockage local est déjà disponible et vous pouvez l'espionner comme suit:

const setItemSpy = jest.spyOn(Object.getPrototypeOf(window.localStorage), 'setItem');
0
TigerBear

Vous devez espionner le prototype de l'objet Storage.

const spy = jest.spyOn(Storage.prototype, 'getItem');

Et après cela pour l'affirmer comme:

expect(spy).toHaveBeenCalledWith(somevalue);
0
user3568791

La solution suivante est compatible pour les tests avec une configuration plus stricte de TypeScript, ESLint, TSLint et Prettier: { "proseWrap": "always", "semi": false, "singleQuote": true, "trailingComma": "es5" }:

class LocalStorageMock {
  public store: {
    [key: string]: string
  }
  constructor() {
    this.store = {}
  }

  public clear() {
    this.store = {}
  }

  public getItem(key: string) {
    return this.store[key] || undefined
  }

  public setItem(key: string, value: string) {
    this.store[key] = value.toString()
  }

  public removeItem(key: string) {
    delete this.store[key]
  }
}
/* tslint:disable-next-line:no-any */
;(global as any).localStorage = new LocalStorageMock()

HT/ https://stackoverflow.com/a/51583401/101290 pour savoir comment mettre à jour global.localStorage

0
Beau Smith