502 lines
17 KiB
JavaScript
502 lines
17 KiB
JavaScript
var Backbone = require('backbone');
|
|
var _ = require('underscore');
|
|
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
|
|
var UserActions = require('builder/data/user-actions');
|
|
var StyleContentView = require('builder/editor/style/style-content-view');
|
|
var StyleDefinitionModel = require('builder/editor/style/style-definition-model');
|
|
var QueryGeometryModel = require('builder/data/query-geometry-model');
|
|
var QuerySchemaModel = require('builder/data/query-schema-model');
|
|
var LayerContentModel = require('builder/data/layer-content-model');
|
|
var AnalysisDefinitionNodesCollection = require('builder/data/analysis-definition-nodes-collection');
|
|
var ConfigModel = require('builder/data/config-model');
|
|
var UserModel = require('builder/data/user-model');
|
|
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
|
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
|
var QueryRowsCollection = require('builder/data/query-rows-collection');
|
|
var FactoryModals = require('../../factories/modals');
|
|
var styleSQLErrorTemplate = require('builder/editor/style/style-content-sql-error.tpl');
|
|
var actionErrorTemplate = require('builder/editor/layers/sql-error-action.tpl');
|
|
var fakePromise = require('fixtures/builder/fake-promise.fixture.js');
|
|
|
|
describe('editor/style/style-content-view', function () {
|
|
beforeEach(function () {
|
|
this.configModel = new ConfigModel({
|
|
base_url: '/u/pepe'
|
|
});
|
|
|
|
this.userModel = new UserModel({}, {
|
|
configModel: this.configModel
|
|
});
|
|
spyOn(this.userModel, 'featureEnabled').and.returnValue(true);
|
|
|
|
this.overlayModel = new Backbone.Model({
|
|
visible: false
|
|
});
|
|
|
|
this.model = new StyleDefinitionModel({
|
|
autogenerated: true
|
|
});
|
|
|
|
spyOn(MetricsTracker, 'track');
|
|
|
|
var attrs = {
|
|
query: 'SELECT * FROM table',
|
|
state: 'unfetched',
|
|
ready: true
|
|
};
|
|
var opts = {
|
|
configModel: this.configModel
|
|
};
|
|
this.querySchemaModel = new QuerySchemaModel(attrs, opts);
|
|
this.queryGeometryModel = new QueryGeometryModel(attrs, opts);
|
|
|
|
this.analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
|
|
configModel: this.configModel,
|
|
userModel: this.userModel
|
|
});
|
|
|
|
this.a0 = this.analysisDefinitionNodesCollection.add({
|
|
id: 'a0',
|
|
type: 'source',
|
|
table_name: 'foo'
|
|
});
|
|
spyOn(this.a0, 'isCustomQueryApplied').and.returnValue(false);
|
|
|
|
this.layerDefinitionsCollection = new LayerDefinitionsCollection(null, {
|
|
configModel: this.configModel,
|
|
userModel: this.userModel,
|
|
analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
|
|
mapId: 'm123',
|
|
stateDefinitionModel: {}
|
|
});
|
|
this.layerDefinitionsCollection.isThereAnyTorqueLayer = function () {};
|
|
this.layerDefinitionModel = new LayerDefinitionModel({
|
|
id: 'abc-123',
|
|
kind: 'carto',
|
|
options: {
|
|
type: 'CartoDB',
|
|
color: '#FABADA',
|
|
table_name: 'foo',
|
|
query: 'SELECT * FROM foo',
|
|
tile_style: 'asdasd',
|
|
visible: true
|
|
}
|
|
}, {
|
|
parse: true,
|
|
configModel: this.configModel,
|
|
collection: this.layerDefinitionsCollection
|
|
});
|
|
|
|
this.layerDefinitionModel.styleModel = this.model;
|
|
this.xhrSpy = jasmine.createSpyObj('xhr', ['abort', 'always', 'fail']);
|
|
spyOn(Backbone.Model.prototype, 'sync').and.returnValue(this.xhrSpy);
|
|
|
|
spyOn(this.layerDefinitionModel, 'save').and.callThrough();
|
|
spyOn(this.layerDefinitionModel, 'getAnalysisDefinitionNodeModel').and.returnValue(this.a0);
|
|
|
|
spyOn(this.querySchemaModel, 'fetch');
|
|
spyOn(this.queryGeometryModel, 'fetch');
|
|
spyOn(StyleContentView.prototype, 'render').and.callThrough();
|
|
|
|
this.userActions = UserActions({
|
|
userModel: this.userModel,
|
|
analysisDefinitionsCollection: {},
|
|
analysisDefinitionNodesCollection: {},
|
|
layerDefinitionsCollection: {},
|
|
widgetDefinitionsCollection: {}
|
|
});
|
|
|
|
this.queryRowsCollection = new QueryRowsCollection([], {
|
|
configModel: this.configModel,
|
|
querySchemaModel: this.querySchemaModel
|
|
});
|
|
|
|
spyOn(this.queryRowsCollection, 'fetch');
|
|
|
|
var querySchemaModel = new Backbone.Model();
|
|
querySchemaModel.hasRepeatedErrors = function () { return false; };
|
|
|
|
var queryGeometryModel = new Backbone.Model();
|
|
queryGeometryModel.hasRepeatedErrors = function () { return false; };
|
|
|
|
var queryRowsCollection = new Backbone.Collection();
|
|
queryRowsCollection.hasRepeatedErrors = function () { return false; };
|
|
|
|
this.layerContentModel = new LayerContentModel({}, {
|
|
querySchemaModel: querySchemaModel,
|
|
queryGeometryModel: queryGeometryModel,
|
|
queryRowsCollection: queryRowsCollection
|
|
});
|
|
|
|
this.view = new StyleContentView({
|
|
configModel: this.configModel,
|
|
userModel: this.userModel,
|
|
userActions: this.userActions,
|
|
layerDefinitionsCollection: this.layerDefinitionsCollection,
|
|
layerDefinitionModel: this.layerDefinitionModel,
|
|
queryGeometryModel: this.queryGeometryModel,
|
|
querySchemaModel: this.querySchemaModel,
|
|
queryRowsCollection: this.queryRowsCollection,
|
|
modals: FactoryModals.createModalService(),
|
|
styleModel: this.model,
|
|
overlayModel: this.overlayModel,
|
|
editorModel: new Backbone.Model(),
|
|
freezeTorgeAggregation: jasmine.createSpy('freezeTorgeAggregation'),
|
|
layerContentModel: this.layerContentModel
|
|
});
|
|
|
|
this.view.render();
|
|
});
|
|
|
|
describe('initialize', function () {
|
|
it('should have called to _buildAggregationCarouselCollection to create _carouselCollection and hook up events', function () {
|
|
expect(this.view._carouselCollection).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('.render', function () {
|
|
it('should render properly', function () {
|
|
spyOn(this.view, '_initViews');
|
|
spyOn(this.view, '_toggleOverlay');
|
|
|
|
this.view.render();
|
|
|
|
expect(this.view._initViews).toHaveBeenCalled();
|
|
expect(this.view._toggleOverlay).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should render the "apply" button properly in advanced mode', function () {
|
|
this.view.$('.Options-bar .CDB-Toggle.js-input').click();
|
|
expect(this.view.$('.js-apply').hasClass('.CDB-Size-small')).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
describe('when layer content model has errors', function () {
|
|
describe('.render', function () {
|
|
it('should render properly', function () {
|
|
spyOn(this.view, '_isErrored').and.returnValue(true);
|
|
spyOn(this.view, '_toggleOverlay');
|
|
spyOn(this.view, '_renderError');
|
|
|
|
this.view.render();
|
|
|
|
expect(this.view._renderError).toHaveBeenCalled();
|
|
expect(this.view._toggleOverlay).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when data is filtered', function () {
|
|
describe('.render', function () {
|
|
it('should render properly', function () {
|
|
spyOn(this.view, '_renderFilteredData');
|
|
this.view._viewState.set('isDataFiltered', true);
|
|
|
|
this.view.render();
|
|
|
|
expect(this.view._renderFilteredData).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('._initViews', function () {
|
|
it('should render the form and the carousel', function () {
|
|
this.view._queryGeometryModel.set({ simple_geom: 'point' });
|
|
this.view.render();
|
|
|
|
expect(this.view.$('.Carousel').length).toBe(1);
|
|
expect(this.view.$('.Editor-HeaderInfo').length).toBe(2);
|
|
expect(this.view.$el.children().first().hasClass('js-aggregationTypes')).toBe(true);
|
|
expect(_.size(this.view._subviews)).toBe(2); // [Carousel, Form]
|
|
});
|
|
|
|
it('should not render carousel view when geometry is not point', function () {
|
|
expect(this.view.$('.Carousel').length).toBe(0);
|
|
expect(this.view.$('.Editor-HeaderInfo').length).toBe(1);
|
|
expect(_.size(this.view._subviews)).toBe(1); // [Form]
|
|
});
|
|
|
|
it('should render the "apply" button properly in advanced mode', function () {
|
|
this.view.$('.Options-bar .CDB-Toggle.js-input').click();
|
|
expect(this.view.$('.js-apply').hasClass('.CDB-Size-small')).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
describe('._initBinds', function () {
|
|
it('should call ._onAutoStyleChanged when _layerDefinitionModel:autoStyle changes', function () {
|
|
spyOn(this.view, '_onAutoStyleChanged');
|
|
|
|
this.view._initBinds();
|
|
this.view._layerDefinitionModel.set({ autoStyle: true });
|
|
|
|
expect(this.view._onAutoStyleChanged).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call .render when layerContentModel:state changes', function () {
|
|
this.view._initBinds();
|
|
this.view._layerContentModel.trigger('change:state');
|
|
|
|
expect(this.view.render).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call .render when _styleModel:render undo', function () {
|
|
this.view._initBinds();
|
|
this.view._styleModel.trigger('undo');
|
|
|
|
expect(this.view.render).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call .render when _styleModel:render redo', function () {
|
|
this.view._initBinds();
|
|
this.view._styleModel.trigger('redo');
|
|
|
|
expect(this.view.render).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call ._onStyleChanged when _layerDefinitionModel changes', function () {
|
|
spyOn(this.view, '_onStyleChanged');
|
|
|
|
this.view._initBinds();
|
|
this.view._layerDefinitionModel.set({ test: true });
|
|
|
|
expect(this.view._onStyleChanged).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call ._checkEditorModel when _layerContentModel:state changes', function () {
|
|
spyOn(this.view, '_checkEditorModel');
|
|
|
|
this.view._initBinds();
|
|
this.view._layerContentModel.trigger('change:state');
|
|
|
|
expect(this.view._checkEditorModel).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call ._toggleOverlay when _overlayModel:visible changes', function () {
|
|
spyOn(this.view, '_toggleOverlay');
|
|
|
|
this.view._initBinds();
|
|
this.view._overlayModel.trigger('change:visible');
|
|
|
|
expect(this.view._toggleOverlay).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call _setViewValues if layerContentModel:state changes', function () {
|
|
spyOn(this.view, '_setViewValues');
|
|
|
|
this.view._initBinds();
|
|
this.view._layerContentModel.trigger('change:state');
|
|
|
|
expect(this.view._setViewValues).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call _checkEditorModel if layerContentModel:state changes', function () {
|
|
spyOn(this.view, '_checkEditorModel');
|
|
|
|
this.view._initBinds();
|
|
this.view._layerContentModel.trigger('change:state');
|
|
|
|
expect(this.view._checkEditorModel).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call render if _queryGeometryModel:status changes', function () {
|
|
this.view._initBinds();
|
|
this.view._queryGeometryModel.trigger('change:status');
|
|
|
|
expect(this.view.render).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('._initViewState', function () {
|
|
it('should initialize _viewState model', function () {
|
|
expect(this.view._viewState).toBeDefined();
|
|
expect(this.view._viewState.get('isDataFiltered')).toEqual(false);
|
|
});
|
|
|
|
it('should call _setViewValues', function () {
|
|
spyOn(this.view, '_setViewValues');
|
|
|
|
this.view._initViewState();
|
|
expect(this.view._setViewValues).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('._setViewValues', function () {
|
|
it('should update _viewState', function (done) {
|
|
spyOn(this.view._layerDefinitionModel, 'isDataFiltered').and.returnValue(Promise.resolve(true));
|
|
this.view._viewState.set('isDataFiltered', false, { silent: true });
|
|
|
|
this.view._setViewValues();
|
|
|
|
setTimeout(function () {
|
|
expect(this.view._viewState.get('isDataFiltered')).toEqual(true);
|
|
done();
|
|
}.bind(this), 0);
|
|
});
|
|
});
|
|
|
|
describe('._buildAggregationCarouselCollection', function () {
|
|
it('should create _carouselCollection and listen to change:selected event', function () {
|
|
spyOn(this.view, '_onSelectAggregation');
|
|
var carouselCollection = this.view._buildAggregationCarouselCollection();
|
|
|
|
expect(carouselCollection).toBeDefined();
|
|
|
|
this.view._carouselCollection.trigger('change:selected');
|
|
|
|
expect(this.view._onSelectAggregation).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('._renderCarousel', function () {
|
|
it('should append carousel markup', function () {
|
|
this.view.$el.html('');
|
|
spyOn(this.view, '_buildAggregationCarouselCollection').and.callThrough();
|
|
|
|
this.view._renderCarousel();
|
|
|
|
expect(this.view.$('ul.Carousel-list > li.Carousel-item').length).toBe(2);
|
|
expect(this.view._buildAggregationCarouselCollection).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('._toggleOverlay', function () {
|
|
it('should toggle overlay', function () {
|
|
expect(this.view.$el.hasClass('is-disabled')).toBe(false);
|
|
|
|
this.view._overlayModel.set('visible', true, { silent: true });
|
|
this.view._toggleOverlay();
|
|
|
|
expect(this.view.$el.hasClass('is-disabled')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('._renderError', function () {
|
|
it('should render the correct template', function () {
|
|
var expectedMarkup = styleSQLErrorTemplate({
|
|
body: _t('editor.error-query.body', {
|
|
action: actionErrorTemplate({
|
|
label: _t('editor.error-query.label')
|
|
})
|
|
})
|
|
});
|
|
|
|
this.view.$el.empty();
|
|
this.view._renderError();
|
|
|
|
expect(this.view.$el.html()).toContain(expectedMarkup);
|
|
});
|
|
});
|
|
|
|
describe('._renderFilteredData', function () {
|
|
it('should render the correct template', function () {
|
|
this.view._renderFilteredData();
|
|
|
|
expect(this.view.$el.html()).toContain('editor.layers.warnings.no-data.message');
|
|
expect(this.view.$el.html()).toContain('editor.layers.warnings.no-data.action-message');
|
|
});
|
|
});
|
|
|
|
describe('on style changed', function () {
|
|
beforeEach(function () {
|
|
spyOn(this.model, 'removeStylesPreAutoStyle');
|
|
this.layerDefinitionModel.save.calls.reset();
|
|
|
|
// Fake styleModel change
|
|
var fillAttrs = _.clone(this.model.get('fill'));
|
|
fillAttrs.size = 34;
|
|
this.model.set('fill', fillAttrs);
|
|
});
|
|
|
|
it('should remove autogenerated attribute', function () {
|
|
expect(this.model.get('autogenerated')).toBeFalsy();
|
|
});
|
|
|
|
it('should remove styles pre autostyle if autostyle', function () {
|
|
this.layerDefinitionModel.set({autoStyle: true}, {silent: true});
|
|
this.model._stylesPreAutoStyle = true;
|
|
var fillAttrs = _.clone(this.model.get('fill'));
|
|
fillAttrs.size = 12;
|
|
this.model.set('fill', fillAttrs);
|
|
expect(this.model.get('autogenerated')).toBeFalsy();
|
|
expect(this.model.removeStylesPreAutoStyle).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should not change cartocss_custom property when styleModel changes', function () {
|
|
this.layerDefinitionModel.set('cartocss_custom', true);
|
|
var fillAttrs = _.clone(this.model.get('fill'));
|
|
fillAttrs.size = 12;
|
|
this.model.set('fill', fillAttrs);
|
|
expect(this.layerDefinitionModel.get('cartocss_custom')).toBe(true);
|
|
});
|
|
|
|
it('should save the layer', function () {
|
|
expect(this.layerDefinitionModel.save.calls.count()).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('autoStyle', function () {
|
|
it('render on autostyle changes', function () {
|
|
this.layerDefinitionModel.set({autoStyle: false});
|
|
expect(StyleContentView.prototype.render).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('_checkEditorModel', function () {
|
|
var hasGeomPromise = null;
|
|
|
|
beforeEach(function () {
|
|
hasGeomPromise = fakePromise(this.view._queryGeometryModel, 'hasValueAsync');
|
|
});
|
|
|
|
afterEach(function () {
|
|
hasGeomPromise = null;
|
|
});
|
|
|
|
it('set _editorModel to disabled if _isErrored when the hasGeom promise resolves', function (done) {
|
|
var self = this;
|
|
spyOn(this.view, '_isErrored').and.returnValue(true);
|
|
this.view._editorModel.set({ disabled: false }, { silent: true });
|
|
|
|
this.view._checkEditorModel();
|
|
hasGeomPromise.resolve(true);
|
|
|
|
setTimeout(function () {
|
|
expect(self.view._editorModel.get('disabled')).toBe(true);
|
|
done();
|
|
}, 0);
|
|
});
|
|
|
|
it('set _editorModel to disabled if hasGeom resolve with false', function (done) {
|
|
var self = this;
|
|
spyOn(this.view, '_isErrored').and.returnValue(false);
|
|
this.view._editorModel.set({ disabled: false }, { silent: true });
|
|
|
|
this.view._checkEditorModel();
|
|
hasGeomPromise.resolve(false);
|
|
|
|
setTimeout(function () {
|
|
expect(self.view._editorModel.get('disabled')).toBe(true);
|
|
done();
|
|
}, 0);
|
|
});
|
|
|
|
it('set _editorModel to enabled if hasGeom resolve with true and not _isErrored', function (done) {
|
|
var self = this;
|
|
spyOn(this.view, '_isErrored').and.returnValue(false);
|
|
this.view._editorModel.set({ disabled: true }, { silent: true });
|
|
|
|
this.view._checkEditorModel();
|
|
hasGeomPromise.resolve(true);
|
|
|
|
setTimeout(function () {
|
|
expect(self.view._editorModel.get('disabled')).toBe(false);
|
|
done();
|
|
}, 0);
|
|
});
|
|
});
|
|
|
|
it('should not have leaks', function () {
|
|
expect(this.view).toHaveNoLeaks();
|
|
});
|
|
});
|