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