2011-01-25 26 views
53

Tengo algunas pruebas de unidad para una función que hace uso de la ventana.location.href - no es ideal, preferiría haberlo pasado, pero no es posible en la implementación. Me pregunto si es posible burlarse de este valor sin hacer realmente que mi página de corredor de prueba vaya a la URL.burlando window.location.href en Javascript

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

Estoy usando jazmín para mi marco de pruebas unitarias.

+1

I que tiene el mismo problema cuando quiero llamar a una función dentro de la con. ¿Cómo lo resuelves? – wizztjh

Respuesta

6

Necesitas simular contexto local y crear su propia versión de window y window.location objetos

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/... 

Si utiliza with entonces todas las variables (incluyendo window!) En primer lugar será mirado desde el objeto de contexto y si no se presente entonces desde el contexto real.

+1

funcionará esta solución en angular2 con mecanografía –

+5

'' con 'declaraciones no están permitidas en modo estricto.' – isherwood

+0

No me parece que pueda escribir pruebas legibles con él. Creo que la solución propuesta por @Kurt Harriger es mucho mejor. -1 –

42

La mejor manera de hacer esto es crear una función de ayuda en algún lugar y luego burlarse de que:

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

Ahora, en lugar de utilizar window.location.href directamente en el código sólo tiene que utilizar esto en su lugar. A continuación, la sustitución de este método cada vez que necesita para devolver un valor burlado:

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

Si quieres una parte específica de la ubicación de la ventana como un parámetro de cadena de consulta a continuación, crear métodos de ayuda para que también y mantener el análisis de tu código principal Algunos marcos de referencia como el jazmín tienen espías de prueba que no sólo puede burlarse de la función para devolver los valores deseados, pero también puede verificado que se llama:

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

veces puede que tenga una biblioteca que modifica window.location y que desea permitir que funcione normalmente pero también ser probado. Si este es el caso, puede usar un cierre para pasar la referencia deseada a su biblioteca, como esta.

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

Luego, en su prueba, antes de incluir su biblioteca, puede volver a definir uno mismo a nivel mundial, y la biblioteca se utilice el mismo simulacro como la vista.

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

En su biblioteca, también se puede hacer algo como lo siguiente, por lo que puede redefinir el auto en cualquier momento de la prueba:

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

En la mayoría si no todos los navegadores modernos, auto ya está una referencia a la ventana por defecto. En las plataformas que implementan la API de trabajador, dentro de un Yo trabajador es una referencia al alcance global. En tanto Node.js auto y la ventana no están definidos, por lo que si lo desea, también puede hacer esto:

self || window || global 

esto puede cambiar si Node.js realmente implementan la API Trabajador.

17

yo propondría dos soluciones que ya se han insinuado en mensajes anteriores aquí:

  • crear una función alrededor del acceso, uso que en su código de producción, resguardo y esto con Jazmín en sus pruebas:

    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"); 
    
  • Use un dependency injection e inyectar una falsificación de la prueba:

    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

En Jasmine 2.x, la sintaxis utilizada en el primer ejemplo parece haber cambiado un poco. '.andReturn()' debe reemplazarse por '.and.returnValue()'. –

3

A continuación se muestra el enfoque que tengo para simular window.location.href y/o cualquier otra cosa que tal vez en un objeto global.

Primero, en lugar de acceder directamente, encapsularlo en un módulo donde el objeto se mantiene con un captador y un colocador. A continuación está mi ejemplo. Estoy usando require, pero eso no es necesario aquí.

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

    var win = window; 

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

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

}); 

Ahora, en la que normalmente ha hecho en su código de algo así como window.location.href, ahora usted haría algo como:

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

Por último, el programa de instalación está completa y se puede probar el código mediante la sustitución de la ventana Objeto con un objeto falso que quieres que esté en su lugar.

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

Esto cambiaría la variable win en el módulo de ventana. Originalmente se estableció en el objeto global window, pero no está configurado para el objeto de la ventana falsa que ha insertado. De modo que ahora, después de que lo haya reemplazado, el código obtendrá su objeto falso de la ventana y su falso href que lo había puesto.

0

IMO, esta solución es una pequeña mejora de cburgmer en que le permite reemplazar window.location.href con $ window.location.href en la fuente. De acuerdo, estoy usando Karma y no Jasmine, pero creo que este enfoque funcionaría con cualquiera de los dos. Y he agregado una dependencia en sinon.

En primer lugar un servicio/producto único:

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

Ahora puede establecer location.href en código mediante la inyección de windowInjectable() como $ ventana como esta:

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

y burlón a cabo en una prueba de unidad que parece:

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

El/la sintaxis colocador captador se remonta a IE 9, y por lo demás ampliamente compatible de acuerdo con https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set

-1

Necesita falsificar window.location.href estando en la misma página. En mi caso, esto cortó funcionó a la perfección:

$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 
Cuestiones relacionadas