2011-01-25 11 views
53

window.location.hrefを使用する関数の単体テストをいくつか持っています。実際に私のテストランナーページを実際にURLに移動させずにこの値を模擬することが可能かどうか疑問に思っています。Javascriptのwindow.location.hrefを参考にしてください。

window.location.href = "http://www.website.com?varName=foo";  
    expect(actions.paramToVar(test_Data)).toEqual("bar"); 

私はユニットテストフレームワークにジャスミンを使用しています。あなたはローカルコンテキストをシミュレートし、withを使用する場合は、(windowを含む!)すべての変数が最初にコンテキストオブジェクトから見て、そうでない場合はされwindowwindow.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/... 

の独自のバージョンを作成する必要が

+1

私はとの内の関数を呼び出したいとき、私は同じ問題を抱えて。どうやってそれを解決するのですか? – wizztjh

答えて

6

実際の文脈から現れます。単に代わりにこれを使用する

var mynamespace = mynamespace || {}; 
    mynamespace.util = (function() { 
     function getWindowLocationHRef() { 
      return window.location.href; 
     } 
     return { 
     getWindowLocationHRef: getWindowLocationHRef 
     } 
    })(); 

今の代わりに、コード内で直接window.location.href使用:

+1

このソリューションはangular2でtypescriptで動作します –

+5

'with 'ステートメントはstrictモードでは許可されません。' – isherwood

+0

あなたはそれを使って読みやすいテストを書くことができるように私には見えません。私は@Kurt Harrigerによって提案された解決策が良い方法だと思います。 -1 –

42

これを行うための最善の方法は、どこかにヘルパー関数を作成し、そのモックすることです。あなたは、このようなクエリ文字列パラメータとしてウィンドウの位置の特定の部分をしたい場合は、あまりにもそのためのヘルパーメソッドを作成して、外の解析を保つ

mynamespace.util.getWindowLocationHRef = function() { 
    return "http://mockhost/mockingpath" 
}; 

:あなたが嘲笑値を返す必要があるとき、あなたは、このメソッドを置き換えますあなたのメインコード。なジャスミンのようないくつかのフレームワークだけでなく、所望の値を返す関数をモックすることができ、テストスパイを持っているだけでなく、それが呼び出された検証することができます

spyOn(mynamespace.util, 'getQueryStringParameterByName').andReturn("desc"); 
//... 
expect(mynamespace.util.getQueryStringParameterByName).toHaveBeenCalledWith("sort"); 
5

を時には、window.locationのを修正ライブラリを有することができ、あなたがしたいですそれが正常に機能することを可能にするだけでなく、テストされる。このような場合は、クロージャーを使用して、このようなライブラリへの参照を渡すことができます。

/* in mylib.js */ 
(function(view){ 
    view.location.href = "foo"; 
}(self || window)); 

は、その後、あなたのテストでは、あなたのライブラリーを含む前に、あなたは世界的に自己を再定義することができ、およびライブラリは、ビューとしてモック自己を使用します。ほとんどで

/* in mylib.js */ 
var mylib = (function(href) { 
    function go (href) { 
     var view = self || window; 
     view.location.href = href; 
    } 
    return {go: go} 
}()); 

、自己が既にすべての最新ブラウザでない場合:あなたは、テストの任意の時点で自己を再定義するように、あなたのライブラリーで

var self = { 
    location: { href: location.href } 
}; 

は、あなたはまた、次のような何かを行うことができますデフォルトではウィンドウへの参照です。 Worker APIを実装するプラットフォームでは、Worker内で自己がグローバルスコープへの参照になります。 Node.jsのが本当に労働者のAPIを実装しない場合

self || window || global 

これは変更される場合があります。あなたが望むならば、あなたもこれを行うことができますので、Node.jsの自己とウィンドウの両方で、定義されていません。

17

私はすでにここ前回の記事でほのめかしされた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"); 
    
  • dependency injectionを使用して、あなたのテストで偽を注入:

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

Jasmine 2.xでは、最初の例で使用した構文が少し変更されているようです。 '.andReturn()'は '.and.returnValue()'に置き換えてください。 –

3

以下は、私がwindow.location.hrefおよび/または多分グローバルオブジェクト上の何かを模擬するために取っているアプローチです。

まず、直接アクセスするのではなく、オブジェクトをゲッターとセッターで保持するモジュールにカプセル化します。以下は私の例です。私はrequireを使用していますが、ここでは必要ありません。あなたは通常、あなたのコード内でwindow.location.hrefのようなものを行っている今

define(["exports"], function(exports){ 

    var win = window; 

    exports.getWindow = function(){ 
    return win; 
    }; 

    exports.setWindow = function(x){ 
    win = x; 
    } 

}); 

、あなたのような何かをするだろう、今:

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を取得します。

0

IMO、このソリューションは、ソースでwindow.location.hrefを$ window.location.hrefに置き換えることができるという点で、cburgmerの小さな改良です。私はカルマを使用していて、ジャスミンは使用していないと考えていますが、私はこのアプローチがどちらかともうまくいくと考えています。私はsinonに依存しています。

まずサービス/シングルトン:

function($window) { 
    $window.location.href = "http://www.website.com?varName=foo"; 
} 

とでそれをからかっ:

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()を注入することによって、コード内でLOCATION.HREF設定することができますユニットテストは次のようになります:

getter/setter構文はIE 9に戻っています。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set

-1

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 
関連する問題