Translate

martes, 5 de agosto de 2014

Testing javascript with jasmine/sinon


Spy

Un spy es un objeto usado para registrar toda interacción con otros objetos, es una función usada para registrar si se ha llamado y cuantas veces, con qué argumentos, los valores devueltos, el valor de this, y cualquier excepción si la hay para cada una de las llamadas a esa función.

Puede ser una función anónima, o envolver a otra función existente controlando así lo anteriormente descrito. En este último caso la función a la que envuelve sigue funcionando igual

Los datos guardados por el spy se guardan en un array args[][] de manera que args[0] serán los argumentos recibidos en la primera llamada, args[1] en la segunda y así consecutivamente.

Los valores devueltos se guardan también en un array returnValues[], donde returnValues[0] sería el valor devuelto en la primera llamada Si no devuelve valor alguno será undefined.

El valor de this se devuelve igual que los valores devueltos pero con el array thisValues[].
Igual con las excepciones que irán en el array exceptions[].

Los spies son útiles para controlar llamadas a una función, que se llame con los argumentos adecuados, que devuelva el valor correcto, etc…

Ejemplo de definición de un spy que registrará todas las operaciones de Extjs.ajax sin interferir en su normal funcionamiento:

sinon.spy (jQuery,’ajax’);
jQuery.getJSON(‘/some/data’);

El spy no interferirá en el normal funcionamiento de jQuery.ajax, pero registrará los datos asociados.

Los métodos más ususales para spy suelen ser:

  •          calledOnce: si se ha llamado una sola vez.
  •          called: al menos una.
  •          calledTwice: dos veces.
  •          calledThrice: tres veces
  •          callCount:  el nº de veces llamado
  •     calledWith(arg1, arg2,…): llamado con los argumentos indicados(puede incluir otros distintos).
  •          calledWithExactly(arg1, arg2,..): llamado con los argumentos indicados y ninguno más.
  •          Threw(): devolvió excepción.


Algunos ejemplos de spies:

Así se define un spy para que actúe cobre el objeto controller.behaviourStore cuando se llame al método load:

storeLoadSpy = U4.testframework.spy(controller.behaviourStore, 'load');

Una vez definido llamaremos a cualquier otro método que queramos saber si hace una llamada a load, y controlaremos por ejemplo que se ha llamado y con los argumentos correctos

expect(storeLoadSpy.called).toBeTruthy();
expect(storeLoadSpy.args[0][0].listNodes).toBe(nodesList.toString());


Stub

Es un sustituto de la función a la que envuelve, o un sustituto de una función que no existe. Permite definir un comportamiento dado al llamar a esa función stub, es decir fijar unos parámetros y que devuelva un valor fijo determinado. Stub implementa la interface spy, por lo que también puede ser usado un stub a modo de spy.

Las dos principales razones para usar stubs es enmascarar comportamientos, por ejemplo evitar la necesidad de tener que hacer peticiones a un servidor, o evitar que una pantalla de confirmación aparezca, etc.. y por otro lado proveer a los test de datos que normalmente son suministrados por otras funciones sin tener que usarlas. Con esto aislamos el test para evitar que otros aspectos externos al test puedan influir.

Los stubs se crean de las siguientes formas:

·        sinon.stub()  crea stub function anónima.
·        sinon.stub(object,”method”) crea un stub para el método object.method
·       sinon.stub(object,”method”,func) crea un stub para el método object.method sustituyéndolo por la función func
·        
Los métodos más usuales para stub son:

  •           returns(value) hace que el stub devuelva siempre ese valor.
  •      throws(exception) lanza una excepción, si exception es un string puede ser el tipo de excepción
  •          withArgs (arg1, arg2,…)


Algunos ejemplos de stubs

Crea stub de función anónima, y lo define de manera que si se llama con el parámetro 42 devuelve 1, si se llama con el 1 devuelve un error, y si no se usa argumento alguno entonces no devuelve nada.

var callback = sinon.stub();
    callback.withArgs(42).returns(1);
    callback.withArgs(1).throws("TypeError");

    callback(); // No return value, no exception
    callback(42); // Returns 1
    callback(1); // Throws TypeError


En el siguiente ejemplo de crea un stub para el método getSelection del objeto behaviourView.grid.getSelectionModel(), que devolverá siempre un array con un record, es decir cada vez que se haga una selección del grid se devuelve el mismo objeto

U4.testframework.stub(behaviourView.grid.getSelectionModel(), 'getSelection').returns([record]);
expect(behaviourView.fireEvent.calledWithExactly('inheritbehaviourmodified',record, behaviourSelected.originalValue)).toBeFalsy();

En este otro ejemplo usaremos un stub para evitar que se haga la llamada al servidor, y como si fuera un spy controlaremos que se ha hecho un POST sobre la url correcta, y con los datos correctos:

saveChanges: function (config) {
        var me = this,
            client,
            jsonData = me.fillJSONData(config.treeStore, config.behaviourStore, config.evidenceStore),
            competenceGroupsPath = 'hrms/competence/competencegroups/';
       
        U4.Ajax.setAccessId(me.accessId);
        client = U4.util.Path.encodeSegment(me.client);
       
        return U4.Ajax.promise({
            url: U4.util.Path.getApiPath(competenceGroupsPath + client),
            method: 'POST',
            jsonData: Ext.JSON.encode(jsonData)
        });
    },
