Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -0,0 +1,290 @@
var Backbone = require('backbone');
var $ = require('jquery');
var TableHeadItemView = require('builder/components/table/head/table-head-item-view');
var TableViewModel = require('builder/components/table/table-view-model');
var UserModel = require('builder/data/user-model');
var AnalysisDefinitionNodeSourceModel = require('builder/data/analysis-definition-node-source-model');
var QueryColumnsCollection = require('builder/data/query-columns-collection');
var FactoryModals = require('../../../factories/modals');
var simulateESCKeyPress = function () {
var e = $.Event('keydown');
e.keyCode = e.which = $.ui.keyCode.ESCAPE;
$(document).trigger(e);
};
var simulateENTERKeyPress = function () {
var e = $.Event('keydown');
e.keyCode = e.which = $.ui.keyCode.ENTER;
$(document).trigger(e);
};
describe('components/table/head/table-head-item-view', function () {
beforeEach(function () {
this.configModel = new Backbone.Model();
var userModel = new UserModel({
name: 'hello'
}, {
configModel: this.configModel
});
this.configModel.getSqlApiUrl = function () { return ''; };
this.analysisDefinitionNodeModel = new AnalysisDefinitionNodeSourceModel({
query: 'select * from pepito',
table_name: 'pepito',
id: 'dummy-id'
}, {
configModel: this.configModel,
userModel: userModel
});
this.columnsCollection = new QueryColumnsCollection([
{
name: 'cartodb_id',
type: 'number'
}, {
name: 'description',
type: 'string'
}
], {
querySchemaModel: this.analysisDefinitionNodeModel.querySchemaModel,
configModel: this.configModel
});
spyOn(this.columnsCollection, 'create');
this.tableViewModel = new TableViewModel({
tableName: 'pepito'
}, {
analysisDefinitionNodeModel: this.analysisDefinitionNodeModel,
columnsCollection: this.columnsCollection
});
spyOn(this.analysisDefinitionNodeModel, 'isCustomQueryApplied').and.returnValue(false);
spyOn(this.analysisDefinitionNodeModel, 'isReadOnly').and.returnValue(false);
this.model = this.columnsCollection.at(1);
spyOn(this.model, 'save');
this.modals = FactoryModals.createModalService();
this.view = new TableHeadItemView({
model: this.model,
columnsCollection: this.columnsCollection,
tableViewModel: this.tableViewModel,
simpleGeometry: 'point',
modals: this.modals
});
});
describe('column-options', function () {
beforeEach(function () {
this._makeClick = function () {
this.view.$('.js-columnOptions').click();
}.bind(this);
this.view.render();
});
it('should open options when options is clicked', function () {
this._makeClick();
expect(this.view._menuView).toBeDefined();
});
it('should highlight/unhighlight when options is opened/closed', function () {
this._makeClick();
expect(this.view.$el.hasClass('is-highlighted')).toBeTruthy();
simulateESCKeyPress();
expect(this.view.$el.hasClass('is-highlighted')).toBeFalsy();
});
describe('table-binds', function () {
beforeEach(function () {
spyOn(this.view, '_initScrollBinding');
spyOn(this.view, '_destroyScrollBinding');
});
it('should bind / unbind table scroll when it is opened / hidden', function () {
this._makeClick();
expect(this.view._initScrollBinding).toHaveBeenCalled();
simulateESCKeyPress();
expect(this.view._destroyScrollBinding).toHaveBeenCalled();
});
});
describe('number of options', function () {
it('should show all options', function () {
this._makeClick();
expect(this.view._menuView.collection.size()).toBe(5);
});
it('should not show all options when table view model is disabled', function () {
spyOn(this.tableViewModel, 'isDisabled').and.returnValue(true);
this._makeClick();
expect(this.view._menuView.collection.size()).toBe(1);
});
it('should not show create/update/delete options if column is geometry', function () {
spyOn(this.model, 'isGeometryColumn').and.returnValue(true);
this.view.render();
this._makeClick();
var items = this.view._menuView.collection;
expect(items.size()).toBe(2);
expect(items.at(0).get('val')).toBe('order');
expect(items.at(1).get('val')).toBe('create');
});
it('should not show create/update/delete options if column is cartodb_id', function () {
spyOn(this.model, 'isCartoDBIDColumn').and.returnValue(true);
this.view.render();
this._makeClick();
var items = this.view._menuView.collection;
expect(items.size()).toBe(2);
expect(items.at(0).get('val')).toBe('order');
expect(items.at(1).get('val')).toBe('create');
});
});
describe('actions', function () {
beforeEach(function () {
spyOn(this.tableViewModel, 'isDisabled').and.returnValue(false);
spyOn(this.model, 'isEditable').and.returnValue(true);
this._makeClick();
this._menuView = this.view._menuView;
});
it('should change table-view-model when order is changed', function () {
spyOn(this.tableViewModel, 'set');
this._menuView.$('.js-asc').click();
expect(this.tableViewModel.set).toHaveBeenCalledWith({ sort_order: 'asc', order_by: 'description' });
});
it('should start editing when rename option is clicked', function () {
spyOn(this.view, '_startEditing');
this._menuView.$('[data-val="rename"]').click();
expect(this.view._startEditing).toHaveBeenCalled();
});
it('should change column type when change option and type is clicked', function () {
spyOn(this.view, '_changeColumnType');
this._menuView.$('[data-val="change"]').click();
this._menuView.$('.Table-columnTypeMenu .js-listItem:eq(0)').click();
expect(this.view._changeColumnType).toHaveBeenCalled();
});
it('should add a new column when change create is clicked', function () {
spyOn(this.view, '_addColumn');
this._menuView.$('[data-val="create"]').click();
expect(this.view._addColumn).toHaveBeenCalled();
});
it('should remove column when remove option is clicked', function () {
spyOn(this.view, '_removeColumn');
this._menuView.$('[data-val="delete"]').click();
expect(this.view._removeColumn).toHaveBeenCalled();
});
});
});
describe('rename', function () {
beforeEach(function () {
this.view.render();
this.$input = this.view.$('.js-attribute');
this._makeDblClick = function () {
this.view.$('.js-attribute').dblclick();
}.bind(this);
});
it('should let edit attribute name if double clicked over it', function () {
spyOn(this.model, 'isEditable').and.returnValue(true);
spyOn(this.tableViewModel, 'isDisabled').and.returnValue(true);
spyOn(this.view, '_startEditing');
this._makeDblClick();
expect(this.view._startEditing).not.toHaveBeenCalled();
this.tableViewModel.isDisabled.and.returnValue(false);
this.model.isEditable.and.returnValue(false);
this._makeDblClick();
expect(this.view._startEditing).not.toHaveBeenCalled();
this.model.isEditable.and.returnValue(true);
this.tableViewModel.isDisabled.and.returnValue(false);
this._makeDblClick();
expect(this.view._startEditing).toHaveBeenCalled();
});
it('should add is-active class, remove readonly and bind changes when it is edited', function () {
spyOn(this.view, '_initRenameBinds');
this._makeDblClick();
expect(this.$input.hasClass('is-active')).toBeTruthy();
expect(this.$input.get(0).hasAttribute('readonly')).toBeFalsy();
expect(this.view._initRenameBinds).toHaveBeenCalled();
});
it('should remove is-active class, add readonly and unbind changes when it is finished/closed', function () {
this._makeDblClick();
spyOn(this.view, '_destroyRenameBinds');
simulateESCKeyPress();
expect(this.$input.val()).toBe(this.model.get('name'));
expect(this.$input.hasClass('is-active')).toBeFalsy();
expect(this.$input.get(0).hasAttribute('readonly')).toBeTruthy();
expect(this.view._destroyRenameBinds).toHaveBeenCalled();
});
it('should save name change when ENTER is pressed', function () {
spyOn(this.view, '_saveNewName');
this._makeDblClick();
simulateENTERKeyPress();
expect(this.view._saveNewName).toHaveBeenCalled();
});
it('should discard name change when ESC is pressed', function () {
spyOn(this.view, '_saveNewName');
this._makeDblClick();
simulateESCKeyPress();
expect(this.view._saveNewName).not.toHaveBeenCalled();
});
it('should open confirmation modal when name is changed', function () {
spyOn(this.model, 'isEditable').and.returnValue(true);
spyOn(this.modals, 'create');
this._makeDblClick();
this.$input.val('helloooo');
simulateENTERKeyPress();
expect(this.modals.create).toHaveBeenCalled();
});
});
describe('.focusInput', function () {
beforeEach(function () {
this.view.render();
this.$input = this.view.$('.js-attribute');
this.$input.val('title');
});
it('should start editing', function () {
spyOn(this.view, '_startEditing');
this.view.focusInput();
expect(this.view._startEditing).toHaveBeenCalled();
});
it('should select the input', function () {
spyOn(this.$input[0], 'select');
this.view.focusInput();
expect(this.$input[0].select).toHaveBeenCalled();
});
});
it('should disable scroll binding and document keypress when view is cleaned', function () {
spyOn(this.view, '_destroyScrollBinding');
spyOn(this.view, '_destroyRenameBinds');
this.view.clean();
expect(this.view._destroyScrollBinding).toHaveBeenCalled();
expect(this.view._destroyRenameBinds).toHaveBeenCalled();
});
it('should have no leaks', function () {
expect(this.view).toHaveNoLeaks();
});
afterEach(function () {
this.view.clean();
});
});
@@ -0,0 +1,60 @@
var TableHeadOptionsItemView = require('builder/components/table/head/table-head-options-item-view');
var tableHeadOptionsItemTemplate = require('builder/components/table/head/table-head-options-item.tpl');
var CustomListItemModel = require('builder/components/custom-list/custom-list-item-model');
describe('components/table/head/table-head-options-item-view', function () {
beforeEach(function () {
this.model = new CustomListItemModel({
label: 'cartodb_id',
type: 'number',
isLastColumns: false,
val: 'change'
});
this.view = new TableHeadOptionsItemView({
model: this.model,
template: tableHeadOptionsItemTemplate
});
});
describe('render', function () {
beforeEach(function () {
this.view.render();
});
it('should be rendered properly', function () {
expect(this.view.$('.CDB-ListDecoration-itemLink').length).toBe(1);
});
it('should render order with both order ways, asc and desc', function () {
this.model.set('val', 'order');
this.view.render();
expect(this.view.$('.js-asc').length).toBe(1);
expect(this.view.$('.js-desc').length).toBe(1);
});
it('should render change an arrow at the end', function () {
this.model.set('val', 'change');
this.view.render();
expect(this.view.$('.CDB-IconFont-rArrowLight').length).toBe(1);
});
});
describe('bind', function () {
it('should open sub menu if option is change', function () {
this.model.set('val', 'change');
spyOn(this.view, '_openSubContextMenu');
this.view.render();
this.view.$el.click();
expect(this.view._openSubContextMenu).toHaveBeenCalled();
expect(this.model.get('selected')).toBeFalsy();
});
});
it('should have no leaks', function () {
expect(this.view).toHaveNoLeaks();
});
afterEach(function () {
this.view.clean();
});
});
@@ -0,0 +1,192 @@
var Backbone = require('backbone');
var TableHeadView = require('builder/components/table/head/table-head-view');
var TableViewModel = require('builder/components/table/table-view-model');
var QuerySchemaModel = require('builder/data/query-schema-model');
var QueryGeometryModel = require('builder/data/query-geometry-model');
var QueryColumnModel = require('builder/data/query-column-model');
var configModelFixture = require('fixtures/builder/config-model.fixture');
var FactoryModals = require('../../../factories/modals');
describe('components/table/head/table-head-view', function () {
beforeEach(function () {
var configModel = this.configModel = configModelFixture();
this.querySchemaModel = new QuerySchemaModel({
status: 'fetched',
query: 'SELECT * FROM pepito'
}, {
configModel: configModel
});
this.queryGeometryModel = new QueryGeometryModel({
status: 'fetched',
simple_geom: 'point',
query: 'SELECT * FROM pepito'
}, {
configModel: configModel
});
this.analysisDefinitionNodeModel = new Backbone.Model();
this.analysisDefinitionNodeModel.isReadOnly = function () {
return false;
};
this.analysisDefinitionNodeModel.isCustomQueryApplied = function () { return false; };
this.tableViewModel = new TableViewModel({
tableName: 'pepito'
}, {
columnsCollection: new Backbone.Collection(),
analysisDefinitionNodeModel: this.analysisDefinitionNodeModel
});
this.columnsCollection = new Backbone.Collection([
{
name: 'cartodb_id',
type: 'number'
}, {
name: 'description',
type: 'string'
}, {
name: 'the_geom_webmercator',
type: 'geometry'
}, {
name: 'center',
type: 'geometry'
}
].map(
function (model) { return new QueryColumnModel(model, { configModel: configModel }); })
);
this.view = new TableHeadView({
columnsCollection: this.columnsCollection,
tableViewModel: this.tableViewModel,
querySchemaModel: this.querySchemaModel,
queryGeometryModel: this.queryGeometryModel,
canHideColumns: false,
modals: FactoryModals.createModalService()
});
});
describe('render', function () {
beforeEach(function () {
spyOn(this.view, '_renderColumnHead').and.callThrough();
this.view.render();
});
it('should render as many columns as column collection items has, except mercator', function () {
expect(this.view._renderColumnHead).toHaveBeenCalled();
expect(this.view._renderColumnHead.calls.count()).toBe(this.columnsCollection.length);
expect(this.view.$('.Table-headItem').length).toBe(this.columnsCollection.length - 1); // all but the_geom_webmercator
expect(this.view.$('.js-attribute[value="the_geom_webmercator"]').length).toBe(0);
});
it('should render the_geom_webmercator when a custom query is applied', function () {
spyOn(this.tableViewModel, 'isCustomQueryApplied').and.returnValue(true);
this.view.render();
expect(this.view.$('.Table-headItem').length).toBe(this.columnsCollection.length);
expect(this.view.$('.js-attribute[value="the_geom_webmercator"]').length).toBe(1);
});
describe('when can hide columns flag is true', function () {
it('should not render center geometry columns', function () {
spyOn(this.tableViewModel, 'isCustomQueryApplied').and.returnValue(true);
this.view = new TableHeadView({
columnsCollection: this.columnsCollection,
tableViewModel: this.tableViewModel,
querySchemaModel: this.querySchemaModel,
queryGeometryModel: this.queryGeometryModel,
canHideColumns: true,
modals: FactoryModals.createModalService()
});
this.view.render();
expect(this.view.$('.Table-headItem').length).toBe(this.columnsCollection.length - 1);
expect(this.view.$('.js-attribute[value="center"]').length).toBe(0);
});
});
});
describe('binds', function () {
beforeEach(function () {
spyOn(this.view, 'render').and.callThrough();
spyOn(this.view, '_scrollToLeft');
spyOn(this.view, '_focusLastHeadItem');
this.view.render();
});
it('should render when table view model changes its sort', function () {
this.tableViewModel.set('sort_order', 'desc');
expect(this.view.render).toHaveBeenCalled();
});
it('should render when table view model changes its order', function () {
this.tableViewModel.set('order_by', 'description');
expect(this.view.render).toHaveBeenCalled();
});
it('should render when simple geometry has changed', function () {
this.queryGeometryModel.set('simple_geom', 'polygon');
expect(this.view.render).toHaveBeenCalled();
});
it('should scroll to left when a new element is added', function () {
jasmine.clock().install();
this.columnsCollection.add(new QueryColumnModel({
name: 'hey',
type: 'date'
}, { configModel: this.configModel }));
// When a new column is added, query schema modal is fetched,
// then columnsCollection is reseted again.
this.columnsCollection.trigger('reset');
jasmine.clock().tick(501);
expect(this.view._scrollToLeft).toHaveBeenCalled();
this.view._scrollToLeft.calls.reset();
this.columnsCollection.remove(this.columnsCollection.at(2));
this.columnsCollection.trigger('reset');
jasmine.clock().tick(501);
expect(this.view._scrollToLeft).not.toHaveBeenCalled();
jasmine.clock().uninstall();
});
it('should focus new element input when a new element is added', function () {
jasmine.clock().install();
this.columnsCollection.add(new QueryColumnModel({
name: 'hey',
type: 'date'
}, { configModel: this.configModel }));
// When a new column is added, query schema modal is fetched,
// then columnsCollection is reseted again.
this.columnsCollection.trigger('reset');
jasmine.clock().tick(501);
expect(this.view._focusLastHeadItem).toHaveBeenCalled();
this.view._focusLastHeadItem.calls.reset();
this.columnsCollection.remove(this.columnsCollection.at(2));
this.columnsCollection.trigger('reset');
jasmine.clock().tick(501);
expect(this.view._focusLastHeadItem).not.toHaveBeenCalled();
jasmine.clock().uninstall();
});
});
describe('._focusLastHeadItem', function () {
it('should call `_lastHeadItemView.focusInput` if _lastHeadItemView is not null', function () {
this.view._lastHeadItemView = {
focusInput: function () { }
};
spyOn(this.view._lastHeadItemView, 'focusInput');
this.view._focusLastHeadItem();
expect(this.view._lastHeadItemView.focusInput).toHaveBeenCalled();
});
});
it('should have no leaks', function () {
expect(this.view).toHaveNoLeaks();
});
afterEach(function () {
this.view.clean();
});
});