Get help with testing, discuss unit testing strategies etc.


Post by Hanterdro »

Hallo,

I work with a lot of direct ajax requests in my extjs application, like this.
			Ext.Ajax.request({
					
				url : 'server_interface/',					
				params:  { '_dc' : (new Date().getTime()) },					
				jsonData: {mode: 'login', name: userLoginData["name"], pwd: userLoginData["pwd"] } ,
				success: this.startLoginSuccsess,
				failure: this.startLoginFailed,
				scope: this
					
			});  
Can I catch with Siesta such Ajax Request and use the data from which the server sends back after a successful ajax request for testing?

Post by mats »

I just pushed this to our repo, to help with Ext JS ajax testing. Thoughts?
/**
@class Siesta.Test.ExtJS.Ajax

This is a mixin, with helper methods for mocking Ajax functionality in Ext JS. This mixin is consumed by {@link Siesta.Test.ExtJS}. 
This is only supported when testing Ext JS 4.
*/
Role('Siesta.Test.ExtJS.Ajax', {
    has : {
        responses : Joose.I.Array,
        urlMatchers : Joose.I.Array
    },

    methods: {

        /**
         * This assertion passes if there is at least one ongoing ajax call.
         * 
         * @param {Object} object (optional) The options object passed to Ext.Ajax.request
         * @param {Description} description The description for the assertion
         */
        isAjaxLoading: function (obj, description) {
            var Ext = this.Ext();
            this.ok(Ext.Ajax.isLoading(obj), description || 'An Ajax call is currently loading');
        },

        /**
         * This method calls the supplied URL using Ext.Ajax.request and then calls the provided callback. The callback will be called with the 
         * same parameters as the normal Ext.Ajax.request callback is called with ("options", "success" and "response"). To get the response text,
         * use response.responseText.
         * 
         * @param {String/Object} url The url or the options to pass to Ext.Ajax.request
         * @param {Function} callback The callback to call after the ajax request is completed
         * @param {Object} scope The scope for the callback
         */
        ajaxRequestAndThen: function (url, callback, scope) {
            var Ext = this.Ext();
            var options = url;

            if (typeof(url) === 'string') {
                options = {
                    url : url,
                    callback : callback,
                    scope : scope
                };
            }

            Ext.Ajax.request(options);
        },

        /**
         * Waits until the 
         * 
         * @param {Object} object (optional) The options object passed to Ext.Ajax.request
         * @param {Function} callback The callback to call after the ajax request is completed
         * @param {Object} scope The scope for the callback
         * @param {Int} timeout The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test#waitForTimeout} value. 
         */
        waitForAjaxRequest: function (obj, callback, scope, timeout) {
            var Ext = this.Ext();
            var msg;

            if (typeof obj === 'function') {
                msg = ' all ajax requests to complete';
                timeout = scope;
                scope = callback;
                callback = obj;
                obj = undefined;
            } else {
                msg = ' ajax request to "' + obj.options.url + '" to complete';
            }

            this.waitFor({
                method          : function() { 
                    if (obj) {
                        return !Ext.Ajax.isLoading(obj) && obj;
                    }
                    return !Ext.Ajax.isLoading(obj);
                }, 
                callback        : callback,
                scope           : scope, 
                timeout         : timeout,
                assertionName   : 'waitForAjaxRequest',
                description     : msg
            });
        }
    }
});
+ a new example coming in the next release.

Post by Hanterdro »

Hi Mats,

I hope i did understand your source code correctly.

I think waitForAjaxRequest is that for what I'm looking.

But I missing to things:

* I dont see how I have access for the record from the ajax request in the callback to check some parameters which I get from the Ajax Request
My Ajax Requst in the first Posts calls this.startLoginSuccess:
	startLoginSuccess : function(record) {
	
	var record = Ext.decode(record.responseText, false);
	
		 if(record.status === true) {
		
			//do something
		}
	}
If I understand your source code correct I can't test for the status parameter which I get from my Ajax Request, because Ext.Ajax.isLoading returns only true or false.
waitForAjaxRequest(null, function(record){

	var record = Ext.decode(record.responseText, false);
	
		 if(record.status === true) {
		
			this.ok('login was successfull');
		}

 });
* How can I test an Ajax failure? (In my case this.startLoginFailed).

* Ok... this is perhaps a little bit complicate ;) Ajax is asyncron. There could be a lot of Ajax Requests at the same time, how can I ensure I test for the correct one?
Example: Every xx seconds I do an ajax request in my application which check the login status. If I do an other Ajax Request to get some special Data, but the Session Ajax Request is fired at the same time, there is a (small) change that the test is will be corrupted, because waitForAjaxRequest my catch the Session ajax request instead the special data ajax request...? (We will test only the complete application, like in your mvc example. Not single widgets).
I think there should be a possibility to catch a single concret ajax request (like a item ID for a widget).
But perhaps this options parameter for waitForAjaxRequest is doing exactly this...? (I don't realy understand him... and why it's the first parameter, when he is optional? *g*).


But thanks a lot for the fast implementation ;)

Post by mats »

Please see the param:
 * @param {Object} object (optional) The options object passed to Ext.Ajax.request
When you perform a Ext.Ajax.request, an object is returned to you identifying the request. Check docs. https://docs.sencha.com/ext-js/4-0/#!/ap ... od-request

When the waiting is done, if you provided a specific request - this object will be passed to you in the next step... See the source:
this.waitFor({
                method          : function() {
                    if (obj) {
                        return !Ext.Ajax.isLoading(obj) && obj;
                    }
                    return !Ext.Ajax.isLoading(obj);
                }, 

Post by Hanterdro »

hm okay... I think I'will wait for the examples in the next release ;)
but good to hear that this is working :D

Post Reply