जेस्ट परीक्षणों में मैं लोकलस्टोरेज से कैसे निपटूं?


144

मुझे जेस्ट परीक्षणों में "लोकलस्टेज को परिभाषित नहीं किया गया है" मिल रहा है जो समझ में आता है लेकिन मेरे विकल्प क्या हैं? ईंटों की दीवार से टकराना।

जवाबों:


142

@Chiedo से महान समाधान

हालाँकि, हम ES2015 सिंटैक्स का उपयोग करते हैं और मुझे लगा कि इसे इस तरह से लिखना थोड़ा साफ है।

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;

8
संभवत: value + ''अशक्त और अपरिभाषित मूल्यों को सही ढंग से संभालने के लिए सेटर में क्या करना चाहिए
menehune23

मुझे लगता है कि लेटेस्ट जेस्ट सिर्फ || nullइसलिए इस्तेमाल कर रहा था कि मेरा टेस्ट फेल हो रहा था, क्योंकि मेरे टेस्ट में मैं इस्तेमाल कर रहा था not.toBeDefined()। @ चेहेदो समाधान इसे फिर से काम करते हैं
jcubic

मुझे लगता है कि यह तकनीकी रूप से एक ठूंठ है :)
नकली

100

इसकी मदद से यह पता लगाया: https://groups.google.com/forum/# .topic/jestjs/9EPhuNWVYTg

निम्नलिखित सामग्री के साथ एक फ़ाइल सेटअप करें:

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

फिर आप अपने पैकेज को अपने जेस्ट कॉन्फिगरेशन के तहत अपने पैकेज में जोड़ें

"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",


6
जाहिरा तौर पर अद्यतन में से एक के साथ इस पैरामीटर का नाम बदल गया है और अब यह कहा जाता है "setupTestFrameworkScriptFile"
ग्रेगॉर्ज़ Pawlik

2
"setupFiles": [...]साथ ही काम करता है। सरणी विकल्प के साथ, मोज़ेक को अलग-अलग फ़ाइलों में अलग करने की अनुमति देता है। जैसे:"setupFiles": ["<rootDir>/__mocks__/localStorageMock.js"]
स्टिगलर

3
getItemयदि कोई डेटा किसी विशिष्ट कुंजी के विरुद्ध सेट नहीं है, तो ब्राउजर द्वारा लौटाया जाने वाला मूल्य थोड़ा अलग है। कॉलिंग getItem("foo")जब इसका सेट नहीं होता है तो उदाहरण के लिए nullएक ब्राउज़र में वापस आ जाएगा , लेकिन undefinedइस नकली द्वारा - यह मेरे परीक्षणों में से एक को विफल करने का कारण बन रहा था। मेरे लिए सरल समाधान समारोह store[key] || nullमें लौटना थाgetItem
बेन ब्रॉडले

यदि आप कुछ ऐसा करते हैं तो यह काम नहीं करता हैlocalStorage['test'] = '123'; localStorage.getItem('test')
लूटना

3
मुझे निम्नलिखित त्रुटि मिल रही है - jest.fn () मान एक नकली फ़ंक्शन या जासूस होना चाहिए। कोई विचार?
पॉल फिजराल्ड़

55

अगर create-react-app का उपयोग करते हैं, तो प्रलेखन में सरल और सरल समाधान बताया गया है ।

इसमें बनाएं src/setupTests.jsऔर डालें:

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

नीचे टिप्पणी में टॉम मेर्ट्ज़ योगदान:

फिर आप यह परीक्षण कर सकते हैं कि आपके लोकलस्टोर्समॉक के कार्यों का उपयोग कुछ ऐसा करके किया जाता है

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

अपने परीक्षणों के अंदर यदि आप यह सुनिश्चित करना चाहते हैं कि इसे बुलाया गया था। की जाँच करें https://facebook.github.io/jest/docs/en/mock-functions.html


हाय c4k! क्या आप कृपया एक उदाहरण दे सकते हैं कि आप अपने परीक्षणों में इसका उपयोग कैसे करेंगे?
डिमो

आपका क्या अर्थ है ? आपको अपने परीक्षणों में कुछ भी इनिशियलाइज़ करने की ज़रूरत नहीं है, यह सिर्फ localStorageआपके कोड में आपके द्वारा उपयोग किए जाने वाले स्वचालित रूप से मॉक करता है । (यदि आप उपयोग करते हैं create-react-appऔर सभी स्वचालित स्क्रिप्ट यह स्वाभाविक रूप से प्रदान करता है)
c4k

