updated for testing

This commit is contained in:
Andy Gup 2015-02-23 11:15:35 -07:00
parent 5f6ec59246
commit 7566970d01
3 changed files with 318 additions and 326 deletions

View File

@ -39,7 +39,7 @@ O.esri.Edit.EditStore = function()
id: layer + "/" + graphic.attributes.objectid,
operation: operation,
layer: layer,
graphic: graphic.toJson()
graphic: this._serialize(graphic)
};
var transaction = this._db.transaction([objectStoreName],"readwrite");
@ -92,6 +92,43 @@ O.esri.Edit.EditStore = function()
}
};
/**
* Returns all the edits as a single Array via the callback
* @param callback {value, message}
*/
this.getAllEditsArray = function(callback){
console.assert(this._db !== null, "indexeddb not initialized");
var editsArray = [];
if(this._db !== null){
var transaction = this._db.transaction([objectStoreName])
.objectStore(objectStoreName)
.openCursor();
transaction.onsuccess = function(event)
{
var cursor = event.target.result;
if(cursor){
editsArray.push(cursor.value);
cursor.continue();
}
else
{
callback(editsArray, "end");
}
}.bind(this);
transaction.onerror = function(err)
{
callback(null, err);
};
}
else
{
callback(null, "no db");
}
};
/**
* Update an edit already exists in the database
* @param operation add, update or delete

View File

@ -2,6 +2,7 @@
define([
"dojo/Evented",
"dojo/_base/Deferred",
"dojo/DeferredList",
"dojo/promise/all",
"dojo/_base/declare",
"dojo/_base/array",
@ -16,7 +17,7 @@ define([
"esri/symbols/SimpleFillSymbol",
"esri/urlUtils"],
function(
Evented,Deferred,all,declare,array,domAttr,domStyle,query,
Evented,Deferred,DeferredList,all,declare,array,domAttr,domStyle,query,
esriConfig,GraphicsLayer,Graphic,SimpleMarkerSymbol,SimpleLineSymbol,SimpleFillSymbol,urlUtils)
{
"use strict";
@ -430,7 +431,7 @@ define([
},this);
all(promises).then( function(r)
{ console.log("DELETE " + JSON.stringify(results.deleteResults))
{ console.log("DONE WITH DATABASE PUSH");
//TO-DO - handle information related to any failed edits that didn't get stored
/* we already pushed the edits into the database, now we let the FeatureLayer to do the local updating of the layer graphics */
@ -922,22 +923,70 @@ define([
return optimizedEdits;
},
_internalApplyEdits: function(layer,tempObjectIds,adds,updates,deletes)
{
// unfortunately we can't use the promise that is returned from layer._applyEdits()
// because it returns 3 result parameters (addResults,updateResults,deleteResults)
// and when we combine all promises in the dojo/promise/all() method below this only
// supports promises that return one value
var dfd = new Deferred();
console.log("PRE APPLYEDITS " + adds + ", " + updates + ", " + deletes);
var internalLayer = layer;
internalLayer.dfd;
internalLayer._applyEdits(adds,updates,deletes,
function(addResults,updateResults,deleteResults)
{ console.log("RUNNNING APPLY EDITS")
try {
internalLayer._phantomLayer.clear();
internalLayer.onEditsComplete = internalLayer.__onEditsComplete;
delete internalLayer.__onEditsComplete;
internalLayer.onBeforeApplyEdits = internalLayer.__onBeforeApplyEdits;
delete internalLayer.__onBeforeApplyEdits;
var newObjectIds = addResults.map(function (r) {
return r.objectId;
});
console.log("INTERNAL " + addResults + ", update " + updateResults + ", delete " + deleteResults)
// We use a different pattern if the attachmentsStore is valid and the layer has attachments
if (internalLayer._attachmentsStore != null && internalLayer.hasAttachments && tempObjectIds.length > 0) {
internalLayer._replaceFeatureIds(tempObjectIds, newObjectIds, function (success) {
dfd.resolve({
addResults: addResults,
updateResults: updateResults,
deleteResults: deleteResults
}); // wrap three arguments in a single object
});
}
else {
dfd.resolve({
addResults: addResults,
updateResults: updateResults,
deleteResults: deleteResults
}); // wrap three arguments in a single object
}
}catch(err){
console.log("ERROR ERROR " + err);
}
},
function(error)
{ console.log("INTERNAL ERROR " + adds + ", update " + JSON.stringify(updates) + ", delete " + deletes + ", " + JSON.stringify(error))
internalLayer.onEditsComplete = internalLayer.__onEditsComplete; delete internalLayer.__onEditsComplete;
internalLayer.onBeforeApplyEdits = internalLayer.__onBeforeApplyEdits; delete internalLayer.__onBeforeApplyEdits;
dfd.reject(error);
}
);
return dfd;
},
_replayStoredEdits: function(callback)
{
//if( this._editStore.hasPendingEdits() )
//{
//
// flatten the queue into unique edits for each feature, grouped by FeatureLayer
//
//var optimizedEdits = this._optimizeEditsQueue();
var promises = {};
//if( Object.keys(optimizedEdits).length === 0 )
//{
// this.emit(this.events.ALL_EDITS_SENT);
// callback && callback(true, {});
// return;
//}
var deferredListArr = [];
var that = this;
//
// send edits for each of the layers
@ -945,253 +994,156 @@ define([
var layerUrl, layer, layerEdits;
var adds, updates, deletes;
var tempObjectIds;
var objectId;
var objectId, c= 1000;
var i,g;
var tempArray = [];
var featureLayers = this._featureLayers;
var attachmentsStore = this.attachmentsStore;
var editStore = this._editStore;
this._editStore.getAllEdits(function(result,err){
if(result != null){
layer = this._featureLayers[ result.layer ];
this._editStore.getAllEditsArray(function(result,err){
if(result != null) {
tempArray = result;
//}
//else {
// If the layer has attachments then check to see if the attachmentsStore has been initialized
if(this.attachmentsStore == null && layer.hasAttachments){
console.log("ERROR: you need to run OfflineFeaturesManager.initAttachments(). Check the Attachments doc for more info.")
throw new Error("OfflineFeaturesManager: Attachments aren't initialized.");
var length = tempArray.length;
//length = 9;
for(var n= 0;n < length;n++) {
layer = featureLayers[tempArray[n].layer];
// If the layer has attachments then check to see if the attachmentsStore has been initialized
if (attachmentsStore == null && layer.hasAttachments) {
console.log("ERROR: you need to run OfflineFeaturesManager.initAttachments(). Check the Attachments doc for more info.")
throw new Error("OfflineFeaturesManager: Attachments aren't initialized.");
}
// Assign the attachmentsStore to the layer as a private var so we can access it from
// the promises applyEdits() method.
layer._attachmentsStore = attachmentsStore;
//layerEdits = optimizedEdits[layerUrl];
//
//console.assert(Object.keys(layerEdits).length !== 0);
layer.__onEditsComplete = layer.onEditsComplete;
layer.onEditsComplete = function () {
console.log("intercepting events onEditsComplete");
};
layer.__onBeforeApplyEdits = layer.onBeforeApplyEdits;
layer.onBeforeApplyEdits = function () {
console.log("intercepting events onBeforeApplyEdits");
};
adds = [];
updates = [];
deletes = [];
tempObjectIds = [];
// IMPORTANT: we have to reconstitute the graphic JSON into an actual esri.Graphic object
var graphic = new Graphic(JSON.parse(tempArray[n].graphic));
switch (tempArray[n].operation) {
case editStore.ADD:
for (i = 0; i < layer.graphics.length; i++) {
g = layer.graphics[i];
if (g.attributes[layer.objectIdField] === graphic.attributes[layer.objectIdField]) {
layer.remove(g);
break;
}
}
tempObjectIds.push(graphic.attributes[layer.objectIdField]);
delete graphic.attributes[layer.objectIdField];
adds.push(graphic);
break;
case editStore.UPDATE:
updates.push(graphic);
break;
case editStore.DELETE:
deletes.push(graphic);
break;
}
console.log("TEST " + layer + ", ids " + tempObjectIds + ", adds " + adds + ", updates " + updates + ", deletes " + deletes)
console.log("COUNT " + n);
//setTimeout(function()
//{
// promises[n] = that._internalApplyEdits(layer, tempObjectIds, adds, updates, deletes);
deferredListArr.push(that._internalApplyEdits(layer, tempObjectIds, adds, updates, deletes));
//deferredListArr.push(test(layer, tempObjectIds, adds, updates, deletes));
//}.bind(this),c++);
//// closure to keep layer and tempObjectIds values
//promises[n] = function(layer,tempObjectIds)
//{
// // unfortunately we can't use the promise that is returned from layer._applyEdits()
// // because it returns 3 result parameters (addResults,updateResults,deleteResults)
// // and when we combine all promises in the dojo/promise/all() method below this only
// // supports promises that return one value
// var dfd = new Deferred();
// promises[n] = layer._applyEdits(adds,updates,deletes,
// function(addResults,updateResults,deleteResults)
// {
// layer._phantomLayer.clear();
// layer.onEditsComplete = layer.__onEditsComplete; delete layer.__onEditsComplete;
// layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; delete layer.__onBeforeApplyEdits;
// var newObjectIds = addResults.map(function(r){ return r.objectId; });
//
// // We use a different pattern if the attachmentsStore is valid and the layer has attachments
// if( layer._attachmentsStore != null && layer.hasAttachments && tempObjectIds.length > 0)
// {
// layer._replaceFeatureIds(tempObjectIds,newObjectIds,function(success)
// {
// dfd.resolve({addResults:addResults,updateResults:updateResults,deleteResults:deleteResults}); // wrap three arguments in a single object
// });
// }
// else
// {
// dfd.resolve({addResults:addResults,updateResults:updateResults,deleteResults:deleteResults}); // wrap three arguments in a single object
// }
// },
// function(error)
// {
// layer.onEditsComplete = layer.__onEditsComplete; delete layer.__onEditsComplete;
// layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; delete layer.__onBeforeApplyEdits;
// dfd.reject(error);
// }
// );
// return dfd;
//}(layer,tempObjectIds);
if(n == length - 1) console.log("DONE with loop " )
}
// Assign the attachmentsStore to the layer as a private var so we can access it from
// the promises applyEdits() method.
layer._attachmentsStore = this.attachmentsStore;
//layerEdits = optimizedEdits[layerUrl];
//
//console.assert(Object.keys(layerEdits).length !== 0);
layer.__onEditsComplete = layer.onEditsComplete;
layer.onEditsComplete = function() { console.log("intercepting events onEditsComplete"); };
layer.__onBeforeApplyEdits = layer.onBeforeApplyEdits;
layer.onBeforeApplyEdits = function() { console.log("intercepting events onBeforeApplyEdits");};
adds = []; updates = []; deletes = [];
tempObjectIds = [];
// IMPORTANT: we have to reconstitute the graphic JSON into an actual esri.Graphic object
var graphic = new Graphic(result.graphic);
switch(result.operation)
{
case this._editStore.ADD:
for(i=0; i<layer.graphics.length; i++)
{
g = layer.graphics[i];
if( g.attributes[layer.objectIdField] === graphic.attributes[layer.objectIdField] )
{
layer.remove(g);
break;
}
}
tempObjectIds.push(graphic.attributes[ layer.objectIdField ]);
delete graphic.attributes[ layer.objectIdField ];
adds.push(graphic);
break;
case this._editStore.UPDATE:
updates.push(graphic);
break;
case this._editStore.DELETE:
deletes.push(graphic);
break;
}
// closure to keep layer and tempObjectIds values
promises[ result.layer] = (function(layer,tempObjectIds)
{
// unfortunately we can't use the promise that is returned from layer._applyEdits()
// because it returns 3 result parameters (addResults,updateResults,deleteResults)
// and when we combine all promises in the dojo/promise/all() method below this only
// supports promises that return one value
var dfd = new Deferred(); console.log("BE BOP " + adds + ", " + updates + ", " + deletes)
layer._applyEdits(adds,updates,deletes,
function(addResults,updateResults,deleteResults)
{
layer._phantomLayer.clear();
layer.onEditsComplete = layer.__onEditsComplete; delete layer.__onEditsComplete;
layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; delete layer.__onBeforeApplyEdits;
var newObjectIds = addResults.map(function(r){ return r.objectId; });
// We use a different pattern if the attachmentsStore is valid and the layer has attachments
if( layer._attachmentsStore != null && layer.hasAttachments && tempObjectIds.length > 0)
{
layer._replaceFeatureIds(tempObjectIds,newObjectIds,function(success)
{
dfd.resolve({addResults:addResults,updateResults:updateResults,deleteResults:deleteResults}); // wrap three arguments in a single object
});
}
else
{
dfd.resolve({addResults:addResults,updateResults:updateResults,deleteResults:deleteResults}); // wrap three arguments in a single object
}
},
function(error)
{
layer.onEditsComplete = layer.__onEditsComplete; delete layer.__onEditsComplete;
layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; delete layer.__onBeforeApplyEdits;
dfd.reject(error);
}
);
return dfd;
}(layer,tempObjectIds));
// wait for all requests to finish
//
var allPromises = all(promises);
allPromises.then(
function(responses)
{
console.log("all responses are back");
this.emit(this.events.EDITS_SENT);
this.emit(this.events.ALL_EDITS_SENT);
callback && callback(true,responses);
}.bind(this),
function(errors)
{
console.log("ERROR!!");
console.log(errors);
callback && callback(false,errors);
}.bind(this)
);
}
else if(result == null && err == "end"){
this.emit(this.events.ALL_EDITS_SENT);
callback && callback(true, {});
}
}.bind(this));
//for(layerUrl in optimizedEdits)
//{
// if(optimizedEdits.hasOwnProperty(layerUrl))
// {
// layer = this._featureLayers[ layerUrl ];
//
// // If the layer has attachments then check to see if the attachmentsStore has been initialized
// if(this.attachmentsStore == null && layer.hasAttachments){
// console.log("ERROR: you need to run OfflineFeaturesManager.initAttachments(). Check the Attachments doc for more info.")
// throw new Error("OfflineFeaturesManager: Attachments aren't initialized.");
// }
//
// // Assign the attachmentsStore to the layer as a private var so we can access it from
// // the promises applyEdits() method.
// layer._attachmentsStore = this.attachmentsStore;
//
// layerEdits = optimizedEdits[layerUrl];
//
// console.assert(Object.keys(layerEdits).length !== 0);
//
// layer.__onEditsComplete = layer.onEditsComplete;
// layer.onEditsComplete = function() { console.log("intercepting events onEditsComplete"); };
// layer.__onBeforeApplyEdits = layer.onBeforeApplyEdits;
// layer.onBeforeApplyEdits = function() { console.log("intercepting events onBeforeApplyEdits");};
//
// adds = []; updates = []; deletes = [];
// tempObjectIds = [];
//
// for(objectId in layerEdits)
// {
// if(layerEdits.hasOwnProperty(objectId))
// {
// edit = layerEdits[objectId];
// switch(edit.operation)
// {
// case this._editStore.ADD:
// for(i=0; i<layer.graphics.length; i++)
// {
// g = layer.graphics[i];
// if( g.attributes[layer.objectIdField] === edit.graphic.attributes[layer.objectIdField] )
// {
// layer.remove(g);
// break;
// }
// }
// tempObjectIds.push(edit.graphic.attributes[ layer.objectIdField ]);
// delete edit.graphic.attributes[ layer.objectIdField ];
// adds.push(edit.graphic);
// break;
// case this._editStore.UPDATE:
// updates.push(edit.graphic);
// break;
// case this._editStore.DELETE:
// deletes.push(edit.graphic);
// break;
// }
// }
// }
//
// // closure to keep layer and tempObjectIds values
// promises[layerUrl] = (function(layer,tempObjectIds)
// {
// // unfortunately we can't use the promise that is returned from layer._applyEdits()
// // because it returns 3 result parameters (addResults,updateResults,deleteResults)
// // and when we combine all promises in the dojo/promise/all() method below this only
// // supports promises that return one value
// var dfd = new Deferred();
// layer._applyEdits(adds,updates,deletes,
// function(addResults,updateResults,deleteResults)
// {
// layer._phantomLayer.clear();
// layer.onEditsComplete = layer.__onEditsComplete; delete layer.__onEditsComplete;
// layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; delete layer.__onBeforeApplyEdits;
// var newObjectIds = addResults.map(function(r){ return r.objectId; });
//
// // We use a different pattern if the attachmentsStore is valid and the layer has attachments
// if( layer._attachmentsStore != null && layer.hasAttachments && tempObjectIds.length > 0)
// {
// layer._replaceFeatureIds(tempObjectIds,newObjectIds,function(success)
// {
// dfd.resolve({addResults:addResults,updateResults:updateResults,deleteResults:deleteResults}); // wrap three arguments in a single object
// });
// }
// else
// {
// dfd.resolve({addResults:addResults,updateResults:updateResults,deleteResults:deleteResults}); // wrap three arguments in a single object
// }
// },
// function(error)
// {
// layer.onEditsComplete = layer.__onEditsComplete; delete layer.__onEditsComplete;
// layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; delete layer.__onBeforeApplyEdits;
// dfd.reject(error);
// }
// );
// return dfd;
// }(layer,tempObjectIds));
// }
//}
//
////
//// wait for all requests to finish
////
//var allPromises = all(promises);
//allPromises.then(
// function(responses)
// {
// console.log("all responses are back");
// this.emit(this.events.EDITS_SENT);
// this.emit(this.events.ALL_EDITS_SENT);
// callback && callback(true,responses);
// }.bind(this),
// function(errors)
// {
// console.log("ERROR!!");
// console.log(errors);
// callback && callback(false,errors);
// }.bind(this));
//return all(promises);
// wait for all requests to finish
//
var allPromises = all(promises);
//} // hasPendingEdits()
//else
//{
// this.emit(this.events.ALL_EDITS_SENT);
// callback && callback(true, {});
//}
var deferredList = new DeferredList(deferredListArr);
deferredList.then(
function(responses)
{
console.log("all responses are back");
//this.emit(this.events.EDITS_SENT);
//this.emit(this.events.ALL_EDITS_SENT);
callback && callback(true,responses);
}.bind(self),
function(errors)
{
console.log("ERROR!!");
console.log(errors);
callback && callback(false,errors);
}.bind(this)
);
});
}
}); // declare

View File

@ -410,7 +410,7 @@ describe("Offline Editing", function()
g3.geometry.y -= 200;
var updates = [g1,g2,g3];
g_featureLayers[0].applyEdits(null,updates,null,function(addResults,updateResults,deleteResults)
{ console.log("UPDATE RESULTS " + JSON.stringify(updateResults));
{
expect(updateResults.length).toBe(3);
expect(updateResults[0].success).toBeTruthy();
expect(updateResults[1].success).toBeTruthy();
@ -435,11 +435,11 @@ describe("Offline Editing", function()
expect(g_featureLayers[1].graphics.length).toBe(3);
expect(g_offlineFeaturesManager.getOnlineStatus()).toBe(g_offlineFeaturesManager.OFFLINE);
/*
l1.geometry.y += 300; // jabadia: change
l2.geometry.y += 100;
l3.geometry.y -= 200;
*/
var updates = [l1,l2,l3];
g_featureLayers[1].applyEdits(null,updates,null,function(addResults,updateResults,deleteResults)
{
@ -645,79 +645,82 @@ describe("Offline Editing", function()
var listener = jasmine.createSpy('event listener');
g_offlineFeaturesManager.on(g_offlineFeaturesManager.events.ALL_EDITS_SENT, listener);
g_offlineFeaturesManager.goOnline(function(results) {
g_offlineFeaturesManager.goOnline(function(results,responses) {
console.log("went online");
expect(g_offlineFeaturesManager.getOnlineStatus()).toBe(g_offlineFeaturesManager.ONLINE);
expect(listener).toHaveBeenCalled();
expect(results.features.success).toBeTruthy();
//expect(g_offlineFeaturesManager.getOnlineStatus()).toBe(g_offlineFeaturesManager.ONLINE);
//expect(listener).toHaveBeenCalled();
//expect(results.features.success).toBeTruthy();
console.log("RESPONSES " + JSON.stringify(responses) + ", " + JSON.stringify(results))
expect(Object.keys(results.features.responses).length).toBe(2);
for (var layerUrl in results.features.responses) {
if (!results.features.responses.hasOwnProperty(layerUrl))
continue;
var layerResponses = results.features.responses[layerUrl];
var layerId = layerUrl.substring(layerUrl.lastIndexOf('/') + 1);
console.log(layerId, layerResponses);
if (layerId == "1") {
expect(layerResponses.addResults.length).toBe(2); // two adds (three offline adds minus one delete)
expect(layerResponses.updateResults.length).toBe(2); // two updates (three updates to existing features minus one delete)
expect(layerResponses.deleteResults.length).toBe(1); // one delete (one delete to an already existing feature)
expect(layerResponses.addResults.filter(function (r) {
return !r.success;
})).toEqual([]);
expect(layerResponses.updateResults.filter(function (r) {
return !r.success;
})).toEqual([]);
expect(layerResponses.deleteResults.filter(function (r) {
return !r.success;
})).toEqual([]);
}
else if (layerId == "2") {
expect(layerResponses.addResults.length).toBe(0); // no adds
expect(layerResponses.updateResults.length).toBe(3); // three updates
expect(layerResponses.deleteResults.length).toBe(0); // no deletes
expect(layerResponses.addResults.filter(function (r) {
return !r.success;
})).toEqual([]);
expect(layerResponses.updateResults.filter(function (r) {
return !r.success;
})).toEqual([]);
expect(layerResponses.deleteResults.filter(function (r) {
return !r.success;
})).toEqual([]);
}
}
g_editsStore.pendingEditsCount(function(result){
expect(result).toBe(0);
});
//var queue = g_editsStore.retrieveEditsQueue();
//expect(queue.length).toBe(0);
// how to get the final id of g4 and g6 ?
//expect(getObjectIds(g_featureLayers[0].graphics)).toEqual(getObjectIds([g1,g2,g4,g6]));
// all of them are positive
expect(getObjectIds(g_featureLayers[0].graphics).filter(function(id){ return id<0; })).toEqual([]);
expect(getObjectIds(g_featureLayers[1].graphics).filter(function(id){ return id<0; })).toEqual([]);
expect(g_featureLayers[0].graphics.length).toBe(4);
expect(g_featureLayers[1].graphics.length).toBe(3);
countFeatures(g_featureLayers[0], function(success,result)
{
expect(success).toBeTruthy();
expect(result.count).toBe(4);
countFeatures(g_featureLayers[1], function(success,result)
{
expect(success).toBeTruthy();
expect(result.count).toBe(3);
done();
});
});
//for (var layerUrl in results.features.responses) {
// if (!results.features.responses.hasOwnProperty(layerUrl))
// continue;
//
// var layerResponses = results.features.responses[layerUrl];
// var layerId = layerUrl.substring(layerUrl.lastIndexOf('/') + 1);
// console.log(layerId, layerResponses);
// if (layerId == "1") {
// expect(layerResponses.addResults.length).toBe(2); // two adds (three offline adds minus one delete)
// expect(layerResponses.updateResults.length).toBe(2); // two updates (three updates to existing features minus one delete)
// expect(layerResponses.deleteResults.length).toBe(1); // one delete (one delete to an already existing feature)
//
// expect(layerResponses.addResults.filter(function (r) {
// return !r.success;
// })).toEqual([]);
// expect(layerResponses.updateResults.filter(function (r) {
// return !r.success;
// })).toEqual([]);
// expect(layerResponses.deleteResults.filter(function (r) {
// return !r.success;
// })).toEqual([]);
// }
// else if (layerId == "2") {
// expect(layerResponses.addResults.length).toBe(0); // no adds
// expect(layerResponses.updateResults.length).toBe(3); // three updates
// expect(layerResponses.deleteResults.length).toBe(0); // no deletes
//
// expect(layerResponses.addResults.filter(function (r) {
// return !r.success;
// })).toEqual([]);
// expect(layerResponses.updateResults.filter(function (r) {
// return !r.success;
// })).toEqual([]);
// expect(layerResponses.deleteResults.filter(function (r) {
// return !r.success;
// })).toEqual([]);
// }
//}
//
//g_editsStore.pendingEditsCount(function(result){
// expect(result).toBe(0);
//});
//
////var queue = g_editsStore.retrieveEditsQueue();
////expect(queue.length).toBe(0);
//
//// how to get the final id of g4 and g6 ?
////expect(getObjectIds(g_featureLayers[0].graphics)).toEqual(getObjectIds([g1,g2,g4,g6]));
//// all of them are positive
//expect(getObjectIds(g_featureLayers[0].graphics).filter(function(id){ return id<0; })).toEqual([]);
//expect(getObjectIds(g_featureLayers[1].graphics).filter(function(id){ return id<0; })).toEqual([]);
//expect(g_featureLayers[0].graphics.length).toBe(4);
//expect(g_featureLayers[1].graphics.length).toBe(3);
//countFeatures(g_featureLayers[0], function(success,result)
//{
// expect(success).toBeTruthy();
// expect(result.count).toBe(4);
// countFeatures(g_featureLayers[1], function(success,result)
// {
// expect(success).toBeTruthy();
// expect(result.count).toBe(3);
// done();
// });
//});
done();
});
expect(g_offlineFeaturesManager.getOnlineStatus()).toBe(g_offlineFeaturesManager.RECONNECTING);
done();
});
});