JavaScriptのmocking window.location.href
-
24-10-2019 - |
質問
window.location.hrefを使用する関数の単体テストがいくつかあります - 理想的ではありません。実際にテストランナーページを実際にURLに移動させることなく、この値をock笑する可能性があるかどうか疑問に思っています。
window.location.href = "http://www.website.com?varName=foo";
expect(actions.paramToVar(test_Data)).toEqual("bar");
ユニットテストフレームワークにジャスミンを使用しています。
解決
ローカルコンテキストをシミュレートし、独自のバージョンを作成する必要があります window
と window.location
オブジェクト
var localContext = {
"window":{
location:{
href: "http://www.website.com?varName=foo"
}
}
}
// simulated context
with(localContext){
console.log(window.location.href);
// http://www.website.com?varName=foo
}
//actual context
console.log(window.location.href);
// http://www.actual.page.url/...
使用する場合 with
次に、すべての変数(を含む window
!)まず、コンテキストオブジェクトから見られ、実際のコンテキストから存在しない場合は見られます。
他のヒント
これを行う最良の方法は、どこかにヘルパー関数を作成し、それをock笑することです。
var mynamespace = mynamespace || {};
mynamespace.util = (function() {
function getWindowLocationHRef() {
return window.location.href;
}
return {
getWindowLocationHRef: getWindowLocationHRef
}
})();
Window.location.hrefを直接使用する代わりに、コードで直接使用するだけで、代わりにこれを使用します。次に、mocked値を返す必要があるときはいつでもこの方法を置き換えることができます。
mynamespace.util.getWindowLocationHRef = function() {
return "http://mockhost/mockingpath"
};
クエリ文字列パラメーターなどのウィンドウの場所の特定の部分が必要な場合は、そのためのヘルパーメソッドを作成し、メインコードから解析を締め出します。ジャスミンなどの一部のフレームワークには、関数をモックして目的の値を返すことができるだけでなく、次のように呼ばれることを確認できます。
spyOn(mynamespace.util, 'getQueryStringParameterByName').andReturn("desc");
//...
expect(mynamespace.util.getQueryStringParameterByName).toHaveBeenCalledWith("sort");
ここで以前の投稿ですでに示唆されている2つのソリューションを提案します。
アクセスの周りに関数を作成し、生産コードでそれを使用し、テストでジャスミンを使用してスタブを作成します。
var actions = { getCurrentURL: function () { return window.location.href; }, paramToVar: function (testData) { ... var url = getCurrentURL(); ... } }; // Test var urlSpy = spyOn(actions, "getCurrentURL").andReturn("http://my/fake?param"); expect(actions.paramToVar(test_Data)).toEqual("bar");
使う 依存関係インジェクション テストに偽物を注入します。
var _actions = function (window) { return { paramToVar: function (testData) { ... var url = window.location.href; ... } }; }; var actions = _actions(window); // Test var fakeWindow = { location: { href: "http://my/fake?param" } }; var fakeActions = _actions(fakeWindow); expect(fakeActions.paramToVar(test_Data)).toEqual("bar");
時々、window.locationを変更するライブラリがある場合があり、それが正常に機能するだけでなく、テストされることを許可したい場合があります。この場合、閉鎖を使用して、このようなライブラリに目的の参照を渡すことができます。
/* in mylib.js */
(function(view){
view.location.href = "foo";
}(self || window));
テストでは、ライブラリを含める前に、グローバルに自己を再定義することができ、ライブラリは模擬自己をビューとして使用します。
var self = {
location: { href: location.href }
};
ライブラリでは、次のようなことをすることもできます。そのため、テストの任意の時点で自己を再定義できます。
/* in mylib.js */
var mylib = (function(href) {
function go ( href ) {
var view = self || window;
view.location.href = href;
}
return {go: go}
}());
すべてではないにしても、ほとんどの最新のブラウザでは、自己はすでにデフォルトでウィンドウへの参照です。ワーカーAPIを実装するプラットフォームでは、労働者の自己内でグローバルな範囲への参照です。 node.jsでは、自己とウィンドウの両方が定義されていないため、必要に応じてこれを行うこともできます。
self || window || global
node.jsが実際にワーカーAPIを実装している場合、これは変更される場合があります。
以下は、window.location.hrefおよび/またはおそらくグローバルオブジェクト上にあるものをmock.location.hrefにockしているアプローチです。
まず、直接アクセスするのではなく、オブジェクトがゲッターとセッターで保持されているモジュールにカプセル化します。以下は私の例です。私は要求を使用していますが、それはここでは必要ありません。
define(["exports"], function(exports){
var win = window;
exports.getWindow = function(){
return win;
};
exports.setWindow = function(x){
win = x;
}
});
さて、あなたは通常あなたのコードで何かをしている場所 window.location.href
, 、今、あなたは次のようなことをします:
var window = global_window.getWindow();
var hrefString = window.location.href;
最後に、セットアップが完了し、代わりにその場所にいる偽のオブジェクトにウィンドウオブジェクトを置き換えることで、コードをテストできます。
fakeWindow = {
location: {
href: "http://google.com?x=y"
}
}
w = require("helpers/global_window");
w.setWindow(fakeWindow);
これは変化します win
ウィンドウモジュールの変数。もともとはグローバルに設定されていました window
オブジェクトですが、それはあなたが入れた偽のウィンドウオブジェクトに設定されていません。したがって、あなたがそれを交換した後、コードはあなたの偽のウィンドウオブジェクトとあなたがそれを入れた偽のhrefを取得します。
IMO、このソリューションは、window.location.hrefをソース内の$ window.location.hrefに置き換えることができるという点で、Cburgmerのわずかな改善です。私はジャスミンではなくカルマを使用していることを確信していますが、このアプローチも機能すると思います。そして、私はシノンへの依存を追加しました。
最初はサービス /シングルトン:
function setHref(theHref) {
window.location.href = theHref;
}
function getHref(theHref) {
return window.location.href;
}
var $$window = {
location: {
setHref: setHref,
getHref: getHref,
get href() {
return this.getHref();
},
set href(v) {
this.setHref(v);
}
}
};
function windowInjectable() { return $$window; }
これで、このような$ウィンドウとしてWindowInjectable()を注入して、コードの場所を設定できます。
function($window) {
$window.location.href = "http://www.website.com?varName=foo";
}
そして、ユニットテストでそれをあざけります:それは次のように見えます:
sinon.stub($window.location, 'setHref'); // this prevents the true window.location.href from being hit.
expect($window.location.setHref.args[0][0]).to.contain('varName=foo');
$window.location.setHref.restore();
Getter / Setterの構文はIE 9に戻り、それ以外の場合は広くサポートされています https://developer.mozilla.org/en-us/docs/web/javascript/reference/functions/set
偽造する必要があります window.location.href
同じページにいる間。私の場合、これは完全に機能しました:
$window.history.push(null, null, 'http://server/#/YOUR_ROUTE');
$location.$$absUrl = $window.location.href;
$location.replace();
// now, $location.path() will return YOUR_ROUTE even if there's no such route