फिर आप यह परीक्षण कर सकते हैं कि आपके लोकलस्टोरीजॉक के कार्यों का उपयोग आपके परीक्षण के समान expect(localStorage.getItem).toBeCalledWith('token')या expect(localStorage.getItem.mock.calls.length).toBe(1)अंदर कुछ करके किया जाता है यदि आप यह सुनिश्चित करना चाहते थे कि इसे बुलाया गया था। की जाँच करें facebook.github.io/jest/docs/en/mock-functions.html
टॉम Mertz

10
इसके लिए मुझे एक त्रुटि मिल रही है - jest.fn () मान एक नकली फ़ंक्शन या जासूस होना चाहिए। कोई विचार?
पॉल फिजराल्ड़

3
यदि आपके पास उपयोग किए जाने वाले कई परीक्षण हैं, तो क्या इससे समस्याएं नहीं होंगी localStorage? क्या आप अन्य परीक्षणों में "स्पिलओवर" को रोकने के लिए प्रत्येक परीक्षण के बाद जासूसों को रीसेट नहीं करना चाहेंगे?
ब्रैंडन स्टर्जन 19

43

वर्तमान में (अक्टूबर '19) लोकलस्टोरेज को मजाक में नहीं कहा जा सकता है और न ही उस पर जासूसी की जा सकती है जैसा कि आप आमतौर पर करते हैं, और जैसा कि क्रिएट-रिएक्शन-ऐप डॉक्स में बताया गया है। यह jsdom में किए गए परिवर्तनों के कारण है। आप इसके बारे में जेस्ट और jsdom इश्यू ट्रैकर्स में पढ़ सकते हैं ।

वर्कअराउंड के रूप में, आप इसके बजाय प्रोटोटाइप की जासूसी कर सकते हैं:

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

वास्तव में यह मेरे लिए सिर्फ स्पाईऑन के साथ काम करता है, सेटमाइट फ़ंक्शन को ओवरराइड करने की कोई आवश्यकता नहीं हैjest.spyOn(window.localStorage.__proto__, 'setItem');
योहन दहमानी

हां, मैंने दोनों को विकल्प के रूप में सूचीबद्ध किया है, दोनों को करने की आवश्यकता नहीं है।
बैस्टियन स्टीन

मेरा मतलब था कि सेटिम के ओवरराइड के बिना भी Y
योहन दाहमणि

मुझे नहीं लगता कि मैं समझता हूं। क्या आप कृपया स्पष्ट कर सकते हैं?
बास्तियन स्टीन

1
आह येस। मैं कह रहा था कि आप पहली पंक्ति या दूसरी पंक्ति का उपयोग कर सकते हैं। वे विकल्प हैं जो एक ही काम करते हैं। जो भी आपकी व्यक्तिगत पसंद है :) भ्रम के बारे में क्षमा करें।
बस्तियन स्टीन

14

या आप सिर्फ इस तरह एक नकली पैकेज लेते हैं:

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

यह न केवल भंडारण की कार्यक्षमता को संभालता है, बल्कि आपको परीक्षण करने की भी अनुमति देता है कि क्या स्टोर वास्तव में कहा गया था।


13

एक बेहतर विकल्प जो undefinedमानों को संभालता है (इसमें नहीं है toString()) और nullयदि मान मौजूद नहीं है तो रिटर्न करता है। reactV15 के साथ यह परीक्षण किया , reduxऔर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

जोड़ने के लिए विचार के लिए एलेक्सिस टायलर को धन्यवाद removeItem: developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
दिमित्री

"अशक्त" और "अपरिभाषित" (शाब्दिक तार)
menehune23

6

यदि आप एक मॉक की तलाश कर रहे हैं और स्टब नहीं है, तो इसका समाधान मैं उपयोग कर रहा हूं:

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

मैं आसान आरंभ के लिए भंडारण वस्तुओं का निर्यात करता हूं। IE मैं आसानी से एक वस्तु पर सेट कर सकते हैं

Jest + JSDom के नए संस्करणों में इसे सेट करना संभव नहीं है, लेकिन लोकलस्टोरेज पहले से ही उपलब्ध है और आप इसे इस तरह से जासूसी कर सकते हैं:

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

5

