みなさん、
誰かがjsdomでlocalStorage / sessionStorage APIの実装に取り組んでいますか?
よろしく、
アルバロ
残念ながら、これらはES2015プロキシなしでは非常に困難です:(。getItem / setItem /etc。を機能させることはできますが、プロパティの変更を正しく適用することは実際には不可能です。
少なくともメモリ内のエクスペリエンス、つまり、sessionStorageと同様の動作をするlocalStorageがあると便利です。
それはそれほど複雑ではないはずですよね?
いいえ、APIを十分にエミュレートできないためです。 単純なユースケース(つまり、getItem / setItemのみを使用)の場合は機能する可能性がありますが、プロパティに直接アクセスするとすぐに、実装が機能しなくなります。
@Sebmaster :別のパッケージの単体テストで使用するストレージインターフェイス用の簡単なシムを作成しました。
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が呼び出された場合に常にゲッターを作成することである程度エミュレートできますが、プロキシなしではその逆(オブジェクトに任意のプロパティを設定)をサポートすることはできません。
そうです、プロパティアクセスによるキーの設定に関する主な問題は、実際のインターフェイスのように、値を文字列に正しく強制できないことだと思います。
はい、それはローカルストレージの非常に重要な側面です。 これには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
上で説明したように、実際のローカルストレージの動作の一部がまだ欠落していることに気付くと思います。
リンクされたソリューションは優れたポリフィルになりますが、jsdomの実装としては十分忠実ではないと思います
@mnahkies正直なところ、ポリフィルは何もないよりはましです(これがあなたが今持っているものです)。 それを入れて、99%の人がとにかく決してヒットしない制限に関するいくつかのドキュメントを追加する必要があります。
最後のコメントに+ 1 、MDNの例では、ストレージへのアクセサーとしてsetItem
とgetItem
を使用しています。 したがって、私たちが本当に欠けているのは一般的なユースケースと見なすことができます。
今のところ、私はjasmine.createSpy
それを解決します(私はJasmineで作業しているので、他のスパイライブラリでもそれを行うことができます)
@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がリリースされ、それとともに...プロキシ。
@Sebmaster 、名前付きのゲッター/セッター/削除者が存在する場合にプロキシを生成できるように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で遊んでいましたが、うまく機能します。 しかし、私は逆に取り組んでいlocalStorage
とsessionStorage
です。 私はそれを適切にテストする方法の同じ問題にまったく同じ問題に走りました、そしてあなたのポリフィルはうまく働きます。 君たちありがとう! デフォルトでjsdomが付属していると便利です。
これに対するwebidl2jsのサポートが実施されました。 人々がこれを引き受けたいのであれば、最近着陸したDOMStringList実装(データセット用)を研究することをお勧めします。
今のところ、すべてをメモリ内に保持できますが、最終的には、必要に応じてディスクに保存する方法を提供する必要があります。 (人々はそれを望んでいますか?)
これを実装したいと思います。 あなたは私に問題を割り当てることができます。
キーが保存されていない場合、 localStorage.getItem()
はundefined
ではなくnull
を返すことになっているため、このモックはより適切に機能します。
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
を渡すと失敗しますが、パラメーターとして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これはよくモックします。 私のテストのいくつかを修正します。 ありがとう。