326 lines
11 KiB
JavaScript
326 lines
11 KiB
JavaScript
|
var _ = require('underscore');
|
||
|
var Backbone = require('backbone');
|
||
|
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||
|
var ConfigModel = require('builder/data/config-model');
|
||
|
var UserModel = require('builder/data/user-model');
|
||
|
var FeatureDefinitionModel = require('builder/data/feature-definition-model');
|
||
|
var AnalysisDefinitionNodesCollection = require('builder/data/analysis-definition-nodes-collection');
|
||
|
|
||
|
describe('data/feature-definition-model', function () {
|
||
|
var userModel;
|
||
|
var configModel;
|
||
|
var layerDefinitionsCollection;
|
||
|
var layerDefinitionModel;
|
||
|
|
||
|
beforeEach(function () {
|
||
|
spyOn(_, 'debounce').and.callFake(function (func) {
|
||
|
return function () {
|
||
|
func.apply(this, arguments);
|
||
|
};
|
||
|
});
|
||
|
|
||
|
configModel = new ConfigModel({
|
||
|
base_url: '/u/pepe'
|
||
|
});
|
||
|
userModel = new UserModel({}, {
|
||
|
configModel: configModel
|
||
|
});
|
||
|
|
||
|
var analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
|
||
|
configModel: configModel,
|
||
|
userModel: userModel
|
||
|
});
|
||
|
|
||
|
layerDefinitionsCollection = new LayerDefinitionsCollection(null, {
|
||
|
configModel: configModel,
|
||
|
userModel: userModel,
|
||
|
analysisDefinitionNodesCollection: analysisDefinitionNodesCollection,
|
||
|
mapId: 'm-123',
|
||
|
stateDefinitionModel: {}
|
||
|
});
|
||
|
layerDefinitionsCollection.add({
|
||
|
id: 'l-1',
|
||
|
kind: 'carto',
|
||
|
options: {
|
||
|
table_name: 'foo'
|
||
|
}
|
||
|
});
|
||
|
layerDefinitionModel = layerDefinitionsCollection.at(0);
|
||
|
layerDefinitionModel.getColumnNamesFromSchema = function () { return ['name', 'country', 'the_geom']; };
|
||
|
|
||
|
this.feature = new FeatureDefinitionModel({
|
||
|
cartodb_id: '12345',
|
||
|
name: 'Madrid',
|
||
|
country: 'Spain'
|
||
|
}, {
|
||
|
configModel: configModel,
|
||
|
layerDefinitionModel: layerDefinitionModel,
|
||
|
userModel: userModel
|
||
|
});
|
||
|
|
||
|
this.fakeQueryRowModel = jasmine.createSpyObj('fakeQueryRowModel', ['save', 'fetch', 'destroy']);
|
||
|
spyOn(this.feature, '_getQueryRowModel').and.returnValue(this.fakeQueryRowModel);
|
||
|
});
|
||
|
|
||
|
it('should create _changesHistory at the beginning', function () {
|
||
|
expect(this.feature._changesHistory).toEqual([]);
|
||
|
});
|
||
|
|
||
|
describe('change bind', function () {
|
||
|
it('should set at the beginning if model is new', function () {
|
||
|
spyOn(FeatureDefinitionModel.prototype, '_bindChangeEvent');
|
||
|
var feature = new FeatureDefinitionModel({}, {
|
||
|
configModel: configModel,
|
||
|
layerDefinitionModel: layerDefinitionModel,
|
||
|
userModel: userModel
|
||
|
});
|
||
|
expect(FeatureDefinitionModel.prototype._bindChangeEvent).toHaveBeenCalled();
|
||
|
expect(feature.isNew()).toBeTruthy();
|
||
|
});
|
||
|
|
||
|
it('should not be set at the beginning if model is not new', function () {
|
||
|
spyOn(FeatureDefinitionModel.prototype, '_bindChangeEvent');
|
||
|
var feature = new FeatureDefinitionModel({
|
||
|
cartodb_id: 1
|
||
|
}, {
|
||
|
configModel: configModel,
|
||
|
layerDefinitionModel: layerDefinitionModel,
|
||
|
userModel: userModel
|
||
|
});
|
||
|
expect(FeatureDefinitionModel.prototype._bindChangeEvent).not.toHaveBeenCalled();
|
||
|
expect(feature.isNew()).toBeFalsy();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('.fetch', function () {
|
||
|
describe('on success', function () {
|
||
|
beforeEach(function () {
|
||
|
this.fakeQueryRowModel.fetch.and.callFake(function (options) {
|
||
|
options && options.success(
|
||
|
new Backbone.Model({
|
||
|
cartodb_id: '3',
|
||
|
the_geom: '{whatever}'
|
||
|
})
|
||
|
);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should fetch from query row model', function () {
|
||
|
this.feature.fetch();
|
||
|
expect(this.fakeQueryRowModel.fetch).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should unbind change binding', function () {
|
||
|
spyOn(this.feature, '_unbindChangeEvent');
|
||
|
this.feature.fetch();
|
||
|
expect(this.feature._unbindChangeEvent).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should set properties after fetch', function () {
|
||
|
expect(this.feature.get('cartodb_id')).toBe('12345');
|
||
|
this.feature.fetch();
|
||
|
expect(this.feature.get('cartodb_id')).toBe('3');
|
||
|
});
|
||
|
|
||
|
it('should listen changes after fetching successfully', function () {
|
||
|
spyOn(this.feature, '_onChange');
|
||
|
this.feature.fetch();
|
||
|
this.feature.set('cartodb_id', 'hello');
|
||
|
expect(this.feature._onChange).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should add to changesHistory all changed attributes after fetching', function () {
|
||
|
this.feature.fetch();
|
||
|
this.feature.set('cartodb_id', 'hey');
|
||
|
expect(this.feature._changesHistory).toEqual(['cartodb_id']);
|
||
|
this.feature.set('the_geom', '{}');
|
||
|
expect(this.feature._changesHistory).toEqual(['cartodb_id', 'the_geom']);
|
||
|
this.feature.set('name', 'Barcelona');
|
||
|
expect(this.feature._changesHistory).toEqual(['cartodb_id', 'the_geom', 'name']);
|
||
|
this.feature.set('cartodb_id', '1');
|
||
|
expect(this.feature._changesHistory).toEqual(['cartodb_id', 'the_geom', 'name']);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('.hasBeenChangedAfterLastSaved', function () {
|
||
|
beforeEach(function () {
|
||
|
this.feature._changesHistory = ['the_geom', 'cartodb_id'];
|
||
|
});
|
||
|
|
||
|
it('should return if an attribute has been changed before last saved', function () {
|
||
|
expect(this.feature.hasBeenChangedAfterLastSaved('the_geom')).toBeTruthy();
|
||
|
expect(this.feature.hasBeenChangedAfterLastSaved('name')).toBeFalsy();
|
||
|
expect(this.feature.hasBeenChangedAfterLastSaved('cartodb_id')).toBeTruthy();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._cleanChangesHistory', function () {
|
||
|
beforeEach(function () {
|
||
|
this.feature._changesHistory = ['the_geom', 'cartodb_id'];
|
||
|
});
|
||
|
|
||
|
it('should clean changesHistory', function () {
|
||
|
expect(this.feature.hasBeenChangedAfterLastSaved('the_geom')).toBeTruthy();
|
||
|
expect(this.feature.hasBeenChangedAfterLastSaved('cartodb_id')).toBeTruthy();
|
||
|
this.feature._cleanChangesHistory();
|
||
|
expect(this.feature.hasBeenChangedAfterLastSaved('the_geom')).toBeFalsy();
|
||
|
expect(this.feature.hasBeenChangedAfterLastSaved('cartodb_id')).toBeFalsy();
|
||
|
expect(this.feature._changesHistory).toEqual([]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('.save', function () {
|
||
|
beforeEach(function () {
|
||
|
this.feature._changesHistory = ['the_geom'];
|
||
|
});
|
||
|
|
||
|
it('should save the feature using the query row model', function () {
|
||
|
this.feature.save();
|
||
|
expect(this.fakeQueryRowModel.save).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
describe('when save succeeds', function () {
|
||
|
beforeEach(function () {
|
||
|
this.fakeQueryRowModel.save.and.callFake(function (attrs, options) {
|
||
|
options && options.success(new Backbone.Model(attrs));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should invoke the success callback', function () {
|
||
|
var successCallback = jasmine.createSpy('successCallback');
|
||
|
this.feature.save({
|
||
|
success: successCallback
|
||
|
});
|
||
|
|
||
|
expect(successCallback).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should clean changes history', function () {
|
||
|
this.feature.save();
|
||
|
expect(this.feature._changesHistory.length).toBe(0);
|
||
|
});
|
||
|
|
||
|
it('should trigger a save event', function () {
|
||
|
var saveCallback = jasmine.createSpy('save');
|
||
|
this.feature.on('save', saveCallback);
|
||
|
|
||
|
this.feature.save();
|
||
|
|
||
|
expect(saveCallback).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should update the cartodb_id of the feature when creating a new row', function () {
|
||
|
this.feature.set('cartodb_id', null);
|
||
|
|
||
|
expect(this.feature.isNew()).toBeTruthy();
|
||
|
|
||
|
this.fakeQueryRowModel.save.and.callFake(function (attrs, options) {
|
||
|
attrs = _.extend({}, attrs, {
|
||
|
cartodb_id: '56789'
|
||
|
});
|
||
|
options && options.success(new Backbone.Model(attrs));
|
||
|
});
|
||
|
|
||
|
this.feature.save();
|
||
|
|
||
|
expect(this.fakeQueryRowModel.save.calls.mostRecent().args[0]).toEqual({
|
||
|
name: 'Madrid',
|
||
|
country: 'Spain'
|
||
|
});
|
||
|
expect(this.feature.get('cartodb_id')).toEqual('56789');
|
||
|
});
|
||
|
|
||
|
it('should NOT update the cartodb_id of the feature when updating an existing row', function () {
|
||
|
expect(this.feature.get('cartodb_id')).toEqual('12345');
|
||
|
|
||
|
// Row is updated and it returns a different cartodb_id. This will never happen
|
||
|
// in The Real World, but it helps in this test
|
||
|
this.fakeQueryRowModel.save.and.callFake(function (attrs, options) {
|
||
|
attrs = _.extend({}, attrs, {
|
||
|
cartodb_id: '56789'
|
||
|
});
|
||
|
options && options.success(new Backbone.Model(attrs));
|
||
|
});
|
||
|
|
||
|
this.feature.save();
|
||
|
|
||
|
expect(this.fakeQueryRowModel.save.calls.mostRecent().args[0]).toEqual({
|
||
|
name: 'Madrid',
|
||
|
country: 'Spain'
|
||
|
});
|
||
|
expect(this.feature.get('cartodb_id')).toEqual('12345');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when save fails', function () {
|
||
|
beforeEach(function () {
|
||
|
this.fakeQueryRowModel.save.and.callFake(function (attrs, options) {
|
||
|
options && options.error();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should invoke the error callback', function () {
|
||
|
var errorCallback = jasmine.createSpy('errorCallback');
|
||
|
this.feature.save({
|
||
|
error: errorCallback
|
||
|
});
|
||
|
|
||
|
expect(errorCallback).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should not clean changes history', function () {
|
||
|
this.feature.save();
|
||
|
expect(this.feature._changesHistory.length).toBe(1);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('.destroy', function () {
|
||
|
describe('when destroy succeeds', function () {
|
||
|
beforeEach(function () {
|
||
|
this.fakeQueryRowModel.destroy.and.callFake(function (options) {
|
||
|
options && options.success();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should invoke the success callback', function () {
|
||
|
var successCallback = jasmine.createSpy('successCallback');
|
||
|
|
||
|
this.feature.destroy({
|
||
|
success: successCallback
|
||
|
});
|
||
|
|
||
|
expect(successCallback).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should trigger an event', function () {
|
||
|
var onRemoveCallback = jasmine.createSpy('onRemoveCallback');
|
||
|
this.feature.on('remove', onRemoveCallback);
|
||
|
|
||
|
this.feature.destroy();
|
||
|
|
||
|
expect(onRemoveCallback).toHaveBeenCalled();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when destroy fails', function () {
|
||
|
beforeEach(function () {
|
||
|
this.fakeQueryRowModel.destroy.and.callFake(function (options) {
|
||
|
options && options.error();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should invoke the error callback', function () {
|
||
|
var errorCallback = jasmine.createSpy('errorCallback');
|
||
|
|
||
|
this.feature.destroy({
|
||
|
error: errorCallback
|
||
|
});
|
||
|
|
||
|
expect(errorCallback).toHaveBeenCalled();
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|