jest 테스트에서 localStorage를 어떻게 처리합니까?


144

Jest 테스트에서 "localStorage가 정의되지 않았습니다"라는 메시지가 계속 표시되지만 내 옵션은 무엇입니까? 벽돌 벽을 명 중.

답변:


141

@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 + ''올바르게 핸들 널 (null)과 정의되지 않은 값으로 세터에
menehune23

최신 jest가 사용 중이라고 생각합니다. || null그래서 내 테스트 에서을 사용 했기 때문에 테스트가 실패했습니다 not.toBeDefined(). 다시 작동하게 @Chiedo 솔루션
jcubic

나는 :)이 기술적으로 그루터기 생각 조롱 버전 여기를 참조하십시오 stackoverflow.com/questions/32911630/...
TigerBear

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

그런 다음 Jest 구성 아래 package.json에 다음 줄을 추가하십시오.

"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",


6
분명히 업데이트 중 하나이 매개 변수의 이름이 변경 지금은 "setupTestFrameworkScriptFile"라고합니다
그르 Pawlik

2
"setupFiles": [...]잘 작동합니다. 배열 옵션을 사용하면 모의 파일을 별도의 파일로 분리 할 수 ​​있습니다. 예 :"setupFiles": ["<rootDir>/__mocks__/localStorageMock.js"]
Stiggler

3
의 반환 값은 getItem특정 키에 대해 데이터가 설정되지 않은 경우 브라우저에서 반환되는 값 과 약간 다릅니다. getItem("foo")설정되지 않은 경우 호출 하면 예를 들어 null브라우저에서 반환 되지만 undefined이 모형으로 인해 테스트 중 하나가 실패했습니다. 나를위한 간단한 해결책 store[key] || nullgetItem기능 으로 돌아 오는 것이 었습니다
Ben Broadley

다음과 같은 작업을 수행하면 작동하지 않습니다localStorage['test'] = '123'; localStorage.getItem('test')
rob

3
jest.fn () 값은 모의 함수 또는 스파이 여야합니다. 어떤 아이디어?
Paul Fitzgerald

55

create-react-app를 사용하는 경우 문서에 설명되어있는 더 간단하고 간단한 솔루션이 있습니다 .

src/setupTests.js이것을 작성 하여 넣습니다.

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

아래의 코멘트에서 Tom Mertz의 공헌 :

그런 다음 다음과 같은 작업을 수행하여 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! 테스트에서 어떻게 사용하는지 예를 들어 주시겠습니까?
Dimo

무슨 소리 야? 테스트에서 아무것도 초기화 할 필요가 없으며 localStorage코드에서 사용 하는 것을 자동으로 조롱 합니다. (만약 당신이 create-react-app자연스럽게 제공하는 모든 자동 스크립트 를 사용한다면 )
c4k

그런 다음 호출되었는지 확인하려는 경우 테스트 와 같은 expect(localStorage.getItem).toBeCalledWith('token')또는 expect(localStorage.getItem.mock.calls.length).toBe(1)내부에서 무언가를 수행하여 localStorageMock의 기능이 사용 되는지 테스트 할 수 있습니다. 확인 facebook.github.io/jest/docs/en/mock-functions.html
톰 메츠에게

10
이를 위해 오류가 발생합니다-jest.fn () 값은 모의 함수 또는 스파이이어야합니다. 어떤 아이디어?
Paul Fitzgerald

3
여러 테스트를 사용하는 경우 문제가되지 localStorage않습니까? "스 필러"가 다른 테스트로 들어 가지 않도록 각 테스트 후 스파이를 재설정하고 싶지 않습니까?
Brandon Sturgeon

43

현재 (Oct '19) localStorage는 평소와 같이 jest가 조롱하거나 감시 할 수 없으며 create-react-app 문서에 설명되어 있습니다. 이것은 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();

실제로 그것은 spyOn과 함께 나를 위해 작동합니다. setItem 함수를 재정의 할 필요가 없습니다jest.spyOn(window.localStorage.__proto__, 'setItem');
Yohan Dahmani

예, 두 가지를 대안으로 나열했습니다. 두 가지를 모두 수행 할 필요는 없습니다.
Bastian Stein

나는 setItem을 재정의하지 않고 의미했습니다 😉
Yohan Dahmani

나는 이해하지 못한다고 생각합니다. 당신은 명확히 할 수 있습니까?
Bastian Stein

1
아 예. 나는 당신이 첫 번째 줄이나 두 번째 줄을 사용할 수 있다고 말하고있었습니다. 그것들은 같은 일을하는 대안입니다. 개인 취향이 무엇이든 :) 혼란에 대해 죄송합니다.
Bastian Stein


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

아이디어를 추가해 준 Alexis Tyler에게 감사의 말을 전합니다 removeItem: developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
Dmitriy

널 (null) 및 정의되지 않은 필요가 "널 (null)"및 "정의되지 않은"(리터럴 문자열)이되어야 함
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

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

이 코드를 setupTests에 삽입하면 정상적으로 작동합니다.

typesctipt가있는 프로젝트에서 테스트했습니다.


나를 위해 Object.defineProperty가 트릭을 만들었습니다. 직접 개체 할당이 작동하지 않았습니다. 감사!
Vicens Fayos 2014

4

불행히도 여기서 찾은 솔루션은 효과가 없었습니다.

그래서 Jest GitHub 문제를 보고이 스레드를 발견했습니다.

가장 많이지지 된 솔루션은 다음과 같습니다.

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

// or

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

내 테스트도 window없거나 Storage정의 되지 않았습니다 . 아마도 내가 사용하는 Jest의 이전 버전 일 수 있습니다.
Antrikshy

3

@ ck4가 제안한 문서 는 jest 에서 사용 localStorage하는 것에 대한 명확한 설명을 제공 합니다. 그러나 모의 함수가 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 = {}
};

스 니펫은 여기 에서 참조 됩니다


2

Typescript가있는 프로젝트 에서이 문제를 해결하기 위해 다른 답변을 생략했습니다. 다음과 같이 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]
    }
}

그런 다음 전역 로컬 스토리지 변수에 직접 액세스하는 대신 앱의 로컬 스토리지에 대한 모든 액세스에 사용하는 LocalStorageWrapper 클래스를 만들었습니다. 테스트를 위해 랩퍼에 모의를 쉽게 설정할 수있게했습니다.


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

조롱을 피하기 위해이 방법을 사용할 수 있습니다.

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

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

그리고 jest 설정에서 :

"setupFiles":["localStorage.js"]

무엇이든 물어보세요.


1

다음 솔루션은보다 엄격한 TypeScript, ESLint, TSLint 및 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()

global.localStorage를 업데이트하는 방법에 대한 HT / https://stackoverflow.com/a/51583401/101290


1

Typescript에서 동일한 작업을 수행하려면 다음을 수행하십시오.

다음 내용으로 파일을 설정하십시오.

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

그런 다음 Jest 구성 아래 package.json에 다음 줄을 추가하십시오.

"setupTestFrameworkScriptFile":"PATH_TO_YOUR_FILE",

또는 로컬 스토리지를 모방하려는 테스트 케이스에서이 파일을 가져옵니다.


0

이것은 나를 위해 일했다.

delete global.localStorage;
global.localStorage = {
getItem: () => 
 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.