program tip

자바 스크립트에서 window.location.href를 조롱

radiobox 2020. 11. 25. 07:50
반응형

자바 스크립트에서 window.location.href를 조롱


window.location.href를 사용하는 함수에 대한 단위 테스트가 있습니다. 이상적이지는 않지만 이것을 전달했지만 구현에서는 불가능합니다. 실제로 내 테스트 실행기 페이지가 실제로 URL로 이동하지 않고도이 값을 조롱 할 수 있는지 궁금합니다.

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

단위 테스트 프레임 워크에 jasmine을 사용하고 있습니다.


로컬 컨텍스트를 시뮬레이션하고 고유 한 버전의 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/...

사용하는 with경우 모든 변수 ( window! 포함 )는 먼저 컨텍스트 객체에서 찾고없는 경우 실제 컨텍스트에서 찾습니다.


이를 수행하는 가장 좋은 방법은 어딘가에 도우미 함수를 만든 다음이를 조롱하는 것입니다.

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

이제 코드에서 직접 window.location.href를 사용하는 대신 이것을 사용하십시오. 그런 다음 모의 값을 반환해야 할 때마다이 메서드를 바꿀 수 있습니다.

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

쿼리 문자열 매개 변수와 같은 창 위치의 특정 부분을 원하면 해당 항목에 대한 도우미 메서드도 만들고 기본 코드에서 구문 분석을 유지하십시오. jasmine과 같은 일부 프레임 워크에는 원하는 값을 반환하도록 함수를 조롱 할 수있을뿐만 아니라 호출되었는지 확인할 수있는 테스트 스파이가 있습니다.

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

이전 게시물에서 이미 암시 된 두 가지 솔루션을 제안합니다.

  • 액세스를 중심으로 함수를 만들고 프로덕션 코드에서 사용하고 테스트에서 Jasmine으로 스텁합니다.

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

모든 최신 브라우저는 아니지만 대부분의 경우 self는 기본적으로 이미 창에 대한 참조입니다. 작업자 API를 구현하는 플랫폼에서 작업자 자체는 전역 범위에 대한 참조입니다. node.js에서는 self와 window가 모두 정의되어 있지 않으므로 원하는 경우 다음을 수행 할 수도 있습니다.

self || window || global

node.js가 실제로 작업자 API를 구현하면 변경 될 수 있습니다.


Below is the approach I have take to mock window.location.href and/or anything else which maybe on a global object.

First, rather than accessing it directly, encapsulate it in a module where the object is kept with a getter and setter. Below is my example. I am using require, but that is not necessary here.

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

  var win = window;

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

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

});

Now, where you have normally done in your code something like window.location.href, now you would do something like:

var window = global_window.getWindow();
var hrefString = window.location.href;

Finally the setup is complete and you can test your code by replacing the window object with a fake object you want to be in its place instead.

fakeWindow = {
  location: {
    href: "http://google.com?x=y"
  }
}
w = require("helpers/global_window");
w.setWindow(fakeWindow);

This would change the win variable in the window module. It was originally set to the global window object, but it is not set to the fake window object you put in. So now after you replaced it, the code will get your fake window object and its fake href you had put it.


IMO, this solution is a small improvement of cburgmer's in that it allows you to replace window.location.href with $window.location.href in the source. Granted I'm using Karma and not Jasmine, but I believe this approach would work with either. And I've added a dependency on sinon.

First a service / singleton:

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

Now I can set location.href in code by injecting windowInjectable() as $window like this:

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

and mocking it out in a unit test it looks like:

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

The getter / setter syntax goes back to IE 9, and is otherwise widely supported according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set


You need to fake window.location.href while being on the same page. In my case, this snipped worked perfectly:

$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

참고URL : https://stackoverflow.com/questions/4792281/mocking-window-location-href-in-javascript

반응형