์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ,
๋๊ตฐ๊ฐ jsdom์์ localStorage/sessionStorage API๋ฅผ ๊ตฌํํ๋ ์์ ์ ํ๊ณ ์์ต๋๊น?
๋ฌธ์ ์ธ์ฌ,
์๋ฐ๋ก
๋ถํํ๋ ES2015 ํ๋ก์ ์์ด๋ ๋งค์ฐ ์ด๋ ต์ต๋๋ค. (. getItem/setItem/etc.๊ฐ ์๋ํ๋๋ก ํ ์ ์์ง๋ง ์์ฑ ์์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉํ๋ ๊ฒ์ ์ค์ ๋ก ๋ถ๊ฐ๋ฅํฉ๋๋ค.
์ ์ด๋ ์ธ๋ฉ๋ชจ๋ฆฌ ๊ฒฝํ, ์ฆ sessionStorage์ ์ ์ฌํ ๋์์ ๊ฐ๋ localStorage๊ฐ ์์ผ๋ฉด ์ข์ ๊ฒ์
๋๋ค.
๋ ๋ณต์กํด์ผ ํฉ๋๊น?
์๋์. API๋ฅผ ์ถฉ๋ถํ ์๋ฎฌ๋ ์ดํธํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ฐ๋จํ ์ฌ์ฉ ์ฌ๋ก(์: getItem/setItem๋ง ์ฌ์ฉ)์ ๊ฒฝ์ฐ ์๋ํ ์ ์์ง๋ง ์์ฑ์ ์ง์ ์ก์ธ์คํ๋ ์ฆ์ ๊ตฌํ์ด ์ค๋จ๋ฉ๋๋ค.
@Sebmaster : ๋ณ๋์ ํจํค์ง์ ๋ํ ๋จ์ ํ ์คํธ์ ์ฌ์ฉํ๊ธฐ ์ํด ์คํ ๋ฆฌ์ง ์ธํฐํ์ด์ค์ ๋ํ ๊ฐ๋จํ shim์ ์์ฑํ์ต๋๋ค.
https://github.com/mnahkies/node-storage-shim
ํ์ฌ ์ผ์์ ์ธ ์๋ฃจ์ ์ด๋ฉฐ ์คํ ๋ฆฌ์ง ์ธํฐํ์ด์ค์ ๋ฉ์๋ ์ด๋ฆ๊ณผ ์ถฉ๋ํ๋ ํค ์ค์ ์ ๊ธ์งํฉ๋๋ค. ๋ํ ํ์ฌ ์ฌ์์ ์ด๋ฒคํธ ๋ฐ์ ๋ถ๋ถ์ ๊ตฌํํ์ง ์์ต๋๋ค.
์ค์ localStorage๋ setItem์ ์ฌ์ฉํ์ฌ ์ด๋ฌํ ํค๋ฅผ ์ค์ ํ ์ ์์ง๋ง ์์ฑ ์ก์ธ์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธฐ๋ฅ ์ ์๊ฐ ๋ ์๊ฐ๊ณ ์ผ๋จ ์ค์ ๋๋ฉด ์์ฑ ์ก์ธ์ค๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ํค์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ด๋ฌํ ์ ํ ์ฌํญ์ ์ ์ธํ๊ณ ๋ ๊ฝค ์ถฉ์คํ ๊ตฌํ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
https://github.com/mnahkies/node-storage-shim/blob/master/test.js
API์ ์ด๋ค ์ธก๋ฉด์ ์ถฉ๋ถํ ์๋ฎฌ๋ ์ดํธํ ์ ์๋์ง ์์ธํ ์ค๋ช ํด ์ฃผ์๊ฒ ์ต๋๊น?
๋ด๊ฐ ๋งํ ์ ์๋ ํ ํ์ฌ ์๋ฎฌ๋ ์ดํธํ ์ ์๋ ์ฃผ์ ์ฌํญ์ ์์ฑ ์ค์ ์ ๋ํ ์๋ต์ผ๋ก ๋ฐ์ํ๋ ์คํ ๋ฆฌ์ง ์ด๋ฒคํธ์ ๋๋ค.
์ธ๊ธ๋ ์ฃผ์ ์ฌํญ์ผ๋ก ์ถฉ๋ถํ ์๋ฃ๋์๋ค๊ณ ์๊ฐํ๋ค๋ฉด jsdom๊ณผ ํตํฉํ ์ ์๊ฒ ๋์ด ๊ธฐ์ฉ๋๋ค.
API์ ์ด๋ค ์ธก๋ฉด์ ์ถฉ๋ถํ ์๋ฎฌ๋ ์ดํธํ ์ ์๋์ง ์์ธํ ์ค๋ช ํด ์ฃผ์๊ฒ ์ต๋๊น?
localStorage๋ ๋ค์๊ณผ ๊ฐ์ด ์ธํฐํ์ด์ค์์ ์ง์ ์์ฑ ์ด๋ฆ ์ค์ ์ ์ง์ํฉ๋๋ค.
localStorage.myKey = "myVal";
localStorage.getItem('myKey') // 'myVal'
localStorage.setItem('otherKey', 'val')
localStorage.otherKey // 'val'
setItem์ด ํธ์ถ๋๋ฉด ํญ์ getter๋ฅผ ์์ฑํ์ฌ ์ด๋ ์ ๋ ์๋ฎฌ๋ ์ดํธํ ์ ์์ง๋ง ํ๋ก์ ์์ด๋ ๋ฐ๋ ๋ฐฉํฅ(๊ฐ์ฒด์ ์์ ์์ฑ ์ค์ )์ ์ง์ํ ์ ์์ต๋๋ค.
๋ง์ต๋๋ค. ์์ฑ ์ก์ธ์ค๋ก ํค๋ฅผ ์ค์ ํ๋ ๊ฒ๊ณผ ๊ด๋ จ๋ ์ฃผ์ ๋ฌธ์ ๋ ์ค์ ์ธํฐํ์ด์ค์ฒ๋ผ ๊ฐ์ ๋ฌธ์์ด๋ก ์ฌ๋ฐ๋ฅด๊ฒ ๊ฐ์ ๋ณํํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
๋ค, ์ด๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ๋งค์ฐ ์ค์ํ ์ธก๋ฉด์ ๋๋ค. ์ด๋ฅผ ์ํด ES6 ํ๋ก์๊ฐ ํ์ํฉ๋๋ค. v8์ ์์ง ์ด๋ฅผ ๊ตฌํํ์ง ์์์ต๋๋ค(microsoft์ mozilla๋ ์ด๋ฏธ ๊ฐ์ง๊ณ ์์ต๋๋ค!)
์ฐ๋ฆฌ๋ jsdom์ ์ฌ๋ฌ ์์น์์ ๋์ผํ ๋ก๋ ๋ธ๋ก์ ์น๊ณ ์์ต๋๋ค.
์ด๊ฒ์ด ์๋ํ์ง ์๋ ์ด์ ๋ฅผ ์ดํดํ ์ ์์ต๋๋ค.
var localStorage = {
getItem: function (key) {
return this[key];
},
setItem: function (key, value) {
this[key] = value;
}
};
localStorage.setItem('foo', 'bar');
localStorage.bar = 'foo'
assert(localStorage.foo === 'bar')
assert(localStorage.getItem('bar') === 'foo')
๋ด๊ฐ ๋ฌด์์ ๋์น๊ณ ์์ต๋๊น?
์์ฑ ์ก์ธ์ค๋ฅผ ์ฌ์ฉํ์ฌ ํญ๋ชฉ์ ์ค์ ํ ๋ ์ค์ localStorage๋ ํญ์ ๊ฐ์ ๋ฌธ์์ด๋ก ๊ฐ์ ๋ณํํฉ๋๋ค.
์:
localStorage.foo = 35
assert(typeof localStorage.foo === "string")
localStorage.foo = {my: 'object'}
assert(localStorage.foo === "[object Object]")
์ด๊ฒ์ ES6 ํ๋ก์ ์์ด๋ ๋ถ๊ฐ๋ฅํ๋ฉฐ localStorage์ ์ค์ํ ํน์ฑ์ ๋๋ค.
์ ๊ฒ ์ด์. ๋น๋ก ๋น์ ์ด ๊ทธ ์์น๋ฅผ ๋น์ ์๊ฒํ๊ณ ์๋ค๋ฉด ;)
๋ ์ค์ํ ๊ฒ์ ๊ฐ์ฒด๋ก ๊ทธ๋ ๊ฒ ํ๋ ๊ฒฝ์ฐ jsdom์ ์ํด ๋ง์คํน๋ ๋ค์ ๋ธ๋ผ์ฐ์ ์์ ๋ฐ์ํ๋ ๋ฒ๊ทธ์ผ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
+1
+1
์๋ง๋ ์ด์ ๊ฐ์ ๊ฒ์ด https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage ?
์์์ ์ค๋ช ํ ๊ฒ์ฒ๋ผ ์ค์ ๋ก์ปฌ ์ ์ฅ์๊ฐ ๊ฐ์ง๊ณ ์๋ ์ผ๋ถ ๋์์ ์ฌ์ ํ ๋์น๊ณ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋ ๊ฒ์ ๋๋ค.
์ฐ๊ฒฐ๋ ์๋ฃจ์ ์ ์ข์ ํด๋ฆฌํ์ ๋ง๋ค์ง๋ง jsdom์ ๋ํ ์ถฉ์คํ ๊ตฌํ์ด ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ง ์์ต๋๋ค.
@mnahkies ์์งํ, polyfill์ ์๋ ๊ฒ๋ณด๋ค ๋ซ์ต๋๋ค(์ง๊ธ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ ๋๋ค). ๋น์ ์ ๊ทธ๊ฒ์ ๋ฃ๊ณ 99%์ ์ฌ๋๋ค์ด ์ด์จ๋ ๋ถ๋ชํ์ง ์์ ํ๊ณ์ ๋ํ ๋ช ๊ฐ์ง ๋ฌธ์๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
๋ง์ง๋ง ์ฃผ์์ +1, MDN์ ์ ๋ setItem
๋ฐ getItem
๋ฅผ ์ ์ฅ์์ ๋ํ ์ ๊ทผ์๋ก ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๊ฐ ์ค์ ๋ก ๋์น๊ณ ์๋ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ก ๊ฐ์ฃผํ ์ ์์ต๋๋ค.
์ง๊ธ์ jasmine.createSpy
ํด๊ฒฐํฉ๋๋ค.
@justinmchase ์ ์๋ฃจ์ ์ ํ ์คํธ์ ์ ํฉํฉ๋๋ค. sessionStorage๋ ์ถ๊ฐํ๊ณ ์ถ์ ์ ์์ต๋๋ค.
var jsdom = require('jsdom').jsdom;
document = jsdom('hello world');
window = document.defaultView;
navigator = window.navigator;
window.localStorage = window.sessionStorage = {
getItem: function (key) {
return this[key];
},
setItem: function (key, value) {
this[key] = value;
}
};
FAIK ์ด๊ฒ์ ์ ์กฐ๋กฑํฉ๋๋ค. ๋ด ํ ์คํธ ์ค ์ผ๋ถ๋ฅผ ์์ ํฉ๋๋ค. ๊ฐ์ฌ ํด์.
๋๊ตฐ๊ฐ ์ค์๋ก ์์ฑ ์ก์ธ์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋ก์ปฌ ์ ์ฅ์์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๋ฏธ๋ฌํ ๋ฒ๊ทธ๋ฅผ ์์ฑํ ๋๊น์ง ํ ์คํธ๋ฅผ ์์ ํฉ๋๋ค.
์ ์๊ฐ์๋ ํ ์คํธ์์ ๋ฉ๋ชจ๋ฆฌ ์๋ฃจ์ ์ผ๋ก ์๋ํ ์ ์๋ ์ค์ ๊ฐ๋ฅํ ์คํ ๋ฆฌ์ง ๋ฐฑ์๋๋ก ์คํ ๋ฆฌ์ง๋ฅผ ์ถ์ํํ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ ๊ฒ์ด ๋ ๋์ ๊ฒ์ ๋๋ค.
๋ํ ๋์ค์ ํ์ํ ๊ฒฝ์ฐ ์ํธํ, ์์ถ, ์บ์ฑ์ ํตํ ์ฐ๊ธฐ ๋ฑ๊ณผ ๊ฐ์ ๋ณต์กํ ์์ ์ ๋ ์ฝ๊ฒ ์ํํ ์ ์์ต๋๋ค.
๋๊ฐ๋๋ค!!!
Node.js v6์ด ๋์๊ณ , ๊ทธ๊ฒ๊ณผ ํจ๊ป... PROXIES.
@Sebmaster , ๋ช ๋ช ๋ getters/setters/deleters๊ฐ ์์ ๋ ํ๋ก์๋ฅผ ์์ฑํ ์ ์๋๋ก webidl2js๋ฅผ ์ ๋ฐ์ดํธํ์๊ฒ ์ต๋๊น? NamedNodeMap์ด๋ NodeList ๋ฑ๊ณผ ๊ฐ์ ๋ค๋ฅธ ๊ฒ๋ค์ ๋ํด ๊ฑฑ์ ํ๊ธฐ ์ ์ ๋จผ์ ์ด ์์ฒญ์ ๋์์ผ๋ก ํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ด๊ฒ์ ํ๋ฅญํ๊ณ ๋ ๋ฆฝ์ ์ด๋ฉฐ ํต์ฌ ํ๋ฆฌ๋ฏธํฐ๋ธ์ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค.
https://html.spec.whatwg.org/multipage/webstorage.html#storage -2์๋ ์ง์ํด์ผ ํ๋ IDL์ด ์์ต๋๋ค. ๊ฐ ๋ฐฉ๋ฒ์ ๋จ์ํ ํ๋ก์์ get ๋์ ๋๋ฆฌ์๋ฅผ impl์ getItem ๋ฑ์ผ๋ก ๋ง๋๋ ๊ฒ์ ๋๋ค.
+1
node-localstorage๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
var LocalStorage = require('node-localstorage').LocalStorage;
global.localStorage = new LocalStorage('./build/localStorageTemp');
global.document = jsdom('');
global.window = document.defaultView;
global.window.localStorage = global.localStorage;
@adjavaherian @justinmchase ๋๋ react-jwt-auth ์ react-jwt-auth-redux ๋ชจ๋์์ ํ
์คํธํ๋ ๋ฐ ์ฌ์ฉํ๋ jsdom์ ๊ฐ์ง๊ณ ๋๊ณ ์์๊ณ ํ๋ฅญํ๊ฒ ์๋ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋๋ ๋ํ ๋ํ ๊ฐ๋ฐ์ ์ํ enverse - ํ๊ฒฝ ๊ฒ์ฌ์ ๋ํด ์ผํ๊ณ ์์ต๋๋ค. ์ํ ์ค ํ๋๋ localStorage
๋ฐ sessionStorage
์
๋๋ค. ๋๋ ๊ทธ๊ฒ์ ์ฌ๋ฐ๋ฅด๊ฒ ํ
์คํธํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋์ผํ ๋ฌธ์ ์ ๋ํด ์ ํํ ์คํํ์ผ๋ฉฐ ๊ทํ์ polyfil์ ํ๋ฅญํ๊ฒ ์๋ํฉ๋๋ค. ๊ฐ์ฌํฉ๋๋ค! ๊ธฐ๋ณธ์ ์ผ๋ก jsdom์ด ํจ๊ป ์ ๊ณต๋๋ค๋ฉด ์ข์ ๊ฒ์
๋๋ค.
์ด์ ๋ํ webidl2js ์ง์์ด ์ด์ ์ ์๋ฆฌ์ ์์ต๋๋ค. ์ฌ๋๋ค์ด ์ด๊ฒ์ ๋ฐ์๋ค์ด๊ณ ์ถ๋ค๋ฉด ์ต๊ทผ์ ๋์จ DOMStringList ๊ตฌํ(๋ฐ์ดํฐ ์ธํธ์ฉ)์ ์ฐ๊ตฌํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
ํ์ฌ๋ก์๋ ๋ชจ๋ ๊ฒ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ณด๊ดํ ์ ์์ง๋ง ๊ฒฐ๊ตญ ์ฌ๋๋ค์ด ์ํ ๊ฒฝ์ฐ ๋์คํฌ์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํด์ผ ํฉ๋๋ค. (์ฌ๋๋ค์ด ๊ทธ๊ฑธ ์ํด?)
์ด๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ๋ ธ๋ ฅํ๊ณ ์ถ์ต๋๋ค. ๋์๊ฒ ๋ฌธ์ ๋ฅผ ํ ๋นํ ์ ์์ต๋๋ค.
ํค๊ฐ ์ ์ฅ๋์ด ์์ง ์์ ๊ฒฝ์ฐ, ๋๋ฌธ์์ด ๋ชจํ์ ์ ์๋ localStorage.getItem()
๋ฐํํ๋๋ก๋์ด null
ํ์ง undefined
:
const jsdom = require('jsdom');
// setup the simplest document possible
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>');;
// get the window object out of the document
const win = doc.defaultView;
win.localStorage = win.sessionStorage = {
getItem: function(key) {
const value = this[key];
return typeof value === 'undefined' ? null : value;
},
setItem: function (key, value) {
this[key] = value;
},
removeItem: function(key) {
return delete this[key]
}
};
// set globals for mocha that make access to document and window feel
// natural in the test environment
global.document = doc;
global.window = win;
์ ๊ด๋ จ์ด ์์ต๋๊น? ์๋ ์ค์ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ ์ ์๋ํฉ๋๋ค. json.parse()
undefined
๋ฅผ ์ธ์๋ก ์ ๋ฌํ๋ฉด json.parse()
๊ฐ ์คํจํ์ง๋ง ๋งค๊ฐ๋ณ์๋ก null
ํ๋ฉด ์ ์๋ํฉ๋๋ค.
let users = JSON.parse(localStorage.getItem('users')) || [];
@simoami win.localStorage = win.sessionStorage = { ... }
์ฐ๊ฒฐ๋๋ ํ ๋น์ ์กฐ์ฌํ์ธ์. ๋ ๋ณ์์ ํ ๋น๋ ๋์ผํ ๊ฐ์ฒด ์ฐธ์กฐ์ด๋ฏ๋ก ๋ ์ค ํ๋์ get/set ํจ์๋ฅผ ํธ์ถํ๋ฉด ๋์ผํ ๊ธฐ๋ณธ ๊ฐ์ฒด์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด localStorage.set('foo', 'bar')
ํธ์ถํ๋ฉด sessionStorage.get('foo')
๊ฐ ์๋ํฉ๋๋ค. ๊ฐ๋จํ ํ
์คํธ์์๋ ๊ด์ฐฎ์ ์ ์์ง๋ง ๋ณ๋์ ์ ์ฅ ๊ณต๊ฐ์ด ํ์ํ ๋ชจ๋ ๊ฒ์ ์๋ง์ด ๋ฉ๋๋ค.
https://gist.github.com/rkurbatov/17468b2ade459a7498c8209800287a03 - ์ด ํด๋ฆฌํ์ ๋ก์ปฌ/์ธ์ ์คํ ๋ฆฌ์ง ๋ชจ๋์ ์ฌ์ฉํฉ๋๋ค. @capaj์ https://github.com/capaj/localstorage-polyfill ์ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค.
๋์ค์ ์ด ์ค๋ ๋๋ฅผ ์ฐ์ฐํ ๋ฐ๊ฒฌํ ์ฌ๋๋ค์ ์ต๊ทผ jsdom ๊ฐ์ ํ์ window._localStorage
๋ฅผ ์์ ์ ๋ชจ์ ์ ์ฅ์๋ก ์ค์ ํด์ผ ํฉ๋๋ค.
ํผ๋๋ฐฑ์ผ๋ก ์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ผ๋ก ์ธ๊ธ๋ ๊ธฐ๋ณธ localStorage ์ด๋ฒคํธ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ jsdom์ ๋ณ๋ ฌ๋ก ์ฌ์ฉํ๊ณ localStorage๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ ์ฌ๋์๊ฒ๋ node-localstorage
๋ฑ์ ๊ฑฐ์ ์ธ๋ชจ๊ฐ ์์ผ๋ฏ๋ก ๋ฐํด๋ฅผ ๋ค์ ๋ฐ๋ช
ํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ณ๋ ฌ ์ฌ์ฉ์ ์ํด ์ค๊ณ๋์ง ์์์ต๋๋ค. for(var key in localStorage)
๋๋ Object.keys(localStorage)
๋ฑ๊ณผ ๊ฐ์ ๊ธฐ๋ณธ ๊ธฐ๋ฅ๋ ์๋ํ์ง ์์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
@justinmchase ์ ์๋ฃจ์ ์ ํ ์คํธ์ ์ ํฉํฉ๋๋ค. sessionStorage๋ ์ถ๊ฐํ๊ณ ์ถ์ ์ ์์ต๋๋ค.
FAIK ์ด๊ฒ์ ์ ์กฐ๋กฑํฉ๋๋ค. ๋ด ํ ์คํธ ์ค ์ผ๋ถ๋ฅผ ์์ ํฉ๋๋ค. ๊ฐ์ฌ ํด์.