javascript unit-testing query-string qunit

javascript - ¿Es posible simular el objeto window.location para una prueba qUnit?



unit-testing query-string (2)

He tenido cierto éxito usando window.history.pushState . Ver esta respuesta StackOverflow . Para cada prueba de unidad, llamo a una función setQueryString(''var=something'') que luego implemento así:

function setQueryString(queryString) { window.history.pushState({}, '''', ''?'' + queryString); }

Deberá borrar la cadena de consulta con el método afterEach de QUnit.module; de ​​lo contrario, la cadena de consulta se establecerá en el valor de la prueba final y obtendrá resultados extraños.

Digamos que tengo una función de utilidad que, por simplicidad (lo real es complicado e irrelevante), devuelve la cadena de consulta de la ventana actual.

var someUtilityFunction = () { return window.location.search.substring(1); };

Ahora quiero realizar una prueba unitaria de esta función en qUnit (no estoy seguro de si el arnés de prueba es relevante o no):

test(''#1 someUtilityFunction works'', function () { // setup var oldQS = window.location.search; window.location.search = ''?key1=value1&key2=value2&key3=value3''; var expectedOutput = ''key1=value1&key2=value2&key3=value3''; // test equals(someUtilityFunction(), expectedOutput, ''someUtilityFunction works as expected.''); // teardown window.location.search = oldQS; });

El problema aquí es que la configuración de window.location.search en una cadena de consulta diferente hace que la página se vuelva a cargar, esencialmente ingresando a un bucle de solicitud infinito. ¿Hay alguna manera de burlarse del objeto window.location sin realizar ningún cambio en la función someUtilityFunction ?


Nos encontramos con el mismo problema hace unos días. Principalmente hay 2 enfoques:

Reescribe tu codigo

Es posible que esta no sea la mejor (si existe) solución, pero considere pasar el objeto de la window a su función para facilitar la burla. Aún mejor, use un cierre y encapsule su código. Esto tiene algunas ventajas más:

  • Puedes sombrear vars globales
  • Puedes usar vars locales privados
  • Puedes evitar nombrar colisiones
  • La sombra hace que la burla sea realmente fácil, solo pasa en otra cosa

Envuelve tu código

Puede envolver todo su código dentro de una función que simula el objeto de la ventana en una variable local. Básicamente tienes dos posibilidades allí también:

Supongamos que este es el simulacro:

var customWindow = { location: { search: "", hash: "" } };

Usar un cierre

var someUtilityFunction; (function(window) { // window is now shadowed by your local variable someUtilityFunction = () { return window.location.search.substring(1); }; })(customWindow);

Esto sombrea la window global con una window local.

Usa la sentencia with

Aunque por lo general estoy fuertemente en contra, podría resolver muchos problemas aquí. Básicamente, ya que remapsula su alcance, puede burlarse muy fácilmente de su entorno.

// first some more preparation for our mock customWindow.window = customWindow; with(customWindow) { // this still creates the var in the global scope var someUtilityFunction = () { // window is a property of customWindow return window.location.search.substring(1); }; // since customWindow is our scope now // this will work also someUtilityFunction = () { // location is a property of customWindow too return location.search.substring(1); }; }

Por cierto: no sé si la propiedad de search sufre los mismos síntomas que la propiedad hash , es decir, a veces incluye el signo de interrogación y otras no. Pero es posible que desee considerar el uso de

window.location.search.replace(/^/?/, "");

en lugar de

window.location.substr(1);