Initial commit
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
var Backbone = require('backbone');
|
||||
var moment = require('moment');
|
||||
var TimeSeriesQueryModel = require('builder/editor/widgets/time-series-query-model');
|
||||
|
||||
describe('editor/widgets/time-series-query-model', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new Backbone.Model({
|
||||
user_name: '/u/pepe',
|
||||
sql_api_template: 'SELECT * from test;',
|
||||
api_key: '1238asd234239asd89asd123'
|
||||
});
|
||||
|
||||
var querySchemaModel = new Backbone.Model({
|
||||
status: 'fetched'
|
||||
});
|
||||
|
||||
querySchemaModel.getColumnType = function () {
|
||||
return 'date';
|
||||
};
|
||||
|
||||
this.model = new TimeSeriesQueryModel({
|
||||
column: 'cartodb_id'
|
||||
}, {
|
||||
configModel: configModel,
|
||||
querySchemaModel: querySchemaModel
|
||||
});
|
||||
});
|
||||
|
||||
it('should call _queryData when change:column', function () {
|
||||
spyOn(this.model, '_queryData');
|
||||
this.model._initBinds();
|
||||
this.model.trigger('change:column');
|
||||
|
||||
expect(this.model._queryData).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call _onQuerySchemaStatusChanged when _querySchemaModel change:status', function () {
|
||||
spyOn(this.model, '_onQuerySchemaStatusChanged');
|
||||
this.model._initBinds();
|
||||
this.model._querySchemaModel.trigger('change:status');
|
||||
|
||||
expect(this.model._onQuerySchemaStatusChanged).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('._onQuerySchemaStatusChanged', function () {
|
||||
it('should call ._queryData if _querySchemaModel is fetched', function () {
|
||||
spyOn(this.model, '_queryData');
|
||||
|
||||
this.model._querySchemaModel.set('status', 'unfetched');
|
||||
this.model._onQuerySchemaStatusChanged();
|
||||
expect(this.model._queryData).not.toHaveBeenCalled();
|
||||
|
||||
this.model._querySchemaModel.set('status', 'fetched');
|
||||
this.model._onQuerySchemaStatusChanged();
|
||||
expect(this.model._queryData).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._queryData', function () {
|
||||
it('should set the status to fetching', function () {
|
||||
spyOn(this.model._SQL, 'execute');
|
||||
this.model.set('status', 'unfetched');
|
||||
this.model._queryData();
|
||||
expect(this.model.get('status')).toEqual('fetching');
|
||||
});
|
||||
|
||||
it('should call _SQL.execute', function () {
|
||||
spyOn(this.model._SQL, 'execute');
|
||||
this.model._queryData();
|
||||
expect(this.model._SQL.execute).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._onQuerySuccess', function () {
|
||||
it('should set the status to fetched', function () {
|
||||
this.model._onQuerySuccess({});
|
||||
expect(this.model.get('status')).toEqual('fetched');
|
||||
});
|
||||
|
||||
it('should call ._calculateBuckets', function () {
|
||||
spyOn(this.model, '_calculateBuckets');
|
||||
this.model._onQuerySuccess({});
|
||||
expect(this.model._calculateBuckets).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._onQueryError', function () {
|
||||
it('should set the status to unavailable', function () {
|
||||
this.model._onQueryError({});
|
||||
expect(this.model.get('status')).toEqual('unavailable');
|
||||
});
|
||||
});
|
||||
|
||||
describe('._calculateBuckets', function () {
|
||||
it('sets the buckets with the correct values', function () {
|
||||
this.model._calculateBuckets(1483228800000, 1451606400000); // 2016-01-01 to 2017-01-01
|
||||
var expected = [
|
||||
{ bins: 527041, val: 'minute', label: 'Minutes' },
|
||||
{ bins: 8785, val: 'hour', 'label': 'Hours' },
|
||||
{ bins: 367, val: 'day', label: 'Days' },
|
||||
{ bins: 54, val: 'week', label: 'Weeks' },
|
||||
{ bins: 13, val: 'month', label: 'Months' },
|
||||
{ bins: 5, val: 'quarter', label: 'Quarters' },
|
||||
{ bins: 2, val: 'year', label: 'Years' },
|
||||
{ bins: 1, val: 'decade', label: 'Decades' }
|
||||
];
|
||||
expect(this.model.get('buckets')).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should get the right decades value', function () {
|
||||
this.model._calculateBuckets(946684800000, 283996800000); // 1979 to 2000
|
||||
var expectedDecades = 4; // 70s, 80s, 90s, 00s
|
||||
var buckets = this.model.get('buckets');
|
||||
|
||||
expect(buckets[7].val).toEqual('decade');
|
||||
expect(buckets[7].bins).toBe(expectedDecades);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._calculateDecadesDiff', function () {
|
||||
function fromYear (year) {
|
||||
var dateString = year.toString() + '-01-01';
|
||||
return moment(dateString);
|
||||
}
|
||||
|
||||
function assertDecadeDiff (startYear, endYear, expectedDiff) {
|
||||
var diff = this.model._calculateDecadesDiff(fromYear(startYear), fromYear(endYear));
|
||||
expect(diff).toBe(expectedDiff);
|
||||
}
|
||||
|
||||
it('should return proper values', function () {
|
||||
var assertDiff = assertDecadeDiff.bind(this);
|
||||
|
||||
assertDiff(1970, 1970, 1);
|
||||
assertDiff(1970, 1979, 1);
|
||||
assertDiff(1970, 1980, 2);
|
||||
assertDiff(1970, 1999, 3);
|
||||
assertDiff(1970, 2000, 4);
|
||||
assertDiff(1500, 1999, 50);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getFilteredBuckets', function () {
|
||||
it('should return the buckets below the limit', function () {
|
||||
this.model._calculateBuckets(1483228800000, 1451606400000);
|
||||
var filteredBuckets = this.model.getFilteredBuckets(367); // Maximum 367 bins
|
||||
var expected = [
|
||||
{ bins: 367, val: 'day', label: 'Days' },
|
||||
{ bins: 54, val: 'week', label: 'Weeks' },
|
||||
{ bins: 13, val: 'month', label: 'Months' },
|
||||
{ bins: 5, val: 'quarter', label: 'Quarters' },
|
||||
{ bins: 2, val: 'year', label: 'Years' },
|
||||
{ bins: 1, val: 'decade', label: 'Decades' }
|
||||
];
|
||||
expect(filteredBuckets).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getPreferredBucket', function () {
|
||||
it('should return the bucket closer to the max bins', function () {
|
||||
this.model._calculateBuckets(1483228800000, 1451606400000);
|
||||
var preferredBucket = this.model.getPreferredBucket(367); // Maximum 367 bins
|
||||
var expected = { bins: 367, val: 'day', label: 'Days' };
|
||||
expect(preferredBucket).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
var $ = require('jquery');
|
||||
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||||
var EditorWidgetView = require('builder/editor/widgets/widget-view');
|
||||
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
|
||||
var WidgetsService = require('builder/editor/widgets/widgets-service');
|
||||
var Router = require('builder/routes/router');
|
||||
var FactoryModals = require('../../factories/modals');
|
||||
|
||||
var ENTER_KEY_CODE = 13;
|
||||
var WIDGET_DEFINITION = {
|
||||
type: 'formula',
|
||||
title: 'AVG districts homes',
|
||||
column: 'areas',
|
||||
operation: 'avg',
|
||||
layer_id: 'l-1',
|
||||
source: 'a0'
|
||||
};
|
||||
var LAYER_DEFINITION = {
|
||||
id: 'l-1',
|
||||
options: {
|
||||
type: 'CartoDB',
|
||||
color: 'red',
|
||||
name: 'Layer Name',
|
||||
table_name: 'table_name'
|
||||
}
|
||||
};
|
||||
|
||||
var ANALYSIS_NODE_SOURCE = {
|
||||
get: function () {
|
||||
return 'Source';
|
||||
},
|
||||
isSourceType: function () {
|
||||
return true;
|
||||
},
|
||||
getColor: function () {
|
||||
return '#fabada';
|
||||
}
|
||||
};
|
||||
|
||||
var ANALYSIS_NODE_NO_SOURCE = {
|
||||
get: function () {
|
||||
return 'Sampling';
|
||||
},
|
||||
isSourceType: function () {
|
||||
return false;
|
||||
},
|
||||
getColor: function () {
|
||||
return '#fabada';
|
||||
}
|
||||
};
|
||||
|
||||
describe('editor/widgets/widget-view', function () {
|
||||
var layerDefinitionModel;
|
||||
var stackLayoutModel;
|
||||
var widgetDefinitionModel;
|
||||
|
||||
beforeEach(function () {
|
||||
jasmine.clock().install();
|
||||
spyOn(Router, 'navigate');
|
||||
|
||||
widgetDefinitionModel = new WidgetDefinitionModel(WIDGET_DEFINITION, {
|
||||
configModel: {},
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
layerDefinitionModel = new LayerDefinitionModel(LAYER_DEFINITION, {
|
||||
parse: true,
|
||||
configModel: {}
|
||||
});
|
||||
layerDefinitionModel.findAnalysisDefinitionNodeModel = function () {
|
||||
return ANALYSIS_NODE_SOURCE;
|
||||
};
|
||||
|
||||
stackLayoutModel = jasmine.createSpyObj('stackLayoutModel', ['nextStep']);
|
||||
|
||||
spyOn(EditorWidgetView.prototype, '_renameWidget');
|
||||
|
||||
this.view = new EditorWidgetView({
|
||||
modals: FactoryModals.createModalService(),
|
||||
userActions: {},
|
||||
model: widgetDefinitionModel,
|
||||
layer: layerDefinitionModel,
|
||||
stackLayoutModel: stackLayoutModel,
|
||||
querySchemaModel: {}
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.clock().uninstall();
|
||||
this.view.remove();
|
||||
});
|
||||
|
||||
describe('.render', function () {
|
||||
it('should render correctly', function () {
|
||||
expect(this.view.$el.html()).toContain(WIDGET_DEFINITION.title);
|
||||
expect(this.view.$el.text()).toContain(WIDGET_DEFINITION.source);
|
||||
expect(this.view.$('.js-toggle-menu').length).toBe(1);
|
||||
expect(this.view.$el.html()).toContain(LAYER_DEFINITION.options.table_name);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when node is an analysis', function () {
|
||||
beforeEach(function () {
|
||||
layerDefinitionModel.findAnalysisDefinitionNodeModel = function () {
|
||||
return ANALYSIS_NODE_NO_SOURCE;
|
||||
};
|
||||
this.view.render();
|
||||
});
|
||||
describe('.render', function () {
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$el.html()).toContain('CDB-IconFont-ray');
|
||||
expect(this.view.$el.html()).toContain(LAYER_DEFINITION.options.name);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should contain js-widgetItem class', function () {
|
||||
expect(this.view.$el.hasClass('js-widgetItem')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should add a data attribute with the model cid', function () {
|
||||
expect(this.view.$el.data('model-cid')).toBe(widgetDefinitionModel.cid);
|
||||
});
|
||||
|
||||
it('should show context menu', function () {
|
||||
this.view.$('.js-toggle-menu').click();
|
||||
expect(this.view._contextMenuFactory.getContextMenu().$('[data-val="rename-widget"]').length).toBe(1);
|
||||
expect(this.view._contextMenuFactory.getContextMenu().$('[data-val="delete-widget"]').length).toBe(1);
|
||||
document.body.removeChild(this.view._contextMenuFactory.getContextMenu().el);
|
||||
});
|
||||
|
||||
it('should rename', function () {
|
||||
var event = $.Event('keyup');
|
||||
event.which = ENTER_KEY_CODE;
|
||||
|
||||
this.view.$('.js-toggle-menu').click();
|
||||
this.view._contextMenuFactory.getContextMenu().$('[data-val="rename-widget"]').click();
|
||||
this.view.$('.js-input').val('foo').trigger('keyup');
|
||||
this.view.$('.js-input').trigger(event);
|
||||
expect(EditorWidgetView.prototype._renameWidget).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when clicking on remove', function () {
|
||||
it('should remove widget with WidgetsService', function () {
|
||||
spyOn(WidgetsService, 'removeWidget');
|
||||
this.view.$('.js-toggle-menu').click();
|
||||
this.view._contextMenuFactory.getContextMenu().$('[data-val="delete-widget"]').click();
|
||||
expect(WidgetsService.removeWidget).toHaveBeenCalledWith(widgetDefinitionModel);
|
||||
});
|
||||
});
|
||||
|
||||
it('should edit widget with WidgetsService', function () {
|
||||
spyOn(WidgetsService, 'editWidget');
|
||||
this.view.$('.js-title').trigger('click');
|
||||
jasmine.clock().tick(201);
|
||||
expect(WidgetsService.editWidget).toHaveBeenCalledWith(widgetDefinitionModel);
|
||||
});
|
||||
|
||||
describe('._onDestroy', function () {
|
||||
it('should call Router.goToWidgetList', function () {
|
||||
spyOn(Router, 'goToWidgetList');
|
||||
|
||||
this.view._onDestroy();
|
||||
|
||||
expect(Router.goToWidgetList).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call .clean', function () {
|
||||
spyOn(this.view, 'clean');
|
||||
|
||||
this.view._onDestroy();
|
||||
|
||||
expect(this.view.clean).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
var Backbone = require('backbone');
|
||||
var WidgetsFormBaseSchemaModel = require('builder/editor/widgets/widgets-form/schema/widgets-form-base-schema-model');
|
||||
|
||||
describe('editor/widgets/widgets-form/schema/widgets-form-base-schema-model', function () {
|
||||
var userModel = {
|
||||
featureEnabled: function (whatever) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
it('should transform sync values to values that the form interprets as expected', function () {
|
||||
var model = new WidgetsFormBaseSchemaModel({
|
||||
sync_on_bbox_change: false
|
||||
}, { parse: true, userModel: userModel });
|
||||
expect(model.get('sync_on_bbox_change')).toEqual('false');
|
||||
|
||||
model = new WidgetsFormBaseSchemaModel({
|
||||
sync_on_bbox_change: true
|
||||
}, { parse: true, userModel: userModel });
|
||||
expect(model.get('sync_on_bbox_change')).toEqual('true');
|
||||
});
|
||||
|
||||
describe('.changeWidgetDefinitionModel', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new Backbone.Model();
|
||||
spyOn(this.widgetDefinitionModel, 'set');
|
||||
});
|
||||
|
||||
it('should set the expected values for the sync values', function () {
|
||||
var model = new WidgetsFormBaseSchemaModel({}, {userModel: userModel});
|
||||
model.set({
|
||||
sync_on_bbox_change: ''
|
||||
});
|
||||
model.changeWidgetDefinitionModel(this.widgetDefinitionModel);
|
||||
expect(this.widgetDefinitionModel.set).toHaveBeenCalled();
|
||||
expect(this.widgetDefinitionModel.set.calls.argsFor(0)[0].sync_on_bbox_change).toBe(false);
|
||||
|
||||
model.set({
|
||||
sync_on_bbox_change: 'true'
|
||||
});
|
||||
this.widgetDefinitionModel.set.calls.reset();
|
||||
model.changeWidgetDefinitionModel(this.widgetDefinitionModel);
|
||||
expect(this.widgetDefinitionModel.set).toHaveBeenCalled();
|
||||
expect(this.widgetDefinitionModel.set.calls.argsFor(0)[0].sync_on_bbox_change).toBe(true);
|
||||
});
|
||||
|
||||
it('should set the expected values for category and autostyle', function () {
|
||||
this.widgetDefinitionModel.attributes.type = 'category';
|
||||
this.widgetDefinitionModel.attributes.column = 'col';
|
||||
|
||||
var model = new WidgetsFormBaseSchemaModel({}, {userModel: userModel});
|
||||
model.set({
|
||||
auto_style_definition: ''
|
||||
});
|
||||
model.changeWidgetDefinitionModel(this.widgetDefinitionModel);
|
||||
expect(this.widgetDefinitionModel.set).toHaveBeenCalled();
|
||||
expect(this.widgetDefinitionModel.set.calls.argsFor(0)[0].auto_style_definition).toBe('');
|
||||
|
||||
model.set({
|
||||
auto_style_definition: {}
|
||||
});
|
||||
this.widgetDefinitionModel.set.calls.reset();
|
||||
model.changeWidgetDefinitionModel(this.widgetDefinitionModel);
|
||||
expect(this.widgetDefinitionModel.set).toHaveBeenCalled();
|
||||
|
||||
var payload = this.widgetDefinitionModel.set.calls.argsFor(0)[0].auto_style_definition;
|
||||
|
||||
expect(payload.color.attribute).toBe('col');
|
||||
expect(payload.color.quantification).toBe('category');
|
||||
expect(payload.color.range.length).toBe(11);
|
||||
expect(payload.color.domain).toBeTruthy();
|
||||
expect(payload.color.bins).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should set the expected values for histogram and autostyle', function () {
|
||||
this.widgetDefinitionModel.attributes.type = 'histogram';
|
||||
this.widgetDefinitionModel.attributes.column = 'col';
|
||||
|
||||
var model = new WidgetsFormBaseSchemaModel({}, {userModel: userModel});
|
||||
model.set({
|
||||
auto_style_definition: ''
|
||||
});
|
||||
model.changeWidgetDefinitionModel(this.widgetDefinitionModel);
|
||||
expect(this.widgetDefinitionModel.set).toHaveBeenCalled();
|
||||
expect(this.widgetDefinitionModel.set.calls.argsFor(0)[0].auto_style_definition).toBe('');
|
||||
|
||||
model.set({
|
||||
auto_style_definition: {}
|
||||
});
|
||||
this.widgetDefinitionModel.set.calls.reset();
|
||||
model.changeWidgetDefinitionModel(this.widgetDefinitionModel);
|
||||
expect(this.widgetDefinitionModel.set).toHaveBeenCalled();
|
||||
|
||||
var payload = this.widgetDefinitionModel.set.calls.argsFor(0)[0].auto_style_definition;
|
||||
|
||||
expect(payload.color.attribute).toBe('col');
|
||||
expect(payload.color.quantification).toBe('quantiles');
|
||||
expect(payload.color.range.length).toBe(7);
|
||||
expect(payload.color.domain).toBeFalsy();
|
||||
expect(payload.color.bins).toBe(7);
|
||||
});
|
||||
});
|
||||
});
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
var Backbone = require('backbone');
|
||||
var WidgetsFormColumnOptionsFactory = require('builder/editor/widgets/widgets-form/widgets-form-column-options-factory');
|
||||
var WidgetsFormCategorySchemaModel = require('builder/editor/widgets/widgets-form/schema/widgets-form-category-schema-model');
|
||||
var FactoryModals = require('../../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/schema/widgets-form-category-schema-model', function () {
|
||||
beforeEach(function () {
|
||||
var querySchemaModel = new Backbone.Model();
|
||||
var userModel = {
|
||||
featureEnabled: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.widgetsFormColumnOptionsFactory = new WidgetsFormColumnOptionsFactory(querySchemaModel);
|
||||
spyOn(this.widgetsFormColumnOptionsFactory, 'create').and.returnValue([{
|
||||
val: 'col',
|
||||
label: 'col',
|
||||
type: 'number'
|
||||
}, {
|
||||
val: 'col2',
|
||||
label: 'col2',
|
||||
type: 'string'
|
||||
}]);
|
||||
spyOn(this.widgetsFormColumnOptionsFactory, 'unavailableColumnsHelpMessage');
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
|
||||
this.model = new WidgetsFormCategorySchemaModel({
|
||||
type: 'category',
|
||||
layer_id: 'l-1',
|
||||
column: 'col',
|
||||
aggregation: 'count'
|
||||
}, {
|
||||
columnOptionsFactory: this.widgetsFormColumnOptionsFactory,
|
||||
userModel: userModel,
|
||||
configModel: {},
|
||||
modals: this.modals
|
||||
});
|
||||
});
|
||||
|
||||
describe('.updateSchema', function () {
|
||||
beforeEach(function () {
|
||||
this.model.updateSchema();
|
||||
});
|
||||
|
||||
it('should contain the real columns as options', function () {
|
||||
expect(this.model.schema.column.options[0].label).toEqual('col');
|
||||
});
|
||||
|
||||
it('should not contain aggregation column if the aggregation is "count"', function () {
|
||||
this.model.set({aggregate: {
|
||||
attribute: 'col',
|
||||
operation: 'avg'
|
||||
}});
|
||||
|
||||
expect(this.model.get('aggregation_column')).toBe('col');
|
||||
|
||||
this.model.set({aggregate: {
|
||||
operation: 'count'
|
||||
}});
|
||||
|
||||
expect(this.model.get('aggregation_column')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
var Backbone = require('backbone');
|
||||
var WidgetsFormColumnOptionsFactory = require('builder/editor/widgets/widgets-form/widgets-form-column-options-factory');
|
||||
var WidgetsFormFormulaSchemaModel = require('builder/editor/widgets/widgets-form/schema/widgets-form-formula-schema-model');
|
||||
var FactoryModals = require('../../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/schema/widgets-form-formula-schema-model', function () {
|
||||
beforeEach(function () {
|
||||
var userModel = {
|
||||
featureEnabled: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.querySchemaModel = new Backbone.Model();
|
||||
this.widgetsFormColumnOptionsFactory = new WidgetsFormColumnOptionsFactory(this.querySchemaModel);
|
||||
spyOn(this.widgetsFormColumnOptionsFactory, 'create').and.returnValue([{
|
||||
val: 'col',
|
||||
label: 'col',
|
||||
type: 'number'
|
||||
}, {
|
||||
val: 'col2',
|
||||
label: 'col2',
|
||||
type: 'string'
|
||||
}]);
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
|
||||
this.model = new WidgetsFormFormulaSchemaModel({
|
||||
type: 'formula',
|
||||
column: 'cartodb_id',
|
||||
operation: 'avg'
|
||||
}, {
|
||||
columnOptionsFactory: this.widgetsFormColumnOptionsFactory,
|
||||
userModel: userModel,
|
||||
configModel: {},
|
||||
modals: this.modals,
|
||||
parse: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse the aggregation correctly', function () {
|
||||
var attrs = this.model.toJSON();
|
||||
expect(attrs.aggregate.operator).toBe('avg');
|
||||
expect(attrs.aggregate.attribute).toBe('cartodb_id');
|
||||
});
|
||||
});
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
var Backbone = require('backbone');
|
||||
var WidgetsFormColumnOptionsFactory = require('builder/editor/widgets/widgets-form/widgets-form-column-options-factory');
|
||||
var WidgetsFormHistogramSchemaModel = require('builder/editor/widgets/widgets-form/schema/widgets-form-histogram-schema-model');
|
||||
var FactoryModals = require('../../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/schema/widgets-form-histogram-schema-model', function () {
|
||||
beforeEach(function () {
|
||||
var userModel = {
|
||||
featureEnabled: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.querySchemaModel = new Backbone.Model();
|
||||
this.widgetsFormColumnOptionsFactory = new WidgetsFormColumnOptionsFactory(this.querySchemaModel);
|
||||
spyOn(this.widgetsFormColumnOptionsFactory, 'create').and.returnValue([{
|
||||
val: 'col',
|
||||
label: 'col',
|
||||
type: 'number'
|
||||
}, {
|
||||
val: 'col2',
|
||||
label: 'col2',
|
||||
type: 'string'
|
||||
}]);
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
|
||||
this.model = new WidgetsFormHistogramSchemaModel({
|
||||
type: 'histogram'
|
||||
}, {
|
||||
columnOptionsFactory: this.widgetsFormColumnOptionsFactory,
|
||||
userModel: userModel,
|
||||
configModel: {},
|
||||
modals: this.modals
|
||||
});
|
||||
});
|
||||
|
||||
describe('.updateSchema', function () {
|
||||
it('column validator is correct', function () {
|
||||
// Arrange
|
||||
var expectedValidator = {
|
||||
type: 'columnType',
|
||||
columnsCollection: this.querySchemaModel.columnsCollection,
|
||||
columnType: 'number'
|
||||
};
|
||||
|
||||
// Act
|
||||
this.model.updateSchema();
|
||||
|
||||
// Assert
|
||||
expect(this.model.schema.column).toBeDefined();
|
||||
expect(this.model.schema.column.validators).toBeDefined();
|
||||
expect(this.model.schema.column.validators[0]).toEqual(expectedValidator);
|
||||
});
|
||||
|
||||
it('bins validator is correct', function () {
|
||||
// Arrange
|
||||
var expectedValidator = {
|
||||
type: 'interval',
|
||||
min: 2,
|
||||
max: 30
|
||||
};
|
||||
|
||||
// Act
|
||||
this.model.updateSchema();
|
||||
|
||||
// Assert
|
||||
expect(this.model.schema.bins).toBeDefined();
|
||||
expect(this.model.schema.bins.validators).toBeDefined();
|
||||
expect(this.model.schema.bins.validators[0]).toEqual('required');
|
||||
expect(this.model.schema.bins.validators[1]).toEqual(expectedValidator);
|
||||
});
|
||||
});
|
||||
});
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var QuerySchemaModel = require('builder/data/query-schema-model');
|
||||
var WidgetsFormColumnOptionsFactory = require('builder/editor/widgets/widgets-form/widgets-form-column-options-factory');
|
||||
var WidgetsFormTimeSeriesSchemaModel = require('builder/editor/widgets/widgets-form/schema/widgets-form-time-series-schema-model');
|
||||
var FactoryModals = require('../../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/schema/widgets-form-time-series-schema-model', function () {
|
||||
beforeEach(function () {
|
||||
var userModel = {
|
||||
featureEnabled: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
user_name: 'pepe'
|
||||
});
|
||||
|
||||
this.querySchemaModel = new QuerySchemaModel({
|
||||
query: 'SELECT * FROM foobar',
|
||||
status: 'fetched'
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
this.querySchemaModel.columnsCollection.reset([
|
||||
{ name: 'cartodb_id', type: 'number' },
|
||||
{ name: 'created_at', type: 'date' }
|
||||
]);
|
||||
|
||||
this.widgetsFormColumnOptionsFactory = new WidgetsFormColumnOptionsFactory(this.querySchemaModel);
|
||||
spyOn(this.widgetsFormColumnOptionsFactory, 'create').and.returnValue([{
|
||||
val: 'col',
|
||||
label: 'col',
|
||||
type: 'number'
|
||||
}, {
|
||||
val: 'col2',
|
||||
label: 'col2',
|
||||
type: 'string'
|
||||
}]);
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
|
||||
this.model = new WidgetsFormTimeSeriesSchemaModel({
|
||||
type: 'time-series',
|
||||
column: 'cartodb_id'
|
||||
}, {
|
||||
columnOptionsFactory: this.widgetsFormColumnOptionsFactory,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
userModel: userModel,
|
||||
configModel: configModel,
|
||||
modals: this.modals
|
||||
});
|
||||
});
|
||||
|
||||
it('should call ._onColumnChanged when column changes', function () {
|
||||
spyOn(this.model, '_onColumnChanged');
|
||||
this.model._initBinds();
|
||||
|
||||
this.model.trigger('change:column');
|
||||
expect(this.model._onColumnChanged).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call .updateSchema when _timeSeriesQueryModel buckets change', function () {
|
||||
spyOn(this.model, 'updateSchema');
|
||||
this.model._initBinds();
|
||||
|
||||
this.model._timeSeriesQueryModel.trigger('change:buckets');
|
||||
expect(this.model.updateSchema).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('.updateSchema', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.model._querySchemaModel, 'isFetched').and.returnValue(true);
|
||||
});
|
||||
|
||||
it('always have column and widget_style_definition', function () {
|
||||
this.model.updateSchema();
|
||||
expect(this.model.schema.column).toBeDefined();
|
||||
expect(this.model.schema.widget_style_definition).toBeDefined();
|
||||
});
|
||||
|
||||
it('should have aggregation, and timezone if column is type date', function () {
|
||||
spyOn(this.model, '_getColumnType').and.returnValue('date');
|
||||
this.model.updateSchema();
|
||||
expect(this.model.schema.aggregation).toBeDefined();
|
||||
expect(this.model.schema.timezone).toBeDefined();
|
||||
expect(this.model.schema.bins).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should have bins if column is not type date', function () {
|
||||
this.model.updateSchema();
|
||||
expect(this.model.schema.bins).toBeDefined();
|
||||
expect(this.model.schema.aggregation).not.toBeDefined();
|
||||
expect(this.model.schema.timezone).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getFields', function () {
|
||||
it('should return column', function () {
|
||||
var fields = this.model.getFields();
|
||||
expect(fields.data).toContain('column');
|
||||
});
|
||||
|
||||
it('should return aggregation if column type is date', function () {
|
||||
spyOn(this.model, '_getColumnType').and.returnValue('date');
|
||||
var fields = this.model.getFields();
|
||||
expect(fields.data).toContain('aggregation');
|
||||
expect(fields.data).toContain('timezone');
|
||||
expect(fields.data).not.toContain('bins');
|
||||
});
|
||||
|
||||
it('should not return aggregation, and timezone if column type is not date', function () {
|
||||
var fields = this.model.getFields();
|
||||
expect(fields.data).toContain('bins');
|
||||
expect(fields.data).not.toContain('aggregation');
|
||||
expect(fields.data).not.toContain('timezone');
|
||||
});
|
||||
|
||||
it('should return sync_on_bbox_change', function () {
|
||||
var fields = this.model.getFields();
|
||||
expect(fields.style).toContain('sync_on_bbox_change');
|
||||
});
|
||||
|
||||
it('should return widget_style_definition', function () {
|
||||
var fields = this.model.getFields();
|
||||
expect(fields.style).toContain('widget_style_definition');
|
||||
});
|
||||
});
|
||||
|
||||
describe('._isDateType', function () {
|
||||
it('should return true if type is date', function () {
|
||||
var model = new Backbone.Model({ type: 'number' });
|
||||
expect(this.model._isDateType(model)).toBe(false);
|
||||
|
||||
model.set('type', 'date');
|
||||
expect(this.model._isDateType(model)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._isNumberType', function () {
|
||||
it('should return true if type is number', function () {
|
||||
var model = new Backbone.Model({ type: 'date' });
|
||||
expect(this.model._isNumberType(model)).toBe(false);
|
||||
|
||||
model.set('type', 'number');
|
||||
expect(this.model._isNumberType(model)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._isNumberOrDateType', function () {
|
||||
it('should return true if type is number', function () {
|
||||
var model = new Backbone.Model({ type: 'string' });
|
||||
expect(this.model._isNumberOrDateType(model)).toBe(false);
|
||||
|
||||
model.set('type', 'number');
|
||||
expect(this.model._isNumberOrDateType(model)).toBe(true);
|
||||
|
||||
model.set('type', 'date');
|
||||
expect(this.model._isNumberOrDateType(model)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._prepareAttributesForWidgetDefinition', function () {
|
||||
describe('column type is date', function () {
|
||||
it('should set bins to undefined and assign an offset to the timezone', function () {
|
||||
spyOn(this.model, '_getColumnType').and.returnValue('date');
|
||||
|
||||
this.model.set({
|
||||
bins: '100',
|
||||
timezone: 'America/Barbados'
|
||||
});
|
||||
|
||||
var attrs = this.model._prepareAttributesForWidgetDefinition();
|
||||
expect(attrs.bins).toBeUndefined();
|
||||
expect(attrs.offset).toBe(-14400);
|
||||
expect(attrs.timezone).toBe('America/Barbados');
|
||||
});
|
||||
});
|
||||
|
||||
describe('column type is not date', function () {
|
||||
it('should set aggregation, timezone, and offset to undefined', function () {
|
||||
spyOn(this.model, '_getColumnType').and.returnValue('number');
|
||||
|
||||
this.model.set({
|
||||
aggregation: 'month',
|
||||
timezone: 'Atlantic/Canary'
|
||||
});
|
||||
|
||||
var attrs = this.model._prepareAttributesForWidgetDefinition();
|
||||
expect(attrs.aggregation).toBeUndefined();
|
||||
expect(attrs.timezone).toBeUndefined();
|
||||
expect(attrs.offset).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('._getColumnType', function () {
|
||||
it('should return the column type', function () {
|
||||
this.model.set('column', 'cartodb_id');
|
||||
expect(this.model._getColumnType()).toEqual('number');
|
||||
});
|
||||
});
|
||||
});
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var QuerySchemaModel = require('builder/data/query-schema-model');
|
||||
var WidgetsFormColumnOptionsFactory = require('builder/editor/widgets/widgets-form/widgets-form-column-options-factory');
|
||||
|
||||
describe('editor/widgets/widgets-form/widgets-form-column-options-factory', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
this.querySchemaModel = new QuerySchemaModel({
|
||||
query: 'SELECT * from foobar'
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.factory = new WidgetsFormColumnOptionsFactory(this.querySchemaModel);
|
||||
});
|
||||
|
||||
describe('.unavailableColumnsHelpMessage', function () {
|
||||
it('should return a string if columns are not available', function () {
|
||||
this.querySchemaModel.set('status', 'fetched');
|
||||
expect(this.factory.unavailableColumnsHelpMessage()).toBeUndefined();
|
||||
|
||||
this.querySchemaModel.set('status', 'unavailable');
|
||||
expect(this.factory.unavailableColumnsHelpMessage()).toEqual(jasmine.any(String));
|
||||
});
|
||||
});
|
||||
|
||||
describe('.create', function () {
|
||||
describe('when columns are not yet fetched', function () {
|
||||
beforeEach(function () {
|
||||
this.querySchemaModel.set('status', 'fetching');
|
||||
});
|
||||
|
||||
it('should return a disable option with loading message', function () {
|
||||
expect(this.factory.create()).toEqual([{val: jasmine.any(String)}]);
|
||||
});
|
||||
|
||||
describe('when columns are not available for whatever reason', function () {
|
||||
beforeEach(function () {
|
||||
this.querySchemaModel.set('status', 'unavailable');
|
||||
});
|
||||
|
||||
it('should return the current val', function () {
|
||||
expect(this.factory.create('current')).toEqual([{val: 'current'}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when columns are finally fetched', function () {
|
||||
beforeEach(function () {
|
||||
this.querySchemaModel.columnsCollection.reset([
|
||||
{name: 'cartodb_id', type: 'number'},
|
||||
{name: 'title', type: 'string'},
|
||||
{name: 'created_at', type: 'date'}
|
||||
]);
|
||||
this.querySchemaModel.set('status', 'fetched');
|
||||
});
|
||||
|
||||
it('should return the columns', function () {
|
||||
expect(this.factory.create('current')).toEqual([
|
||||
{
|
||||
label: 'cartodb_id',
|
||||
val: 'cartodb_id',
|
||||
type: 'number'
|
||||
}, {
|
||||
label: 'title',
|
||||
val: 'title',
|
||||
type: 'string'
|
||||
}, {
|
||||
label: 'created_at',
|
||||
val: 'created_at',
|
||||
type: 'date'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return only valid columns if filter is given', function () {
|
||||
var noStringsFilter = function (m) {
|
||||
return m.get('type') !== 'string';
|
||||
};
|
||||
expect(this.factory.create('current', noStringsFilter)).toEqual([
|
||||
{
|
||||
label: 'cartodb_id',
|
||||
val: 'cartodb_id',
|
||||
type: 'number'
|
||||
}, {
|
||||
label: 'created_at',
|
||||
val: 'created_at',
|
||||
type: 'date'
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var QuerySchemaModel = require('builder/data/query-schema-model');
|
||||
var WidgetsFormContentView = require('builder/editor/widgets/widgets-form/widgets-form-content-view');
|
||||
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
|
||||
var Router = require('builder/routes/router');
|
||||
var FactoryModals = require('../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/widgets-form-content-view', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(Router, 'navigate');
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
var querySchemaModel = new QuerySchemaModel({
|
||||
query: 'SELECT * FROM foobar',
|
||||
status: 'fetched'
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
querySchemaModel.columnsCollection.reset([
|
||||
{ name: 'cartodb_id', type: 'number' },
|
||||
{ name: 'created_at', type: 'date' }
|
||||
]);
|
||||
|
||||
var userModel = {
|
||||
featureEnabled: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
|
||||
var dfd = $.Deferred();
|
||||
dfd.resolve();
|
||||
spyOn(querySchemaModel, 'fetch').and.returnValue(dfd.promise());
|
||||
|
||||
this.analysisDefinitionNodesCollection = new Backbone.Collection();
|
||||
var nodeDefModel = this.analysisDefinitionNodesCollection.add({
|
||||
id: 'a0',
|
||||
type: 'source',
|
||||
table_name: 'test'
|
||||
});
|
||||
nodeDefModel.querySchemaModel = querySchemaModel;
|
||||
nodeDefModel.isSourceType = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
this.layerDefinitionsCollection = new Backbone.Collection({
|
||||
id: 'l1',
|
||||
color: 'red',
|
||||
name: 'layerrr'
|
||||
});
|
||||
var layerDefinitionModel = this.layerDefinitionsCollection.at(0);
|
||||
layerDefinitionModel.getName = function () {
|
||||
return this.get('name');
|
||||
};
|
||||
layerDefinitionModel.getTableName = function () {
|
||||
return 'table name';
|
||||
};
|
||||
layerDefinitionModel.getAnalysisDefinitionNodeModel = function () {
|
||||
return nodeDefModel;
|
||||
};
|
||||
layerDefinitionModel.findAnalysisDefinitionNodeModel = function () {
|
||||
return nodeDefModel;
|
||||
};
|
||||
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'formula',
|
||||
layer_id: 'l1',
|
||||
source: 'a0',
|
||||
column: 'hello',
|
||||
operation: 'sum',
|
||||
prefix: 'my-prefix'
|
||||
}, {
|
||||
configModel: configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
this.stackLayoutModel = jasmine.createSpyObj('stackLayoutModel', ['prevStep']);
|
||||
|
||||
this.view = new WidgetsFormContentView({
|
||||
userActions: {},
|
||||
modals: this.modals,
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
layerDefinitionsCollection: this.layerDefinitionsCollection,
|
||||
analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
|
||||
stackLayoutModel: this.stackLayoutModel,
|
||||
stackLayoutPrevStep: 0,
|
||||
userModel: userModel,
|
||||
configModel: configModel
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should generate the right tabs', function () {
|
||||
expect(this.view.$el.text()).toContain('editor.widgets.widgets-form.data.title');
|
||||
expect(this.view.$el.text()).toContain('editor.widgets.widgets-form.style.title');
|
||||
});
|
||||
|
||||
it('should get back to the previous step if arrow is clicked', function () {
|
||||
spyOn(Router, 'goToPreviousRoute');
|
||||
|
||||
this.view.$('.js-back').click();
|
||||
|
||||
expect(Router.goToPreviousRoute).toHaveBeenCalledWith({
|
||||
fallback: 'widgets'
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
var _ = require('underscore');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var QuerySchemaModel = require('builder/data/query-schema-model');
|
||||
var WidgetsFormFactory = require('builder/editor/widgets/widgets-form/widgets-form-factory');
|
||||
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
|
||||
var FactoryModals = require('../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/widgets-form-factory', function () {
|
||||
var userModel = {
|
||||
featureEnabled: function (whatever) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
this.configModel = new ConfigModel({
|
||||
base_url: '/u/pepe',
|
||||
user_name: 'pepe'
|
||||
});
|
||||
this.querySchemaModel = new QuerySchemaModel({
|
||||
query: 'SELECT * FROM foobar'
|
||||
}, {
|
||||
configModel: this.configModel
|
||||
});
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
});
|
||||
|
||||
describe('data form', function () {
|
||||
describe('formula data form', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
layer_id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'formula',
|
||||
options: {
|
||||
column: 'hello',
|
||||
operation: 'sum',
|
||||
prefix: 'my-prefix'
|
||||
}
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the widget form model', function () {
|
||||
var model = WidgetsFormFactory.createWidgetFormModel({
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
modals: this.modals,
|
||||
userModel: userModel,
|
||||
configModel: this.configModel
|
||||
});
|
||||
expect(model).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('category data form', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
layer_id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'category',
|
||||
options: {
|
||||
column: 'hello'
|
||||
}
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the widget form model', function () {
|
||||
var model = WidgetsFormFactory.createWidgetFormModel({
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
modals: this.modals,
|
||||
userModel: userModel,
|
||||
configModel: this.configModel
|
||||
});
|
||||
expect(model).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('histogram data form', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
layer_id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'histogram',
|
||||
options: {
|
||||
column: 'hello'
|
||||
}
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the widget form model', function () {
|
||||
var model = WidgetsFormFactory.createWidgetFormModel({
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
modals: this.modals,
|
||||
userModel: userModel,
|
||||
configModel: this.configModel
|
||||
});
|
||||
expect(model).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('time-series data form', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
layer_id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'time-series',
|
||||
options: {
|
||||
column: 'hello'
|
||||
}
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the widget form model', function () {
|
||||
var model = WidgetsFormFactory.createWidgetFormModel({
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
modals: this.modals,
|
||||
userModel: userModel,
|
||||
configModel: this.configModel
|
||||
});
|
||||
expect(model).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('style', function () {
|
||||
describe('rest style form', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
layer_id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'category',
|
||||
options: {
|
||||
column: 'hello'
|
||||
}
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the widget form model', function () {
|
||||
var model = WidgetsFormFactory.createWidgetFormModel({
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
modals: this.modals,
|
||||
userModel: userModel,
|
||||
configModel: this.configModel
|
||||
});
|
||||
expect(model.schema.description).not.toBeDefined();
|
||||
expect(model.schema.sync_on_bbox_change).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('formula style form', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
layer_id: 'w-456',
|
||||
title: 'helloooo',
|
||||
type: 'formula',
|
||||
options: {
|
||||
column: 'hello'
|
||||
}
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the widget form model', function () {
|
||||
var model = WidgetsFormFactory.createWidgetFormModel({
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
modals: this.modals,
|
||||
userModel: userModel,
|
||||
configModel: this.configModel
|
||||
});
|
||||
expect(model).toBeDefined();
|
||||
|
||||
model.updateSchema();
|
||||
expect(model.schema.description).toBeDefined();
|
||||
expect(model.schema.sync_on_bbox_change).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('type validation', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
layer_id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'time-series',
|
||||
options: {
|
||||
column: 'hello'
|
||||
}
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
});
|
||||
|
||||
describe('data validation', function () {
|
||||
it('should return the valid widget types for string columns', function () {
|
||||
this.querySchemaModel.columnsCollection.reset([
|
||||
{ name: 'cartodb_id', type: 'string' },
|
||||
{ name: 'nobel_prizes_winners', type: 'string' },
|
||||
{ name: 'year', type: 'string' }
|
||||
]);
|
||||
|
||||
var types = WidgetsFormFactory.getDataTypes(this.querySchemaModel);
|
||||
var values = _.pluck(types, 'value');
|
||||
expect(values.sort()).toEqual(['category']);
|
||||
});
|
||||
|
||||
it('should return the valid widget types for numeric columns', function () {
|
||||
this.querySchemaModel.columnsCollection.reset([
|
||||
{ name: 'cartodb_id', type: 'number' },
|
||||
{ name: 'year', type: 'number' }
|
||||
]);
|
||||
|
||||
var types = WidgetsFormFactory.getDataTypes(this.querySchemaModel);
|
||||
var values = _.pluck(types, 'value');
|
||||
expect(values.sort()).toEqual(['category', 'formula', 'histogram', 'time-series']);
|
||||
});
|
||||
|
||||
it('should return the valid widget types for date columns', function () {
|
||||
this.querySchemaModel.columnsCollection.reset([
|
||||
{ name: 'year', type: 'date' }
|
||||
]);
|
||||
|
||||
var types = WidgetsFormFactory.getDataTypes(this.querySchemaModel);
|
||||
var values = _.pluck(types, 'value');
|
||||
expect(values.sort()).toEqual(['category', 'time-series']);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
var QuerySchemaModel = require('builder/data/query-schema-model');
|
||||
var WidgetsFormFieldsView = require('builder/editor/widgets/widgets-form/widgets-form-fields-view');
|
||||
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
|
||||
|
||||
describe('editor/widgets/widgets-form/widgets-form-fields-view', function () {
|
||||
beforeEach(function () {
|
||||
var querySchemaModel = new QuerySchemaModel({
|
||||
query: 'SELECT * FROM foobar',
|
||||
status: 'fetched'
|
||||
}, {
|
||||
configModel: {}
|
||||
});
|
||||
querySchemaModel.columnsCollection.reset([
|
||||
{ name: 'cartodb_id', type: 'number' },
|
||||
{ name: 'created_at', type: 'date' }
|
||||
]);
|
||||
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'formula',
|
||||
layer_id: 'l1',
|
||||
source: 'a0',
|
||||
column: 'hello',
|
||||
operation: 'sum'
|
||||
}, {
|
||||
configModel: {},
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
this.view = new WidgetsFormFieldsView({
|
||||
userActions: {},
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: querySchemaModel,
|
||||
configModel: {},
|
||||
userModel: {},
|
||||
modals: {}
|
||||
});
|
||||
|
||||
spyOn(this.view, 'render').and.callThrough();
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
describe('.validateForm', function () {
|
||||
it('should call _widgetFormView.validate()', function () {
|
||||
spyOn(this.view._widgetFormView, 'validate');
|
||||
|
||||
this.view.validateForm();
|
||||
|
||||
expect(this.view._widgetFormView.validate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call .render if _widgetFormModel change:column, change:aggregation or changeSchema is triggered', function () {
|
||||
this.view._widgetFormModel.trigger('change:column');
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
|
||||
this.view._widgetFormModel.trigger('change:aggregation');
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
|
||||
this.view._widgetFormModel.trigger('changeSchema');
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,258 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var QuerySchemaModel = require('builder/data/query-schema-model');
|
||||
var WidgetsFormView = require('builder/editor/widgets/widgets-form/widgets-form-view');
|
||||
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
|
||||
var UserActions = require('builder/data/user-actions');
|
||||
var FactoryModals = require('../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/widgets-form-view', function () {
|
||||
beforeEach(function () {
|
||||
this.configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.querySchemaModel = new QuerySchemaModel({
|
||||
query: 'SELECT * FROM foobar',
|
||||
status: 'fetched'
|
||||
}, {
|
||||
configModel: this.configModel
|
||||
});
|
||||
this.querySchemaModel.columnsCollection.reset([
|
||||
{ name: 'cartodb_id', type: 'number' },
|
||||
{ name: 'created_at', type: 'date' }
|
||||
]);
|
||||
|
||||
var dfd = $.Deferred();
|
||||
dfd.resolve();
|
||||
spyOn(this.querySchemaModel, 'fetch').and.returnValue(dfd.promise());
|
||||
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'formula',
|
||||
layer_id: 'l1',
|
||||
source: 'a0',
|
||||
column: 'hello',
|
||||
operation: 'sum'
|
||||
}, {
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
|
||||
this.userModel = {
|
||||
featureEnabled: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
this.userActions = UserActions({
|
||||
userModel: this.userModel,
|
||||
analysisDefinitionsCollection: {},
|
||||
analysisDefinitionNodesCollection: {},
|
||||
layerDefinitionsCollection: {},
|
||||
widgetDefinitionsCollection: {}
|
||||
});
|
||||
this.promise = $.Deferred();
|
||||
spyOn(this.userActions, 'saveWidget').and.returnValue(this.promise);
|
||||
|
||||
this.view = new WidgetsFormView({
|
||||
userActions: this.userActions,
|
||||
widgetDefinitionModel: this.widgetDefinitionModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
configModel: {},
|
||||
userModel: this.userModel,
|
||||
modals: this.modals
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(_.size(this.view._subviews)).toBe(2); // carousel and form fields
|
||||
});
|
||||
|
||||
it('should update form model when widgetDefinitionModel rename', function () {
|
||||
this.widgetDefinitionModel.set({title: 'wadus'});
|
||||
expect(this.view._formView._widgetFormModel.get('title')).toBe('wadus');
|
||||
});
|
||||
|
||||
it('should have enabler editor component for suffix and prefix, disable by default', function () {
|
||||
expect(this.view.$('input[name=prefix]').length).toBe(1);
|
||||
expect(this.view.$('input[name=suffix]').length).toBe(1);
|
||||
expect(this.view.$('input[name=prefix]').prop('readonly')).toBe(true);
|
||||
expect(this.view.$('input[name=suffix]').prop('readonly')).toBe(true);
|
||||
});
|
||||
|
||||
it('should include widget style fields if needed', function () {
|
||||
// formula widget
|
||||
expect(this.view.$('div.js-input[name=widget_style_definition]').length).toBe(0);
|
||||
expect(this.view.$('div.js-input[name=auto_style_definition]').length).toBe(0);
|
||||
|
||||
this.widgetDefinitionModel.set({type: 'category'});
|
||||
this.view.render();
|
||||
|
||||
// category widget
|
||||
expect(this.view.$('div.js-input[name=widget_style_definition]').length).toBe(1);
|
||||
expect(this.view.$('div.js-input[name=auto_style_definition]').length).toBe(1);
|
||||
|
||||
this.widgetDefinitionModel.set({type: 'histogram'});
|
||||
this.view.render();
|
||||
|
||||
// category widget
|
||||
expect(this.view.$('div.js-input[name=widget_style_definition]').length).toBe(1);
|
||||
expect(this.view.$('div.js-input[name=auto_style_definition]').length).toBe(1);
|
||||
});
|
||||
|
||||
describe('._initBinds', function () {
|
||||
it('should call ._renderFormAndValidate when change:type of _widgetDefinitionModel is triggered', function () {
|
||||
spyOn(this.view, '_renderFormAndValidate');
|
||||
|
||||
this.view._initBinds();
|
||||
this.view._widgetDefinitionModel.set('type', 'histogram');
|
||||
|
||||
expect(this.view._renderFormAndValidate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call .render when change:status of _querySchemaModel is triggered', function () {
|
||||
spyOn(this.view, 'render');
|
||||
|
||||
this.view._initBinds();
|
||||
this.view._querySchemaModel.set('status', 'error');
|
||||
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call ._shouldFetchQuery when change:status of _querySchemaModel:query changes', function () {
|
||||
spyOn(this.view, '_shouldFetchQuery');
|
||||
|
||||
this.view._initBinds();
|
||||
this.view._querySchemaModel.set('query', 'SELECT * FROM somewhere;');
|
||||
|
||||
expect(this.view._shouldFetchQuery).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._getFilteredDataTypes', function () {
|
||||
beforeEach(function () {
|
||||
var collection = new Backbone.Collection();
|
||||
|
||||
var widgetDefinitionModel1 = new WidgetDefinitionModel({
|
||||
title: 'some title',
|
||||
type: 'formula',
|
||||
layer_id: 'l1',
|
||||
source: 'a0',
|
||||
column: 'hello',
|
||||
operation: 'sum'
|
||||
}, {
|
||||
collection: collection,
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
var widgetDefinitionModel2 = new WidgetDefinitionModel({
|
||||
layer_id: 'l1',
|
||||
title: 'some title',
|
||||
type: 'time-series',
|
||||
options: {
|
||||
column: 'hello'
|
||||
}
|
||||
}, {
|
||||
collection: collection,
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
var widgetDefinitionModel3 = new WidgetDefinitionModel({
|
||||
title: 'some title',
|
||||
type: 'formula',
|
||||
layer_id: 'l1',
|
||||
source: 'a0',
|
||||
column: 'hello',
|
||||
operation: 'sum'
|
||||
}, {
|
||||
collection: new Backbone.Collection(),
|
||||
configModel: this.configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
collection.add(widgetDefinitionModel1);
|
||||
collection.add(widgetDefinitionModel2);
|
||||
|
||||
this.view1 = new WidgetsFormView({
|
||||
userActions: this.userActions,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
configModel: {},
|
||||
widgetDefinitionModel: widgetDefinitionModel1,
|
||||
userModel: this.userModel,
|
||||
modals: this.modals
|
||||
});
|
||||
|
||||
this.view2 = new WidgetsFormView({
|
||||
userActions: this.userActions,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
configModel: {},
|
||||
widgetDefinitionModel: widgetDefinitionModel2,
|
||||
userModel: this.userModel,
|
||||
modals: this.modals
|
||||
});
|
||||
|
||||
this.view3 = new WidgetsFormView({
|
||||
userActions: this.userActions,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
configModel: {},
|
||||
widgetDefinitionModel: widgetDefinitionModel3,
|
||||
userModel: this.userModel,
|
||||
modals: this.modals
|
||||
});
|
||||
});
|
||||
|
||||
it('should not include time-series if there is a time-series widget', function () {
|
||||
var filteredDataTypes = this.view1._getFilteredDataTypes();
|
||||
expect(filteredDataTypes.length).toBe(3);
|
||||
});
|
||||
it('should include time-series if it is a time-series widget', function () {
|
||||
var filteredDataTypes = this.view2._getFilteredDataTypes();
|
||||
expect(filteredDataTypes.length).toBe(4);
|
||||
});
|
||||
it('should include time-series if there is not a time-series widget', function () {
|
||||
var filteredDataTypes = this.view3._getFilteredDataTypes();
|
||||
expect(filteredDataTypes.length).toBe(4);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view1.clean();
|
||||
this.view2.clean();
|
||||
this.view3.clean();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._renderFormAndValidate', function () {
|
||||
it('should call _renderForm and saveWidget if the form pass the validation', function () {
|
||||
spyOn(this.view, '_renderForm');
|
||||
spyOn(this.view._formView, 'validateForm').and.returnValue(null);
|
||||
|
||||
this.view._renderFormAndValidate();
|
||||
|
||||
expect(this.view._renderForm).toHaveBeenCalled();
|
||||
expect(this.view._userActions.saveWidget).toHaveBeenCalledWith(this.widgetDefinitionModel);
|
||||
});
|
||||
|
||||
it('should call _renderForm and not call saveWidget if the form dont pass the validation', function () {
|
||||
spyOn(this.view, '_renderForm');
|
||||
spyOn(this.view._formView, 'validateForm').and.returnValue('Error');
|
||||
|
||||
this.view._renderFormAndValidate();
|
||||
|
||||
expect(this.view._renderForm).toHaveBeenCalled();
|
||||
expect(this.view._userActions.saveWidget).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,126 @@
|
||||
var Backbone = require('backbone');
|
||||
var $ = require('jquery');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||||
var WidgetHeader = require('builder/editor/widgets/widgets-form/widget-header');
|
||||
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
|
||||
var FactoryModals = require('../../../factories/modals');
|
||||
|
||||
describe('editor/widgets/widgets-form/widgets-header', function () {
|
||||
var nodeDefModel;
|
||||
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
nodeDefModel = new Backbone.Model({
|
||||
id: 'a0',
|
||||
type: 'source',
|
||||
table_name: 'kvothe'
|
||||
});
|
||||
nodeDefModel.isSourceType = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
var layerDefinitionModel = new LayerDefinitionModel({
|
||||
id: 'l1',
|
||||
color: 'red',
|
||||
name: 'Kvothe Kingskiller',
|
||||
kind: 'carto',
|
||||
table_name: 'kvothe'
|
||||
}, {
|
||||
parse: false,
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
layerDefinitionModel.findAnalysisDefinitionNodeModel = function () {
|
||||
return nodeDefModel;
|
||||
};
|
||||
|
||||
this.widgetDefinitionModel = new WidgetDefinitionModel({
|
||||
id: 'w-456',
|
||||
title: 'some title',
|
||||
type: 'formula',
|
||||
layer_id: 'l1',
|
||||
source: 'a0',
|
||||
column: 'hello',
|
||||
operation: 'sum',
|
||||
prefix: 'my-prefix'
|
||||
}, {
|
||||
configModel: configModel,
|
||||
mapId: 'm-123'
|
||||
});
|
||||
|
||||
this.modals = FactoryModals.createModalService();
|
||||
|
||||
this.stackLayoutModel = jasmine.createSpyObj('stackLayoutModel', ['prevStep']);
|
||||
|
||||
spyOn(WidgetHeader.prototype, '_confirmDeleteWidget');
|
||||
spyOn(WidgetHeader.prototype, '_renameWidget');
|
||||
|
||||
this.view = new WidgetHeader({
|
||||
userActions: {},
|
||||
modals: this.modals,
|
||||
model: this.widgetDefinitionModel,
|
||||
layerDefinitionModel: layerDefinitionModel,
|
||||
stackLayoutModel: this.stackLayoutModel,
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
describe('.render', function () {
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$('.js-toggle-menu').length).toBe(1);
|
||||
expect(this.view.$('.js-title').length).toBe(1);
|
||||
expect(this.view.$('.js-title').text()).toContain('some title');
|
||||
expect(this.view.$el.html()).toContain('a0');
|
||||
expect(this.view.$el.html()).toContain('kvothe');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when node is an analysis', function () {
|
||||
describe('.render', function () {
|
||||
beforeEach(function () {
|
||||
nodeDefModel.isSourceType = function () {
|
||||
return false;
|
||||
};
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$el.html()).toContain('Kvothe Kingskiller');
|
||||
expect(this.view.$el.html()).toContain('CDB-IconFont-ray');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show context menu', function () {
|
||||
this.view.$('.js-toggle-menu').click();
|
||||
expect(this.view._contextMenuFactory.getContextMenu().$('[data-val="rename-widget"]').length).toBe(1);
|
||||
expect(this.view._contextMenuFactory.getContextMenu().$('[data-val="delete-widget"]').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should rename', function () {
|
||||
var e = $.Event('keyup');
|
||||
e.which = 13;
|
||||
|
||||
this.view.$('.js-toggle-menu').click();
|
||||
this.view._contextMenuFactory.getContextMenu().$('[data-val="rename-widget"]').click();
|
||||
this.view.$('.js-input').val('foo').trigger('keyup');
|
||||
this.view.$('.js-input').trigger(e);
|
||||
expect(WidgetHeader.prototype._renameWidget).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should delete', function () {
|
||||
this.view.$('.js-toggle-menu').click();
|
||||
this.view._contextMenuFactory.getContextMenu().$('[data-val="delete-widget"]').click();
|
||||
expect(WidgetHeader.prototype._confirmDeleteWidget).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var WidgetsService = require('builder/editor/widgets/widgets-service');
|
||||
var ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
var Router = require('builder/routes/router');
|
||||
|
||||
describe('editor/widgets/widgets-service', function () {
|
||||
var widgetModel;
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(Router, 'goToWidget');
|
||||
spyOn(Router, 'goToWidgetList');
|
||||
|
||||
widgetModel = new Backbone.Model({ id: 'wadus', name: 'wadus' });
|
||||
WidgetsService._editorModel = new Backbone.Model();
|
||||
WidgetsService._modals = new ModalsServiceModel();
|
||||
});
|
||||
|
||||
describe('.editWidget', function () {
|
||||
it('should set `edition` to false in _editorModel', function () {
|
||||
spyOn(WidgetsService._editorModel, 'set');
|
||||
|
||||
WidgetsService.editWidget(widgetModel);
|
||||
|
||||
expect(WidgetsService._editorModel.set).toHaveBeenCalledWith('edition', false);
|
||||
});
|
||||
|
||||
it('should call Router.goToWidget with the widgetModel id', function () {
|
||||
WidgetsService.editWidget(widgetModel);
|
||||
expect(Router.goToWidget).toHaveBeenCalledWith(widgetModel.get('id'));
|
||||
});
|
||||
|
||||
it('should trigger `cancelPreviousEditions` in _editorModel', function () {
|
||||
spyOn(WidgetsService._editorModel, 'trigger');
|
||||
|
||||
WidgetsService.editWidget(widgetModel);
|
||||
|
||||
expect(WidgetsService._editorModel.trigger).toHaveBeenCalledWith('cancelPreviousEditions');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.removeWidget', function () {
|
||||
afterEach(function () {
|
||||
WidgetsService._modalView.clean();
|
||||
});
|
||||
|
||||
describe('when the widgetDefinitionModel is defined', function () {
|
||||
it('should create a delete confirmation widget template', function () {
|
||||
spyOn(WidgetsService._modals, 'create').and.callThrough();
|
||||
|
||||
WidgetsService.removeWidget(widgetModel);
|
||||
|
||||
expect(WidgetsService._modals.create).toHaveBeenCalled();
|
||||
expect($('.js-cancel').text().trim()).toEqual('editor.widgets.delete.cancel');
|
||||
expect($('.js-confirm').text().trim()).toEqual('editor.widgets.delete.confirm');
|
||||
});
|
||||
|
||||
it('should destroy the widget when the user clicks on ', function () {
|
||||
spyOn(widgetModel, 'destroy');
|
||||
|
||||
WidgetsService.removeWidget(widgetModel);
|
||||
$('.js-confirm').click();
|
||||
|
||||
expect(widgetModel.destroy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should redirect to the widget list when the user clicks on confirm', function () {
|
||||
spyOn(widgetModel, 'destroy');
|
||||
|
||||
WidgetsService.removeWidget(widgetModel);
|
||||
$('.js-confirm').click();
|
||||
|
||||
expect(Router.goToWidgetList).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,236 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var UserActions = require('builder/data/user-actions');
|
||||
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||||
var EditorWidgetsView = require('builder/editor/widgets/widgets-view');
|
||||
var WidgetDefinitionModel = require('builder/data/widget-definition-model');
|
||||
var Router = require('builder/routes/router');
|
||||
var FactoryModals = require('../../factories/modals');
|
||||
|
||||
var STATES = {
|
||||
loading: 'loading',
|
||||
ready: 'ready'
|
||||
};
|
||||
|
||||
describe('editor/widgets/widgets-view', function () {
|
||||
var analysisDefinitionNodeModel;
|
||||
|
||||
function createLayerDefinitionsCollection (layerDefinitionModel) {
|
||||
var layerDefinitionsCollection = new Backbone.Collection([layerDefinitionModel]);
|
||||
|
||||
layerDefinitionsCollection.loadAllQueryGeometryModels = function (callback) {
|
||||
callback();
|
||||
};
|
||||
|
||||
layerDefinitionsCollection.isThereAnyGeometryData = function () {
|
||||
return Promise.resolve(true);
|
||||
};
|
||||
|
||||
return layerDefinitionsCollection;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(Router, 'navigate');
|
||||
|
||||
this.model = new LayerDefinitionModel({
|
||||
id: 'l-100',
|
||||
options: {
|
||||
type: 'CartoDB'
|
||||
}
|
||||
}, {
|
||||
parse: true,
|
||||
configModel: {}
|
||||
});
|
||||
|
||||
analysisDefinitionNodeModel = new Backbone.Model({ type: 'source' });
|
||||
analysisDefinitionNodeModel.querySchemaModel = new Backbone.Model();
|
||||
analysisDefinitionNodeModel.querySchemaModel.hasGeometryData = function () {
|
||||
return true;
|
||||
};
|
||||
analysisDefinitionNodeModel.isSourceType = function () {
|
||||
return true;
|
||||
};
|
||||
analysisDefinitionNodeModel.getColor = function () {
|
||||
return '#fabada';
|
||||
};
|
||||
this.model.findAnalysisDefinitionNodeModel = function () {
|
||||
return analysisDefinitionNodeModel;
|
||||
};
|
||||
|
||||
spyOn(this.model, 'getAnalysisDefinitionNodeModel').and.returnValue(analysisDefinitionNodeModel);
|
||||
|
||||
this.widgetDefinitionsCollection = new Backbone.Collection();
|
||||
this.analysisDefinitionNodesCollection = new Backbone.Collection();
|
||||
this.layerDefinitionsCollection = createLayerDefinitionsCollection(this.model);
|
||||
|
||||
this.userActions = UserActions({
|
||||
userModel: {},
|
||||
analysisDefinitionsCollection: {},
|
||||
analysisDefinitionNodesCollection: {},
|
||||
layerDefinitionsCollection: {},
|
||||
widgetDefinitionsCollection: {}
|
||||
});
|
||||
this.promise = $.Deferred();
|
||||
spyOn(this.userActions, 'saveWidget').and.returnValue(this.promise);
|
||||
|
||||
this.view = new EditorWidgetsView({
|
||||
modals: FactoryModals.createModalService(),
|
||||
userActions: this.userActions,
|
||||
userModel: {},
|
||||
configModel: {},
|
||||
analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
|
||||
widgetDefinitionsCollection: this.widgetDefinitionsCollection,
|
||||
layerDefinitionsCollection: this.layerDefinitionsCollection,
|
||||
stackLayoutModel: jasmine.createSpyObj('stackLayoutModel', ['nextStep'])
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
describe('_initialize', function () {
|
||||
it('should initialize a viewModel with a state', function () {
|
||||
expect(this.view.viewModel).toBeDefined();
|
||||
expect(this.view.viewModel.get('state')).toBeDefined();
|
||||
});
|
||||
|
||||
describe('._initViewState', function () {
|
||||
it('should initialze a viewState that indicates if there is geometry data', function () {
|
||||
expect(this.view._viewState).toBeDefined();
|
||||
expect(this.view._viewState.get('anyGeometryData')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call _setViewState', function () {
|
||||
spyOn(this.view, '_setViewState');
|
||||
|
||||
this.view._initViewState();
|
||||
expect(this.view._setViewState).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('._setViewState', function () {
|
||||
it('should update _viewState and set if there is geometry data', function (done) {
|
||||
this.view._viewState.set('anyGeometryData', false);
|
||||
spyOn(this.layerDefinitionsCollection, 'isThereAnyGeometryData').and.returnValue(Promise.resolve(true));
|
||||
|
||||
this.view._setViewState();
|
||||
|
||||
setTimeout(function () {
|
||||
expect(this.view._viewState.get('anyGeometryData')).toEqual(true);
|
||||
done();
|
||||
}.bind(this), 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
it('should render loading view if state is loading', function () {
|
||||
this.view.viewModel.set({state: STATES.loading});
|
||||
this.view.render();
|
||||
expect(this.view.$('.FormPlaceholder-widget').length).toBe(4);
|
||||
});
|
||||
|
||||
it('should not render no geometry view when _anyGeometryData is true', function () {
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$el.text()).not.toContain('editor.widgets.no-geometry-data');
|
||||
});
|
||||
|
||||
it('should render no geometry view if no data when no geometry data', function () {
|
||||
this.view._viewState.set('anyGeometryData', false);
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$el.text()).toContain('editor.widgets.no-geometry-data');
|
||||
});
|
||||
|
||||
it('should render if widgets collection add one or more widgets', function () {
|
||||
spyOn(this.view, 'render');
|
||||
|
||||
this.view._initBinds();
|
||||
this.widgetDefinitionsCollection.trigger('successAdd');
|
||||
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortable', function () {
|
||||
beforeEach(function () {
|
||||
this.widgetDefModel1 = new WidgetDefinitionModel({
|
||||
id: 'widget-1',
|
||||
type: 'formula',
|
||||
title: 'formula example',
|
||||
layer_id: 'l-100',
|
||||
column: 'areas',
|
||||
operation: 'avg',
|
||||
order: 1
|
||||
}, {
|
||||
configModel: {},
|
||||
mapId: 'm-123'
|
||||
});
|
||||
this.widgetDefModel2 = new WidgetDefinitionModel({
|
||||
id: 'widget-2',
|
||||
type: 'histogram',
|
||||
title: 'histogram example',
|
||||
layer_id: 'l-100',
|
||||
column: 'population',
|
||||
order: 0
|
||||
}, {
|
||||
configModel: {},
|
||||
mapId: 'm-123'
|
||||
});
|
||||
this.widgetDefinitionsCollection.add(this.widgetDefModel1);
|
||||
this.widgetDefinitionsCollection.add(this.widgetDefModel2);
|
||||
});
|
||||
|
||||
it('should be initialized when view is rendered', function () {
|
||||
spyOn(this.view, '_initSortable').and.callThrough();
|
||||
this.view.render();
|
||||
expect(this.view._initSortable).toHaveBeenCalled();
|
||||
expect(this.view.$('.js-widgets').data('ui-sortable')).not.toBeUndefined();
|
||||
});
|
||||
|
||||
it('should be show the widgets in the right order', function () {
|
||||
this.view.render();
|
||||
expect(this.view.$('.js-widgets li:nth-child(1) .js-title').text()).toBe('histogram example');
|
||||
expect(this.view.$('.js-widgets li:nth-child(2) .js-title').text()).toBe('formula example');
|
||||
});
|
||||
|
||||
it('should update the order of the models when sort has finished', function () {
|
||||
this.view.render();
|
||||
expect(this.widgetDefModel2.get('order')).toBe(0);
|
||||
expect(this.widgetDefModel1.get('order')).toBe(1);
|
||||
|
||||
// Impossible to fake sortable behaviour so...
|
||||
this.view.$('.js-widgetItem:eq(1)').insertBefore(this.view.$('.js-widgetItem:eq(0)'));
|
||||
this.view._onSortableFinish();
|
||||
|
||||
// End of fake sortable
|
||||
expect(this.widgetDefModel1.get('order')).toBe(0);
|
||||
expect(this.widgetDefModel2.get('order')).toBe(1);
|
||||
expect(this.userActions.saveWidget).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when adding a widget definition', function () {
|
||||
var widgetDefModel;
|
||||
|
||||
beforeEach(function () {
|
||||
widgetDefModel = new WidgetDefinitionModel({
|
||||
id: 'widget-3',
|
||||
type: 'formula',
|
||||
title: 'AVG districts homes',
|
||||
layer_id: 'l-100',
|
||||
column: 'areas',
|
||||
operation: 'avg'
|
||||
}, {
|
||||
configModel: {},
|
||||
mapId: 'm-123'
|
||||
});
|
||||
this.widgetDefinitionsCollection.add(widgetDefModel);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
this.view.render();
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user