मुझे यह समाधान गितुब से मिला

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

आप इस कोड को अपने setupTests में सम्मिलित कर सकते हैं और इसे ठीक काम करना चाहिए।

मैंने इसे एक प्रोजेक्ट में टाइपसीटिप के साथ परीक्षण किया।


मेरे लिए Object.defineProperty ने ट्रिक बनाई। प्रत्यक्ष वस्तु असाइनमेंट काम नहीं किया। धन्यवाद!
विसेंस फेयोस

4

दुर्भाग्य से, जो समाधान मैंने यहां पाया है वह मेरे लिए काम नहीं किया।

इसलिए मैं जेस्ट गिटहब मुद्दों को देख रहा था और इस सूत्र को पाया

सबसे अधिक उत्कीर्ण समाधान ये थे:

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

// or

Storage.prototype.getItem = jest.fn(() => 'bla');

मेरे परीक्षण नहीं है window या Storageतो परिभाषित या । शायद यह जेस्ट का पुराना संस्करण है जिसका मैं उपयोग कर रहा हूं।
अंतीक्षरी

3

जैसा कि @ ck4 ने सुझाव दिया है कि दस्तावेज़localStorage में jest का उपयोग करने के लिए स्पष्ट स्पष्टीकरण है । हालाँकि, मॉक फ़ंक्शंस किसी भी निष्पादन में विफल रहे थेlocalStorage तरीके ।

नीचे मेरी प्रतिक्रिया घटक का विस्तृत उदाहरण है जो डेटा लिखने और पढ़ने के लिए अमूर्त तरीकों का उपयोग करता है,

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

त्रुटि:

TypeError: _setupLocalStorage2.default.setItem is not a function

फिक्स:
हंसी के लिए नकली समारोह नीचे जोड़ें (पथ: .jest/mocks/setUpStore.js)

let mockStorage = {};

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

स्निपेट को यहाँ से संदर्भित किया गया है


3

आप इस दृष्टिकोण का उपयोग कर सकते हैं, मॉकिंग से बचने के लिए।

Storage.prototype.getItem = jest.fn(() => expectedPayload);

2

टाइपस्क्रिप्ट के साथ एक परियोजना के लिए इसे हल करने के लिए यहां कुछ अन्य उत्तरों को हटा दिया गया। मैंने इस तरह से एक LocalStorageMock बनाया:

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

फिर मैंने एक लोकलस्टोरीजवापर क्लास बनाई, जिसका उपयोग मैं सीधे ग्लोबल स्टोरेज वेरिएबल को एक्सेस करने के बजाय ऐप में लोकल स्टोरेज तक पहुंच के लिए करता हूं। परीक्षणों के लिए आवरण में नकली सेट करना आसान बना दिया।


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

    });
});

एक नकली बनाएं और इसे globalऑब्जेक्ट में जोड़ें


2

आपको इस स्निपेट्स के साथ स्थानीय भंडारण का मजाक उड़ाना होगा

// localStorage.js

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

और जंग विन्यास में:

"setupFiles":["localStorage.js"]

बेझिझक कुछ भी पूछ सकते हैं।


1

निम्नलिखित समाधान सख्त टाइपस्क्रिप्ट, ESLint, TSLint और Prettier config के परीक्षण के लिए संगत है { "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 कैसे global.localStorage अद्यतन करने के लिए


1

टाइपस्क्रिप्ट में समान करने के लिए, निम्नलिखित करें:

निम्नलिखित सामग्री के साथ एक फ़ाइल सेटअप करें:

let localStorageMock = (function() {
  let store = new Map()
  return {

    getItem(key: string):string {
      return store.get(key);
    },

    setItem: function(key: string, value: string) {
      store.set(key, value);
    },

    clear: function() {
      store = new Map();
    },

    removeItem: function(key: string) {
        store.delete(key)
    }
  };
})();
Object.defineProperty(window, 'localStorage', { value: localStorageMock });

फिर आप अपने पैकेज को अपने जेस्ट कॉन्फिगरेशन के तहत अपने पैकेज में जोड़ें

"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",

या आप इस फ़ाइल को अपने परीक्षण के मामले में आयात करते हैं जहाँ आप लोकलस्टोर का मजाक बनाना चाहते हैं।


0

इसने मेरे लिए काम किया,

delete global.localStorage;
global.localStorage = {
getItem: () => 
 }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.