promiseStub = U4.testframework.stub(U4.Ajax, 'promise');
saveProxy.saveChanges(config);
expect(promiseStub.calledOnce).toBeTruthy();
expect(promiseStub.args[0][0].method).toBe('POST');
expect(promiseStub.args[0][0].url).toBe('hrms/competence/competencegroups/XX');
expect(promiseStub.args[0][0].jsonData).toBe(jsonDataExpected);

Ejemplo de crear un FakeServer que simule un servidor que devuelva los datos a una petición de un store.load (response debe ser un array con los elementos a devolver), igualmente se usa un spy asociado a Ext.Ajax sobre el método ‘request’ para controlar si se hizo una llamada

fakeServer = U4.testframework.createFakeServer();
fakeServer.respondWith('GET', new RegExp('.*hrms/competence/competencegroups/.*'),
                [200, { 'Content-Type': 'application/json' },
                    response]);

spyAjaxRequest = U4.testframework.spy(Ext.Ajax, 'request');

store.load({ listNodes: '' });
fakeServer.respond();
expect(spyAjaxRequest.calledOnce).toBeTruthy();


Otro ejemplo de stub para evitar que se muestre un mensaje de confirmación y comprobar que se ha llamado a dicho mensaje.

stubOnShow = U4.testframework.stub(U4.Msg, 'show').yieldsTo('fn', 'ok');


expect(stubOnShow.called).toBeTruthy();

jueves, 12 de junio de 2014

Subida a Lentegí desde Almuñecar


Lugar: Costa Tropical, Almuñecar, Granada, España.
Tipo de Ruta: Carretera. Montaña.

Ruta de montaña de poco kilometraje, 42km pero exigente. La salida se  hace desde la localidad de Almuñecar, a la que retornaremos una vez alcanzada la locaidad de Lentegí. El punto mínimo de altura es el nivel del mar mientras que el punto mas alto alcanzado es de 694m. El acumulado de desnivel es de 780m.

Esta ruta tiene tres zonas claramente diferenciadas, la primera de ella desde la salida hasta el km 8 es practicamente llana, con algún repecho poco reseñable mientras transitamos por el valle del rio guadalfeo entre campos de aguacates.
Una vez alcanzado el km 8 comienza la segunda parte con una suave ascensión hasta el cruce de Lentegí en el Km  15, atravesando las localidades de Jete primero y Otivar después. 



De vez en cuando encontramos alguna rampa mas pronunciada, pero la subida es sencilla. A medida que discurran los kilómetros el porcentaje de las ascensión irá incrementando hasta alcanzar el cruce mencionado.

Comienza aquí la tercera parte de la subida girando a la derecha para comenzar la ascensión a Lentegí. Mientras subimos entre pinos podremos contemplar enfrente la subida al mirador de la cabra. 

Sobre Lentegí y la Cabra y la Sierra de Almijara y Tejeda al fondo


En el km 18 encontraremos un cruce tomando el desvio hacia la derecha en dirección a la piscina, vienen ahora las últimas rampas que nos dejan en la parte superior del pueblo.
Una vez alcanzado este bajaremos en dirección al centro del pueblo para retornar por la misma carretera que subimos. Cuidado con el primer km de bajada que es bastante pronunciado.

lunes, 19 de mayo de 2014

Ext.JS and Visual Studio: HTTP Error 404 file not found when loading json file

I have the following store defined, loading data from a json file:

Ext.define('Uge.store.Articles', {
    extend: 'Ext.data.Store',
    model: 'Uge.model.Article',
    proxy: {
        type: 'ajax',
        url: 'data/articles.json',
        reader: {
            type: 'json',
            root: 'articles',
            successProperty: 'success'
        }
    },
    autoLoad: true
});

Data to load is inside the file data/articles.json, but when trying to load data we get an error pointing that file could not be found.
 
To avoid this error you need to set your project to accept json file types. You can do this setting the following configuration into web.config file:


domingo, 20 de abril de 2014

Googlemaps javaScript API with Ext.NET and Web Forms

Googlemaps API is a desktop and mobile web mapping service application and technology provided by Google, offering satellite imagery, street maps, and Street View perspectives, as well as functions such as a route planner for traveling by foot, car, bicycle (beta test), or with public transportation.

You can use it embed in your web pages. Here you can find some documentation on how-to register for use and some examples: https://developers.google.com/maps/documentation/javascript/tutorial

This is an example showing a map with the localization for a given shop:


The first step to use is to obtain a key.

Next you need to add a script in web page in order to allow access to googlemap, using the key previously obtained:



Next step is to add a script to the page used to load the map with the position needed. in my case I use a marker to mark the desired position:

In the aps.net page we need to include an element, could be a div, or a panel, with the name map_canvas to draw the map on it.


In my page I am using a TabPanel, and I use the Panel map_canvas to draw the map. To access this element inside the DOM is important to take care about the real name used. For this a launch the pagem and then using Inspect Element a obtain the real name. In my case was 'cpMainContent_map_canvas-body'. This is becacuse I  am using Masterpages, and then the panel is nested with another panels, and ContentPlaceHolder.

 To load the correct map a use a Listener associated to the loading of the tab page having the map. This listener use initializeMap taking the longitude, latitude and name parameter from text fields inside the page.



Also I have added a few functionalities to the map, allowing to reposition the marker doing click over the map and reloading latitude and longitude data to web fields. And finally you could also make click over the marker to make zoom and center the position to this marker.