828 lines
28 KiB
JavaScript
828 lines
28 KiB
JavaScript
|
var _ = require('underscore');
|
||
|
var $ = require('jquery');
|
||
|
var Backbone = require('backbone');
|
||
|
var AnalysisDefinitionNodeSourceModel = require('builder/data/analysis-definition-node-source-model');
|
||
|
var AnalysisFormsCollection = require('builder/editor/layers/layer-content-views/analyses/analysis-forms-collection');
|
||
|
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||
|
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||
|
var LayerContentView = require('builder/editor/layers/layer-content-view');
|
||
|
var ConfigModel = require('builder/data/config-model');
|
||
|
var UserModel = require('builder/data/user-model');
|
||
|
var EditorModel = require('builder/data/editor-model');
|
||
|
var UserNotifications = require('builder/data/user-notifications');
|
||
|
var AnalysesService = require('builder/editor/layers/layer-content-views/analyses/analyses-service');
|
||
|
var FactoryModals = require('../../factories/modals');
|
||
|
var Router = require('builder/routes/router');
|
||
|
|
||
|
describe('editor/layers/layer-content-view/layer-content-view', function () {
|
||
|
var view;
|
||
|
var analysisDefinitionNodeModel;
|
||
|
var editorModel;
|
||
|
var layerDefinitionModel;
|
||
|
var dashboardCanvasEl;
|
||
|
var handleRouteSpy;
|
||
|
var analysesTabName = 'analyses';
|
||
|
var dataTabName = 'data';
|
||
|
|
||
|
var createViewFn = function (options) {
|
||
|
dashboardCanvasEl = document.createElement('div');
|
||
|
dashboardCanvasEl.className = 'CDB-Dashboard-canvas';
|
||
|
document.body.appendChild(dashboardCanvasEl);
|
||
|
|
||
|
var canvas = document.createElement('div');
|
||
|
canvas.classList.add('CDB-Map-canvas');
|
||
|
dashboardCanvasEl.appendChild(canvas);
|
||
|
|
||
|
var configModel = new ConfigModel({
|
||
|
base_url: '/u/pepe',
|
||
|
user_name: 'pepe',
|
||
|
sql_api_protocol: 'http'
|
||
|
});
|
||
|
|
||
|
var userModel = new UserModel({}, {
|
||
|
configModel: configModel,
|
||
|
username: 'pepe'
|
||
|
});
|
||
|
|
||
|
var mapDefModel = new Backbone.Model({
|
||
|
legends: true
|
||
|
});
|
||
|
|
||
|
layerDefinitionModel = new LayerDefinitionModel({
|
||
|
id: 'l-1',
|
||
|
kind: 'carto',
|
||
|
options: {
|
||
|
source: 'a0',
|
||
|
letter: 'a',
|
||
|
table_name: 'foo'
|
||
|
}
|
||
|
}, {
|
||
|
parse: true,
|
||
|
configModel: configModel
|
||
|
});
|
||
|
|
||
|
var onboardings = new Backbone.Model();
|
||
|
onboardings.create = function () {};
|
||
|
onboardings.destroy = function () {};
|
||
|
|
||
|
analysisDefinitionNodeModel = new AnalysisDefinitionNodeSourceModel({
|
||
|
id: 'a1',
|
||
|
type: 'source',
|
||
|
table_name: 'foo'
|
||
|
}, {
|
||
|
configModel: configModel,
|
||
|
userModel: userModel,
|
||
|
collection: new Backbone.Collection()
|
||
|
});
|
||
|
|
||
|
analysisDefinitionNodeModel.querySchemaModel.attributes.query = 'SELECT * FROM foo';
|
||
|
|
||
|
var layerDefinitionsCollection = new LayerDefinitionsCollection(null, {
|
||
|
configModel: configModel,
|
||
|
userModel: userModel,
|
||
|
analysisDefinitionNodesCollection: new Backbone.Collection(),
|
||
|
mapId: 'map-123',
|
||
|
stateDefinitionModel: {}
|
||
|
});
|
||
|
|
||
|
layerDefinitionsCollection.add(layerDefinitionModel);
|
||
|
|
||
|
var widgetDefinitionsCollection = new Backbone.Collection();
|
||
|
|
||
|
widgetDefinitionsCollection.isThereTimeSeries = function () {
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
widgetDefinitionsCollection.isThereOtherWidgets = function () {
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
spyOn(layerDefinitionModel, 'getAnalysisDefinitionNodeModel').and.returnValue(analysisDefinitionNodeModel);
|
||
|
spyOn(layerDefinitionModel, 'findAnalysisDefinitionNodeModel').and.returnValue(analysisDefinitionNodeModel);
|
||
|
spyOn(Router, 'goToLayerList');
|
||
|
spyOn(Router, 'navigate');
|
||
|
|
||
|
handleRouteSpy = spyOn(LayerContentView.prototype, '_handleRoute');
|
||
|
|
||
|
var onboardingNotification = new UserNotifications({}, {
|
||
|
key: 'builder',
|
||
|
configModel: configModel
|
||
|
});
|
||
|
|
||
|
var visDefinitionModel = new Backbone.Model();
|
||
|
var stackLayoutModel = jasmine.createSpyObj('stackLayoutModel', ['prevStep', 'goToStep']);
|
||
|
|
||
|
AnalysesService.init({
|
||
|
onboardings: onboardings,
|
||
|
layerDefinitionsCollection: layerDefinitionsCollection,
|
||
|
modals: FactoryModals.createModalService(),
|
||
|
userModel: userModel,
|
||
|
configModel: configModel
|
||
|
});
|
||
|
|
||
|
editorModel = new EditorModel({ edition: false });
|
||
|
|
||
|
var viewOptions = {
|
||
|
mapDefinitionModel: mapDefModel,
|
||
|
layerDefinitionModel: layerDefinitionModel,
|
||
|
analysisDefinitionsCollection: new Backbone.Collection(),
|
||
|
analysisDefinitionNodesCollection: new Backbone.Collection(),
|
||
|
layerDefinitionsCollection: layerDefinitionsCollection,
|
||
|
legendDefinitionsCollection: new Backbone.Collection(),
|
||
|
widgetDefinitionsCollection: widgetDefinitionsCollection,
|
||
|
userModel: userModel,
|
||
|
modals: FactoryModals.createModalService(),
|
||
|
onboardings: onboardings,
|
||
|
analysis: {},
|
||
|
userActions: {},
|
||
|
vis: {},
|
||
|
stackLayoutModel: stackLayoutModel,
|
||
|
configModel: configModel,
|
||
|
editorModel: editorModel,
|
||
|
mapModeModel: jasmine.createSpyObj('mapModeModel', ['enterDrawingFeatureMode']),
|
||
|
stateDefinitionModel: {},
|
||
|
onboardingNotification: onboardingNotification,
|
||
|
visDefinitionModel: visDefinitionModel
|
||
|
};
|
||
|
|
||
|
return new LayerContentView(_.extend(viewOptions, options));
|
||
|
};
|
||
|
|
||
|
describe('.initialize', function () {
|
||
|
beforeEach(function () {
|
||
|
spyOn(LayerContentView.prototype, '_updateViewState').and.callThrough();
|
||
|
spyOn(LayerContentView.prototype, '_initViewState').and.callThrough();
|
||
|
spyOn(LayerContentView.prototype, '_initBinds').and.callThrough();
|
||
|
spyOn(AnalysesService, 'setLayerId').and.callThrough();
|
||
|
|
||
|
view = createViewFn();
|
||
|
});
|
||
|
|
||
|
it('should initialize correctly', function () {
|
||
|
expect(view.model._querySchemaModel).toBeDefined();
|
||
|
expect(view.model._queryGeometryModel).toBeDefined();
|
||
|
expect(view.model._queryRowsCollection).toBeDefined();
|
||
|
|
||
|
expect(LayerContentView.prototype._updateViewState).toHaveBeenCalled();
|
||
|
expect(LayerContentView.prototype._initViewState).toHaveBeenCalled();
|
||
|
expect(LayerContentView.prototype._initBinds).toHaveBeenCalled();
|
||
|
expect(AnalysesService.setLayerId).toHaveBeenCalled();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('.render', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
spyOn(view, '_renderHeaderView').and.callThrough();
|
||
|
spyOn(view, '_renderLayerTabPaneView').and.callThrough();
|
||
|
});
|
||
|
|
||
|
it('should render correctly', function () {
|
||
|
view.render();
|
||
|
|
||
|
expect(_.size(view._subviews)).toBe(3); // [Header, Geometry Toolips]
|
||
|
expect(view.$('.Editor-HeaderInfo-titleText').text()).toContain('foo');
|
||
|
});
|
||
|
|
||
|
it('should have no leaks', function () {
|
||
|
expect(view).toHaveNoLeaks();
|
||
|
});
|
||
|
|
||
|
describe('when all query objects are loaded', function () {
|
||
|
beforeEach(function () {
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should render correctly', function () {
|
||
|
expect(_.size(view._subviews)).toBe(3); // [Header, TabPane, Geometry Toolips]
|
||
|
expect(view.$('.Editor-HeaderInfo-titleText').text()).toContain('foo');
|
||
|
expect(view.$('.CDB-NavMenu .CDB-NavMenu-item').length).toBe(5);
|
||
|
expect(view.$('.js-editorPanelContent').length).toBe(1); // Onboarding
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when can be georeferenced', function () {
|
||
|
beforeEach(function () {
|
||
|
view._viewState.set('canBeGeoreferenced', true);
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should disable tabs', function () {
|
||
|
expect(view.$el.find('.CDB-NavMenu-item.is-disabled').length).toBe(3);
|
||
|
});
|
||
|
|
||
|
it('should select the analysis tab', function () {
|
||
|
expect(view._layerTabPaneView.getSelectedTabPaneName()).toBe(analysesTabName);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when analysisDefinitionNodeModel has errors', function () {
|
||
|
beforeEach(function () {
|
||
|
spyOn(analysisDefinitionNodeModel, 'hasFailed').and.returnValue(true);
|
||
|
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should disable tabs properly', function () {
|
||
|
expect(view.$el.find('.CDB-NavMenu-item.is-disabled').length).toBe(3);
|
||
|
});
|
||
|
|
||
|
it('should select the analysis tab', function () {
|
||
|
expect(view._layerTabPaneView.getSelectedTabPaneName()).toBe(analysesTabName);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when is empty', function () {
|
||
|
beforeEach(function () {
|
||
|
spyOn(analysisDefinitionNodeModel.querySchemaModel, 'isDone').and.returnValue(true);
|
||
|
spyOn(analysisDefinitionNodeModel.queryGeometryModel, 'isDone').and.returnValue(true);
|
||
|
spyOn(analysisDefinitionNodeModel.queryRowsCollection, 'isDone').and.returnValue(true);
|
||
|
spyOn(analysisDefinitionNodeModel, 'hasFailed').and.returnValue(false);
|
||
|
|
||
|
view._viewState.set({
|
||
|
isLayerEmpty: true
|
||
|
});
|
||
|
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should select the data tab', function () {
|
||
|
expect(view._layerTabPaneView.getSelectedTabPaneName()).toBe(dataTabName);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._initViewState', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
});
|
||
|
|
||
|
it('should initialize viewState', function () {
|
||
|
view._initViewState();
|
||
|
|
||
|
expect(view._viewState).toBeDefined();
|
||
|
expect(view._viewState.get('isLayerEmpty')).toEqual(false);
|
||
|
expect(view._viewState.get('canBeGeoreferenced')).toEqual(false);
|
||
|
expect(view._viewState.get('isLayerDone')).toEqual(false);
|
||
|
});
|
||
|
|
||
|
it('should call setViewState', function () {
|
||
|
spyOn(view, '_setViewState');
|
||
|
|
||
|
view._initViewState();
|
||
|
|
||
|
expect(view._setViewState).toHaveBeenCalled();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._updateViewState', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
spyOn(view, '_fetchAllQueryObjects').and.returnValue(Promise.resolve(true));
|
||
|
spyOn(view, '_setViewState').and.callThrough();
|
||
|
});
|
||
|
|
||
|
it('should call _setViewState if isDone', function () {
|
||
|
spyOn(view.model, 'isDone').and.returnValue(true);
|
||
|
|
||
|
view._updateViewState();
|
||
|
|
||
|
expect(view._setViewState).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call _setViewState after all queries have been fetched', function (done) {
|
||
|
spyOn(view.model, 'isDone').and.returnValue(false);
|
||
|
|
||
|
view._updateViewState();
|
||
|
|
||
|
setTimeout(function () {
|
||
|
expect(view._setViewState).toHaveBeenCalled();
|
||
|
done();
|
||
|
}, 0);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._setViewState', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
});
|
||
|
|
||
|
describe('set isLayerEmpty', function () {
|
||
|
it('should be setted to true if layer is empty', function (done) {
|
||
|
view.render();
|
||
|
|
||
|
spyOn(view, 'render');
|
||
|
spyOn(view._layerDefinitionModel, 'isEmptyAsync').and.returnValue(Promise.resolve(true));
|
||
|
spyOn(view._layerDefinitionModel, 'canBeGeoreferenced').and.returnValue(Promise.resolve(true));
|
||
|
|
||
|
view._setViewState();
|
||
|
|
||
|
setTimeout(function () {
|
||
|
expect(view._viewState.get('isLayerEmpty')).toEqual(true);
|
||
|
expect(view._viewState.get('canBeGeoreferenced')).toEqual(true);
|
||
|
done();
|
||
|
}, 0);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('set canBeGeoreferenced', function () {
|
||
|
it('should be setted to true if layer can not be georeferenced', function (done) {
|
||
|
view._viewState.set({
|
||
|
isLayerEmpty: true,
|
||
|
canBeGeoreferenced: false
|
||
|
});
|
||
|
|
||
|
view.render();
|
||
|
|
||
|
spyOn(view._layerDefinitionModel, 'isEmptyAsync').and.returnValue(Promise.resolve(true));
|
||
|
spyOn(view._layerDefinitionModel, 'canBeGeoreferenced').and.returnValue(Promise.resolve(true));
|
||
|
|
||
|
view._setViewState();
|
||
|
|
||
|
setTimeout(function () {
|
||
|
expect(view._viewState.get('canBeGeoreferenced')).toEqual(true);
|
||
|
done();
|
||
|
}, 0);
|
||
|
});
|
||
|
|
||
|
it('should be setted to false if layer can be georeferenced', function (done) {
|
||
|
view._viewState.set({
|
||
|
isLayerEmpty: true,
|
||
|
canBeGeoreferenced: true
|
||
|
});
|
||
|
|
||
|
view.render();
|
||
|
|
||
|
spyOn(view._layerDefinitionModel, 'isEmptyAsync').and.returnValue(Promise.resolve(true));
|
||
|
spyOn(view._layerDefinitionModel, 'canBeGeoreferenced').and.returnValue(Promise.resolve(false));
|
||
|
|
||
|
view._setViewState();
|
||
|
|
||
|
setTimeout(function () {
|
||
|
expect(view._viewState.get('canBeGeoreferenced')).toEqual(false);
|
||
|
done();
|
||
|
}, 0);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('set isLayerDone', function () {
|
||
|
// isLayerDone can be false when entering and the UI should respond to that
|
||
|
it('should set isLayerDone when entering the function and again when the promise resolves', function (done) {
|
||
|
view._viewState.set('isLayerDone', true, { silent: true });
|
||
|
spyOn(view._layerDefinitionModel, 'isEmptyAsync').and.returnValue(Promise.resolve(true));
|
||
|
spyOn(view._layerDefinitionModel, 'canBeGeoreferenced').and.returnValue(Promise.resolve(false));
|
||
|
spyOn(view._layerDefinitionModel, 'isDone').and.returnValue(false);
|
||
|
|
||
|
view._setViewState();
|
||
|
|
||
|
expect(view._viewState.get('isLayerDone')).toBe(false);
|
||
|
view._layerDefinitionModel.isDone.and.returnValue(true);
|
||
|
setTimeout(function () {
|
||
|
expect(view._viewState.get('isLayerDone')).toEqual(true);
|
||
|
done();
|
||
|
}, 0);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._renderLayerTabPaneView', function () {
|
||
|
it('should disable all tabs but data is layer is empty', function () {
|
||
|
view = createViewFn();
|
||
|
view._viewState.set({
|
||
|
isLayerEmpty: true,
|
||
|
isLayerDone: true
|
||
|
}, { silent: true });
|
||
|
|
||
|
view._renderLayerTabPaneView();
|
||
|
|
||
|
var tabs = view.$('nav > ul > li');
|
||
|
|
||
|
expect(tabs[0].classList.contains('is-disabled')).toBe(false);
|
||
|
expect(tabs[1].classList.contains('is-disabled')).toBe(true);
|
||
|
expect(tabs[2].classList.contains('is-disabled')).toBe(true);
|
||
|
expect(tabs[3].classList.contains('is-disabled')).toBe(true);
|
||
|
expect(tabs[4].classList.contains('is-disabled')).toBe(true);
|
||
|
});
|
||
|
|
||
|
it('should enable all tabs but data is layer is not empty', function () {
|
||
|
view = createViewFn();
|
||
|
view._viewState.set({
|
||
|
isLayerEmpty: false,
|
||
|
isLayerDone: true
|
||
|
}, { silent: true });
|
||
|
|
||
|
view._renderLayerTabPaneView();
|
||
|
|
||
|
var tabs = view.$('nav > ul > li');
|
||
|
|
||
|
expect(tabs[0].classList.contains('is-disabled')).toBe(false);
|
||
|
expect(tabs[1].classList.contains('is-disabled')).toBe(false);
|
||
|
expect(tabs[2].classList.contains('is-disabled')).toBe(false);
|
||
|
expect(tabs[3].classList.contains('is-disabled')).toBe(false);
|
||
|
expect(tabs[4].classList.contains('is-disabled')).toBe(false);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._onClickBack', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should call goToLayerList in Router', function () {
|
||
|
view.$('.js-back').click();
|
||
|
|
||
|
expect(Router.goToLayerList).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should set editorModel edition to false', function () {
|
||
|
editorModel.set('edition', true, { silent: true });
|
||
|
|
||
|
view.$('.js-back').click();
|
||
|
|
||
|
expect(editorModel.get('edition')).toBe(false);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('.handleRoute', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should create editOverlay', function () {
|
||
|
handleRouteSpy.and.callThrough();
|
||
|
var routeModel = new Backbone.Model({
|
||
|
currentRoute: ['add_feature_']
|
||
|
});
|
||
|
|
||
|
view._handleRoute(routeModel);
|
||
|
|
||
|
expect($(dashboardCanvasEl).find('.js-editOverlay').length).toBe(1);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._renderContextButtons', function () {
|
||
|
var analysisDefNodeModel;
|
||
|
var layerDefinitionModel;
|
||
|
var queryGeometryModel;
|
||
|
var needsGeoSpy;
|
||
|
var isEmptySpy;
|
||
|
|
||
|
function hasTipsy (subviews) {
|
||
|
var newGeomItems = _.filter(subviews, function (elem) {
|
||
|
return elem.el.classList.contains('js-newGeometryView');
|
||
|
});
|
||
|
|
||
|
if (newGeomItems.length === 0) return false;
|
||
|
|
||
|
return newGeomItems.reduce(function (hasTipsy, btn) {
|
||
|
return btn.tipsy && hasTipsy;
|
||
|
}, true);
|
||
|
}
|
||
|
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
view.render();
|
||
|
|
||
|
analysisDefNodeModel = view._getAnalysisDefinitionNodeModel();
|
||
|
layerDefinitionModel = view._layerDefinitionModel;
|
||
|
queryGeometryModel = view._getQueryGeometryModel();
|
||
|
|
||
|
spyOn(analysisDefNodeModel, 'isReadOnly');
|
||
|
needsGeoSpy = spyOn(view._layerDefinitionModel, 'canBeGeoreferenced');
|
||
|
isEmptySpy = spyOn(view._layerDefinitionModel, 'isEmptyAsync');
|
||
|
|
||
|
view._renderContextButtons();
|
||
|
});
|
||
|
|
||
|
afterEach(function () {
|
||
|
view._destroyContextButtons();
|
||
|
});
|
||
|
|
||
|
it('shouldn\'t disable tabs', function () {
|
||
|
needsGeoSpy.and.returnValue(Promise.resolve(false));
|
||
|
isEmptySpy.and.returnValue(Promise.resolve(false));
|
||
|
|
||
|
view.render();
|
||
|
|
||
|
expect(view.$el.find('.CDB-NavMenu-item.is-disabled').length).toBe(0);
|
||
|
});
|
||
|
|
||
|
it('should not create editOverlay tip view', function () {
|
||
|
expect($(dashboardCanvasEl).find('js-editOverlay').length).toBe(0);
|
||
|
});
|
||
|
|
||
|
it('should navigate when click on new geometry', function () {
|
||
|
queryGeometryModel.set('simple_geom', 'point');
|
||
|
analysisDefNodeModel.isReadOnly.and.returnValue(false);
|
||
|
layerDefinitionModel.set('visible', true);
|
||
|
view._renderContextButtons();
|
||
|
|
||
|
$(dashboardCanvasEl).find('.js-newGeometry').trigger('click');
|
||
|
|
||
|
expect(Router.navigate).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should render context switch toggler properly', function () {
|
||
|
expect($(dashboardCanvasEl).find('.Editor-contextSwitcher.js-mapTableView').length).toBe(1);
|
||
|
});
|
||
|
|
||
|
it('should render geometry buttons properly', function () {
|
||
|
expect($(dashboardCanvasEl).find('.Editor-contextSwitcherItem.js-newGeometryItem').length).toBe(3);
|
||
|
});
|
||
|
|
||
|
it('should disable edit geometry buttons when node is read only and visible', function () {
|
||
|
analysisDefNodeModel.isReadOnly.and.returnValue(true);
|
||
|
layerDefinitionModel.set('visible', true);
|
||
|
expect($(dashboardCanvasEl).find('.Editor-contextSwitcherItem.js-newGeometryItem.is-disabled').length).toBe(3);
|
||
|
});
|
||
|
|
||
|
it('should disable edit geometry buttons when node is read only and not visible', function () {
|
||
|
analysisDefNodeModel.isReadOnly.and.returnValue(true);
|
||
|
layerDefinitionModel.set('visible', false);
|
||
|
expect($(dashboardCanvasEl).find('.Editor-contextSwitcherItem.js-newGeometryItem.is-disabled').length).toBe(3);
|
||
|
});
|
||
|
|
||
|
it('should disable edit geometry buttons when node is neither visible nor read only', function () {
|
||
|
analysisDefNodeModel.isReadOnly.and.returnValue(false);
|
||
|
layerDefinitionModel.set('visible', false);
|
||
|
expect($(dashboardCanvasEl).find('.Editor-contextSwitcherItem.js-newGeometryItem.is-disabled').length).toBe(3);
|
||
|
});
|
||
|
|
||
|
it('should not disable edit geometry buttons when node is visible and not read only', function () {
|
||
|
analysisDefNodeModel.isReadOnly.and.returnValue(false);
|
||
|
layerDefinitionModel.set('visible', true);
|
||
|
expect($(dashboardCanvasEl).find('.Editor-contextSwitcherItem.js-newGeometryItem.is-disabled').length).toBe(0);
|
||
|
});
|
||
|
|
||
|
it('should add tipsy subview when not visible or read only', function () {
|
||
|
view.clearSubViews();
|
||
|
analysisDefNodeModel.isReadOnly.and.returnValue(true);
|
||
|
layerDefinitionModel.set('visible', false);
|
||
|
expect(hasTipsy(view._subviews)).toBe(true);
|
||
|
});
|
||
|
|
||
|
it('should not add tipsy subview when not visible or read only', function () {
|
||
|
view.clearSubViews();
|
||
|
analysisDefNodeModel.isReadOnly.and.returnValue(false);
|
||
|
layerDefinitionModel.set('visible', true);
|
||
|
expect(hasTipsy(view._subviews)).toBe(false);
|
||
|
});
|
||
|
|
||
|
it('should display only one button per geometry', function () {
|
||
|
queryGeometryModel.set('simple_geom', 'polygon');
|
||
|
view._renderContextButtons();
|
||
|
expect($(dashboardCanvasEl).find('.Editor-contextSwitcherItem.js-newGeometryItem').length).toBe(1);
|
||
|
});
|
||
|
|
||
|
it('should show the button for the simple_geom type', function () {
|
||
|
queryGeometryModel.set('simple_geom', 'point');
|
||
|
view._renderContextButtons();
|
||
|
expect($(dashboardCanvasEl).find('.js-newGeometry[data-feature-type="point"]').length).toBe(1);
|
||
|
|
||
|
queryGeometryModel.set('simple_geom', 'line');
|
||
|
view._renderContextButtons();
|
||
|
expect($(dashboardCanvasEl).find('.js-newGeometry[data-feature-type="line"]').length).toBe(1);
|
||
|
|
||
|
queryGeometryModel.set('simple_geom', 'polygon');
|
||
|
view._renderContextButtons();
|
||
|
expect($(dashboardCanvasEl).find('.js-newGeometry[data-feature-type="polygon"]').length).toBe(1);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._initBinds', function () {
|
||
|
function buildResponse (geom) {
|
||
|
return {
|
||
|
status: 200,
|
||
|
contentType: 'application/json; charset=utf-8',
|
||
|
responseText: '{"rows":[{"the_geom":"' + geom + '"}],"time":0.005,"fields":{"the_geom":{"type":"string"}},"total_rows":1}'
|
||
|
};
|
||
|
}
|
||
|
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
jasmine.Ajax.install();
|
||
|
});
|
||
|
|
||
|
afterEach(function () {
|
||
|
jasmine.Ajax.uninstall();
|
||
|
});
|
||
|
|
||
|
it('should call _renderContextButtons and set default style properties if there is a change in simple_geom to a valid value', function () {
|
||
|
var queryGeometryModel = view._getQueryGeometryModel();
|
||
|
queryGeometryModel.set('status', 'unfetched');
|
||
|
queryGeometryModel.set('simple_geom', 'point');
|
||
|
queryGeometryModel.set('query', 'SELECT TOP 10 FROM fake_table;');
|
||
|
spyOn(view, '_renderContextButtons');
|
||
|
|
||
|
jasmine.Ajax.stubRequest(/sql/)
|
||
|
.andReturn(buildResponse('polygon'));
|
||
|
view._initBinds();
|
||
|
|
||
|
queryGeometryModel.set('simple_geom', 'polygon');
|
||
|
|
||
|
expect(view._renderContextButtons).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call _renderContextButtons and not set default style properties if there is a change in simple_geom to nothing', function () {
|
||
|
var queryGeometryModel = view._getQueryGeometryModel();
|
||
|
queryGeometryModel.set('status', 'unfetched');
|
||
|
queryGeometryModel.set('simple_geom', 'point');
|
||
|
queryGeometryModel.set('query', 'SELECT TOP 10 FROM fake_table;');
|
||
|
spyOn(view, '_renderContextButtons');
|
||
|
|
||
|
jasmine.Ajax.stubRequest(/sql/)
|
||
|
.andReturn(buildResponse(''));
|
||
|
view._initBinds();
|
||
|
|
||
|
queryGeometryModel.set('simple_geom', '');
|
||
|
|
||
|
expect(view._renderContextButtons).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call _onTogglerChanged if togglerModel:active changes', function () {
|
||
|
spyOn(view, '_onTogglerChanged');
|
||
|
view._initBinds();
|
||
|
view._togglerModel.trigger('change:active');
|
||
|
expect(view._onTogglerChanged).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call handleRoute if routeModel:currentRoute changes', function () {
|
||
|
var routeModel = Router.getRouteModel();
|
||
|
|
||
|
routeModel.trigger('change:currentRoute', routeModel);
|
||
|
|
||
|
expect(view._handleRoute).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call render if analysisDefinitionNodeModel:error changes', function () {
|
||
|
spyOn(view, 'render');
|
||
|
view._initBinds();
|
||
|
analysisDefinitionNodeModel.trigger('change:error');
|
||
|
expect(view.render).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call _updateViewState on change model state', function () {
|
||
|
spyOn(view, 'render');
|
||
|
spyOn(view, '_updateViewState');
|
||
|
|
||
|
view._initBinds();
|
||
|
|
||
|
view.model.set('state', 'fake');
|
||
|
expect(view._updateViewState).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call _updateViewState on change layerDefinitionModel source', function () {
|
||
|
spyOn(view, 'render');
|
||
|
spyOn(view, '_updateViewState');
|
||
|
|
||
|
view._initBinds();
|
||
|
|
||
|
view._layerDefinitionModel.set('source', 'fake');
|
||
|
|
||
|
expect(view._updateViewState).toHaveBeenCalled();
|
||
|
});
|
||
|
}); // end of '._initBinds'
|
||
|
|
||
|
describe('._onTogglerChanged', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should set context correctly', function () {
|
||
|
expect(view.model.get('context')).toEqual('map');
|
||
|
view._togglerModel.set('active', true, { silent: true });
|
||
|
view._onTogglerChanged();
|
||
|
expect(view.model.get('context')).toEqual('table');
|
||
|
|
||
|
view._togglerModel.set('active', false, { silent: true });
|
||
|
view._onTogglerChanged();
|
||
|
expect(view.model.get('context')).toEqual('map');
|
||
|
});
|
||
|
|
||
|
it('should call _initTable if context is table', function () {
|
||
|
spyOn(view, '_initTable');
|
||
|
view._togglerModel.set('active', true, { silent: true });
|
||
|
view._onTogglerChanged();
|
||
|
expect(view._initTable).toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('should call _destroyTable if context is map', function () {
|
||
|
spyOn(view, '_destroyTable');
|
||
|
view._togglerModel.set('active', false, { silent: true });
|
||
|
view._onTogglerChanged();
|
||
|
expect(view._destroyTable).toHaveBeenCalled();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('._isContextTable', function () {
|
||
|
beforeEach(function () {
|
||
|
view = createViewFn();
|
||
|
view.render();
|
||
|
});
|
||
|
|
||
|
it('should return true if model context is table', function () {
|
||
|
expect(view._isContextTable()).toBe(false);
|
||
|
view.model.set('context', 'table', { silent: true });
|
||
|
expect(view._isContextTable()).toBe(true);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when rendering analysis tab', function () {
|
||
|
var addBindingsAndRender = function () {
|
||
|
spyOn(analysisDefinitionNodeModel.querySchemaModel, 'isDone').and.returnValue(true);
|
||
|
spyOn(analysisDefinitionNodeModel.queryGeometryModel, 'isDone').and.returnValue(true);
|
||
|
spyOn(analysisDefinitionNodeModel.queryRowsCollection, 'isDone').and.returnValue(true);
|
||
|
|
||
|
view.render();
|
||
|
};
|
||
|
|
||
|
describe('when analysis payload is a string and its in the formsCollection', function () {
|
||
|
it('should use the analysis payload as selectedNodeId', function () {
|
||
|
var analysisPayload = 'a1';
|
||
|
spyOn(AnalysisFormsCollection.prototype, 'get').and.returnValue(analysisPayload);
|
||
|
view = createViewFn({
|
||
|
selectedTabItem: 'analyses',
|
||
|
analysisPayload: analysisPayload
|
||
|
});
|
||
|
|
||
|
addBindingsAndRender();
|
||
|
|
||
|
var analysesContentView = _.find(view._layerTabPaneView._subviews, function (view) {
|
||
|
return view.className === 'Editor-content';
|
||
|
});
|
||
|
|
||
|
expect(analysesContentView._selectedNodeId).toEqual(analysisPayload);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when analysis payload is an object', function () {
|
||
|
it('should use the analysis payload id key as selectedNodeId', function () {
|
||
|
var analysisPayload = {
|
||
|
id: 'a2'
|
||
|
};
|
||
|
view = createViewFn({
|
||
|
selectedTabItem: 'analyses',
|
||
|
analysisPayload: analysisPayload
|
||
|
});
|
||
|
|
||
|
addBindingsAndRender();
|
||
|
|
||
|
var analysesContentView = _.find(view._layerTabPaneView._subviews, function (view) {
|
||
|
return view.className === 'Editor-content';
|
||
|
});
|
||
|
|
||
|
expect(analysesContentView._selectedNodeId).toEqual(analysisPayload.id);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when analysis payload is null', function () {
|
||
|
describe('when last node exists', function () {
|
||
|
it('should redirect to the last node id', function () {
|
||
|
var lastAnalysisNode = new Backbone.Model({
|
||
|
id: 'a1'
|
||
|
});
|
||
|
spyOn(AnalysisFormsCollection.prototype, 'at').and.returnValue(lastAnalysisNode);
|
||
|
spyOn(Router, 'goToAnalysisNode');
|
||
|
view = createViewFn({
|
||
|
selectedTabItem: 'analyses',
|
||
|
analysisPayload: null
|
||
|
});
|
||
|
|
||
|
addBindingsAndRender();
|
||
|
|
||
|
expect(Router.goToAnalysisNode).toHaveBeenCalledWith(
|
||
|
layerDefinitionModel.get('id'),
|
||
|
lastAnalysisNode.get('id'),
|
||
|
{ trigger: false, replace: true }
|
||
|
);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('when there is no nodes left', function () {
|
||
|
it('should redirect to the analysis tab', function () {
|
||
|
spyOn(Router, 'goToAnalysisTab');
|
||
|
view = createViewFn({
|
||
|
selectedTabItem: 'analyses',
|
||
|
analysisPayload: null
|
||
|
});
|
||
|
|
||
|
addBindingsAndRender();
|
||
|
|
||
|
expect(Router.goToAnalysisTab).toHaveBeenCalledWith(
|
||
|
layerDefinitionModel.get('id'),
|
||
|
{ trigger: false, replace: true }
|
||
|
);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
afterEach(function () {
|
||
|
dashboardCanvasEl.parentNode && dashboardCanvasEl.parentNode.removeChild(dashboardCanvasEl);
|
||
|
view.clean();
|
||
|
});
|
||
|
});
|