I have written unit test for ajax suing Qunit, but getting error like
Error: assertion outside test context, was .success#http://test.loc/assets/test/widget-add-or-edit-test.js:227
b.Callbacks/c#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
b.Callbacks/p.fireWith#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:3
k#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:5 .send/r#http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js:5
Source:
http://code.jquery.com/qunit/qunit-1.11.0.js:899
my test code is
test( "Widget.updateAxisTypeAjax x", function() {
stop();
Widget.updateAxisTypeAjax( {
axis : 'x' ,
x_id : 179,
y_id : 175
} ,{
success : function( response ){
ok( true, "updateAxisTypeAjax Success PASS!");
equal( typeof response ,
"object" ,
"updateAxisTypeAjax response is json valid object !"
);
equal( typeof response == "object" &&
( "average" in response ) &&
("is_datetime" in response) ,
true ,
"updateAxisTypeAjax average check PASS !"
);
} ,
complete : function(){
ok(true, "updateAxisTypeAjax completed PASS!");
start();
}
});
});
and Widget.updateAxisTypeAjax is
Widget.updateAxisTypeAjax = function( data_obj, callbacks ){
data_obj = jQuery.extend( data_obj ,{
action : 'update_axis'
});
Widget.ajax( 5 )
.data( data_obj )
.callbacks( callbacks )
.fire();
}
and Widget.ajax is :
var Widget = Widget || {} ;
function _WidgetAjax( type ){
var loader = $('#series_loader');
this.ajaxUrl = '/dashboard/charts/ajax/' + ( type || 1 ) ;
this.ajaxSettings = {
url: this.ajaxUrl ,
type:"GET",
data :{} ,
complete : function(){ // always
loader.hide();
}
};
// show ajax loading
loader.show();
this.data = function( data ){
jQuery.extend( this.ajaxSettings, { data: data } );
return this;
}
this.callbacks = function( callbacks ){
jQuery.extend( this.ajaxSettings, callbacks || {} );
return this;
}
this.success = function( func ){
if ( jQuery.isFunction( func ) ){
jQuery.extend( this.ajaxSettings, { success: func } );
}
return this;
};
this.fire = function(){
return $.ajax( this.ajaxSettings );
};
};
Widget.ajax = function( type ){
return new _WidgetAjax( type );
};
Please help me fix this unit test error !
You're testing an asynchronous function, so you need to use the async features in QUnit.
Instead of test you should be using asyncTest
Here is the documentation.
Note that you have to tell QUnit how many assertions to expect when doing async tests.
asyncTest( "Widget.updateAxisTypeAjax x", 4, function() {
stop();
Widget.updateAxisTypeAjax( {
axis : 'x' ,
x_id : 179,
y_id : 175
} ,{
success : function( response ){
ok( true, "updateAxisTypeAjax Success PASS!");
equal( typeof response ,
"object" ,
"updateAxisTypeAjax response is json valid object !"
);
equal( typeof response == "object" &&
( "average" in response ) &&
("is_datetime" in response) ,
true ,
"updateAxisTypeAjax average check PASS !"
);
} ,
complete : function(){
ok(true, "updateAxisTypeAjax completed PASS!");
start();
}
});
});
Should probably work. This shouldn't be too hard to fix!
Related
XDomainRequest most of them time works ok but sometimes aborts in ie9 specially. has anyone experienced this before?
In case you want to see this is the xdr implementation im using:
(function( jQuery ) {
if ( window.XDomainRequest ) {
jQuery.ajaxTransport(function( s ) {
if ( s.crossDomain && s.async ) {
if ( s.timeout ) {
s.xdrTimeout = s.timeout;
delete s.timeout;
}
var xdr;
return {
send: function( _, complete ) {
function callback( status, statusText, responses, responseHeaders ) {
xdr.onload = xdr.onerror = xdr.ontimeout = jQuery.noop;
xdr = undefined;
complete( status, statusText, responses, responseHeaders );
}
xdr = new window.XDomainRequest();
xdr.onload = function() {
callback( 200, "OK", { text: xdr.responseText }, "Content-Type: " + xdr.contentType );
};
xdr.onerror = function() {
callback( 404, "Not Found" );
};
xdr.onprogress = function() {};
if ( s.xdrTimeout ) {
xdr.ontimeout = function() {
callback( 0, "timeout" );
};
xdr.timeout = s.xdrTimeout;
}
xdr.open( s.type, s.url, true );
xdr.send( ( s.hasContent && s.data ) || null );
},
abort: function() {
if ( xdr ) {
xdr.onerror = jQuery.noop();
xdr.abort();
}
}
};
}
});
}
})( jQuery );
I had this issue a while back and I found that if you wrap your send method inside a setTimeout it solves the issue.
setTimeout(function(){
xdr.send( ( s.hasContent && s.data ) || null );
}, 0);
Hello I'm parsing some data from my database into a table using aui-datatable plugin however I would like to add some basic sorting in my columns. Bellow you may see the function "renderProducts" which renders the data-table. Furthermore bellow is a sample column object that is being passed into the table renderer.
var API= (function(Y){
var settings = {
serviceURL : null
};
var getServiceAttribute = function( attribute ) {
return '_openpimadmin_WAR_OpenTest_' + attribute;
}
var getServiceURL = function( service ) {
return settings.serviceURL + '&p_p_resource_id=' + service;
};
var service = function( service, dataSet, handlers ){
var serviceData = {};
var serviceHandlers = {
start : function(){},
success : function(){},
failure : function(){},
end : function(){}
};
for (prop in dataSet) {
serviceData[getServiceAttribute(prop)] = dataSet[prop];
}
for (prop in handlers) {
if ( serviceHandlers.hasOwnProperty(prop) && typeof handlers[prop] === 'function') {
serviceHandlers[prop] = handlers[prop];
}
}
Y.io(
getServiceURL( service ),
{
method : 'POST',
data : serviceData,
on : {
start : function( transactionID ) {
serviceHandlers.start(transactionID);
},
success : function( transactionID, response ) {
var parsed = Y.JSON.parse(response.responseText);
if (parsed.success === true){
serviceHandlers.success( transactionID, parsed );
} else {
console.log('Service [' + service + '] error: ' + parsed.error);
}
},
failure : function( transactionID, response ) {
serviceHandlers.failure( transactionID, response );
},
end : function( transactionID ) {
serviceHandlers.end( transactionID );
}
}
}
);
}
return {
services : {
getProducts : function( dataSet, handlers ){
dataSet = dataSet || {};
handlers = handlers || {};
service( 'getProducts', dataSet, handlers );
},
getProductsTableAttributeHeaders : function( dataSet, handlers) {
dataSet = dataSet || {};
handlers = handlers || {};
service( 'getProductsTableAttributeHeaders', dataSet, handlers );
},
},
views : {
renderProducts : function( el, columns, dataSet ) {
Y.one(el).get('childNodes').remove();
new Y.DataTable.Base({
columnset : columns,
recordset : dataSet,
width: '100%'
}).render(el);
}
},
get : function( prop ) {
return settings[prop];
},
set : function( options ) {
settings = Y.merge( settings, options );
}
};
})( YUI().use('node', 'io', 'aui-datatable', 'datatable-sort', function(Y){return Y;}) );
Column object:
Object {key: "name", label: "Όνομα", allowHTML: true, emptyCellValue: "<em>(not set)</em>", sortable: true}
The issue I'm facing is that sorting is nowhere to be seen, columns dont seem interactive and the user is not able to sort them, although the table is being rendered fine.
Thank you in advance.
PS: I'm new to YUI().
You need to make sure that sortable: true set for column that need sorting.
Here is a real world example with sorting feature
It seems this was the problem:
new Y.DataTable.Base({
columnset : columns,
recordset : dataSet,
width: '100%'
}).render(el);
Should have been like this:
new Y.DataTable({
columnset : columns,
recordset : dataSet,
width: '100%'
}).render(el);
I got this response from ajax
{
"laborCostIndex":0.0,
"laborDailyWage":0.0,
"laborHourlyWage":0.0,
"laborMonthlyWage":0.0,
"laborLeave":0.0,
"laborBonus":0.0,
"laborSSS":0.0,
"laborPagIbig":0.0,
"laborPhilHealth":0.0,
"laborEMP":0.0,
"laborTotalMonthlyRate":110.0,
"laborTotalDailyRate":4.230769230769231,
"laborTotalHourlyRate":0.5288461538461539
}
I'm trying to access the element inside through this:
response.laborCostIndex and response['laborCostIndex'] but seems doesn't work for me.
The ajax is from the xeditable here is the code:
UPDATE: posted the whole ajax
$('.laborCostIndex').editable({
pk: '1',
name: 'laborCostIndex',
url: '../BTool/edit_laborCostIndex.do',
validate: function( value ) {
if($.trim( value ) == '') {
return 'This field is required';
} else if( isNaN( value ) ) {
return 'Only accepts numbers';
}
},
params: function(params) {
var basicDailyWage = $(this).closest('td').next('td').find('a').text();
var pagIbig = $(this).closest('tr').find(':nth-child(11)').find('a').text();
var emp = $(this).closest('tr').find(':nth-child(13)').find('a').text();
var datas = new Array(basicDailyWage, pagIbig, emp);
params.pk = datas;
return params;
},
success: function(response, newValue) {
console.log( response );
console.log( response.laborCostIndex );
console.log( response['laborCostIndex'] );
}
});
Both results to undefined, I don't know why.
Try this in your success function
var obj = JSON.parse(response);
console.log( obj.laborCostIndex);
I've been using javascript for years, and gotten pretty good at it since I started a web development job, but working with node on a personal project I am having issues.
I create an object
;( function( undefined ) {
'use strict';
var scrape = {
data : {},
scrapers: [],
init : function( coins, exchanges, trade_paths ) {
scrape.start_time = new Date().getMilliseconds();
// Load events
var Event = require( 'events' );
// Add an eventEmitter to process
process.event = new Event.EventEmitter()
// Now we can load any modules, now that global process is modified ;)
//require( './bter.js' );
exchanges.forEach( function( exchange ) {
console.log( exchange.name + '.js' );
require( exchange.name.toLower() + '.js' );
} );
// Trigger the preload event
process.event.emit( 'scraper::init', coins );
// Response to all modules processes
process.event.on( 'scraper::add', scrape.add );
},
add : function( module ) {
scrape.data[module.name] = module.data;
}
};
// Get list of exchanges, coins, and trade paths
var sql_data = {
sql : {},
db : {},
coins : [],
exchanges : [],
trade_paths : [],
init : function() {
sql_data.sql = require( 'mysql' );
sql_data.db = sql_data.sql.createConnection( {
host : '127.0.0.1',
user : 'root',
password : ''
} );
sql_data.db.connect();
// Get coin list
sql_data.db.query('SELECT * FROM `node`.`coins` WHERE active=true', function(err, rows, fields) {
if( typeof rows !== 'undefined' ) {
sql_data.coins = rows;
}
// Oddly, if no error, its equal to null.
if( err !== null ) {
console.log( err );
}
} );
// Get exchange list
sql_data.db.query( 'SELECT * FROM `node`.`exchanges` WHERE active=true', function( err, rows, fields ) {
if( typeof rows !== 'undefined' ) {
sql_data.exchanges = rows;
}
if( err !== null ) {
console.log( err );
}
} );
// Get trade paths
sql_data.db.query( 'SELECT * FROM `node`.`trade_paths` WHERE active=true', function( err, rows, fields ) {
if( typeof rows !== 'undefined' ) {
sql_data.trade_paths = rows;
}
if( err !== null ) {
console.log( err );
}
} );
// Close connection to the database
sql_data.db.end();
}
};
sql_data.init();
// Start scraping
scrape.init( sql_data.coins, sql_data.exchanges, sql_data.trade_paths );
} () );
object.x is not accessible. Not even within object itself. I don't know what to do or how to fix this.
Your scrape.init function is called before you received data from mysql. You need to call it inside sql_data.init callback (which you can safely call in third .query() since mysql queries are executed sequentially per connection).
I would like to run some specific code around put() and add() for Dojo stores.
The problem I am having is that for JSON REST stores, in JsonRest.js add() is just a function that calls put():
add: function(object, options){
options = options || {};
options.overwrite = false;
return this.put(object, options);
},
So, if I use aspect.around() with add(), my code ends up being executed twice IF I apply my code to stores created with a store that implements add() as a stub to put().
Please note that I realise that most stores will do that. I just want my solution to be guaranteed to work with any store, whether there is method nesting or not.
Dojo's own Observable.js has the same problem. This is how they deal with it:
function whenFinished(method, action){
var original = store[method];
if(original){
store[method] = function(value){
if(inMethod){
// if one method calls another (like add() calling put()) we don't want two events
return original.apply(this, arguments);
}
inMethod = true;
try{
var results = original.apply(this, arguments);
Deferred.when(results, function(results){
action((typeof results == "object" && results) || value);
});
return results;
}finally{
inMethod = false;
}
};
}
}
// monitor for updates by listening to these methods
whenFinished("put", function(object){
store.notify(object, store.getIdentity(object));
});
whenFinished("add", function(object){
store.notify(object);
});
whenFinished("remove", function(id){
store.notify(undefined, id);
});
My question is: is there a simple, "short" way to change my existing code so that it checks if it's within a method, and avoid running the code twice?
I gave it a go, but I ended up with clanky, hacky code. I am sure I am missing something...
Here is my existing code:
topic.subscribe( 'hotplate/hotDojoStores/newStore', function( storeName, store ){
aspect.around( store, 'put', function( put ){
return function( object, options ){
return when( put.call( store, object, options ) ).then( function( r ) {
var eventName;
var identity = store.idProperty;
eventName = object[ identity ] ? 'storeRecordUpdate' : 'storeRecordCreate';
topic.publish( eventName, null, { type: eventName, storeName: storeName, objectId: r[ identity ], object: object }, false );
} );
}
});
aspect.around( store, 'add', function( add ){
return function( object, options ){
return when( add.call( store, object, options ) ).then( function( r ) {
var identity = store.idProperty;
topic.publish('storeRecordCreate', null, { storeName: storeName, storeTarget: storeTarget, objectId: r[identity], object: object }, false } );
});
}
});
});
This is my attempt...
What I don't really "get" about my attempt is whether it's 100% safe or not.
If store.add() is called twice in a row, is is ever possible that inMethod is set to true by the first call, and that the second add() call then finds it already set to true because the first one hasn't managed to set it to false yet?
This would only really be possible if nextTick() is called in between the two calls I assume?
Or am I just completely confused by it all? (Which is very possible...)
topic.subscribe( 'hotplate/hotDojoStores/newStore', function( storeName, store ){
var inMethod;
aspect.around( store, 'put', function( put ){
return function( object, options ){
if( inMethod ){
return when( put.call( store, object, options ) );
} else {
inMethod = true;
try {
return when( put.call( store, object, options ) ).then( function( r ) {
var eventName;
var identity = store.idProperty;
eventName = object[ identity ] ? 'storeRecordUpdate' : 'storeRecordCreate';
topic.publish( eventName, null, { type: eventName, storeName: storeName, objectId: r[ identity ], object: object }, false );
});
} finally {
inMethod = false;
}
}
}
});
aspect.around( store, 'add', function( add ){
return function( object, options ){
if( inMethod ){
return when( add.call( store, object, options ) );
} else {
inMethod = true;
try {
return when( add.call( store, object, options ) ).then( function( r ) {
var identity = store.idProperty;
topic.publish('storeRecordCreate', null, { type: 'storeRecordCreate', storeName: storeName, objectId: r[identity], object: object }, false );
});
} finally {
inMethod = false;
}
}
}
});
aspect.around( store, 'remove', function( remove ){
return function( objectId, options ){
return when( remove.call( store, objectId, options ) ).then( function( r ) {
topic.publish('storeRecordRemove', null, { type: 'storeRecordRemove', storeName: storeName, objectId: objectId }, false );
});
};
});
});