Initial commit
This commit is contained in:
+140
@@ -0,0 +1,140 @@
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var AnalysisDefinitionNodessCollection = require('builder/data/analysis-definition-nodes-collection');
|
||||
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||||
var AddAnalysisView = require('builder/components/modals/add-analysis/add-analysis-view');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var DataServicesApiCheck = require('builder/editor/layers/layer-content-views/analyses/analyses-quota/analyses-quota-info');
|
||||
var Router = require('builder/routes/router');
|
||||
|
||||
describe('components/modals/add-analysis/add-analysis-view', function () {
|
||||
beforeEach(function () {
|
||||
this.modalModel = new Backbone.Model();
|
||||
spyOn(this.modalModel, 'destroy');
|
||||
spyOn(Router, 'navigate');
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe',
|
||||
user_name: 'foo',
|
||||
sql_api_template: 'foo',
|
||||
api_key: 'foo'
|
||||
});
|
||||
|
||||
var userModel = new UserModel({}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection = new AnalysisDefinitionNodessCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel
|
||||
});
|
||||
this.a0 = this.analysisDefinitionNodesCollection.add({
|
||||
id: 'a0',
|
||||
type: 'source',
|
||||
params: {
|
||||
query: 'SELECT * from alice'
|
||||
},
|
||||
options: {
|
||||
table_name: 'alice'
|
||||
}
|
||||
});
|
||||
this.layerDefinitionsCollection = new LayerDefinitionsCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel,
|
||||
analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
|
||||
mapId: '123',
|
||||
stateDefinitionModel: new Backbone.Model()
|
||||
});
|
||||
this.layerA = this.layerDefinitionsCollection.add({
|
||||
id: 'layerA',
|
||||
kind: 'carto',
|
||||
options: {
|
||||
source: 'a0',
|
||||
table_name: 'alice'
|
||||
}
|
||||
});
|
||||
|
||||
DataServicesApiCheck.get(configModel)._state = 'fetched';
|
||||
|
||||
this.queryGeometryModel = this.a0.queryGeometryModel;
|
||||
spyOn(this.queryGeometryModel, 'sync');
|
||||
spyOn(this.queryGeometryModel, 'fetch').and.callThrough();
|
||||
|
||||
this.view = new AddAnalysisView({
|
||||
configModel: configModel,
|
||||
userModel: userModel,
|
||||
modalModel: this.modalModel,
|
||||
layerDefinitionModel: this.layerA
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render the loading view', function () {
|
||||
expect(this.view.$el.html()).toContain('loading');
|
||||
});
|
||||
|
||||
describe('when geometry output type is fetched', function () {
|
||||
beforeEach(function () {
|
||||
this.queryGeometryModel.set('simple_geom', 'polygon');
|
||||
this.queryGeometryModel.sync.calls.argsFor(0)[2].success({
|
||||
fields: {},
|
||||
rows: []
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the content view', function () {
|
||||
expect(this.view.$el.html()).not.toContain('loading');
|
||||
expect(this.view.$el.html()).not.toContain('error');
|
||||
});
|
||||
|
||||
it('should render the tabs', function () {
|
||||
expect(this.view.$('.js-menu li').size()).toBe(4);
|
||||
expect(this.view.$('.js-menu li:eq(0) button').html()).toContain('analysis-category.all');
|
||||
expect(this.view.$('.js-menu li:eq(1) button').html()).toContain('analysis-category.create-clean');
|
||||
expect(this.view.$('.js-menu li:eq(2) button').html()).toContain('analysis-category.analyze-predict');
|
||||
expect(this.view.$('.js-menu li:eq(3) button').html()).toContain('analysis-category.data-transformation');
|
||||
});
|
||||
|
||||
describe('when click add when there is no selection', function () {
|
||||
it('should do nothing', function () {
|
||||
this.view.$('.js-add').click();
|
||||
expect(this.modalModel.destroy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when an option is selected', function () {
|
||||
beforeEach(function () {
|
||||
expect(this.view.$('.js-add').hasClass('is-disabled')).toBe(true);
|
||||
var $el = this.view.$('[title*=georeference]').first();
|
||||
expect($el.length).toEqual(1, 'should only click one item (the custom georeference one)');
|
||||
|
||||
$el.click();
|
||||
});
|
||||
|
||||
it('should enable add-button', function () {
|
||||
expect(this.view.$('.js-add').hasClass('is-disabled')).toBe(false);
|
||||
});
|
||||
|
||||
describe('when click add', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('.js-add').click();
|
||||
});
|
||||
|
||||
it('should destroy the modal and pass the created node model', function () {
|
||||
expect(this.modalModel.destroy).toHaveBeenCalled();
|
||||
expect(this.modalModel.destroy.calls.argsFor(0)).toEqual([
|
||||
jasmine.objectContaining({
|
||||
id: 'a1',
|
||||
source: 'a0',
|
||||
type: jasmine.any(String)
|
||||
})
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||||
var CamshaftReference = require('builder/data/camshaft-reference');
|
||||
var AnalysisOptionModel = require('builder/components/modals/add-analysis/analysis-option-models/analysis-option-model');
|
||||
|
||||
describe('builder/components/modals/add-analysis/analysis-option-models/analysis-option-model', function () {
|
||||
beforeEach(function () {
|
||||
this.model = new AnalysisOptionModel({
|
||||
title: 'a Buffer',
|
||||
desc: 'An example of how buffer would/should behave',
|
||||
type_group: 'Specs',
|
||||
dummy: false
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'buffer',
|
||||
radius: 123
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('.acceptsGeometryTypeAsInput', function () {
|
||||
it('should return true for valid geometries', function () {
|
||||
expect(this.model.acceptsGeometryTypeAsInput('point')).toBe(true);
|
||||
expect(this.model.acceptsGeometryTypeAsInput('polygon')).toBe(true);
|
||||
expect(this.model.acceptsGeometryTypeAsInput('line')).toBe(true);
|
||||
|
||||
var model = new AnalysisOptionModel(null, {nodeAttrs: {type: 'trade-area'}});
|
||||
expect(model.acceptsGeometryTypeAsInput('point')).toBe(true);
|
||||
expect(model.acceptsGeometryTypeAsInput('polygon')).toBe(false);
|
||||
});
|
||||
|
||||
it('should skip camshaft geometry validation if our analysis is a dummy one', function () {
|
||||
this.model.set('dummy', true);
|
||||
spyOn(CamshaftReference, 'isValidInputGeometryForType');
|
||||
this.model.acceptsGeometryTypeAsInput('line');
|
||||
expect(CamshaftReference.isValidInputGeometryForType).not.toHaveBeenCalled();
|
||||
this.model.set('dummy', false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getValidInputGeometries', function () {
|
||||
it('should return valid input geometries', function () {
|
||||
expect(this.model.getValidInputGeometries()).toEqual(jasmine.any(Array));
|
||||
expect(this.model.getValidInputGeometries()[0]).toEqual(jasmine.any(String));
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getFormAttrs', function () {
|
||||
beforeEach(function () {
|
||||
this.layerDefModel = new LayerDefinitionModel({
|
||||
id: 'layerA',
|
||||
type: 'cartoDB',
|
||||
letter: 'a',
|
||||
source: 'a0'
|
||||
}, {
|
||||
configModel: {}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a layer with own source', function () {
|
||||
it('should return attrs to create a form model for analysis', function () {
|
||||
expect(this.model.getFormAttrs(this.layerDefModel)).toEqual({
|
||||
id: 'a1',
|
||||
source: 'a0',
|
||||
type: 'buffer',
|
||||
radius: 123
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a layer which source belongs to another layer', function () {
|
||||
beforeEach(function () {
|
||||
this.layerDefModel.set('source', 'b0');
|
||||
});
|
||||
|
||||
it('should return attrs to create a form model for analysis', function () {
|
||||
var attrs = this.model.getFormAttrs(this.layerDefModel);
|
||||
expect(attrs.id).toEqual('a1', 'id should be adapted for layer, not continue on source node');
|
||||
expect(attrs).toEqual({
|
||||
id: 'a1',
|
||||
source: 'b0',
|
||||
type: 'buffer',
|
||||
radius: 123
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
var Backbone = require('backbone');
|
||||
var AnalysisOptionModel = require('builder/components/modals/add-analysis/analysis-option-models/analysis-option-model');
|
||||
var SQLFunctionOptionModel = require('builder/components/modals/add-analysis/analysis-option-models/deprecated-sql-function-option-model');
|
||||
|
||||
describe('deprecated-sql-function-option-model', function () {
|
||||
var model;
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(AnalysisOptionModel.prototype, 'getFormAttrs').and.returnValue({
|
||||
source: 'y0' // Return always this `source` property. We need to check that it gets deleted.
|
||||
});
|
||||
model = new SQLFunctionOptionModel(null, {
|
||||
nodeAttrs: {
|
||||
key: 'value'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFormAttrs', function () {
|
||||
it('should get form attributes, delete source and set primary_source with the layer definition attributes', function () {
|
||||
var fakeLayerDefModel = new Backbone.Model({
|
||||
source: 'z0'
|
||||
});
|
||||
|
||||
var formAttrs = model.getFormAttrs(fakeLayerDefModel);
|
||||
|
||||
expect(AnalysisOptionModel.prototype.getFormAttrs).toHaveBeenCalledWith(fakeLayerDefModel);
|
||||
expect(formAttrs).toEqual({ primary_source: 'z0' });
|
||||
});
|
||||
});
|
||||
});
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||||
var GeneratedAnalysisOptionModel = require('builder/components/modals/add-analysis/analysis-option-models/generated-analysis-option-model');
|
||||
|
||||
describe('builder/components/modals/add-analysis/analysis-option-models/generated-analysis-option-model', function () {
|
||||
beforeEach(function () {
|
||||
this.layerA = new LayerDefinitionModel({
|
||||
id: 'layerA',
|
||||
type: 'cartoDB',
|
||||
letter: 'a',
|
||||
source: 'a0'
|
||||
}, {
|
||||
configModel: {}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when created a type with a single source', function () {
|
||||
beforeEach(function () {
|
||||
this.model = new GeneratedAnalysisOptionModel({
|
||||
title: 'filter-category',
|
||||
desc: 'An example of a generated option model'
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'filter-category'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getFormAttrs', function () {
|
||||
it('should return attrs to create a form model for analysis', function () {
|
||||
expect(this.model.getFormAttrs(this.layerA)).toEqual({
|
||||
id: 'a1',
|
||||
source: 'a0',
|
||||
type: 'filter-category'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when created a type with multiple input sources', function () {
|
||||
beforeEach(function () {
|
||||
this.model = new GeneratedAnalysisOptionModel({
|
||||
title: 'aggregate-intersection',
|
||||
desc: 'An example of a generated option model with multiple sources'
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'aggregate-intersection'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getFormAttrs', function () {
|
||||
it('should return attrs but w/o any source set', function () {
|
||||
expect(this.model.getFormAttrs(this.layerA)).toEqual({
|
||||
id: 'a1',
|
||||
type: 'aggregate-intersection'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||||
var MergeAnalysisOptionModel = require('builder/components/modals/add-analysis/analysis-option-models/merge-analysis-option-model');
|
||||
|
||||
describe('builder/components/modals/add-analysis/analysis-option-models/merge-analysis-option-model', function () {
|
||||
beforeEach(function () {
|
||||
this.layerA = new LayerDefinitionModel({
|
||||
id: 'layerA',
|
||||
type: 'cartoDB',
|
||||
letter: 'a',
|
||||
source: 'a0'
|
||||
}, {
|
||||
configModel: {}
|
||||
});
|
||||
|
||||
this.model = new MergeAnalysisOptionModel({
|
||||
title: 'merge',
|
||||
desc: 'An example of a generated option model'
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'merge'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getFormAttrs', function () {
|
||||
it('should return attrs to create a form model for analysis', function () {
|
||||
expect(this.model.getFormAttrs(this.layerA)).toEqual({
|
||||
id: 'a1',
|
||||
type: 'merge',
|
||||
left_source: 'a0',
|
||||
primary_source_name: 'left_source'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
var AnalysisOptionModel = require('builder/components/modals/add-analysis/analysis-option-models/analysis-option-model');
|
||||
var AnalysisOptionView = require('builder/components/modals/add-analysis/analysis-option-view');
|
||||
describe('components/modals/add-analysis/analysis-option-view', function () {
|
||||
beforeEach(function () {
|
||||
this.model = new AnalysisOptionModel({
|
||||
title: 'Buffer',
|
||||
desc: 'describes the buffer type',
|
||||
type_group: 'area of influence',
|
||||
link: 'https://carto.com'
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'buffer'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a simple geometry type', function () {
|
||||
beforeEach(function () {
|
||||
this.view = new AnalysisOptionView({
|
||||
model: this.model,
|
||||
simpleGeometryTypeInput: 'point'
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render the info', function () {
|
||||
expect(this.view.$el.html()).toContain('Buffer');
|
||||
expect(this.view.$el.html()).toContain('describes the buffer');
|
||||
});
|
||||
|
||||
it('should not select the item if the link is clicked', function () {
|
||||
expect(this.view.$('.js-more').length).toBe(1);
|
||||
|
||||
this.view.$('.js-more').click();
|
||||
|
||||
expect(this.model.get('selected')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should render the animation', function () {
|
||||
expect(this.view.$('.js-animation').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should launch the animation on hover', function () {
|
||||
this.view._acceptsInputGeometry = function () { return true; };
|
||||
|
||||
this.view.$el.trigger('mouseenter');
|
||||
expect(this.view.$('.js-animation').hasClass('has-autoplay')).toBeTruthy();
|
||||
|
||||
this.view.$el.trigger('mouseleave');
|
||||
expect(this.view.$('.js-animation').hasClass('has-autoplay')).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('when selected', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('selected', true);
|
||||
});
|
||||
|
||||
it('should highlight the item', function () {
|
||||
expect(this.view.el.className).toContain('is-selected');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when geometry type does not match ', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.model, 'acceptsGeometryTypeAsInput').and.returnValue(false);
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should disable the view', function () {
|
||||
expect(this.view.el.className).toContain('is-disabled');
|
||||
});
|
||||
|
||||
it('should show alternative desc', function () {
|
||||
expect(this.view.$el.html()).toContain('disabled-option-desc');
|
||||
expect(this.view.$el.html()).not.toContain('describes the buffer');
|
||||
});
|
||||
|
||||
it('should not be able to select it', function () {
|
||||
this.view.$el.click();
|
||||
expect(this.view.el.className).not.toContain('selected');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when not given any geometry type', function () {
|
||||
beforeEach(function () {
|
||||
this.view = new AnalysisOptionView({
|
||||
model: this.model
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
});
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
var AnalysisOptionsCollection = require('builder/components/modals/add-analysis/analysis-options-collection');
|
||||
|
||||
describe('components/modals/add-analysis/analysis-options-collection', function () {
|
||||
beforeEach(function () {
|
||||
this.collection = new AnalysisOptionsCollection();
|
||||
});
|
||||
|
||||
describe('when reset with some options', function () {
|
||||
beforeEach(function () {
|
||||
this.collection.reset([
|
||||
{
|
||||
title: 'A Buffer',
|
||||
nodeAttrs: {
|
||||
type: 'buffer'
|
||||
}
|
||||
}, {
|
||||
title: 'A Trade-Area',
|
||||
nodeAttrs: {
|
||||
type: 'trade-area'
|
||||
}
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should create a model for given data', function () {
|
||||
expect(this.collection.length).toEqual(2);
|
||||
expect(this.collection.first().get('title')).toEqual(jasmine.any(String));
|
||||
expect(this.collection.first().getFormAttrs).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it('should only allow one selection at a time', function () {
|
||||
expect(this.collection.pluck('selected')).toEqual([false, false]);
|
||||
|
||||
this.collection.first().set('selected', true);
|
||||
expect(this.collection.pluck('selected')).toEqual([true, false]);
|
||||
|
||||
this.collection.last().set('selected', true);
|
||||
expect(this.collection.pluck('selected')).toEqual([false, true]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
var Backbone = require('backbone');
|
||||
var _ = require('underscore');
|
||||
var camshaftReferenceAnalyses = require('camshaft-reference').getVersion('latest').analyses;
|
||||
var analysisOptions = require('builder/components/modals/add-analysis/analysis-options');
|
||||
var DataServicesApiCheck = require('builder/editor/layers/layer-content-views/analyses/analyses-quota/analyses-quota-info');
|
||||
|
||||
describe('builder/components/modals/add-analysis/analysis-options', function () {
|
||||
var configModel = new Backbone.Model({
|
||||
user_name: 'foo',
|
||||
sql_api_template: 'foo',
|
||||
api_key: 'foo'
|
||||
});
|
||||
configModel.dataServiceEnabled = function () { return true; };
|
||||
|
||||
var userModel = new Backbone.Model();
|
||||
userModel.featureEnabled = function () { return true; };
|
||||
|
||||
var queryGeometryModel = new Backbone.Model();
|
||||
queryGeometryModel.isPolygon = function () { return true; };
|
||||
|
||||
DataServicesApiCheck.get(configModel)._state = 'fetched';
|
||||
|
||||
it('should not add generated option if feature flag is disabled', function () {
|
||||
userModel.featureEnabled = function () { return false; };
|
||||
configModel.dataServiceEnabled = function () { return false; };
|
||||
var defaultAnalysisOptions = analysisOptions({
|
||||
userModel: userModel,
|
||||
configModel: configModel,
|
||||
queryGeometryModel: queryGeometryModel
|
||||
});
|
||||
expect(defaultAnalysisOptions['generated']).toBeUndefined('should not have any generated options');
|
||||
});
|
||||
|
||||
describe('each category (including generated)', function () {
|
||||
var options = analysisOptions({
|
||||
userModel: userModel,
|
||||
configModel: configModel,
|
||||
queryGeometryModel: queryGeometryModel
|
||||
});
|
||||
|
||||
_.each(options, function (item, category) {
|
||||
it('should have a key', function () {
|
||||
expect(category).toEqual(jasmine.any(String));
|
||||
});
|
||||
|
||||
describe('category: ' + category, function () {
|
||||
describe('should have a definition', function () {
|
||||
var def = options[category];
|
||||
|
||||
beforeEach(function () {
|
||||
expect(def).toEqual(jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('should have a title', function () {
|
||||
expect(def.title).toEqual(jasmine.any(String));
|
||||
});
|
||||
|
||||
it('should have analyses', function () {
|
||||
expect(def.analyses).toEqual(jasmine.any(Array));
|
||||
expect(def.analyses.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
describe('each analysis', function () {
|
||||
def.analyses.forEach(function (d) {
|
||||
describe('analysis: ' + d.title, function () {
|
||||
it('should have a title', function () {
|
||||
expect(d.title).toEqual(jasmine.any(String));
|
||||
});
|
||||
|
||||
it('should have a description', function () {
|
||||
expect(d.desc).toEqual(jasmine.any(String));
|
||||
});
|
||||
|
||||
it('should have attrs to create a node from', function () {
|
||||
expect(d.nodeAttrs).toEqual(jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('should have at least a type', function () {
|
||||
expect(d.nodeAttrs.type).toEqual(jasmine.any(String));
|
||||
|
||||
if (d.dummy !== true) {
|
||||
expect(camshaftReferenceAnalyses[d.nodeAttrs.type]).toBeDefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
var Backbone = require('backbone');
|
||||
var AnalysisViewPane = require('builder/components/modals/add-analysis/analysis-view-pane');
|
||||
var AnalysisOptionModel = require('builder/components/modals/add-analysis/analysis-option-models/analysis-option-model');
|
||||
var Router = require('builder/routes/router');
|
||||
|
||||
describe('components/modals/add-analysis/analysis-view-pane', function () {
|
||||
var view, analysisOptionsCollection;
|
||||
|
||||
var createViewFn = function (options) {
|
||||
analysisOptionsCollection = new Backbone.Collection([
|
||||
new AnalysisOptionModel({
|
||||
category: 'create_clean',
|
||||
desc: 'Use street addresses, city names, or other location text to generate point geometries.',
|
||||
selected: false,
|
||||
title: 'Georeference',
|
||||
type: 'georeference-long-lat',
|
||||
type_group: ''
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'georeference-long-lat'
|
||||
}
|
||||
}), new AnalysisOptionModel({
|
||||
category: 'analyze_predict',
|
||||
desc: 'Moran description',
|
||||
selected: false,
|
||||
title: 'Moran',
|
||||
type: 'moran',
|
||||
type_group: ''
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'moran'
|
||||
}
|
||||
}), new AnalysisOptionModel({
|
||||
category: 'data_transformation',
|
||||
desc: 'Centroid description',
|
||||
selected: false,
|
||||
title: 'Centroid',
|
||||
type: 'centroid',
|
||||
type_group: ''
|
||||
}, {
|
||||
nodeAttrs: {
|
||||
type: 'centroid'
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
var view = new AnalysisViewPane({
|
||||
stackLayoutModel: new Backbone.Model(),
|
||||
modalModel: new Backbone.Model(),
|
||||
queryGeometryModel: new Backbone.Model(),
|
||||
analysisOptions: {
|
||||
create_clean: {
|
||||
title: 'Create and clean',
|
||||
analyses: [{
|
||||
desc: 'Use street addresses, city names, or other location text to generate point geometries.',
|
||||
nodeAttrs: {
|
||||
type: 'georeference-long-lat'
|
||||
},
|
||||
title: 'Georeference'
|
||||
}]
|
||||
},
|
||||
analyze_predict: {
|
||||
title: 'Analyze and predict',
|
||||
analyses: [{
|
||||
desc: 'Moran desc',
|
||||
nodeAttrs: {
|
||||
type: 'moran'
|
||||
},
|
||||
title: 'Moran'
|
||||
}]
|
||||
},
|
||||
data_transformation: {
|
||||
title: 'Data Transformation',
|
||||
analyses: [{
|
||||
desc: 'Centroid desc',
|
||||
nodeAttrs: {
|
||||
type: 'centroid'
|
||||
},
|
||||
title: 'Centroid'
|
||||
}]
|
||||
}
|
||||
},
|
||||
analysisOptionsCollection: analysisOptionsCollection,
|
||||
layerDefinitionModel: new Backbone.Model({
|
||||
id: 'some-layer-id',
|
||||
letter: 'a',
|
||||
source: 'a0'
|
||||
}),
|
||||
collection: new Backbone.Collection([
|
||||
{ selected: true,
|
||||
id: 'a3',
|
||||
title: 'Intersection',
|
||||
category: 'analyze-predict',
|
||||
type: 'intersection',
|
||||
genericType: 'intersection',
|
||||
analysisParams: {}
|
||||
}
|
||||
])
|
||||
});
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(Router, 'navigate');
|
||||
|
||||
view = createViewFn();
|
||||
view.render();
|
||||
});
|
||||
|
||||
describe('.render', function () {
|
||||
it('should render properly', function () {
|
||||
expect(view.$el.html()).toContain('analysis-category.create-clean');
|
||||
expect(view.$el.html()).toContain('analysis-category.analyze-predict');
|
||||
expect(view.$el.html()).toContain('analysis-category.data-transformation');
|
||||
expect(view.$('.js-add').hasClass('is-disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
|
||||
it('should go to tab item', function () {
|
||||
analysisOptionsCollection.at(0).set('selected', true);
|
||||
view.goToTabItem('create_clean');
|
||||
|
||||
expect(view.$('.js-add').hasClass('is-disabled')).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('._onAddAnalysis', function () {
|
||||
it('should call goToAnalysisNode', function () {
|
||||
spyOn(Router, 'goToAnalysisNode');
|
||||
|
||||
analysisOptionsCollection.at(0).set('selected', true);
|
||||
view._onAddAnalysis();
|
||||
|
||||
expect(Router.goToAnalysisNode).toHaveBeenCalledWith('some-layer-id', 'a1');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,217 @@
|
||||
var AddBasemapModel = require('builder/components/modals/add-basemap/add-basemap-model');
|
||||
var BasemapsCollection = require('builder/editor/layers/basemap-content-views/basemaps-collection');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||||
var AnalysisDefinitionNodesCollection = require('builder/data/analysis-definition-nodes-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
|
||||
describe('components/modals/add-basemap/add-basemap-model', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
var userModel = new UserModel({}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel
|
||||
});
|
||||
|
||||
this.layerDefinitionsCollection = new LayerDefinitionsCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel,
|
||||
analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
|
||||
mapId: 'm-123',
|
||||
stateDefinitionModel: {}
|
||||
});
|
||||
this.layerDefinitionsCollection.add({
|
||||
id: 'l-1',
|
||||
kind: 'carto',
|
||||
options: {
|
||||
table_name: 'foo',
|
||||
className: 'positron_rainbow',
|
||||
category: 'CARTO'
|
||||
}
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
category: 'Custom',
|
||||
className: 'httpsaexamplecomzxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new AddBasemapModel({}, {
|
||||
layerDefinitionsCollection: this.layerDefinitionsCollection,
|
||||
basemapsCollection: new BasemapsCollection([{
|
||||
id: 'basemap-id-1',
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
val: 'httpsaexamplecomzxypng'
|
||||
}]),
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
});
|
||||
|
||||
it('should start with tabs for current view', function () {
|
||||
expect(this.model.get('contentPane')).toEqual('tabs');
|
||||
});
|
||||
|
||||
it('should start on XYZ tab', function () {
|
||||
expect(this.model.get('currentTab')).toEqual('xyz');
|
||||
});
|
||||
|
||||
describe('.activeTabModel', function () {
|
||||
it('should return the model for current tab', function () {
|
||||
expect(this.model.activeTabModel()).toEqual(jasmine.any(Object));
|
||||
});
|
||||
});
|
||||
|
||||
describe('.canSaveBasemap', function () {
|
||||
it('should return true if there is a layer set on current tab model and is not processing something', function () {
|
||||
expect(this.model.canSaveBasemap()).toBeFalsy();
|
||||
|
||||
this.model.activeTabModel().set('layer', {});
|
||||
expect(this.model.canSaveBasemap()).toBeTruthy();
|
||||
|
||||
this.model.set('contentPane', 'not tabs');
|
||||
expect(this.model.canSaveBasemap()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.saveBasemap', function () {
|
||||
beforeEach(function () {
|
||||
var url = 'https://b.example.com/{z}/{x}/{y}.png';
|
||||
|
||||
this.layer = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: url,
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
name: '',
|
||||
tms: false,
|
||||
category: 'Custom',
|
||||
type: 'Tiled'
|
||||
});
|
||||
this.layer.set('className', this.layer._generateClassName(url));
|
||||
spyOn(this.layer, 'save');
|
||||
this.model.activeTabModel().set('layer', this.layer);
|
||||
});
|
||||
|
||||
describe('when layer has already been added', function () {
|
||||
beforeEach(function () {
|
||||
this.model._basemapsCollection.add({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'https://b.example.com/{z}/{x}/{y}.png',
|
||||
val: 'httpsbexamplecomzxypng'
|
||||
});
|
||||
this.customBaselayersCollection.add(this.layer);
|
||||
spyOn(this.model.activeTabModel(), 'hasAlreadyAddedLayer').and.returnValue(true);
|
||||
spyOn(this.model._layerDefinitionsCollection, 'setBaseLayer');
|
||||
spyOn(this.model._basemapsCollection, 'updateSelected');
|
||||
this.model.saveBasemap();
|
||||
});
|
||||
|
||||
it('should call hasAlreadyAddedLayer with baseLayers', function () {
|
||||
expect(this.model.activeTabModel().hasAlreadyAddedLayer).toHaveBeenCalledWith(this.customBaselayersCollection);
|
||||
});
|
||||
|
||||
it('should change baseLayer', function () {
|
||||
expect(this.model._layerDefinitionsCollection.setBaseLayer).toHaveBeenCalledWith({
|
||||
id: 'basemap-id-2',
|
||||
className: 'httpsbexamplecomzxypng',
|
||||
urlTemplate: 'https://b.example.com/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
name: '',
|
||||
tms: false,
|
||||
category: 'Custom',
|
||||
type: 'Tiled'
|
||||
});
|
||||
});
|
||||
|
||||
it('should update selected in basemapsCollection', function () {
|
||||
expect(this.model._basemapsCollection.updateSelected).toHaveBeenCalledWith('httpsbexamplecomzxypng');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when layer is new', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.model._layerDefinitionsCollection, 'setBaseLayer');
|
||||
spyOn(this.model._basemapsCollection, 'updateSelected');
|
||||
this.model.saveBasemap();
|
||||
});
|
||||
|
||||
it('should add layer to baselayers', function () {
|
||||
expect(this.customBaselayersCollection.contains(this.layer)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should call save on layer', function () {
|
||||
expect(this.layer.save).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when save succeeds', function () {
|
||||
beforeEach(function () {
|
||||
this.layer.save.calls.argsFor(0)[1].success({}, {
|
||||
options: {
|
||||
urlTemplate: 'https://b.example.com/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
name: '',
|
||||
tms: false,
|
||||
category: 'Custom',
|
||||
type: 'Tiled',
|
||||
className: 'httpsbexamplecomzxypng'
|
||||
},
|
||||
kind: 'tiled',
|
||||
infowindow: null,
|
||||
tooltip: null,
|
||||
id: 'basemap-id-2',
|
||||
order: 2
|
||||
});
|
||||
});
|
||||
|
||||
it('should change baseLayer', function () {
|
||||
expect(this.model._layerDefinitionsCollection.setBaseLayer).toHaveBeenCalledWith({
|
||||
id: 'basemap-id-2',
|
||||
className: 'httpsbexamplecomzxypng',
|
||||
urlTemplate: 'https://b.example.com/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
name: '',
|
||||
tms: false,
|
||||
category: 'Custom',
|
||||
type: 'Tiled'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when save fails', function () {
|
||||
beforeEach(function () {
|
||||
this.layer.save.calls.argsFor(0)[1].error();
|
||||
});
|
||||
|
||||
it('should remove layer from baselayers', function () {
|
||||
expect(this.customBaselayersCollection.contains(this.layer)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should set current view to addBasemapFailed', function () {
|
||||
expect(this.model.get('contentPane')).toEqual('addBasemapFailed');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,140 @@
|
||||
var AddBasemapView = require('builder/components/modals/add-basemap/add-basemap-view');
|
||||
var AddBasemapModel = require('builder/components/modals/add-basemap/add-basemap-model');
|
||||
var BasemapsCollection = require('builder/editor/layers/basemap-content-views/basemaps-collection');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||||
var AnalysisDefinitionNodesCollection = require('builder/data/analysis-definition-nodes-collection');
|
||||
var ModalViewModel = require('builder/components/modals/modal-view-model');
|
||||
|
||||
describe('components/modals/add-basemap/add-basemap-view', function () {
|
||||
beforeEach(function () {
|
||||
this.createContentViewResult = {};
|
||||
this.createContentView = jasmine.createSpy('createContentView').and.returnValue(this.createContentViewResult);
|
||||
spyOn(ModalViewModel.prototype, 'destroy').and.callThrough();
|
||||
this.modalModel = new ModalViewModel({
|
||||
createContentView: this.createContentView
|
||||
});
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
var userModel = new UserModel({}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel
|
||||
});
|
||||
|
||||
this.layerDefinitionsCollection = new LayerDefinitionsCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel,
|
||||
analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
|
||||
mapId: 'm-123',
|
||||
stateDefinitionModel: {}
|
||||
});
|
||||
this.layerDefinitionsCollection.add({
|
||||
id: 'l-1',
|
||||
kind: 'carto',
|
||||
options: {
|
||||
table_name: 'foo',
|
||||
className: 'positron_rainbow',
|
||||
category: 'CARTO'
|
||||
}
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: '',
|
||||
category: 'Custom'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new AddBasemapModel({}, {
|
||||
layerDefinitionsCollection: this.layerDefinitionsCollection,
|
||||
basemapsCollection: new BasemapsCollection(),
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
|
||||
this.view = new AddBasemapView({
|
||||
modalModel: this.modalModel,
|
||||
layerDefinitionsCollection: this.layerDefinitionsCollection,
|
||||
createModel: this.model
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render the tabs', function () {
|
||||
expect(this.innerHTML()).toContain('XYZ');
|
||||
});
|
||||
|
||||
it('should start on XYZ view', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.xyz.insert');
|
||||
});
|
||||
|
||||
it('should highlight the selected tab', function () {
|
||||
expect(this.view.$('.Modal-navigation .is-selected button').data('name')).toBe('xyz');
|
||||
expect(this.view.$('.Modal-navigation .is-selected button').data('name')).not.toBe('mapbox');
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
describe('when clicking on a tab', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('button[data-name="mapbox"]').click();
|
||||
});
|
||||
|
||||
it('should change tab', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.mapbox.insert');
|
||||
});
|
||||
|
||||
it('should highlight new tab', function () {
|
||||
expect(this.view.$('.Modal-navigation .is-selected button').data('name')).toBe('mapbox');
|
||||
expect(this.view.$('.Modal-navigation .is-selected button').data('name')).not.toBe('xyz');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when click OK', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.view._createModel, 'canSaveBasemap').and.returnValue(true);
|
||||
spyOn(this.view._createModel, 'saveBasemap');
|
||||
this.view.$('.js-ok').click();
|
||||
});
|
||||
|
||||
it('should save new basemap', function () {
|
||||
expect(this.view._createModel.saveBasemap).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when save succeeds', function () {
|
||||
it('should close view', function () {
|
||||
this.view._createModel.trigger('saveBasemapDone');
|
||||
expect(ModalViewModel.prototype.destroy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when save fails', function () {
|
||||
beforeEach(function () {
|
||||
this.view._createModel.set('contentPane', 'addBasemapFailed');
|
||||
});
|
||||
|
||||
it('should show an error explanation', function () {
|
||||
expect(this.innerHTML()).toContain('error');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var MapboxModel = require('builder/components/modals/add-basemap/mapbox/mapbox-model.js');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
|
||||
describe('editor/components/modals/add-basemap/mapbox/mapbox-model', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.tiles.mapbox.com/v4/map.id/{z}/{x}/{y}.png?access_token=',
|
||||
category: 'Mapbox',
|
||||
className: 'httpsatilesmapboxcomv4mapidzxypngaccess_token'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new MapboxModel();
|
||||
});
|
||||
|
||||
describe('.hasAlreadyAddedLayer', function () {
|
||||
it('should return true if layer has already been added', function () {
|
||||
this.model.set('layer', new CustomBaselayerModel({}));
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBeFalsy();
|
||||
|
||||
this.model.set('layer', this.customBaselayersCollection.at(0));
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
var $ = require('jquery');
|
||||
var MapboxToTileLayerFactory = require('builder/components/modals/add-basemap/mapbox/mapbox-to-tile-layer-factory');
|
||||
|
||||
describe('editor/components/modals/add-basemap/mapbox/mapbox-to-tile-layer-factory', function () {
|
||||
beforeEach(function () {
|
||||
this.factory = new MapboxToTileLayerFactory({
|
||||
url: 'https://a.tiles.mapbox.com/v4/username.123abc45d/'
|
||||
});
|
||||
});
|
||||
|
||||
describe('._fixHTTPS', function () {
|
||||
it('should fix mapbox https url', function () {
|
||||
var url = MapboxToTileLayerFactory.prototype._fixHTTPS('http://a.tiles.mapbox.com/v4/examples.map-4l7djmvo.json', {
|
||||
protocol: 'https:'
|
||||
});
|
||||
expect(url).toEqual('https://dnv9my2eseobd.cloudfront.net/v4/examples.map-4l7djmvo.json');
|
||||
|
||||
url = MapboxToTileLayerFactory.prototype._fixHTTPS('http://a.tiles.mapbox.com/v4/examples.map-4l7djmvo.json', {
|
||||
protocol: 'http:'
|
||||
});
|
||||
expect(url).toEqual('http://a.tiles.mapbox.com/v4/examples.map-4l7djmvo.json');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.createTileLayer', function () {
|
||||
beforeEach(function () {
|
||||
this.successSpy = jasmine.createSpy('success');
|
||||
this.errorSpy = jasmine.createSpy('error');
|
||||
this.callbacks = {
|
||||
success: this.successSpy,
|
||||
error: this.errorSpy
|
||||
};
|
||||
|
||||
// for sure jasmine has a function for this
|
||||
spyOn($, 'ajax');
|
||||
});
|
||||
|
||||
describe('when provided an edit URL', function () {
|
||||
beforeEach(function () {
|
||||
this.username = 'cartodb';
|
||||
this.mapID = 'map-eeoepub0';
|
||||
this.mapboxID = this.username + '.' + this.mapID;
|
||||
|
||||
this.factory.set({
|
||||
url: 'https://tiles.mapbox.com/' + this.username + '/edit/' + this.mapID + '#3/0.09/0.00'
|
||||
});
|
||||
this.factory.createTileLayer(this.callbacks);
|
||||
});
|
||||
|
||||
describe('when valid URL', function () {
|
||||
beforeEach(function () {
|
||||
$.ajax.calls.argsFor(0)[0].success({
|
||||
attribution: 'attribution str',
|
||||
minzoom: 2,
|
||||
maxzoom: 4
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the success callback', function () {
|
||||
expect(this.successSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should have an expected urlTemplate value on the returned layer', function () {
|
||||
expect(this.successSpy).toHaveBeenCalledWith(jasmine.any(Object));
|
||||
var url = 'https://a.tiles.mapbox.com/v4/' + this.mapboxID + '/{z}/{x}/{y}.png';
|
||||
expect(this.successSpy.calls.argsFor(0)[0].get('urlTemplate')).toEqual(url);
|
||||
});
|
||||
|
||||
it('should also set expected metadata', function () {
|
||||
var tileLayer = this.successSpy.calls.argsFor(0)[0];
|
||||
expect(tileLayer.get('attribution')).toEqual('attribution str');
|
||||
expect(tileLayer.get('minZoom')).toEqual(2);
|
||||
expect(tileLayer.get('maxZoom')).toEqual(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fails to validate URL', function () {
|
||||
beforeEach(function () {
|
||||
$.ajax.calls.argsFor(0)[0].error();
|
||||
});
|
||||
|
||||
it('should call error callback with error message', function () {
|
||||
expect(this.errorSpy).toHaveBeenCalled();
|
||||
expect(this.errorSpy).toHaveBeenCalledWith(jasmine.any(String));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an embed URL', function () {
|
||||
beforeEach(function () {
|
||||
this.mapboxID = 'cartodb.map-eeoepub0';
|
||||
|
||||
this.factory.set({
|
||||
url: 'http://a.tiles.mapbox.com/v4/' + this.mapboxID + '/page.html'
|
||||
});
|
||||
this.factory.createTileLayer(this.callbacks);
|
||||
});
|
||||
|
||||
describe('when valid URL', function () {
|
||||
beforeEach(function () {
|
||||
$.ajax.calls.argsFor(0)[0].success({
|
||||
attribution: 'attribution str',
|
||||
minzoom: 2,
|
||||
maxzoom: 4
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the success callback', function () {
|
||||
expect(this.successSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should have an expected urlTemplate value on the returned layer', function () {
|
||||
expect(this.successSpy).toHaveBeenCalledWith(jasmine.any(Object));
|
||||
var url = 'https://a.tiles.mapbox.com/v4/' + this.mapboxID + '/{z}/{x}/{y}.png';
|
||||
expect(this.successSpy.calls.argsFor(0)[0].get('urlTemplate')).toEqual(url);
|
||||
});
|
||||
|
||||
it('should also set expected metadata', function () {
|
||||
var tileLayer = this.successSpy.calls.argsFor(0)[0];
|
||||
expect(tileLayer.get('attribution')).toEqual('attribution str');
|
||||
expect(tileLayer.get('minZoom')).toEqual(2);
|
||||
expect(tileLayer.get('maxZoom')).toEqual(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fails to validate URL', function () {
|
||||
beforeEach(function () {
|
||||
$.ajax.calls.argsFor(0)[0].error();
|
||||
});
|
||||
|
||||
it('should call error callback with error message', function () {
|
||||
expect(this.errorSpy).toHaveBeenCalled();
|
||||
expect(this.errorSpy).toHaveBeenCalledWith(jasmine.any(String));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided a XYZ URL', function () {
|
||||
beforeEach(function () {
|
||||
this.mapboxID = 'cartodb.map-eeoepub0';
|
||||
|
||||
var self = this;
|
||||
this.img = {};
|
||||
spyOn(window, 'Image').and.callFake(function () {
|
||||
return self.img;
|
||||
});
|
||||
|
||||
this.factory.set({
|
||||
url: 'https://a.tiles.mapbox.com/v4/' + this.mapboxID + '/{z}/{y}/{x}.png'
|
||||
});
|
||||
this.factory.createTileLayer(this.callbacks);
|
||||
});
|
||||
|
||||
describe('when valid URL and tiles', function () {
|
||||
beforeEach(function () {
|
||||
this.img.onload();
|
||||
});
|
||||
|
||||
it('should call the success callback', function () {
|
||||
expect(this.successSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should have an expected urlTemplate value on the returned layer', function () {
|
||||
expect(this.successSpy).toHaveBeenCalledWith(jasmine.any(Object));
|
||||
var url = 'https://a.tiles.mapbox.com/v4/' + this.mapboxID + '/{z}/{y}/{x}.png';
|
||||
expect(this.successSpy.calls.argsFor(0)[0].get('urlTemplate')).toEqual(url);
|
||||
});
|
||||
|
||||
it('should also set expected metadata', function () {
|
||||
var tileLayer = this.successSpy.calls.argsFor(0)[0];
|
||||
expect(tileLayer.get('attribution')).toBeNull();
|
||||
expect(tileLayer.get('minZoom')).toEqual(0);
|
||||
expect(tileLayer.get('maxZoom')).toEqual(21);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when fails to validate URL', function () {
|
||||
beforeEach(function () {
|
||||
this.img.onerror();
|
||||
});
|
||||
|
||||
it('should call error callback with error message', function () {
|
||||
expect(this.errorSpy).toHaveBeenCalled();
|
||||
expect(this.errorSpy).toHaveBeenCalledWith(jasmine.any(String));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
var $ = require('jquery');
|
||||
var MapboxView = require('builder/components/modals/add-basemap/mapbox/mapbox-view');
|
||||
var MapboxModel = require('builder/components/modals/add-basemap/mapbox/mapbox-model');
|
||||
var MapboxToTileLayerFactory = require('builder/components/modals/add-basemap/mapbox/mapbox-to-tile-layer-factory');
|
||||
|
||||
describe('editor/components/modals/add-basemap/mapbox/mapbox-view', function () {
|
||||
beforeEach(function () {
|
||||
this.model = new MapboxModel();
|
||||
|
||||
var submitButton = $('<button class="is-disabled">Submit</button>');
|
||||
var modalFooter = $('<div></div>');
|
||||
|
||||
this.view = new MapboxView({
|
||||
model: this.model,
|
||||
submitButton: submitButton,
|
||||
modalFooter: modalFooter
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render the inputs', function () {
|
||||
expect(this.view.$('input').length).toEqual(1);
|
||||
});
|
||||
|
||||
describe('when click save', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(MapboxToTileLayerFactory.prototype, 'createTileLayer');
|
||||
spyOn(this.model, 'validateInputs').and.callThrough();
|
||||
this.view.$('.js-url').val('mapbox/URL');
|
||||
this.view._submitButton.click();
|
||||
});
|
||||
|
||||
it('should call validateInputs on model with current values', function () {
|
||||
expect(this.model.validateInputs).toHaveBeenCalled();
|
||||
expect(this.model.validateInputs).toHaveBeenCalledWith('mapbox/URL');
|
||||
});
|
||||
|
||||
it('should show the loading message', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.validating');
|
||||
expect(this.view.$('input').length).toEqual(0);
|
||||
});
|
||||
|
||||
describe('when layer is created', function () {
|
||||
beforeEach(function () {
|
||||
this.saveBasemapSpy = jasmine.createSpy('saveBasemap');
|
||||
this.model.bind('saveBasemap', this.saveBasemapSpy);
|
||||
this.tileLayer = jasmine.createSpy('CustomBaselayerModel');
|
||||
MapboxToTileLayerFactory.prototype.createTileLayer.calls.argsFor(0)[0].success(this.tileLayer);
|
||||
});
|
||||
|
||||
it('should set the layer on the model', function () {
|
||||
expect(this.model.get('layer')).toBe(this.tileLayer);
|
||||
});
|
||||
|
||||
it('should trigger saveBasemap event', function () {
|
||||
expect(this.saveBasemapSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when layer fails to be created', function () {
|
||||
beforeEach(function () {
|
||||
MapboxToTileLayerFactory.prototype.createTileLayer.calls.argsFor(0)[0].error('something failed');
|
||||
});
|
||||
|
||||
it('should show the start view again', function () {
|
||||
expect(this.view.$('input').length).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var NASAModel = require('builder/components/modals/add-basemap/nasa/nasa-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
|
||||
describe('components/modals/add-basemap/nasa/nasa-model', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'http://map1.vis.earthdata.nasa.gov/wmts-webmerc/MODIS_Terra_CorrectedReflectance_TrueColor/default/2016-09-20/GoogleMapsCompatible_Level9/{z}/{y}/{x}.jpeg',
|
||||
category: 'NASA',
|
||||
className: 'httpmap1visearthdatanasagovwmtswebmercmodis_terra_correctedreflectance_truecolordefault20160920googlemapscompatible_level9zyxjpeg'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new NASAModel(null, {
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
});
|
||||
|
||||
describe('when model changes', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set({
|
||||
date: '2015-05-25',
|
||||
layerType: 'day'
|
||||
});
|
||||
});
|
||||
|
||||
it('should set layer', function () {
|
||||
expect(this.model.get('layer')).toEqual(jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('should set layer with expected params', function () {
|
||||
var layer = this.model.get('layer');
|
||||
expect(layer.get('urlTemplate')).toMatch('/2015-05-25/.*\{x\}');
|
||||
expect(layer.get('attribution')).toEqual(jasmine.any(String));
|
||||
expect(layer.get('maxZoom')).toEqual(jasmine.any(Number));
|
||||
expect(layer.get('minZoom')).toEqual(jasmine.any(Number));
|
||||
expect(layer.get('name')).toMatch('.* 2015-05-25');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.hasAlreadyAddedLayer', function () {
|
||||
beforeEach(function () {
|
||||
this.customBaselayerModel = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'http://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_CityLights_2012/default/2015-05-25/GoogleMapsCompatible_Level8/{z}/{y}/{x}.jpeg',
|
||||
className: 'httpmap1visearthdatanasagovwmtswebmercviirscitylights2012default20150525googlemapscompatiblelevel8zyxjpeg',
|
||||
category: 'NASA'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return true if layer has already been added', function () {
|
||||
this.model.set('layer', this.customBaselayerModel);
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBe(false);
|
||||
|
||||
this.model.set('layer', this.customBaselayersCollection.at(0));
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
var $ = require('jquery');
|
||||
var NASAView = require('builder/components/modals/add-basemap/nasa/nasa-view');
|
||||
var NASAModel = require('builder/components/modals/add-basemap/nasa/nasa-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
|
||||
describe('components/modals/add-basemap/nasa/nasa-view', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'http://map1.vis.earthdata.nasa.gov/wmts-webmerc/MODIS_Terra_CorrectedReflectance_TrueColor/default/2016-09-20/GoogleMapsCompatible_Level9/{z}/{y}/{x}.jpeg',
|
||||
category: 'NASA',
|
||||
className: 'httpmap1visearthdatanasagovwmtswebmercmodis_terra_correctedreflectance_truecolordefault20160920googlemapscompatible_level9zyxjpeg'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new NASAModel(null, {
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
|
||||
var submitButton = $('<button class="is-disabled">Submit</button>');
|
||||
|
||||
this.view = new NASAView({
|
||||
model: this.model,
|
||||
submitButton: submitButton
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render day option as pre-selected', function () {
|
||||
expect(this.view.$('.js-day .RadioButton-input').hasClass('is-checked')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show date picker', function () {
|
||||
expect(this.view.$('.DatePicker').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render date of yesterday as start date', function () {
|
||||
expect(this.innerHTML()).toMatch(/\d{4}-\d{2}-\d{2}/);
|
||||
});
|
||||
|
||||
describe('when changing from day to night', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('.js-night').click();
|
||||
});
|
||||
|
||||
it('should disable date picker', function () {
|
||||
expect(this.view.$('.DatePicker .DatePicker-dates').hasClass('is-disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when changing back to day', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('.js-day').click();
|
||||
});
|
||||
|
||||
it('should enable date picker again', function () {
|
||||
expect(this.view.$('.DatePicker .DatePicker-dates').hasClass('is-disabled')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var TabsView = require('builder/components/modals/add-basemap/tabs-view');
|
||||
|
||||
describe('basemap-tabs-view', function () {
|
||||
beforeEach(function () {
|
||||
this.view = new TabsView({
|
||||
model: new Backbone.Model({
|
||||
tabs: new Backbone.Collection([])
|
||||
}),
|
||||
submitButton: {},
|
||||
modalFooter: {}
|
||||
});
|
||||
this.view.model.activeTabModel = function () {
|
||||
return {
|
||||
createView: function () {
|
||||
return new CoreView();
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
describe('.render', function () {
|
||||
it('should have the proper class name', function () {
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$el.hasClass('Modal-outer')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
var TileJSONLayerModel = require('builder/components/modals/add-basemap/tilejson/tilejson-layer-model');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
|
||||
describe('components/modals/add-basemap/tilejson/tilejson-layer-model', function () {
|
||||
beforeEach(function () {
|
||||
this.model = new TileJSONLayerModel();
|
||||
this.model.setUrl('/tile.json');
|
||||
|
||||
this.attrsExFromToTileJSONSpec = {
|
||||
tilejson: '2.1.0',
|
||||
name: 'compositing',
|
||||
description: 'A simple, light grey world.',
|
||||
version: '1.0.0',
|
||||
attribution: '<a href="http://openstreetmap.org">OSM contributors</a>',
|
||||
template: '{{#__teaser__}}{{NAME}}{{/__teaser__}}',
|
||||
legend: 'Dangerous zones are red, safe zones are green',
|
||||
scheme: 'xyz',
|
||||
tiles: [
|
||||
'http://localhost:8888/admin/1.0.0/world-light,broadband/{z}/{x}/{y}.png'
|
||||
],
|
||||
grids: [
|
||||
'http://localhost:8888/admin/1.0.0/broadband/{z}/{x}/{y}.grid.json'
|
||||
],
|
||||
data: [
|
||||
'http://localhost:8888/admin/data.geojson'
|
||||
],
|
||||
minzoom: 0,
|
||||
maxzoom: 11,
|
||||
bounds: [ -180, -85.05112877980659, 180, 85.0511287798066 ],
|
||||
center: [ -76.275329586789, 39.153492567373, 8 ]
|
||||
};
|
||||
});
|
||||
|
||||
it('should have a custom URL to get JSON result', function () {
|
||||
expect(this.model.url()).toEqual('/tile.json');
|
||||
});
|
||||
|
||||
describe('.newTileLayer', function () {
|
||||
describe('when have fetched model successfully', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set(this.attrsExFromToTileJSONSpec);
|
||||
});
|
||||
|
||||
it('should return a new tile layer', function () {
|
||||
expect(this.model.newTileLayer() instanceof CustomBaselayerModel).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return model with expected attrs', function () {
|
||||
var tileLayer = this.model.newTileLayer();
|
||||
expect(tileLayer.get('urlTemplate')).toEqual('http://localhost:8888/admin/1.0.0/world-light,broadband/{z}/{x}/{y}.png');
|
||||
expect(tileLayer.get('maxZoom')).toEqual(11);
|
||||
expect(tileLayer.get('minZoom')).toEqual(0);
|
||||
expect(tileLayer.get('bounding_boxes')).toEqual([ -180, -85.05112877980659, 180, 85.0511287798066 ]);
|
||||
expect(tileLayer.get('attribution')).toEqual('<a href="http://openstreetmap.org">OSM contributors</a>');
|
||||
expect(tileLayer.get('name')).toEqual('compositing');
|
||||
});
|
||||
|
||||
it('should set the TMS option based on the value of scheme', function () {
|
||||
expect(this.model.newTileLayer().get('tms')).toEqual(false);
|
||||
|
||||
this.model.set('scheme', 'tms');
|
||||
expect(this.model.newTileLayer().get('tms')).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var TileJSONModel = require('builder/components/modals/add-basemap/tilejson/tilejson-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
|
||||
describe('components/modals/add-basemap/tilejson/tilejson-model', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.tiles.mapbox.com/v3/mapbox.geography-class/{z}/{x}/{y}.png',
|
||||
category: 'TileJSON',
|
||||
className: 'httpsatilesmapboxcomv3mapboxgeographyclasszxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new TileJSONModel();
|
||||
});
|
||||
|
||||
describe('.hasAlreadyAddedLayer', function () {
|
||||
beforeEach(function () {
|
||||
this.customBaselayerModel = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'https://b.tiles.mapbox.com/v3/mapbox.geography-class/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
className: 'httpsbtilesmapboxcomv3mapboxgeographyclasszxypng',
|
||||
name: 'Geography Class',
|
||||
tms: false,
|
||||
category: 'TileJSON',
|
||||
type: 'Tiled'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return true if layer has already been added', function () {
|
||||
this.model.set('layer', this.customBaselayerModel);
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBe(false);
|
||||
|
||||
this.model.set('layer', this.customBaselayersCollection.at(0));
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
var _ = require('underscore');
|
||||
var $ = require('jquery');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var TileJSONModel = require('builder/components/modals/add-basemap/tilejson/tilejson-model');
|
||||
var TileJSONView = require('builder/components/modals/add-basemap/tilejson/tilejson-view');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
var TileJSONLayerModel = require('builder/components/modals/add-basemap/tilejson/tilejson-layer-model');
|
||||
|
||||
describe('components/modals/add-basemap/tilejson/tilejson-view', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(_, 'debounce').and.callFake(function (func) {
|
||||
return function () {
|
||||
func.apply(this, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.tiles.mapbox.com/v3/mapbox.geography-class/{z}/{x}/{y}.png',
|
||||
category: 'TileJSON',
|
||||
className: 'httpsatilesmapboxcomv3mapboxgeographyclasszxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new TileJSONModel(null, {
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
|
||||
var submitButton = $('<button class="is-disabled">Submit</button>');
|
||||
var tileJSONLayerModel = new TileJSONLayerModel();
|
||||
|
||||
this.view = new TileJSONView({
|
||||
model: this.model,
|
||||
customBaselayersCollection: this.customBaselayersCollection,
|
||||
submitButton: submitButton,
|
||||
tileJSONLayerModel: tileJSONLayerModel
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render the set button as disabled initially', function () {
|
||||
expect(this.view._submitButton.hasClass('is-disabled')).toBe(true);
|
||||
});
|
||||
|
||||
describe('when user written a URL', function () {
|
||||
describe('when URL is half-done or invalid', function () {
|
||||
beforeEach(function () {
|
||||
spyOn($, 'ajax');
|
||||
|
||||
this.view.$('.js-url')
|
||||
.val('ht')
|
||||
.trigger('keydown');
|
||||
});
|
||||
|
||||
it('should indicate that it is validating URL', function () {
|
||||
expect(this.innerHTML()).toMatch('js-validating.*display: inline');
|
||||
});
|
||||
|
||||
describe('when triggers error', function () {
|
||||
beforeEach(function () {
|
||||
$.ajax.calls.argsFor(0)[0].error();
|
||||
});
|
||||
|
||||
it('should show error', function () {
|
||||
expect(this.view.$('.js-error').attr('class')).toContain('is-visible');
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.tilejson.invalid');
|
||||
});
|
||||
|
||||
it('should not indicate validating anymore', function () {
|
||||
expect(this.innerHTML()).not.toMatch('js-validating.*display: inline');
|
||||
});
|
||||
|
||||
it('should disable OK button', function () {
|
||||
expect(this.view._submitButton.hasClass('is-disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when finally written/pasted a valid URL', function () {
|
||||
beforeEach(function () {
|
||||
this.layer = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'https://b.tiles.mapbox.com/v3/mapbox.geography-class/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
className: 'httpsbtilesmapboxcomv3mapboxgeographyclasszxypng',
|
||||
name: 'Geography Class',
|
||||
tms: false,
|
||||
category: 'TileJSON',
|
||||
type: 'Tiled'
|
||||
});
|
||||
|
||||
spyOn(this.view._tileJSONLayerModel, 'newTileLayer').and.returnValue(this.layer);
|
||||
|
||||
$.ajax.calls.argsFor(0)[0].success();
|
||||
});
|
||||
|
||||
it('should create layer with url', function () {
|
||||
expect(this.model.get('layer')).toBe(this.layer);
|
||||
});
|
||||
|
||||
it('should enable save button', function () {
|
||||
expect(this.view.$('.js-ok').attr('class')).not.toContain('is-disabled');
|
||||
});
|
||||
|
||||
it('should hide error', function () {
|
||||
expect(this.view.$('.js-error').attr('class')).not.toContain('is-visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
var WMSModel = require('builder/components/modals/add-basemap/wms/wms-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
var SelectLayerView = require('builder/components/modals/add-basemap/wms/select-layer-view');
|
||||
|
||||
describe('editor/components/modals/add-basemap/wms/select-layer-view', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
category: 'Custom',
|
||||
className: 'httpsaexamplecomzxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.layer = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
className: 'httpsaexamplecomzxypng',
|
||||
name: 'item #2',
|
||||
tms: false,
|
||||
category: 'WMS',
|
||||
type: 'Tiled'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection.add(this.layer);
|
||||
|
||||
this.model = new WMSModel(null, {
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
|
||||
this.view = new SelectLayerView({
|
||||
model: this.model,
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
describe('when there are a bunch of layers and some unavailable ones', function () {
|
||||
beforeEach(function () {
|
||||
this.model.wmsLayersCollection.reset([{
|
||||
title: 'item #1'
|
||||
}, {
|
||||
title: 'item #2'
|
||||
}, {
|
||||
title: 'item #3'
|
||||
}, {
|
||||
title: 'item #4'
|
||||
}]);
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render the amount of layers', function () {
|
||||
expect(this.model.getLayers().length).toBe(4);
|
||||
expect(this.model.layersAvailableCount()).toBe(3);
|
||||
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.wms.placeholder');
|
||||
});
|
||||
|
||||
it('should render the individual items', function () {
|
||||
expect(this.innerHTML()).toContain('item #1');
|
||||
expect(this.innerHTML()).toContain('item #4');
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when click back', function () {
|
||||
beforeEach(function () {
|
||||
this.view.$('.js-back').click();
|
||||
});
|
||||
|
||||
it('should set current view to go back to enter URL', function () {
|
||||
expect(this.model.get('currentView')).toEqual('enterURL');
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
var LayersCollection = require('builder/components/modals/add-basemap/wms/wms-layers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
var WMSService = require('builder/data/wms-service');
|
||||
|
||||
describe('editor/components/modals/add-basemap/wms/wms-layer-model', function () {
|
||||
beforeEach(function () {
|
||||
this.wmsService = new WMSService();
|
||||
this.wmsLayersCollection = new LayersCollection(null, {
|
||||
wmsService: this.wmsService
|
||||
});
|
||||
|
||||
this.wmsLayersCollection.reset([{}]);
|
||||
|
||||
this.model = this.wmsLayersCollection.at(0);
|
||||
});
|
||||
|
||||
it('should have idle state by default', function () {
|
||||
expect(this.model.get('state')).toEqual('idle');
|
||||
});
|
||||
|
||||
describe('.createProxiedLayerOrCustomBaselayerModel', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.model, 'save');
|
||||
});
|
||||
|
||||
describe('when is a WMS resource', function () {
|
||||
beforeEach(function () {
|
||||
this.model.createProxiedLayerOrCustomBaselayerModel();
|
||||
});
|
||||
|
||||
it('should change state to saving', function () {
|
||||
expect(this.model.get('state')).toEqual('saving');
|
||||
});
|
||||
|
||||
it('should save the WMS model', function () {
|
||||
expect(this.model.save).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when save succeeds', function () {
|
||||
describe('when can create customBaselayerModel', function () {
|
||||
beforeEach(function () {
|
||||
this.customBaselayerModel = jasmine.createSpy('customBaselayerModel');
|
||||
spyOn(this.model, '_newProxiedBaselayerModel').and.returnValue(this.customBaselayerModel);
|
||||
this.model.save.calls.argsFor(0)[1].success();
|
||||
});
|
||||
|
||||
it('should create a new tile layer', function () {
|
||||
expect(this.model.get('customBaselayerModel')).toBe(this.customBaselayerModel);
|
||||
});
|
||||
|
||||
it('should set state to saveDone', function () {
|
||||
expect(this.model.get('state')).toEqual('saveDone');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when could not create customBaselayerModel', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.model, '_newProxiedBaselayerModel').and.throwError('meh');
|
||||
this.model.save.calls.argsFor(0)[1].success();
|
||||
});
|
||||
|
||||
it('should not have any customBaselayerModel set', function () {
|
||||
expect(this.model.get('customBaselayerModel')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should set state to saveDone', function () {
|
||||
expect(this.model.get('state')).toEqual('saveFail');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when save fails', function () {
|
||||
beforeEach(function () {
|
||||
this.model.save.calls.argsFor(0)[1].error();
|
||||
});
|
||||
|
||||
it('should set state to saveFail', function () {
|
||||
expect(this.model.get('state')).toEqual('saveFail');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when is a WMTS resource with unsupported matrix set (e.g. GoogleMapsCompatible)', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set({
|
||||
type: 'wmts',
|
||||
url_template: 'http://foo.com/bar/%%(z)s/%%(x)s/%%(y)s.png',
|
||||
matrix_sets: ['GoogleMapsCompatible']
|
||||
});
|
||||
spyOn(this.model, '_byCustomURL').and.callThrough();
|
||||
this.model.createProxiedLayerOrCustomBaselayerModel();
|
||||
});
|
||||
|
||||
it('should create the tile layer with a proper XYZ URL', function () {
|
||||
expect(this.model._byCustomURL).toHaveBeenCalled();
|
||||
expect(this.model._byCustomURL.calls.argsFor(0)[0]).toEqual('http://foo.com/bar/{z}/{x}/{y}.png');
|
||||
});
|
||||
|
||||
it('should return a tile layer directly instead', function () {
|
||||
expect(this.model.get('customBaselayerModel') instanceof CustomBaselayerModel).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set saveDone', function () {
|
||||
expect(this.model.get('state')).toEqual('saveDone');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('._newProxiedBaselayerModel', function () {
|
||||
it('should throw an error unless mapproxy id is present', function () {
|
||||
expect(function () {
|
||||
this.model._newProxiedBaselayerModel();
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
describe('when mapproxy id is present', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set({
|
||||
mapproxy_id: 'abc123',
|
||||
attribution: 'attribution',
|
||||
name: 'tilelayer test',
|
||||
bounding_boxes: [1, 2, 3, 4]
|
||||
});
|
||||
this.proxiedBaselayerModel = this.model._newProxiedBaselayerModel();
|
||||
});
|
||||
|
||||
it('should return a tilelayer object', function () {
|
||||
expect(this.proxiedBaselayerModel).toEqual(jasmine.any(CustomBaselayerModel));
|
||||
});
|
||||
|
||||
it('should should have expected attrs on returned object', function () {
|
||||
expect(this.proxiedBaselayerModel.get('urlTemplate')).toMatch('/abc123/wmts/');
|
||||
expect(this.proxiedBaselayerModel.get('attribution')).toEqual('attribution');
|
||||
expect(this.proxiedBaselayerModel.get('maxZoom')).toEqual(21);
|
||||
expect(this.proxiedBaselayerModel.get('minZoom')).toEqual(0);
|
||||
expect(this.proxiedBaselayerModel.get('name')).toEqual('tilelayer test');
|
||||
expect(this.proxiedBaselayerModel.get('proxy')).toBeTruthy();
|
||||
expect(this.proxiedBaselayerModel.get('bounding_boxes')).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
var LayerView = require('builder/components/modals/add-basemap/wms/wms-layer-view');
|
||||
var LayerModel = require('builder/components/modals/add-basemap/wms/wms-layer-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
var WMSService = require('builder/data/wms-service');
|
||||
|
||||
describe('editor/components/modals/add-basemap/wms/wms-layer-view', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.wmsService = new WMSService();
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
category: 'Custom',
|
||||
className: 'httpsaexamplecomzxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new LayerModel(null, {
|
||||
wmsService: this.wmsService
|
||||
});
|
||||
|
||||
this.view = new LayerView({
|
||||
model: this.model,
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render item title or name', function () {
|
||||
this.model.set('name', 'Roads');
|
||||
this.view.render();
|
||||
expect(this.innerHTML()).toContain('Roads');
|
||||
this.model.set('title', 'Title has prio');
|
||||
this.view.render();
|
||||
expect(this.innerHTML()).toContain('Title has prio');
|
||||
});
|
||||
|
||||
it('should not disable any item by default', function () {
|
||||
expect(this.innerHTML).not.toContain('is-disabled');
|
||||
});
|
||||
|
||||
describe('when can not save layer', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('title', 'Test');
|
||||
|
||||
this.layer = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
className: 'httpsaexamplecomzxypng',
|
||||
name: 'Test',
|
||||
tms: false,
|
||||
category: 'WMS',
|
||||
type: 'Tiled'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection.add(this.layer);
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should disable item', function () {
|
||||
expect(this.innerHTML()).toContain('is-disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when clicking add this', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.model, 'createProxiedLayerOrCustomBaselayerModel');
|
||||
spyOn(this.model, 'canSave');
|
||||
});
|
||||
|
||||
it('should call save on model only if can save', function () {
|
||||
this.model.canSave.and.returnValue(false);
|
||||
this.view.$('.js-add').click();
|
||||
expect(this.model.createProxiedLayerOrCustomBaselayerModel).not.toHaveBeenCalled();
|
||||
|
||||
this.model.canSave.and.returnValue(true);
|
||||
this.view.$('.js-add').click();
|
||||
expect(this.model.createProxiedLayerOrCustomBaselayerModel).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
var $ = require('jquery');
|
||||
var LayersCollection = require('builder/components/modals/add-basemap/wms/wms-layers-collection');
|
||||
var WMSService = require('builder/data/wms-service');
|
||||
|
||||
describe('editor/components/modals/add-basemap/wms/wms-layers-collection', function () {
|
||||
beforeEach(function () {
|
||||
spyOn($, 'ajax').and.callFake(function (options) {
|
||||
options.success({});
|
||||
});
|
||||
|
||||
this.wmsService = new WMSService();
|
||||
this.wmsLayersCollection = new LayersCollection(null, {
|
||||
wmsService: this.wmsService
|
||||
});
|
||||
});
|
||||
|
||||
describe('.fetch', function () {
|
||||
beforeEach(function () {
|
||||
this.url = 'http://openlayers.org/en/v3.5.0/examples/data/ogcsample.xml';
|
||||
spyOn(this.wmsLayersCollection._wmsService, 'getFetchLayersURL').and.returnValue(this.url);
|
||||
|
||||
this.wmsLayersCollection.fetch();
|
||||
});
|
||||
|
||||
it('should fetch layers from given URL', function () {
|
||||
expect(this.wmsLayersCollection._wmsService.getFetchLayersURL).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
var WMSModel = require('builder/components/modals/add-basemap/wms/wms-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
|
||||
describe('editor/components/modals/add-basemap/wms/wms-model', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
category: 'Custom',
|
||||
className: 'httpsaexamplecomzxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new WMSModel(null, {
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any layers initially', function () {
|
||||
expect(this.model.wmsLayersCollection.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should have enter URl as initial view', function () {
|
||||
expect(this.model.get('currentView')).toEqual('enterURL');
|
||||
});
|
||||
|
||||
describe('.fetchLayers', function () {
|
||||
beforeEach(function () {
|
||||
this.url = 'http://openlayers.org/en/v3.5.0/examples/data/ogcsample.xml';
|
||||
this.model.wmsLayersCollection.sync = function (a, b, opts) {
|
||||
};
|
||||
spyOn(this.model.wmsLayersCollection, 'fetch').and.callThrough();
|
||||
this.model.fetchLayers(this.url);
|
||||
});
|
||||
|
||||
it('should fetch layers from given URL', function () {
|
||||
expect(this.model.wmsLayersCollection.fetch).toHaveBeenCalled();
|
||||
expect(this.model.wmsLayersCollection._wmsService._wms_url).toEqual(this.url);
|
||||
});
|
||||
|
||||
it('should change view to indicate that layers are being fetched', function () {
|
||||
expect(this.model.get('currentView')).toEqual('fetchingLayers');
|
||||
});
|
||||
|
||||
describe('when fetch is done', function () {
|
||||
describe('when there are layers', function () {
|
||||
beforeEach(function () {
|
||||
this.model.wmsLayersCollection.sync = function (a, b, opts) {
|
||||
opts.success({
|
||||
layers: [{}, {}, {}],
|
||||
title: 'title',
|
||||
type: 'type'
|
||||
});
|
||||
};
|
||||
this.model.fetchLayers(this.url);
|
||||
});
|
||||
|
||||
it('should change view to select layer', function () {
|
||||
expect(this.model.get('currentView')).toEqual('selectLayer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there are no layer', function () {
|
||||
beforeEach(function () {
|
||||
this.model.wmsLayersCollection.sync = function (a, b, opts) {
|
||||
opts.success({
|
||||
layers: [],
|
||||
title: 'title',
|
||||
type: 'type'
|
||||
});
|
||||
};
|
||||
this.model.fetchLayers(this.url);
|
||||
});
|
||||
|
||||
it('should change view back to enter URL', function () {
|
||||
expect(this.model.get('currentView')).toEqual('enterURL');
|
||||
});
|
||||
|
||||
it('should indicate that layers were fetched', function () {
|
||||
expect(this.model.get('layersFetched')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a layer changes state', function () {
|
||||
beforeEach(function () {
|
||||
this.saveBasemapSpy = jasmine.createSpy('saveBasemap');
|
||||
this.model.bind('saveBasemap', this.saveBasemapSpy);
|
||||
this.model.wmsLayersCollection.reset([{}, {}, {}]);
|
||||
});
|
||||
|
||||
it('should set the current view appropriately', function () {
|
||||
this.model.wmsLayersCollection.at(1).set('state', 'saving');
|
||||
expect(this.model.get('currentView')).toEqual('savingLayer');
|
||||
|
||||
this.model.wmsLayersCollection.at(1).set('state', 'saveFail');
|
||||
expect(this.model.get('currentView')).toEqual('saveFail');
|
||||
});
|
||||
|
||||
it('should select layer if state is done', function () {
|
||||
this.customBaselayerModel = {};
|
||||
|
||||
this.model.wmsLayersCollection.at(1).set({
|
||||
state: 'saveDone',
|
||||
customBaselayerModel: this.customBaselayerModel
|
||||
});
|
||||
expect(this.saveBasemapSpy).toHaveBeenCalled();
|
||||
expect(this.model.get('layer')).toBe(this.customBaselayerModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
var _ = require('underscore');
|
||||
var $ = require('jquery');
|
||||
var WMSView = require('builder/components/modals/add-basemap/wms/wms-view');
|
||||
var WMSModel = require('builder/components/modals/add-basemap/wms/wms-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
|
||||
describe('editor/components/modals/add-basemap/wms/wms-view', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(_, 'debounce').and.callFake(function (func) {
|
||||
return function () {
|
||||
func.apply(this, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
category: 'Custom',
|
||||
className: 'httpsaexamplecomzxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new WMSModel(null, {
|
||||
customBaselayersCollection: this.customBaselayersCollection
|
||||
});
|
||||
|
||||
var submitButton = $('<button class="is-disabled">Submit</button>');
|
||||
var modalFooter = $('<div></div>');
|
||||
|
||||
this.view = new WMSView({
|
||||
model: this.model,
|
||||
customBaselayersCollection: this.customBaselayersCollection,
|
||||
submitButton: submitButton,
|
||||
modalFooter: modalFooter
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render the set button as disabled initially', function () {
|
||||
expect(this.view._submitButton.hasClass('is-disabled')).toBe(true);
|
||||
});
|
||||
|
||||
describe('when user written a URL', function () {
|
||||
beforeEach(function () {
|
||||
var $el = this.view.$('.js-url');
|
||||
$el.val('http://openlayers.org/en/v3.5.0/examples/data/ogcsample.xml');
|
||||
$el.trigger('keydown');
|
||||
});
|
||||
|
||||
it('should enable get-layers button', function () {
|
||||
expect(this.view._submitButton.hasClass('is-disabled')).toBe(false);
|
||||
});
|
||||
|
||||
describe('when click fetch layers', function () {
|
||||
beforeEach(function () {
|
||||
this.model.wmsLayersCollection.sync = function (a, b, opts) {
|
||||
};
|
||||
|
||||
spyOn(this.model, 'fetchLayers').and.callThrough();
|
||||
this.view._submitButton.click();
|
||||
});
|
||||
|
||||
it('should show fetching layers', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.fetching');
|
||||
});
|
||||
|
||||
it('should call fetch layers on view model', function () {
|
||||
expect(this.model.fetchLayers).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when there is at least one layer fetched', function () {
|
||||
beforeEach(function () {
|
||||
this.model.wmsLayersCollection.reset([{ name: '' }]);
|
||||
});
|
||||
|
||||
it('should change to select layer view', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.wms.placeholder');
|
||||
});
|
||||
|
||||
it('should show the search form', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-layer.navigation.search');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there are several layers fetched', function () {
|
||||
beforeEach(function () {
|
||||
this.model.wmsLayersCollection.reset([
|
||||
{ name: 'Bageshwar' },
|
||||
{ name: 'Bagaha' },
|
||||
{ name: 'Bahadurgarh' },
|
||||
{ name: 'baharampur' },
|
||||
{ name: 'Bahraich' },
|
||||
{ name: 'Chirmiri' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should allow to search', function () {
|
||||
this.view.$el.find('.js-search-input').val('Bah');
|
||||
this.view.$el.find('.js-search-link').click();
|
||||
expect(this.innerHTML()).toContain('Bahraich');
|
||||
expect(this.innerHTML()).toContain('Bahadurgarh');
|
||||
expect(this.innerHTML()).toContain('baharampur');
|
||||
expect(this.innerHTML()).not.toContain('Chirmiri');
|
||||
});
|
||||
|
||||
it('should show a no result search', function () {
|
||||
this.view.$el.find('.js-search-input').val('León');
|
||||
this.view.$el.find('.js-search-link').click();
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.wms.unfortunately');
|
||||
});
|
||||
|
||||
it('should close the search', function () {
|
||||
this.view.$el.find('.js-search-input').val('Bah');
|
||||
this.view.$el.find('.js-search-link').click();
|
||||
this.view.$el.find('.js-clean-search').click();
|
||||
expect(this.view.$el.find('.js-search-input').val()).toBeFalsy();
|
||||
expect(this.innerHTML()).toContain('Bageshwar');
|
||||
expect(this.innerHTML()).toContain('Bagaha');
|
||||
expect(this.innerHTML()).toContain('Bahraich');
|
||||
expect(this.innerHTML()).toContain('Bahadurgarh');
|
||||
expect(this.innerHTML()).toContain('baharampur');
|
||||
expect(this.innerHTML()).toContain('Chirmiri');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there are no layers fetched', function () {
|
||||
beforeEach(function () {
|
||||
this.model.wmsLayersCollection.reset();
|
||||
});
|
||||
|
||||
it('should set back to enter url view', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.wms.insert');
|
||||
});
|
||||
|
||||
it('should show an error indicating URL being invalid', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.wms.invalid');
|
||||
});
|
||||
|
||||
it("shouldn't show the search form", function () {
|
||||
expect(this.innerHTML()).not.toContain('components.modals.add-layer.navigation.search');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when layer is added', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('currentView', 'savingLayer');
|
||||
});
|
||||
|
||||
it('should show saving layer indicator', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.saving');
|
||||
});
|
||||
|
||||
describe('when layer is not saved', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('currentView', 'saveFail');
|
||||
});
|
||||
|
||||
it('should show error view', function () {
|
||||
expect(this.innerHTML()).toContain('error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var XYZModel = require('builder/components/modals/add-basemap/xyz/xyz-model');
|
||||
var CustomBaselayersCollection = require('builder/data/custom-baselayers-collection');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
|
||||
describe('components/modals/add-basemap/xyz/xyz-model', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.customBaselayersCollection = new CustomBaselayersCollection([{
|
||||
id: 'basemap-id-1',
|
||||
options: {
|
||||
urlTemplate: 'https://a.example.com/{z}/{x}/{y}.png',
|
||||
category: 'Custom',
|
||||
className: 'httpsaexamplecomzxypng'
|
||||
}
|
||||
}], {
|
||||
configModel: configModel,
|
||||
currentUserId: 'current-user-id'
|
||||
});
|
||||
|
||||
this.model = new XYZModel();
|
||||
});
|
||||
|
||||
describe('.hasAlreadyAddedLayer', function () {
|
||||
beforeEach(function () {
|
||||
this.customBaselayerModel = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'https://b.example.com/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
className: 'httpsbexamplecomzxypng',
|
||||
name: 'item #2',
|
||||
tms: false,
|
||||
category: 'Custom',
|
||||
type: 'Tiled'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return true if layer has already been added', function () {
|
||||
this.model.set('layer', this.customBaselayerModel);
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBe(false);
|
||||
|
||||
this.model.set('layer', this.customBaselayersCollection.at(0));
|
||||
expect(this.model.hasAlreadyAddedLayer(this.customBaselayersCollection)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,156 @@
|
||||
var _ = require('underscore');
|
||||
var $ = require('jquery');
|
||||
var XYZView = require('builder/components/modals/add-basemap/xyz/xyz-view');
|
||||
var XYZModel = require('builder/components/modals/add-basemap/xyz/xyz-model');
|
||||
var CustomBaselayerModel = require('builder/data/custom-baselayer-model');
|
||||
|
||||
describe('components/modals/add-basemap/xyz/xyz-view', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(_, 'debounce').and.callFake(function (func) {
|
||||
return function () {
|
||||
func.apply(this, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
var submitButton = $('<button class="is-disabled">Submit</button>');
|
||||
|
||||
this.model = new XYZModel();
|
||||
this.view = new XYZView({
|
||||
model: this.model,
|
||||
submitButton: submitButton
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render the set button as disabled initially', function () {
|
||||
expect(this.view._submitButton.hasClass('is-disabled')).toBe(true);
|
||||
});
|
||||
|
||||
it('should change TMS checkbox when model changes', function () {
|
||||
expect(this.view.$('.js-tms .Checkbox-input').hasClass('is-checked')).toBeFalsy();
|
||||
this.view.model.set('tms', true);
|
||||
expect(this.view.$('.js-tms .Checkbox-input').hasClass('is-checked')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when user written a URL', function () {
|
||||
describe('when URL is half-done or invalid', function () {
|
||||
beforeEach(function () {
|
||||
var $el = this.view.$('.js-url');
|
||||
$el.val('ht');
|
||||
$el.trigger('keydown');
|
||||
$el.val('htt');
|
||||
$el.trigger('keydown');
|
||||
});
|
||||
|
||||
it('should show error', function () {
|
||||
expect(this.view.$('.js-error').attr('class')).toContain('is-visible');
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.xyz.not-valid');
|
||||
});
|
||||
|
||||
it('should disable OK button', function () {
|
||||
expect(this.view._submitButton.hasClass('is-disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when finally written/pasted a valid URL', function () {
|
||||
beforeEach(function () {
|
||||
this.layer = new CustomBaselayerModel({
|
||||
id: 'basemap-id-2',
|
||||
urlTemplate: 'https://b.example.com/{z}/{x}/{y}.png',
|
||||
attribution: null,
|
||||
maxZoom: 21,
|
||||
minZoom: 0,
|
||||
name: '',
|
||||
tms: false,
|
||||
category: 'Custom',
|
||||
type: 'Tiled'
|
||||
});
|
||||
spyOn(this.layer, 'validateTemplateURL');
|
||||
});
|
||||
|
||||
describe('when URL does not have a valid XYZ format', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.view, '_byCustomURL').and.throwError();
|
||||
|
||||
this.view.$('.js-url')
|
||||
.val('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png')
|
||||
.trigger('keydown');
|
||||
});
|
||||
|
||||
it('should show error', function () {
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.xyz.not-valid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when URL has a valid XYZ format', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.view, '_byCustomURL').and.returnValue(this.layer);
|
||||
|
||||
this.view.$('.js-url')
|
||||
.val('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png')
|
||||
.trigger('keydown');
|
||||
});
|
||||
|
||||
it('should create layer with url', function () {
|
||||
expect(this.view._byCustomURL).toHaveBeenCalledWith('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', false);
|
||||
});
|
||||
|
||||
it('should set the layer on the view model', function () {
|
||||
expect(this.model.get('layer')).toBe(this.layer);
|
||||
});
|
||||
|
||||
it('should disable the save button', function () {
|
||||
expect(this.view._submitButton.attr('class')).toContain('is-disabled');
|
||||
});
|
||||
|
||||
it('should hide error', function () {
|
||||
expect(this.view.$('.js-error').attr('class')).not.toContain('is-visible');
|
||||
});
|
||||
|
||||
it('should validate template URL', function () {
|
||||
expect(this.layer.validateTemplateURL).toHaveBeenCalledWith({
|
||||
success: jasmine.any(Function),
|
||||
error: jasmine.any(Function)
|
||||
});
|
||||
});
|
||||
|
||||
describe('when URL is finally validated', function () {
|
||||
beforeEach(function () {
|
||||
this.layer.validateTemplateURL.calls.argsFor(0)[0].success();
|
||||
});
|
||||
|
||||
it('should enable save button', function () {
|
||||
expect(this.view._submitButton.attr('class')).not.toContain('is-disabled');
|
||||
});
|
||||
|
||||
it('should hide error', function () {
|
||||
expect(this.view.$('.js-error').attr('class')).not.toContain('is-visible');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when URL fails to be validated', function () {
|
||||
beforeEach(function () {
|
||||
this.layer.validateTemplateURL.calls.argsFor(0)[0].error();
|
||||
});
|
||||
|
||||
it('should enable save button', function () {
|
||||
expect(this.view._submitButton.attr('class')).not.toContain('is-disabled');
|
||||
});
|
||||
|
||||
it('should show error', function () {
|
||||
expect(this.view.$('.js-error').attr('class')).toContain('is-visible');
|
||||
expect(this.innerHTML()).toContain('components.modals.add-basemap.xyz.couldnt-validate');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,306 @@
|
||||
var Backbone = require('backbone');
|
||||
var AddLayerModel = require('builder/components/modals/add-layer/add-layer-model');
|
||||
var TableModel = require('builder/data/table-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var sharedForCreateListingViewModel = require('./shared-for-create-listing-view-model.spec.js');
|
||||
var sharedForCreateListingImportViewModel = require('./shared-for-import-view-model.spec.js');
|
||||
var UserActions = require('builder/data/user-actions');
|
||||
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
|
||||
|
||||
describe('components/modals/add-layer/add-layer-model', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
|
||||
spyOn(MetricsTracker, 'track');
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
var vizUrl = 'http(s)?://(.)+' + configModel.get('base_url') + '/api/v1/viz.*';
|
||||
jasmine.Ajax.stubRequest(new RegExp(vizUrl)).andReturn({
|
||||
status: 200
|
||||
});
|
||||
|
||||
this.pollingModel = new Backbone.Model();
|
||||
|
||||
this.userModel = new UserModel({
|
||||
username: 'pepe'
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.userActions = UserActions({
|
||||
userModel: this.userModel,
|
||||
analysisDefinitionNodesCollection: {},
|
||||
analysisDefinitionsCollection: {},
|
||||
layerDefinitionsCollection: {},
|
||||
widgetDefinitionsCollection: {}
|
||||
});
|
||||
spyOn(this.userActions, 'createLayerFromTable');
|
||||
|
||||
this.model = new AddLayerModel(null, {
|
||||
pollingModel: this.pollingModel,
|
||||
configModel: configModel,
|
||||
userModel: this.userModel,
|
||||
userActions: this.userActions
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
sharedForCreateListingViewModel.call(this);
|
||||
sharedForCreateListingImportViewModel.call(this);
|
||||
|
||||
it('should have listing as default content pane', function () {
|
||||
expect(this.model.get('contentPane')).toEqual('listing');
|
||||
});
|
||||
|
||||
describe('.canFinish', function () {
|
||||
describe('when listing is import', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.model._uploadModel, 'isValidToUpload');
|
||||
this.model.set('listing', 'import');
|
||||
});
|
||||
|
||||
it('should return true only if upload is valid', function () {
|
||||
expect(this.model.canFinish()).toBeFalsy();
|
||||
|
||||
this.model._uploadModel.isValidToUpload = function () { return true; };
|
||||
expect(this.model.canFinish()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when listing is datasets', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('listing', 'datasets');
|
||||
});
|
||||
|
||||
it('should return true if there is at least one dataset selected', function () {
|
||||
expect(this.model.canFinish()).toBeFalsy();
|
||||
|
||||
this.model._selectedDatasetsCollection.add({});
|
||||
expect(this.model.canFinish()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.canSelect', function () {
|
||||
beforeEach(function () {
|
||||
this.dataset = new Backbone.Model({
|
||||
selected: false
|
||||
});
|
||||
});
|
||||
|
||||
it('should return true only if there is dataset selected or if wanting to deselect', function () {
|
||||
expect(this.model.canSelect(this.dataset)).toBeTruthy();
|
||||
|
||||
this.model._selectedDatasetsCollection.add({ selected: true });
|
||||
expect(this.model.canSelect(this.dataset)).toBeFalsy();
|
||||
|
||||
this.dataset.set('selected', true);
|
||||
expect(this.model.canSelect(this.dataset)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.finish', function () {
|
||||
describe('when an dataset is selected', function () {
|
||||
describe('when dataset is a remote one (from library)', function () {
|
||||
beforeEach(function () {
|
||||
this.pollingModel.bind('importByUploadData', function (data) {
|
||||
this.importByUploadData = data;
|
||||
}, this);
|
||||
|
||||
this.model._tablesCollection.reset([{
|
||||
id: 'abc-123',
|
||||
type: 'remote',
|
||||
name: 'foobar',
|
||||
external_source: {
|
||||
size: 1024
|
||||
}
|
||||
}]);
|
||||
this.model._tablesCollection.at(0).set('selected', true);
|
||||
this.model.finish();
|
||||
});
|
||||
|
||||
it('should trigger a importByUploadData event', function () {
|
||||
expect(this.importByUploadData).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should pass a metadata object with necessary data to import dataset', function () {
|
||||
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ type: 'remote' }));
|
||||
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ value: 'foobar' }));
|
||||
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ remote_visualization_id: 'abc-123' }));
|
||||
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ size: 1024 }));
|
||||
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ create_vis: false }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when dataset is not a remote one', function () {
|
||||
beforeEach(function () {
|
||||
this.model.bind('addLayerDone', function () {
|
||||
this.addLayerDoneCalled = true;
|
||||
}, this);
|
||||
|
||||
this.model._tablesCollection.reset([{
|
||||
id: 'abc',
|
||||
type: 'table',
|
||||
name: 'paco',
|
||||
table: {
|
||||
name: 'tableName'
|
||||
}
|
||||
}]);
|
||||
this.model._tablesCollection.at(0).set('selected', true);
|
||||
this.model.finish();
|
||||
});
|
||||
|
||||
it('should create layer from dataset', function () {
|
||||
expect(this.userActions.createLayerFromTable).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create layer with expected params', function () {
|
||||
var tableModel = this.userActions.createLayerFromTable.calls.argsFor(0)[0];
|
||||
expect(tableModel.get('name')).toBe('tableName');
|
||||
});
|
||||
|
||||
it('should change the content view setting', function () {
|
||||
expect(this.model.get('contentPane')).toEqual('addingNewLayer');
|
||||
});
|
||||
|
||||
describe('when adding layer succeeds', function () {
|
||||
beforeEach(function () {
|
||||
var createdModel = new Backbone.Model({ id: 'test' });
|
||||
expect(this.addLayerDoneCalled).toBeFalsy();
|
||||
this.userActions.createLayerFromTable.calls.argsFor(0)[1].success(createdModel);
|
||||
});
|
||||
|
||||
it('should trigger addLayerDone', function () {
|
||||
expect(this.addLayerDoneCalled).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when adding layer fails', function () {
|
||||
beforeEach(function () {
|
||||
this.userActions.createLayerFromTable.calls.argsFor(0)[1].error({}, {
|
||||
responseText: '{"error": ["meh"]}'
|
||||
});
|
||||
});
|
||||
|
||||
it('should change contentPane to addLayerFail', function () {
|
||||
expect(this.model.get('contentPane')).toEqual('addLayerFailed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when table quota exceeded', function () {
|
||||
beforeEach(function () {
|
||||
this.userActions.createLayerFromTable.calls.argsFor(0)[1].error({}, {
|
||||
responseText: '{"errors": ["You have reached your table quota"]}'
|
||||
});
|
||||
});
|
||||
|
||||
it('should change contentPane to datasetQuotaExceeded', function () {
|
||||
expect(this.model.get('contentPane')).toEqual('datasetQuotaExceeded');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.createFromScratch', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(TableModel.prototype, 'save').and.callFake(function () {
|
||||
this.set('name', 'name-just-for-testing-purposes', { silent: true });
|
||||
return this;
|
||||
});
|
||||
});
|
||||
|
||||
it('should change to loading state', function () {
|
||||
this.model.createFromScratch();
|
||||
expect(this.model.get('contentPane')).toEqual('creatingFromScratch');
|
||||
});
|
||||
|
||||
it('should save a new dataset table', function () {
|
||||
this.model.createFromScratch();
|
||||
expect(TableModel.prototype.save).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when table is successfully created', function () {
|
||||
it('should add the table as new layer', function () {
|
||||
this.model.createFromScratch();
|
||||
TableModel.prototype.save.calls.argsFor(0)[1].success();
|
||||
|
||||
expect(this.userActions.createLayerFromTable).toHaveBeenCalled();
|
||||
var tableModel = this.userActions.createLayerFromTable.calls.argsFor(0)[0];
|
||||
expect(tableModel.get('name')).toBe('name-just-for-testing-purposes');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when an upload is set', function () {
|
||||
beforeEach(function () {
|
||||
this.pollingModel.bind('importByUploadData', function (d) {
|
||||
this.importByUploadData = d;
|
||||
}, this);
|
||||
this.model.set('listing', 'import');
|
||||
this.model.finish();
|
||||
});
|
||||
|
||||
it('should call pollingModel importByUploadData with expected data', function () {
|
||||
expect(this.importByUploadData).toBeTruthy();
|
||||
expect(this.importByUploadData).toEqual(jasmine.objectContaining({ state: 'idle' }));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when listing', function () {
|
||||
it('should detect which', function () {
|
||||
this.model.set('listing', 'import');
|
||||
expect(this.model._atImportPane()).toBe(true);
|
||||
|
||||
this.model.set('listing', 'datasets');
|
||||
expect(this.model._atImportPane()).toBe(false);
|
||||
expect(this.model._atDatasetsPane()).toBe(true);
|
||||
|
||||
this.model.set('listing', 'scratch');
|
||||
expect(this.model._atDatasetsPane()).toBe(false);
|
||||
expect(this.model._atScratchPane()).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect "twitter import pane"', function () {
|
||||
this.model.set('listing', 'import');
|
||||
|
||||
this.model.set('activeImportPane', 'twitter');
|
||||
expect(this.model._atTwitterImportPane()).toBe(true);
|
||||
|
||||
this.model.set('activeImportPane', '*whatever-else*');
|
||||
expect(this.model._atTwitterImportPane()).toBe(false);
|
||||
});
|
||||
|
||||
describe('and deciding on togglers', function () {
|
||||
it('should decide to show "guessing toggler" if at import', function () {
|
||||
this.model.set('listing', 'import');
|
||||
expect(this.model.showGuessingToggler()).toBe(true);
|
||||
|
||||
this.model.set('listing', 'datasets');
|
||||
expect(this.model.showGuessingToggler()).toBe(false);
|
||||
});
|
||||
|
||||
it('should decide to show "privacy toggler" if at import (unless deprecated twitter)', function () {
|
||||
this.model.set('listing', 'import');
|
||||
|
||||
this.model.set('activeImportPane', '*whatever-but-twitter*');
|
||||
expect(this.model.showPrivacyToggler()).toBe(true);
|
||||
|
||||
this.model.set('activeImportPane', 'twitter');
|
||||
var spy = spyOn(this.userModel, 'hasOwnTwitterCredentials');
|
||||
spy.and.returnValue(true);
|
||||
expect(this.model.showPrivacyToggler()).toBe(true);
|
||||
|
||||
spy.and.returnValue(false);
|
||||
expect(this.model.showPrivacyToggler()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('underscore');
|
||||
var CreditsUsageView = require('builder/components/modals/add-layer/content/imports/import-twitter/credits-usage-view');
|
||||
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
|
||||
|
||||
/** Note: More behaviour is tested on its parent view (import-twitter.view.spec.js) */
|
||||
describe('components/modals/add-layer/content/imports/imports-twitter/credits-usage-view', function () {
|
||||
beforeEach(function () {
|
||||
this.userModel = getUserModelFixture();
|
||||
|
||||
// extracted from `import-twitter.tpl`
|
||||
this.tplForView =
|
||||
'<div class="Form-rowData Form-rowData--longer CreditsUsage">' +
|
||||
' <div class="UISlider CreditsUsage-slider js-slider"></div>' +
|
||||
' <div class="CreditsUsage-info CDB-Text CDB-Size-medium js-info"></div>' +
|
||||
'</div>';
|
||||
|
||||
this.createView = function (opts) {
|
||||
var custom = opts || {};
|
||||
var defaults = {
|
||||
userModel: this.userModel,
|
||||
el: $(this.tplForView)
|
||||
};
|
||||
return new CreditsUsageView(_.extend(defaults, custom));
|
||||
};
|
||||
this.view = this.createView();
|
||||
});
|
||||
|
||||
it('should be enabled by default', function () {
|
||||
expect(this.view._disabled).toBe(false);
|
||||
});
|
||||
|
||||
it('can be created disabled or enabled', function () {
|
||||
var v = this.createView({disabled: true});
|
||||
expect(v._disabled).toBe(true);
|
||||
|
||||
v = this.createView({disabled: false});
|
||||
expect(v._disabled).toBe(false);
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
beforeEach(function () {
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$('.js-slider').length).toBe(1);
|
||||
expect(this.view.$('.js-info').length).toBe(1);
|
||||
});
|
||||
|
||||
it('can be rendered with a disabled or enabled slider', function () {
|
||||
expect(this.view._disabled).toBe(false);
|
||||
expect(this.view.$('.js-slider').slider('option', 'disabled')).toBe(false);
|
||||
|
||||
this.view._disabled = true;
|
||||
this.view.render();
|
||||
expect(this.view.$('.js-slider').slider('option', 'disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
var _ = require('underscore');
|
||||
var ImportTwitterView = require('builder/components/modals/add-layer/content/imports/import-twitter/import-twitter-view');
|
||||
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
|
||||
var getConfigModelFixture = require('fixtures/builder/config-model.fixture.js');
|
||||
|
||||
describe('components/modals/add-layer/content/imports/imports-twitter/import-twitter-view', function () {
|
||||
beforeEach(function () {
|
||||
this.userModel = getUserModelFixture();
|
||||
|
||||
this.view = new ImportTwitterView({
|
||||
userModel: this.userModel,
|
||||
configModel: getConfigModelFixture()
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
it('should be rendered properly', function () {
|
||||
expect(this.view.$('.ImportTwitterPanel-categories').length).toBe(1);
|
||||
expect(this.view.$('.ImportTwitterPanel-datePicker').length).toBe(1);
|
||||
expect(this.view.$('.ImportTwitterPanel-creditsUsage').length).toBe(1);
|
||||
});
|
||||
|
||||
describe('twitter categories', function () {
|
||||
beforeEach(function () {
|
||||
this.categories = this.view.categories;
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.categories.$('.TwitterCategory').length).toBe(1);
|
||||
expect(this.categories.$('.TwitterCategory label').text()).toBe(
|
||||
'components.modals.add-layer.imports.twitter.category 1');
|
||||
});
|
||||
|
||||
it('should create a new category when the before one has any character', function () {
|
||||
this.categories.$('.TwitterCategory .js-terms').val('test');
|
||||
this.categories.$('.TwitterCategory .js-terms').trigger('keydown');
|
||||
expect(this.categories.$('.TwitterCategory').length).toBe(2);
|
||||
});
|
||||
|
||||
it('should delete the category when it is empty and it is not the first one', function () {
|
||||
this.categories.$('.TwitterCategory .js-terms').val('test');
|
||||
this.categories.$('.TwitterCategory .js-terms').trigger('keydown');
|
||||
expect(this.categories.$('.TwitterCategory').length).toBe(2);
|
||||
this.categories.$('.TwitterCategory:eq(0) .js-terms').val('');
|
||||
this.categories.$('.TwitterCategory:eq(0) .js-terms').trigger('keydown');
|
||||
expect(this.categories.$('.TwitterCategory').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render 4 categories as max', function () {
|
||||
for (var i = 0, l = 10; i < l; i++) {
|
||||
this.categories.$('.TwitterCategory:eq(' + i + ') .js-terms').val('test');
|
||||
this.categories.$('.TwitterCategory:eq(' + i + ') .js-terms').trigger('keydown');
|
||||
}
|
||||
expect(this.categories.$('.TwitterCategory').length).toBe(4);
|
||||
});
|
||||
|
||||
it('should return categories as JSON format', function () {
|
||||
this.categories.$('.TwitterCategory .js-terms').val('test');
|
||||
this.categories.$('.TwitterCategory .js-terms').trigger('keydown');
|
||||
var categories = this.categories.getCategories();
|
||||
expect(categories.length).toBe(2);
|
||||
expect(categories[0].category).toBe('1');
|
||||
expect(categories[0].terms.length).toBe(1);
|
||||
expect(categories[0].terms[0]).toBe('test');
|
||||
expect(categories[1].category).toBe('2');
|
||||
expect(categories[1].terms.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('twitter credits', function () {
|
||||
beforeEach(function () {
|
||||
this.creditsUsage = this.view.creditsUsage;
|
||||
|
||||
var creditsInfoKey = _.keys(this.creditsUsage._subviews)[0];
|
||||
this.creditsInfo = this.creditsUsage._subviews[creditsInfoKey];
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.creditsUsage.$('.CreditsUsage-slider').length).toBe(1);
|
||||
expect(this.creditsUsage.$('.CreditsUsage-info').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should set as min value 1%, not 0%', function () {
|
||||
this.creditsUsage.$('.js-slider').slider('value', 0);
|
||||
expect(this.creditsUsage.model.get('value')).toBe(1);
|
||||
});
|
||||
|
||||
it('should start around 80% of quota', function () {
|
||||
var perValue = (this.creditsUsage.model.get('value') * 100) / this.userModel.get('twitter').quota;
|
||||
expect(perValue).toBe(80);
|
||||
});
|
||||
|
||||
it("should let choose 'no limits' when user doesn't have hard limits", function () {
|
||||
this.creditsUsage.$('.js-slider').slider('value', 101);
|
||||
expect(this.creditsUsage.$('.js-info').text()).toContain(
|
||||
'components.modals.add-layer.imports.twitter.credits-no-limit');
|
||||
});
|
||||
|
||||
it("shouldn't let choose 'no limits' when user has hard limits", function () {
|
||||
var twitterData = this.userModel.get('twitter');
|
||||
twitterData.hard_limit = true;
|
||||
this.userModel.set('twitter', twitterData);
|
||||
this.creditsUsage.render();
|
||||
this.creditsUsage.$('.js-slider').slider('value', 101);
|
||||
expect(this.creditsUsage.$('.js-info').text()).not.toContain(
|
||||
'components.modals.add-layer.imports.twitter.credits-no-limit');
|
||||
});
|
||||
|
||||
it('should disable slider when user has reached his/her limits', function () {
|
||||
var twitterData = this.userModel.get('twitter');
|
||||
twitterData.monthly_use = 110;
|
||||
this.userModel.set('twitter', twitterData);
|
||||
this.view.render();
|
||||
expect(this.view.$('.js-slider').slider('option', 'disabled')).toBeTruthy();
|
||||
expect(this.view.$('.js-info').text()).toContain(
|
||||
'components.modals.add-layer.imports.twitter.credits-consumed');
|
||||
});
|
||||
|
||||
it('should change credits info when credits value has changed', function () {
|
||||
expect(this.creditsInfo.model.get('value')).toBe(80);
|
||||
this.creditsUsage.model.set('value', 30);
|
||||
expect(this.creditsInfo.model.get('value')).toBe(30);
|
||||
});
|
||||
|
||||
it('should update model when value has changed', function (done) {
|
||||
expect(this.creditsUsage.model.get('value')).toBe(80);
|
||||
spyOn(this.view.model, 'validate').and.callThrough();
|
||||
this.creditsUsage.model.set('value', 1);
|
||||
var that = this;
|
||||
_.defer(function () {
|
||||
var lastCall = that.view.model.validate.calls.mostRecent();
|
||||
var lastArg = lastCall.args[0].user_defined_limits.twitter_credits_limit;
|
||||
expect(lastArg).toEqual(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('enabled or disabled according to user\'s own credentials', function () {
|
||||
beforeEach(function () {
|
||||
this.spyOnHasOwnTwitterCredentials = spyOn(this.userModel, 'hasOwnTwitterCredentials');
|
||||
|
||||
this.formIsEnabled = function () {
|
||||
var categories = !this.view.categories._disabled;
|
||||
var datepicker = !this.view.datepicker._disabled;
|
||||
var creditsUsage = !this.view.creditsUsage._disabled;
|
||||
|
||||
var allInputsEnabled = categories && datepicker && creditsUsage;
|
||||
return allInputsEnabled;
|
||||
};
|
||||
});
|
||||
|
||||
it('should be enabled if user has his own credentials', function () {
|
||||
this.spyOnHasOwnTwitterCredentials.and.returnValue(true);
|
||||
this.view._initViews();
|
||||
expect(this.formIsEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
it('should not be enabled if uses don\'t have his own', function () {
|
||||
this.spyOnHasOwnTwitterCredentials.and.returnValue(false);
|
||||
this.view._initViews();
|
||||
expect(this.formIsEnabled()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
var _ = require('underscore');
|
||||
var TwitterCategoriesView = require('builder/components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-categories-view');
|
||||
|
||||
/** Note: More behaviour, specially 'render', is tested on its parent view (import-twitter.view.spec.js) */
|
||||
describe('components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-categories-view', function () {
|
||||
beforeEach(function () {
|
||||
this.createView = function (opts) {
|
||||
var custom = opts || {};
|
||||
var defaults = {};
|
||||
var view = new TwitterCategoriesView(_.extend(defaults, custom));
|
||||
|
||||
view.categoriesAreDisabled = function () {
|
||||
var allDisabled = this.collection.every(function (category) {
|
||||
return category.get('disabled');
|
||||
});
|
||||
return allDisabled;
|
||||
};
|
||||
|
||||
return view;
|
||||
};
|
||||
this.view = this.createView();
|
||||
});
|
||||
|
||||
it('should be enabled by default', function () {
|
||||
expect(this.view._disabled).toBe(false);
|
||||
expect(this.view.categoriesAreDisabled()).toBe(false);
|
||||
});
|
||||
|
||||
it('can be created disabled or enabled', function () {
|
||||
var v = this.createView({disabled: true});
|
||||
expect(v._disabled).toBe(true);
|
||||
expect(v.categoriesAreDisabled()).toBe(true);
|
||||
|
||||
v = this.createView({disabled: false});
|
||||
expect(v._disabled).toBe(false);
|
||||
expect(v.categoriesAreDisabled()).toBe(false);
|
||||
});
|
||||
});
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
var Backbone = require('backbone');
|
||||
var TwitterCategoryView = require('builder/components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-category-view');
|
||||
|
||||
/** Note: More behaviour is tested on its parent view (import-twitter.view.spec.js) */
|
||||
describe('components/modals/add-layer/content/imports/import-twitter/twitter-categories/twitter-category-view', function () {
|
||||
beforeEach(function () {
|
||||
this.createView = function () {
|
||||
var m = new Backbone.Model({
|
||||
terms: [],
|
||||
category: '1',
|
||||
counter: 1014
|
||||
});
|
||||
return new TwitterCategoryView({model: m});
|
||||
};
|
||||
this.view = this.createView();
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
beforeEach(function () {
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$('input').length).toBe(1);
|
||||
});
|
||||
|
||||
it('can be rendered disabled or enabled', function () {
|
||||
this.view.model.set('disabled', false);
|
||||
this.view.render();
|
||||
expect(this.view.$('input').prop('disabled')).toBe(false);
|
||||
|
||||
this.view.model.set('disabled', true);
|
||||
this.view.render();
|
||||
expect(this.view.$('input').prop('disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
var Backbone = require('backbone');
|
||||
var ImportsView = require('builder/components/modals/add-layer/content/imports/imports-view');
|
||||
var AddLayerModel = require('builder/components/modals/add-layer/add-layer-model');
|
||||
var userModel = require('fixtures/builder/user-model.fixture');
|
||||
var configModel = require('fixtures/builder/config-model.fixture');
|
||||
|
||||
describe('components/modals/add-layer/content/imports/imports-view', function () {
|
||||
var privacyModel = new Backbone.Model();
|
||||
var guessingModel = new Backbone.Model();
|
||||
var _userModel = userModel({
|
||||
mailchimp: {
|
||||
enabled: true
|
||||
}
|
||||
});
|
||||
var _configModel = configModel({
|
||||
oauth_gdrive: true
|
||||
});
|
||||
var createModel = new AddLayerModel({}, {
|
||||
userModel: _userModel,
|
||||
configModel: _configModel,
|
||||
userActions: {},
|
||||
pollingModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
this.view = new ImportsView({
|
||||
userModel: _userModel,
|
||||
configModel: _configModel,
|
||||
createModel: createModel,
|
||||
privacyModel: privacyModel,
|
||||
guessingModel: guessingModel
|
||||
});
|
||||
|
||||
spyOn(this.view, '_setUploadModel');
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should call _setUploadModel on change events', function () {
|
||||
// Switch tabs back and forth, this used to break because backbone drops events
|
||||
this.view.$('.js-gdriveTab').click();
|
||||
this.view.$('.js-fileTab').click();
|
||||
var selectedTab = this.view._tabPaneCollection.filter(function (e) {
|
||||
return e.get('selected') === true;
|
||||
})[0];
|
||||
|
||||
selectedTab.attributes.createContentView().trigger('change');
|
||||
expect(this.view._setUploadModel).toHaveBeenCalled();
|
||||
this.view.clean();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
// Remove dropzone leaftover elements
|
||||
document.querySelector('input.dz-hidden-input').remove();
|
||||
});
|
||||
});
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
var Backbone = require('backbone');
|
||||
var GuessingTogglerView = require('builder/components/modals/add-layer/footer/guessing-toggler-view');
|
||||
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
|
||||
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
|
||||
var getConfigModelFixture = require('fixtures/builder/config-model.fixture.js');
|
||||
|
||||
describe('components/modals/add-layer/footer/guessing-toggler-view', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
|
||||
.andReturn({ status: 200 });
|
||||
|
||||
this.upgradeUrl = window.upgrade_url;
|
||||
window.upgrade_url = 'paco_upgrade';
|
||||
|
||||
this.userModel = getUserModelFixture();
|
||||
|
||||
this.createModel = new CreateModel({
|
||||
type: 'map',
|
||||
contentPane: 'listing',
|
||||
listing: 'import'
|
||||
}, {
|
||||
configModel: getConfigModelFixture(),
|
||||
userModel: this.userModel,
|
||||
userActions: {},
|
||||
pollingModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
this.guessingModel = new Backbone.Model({ guessing: true });
|
||||
this.view = new GuessingTogglerView({
|
||||
userModel: this.userModel,
|
||||
guessingModel: this.guessingModel,
|
||||
createModel: this.createModel,
|
||||
configModel: jasmine.createSpyObj('configModel', ['get'])
|
||||
});
|
||||
|
||||
spyOn(this.createModel, 'bind').and.callThrough();
|
||||
this.spyOnHasOwnTwitterCredentials = spyOn(this.userModel, 'hasOwnTwitterCredentials');
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.guessing-desc');
|
||||
expect(this.view.$('.js-toggle').length).toBe(1);
|
||||
expect(this.view.$('.js-toggle input').is(':checked')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when twitter import is active', function () {
|
||||
beforeEach(function () {
|
||||
this.createModel.set('activeImportPane', 'twitter');
|
||||
});
|
||||
|
||||
it('should not render guessing button', function () {
|
||||
expect(this.view.$el.text()).not.toContain('components.modals.add-layer.footer.guessing-desc');
|
||||
expect(this.view.$('button').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should display how to get historical data when user has his own credentials', function () {
|
||||
this.spyOnHasOwnTwitterCredentials.and.returnValue(true);
|
||||
this.view.render();
|
||||
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.twitter-how-to-historical');
|
||||
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.contact-team');
|
||||
});
|
||||
|
||||
it('should display a deprecated warning if user does not have his own credentials', function () {
|
||||
this.spyOnHasOwnTwitterCredentials.and.returnValue(false);
|
||||
this.view.render();
|
||||
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.deprecated-connector');
|
||||
expect(this.view.$el.text()).toContain('components.modals.add-layer.footer.twitter-contact-support');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not change type and content guessing attributes when button is clicked', function () {
|
||||
// Valid "upload"
|
||||
var uploadModel = this.createModel.getUploadModel();
|
||||
uploadModel.setUpload({
|
||||
type: 'url',
|
||||
value: 'https://carto.com'
|
||||
});
|
||||
expect(uploadModel.get('content_guessing')).toBeTruthy();
|
||||
expect(uploadModel.get('type_guessing')).toBeTruthy();
|
||||
expect(this.guessingModel.get('guessing')).toBeTruthy();
|
||||
this.view.$('.js-toggle').click();
|
||||
expect(this.guessingModel.get('guessing')).toBeFalsy();
|
||||
expect(uploadModel.get('content_guessing')).toBeTruthy();
|
||||
expect(uploadModel.get('type_guessing')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not change type and content guessing attributes when upload isn\'t valid', function () {
|
||||
// Non valid "upload"
|
||||
var uploadModel = this.createModel.getUploadModel();
|
||||
uploadModel.setUpload({
|
||||
type: 'url',
|
||||
value: 'hello'
|
||||
});
|
||||
this.view.$('.js-toggle').click();
|
||||
expect(this.guessingModel.get('guessing')).toBeFalsy();
|
||||
expect(uploadModel.get('content_guessing')).toBeTruthy();
|
||||
expect(uploadModel.get('type_guessing')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
var Backbone = require('backbone');
|
||||
var PrivacyTogglerView = require('builder/components/modals/add-layer/footer/privacy-toggler-view');
|
||||
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
|
||||
var getUserModelFixture = require('fixtures/builder/user-model.fixture.js');
|
||||
var getConfigModelFixture = require('fixtures/builder/config-model.fixture.js');
|
||||
|
||||
describe('components/modals/add-layer/footer/privacy-toggler-view', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
|
||||
.andReturn({ status: 200 });
|
||||
|
||||
this.upgradeUrl = window.upgrade_url;
|
||||
window.upgrade_url = 'paco_upgrade';
|
||||
|
||||
this.userModel = getUserModelFixture();
|
||||
var configModel = getConfigModelFixture();
|
||||
|
||||
this.model = new CreateModel({
|
||||
option: 'listing',
|
||||
listing: 'import'
|
||||
}, {
|
||||
configModel: configModel,
|
||||
userModel: this.userModel,
|
||||
userActions: {},
|
||||
pollingModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
this.privacyModel = new Backbone.Model({ privacy: 'PUBLIC' });
|
||||
this.view = new PrivacyTogglerView({
|
||||
userModel: this.userModel,
|
||||
privacyModel: this.privacyModel,
|
||||
createModel: this.model,
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
spyOn(this.model, 'bind').and.callThrough();
|
||||
this.spyOnHasOwnTwitterCredentials = spyOn(this.userModel, 'hasOwnTwitterCredentials');
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$('.PrivacyToggler').length).toBe(1);
|
||||
expect(this.view.$('.PrivacyToggler--PUBLIC').length).toBe(1);
|
||||
expect(this.view.$('.PrivacyToggler').hasClass('is-disabled')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should change privacy when it is clicked', function () {
|
||||
expect(this.privacyModel.get('privacy')).toBe('PUBLIC');
|
||||
expect(this.view.$('.PrivacyToggler--PUBLIC').length).toBe(1);
|
||||
this.view.$('.PrivacyToggler').click();
|
||||
expect(this.privacyModel.get('privacy')).toBe('PRIVATE');
|
||||
expect(this.view.$('.PrivacyToggler--PRIVATE').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should point to upgrade when user can\'t change privacy', function () {
|
||||
var actions = { private_tables: false };
|
||||
this.userModel.set('actions', actions);
|
||||
this.view.render();
|
||||
expect(this.view.$('a.PrivacyToggler').length).toBe(1);
|
||||
expect(this.view.$('a.PrivacyToggler').attr('href')).toBe('paco_upgrade');
|
||||
expect(this.view.$('.PrivacyToggler').hasClass('is-disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not point to upgrade if user can\'t change privacy and there is no upgrade url', function () {
|
||||
window.upgrade_url = '';
|
||||
var actions = { private_tables: false };
|
||||
this.userModel.set('actions', actions);
|
||||
this.view.render();
|
||||
expect(this.view.$('a.PrivacyToggler').length).toBe(0);
|
||||
expect(this.view.$('button.PrivacyToggler').length).toBe(1);
|
||||
expect(this.view.$('.PrivacyToggler').hasClass('is-disabled')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
describe('when twitter import is active', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('activeImportPane', 'twitter');
|
||||
});
|
||||
|
||||
it('should be displayed if user has his own credentials', function () {
|
||||
this.spyOnHasOwnTwitterCredentials.and.returnValue(true);
|
||||
this.view.render();
|
||||
expect(this.view.$('.PrivacyToggler').length).toBe(1);
|
||||
});
|
||||
|
||||
it('it should not be displayed if user does not have his own credentials', function () {
|
||||
this.spyOnHasOwnTwitterCredentials.and.returnValue(false);
|
||||
this.view.render();
|
||||
expect(this.view.$('.PrivacyToggler').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
window.upgrade_url = this.upgradeUrl;
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var ListingView = require('builder/components/modals/add-layer/content/listing-view');
|
||||
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
|
||||
describe('components/modals/add-layer/listing-view', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
|
||||
.andReturn({ status: 200 });
|
||||
|
||||
var configModel = jasmine.createSpyObj('configModel', ['get', 'urlVersion']);
|
||||
this.userModel = new UserModel({
|
||||
username: 'pepe',
|
||||
actions: {
|
||||
private_tables: true
|
||||
}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.createModel = new CreateModel({
|
||||
type: 'map',
|
||||
contentPane: 'listing',
|
||||
listing: 'import'
|
||||
}, {
|
||||
configModel: configModel,
|
||||
userModel: this.userModel,
|
||||
userActions: {},
|
||||
pollingModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
this.view = new ListingView({
|
||||
userModel: this.userModel,
|
||||
createModel: this.createModel,
|
||||
configModel: configModel,
|
||||
privacyModel: new Backbone.Model({
|
||||
privacy: 'PRIVATE'
|
||||
}),
|
||||
guessingModel: new Backbone.Model({
|
||||
guessing: true
|
||||
})
|
||||
});
|
||||
|
||||
spyOn(this.createModel._tablesCollection, 'fetch');
|
||||
spyOn(this.createModel, 'bind').and.callThrough();
|
||||
spyOn(this.createModel._visualizationFetchModel, 'bind').and.callThrough();
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should render correctly', function () {
|
||||
this.createModel.set('option', 'listing');
|
||||
expect(_.size(this.view._subviews)).toBe(1);
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,226 @@
|
||||
var Backbone = require('backbone');
|
||||
var CreateModel = require('builder/components/modals/add-layer/add-layer-model');
|
||||
var VisualizationsFetchModel = require('builder/data/visualizations-fetch-model');
|
||||
var TablesCollection = require('builder/data/tables-collection');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var NavigationView = require('builder/components/modals/add-layer/content/navigation-view');
|
||||
var _ = require('underscore');
|
||||
|
||||
describe('components/modals/add-layer/navigation-view', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
|
||||
.andReturn({ status: 200 });
|
||||
|
||||
this.configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.userModel = new UserModel({
|
||||
username: 'pepe',
|
||||
remaining_byte_quota: 10
|
||||
}, {
|
||||
configModel: this.configModel
|
||||
});
|
||||
|
||||
this.createModel = new CreateModel(
|
||||
{},
|
||||
{
|
||||
configModel: this.configModel,
|
||||
userModel: this.userModel,
|
||||
userActions: {},
|
||||
pollingModel: new Backbone.Model()
|
||||
}
|
||||
);
|
||||
|
||||
this.visFetchModel = new VisualizationsFetchModel({
|
||||
content_type: 'datasets'
|
||||
});
|
||||
|
||||
this.tablesCollection = new TablesCollection([], {
|
||||
configModel: this.configModel
|
||||
});
|
||||
|
||||
this.createView = function () {
|
||||
this.view = new NavigationView({
|
||||
configModel: this.configModel,
|
||||
userModel: this.userModel,
|
||||
routerModel: this.visFetchModel,
|
||||
createModel: this.createModel,
|
||||
tablesCollection: this.tablesCollection
|
||||
});
|
||||
};
|
||||
this.createView();
|
||||
|
||||
this.createModel.set('type', 'dataset');
|
||||
|
||||
spyOn(this.createModel, 'bind').and.callThrough();
|
||||
spyOn(this.visFetchModel, 'bind').and.callThrough();
|
||||
spyOn(this.tablesCollection, 'bind').and.callThrough();
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.Ajax.uninstall();
|
||||
this.view.remove();
|
||||
});
|
||||
|
||||
it('should render correctly', function () {
|
||||
expect(this.view.$('.Filters-searchLink').length).toBe(1);
|
||||
expect(this.view.$('.js-typeItem').length).toBe(3);
|
||||
});
|
||||
|
||||
// TBD: create dataset dialog still not implemented
|
||||
// it('should not render several links when create dialog type is dataset', function () {
|
||||
// this.createModel = new CreateDatasetModel({},
|
||||
// {js-typeItem
|
||||
// visMap: {},
|
||||
// configModel: this.configModel,
|
||||
// userModel: this.userModel
|
||||
// });
|
||||
// this.createView();
|
||||
// this.view.render();
|
||||
// expect(this.view.$('.Filters-searchLink').length).toBe(1);
|
||||
// expect(this.view.$('.Filters-typeLink').length).toBe(3);
|
||||
// });
|
||||
|
||||
describe('when data library is enabled', function () {
|
||||
describe('.render', function () {
|
||||
it('should render correctly', function () {
|
||||
spyOn(this.view._configModel, 'dataLibraryEnabled').and.returnValue(true);
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$('.js-typeItem').length).toBe(4);
|
||||
expect(this.innerHTML()).toContain('components.modals.add-layer.navigation.data-library');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.initBinds', function () {
|
||||
it('should render when listing state changes', function () {
|
||||
spyOn(this.view, 'render');
|
||||
this.view._initBinds();
|
||||
|
||||
this.createModel.trigger('change:listing');
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render when router model changes', function () {
|
||||
spyOn(this.view, 'render');
|
||||
this.view._initBinds();
|
||||
|
||||
this.visFetchModel.trigger('change');
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render when collection changes', function () {
|
||||
spyOn(this.view, 'render');
|
||||
this.view._initBinds();
|
||||
|
||||
this.tablesCollection.trigger('sync');
|
||||
expect(this.view.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call _onChangeIsSearchEnabled when model isSearchEnabled changes', function () {
|
||||
spyOn(this.view, '_onChangeIsSearchEnabled');
|
||||
this.view._initBinds();
|
||||
|
||||
this.view.model.trigger('change:isSearchEnabled');
|
||||
expect(this.view._onChangeIsSearchEnabled).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create from scratch when create empty button is clicked', function () {
|
||||
spyOn(this.createModel, 'createFromScratch');
|
||||
this.userModel.set('account_type', 'ACCOUNT');
|
||||
this.view.render();
|
||||
this.view.$('.js-create-empty').click();
|
||||
expect(this.createModel.createFromScratch).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disable connect-dataset option when user is out of bytes quota', function () {
|
||||
this.createModel.set('listing', 'datasets');
|
||||
this.userModel.set('remaining_byte_quota', 0);
|
||||
this.view.render();
|
||||
expect(this.view.$('.js-connect').hasClass('is-disabled')).toBeTruthy();
|
||||
this.view.$('.js-connect').click();
|
||||
expect(this.createModel.get('listing')).not.toBe('import');
|
||||
});
|
||||
|
||||
it('should disable connect-dataset option when user Individual and is out of datasets quota', function () {
|
||||
this.createModel.set('listing', 'datasets');
|
||||
this.userModel.set('account_type', 'Individual');
|
||||
this.userModel.set('table_quota', 40);
|
||||
this.userModel.set('table_count', 40);
|
||||
this.view.render();
|
||||
expect(this.view.$('.js-connect').hasClass('is-disabled')).toBeTruthy();
|
||||
this.view.$('.js-connect').click();
|
||||
expect(this.createModel.get('listing')).not.toBe('import');
|
||||
});
|
||||
|
||||
it('should disable create empty dataset option when user is out of bytes quota', function () {
|
||||
spyOn(this.createModel, 'createFromScratch');
|
||||
this.createModel.set('listing', 'datasets');
|
||||
this.userModel.set('remaining_byte_quota', 0);
|
||||
this.view.render();
|
||||
expect(this.view.$('.js-create-empty').hasClass('is-disabled')).toBeTruthy();
|
||||
this.view.$('.js-create-empty').click();
|
||||
expect(this.createModel.createFromScratch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disable create empty dataset option when user Individual and is out of datasets quota', function () {
|
||||
spyOn(this.createModel, 'createFromScratch');
|
||||
this.createModel.set('listing', 'datasets');
|
||||
this.userModel.set('account_type', 'Individual');
|
||||
this.userModel.set('table_quota', 40);
|
||||
this.userModel.set('table_count', 40);
|
||||
this.view.render();
|
||||
expect(this.view.$('.js-create-empty').hasClass('is-disabled')).toBeTruthy();
|
||||
this.view.$('.js-create-empty').click();
|
||||
expect(this.createModel.createFromScratch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should search starting for the first page', function () {
|
||||
this.visFetchModel.set('page', 2);
|
||||
this.view.$('.js-search-input').val('test');
|
||||
this.view.$('.js-search-form').submit();
|
||||
expect(this.visFetchModel.get('page')).toBe(1);
|
||||
});
|
||||
|
||||
it('should change router model and listing model when a link is clicked', function () {
|
||||
spyOn(this.view._configModel, 'dataLibraryEnabled').and.returnValue(true);
|
||||
this.view.render();
|
||||
var routerChanged = false;
|
||||
var stateChanged = false;
|
||||
|
||||
function resetFlags () {
|
||||
routerChanged = false;
|
||||
stateChanged = false;
|
||||
}
|
||||
|
||||
this.visFetchModel.bind('change', function (m, c) {
|
||||
if (!_.isEmpty(m.changed)) routerChanged = true;
|
||||
});
|
||||
this.createModel.bind('change', function (m, c) {
|
||||
if (!_.isEmpty(m.changed)) stateChanged = true;
|
||||
});
|
||||
|
||||
resetFlags();
|
||||
|
||||
this.view.$('.js-connect').click();
|
||||
expect(routerChanged).toBeFalsy();
|
||||
expect(stateChanged).toBeTruthy();
|
||||
|
||||
resetFlags();
|
||||
|
||||
this.view.$('.js-library').click();
|
||||
expect(routerChanged).toBeTruthy();
|
||||
expect(stateChanged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
var Backbone = require('backbone');
|
||||
|
||||
/**
|
||||
* Common test cases for a create listing view model.
|
||||
* Expected to be called in the context of the top-describe closure of an option model, e.g.:
|
||||
* describe('...', function() {
|
||||
* beforeEach(function() {
|
||||
* this.model = new Model({});
|
||||
* });
|
||||
* sharedForCreateListingViewModel.call(this);
|
||||
*/
|
||||
module.exports = function () {
|
||||
it('should have listing attr representing current listing view', function () {
|
||||
expect(this.model.get('listing')).toEqual(jasmine.any(String));
|
||||
expect(this.model.get('listing')).not.toEqual(''); // should have an initial value
|
||||
});
|
||||
|
||||
describe('.showLibrary', function () {
|
||||
it('should return a boolean for if data library should be loaded', function () {
|
||||
expect(this.model.showLibrary()).toEqual(jasmine.any(Boolean));
|
||||
});
|
||||
});
|
||||
|
||||
describe('.canSelect', function () {
|
||||
it('should return a boolean for if user can select an item (more)', function () {
|
||||
var datasetModel = new Backbone.Model();
|
||||
expect(this.model.canSelect(datasetModel)).toEqual(jasmine.any(Boolean));
|
||||
});
|
||||
});
|
||||
|
||||
describe('.showDatasets', function () {
|
||||
it('should return a boolean for whether to show datasets or not', function () {
|
||||
expect(this.model.showDatasets()).toEqual(jasmine.any(Boolean));
|
||||
});
|
||||
});
|
||||
};
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Common test cases for a import view model in a create listing.
|
||||
* Expected to be called in the context of the top-describe closure of an option model, e.g.:
|
||||
* describe('...', function() {
|
||||
* beforeEach(function() {
|
||||
* this.model = new Model({});
|
||||
* });
|
||||
* sharedForImportViewModel.call(this);
|
||||
*/
|
||||
module.exports = function () {
|
||||
describe('.setActiveImportPane', function () {
|
||||
it('should be a function to set which pane is currently active', function () {
|
||||
expect(this.model.setActiveImportPane).toEqual(jasmine.any(Function));
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,264 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var AnalysisDefinitionNodesCollection = require('builder/data/analysis-definition-nodes-collection');
|
||||
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||||
var AddWidgetsView = require('builder/components/modals/add-widgets/add-widgets-view');
|
||||
|
||||
describe('components/modals/add-widgets/add-widgets-view', function () {
|
||||
var LOADING_TITLE = 'loading-';
|
||||
var view;
|
||||
var configModel;
|
||||
var userModel;
|
||||
var analysisDefinitionNodesCollection;
|
||||
var layerDefinitionsCollection;
|
||||
var querySchemaModel0;
|
||||
var querySchemaModel1;
|
||||
var querySchemaModel2;
|
||||
var modalModel;
|
||||
|
||||
function createViewFn (options) {
|
||||
var defaultOptions;
|
||||
|
||||
configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
userModel = new UserModel({}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel
|
||||
});
|
||||
|
||||
layerDefinitionsCollection = new LayerDefinitionsCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel,
|
||||
analysisDefinitionNodesCollection: analysisDefinitionNodesCollection,
|
||||
mapId: 'map-123',
|
||||
stateDefinitionModel: {}
|
||||
});
|
||||
|
||||
analysisDefinitionNodesCollection.add({
|
||||
id: 'a0',
|
||||
type: 'source',
|
||||
query: 'SELECT * FROM table_name'
|
||||
});
|
||||
|
||||
analysisDefinitionNodesCollection.add({
|
||||
id: 'a1',
|
||||
type: 'buffer',
|
||||
radio: 300,
|
||||
source: 'a0'
|
||||
});
|
||||
|
||||
analysisDefinitionNodesCollection.add({
|
||||
id: 'a2',
|
||||
type: 'buffer',
|
||||
radio: 300,
|
||||
source: 'a1'
|
||||
});
|
||||
|
||||
querySchemaModel0 = analysisDefinitionNodesCollection.at(0).querySchemaModel;
|
||||
querySchemaModel1 = analysisDefinitionNodesCollection.at(1).querySchemaModel;
|
||||
querySchemaModel2 = analysisDefinitionNodesCollection.at(2).querySchemaModel;
|
||||
|
||||
querySchemaModel0.set({ status: 'fetched', query: 'SELECT * FROM table_name' });
|
||||
querySchemaModel1.set({ status: 'unavailable' });
|
||||
querySchemaModel2.set({ query: 'SELECT * FROM test' });
|
||||
querySchemaModel2.set({ status: 'fetching' });
|
||||
|
||||
spyOn(querySchemaModel0, 'fetch');
|
||||
spyOn(querySchemaModel1, 'fetch');
|
||||
spyOn(querySchemaModel2, 'fetch');
|
||||
|
||||
modalModel = new Backbone.Model();
|
||||
|
||||
defaultOptions = {
|
||||
modalModel: modalModel,
|
||||
userActions: {
|
||||
saveWidgetOption: function (widgetOptionModels) {
|
||||
return Promise.resolve(widgetOptionModels);
|
||||
},
|
||||
updateWidgetsOrder: function (widgetOptionModels) {
|
||||
return Promise.resolve(widgetOptionModels);
|
||||
},
|
||||
goToEditWidget: function () {}
|
||||
},
|
||||
analysisDefinitionNodesCollection: analysisDefinitionNodesCollection,
|
||||
layerDefinitionsCollection: layerDefinitionsCollection,
|
||||
widgetDefinitionsCollection: new Backbone.Collection()
|
||||
};
|
||||
|
||||
return new AddWidgetsView(_.extend(defaultOptions, options));
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
view = createViewFn();
|
||||
|
||||
view.render();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should show loading msg until all are fetched', function () {
|
||||
expect(view.$('.js-body').html()).toContain(LOADING_TITLE);
|
||||
});
|
||||
|
||||
describe('when all layer tables are fetched', function () {
|
||||
beforeEach(function () {
|
||||
querySchemaModel2.set('status', 'fetched');
|
||||
});
|
||||
|
||||
it('should render the content view', function () {
|
||||
expect(view.$('.js-body').html()).not.toContain(LOADING_TITLE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the user clicks on continue', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(view, '_hasFetchedAllQuerySchemas').and.returnValue(true);
|
||||
view.render();
|
||||
});
|
||||
|
||||
it('should call _saveSelectedWidgets if there are selected widgets', function () {
|
||||
var saveSelectedWidgetsSpy = spyOn(view, '_saveSelectedWidgets').and.callThrough();
|
||||
|
||||
view._optionsCollection.add(new Backbone.Model({
|
||||
id: '1',
|
||||
selected: true
|
||||
}));
|
||||
|
||||
view._onContinue();
|
||||
|
||||
expect(saveSelectedWidgetsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call _saveSelectedWidgets if there are not selected widgets', function () {
|
||||
var saveSelectedWidgetsSpy = spyOn(view, '_saveSelectedWidgets').and.returnValue(true);
|
||||
|
||||
view._optionsCollection.add(new Backbone.Model({
|
||||
id: '2',
|
||||
selected: false
|
||||
}));
|
||||
|
||||
view._onContinue();
|
||||
|
||||
expect(saveSelectedWidgetsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call user actions to update widgets if the _saveSelectedWidgets succeeds', function (done) {
|
||||
spyOn(view, '_saveSelectedWidgets').and.returnValue(Promise.resolve());
|
||||
spyOn(view._userActions, 'updateWidgetsOrder');
|
||||
spyOn(view._userActions, 'goToEditWidget');
|
||||
|
||||
view._optionsCollection.add(new Backbone.Model({
|
||||
id: '1',
|
||||
selected: true
|
||||
}));
|
||||
|
||||
view._onContinue();
|
||||
|
||||
setTimeout(function () {
|
||||
expect(view._userActions.updateWidgetsOrder).toHaveBeenCalled();
|
||||
expect(view._userActions.goToEditWidget).toHaveBeenCalled();
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('should call user actions to update widgets if the _saveSelectedWidgets fails', function (done) {
|
||||
spyOn(view, '_saveSelectedWidgets').and.returnValue(Promise.reject());
|
||||
spyOn(view._userActions, 'updateWidgetsOrder');
|
||||
spyOn(view._userActions, 'goToEditWidget');
|
||||
|
||||
view._optionsCollection.add(new Backbone.Model({
|
||||
id: '1',
|
||||
selected: true
|
||||
}));
|
||||
|
||||
view._onContinue();
|
||||
|
||||
setTimeout(function () {
|
||||
expect(view._userActions.updateWidgetsOrder).toHaveBeenCalled();
|
||||
expect(view._userActions.goToEditWidget).not.toHaveBeenCalled();
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the selected widgets are selected to be saved', function () {
|
||||
it('should call saveWidgetOption for each selectedOptionModel', function () {
|
||||
var saveWidgetOptionSpy = spyOn(view._userActions, 'saveWidgetOption').and.callThrough();
|
||||
|
||||
var widgetModel_1 = new Backbone.Model({
|
||||
id: '1',
|
||||
selected: true
|
||||
});
|
||||
|
||||
var widgetModel_2 = new Backbone.Model({
|
||||
id: '2',
|
||||
selected: true
|
||||
});
|
||||
|
||||
view._saveSelectedWidgets([widgetModel_1, widgetModel_2]);
|
||||
|
||||
expect(saveWidgetOptionSpy).toHaveBeenCalledWith(widgetModel_1);
|
||||
expect(saveWidgetOptionSpy).toHaveBeenCalledWith(widgetModel_2);
|
||||
});
|
||||
|
||||
it('should return an async response that succeeds if all the widgets can be saved', function (done) {
|
||||
var widgetModel_1 = new Backbone.Model({
|
||||
id: '1',
|
||||
selected: false
|
||||
});
|
||||
|
||||
var widgetModel_2 = new Backbone.Model({
|
||||
id: '2',
|
||||
selected: true
|
||||
});
|
||||
|
||||
view._saveSelectedWidgets([widgetModel_1, widgetModel_2])
|
||||
.then(function (response) {
|
||||
expect(response.length).toEqual(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an async response that fails if one of the widgets can not be saved', function (done) {
|
||||
var errorResponse = 'Error';
|
||||
|
||||
view = createViewFn({userActions: {
|
||||
saveWidgetOption: function () {
|
||||
return Promise.reject(errorResponse);
|
||||
},
|
||||
updateWidgetsOrder: function () {
|
||||
return Promise.resolve({});
|
||||
},
|
||||
goToEditWidget: function () {}
|
||||
}});
|
||||
|
||||
view.render();
|
||||
|
||||
var widgetModel_1 = new Backbone.Model({
|
||||
id: '1',
|
||||
selected: false
|
||||
});
|
||||
|
||||
var widgetModel_2 = new Backbone.Model({
|
||||
id: '2',
|
||||
selected: true
|
||||
});
|
||||
|
||||
view._saveSelectedWidgets([widgetModel_1, widgetModel_2])
|
||||
.catch(function (response) {
|
||||
expect(response).toEqual(errorResponse);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
var Backbone = require('backbone');
|
||||
var BodyView = require('builder/components/modals/add-widgets/body-view');
|
||||
var WidgetOptionModel = require('builder/components/modals/add-widgets/widget-option-model');
|
||||
var widgetsTypes = require('builder/components/modals/add-widgets/widgets-types');
|
||||
|
||||
describe('components/modals/add-widgets/body-view', function () {
|
||||
beforeEach(function () {
|
||||
var layerDefinitionModel = new Backbone.Model();
|
||||
layerDefinitionModel.getColor = function () { return '#fabada'; };
|
||||
layerDefinitionModel.getName = function () { return 'layer'; };
|
||||
layerDefinitionModel.getTableName = function () { return 'table_name'; };
|
||||
|
||||
var analysisDefinitionNodeModel = new Backbone.Model({
|
||||
id: 'a1'
|
||||
});
|
||||
analysisDefinitionNodeModel.isSourceType = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
var tuples = [{
|
||||
columnModel: new Backbone.Model(),
|
||||
analysisDefinitionNodeModel: analysisDefinitionNodeModel,
|
||||
layerDefinitionModel: layerDefinitionModel
|
||||
}];
|
||||
this.optionsCollection = new Backbone.Collection([
|
||||
new WidgetOptionModel({
|
||||
type: 'category',
|
||||
layer_index: 0,
|
||||
tuples: tuples
|
||||
}),
|
||||
new WidgetOptionModel({
|
||||
type: 'histogram',
|
||||
layer_index: 0,
|
||||
tuples: tuples
|
||||
}),
|
||||
new WidgetOptionModel({
|
||||
type: 'formula',
|
||||
layer_index: 0,
|
||||
tuples: tuples
|
||||
}),
|
||||
new WidgetOptionModel({
|
||||
type: 'time-series',
|
||||
layer_index: 0,
|
||||
tuples: tuples
|
||||
})
|
||||
]);
|
||||
|
||||
this.view = new BodyView({
|
||||
optionsCollection: this.optionsCollection,
|
||||
widgetsTypes: widgetsTypes
|
||||
});
|
||||
this.view = this.view.render();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render fine', function () {
|
||||
expect(this.view).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create tab pane items when there is at least one option of that type', function () {
|
||||
expect(this.view.$el.html()).toContain('formula');
|
||||
expect(this.view.$el.html()).toContain('category');
|
||||
expect(this.view.$el.html()).toContain('histogram');
|
||||
expect(this.view.$el.html()).toContain('time-series');
|
||||
});
|
||||
});
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var CategoryOptionModel = require('builder/components/modals/add-widgets/category/category-option-model');
|
||||
|
||||
describe('components/modals/add-widgets/category/category-option-model', function () {
|
||||
var model;
|
||||
var defaultOptions;
|
||||
var widgetDefinitionsCollection;
|
||||
var layerDefinitionModel;
|
||||
var analysisDefinitionNodeModel;
|
||||
var defaultTuples;
|
||||
var columnModel;
|
||||
|
||||
var createModelFn = function (options, optionsTuples) {
|
||||
widgetDefinitionsCollection = new Backbone.Collection({});
|
||||
|
||||
widgetDefinitionsCollection.addWidget = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
layerDefinitionModel = new Backbone.Model({
|
||||
id: 'layerDefinitionModel1',
|
||||
style: new Backbone.Model()
|
||||
});
|
||||
|
||||
columnModel = new Backbone.Model({
|
||||
name: 'line'
|
||||
});
|
||||
|
||||
analysisDefinitionNodeModel = new Backbone.Model({
|
||||
id: 'analysesDefinitionNodeModel1'
|
||||
});
|
||||
|
||||
defaultTuples = [{
|
||||
columnModel: columnModel,
|
||||
layerDefinitionModel: layerDefinitionModel,
|
||||
analysisDefinitionNodeModel: analysisDefinitionNodeModel
|
||||
}];
|
||||
|
||||
defaultOptions = {
|
||||
layer_index: '0',
|
||||
title: 'default-title',
|
||||
tuples: _.extend(defaultTuples, optionsTuples)
|
||||
};
|
||||
|
||||
return new CategoryOptionModel(_.extend(defaultOptions, options));
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
model = createModelFn();
|
||||
});
|
||||
|
||||
it('should have a "category" type by default', function () {
|
||||
expect(model.get('type')).toEqual('category');
|
||||
});
|
||||
|
||||
it('should return the result of the "addWidget" function from the given widgetDefinitionsCollection', function () {
|
||||
var addWidgetSpy = spyOn(widgetDefinitionsCollection, 'addWidget').and.returnValue(true);
|
||||
|
||||
model.save(widgetDefinitionsCollection);
|
||||
|
||||
expect(addWidgetSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
var _ = require('underscore');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var AnalysisDefinitionNodesCollection = require('builder/data/analysis-definition-nodes-collection');
|
||||
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||||
var createTuplesItems = require('builder/components/modals/add-widgets/create-tuples-items');
|
||||
|
||||
describe('components/modals/add-widgets/create-tuples-items', function () {
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
var userModel = new UserModel({}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection(null, {
|
||||
configModel: configModel,
|
||||
userModel: userModel
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection.add({
|
||||
id: 'a0',
|
||||
type: 'source',
|
||||
query: 'SELECT * FROM table_name'
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection.add({
|
||||
id: 'b0',
|
||||
type: 'source',
|
||||
query: 'SELECT * FROM table_name_two'
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection.add({
|
||||
id: 'a1',
|
||||
type: 'buffer',
|
||||
radio: 300,
|
||||
source: 'a0'
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection.add({
|
||||
id: 'b1',
|
||||
type: 'buffer',
|
||||
radio: 300,
|
||||
source: 'a1'
|
||||
});
|
||||
|
||||
this.analysisDefinitionNodesCollection.add({
|
||||
id: 'secondary_source', // created when selecting secondary nodes, so technically orphaned if not used later.
|
||||
type: 'source',
|
||||
query: 'SELECT * FROM secondary_source'
|
||||
});
|
||||
|
||||
this.layerDefinitionsCollection = new LayerDefinitionsCollection([
|
||||
{
|
||||
id: 'l0',
|
||||
kind: 'tiled'
|
||||
}, {
|
||||
id: 'l1',
|
||||
kind: 'carto',
|
||||
options: {
|
||||
table_name: 'foo_table'
|
||||
}
|
||||
}, {
|
||||
id: 'l2',
|
||||
kind: 'carto',
|
||||
options: {
|
||||
table_name: 'bar_table'
|
||||
}
|
||||
}
|
||||
], {
|
||||
configModel: configModel,
|
||||
userModel: userModel,
|
||||
analysisDefinitionNodesCollection: this.analysisDefinitionNodesCollection,
|
||||
mapId: 'm-123',
|
||||
stateDefinitionModel: {}
|
||||
});
|
||||
|
||||
var a1 = this.analysisDefinitionNodesCollection.get('a1');
|
||||
a1.querySchemaModel.columnsCollection.reset([
|
||||
{
|
||||
name: 'cartodb_id',
|
||||
type: 'number'
|
||||
}, {
|
||||
name: 'county_name',
|
||||
type: 'string'
|
||||
}, {
|
||||
name: 'the_geom',
|
||||
type: 'geom'
|
||||
}, {
|
||||
name: 'the_geom_webmercator',
|
||||
type: 'geom'
|
||||
}, {
|
||||
name: 'pop_count',
|
||||
type: 'number'
|
||||
}, {
|
||||
name: 'created_at',
|
||||
type: 'date'
|
||||
}, {
|
||||
name: 'updated_at',
|
||||
type: 'date'
|
||||
}
|
||||
]);
|
||||
|
||||
var b1 = this.analysisDefinitionNodesCollection.get('b1');
|
||||
b1.querySchemaModel.columnsCollection.reset([
|
||||
{
|
||||
name: 'cartodb_id',
|
||||
type: 'number'
|
||||
}, {
|
||||
name: 'pop_count',
|
||||
type: 'number'
|
||||
}
|
||||
]);
|
||||
|
||||
var secondary = this.analysisDefinitionNodesCollection.get('secondary_source');
|
||||
secondary.querySchemaModel.columnsCollection.reset([
|
||||
{
|
||||
name: 'only_for_secondary',
|
||||
type: 'number'
|
||||
}
|
||||
]);
|
||||
|
||||
a1.queryGeometryModel.isDone = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
a1.queryGeometryModel.set('simple_geom', true);
|
||||
|
||||
b1.queryGeometryModel.isDone = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
b1.queryGeometryModel.set('simple_geom', true);
|
||||
|
||||
this.tuplesItems = createTuplesItems(this.analysisDefinitionNodesCollection, this.layerDefinitionsCollection);
|
||||
});
|
||||
|
||||
it('should return an object', function () {
|
||||
expect(this.tuplesItems).toEqual(jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('should contain an item for each column name+type match', function () {
|
||||
expect(this.tuplesItems['county_name-string'].length).toEqual(1);
|
||||
expect(this.tuplesItems['pop_count-number'].length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should not add items for blacklisted columns', function () {
|
||||
var keys = _.keys(this.tuplesItems).toString();
|
||||
expect(keys).not.toContain('the_geom');
|
||||
expect(keys).not.toContain('the_geom_webmercator');
|
||||
expect(keys).not.toContain('created_at');
|
||||
expect(keys).not.toContain('updated_at');
|
||||
});
|
||||
|
||||
it('should not contain a tuple when no geometry data', function () {
|
||||
var b1 = this.analysisDefinitionNodesCollection.get('b1');
|
||||
|
||||
b1.queryGeometryModel.isDone = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
b1.queryGeometryModel.set('simple_geom', false);
|
||||
|
||||
this.tuplesItems = createTuplesItems(this.analysisDefinitionNodesCollection, this.layerDefinitionsCollection);
|
||||
|
||||
var tuples = this.tuplesItems['pop_count-number'];
|
||||
expect(tuples.length).toBe(1);
|
||||
expect(tuples[0].layerDefinitionModel.id).toEqual('l1');
|
||||
});
|
||||
|
||||
it('should contain a tuple of column+layer definition in each item', function () {
|
||||
var tuples = this.tuplesItems['pop_count-number'];
|
||||
|
||||
expect(tuples[0].columnModel).toBeDefined();
|
||||
expect(tuples[0].columnModel.get('name')).toEqual('pop_count');
|
||||
expect(tuples[0].layerDefinitionModel.id).toEqual('l1');
|
||||
|
||||
expect(tuples[1].columnModel).toBeDefined();
|
||||
expect(tuples[1].columnModel.get('name')).toEqual('pop_count');
|
||||
expect(tuples[1].layerDefinitionModel.id).toEqual('l2');
|
||||
});
|
||||
|
||||
it('should skip nodes that does not have an owning layer', function () {
|
||||
for (var columnName in this.tuplesItems) {
|
||||
var tuples = this.tuplesItems[columnName];
|
||||
tuples.forEach(function (tuple) {
|
||||
expect(tuple.columnModel).toBeDefined('a tuple for ' + columnName + ' is missing columnModel');
|
||||
expect(tuple.layerDefinitionModel).toBeDefined('a tuple for ' + columnName + ' is missing layerDefinitionModel');
|
||||
expect(tuple.analysisDefinitionNodeModel).toBeDefined('a tuple for ' + columnName + ' is missing analysisDefinitionModel');
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
});
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var FormulaOptionModel = require('builder/components/modals/add-widgets/formula/formula-option-model');
|
||||
|
||||
describe('components/modals/add-widgets/formula/formula-option-model', function () {
|
||||
var model;
|
||||
var defaultOptions;
|
||||
var widgetDefinitionsCollection;
|
||||
var layerDefinitionModel;
|
||||
var analysisDefinitionNodeModel;
|
||||
var defaultTuples;
|
||||
var columnModel;
|
||||
|
||||
var createModelFn = function (options, optionsTuples) {
|
||||
widgetDefinitionsCollection = new Backbone.Collection({});
|
||||
|
||||
widgetDefinitionsCollection.addWidget = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
layerDefinitionModel = new Backbone.Model({
|
||||
id: 'layerDefinitionModel1',
|
||||
style: new Backbone.Model()
|
||||
});
|
||||
|
||||
columnModel = new Backbone.Model({
|
||||
name: 'line'
|
||||
});
|
||||
|
||||
analysisDefinitionNodeModel = new Backbone.Model({
|
||||
id: 'analysesDefinitionNodeModel1'
|
||||
});
|
||||
|
||||
defaultTuples = [{
|
||||
columnModel: columnModel,
|
||||
layerDefinitionModel: layerDefinitionModel,
|
||||
analysisDefinitionNodeModel: analysisDefinitionNodeModel
|
||||
}];
|
||||
|
||||
defaultOptions = {
|
||||
layer_index: '0',
|
||||
title: 'default-title',
|
||||
tuples: _.extend(defaultTuples, optionsTuples)
|
||||
};
|
||||
|
||||
return new FormulaOptionModel(_.extend(defaultOptions, options));
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
model = createModelFn();
|
||||
});
|
||||
|
||||
it('should have a "formula" type by default', function () {
|
||||
expect(model.get('type')).toEqual('formula');
|
||||
});
|
||||
|
||||
it('should return the result of the "addWidget" function from the given widgetDefinitionsCollection', function () {
|
||||
var addWidgetSpy = spyOn(widgetDefinitionsCollection, 'addWidget').and.returnValue(true);
|
||||
|
||||
model.save(widgetDefinitionsCollection);
|
||||
|
||||
expect(addWidgetSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var HistogramOptionModel = require('builder/components/modals/add-widgets/histogram/histogram-option-model');
|
||||
|
||||
describe('components/modals/add-widgets/histogram/histogram-option-model', function () {
|
||||
var model;
|
||||
var defaultOptions;
|
||||
var widgetDefinitionsCollection;
|
||||
var layerDefinitionModel;
|
||||
var analysisDefinitionNodeModel;
|
||||
var defaultTuples;
|
||||
var columnModel;
|
||||
|
||||
var createModelFn = function (options, optionsTuples) {
|
||||
widgetDefinitionsCollection = new Backbone.Collection({});
|
||||
|
||||
widgetDefinitionsCollection.addWidget = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
layerDefinitionModel = new Backbone.Model({
|
||||
id: 'layerDefinitionModel1',
|
||||
style: new Backbone.Model()
|
||||
});
|
||||
|
||||
columnModel = new Backbone.Model({
|
||||
name: 'line'
|
||||
});
|
||||
|
||||
analysisDefinitionNodeModel = new Backbone.Model({
|
||||
id: 'analysesDefinitionNodeModel1'
|
||||
});
|
||||
|
||||
defaultTuples = [{
|
||||
columnModel: columnModel,
|
||||
layerDefinitionModel: layerDefinitionModel,
|
||||
analysisDefinitionNodeModel: analysisDefinitionNodeModel
|
||||
}];
|
||||
|
||||
defaultOptions = {
|
||||
layer_index: '0',
|
||||
title: 'default-title',
|
||||
tuples: _.extend(defaultTuples, optionsTuples)
|
||||
};
|
||||
|
||||
return new HistogramOptionModel(_.extend(defaultOptions, options));
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
model = createModelFn();
|
||||
});
|
||||
|
||||
it('should have a "histogram" type by default', function () {
|
||||
expect(model.get('type')).toEqual('histogram');
|
||||
});
|
||||
|
||||
it('should return the result of the "addWidget" function from the given widgetDefinitionsCollection', function () {
|
||||
var addWidgetSpy = spyOn(widgetDefinitionsCollection, 'addWidget').and.returnValue(true);
|
||||
|
||||
model.save(widgetDefinitionsCollection);
|
||||
|
||||
expect(addWidgetSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var LayerSelectorView = require('builder/components/modals/add-widgets/layer-selector-view');
|
||||
|
||||
describe('components/modals/add-widgets/layer-selector-view', function () {
|
||||
var $el;
|
||||
|
||||
beforeEach(function () {
|
||||
$el = $('<div class="js-WidgetList-item"></div>');
|
||||
|
||||
this.columnModel1 = new Backbone.Model({
|
||||
name: 'col',
|
||||
type: 'string'
|
||||
});
|
||||
this.analysisDefinitionModel1 = new Backbone.Model({ id: 'a1' });
|
||||
this.analysisDefinitionModel2 = new Backbone.Model({ id: 'a2' });
|
||||
this.analysisDefinitionModel1.isSourceType = this.analysisDefinitionModel2.isSourceType = function () {
|
||||
return true;
|
||||
};
|
||||
this.layerDefinitionModel1 = new Backbone.Model({
|
||||
table_name: 'foo'
|
||||
});
|
||||
this.columnModel2 = new Backbone.Model({
|
||||
name: 'col',
|
||||
type: 'string'
|
||||
});
|
||||
this.layerDefinitionModel2 = new Backbone.Model({
|
||||
table_name: 'bar'
|
||||
});
|
||||
this.layerDefinitionModel1.getColor = this.layerDefinitionModel2.getColor = function () {
|
||||
return '#fabada';
|
||||
};
|
||||
this.layerDefinitionModel1.getName = this.layerDefinitionModel2.getName = function () {
|
||||
return this.get('table_name');
|
||||
};
|
||||
this.layerDefinitionModel1.getTableName = this.layerDefinitionModel2.getTableName = function () {
|
||||
return this.get('table_name');
|
||||
};
|
||||
|
||||
this.model = new Backbone.Model({
|
||||
layer_index: 0,
|
||||
tuples: [{
|
||||
columnModel: this.columnModel1,
|
||||
layerDefinitionModel: this.layerDefinitionModel1,
|
||||
analysisDefinitionNodeModel: this.analysisDefinitionModel1
|
||||
}, {
|
||||
columnModel: this.columnModel2,
|
||||
layerDefinitionModel: this.layerDefinitionModel2,
|
||||
analysisDefinitionNodeModel: this.analysisDefinitionModel2
|
||||
}]
|
||||
});
|
||||
|
||||
this.view = new LayerSelectorView({
|
||||
model: this.model
|
||||
});
|
||||
this.view = this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
$el.remove();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render table name and node id in the selected item', function () {
|
||||
expect(this.view).toBeDefined();
|
||||
expect(this.view.$el.html()).toContain('foo');
|
||||
expect(this.view.$el.html()).toContain('a1');
|
||||
});
|
||||
|
||||
it('should render table name and node id in the custom list items', function () {
|
||||
this.view._selectView._onButtonClick();
|
||||
var customList = this.view.$('.js-list').html();
|
||||
|
||||
expect(customList).toContain('foo');
|
||||
expect(customList).toContain('a1');
|
||||
expect(customList).toContain('bar');
|
||||
expect(customList).toContain('a2');
|
||||
});
|
||||
|
||||
it('should change the selected item', function () {
|
||||
expect(this.model.get('layer_index')).toEqual(0);
|
||||
});
|
||||
|
||||
it('should stop event propagation when element is clicked', function () {
|
||||
var eventMock = {
|
||||
stopPropagation: jasmine.createSpy()
|
||||
};
|
||||
|
||||
this.view._onClick(eventMock);
|
||||
|
||||
expect(eventMock.stopPropagation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when a new option is selected', function () {
|
||||
beforeEach(function () {
|
||||
this.view._selectView.setValue(1);
|
||||
this.view._selectView.trigger('change');
|
||||
});
|
||||
|
||||
it('should change the selected item', function () {
|
||||
expect(this.model.get('layer_index')).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._onMouseOver', function () {
|
||||
it('should set highlighted to true', function () {
|
||||
expect(this.view._stateModel.get('highlighted')).toBe(false);
|
||||
|
||||
this.view._onMouseOver();
|
||||
|
||||
expect(this.view._stateModel.get('highlighted')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._onMouseOut', function () {
|
||||
it('should set highlighted to false', function () {
|
||||
this.view._stateModel.set({ highlighted: true }, { silent: true });
|
||||
|
||||
this.view._onMouseOut();
|
||||
|
||||
expect(this.view._stateModel.get('highlighted')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._toggleHover', function () {
|
||||
it('should toggle highlighted', function () {
|
||||
$el.append(this.view.el);
|
||||
|
||||
this.view._stateModel.set('highlighted', true, { silent: true });
|
||||
this.view._toggleHover();
|
||||
|
||||
expect($el.hasClass('is-hover')).toBe(true);
|
||||
|
||||
this.view._stateModel.set('highlighted', false, { silent: true });
|
||||
this.view._toggleHover();
|
||||
|
||||
expect($el.hasClass('is-hover')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var TimeSeriesOptionModel = require('builder/components/modals/add-widgets/time-series/time-series-option-model');
|
||||
|
||||
describe('components/modals/add-widgets/time-series/time-series-option-model', function () {
|
||||
var model;
|
||||
var defaultOptions;
|
||||
var widgetDefinitionsCollection;
|
||||
var layerDefinitionModel;
|
||||
var analysisDefinitionNodeModel;
|
||||
var defaultTuples;
|
||||
var columnModel;
|
||||
|
||||
var createModelFn = function (options, optionsTuples) {
|
||||
widgetDefinitionsCollection = new Backbone.Collection({});
|
||||
|
||||
widgetDefinitionsCollection.addWidget = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
layerDefinitionModel = new Backbone.Model({
|
||||
id: 'layerDefinitionModel1',
|
||||
style: new Backbone.Model()
|
||||
});
|
||||
|
||||
columnModel = new Backbone.Model({
|
||||
name: 'line'
|
||||
});
|
||||
|
||||
analysisDefinitionNodeModel = new Backbone.Model({
|
||||
id: 'analysesDefinitionNodeModel1'
|
||||
});
|
||||
|
||||
defaultTuples = [{
|
||||
columnModel: columnModel,
|
||||
layerDefinitionModel: layerDefinitionModel,
|
||||
analysisDefinitionNodeModel: analysisDefinitionNodeModel
|
||||
}];
|
||||
|
||||
defaultOptions = {
|
||||
layer_index: '0',
|
||||
title: 'default-title',
|
||||
tuples: _.extend(defaultTuples, optionsTuples)
|
||||
};
|
||||
|
||||
return new TimeSeriesOptionModel(_.extend(defaultOptions, options));
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
model = createModelFn();
|
||||
});
|
||||
|
||||
it('should have a "time-series" type by default', function () {
|
||||
expect(model.get('type')).toEqual('time-series');
|
||||
});
|
||||
|
||||
it('should return the result of the "addWidget" function from the given widgetDefinitionsCollection', function () {
|
||||
var addWidgetSpy = spyOn(widgetDefinitionsCollection, 'addWidget').and.returnValue(true);
|
||||
|
||||
model.save(widgetDefinitionsCollection);
|
||||
|
||||
expect(addWidgetSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var widgetsTypes = require('builder/components/modals/add-widgets/widgets-types');
|
||||
var TimeSeriesNoneOptionModel = require('builder/components/modals/add-widgets/time-series/time-series-none-option-model');
|
||||
|
||||
describe('components/modals/add-widgets/widgets-types', function () {
|
||||
describe('all items', function () {
|
||||
it('should have a type prop', function () {
|
||||
widgetsTypes.forEach(function (d) {
|
||||
expect(d.type).toMatch(/\w+/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have a createTabPaneItem method', function () {
|
||||
widgetsTypes.forEach(function (d) {
|
||||
expect(d.createTabPaneItem).toEqual(jasmine.any(Function));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('times-series', function () {
|
||||
beforeEach(function () {
|
||||
this.d = _.find(widgetsTypes, function (d) {
|
||||
return d.type === 'time-series';
|
||||
});
|
||||
});
|
||||
|
||||
describe('.createOptionModels', function () {
|
||||
it('should always create a none-option even if there are no tuples items', function () {
|
||||
var widgetDefinitionsCollection = new Backbone.Collection();
|
||||
var models = this.d.createOptionModels([], widgetDefinitionsCollection);
|
||||
expect(models.length).toEqual(1);
|
||||
expect(models[0]).toEqual(jasmine.any(TimeSeriesNoneOptionModel));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
var Backbone = require('backbone');
|
||||
var DatasetMetadataView = require('builder/components/modals/dataset-metadata/dataset-metadata-view');
|
||||
|
||||
describe('components/modals/dataset-metadata/dataset-metadata-view', function () {
|
||||
beforeEach(function () {
|
||||
this.view = new DatasetMetadataView({
|
||||
modalModel: new Backbone.Model(),
|
||||
configModel: new Backbone.Model(),
|
||||
visDefinitionModel: new Backbone.Model(),
|
||||
isLocked: false
|
||||
});
|
||||
});
|
||||
|
||||
it('._getMetadataName sanitizes input', function () {
|
||||
this.view._visMetadataModel.set('name', "><script>alert('yep');</script>");
|
||||
|
||||
var name = this.view._getMetadataName();
|
||||
|
||||
expect(name).toEqual('>');
|
||||
});
|
||||
|
||||
it('._getMetadataDescription sanitizes input', function () {
|
||||
this.view._visMetadataModel.set('description', "<img src='http://emojipedia-us.s3.amazonaws.com/cache/b8/b4/b8b4e86a110557e6b6d666c9cf6d6cc8.png' />");
|
||||
|
||||
var name = this.view._getMetadataDescription();
|
||||
|
||||
expect(name).toEqual('<img>');
|
||||
});
|
||||
|
||||
it('._getMetadataTags sanitizes input', function () {
|
||||
this.view._visMetadataModel.set('tags', [
|
||||
"<img src='http://emojipedia-us.s3.amazonaws.com/cache/b8/b4/b8b4e86a110557e6b6d666c9cf6d6cc8.png' />",
|
||||
"><script>alert('yep');</script>"
|
||||
]);
|
||||
|
||||
var tags = this.view._getMetadataTags();
|
||||
|
||||
expect(tags.length).toBe(2);
|
||||
expect(tags[0]).toEqual('<img>');
|
||||
expect(tags[1]).toEqual('>');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
var Backbone = require('backbone');
|
||||
var FormView = require('builder/components/modals/dataset-metadata/form/form-view');
|
||||
|
||||
describe('components/modals/dataset-metadata/form-view', function () {
|
||||
beforeEach(function () {
|
||||
this.view = new FormView({
|
||||
visDefinitionModel: new Backbone.Model(),
|
||||
visMetadataModel: new Backbone.Model(),
|
||||
configModel: new Backbone.Model(),
|
||||
isLocked: false
|
||||
});
|
||||
this.view.model = {};
|
||||
});
|
||||
|
||||
it('._commitView should call _sanitizeName', function () {
|
||||
spyOn(this.view, '_sanitizeName');
|
||||
var name = 'something';
|
||||
var view = {
|
||||
model: {
|
||||
changed: {name: name},
|
||||
get: function () {
|
||||
return name;
|
||||
}
|
||||
},
|
||||
commit: function () {}
|
||||
};
|
||||
|
||||
this.view._commitView(view);
|
||||
|
||||
expect(this.view._sanitizeName).toHaveBeenCalledWith(name);
|
||||
});
|
||||
|
||||
it('._sanitizeName should sanitize input and set metadata model name', function () {
|
||||
this.view._sanitizeName('<script>');
|
||||
expect(this.view._visMetadataModel.get('name')).toEqual('');
|
||||
|
||||
this.view._sanitizeName('something');
|
||||
expect(this.view._visMetadataModel.get('name')).toEqual('something');
|
||||
|
||||
this.view._sanitizeName(null);
|
||||
expect(this.view._visMetadataModel.get('name')).toEqual('');
|
||||
});
|
||||
});
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var EditorVisualizationWarningView = require('builder/components/modals/editor-visualization-warning/editor-visualization-warning-view');
|
||||
|
||||
describe('builder/components/modals/editor-visualization-warning', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/viz\?.*'))
|
||||
.andReturn({ status: 200 });
|
||||
|
||||
var visDefinitionModel = new VisDefinitionModel({
|
||||
id: '1234567890',
|
||||
name: 'Foo Map',
|
||||
type: 'derived'
|
||||
}, {
|
||||
configModel: new ConfigModel({
|
||||
base_url: '/u/marieta'
|
||||
})
|
||||
});
|
||||
|
||||
var modalModel = new Backbone.Model();
|
||||
|
||||
spyOn(EditorVisualizationWarningView.prototype, '_goToDashboard');
|
||||
|
||||
this.view = new EditorVisualizationWarningView({
|
||||
modalModel: modalModel,
|
||||
visDefinitionModel: visDefinitionModel
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render template', function () {
|
||||
expect(this.view.$el.html()).toContain('Modal-inner');
|
||||
});
|
||||
|
||||
describe('_onOpen', function () {
|
||||
it('should call _onOpen when .js-open is clicked', function () {
|
||||
spyOn(this.view, '_renderLoading');
|
||||
this.view.$('.js-open').click();
|
||||
expect(this.view._renderLoading).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should destroy modalModel if the map version update succeeds', function () {
|
||||
spyOn(this.view._modalModel, 'destroy');
|
||||
this.view._visDefinitionModel.save = function (a, opts) {
|
||||
opts.success();
|
||||
};
|
||||
this.view.$('.js-open').click();
|
||||
expect(this.view._modalModel.destroy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call _renderError if the map version update fails', function () {
|
||||
spyOn(this.view, '_renderError');
|
||||
this.view._visDefinitionModel.save = function (a, opts) {
|
||||
var e = {
|
||||
readyState: 4,
|
||||
responseText: '',
|
||||
status: 405,
|
||||
statusText: 'Method Not Allowed'
|
||||
};
|
||||
|
||||
opts.error({model: 'lorem ipsum'}, e);
|
||||
};
|
||||
this.view.$('.js-open').click();
|
||||
expect(this.view._renderError).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('_onDuplicate', function () {
|
||||
it('should call _onDuplicate when .js-duplicate is clicked', function () {
|
||||
spyOn(this.view, '_renderLoading').and.callFake(function () {
|
||||
return true;
|
||||
});
|
||||
this.view.$('.js-duplicate').click();
|
||||
expect(this.view._renderLoading).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should redirect to the duplicated map builder view if duplication succeeds', function () {
|
||||
var newVisModel = new VisDefinitionModel({
|
||||
id: '111',
|
||||
name: 'table_1',
|
||||
privacy: 'PUBLIC',
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: this.view._visDefinitionModel._configModel
|
||||
});
|
||||
|
||||
VisDefinitionModel.prototype.save = function (a, opts) {
|
||||
opts.success(newVisModel);
|
||||
};
|
||||
|
||||
spyOn(this.view, '_redirectToBuilder');
|
||||
|
||||
this.view.$('.js-duplicate').click();
|
||||
expect(this.view._redirectToBuilder).toHaveBeenCalledWith('/u/marieta/builder/111/');
|
||||
});
|
||||
|
||||
it('should call _renderError if the map version update fails', function () {
|
||||
spyOn(this.view, '_renderError');
|
||||
VisDefinitionModel.prototype.save = function (a, opts) {
|
||||
var e = {
|
||||
readyState: 4,
|
||||
responseText: '',
|
||||
status: 405,
|
||||
statusText: 'Method Not Allowed'
|
||||
};
|
||||
|
||||
opts.error({model: 'lorem ipsum'}, e);
|
||||
};
|
||||
|
||||
this.view.$('.js-duplicate').click();
|
||||
expect(this.view._renderError).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('_onCancel', function () {
|
||||
it('should call _onCancel when .js-cancel is clicked', function () {
|
||||
this.view.$('.js-cancel').click();
|
||||
expect(EditorVisualizationWarningView.prototype._goToDashboard).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var ExportView = require('builder/components/modals/export-data/modal-export-data-view');
|
||||
var MetricsTracker = require('builder/components/metrics/metrics-tracker');
|
||||
var MetricsTypes = require('builder/components/metrics/metrics-types');
|
||||
|
||||
describe('components/modals/export-data/modal-export-data-view', function () {
|
||||
beforeEach(function () {
|
||||
this.configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
this.queryGeometryModel = new Backbone.Model({
|
||||
status: 'fetched',
|
||||
simple_geom: 'point',
|
||||
query: 'select * from wadus'
|
||||
});
|
||||
|
||||
this.querySchemaModel = new Backbone.Model({
|
||||
query: 'select * from wadus'
|
||||
});
|
||||
|
||||
spyOn(ExportView.prototype, 'submit');
|
||||
|
||||
MetricsTracker.init({
|
||||
userId: 'USER_ID',
|
||||
visId: 'VIS_ID',
|
||||
configModel: new Backbone.Model()
|
||||
});
|
||||
spyOn(MetricsTracker, 'track');
|
||||
|
||||
this.modalModel = new Backbone.Model();
|
||||
this.view = new ExportView({
|
||||
configModel: this.configModel,
|
||||
queryGeometryModel: this.queryGeometryModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
canHideColumns: false,
|
||||
modalModel: this.modalModel,
|
||||
fromView: 'layer'
|
||||
});
|
||||
spyOn(this.view, 'fetchCSV').and.callThrough();
|
||||
spyOn(this.view, '_fetchGET');
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
it('should render properly for points', function () {
|
||||
expect(this.view.$('.Modal-listFormItem').length).toBe(6);
|
||||
expect(this.view.$('.Modal-listFormItem.is-disabled').length).toBe(0);
|
||||
expect(this.view.$('[data-format=csv]:checked').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render properly for lines', function () {
|
||||
this.queryGeometryModel.set('simple_geom', 'line');
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$('.Modal-listFormItem').length).toBe(6);
|
||||
expect(this.view.$('.Modal-listFormItem.is-disabled').length).toBe(0);
|
||||
expect(this.view.$('[data-format=csv]:checked').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render properly for polygons', function () {
|
||||
this.queryGeometryModel.set('simple_geom', 'polygon');
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$('.Modal-listFormItem').length).toBe(6);
|
||||
expect(this.view.$('.Modal-listFormItem.is-disabled').length).toBe(0);
|
||||
expect(this.view.$('[data-format=csv]:checked').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render properly for no geometries', function () {
|
||||
this.queryGeometryModel.set('simple_geom', null);
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$('.Modal-listFormItem').length).toBe(6);
|
||||
expect(this.view.$('.Modal-listFormItem.is-disabled').length).toBe(5);
|
||||
expect(this.view.$('[data-format=csv]:disabled').length).toBe(0);
|
||||
expect(this.view.$('[data-format=csv]:checked').length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions', function () {
|
||||
describe('confirm', function () {
|
||||
it('should track a metric if optional layerModel is present', function () {
|
||||
var layerModel = new Backbone.Model({
|
||||
id: 'wadus',
|
||||
source: 'd0',
|
||||
visible: true,
|
||||
table_name: 'wadus',
|
||||
visualization_id: 'wadus',
|
||||
user_id: 'wadus'
|
||||
});
|
||||
layerModel.getName = jasmine.createSpy('getName');
|
||||
|
||||
// Create a new view with (optional) layerModel
|
||||
var view = new ExportView({
|
||||
layerModel: layerModel,
|
||||
configModel: this.configModel,
|
||||
queryGeometryModel: this.queryGeometryModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
canHideColumns: false,
|
||||
modalModel: {},
|
||||
fromView: 'layer'
|
||||
});
|
||||
spyOn(view, 'fetchCSV');
|
||||
view.render();
|
||||
view.$('.js-confirm').trigger('click');
|
||||
|
||||
expect(MetricsTracker.track).toHaveBeenCalledWith(MetricsTypes.DOWNLOADED_LAYER, {
|
||||
'from_view': 'layer',
|
||||
'format': 'csv',
|
||||
'layer_id': 'wadus',
|
||||
'source': 'd0',
|
||||
'visible': true,
|
||||
'table_name': 'wadus'
|
||||
});
|
||||
expect(view.fetchCSV).toHaveBeenCalled();
|
||||
view.clean();
|
||||
});
|
||||
|
||||
it('should NOT track a metric if layerModel is NOT present', function () {
|
||||
this.view.$('.js-confirm').trigger('click');
|
||||
|
||||
expect(MetricsTracker.track).not.toHaveBeenCalled();
|
||||
expect(this.view.fetchCSV).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fetch the file', function () {
|
||||
this.view.$('.js-confirm').trigger('click');
|
||||
|
||||
expect(this.view.fetchCSV).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should always drop the_geom_webmercator', function () {
|
||||
this.view.$('.js-confirm').trigger('click');
|
||||
expect(this.view.$('.js-skipfields').val()).toContain('the_geom_webmercator');
|
||||
});
|
||||
|
||||
it('should not drop the_geom for CSV files', function () {
|
||||
this.view.$('.js-confirm').trigger('click');
|
||||
expect(this.view.$('.js-skipfields').val()).toBe('the_geom_webmercator');
|
||||
});
|
||||
|
||||
it('should drop the_geom for files that are not CSV', function () {
|
||||
this.view.$('.js-format[data-format="csv"]').attr('checked', null);
|
||||
this.view.$('.js-format[data-format="gpkg"]').attr('checked', true);
|
||||
this.view.$('.js-confirm').trigger('click');
|
||||
expect(this.view.$('.js-skipfields').val()).toContain('the_geom_webmercator,the_geom');
|
||||
});
|
||||
|
||||
describe('if the view can hide columns', function () {
|
||||
beforeEach(function () {
|
||||
this.querySchemaModel.getColumnNames = function () { return ['center']; };
|
||||
this.view = new ExportView({
|
||||
configModel: this.configModel,
|
||||
queryGeometryModel: this.queryGeometryModel,
|
||||
querySchemaModel: this.querySchemaModel,
|
||||
canHideColumns: true,
|
||||
modalModel: {},
|
||||
fromView: 'layer'
|
||||
});
|
||||
spyOn(this.view, '_fetchGET');
|
||||
spyOn(this.view, '_close');
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
|
||||
it('should not drop center columns if it is not geometry', function () {
|
||||
this.querySchemaModel.getColumnType = function () { return 'wadus'; };
|
||||
this.view.$('.js-confirm').trigger('click');
|
||||
expect(this.view.$('.js-skipfields').val()).not.toContain('center');
|
||||
});
|
||||
|
||||
it('should drop center column if it is geometry-typed', function () {
|
||||
this.querySchemaModel.getColumnType = function () { return 'geometry'; };
|
||||
this.view.$('.js-confirm').trigger('click');
|
||||
expect(this.view.$('.js-skipfields').val()).toContain('center');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancel', function () {
|
||||
it('should destroy the model', function () {
|
||||
spyOn(this.modalModel, 'destroy');
|
||||
|
||||
this.view.$('.js-cancel').trigger('click');
|
||||
|
||||
expect(this.modalModel.destroy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
var Backbone = require('backbone');
|
||||
var FormView = require('builder/components/modals/map-metadata/form/form-view');
|
||||
|
||||
describe('components/modals/map-metadata/form-view', function () {
|
||||
beforeEach(function () {
|
||||
this.view = new FormView({
|
||||
visDefinitionModel: new Backbone.Model(),
|
||||
visMetadataModel: new Backbone.Model()
|
||||
});
|
||||
this.view.model = {};
|
||||
});
|
||||
|
||||
it('._commitView should call _sanitizeName', function () {
|
||||
spyOn(this.view, '_sanitizeName');
|
||||
var name = 'something';
|
||||
var view = {
|
||||
model: {
|
||||
changed: {name: name},
|
||||
get: function () {
|
||||
return name;
|
||||
}
|
||||
},
|
||||
commit: function () {}
|
||||
};
|
||||
|
||||
this.view._commitView(view);
|
||||
|
||||
expect(this.view._sanitizeName).toHaveBeenCalledWith(name);
|
||||
});
|
||||
|
||||
it('._sanitizeName should sanitize input and set metadata model name', function () {
|
||||
this.view._sanitizeName('<script>');
|
||||
expect(this.view._visMetadataModel.get('name')).toEqual('');
|
||||
|
||||
this.view._sanitizeName('something');
|
||||
expect(this.view._visMetadataModel.get('name')).toEqual('something');
|
||||
|
||||
this.view._sanitizeName(null);
|
||||
expect(this.view._visMetadataModel.get('name')).toEqual('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
var Backbone = require('backbone');
|
||||
var MetadataView = require('builder/components/modals/map-metadata/map-metadata-view');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
|
||||
describe('components/modals/map-metadata/map-metadata-view', function () {
|
||||
var view;
|
||||
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
var visDefinitionModel = new VisDefinitionModel({
|
||||
name: 'Foo Map',
|
||||
privacy: 'LINK',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
tags: ['foo', 'bar'],
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
view = new MetadataView({
|
||||
modalModel: new Backbone.Model(),
|
||||
visDefinitionModel: visDefinitionModel
|
||||
});
|
||||
|
||||
view.render();
|
||||
view.$el.appendTo(document.body);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
var parent = view.el.parentNode;
|
||||
parent && parent.removeChild(view.el);
|
||||
view.clean();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(view.$('.Metadata-form').length).toBe(1);
|
||||
expect(view.$('.js-name-field input').length).toBe(1);
|
||||
expect(view.$('.js-name-field input').val()).toBe('Foo Map');
|
||||
expect(view.$('.js-description-field textarea').length).toBe(1);
|
||||
expect(view.$('.js-tags-field .Form-tagsList').length).toBe(1);
|
||||
expect(view.$('.tagit-label').length).toBe(2);
|
||||
expect(view.$('.tagit-label').eq(0).text()).toBe('foo');
|
||||
expect(view.$('.tagit-label').eq(1).text()).toBe('bar');
|
||||
});
|
||||
|
||||
it('should render error', function () {
|
||||
view._stateModel.set({status: 'error'});
|
||||
expect(view.$('.u-errorTextColor').length).toBe(1);
|
||||
expect(view.$('input[type=password]').length).toBe(0);
|
||||
expect(view.$('.Tag').length).toBe(0);
|
||||
expect(view.$('.Modal-actions-button').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render loading', function () {
|
||||
view._stateModel.set({status: 'loading'});
|
||||
expect(view.$('.Modal-actions-button').length).toBe(0);
|
||||
expect(view.$('input[type=password]').length).toBe(0);
|
||||
expect(view.$('.js-loader').length).toBe(1);
|
||||
});
|
||||
|
||||
it('._getMetadataName sanitizes input', function () {
|
||||
view._visMetadataModel.set('name', "><script>alert('yep');</script>");
|
||||
|
||||
var name = view._getMetadataName();
|
||||
|
||||
expect(name).toEqual('>');
|
||||
});
|
||||
|
||||
it('._getMetadataDescription sanitizes input', function () {
|
||||
view._visMetadataModel.set('description', "<img src='http://emojipedia-us.s3.amazonaws.com/cache/b8/b4/b8b4e86a110557e6b6d666c9cf6d6cc8.png' />");
|
||||
|
||||
var name = view._getMetadataDescription();
|
||||
|
||||
expect(name).toEqual('<img>');
|
||||
});
|
||||
|
||||
it('._getMetadataTags sanitizes input', function () {
|
||||
view._visMetadataModel.set('tags', [
|
||||
"<img src='http://emojipedia-us.s3.amazonaws.com/cache/b8/b4/b8b4e86a110557e6b6d666c9cf6d6cc8.png' />",
|
||||
"><script>alert('yep');</script>"
|
||||
]);
|
||||
|
||||
var tags = view._getMetadataTags();
|
||||
|
||||
expect(tags.length).toBe(2);
|
||||
expect(tags[0]).toEqual('<img>');
|
||||
expect(tags[1]).toEqual('>');
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var saveMetadataMap = require('builder/components/modals/map-metadata/save-metadata-map');
|
||||
|
||||
describe('components/modals/map-metadata/save-metadata-map', function () {
|
||||
var visDefinitionModel;
|
||||
var successSaveSpy;
|
||||
var errorSaveSpy;
|
||||
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
visDefinitionModel = new VisDefinitionModel({
|
||||
name: 'Foo Map',
|
||||
privacy: 'LINK',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
tags: ['foo', 'bar'],
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
successSaveSpy = jasmine.createSpy('successSave');
|
||||
errorSaveSpy = jasmine.createSpy('erroSave');
|
||||
spyOn(visDefinitionModel, 'save');
|
||||
});
|
||||
|
||||
it('should rename document title and the suffix should contain | CARTO', function () {
|
||||
saveMetadataMap({
|
||||
onSuccess: successSaveSpy,
|
||||
onError: errorSaveSpy,
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
name: 'FOO',
|
||||
description: 'Wadus',
|
||||
tags: ['foo', 'bar']
|
||||
});
|
||||
|
||||
expect(visDefinitionModel.save).toHaveBeenCalled();
|
||||
visDefinitionModel.save.calls.argsFor(0)[1].success();
|
||||
|
||||
expect(successSaveSpy).toHaveBeenCalled();
|
||||
expect(document.title).not.toMatch(/CartoDB/);
|
||||
expect(document.title).toBe('FOO | 快点');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
var $ = require('jquery');
|
||||
var ModalConfirmationView = require('builder/components/modals/confirmation/modal-confirmation-view');
|
||||
var templateExample = require('builder/components/table/head/modals-templates/rename-table-column.tpl');
|
||||
|
||||
var simulateENTERKeyPress = function () {
|
||||
var e = $.Event('keydown');
|
||||
e.keyCode = e.which = $.ui.keyCode.ENTER;
|
||||
$(document).trigger(e);
|
||||
};
|
||||
|
||||
describe('components/modals/modal-confirmation-view', function () {
|
||||
beforeEach(function () {
|
||||
this.view = new ModalConfirmationView({
|
||||
modalModel: {},
|
||||
template: templateExample,
|
||||
loadingTitle: 'loading-title',
|
||||
renderOpts: {
|
||||
columnName: 'pepito',
|
||||
newName: 'pepita'
|
||||
},
|
||||
runAction: function () {}
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
describe('binds', function () {
|
||||
it('should render loading view when ok button is clicked', function () {
|
||||
spyOn(this.view, '_renderLoadingView');
|
||||
this.view.$('.js-confirm').click();
|
||||
expect(this.view._renderLoadingView).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should runAction when ENTER is pressed', function () {
|
||||
spyOn(this.view, '_runAction');
|
||||
simulateENTERKeyPress();
|
||||
expect(this.view._runAction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disable ENTER binding when is disabled', function () {
|
||||
spyOn(this.view, '_runAction');
|
||||
this.view._disableBinds();
|
||||
simulateENTERKeyPress();
|
||||
expect(this.view._runAction).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should have .js-confirm and .js-cancel present in the template', function () {
|
||||
expect(this.view.$('.js-confirm').length).toBe(1);
|
||||
expect(this.view.$('.js-cancel').length).toBe(1);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.clean();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
var ModalViewModel = require('builder/components/modals/modal-view-model');
|
||||
|
||||
describe('components/modals/modal-view-model', function () {
|
||||
beforeEach(function () {
|
||||
this.createContentViewResult = {};
|
||||
this.createContentView = jasmine.createSpy('createContentView').and.returnValue(this.createContentViewResult);
|
||||
this.model = new ModalViewModel({
|
||||
createContentView: this.createContentView
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow show/hide modal', function () {
|
||||
expect(this.model.get('show')).toBe(true);
|
||||
expect(this.model.isHidden()).toBe(false);
|
||||
|
||||
this.model.hide();
|
||||
expect(this.model.get('show')).toBe(false);
|
||||
expect(this.model.isHidden()).toBe(true);
|
||||
|
||||
this.model.show();
|
||||
expect(this.model.get('show')).toBe(true);
|
||||
expect(this.model.isHidden()).toBe(false);
|
||||
});
|
||||
|
||||
describe('.createContentView', function () {
|
||||
beforeEach(function () {
|
||||
this.view = this.model.createContentView();
|
||||
});
|
||||
|
||||
it('should create content view given viewModel', function () {
|
||||
expect(this.createContentView).toHaveBeenCalled();
|
||||
expect(this.createContentView).toHaveBeenCalledWith(this.model);
|
||||
});
|
||||
|
||||
it('should return created view', function () {
|
||||
expect(this.view).toBe(this.createContentViewResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.destroy', function () {
|
||||
beforeEach(function () {
|
||||
this.destroySpy = jasmine.createSpy('onDestroy');
|
||||
this.model.on('destroy', this.destroySpy);
|
||||
this.model.destroy('arg1', 'arg2', 'arg3');
|
||||
});
|
||||
|
||||
it('should destroy the model', function () {
|
||||
expect(this.destroySpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass through any arguments to listener', function () {
|
||||
var args = this.destroySpy.calls.argsFor(0);
|
||||
expect(args[0]).toEqual('arg1');
|
||||
expect(args[1]).toEqual('arg2');
|
||||
expect(args[2]).toEqual('arg3');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var ModalViewModel = require('builder/components/modals/modal-view-model');
|
||||
var ModalView = require('builder/components/modals/modal-view');
|
||||
|
||||
describe('components/modals/modal-view', function () {
|
||||
var view, model, contentView, contentViewModel, contentViewEventSpy;
|
||||
|
||||
var createViewFn = function (options) {
|
||||
contentViewEventSpy = jasmine.createSpy('test');
|
||||
|
||||
model = new ModalViewModel({
|
||||
createContentView: function () { return contentView; }
|
||||
});
|
||||
|
||||
var TestView = CoreView.extend({
|
||||
initialize: function () {
|
||||
this.model.on('test', contentViewEventSpy, this);
|
||||
}
|
||||
});
|
||||
|
||||
contentViewModel = new Backbone.Model();
|
||||
contentView = new TestView({model: contentViewModel});
|
||||
spyOn(contentView, 'render').and.callThrough();
|
||||
|
||||
var defaultOptions = {
|
||||
model: model
|
||||
};
|
||||
|
||||
view = new ModalView(_.extend(defaultOptions, options));
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
it('should have no leaks', function () {
|
||||
view = createViewFn();
|
||||
|
||||
view.render();
|
||||
|
||||
expect(view).toHaveNoLeaks();
|
||||
});
|
||||
|
||||
it('should render dialog classes', function () {
|
||||
view = createViewFn();
|
||||
|
||||
view.render();
|
||||
|
||||
expect(view.$el.html()).toContain('Dialog');
|
||||
expect(view.$el.html()).toContain('Dialog-contentWrapper');
|
||||
});
|
||||
|
||||
it('should not render close button if escapeOptionsDisabled is present', function () {
|
||||
view = createViewFn({
|
||||
escapeOptionsDisabled: true
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
expect(view.$el.html()).not.toContain('js-close');
|
||||
});
|
||||
|
||||
it('should not render close button if breadcrumbsEnabled is present', function () {
|
||||
view = createViewFn({
|
||||
breadcrumbsEnabled: true
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
expect(view.$el.html()).toContain('<div class="Dialog-headerWrapper">');
|
||||
expect(view.$el.html()).not.toContain('<button class="CDB-Shape js-close Dialog-closeBtn">');
|
||||
});
|
||||
|
||||
describe('when close is clicked', function () {
|
||||
beforeEach(function () {
|
||||
view = createViewFn();
|
||||
|
||||
view.render();
|
||||
|
||||
contentViewModel.trigger('test', 'asd');
|
||||
expect(contentViewEventSpy).toHaveBeenCalled();
|
||||
contentViewEventSpy.calls.reset();
|
||||
|
||||
jasmine.clock().install();
|
||||
spyOn(view, 'hide').and.callThrough();
|
||||
spyOn(view, 'clean').and.callThrough();
|
||||
spyOn(model, 'destroy').and.callThrough();
|
||||
view.$('.js-close').click();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it('should destroy the model', function () {
|
||||
expect(model.destroy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should hide modal', function () {
|
||||
expect(view.hide).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not react to model bindings anymore', function () {
|
||||
contentViewModel.trigger('test', 'asd');
|
||||
expect(contentViewEventSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not clean the view right away', function () {
|
||||
expect(view.clean).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('when the close animation is done', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.clock().tick(1000);
|
||||
});
|
||||
|
||||
it('should have cleaned the view', function () {
|
||||
expect(view.clean).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not react to model bindings anymore', function () {
|
||||
contentViewModel.trigger('test', 'asd');
|
||||
expect(contentViewEventSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should have no leaks', function () {
|
||||
expect(view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
var Router = require('builder/routes/router');
|
||||
|
||||
describe('components/modals/modals-service-model', function () {
|
||||
beforeEach(function () {
|
||||
this.modals = new ModalsServiceModel();
|
||||
this.willCreateModalSpy = jasmine.createSpy('willCreateModal');
|
||||
this.didCreateModalSpy = jasmine.createSpy('didCreateModal');
|
||||
this.modals.on('willCreateModal', this.willCreateModalSpy);
|
||||
this.modals.on('didCreateModal', this.didCreateModalSpy);
|
||||
});
|
||||
|
||||
describe('.create', function () {
|
||||
var contentView, contentView2;
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(Router, 'navigate');
|
||||
spyOn(document.body, 'appendChild');
|
||||
|
||||
contentView = new CoreView();
|
||||
spyOn(contentView, 'render').and.callThrough();
|
||||
|
||||
this.modalView = this.modals.create(function () {
|
||||
return contentView;
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a modal view', function () {
|
||||
expect(this.modalView).toBeDefined();
|
||||
});
|
||||
|
||||
it('should trigger a willCreateModal event', function () {
|
||||
expect(this.willCreateModalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should trigger a didCreateModal event', function () {
|
||||
expect(this.didCreateModalSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render the content view', function () {
|
||||
expect(contentView.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should append the modal to the body', function () {
|
||||
expect(document.body.appendChild).toHaveBeenCalledWith(this.modalView.el);
|
||||
});
|
||||
|
||||
it('should add the special body class', function () {
|
||||
expect(document.body.className).toContain('is-inDialog');
|
||||
});
|
||||
|
||||
describe('subsequent calls', function () {
|
||||
beforeEach(function () {
|
||||
contentView2 = new CoreView();
|
||||
spyOn(contentView2, 'render').and.callThrough();
|
||||
|
||||
this.modalView2 = this.modals.create(function () {
|
||||
return contentView2;
|
||||
});
|
||||
});
|
||||
|
||||
it('should reuse modal view', function () {
|
||||
expect(this.modalView2).toBe(this.modalView);
|
||||
});
|
||||
|
||||
it('should append the new modal to the body', function () {
|
||||
expect(document.body.appendChild).toHaveBeenCalledWith(this.modalView2.el);
|
||||
});
|
||||
|
||||
it('should keep the special body class', function () {
|
||||
expect(document.body.className).toContain('is-inDialog');
|
||||
});
|
||||
|
||||
describe('when destroyed', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.clock().install();
|
||||
this.destroyOnceSpy = jasmine.createSpy('destroyedModal');
|
||||
this.modals.onDestroyOnce(this.destroyOnceSpy);
|
||||
spyOn(this.modalView2, 'clean').and.callThrough();
|
||||
this.modalView2.destroy();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.clock().uninstall();
|
||||
});
|
||||
|
||||
it('should not clean the view right away but wait until after animation', function () {
|
||||
expect(this.modalView2.clean).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should have closing animation', function () {
|
||||
expect(this.modalView2.el.className).toContain('is-closing');
|
||||
expect(this.modalView2.el.className).not.toContain('is-opening');
|
||||
});
|
||||
|
||||
it('should remove the special body class', function () {
|
||||
expect(document.body.className).not.toContain('is-inDialog');
|
||||
});
|
||||
|
||||
describe('when close animation is done', function () {
|
||||
beforeEach(function () {
|
||||
jasmine.clock().tick(250);
|
||||
});
|
||||
|
||||
it('should have cleaned the view', function () {
|
||||
expect(this.modalView2.clean).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should have triggered listener', function () {
|
||||
expect(this.destroyOnceSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var PrivacyWarningView = require('builder/components/modals/privacy-warning/privacy-warning-view');
|
||||
|
||||
describe('components/modals/privacy-warning/privacy-warning-view', function () {
|
||||
var view;
|
||||
|
||||
var createViewFn = function (viewOptions) {
|
||||
var modals = new Backbone.Model();
|
||||
|
||||
var view = new PrivacyWarningView(
|
||||
_.extend({
|
||||
privacyType: 'PUBLIC',
|
||||
modalModel: modals
|
||||
}, viewOptions)
|
||||
);
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
afterEach(function () {
|
||||
if (view) view.clean();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
var visualizationView = createViewFn();
|
||||
visualizationView.render();
|
||||
|
||||
expect(visualizationView.$('h2').text()).toContain('components.modals.privacy-warning.title.visualization.PUBLIC');
|
||||
expect(visualizationView.$('p').text()).toContain('components.modals.privacy-warning.description');
|
||||
expect(visualizationView.$('.js-cancel').text()).toContain('components.modals.privacy-warning.cancel');
|
||||
expect(visualizationView.$('.js-confirm').text()).toContain('components.modals.privacy-warning.confirm');
|
||||
|
||||
var datasetView = createViewFn({
|
||||
type: 'dataset'
|
||||
});
|
||||
datasetView.render();
|
||||
|
||||
expect(datasetView.$('h2').text()).toContain('components.modals.privacy-warning.title.dataset');
|
||||
|
||||
visualizationView.clean();
|
||||
datasetView.clean();
|
||||
});
|
||||
|
||||
it('should invoke confirm callback when clicking confirm', function () {
|
||||
var confirmCallbackSpy = jasmine.createSpy();
|
||||
|
||||
view = createViewFn({
|
||||
onConfirm: confirmCallbackSpy
|
||||
});
|
||||
view.render();
|
||||
|
||||
view.$('.js-confirm').click();
|
||||
|
||||
expect(confirmCallbackSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should invoke cancel callback when dismissing the modal', function () {
|
||||
var dismissCallbackSpy = jasmine.createSpy();
|
||||
|
||||
view = createViewFn({
|
||||
onDismiss: dismissCallbackSpy
|
||||
});
|
||||
view.render();
|
||||
|
||||
view.$('.js-cancel').click();
|
||||
|
||||
expect(dismissCallbackSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
var PrivacyCollection = require('builder/components/modals/publish/privacy-collection');
|
||||
|
||||
describe('components/modals/publish/privacy-collection', function () {
|
||||
var collection;
|
||||
|
||||
beforeEach(function () {
|
||||
collection = new PrivacyCollection();
|
||||
});
|
||||
|
||||
describe('when reset with some options', function () {
|
||||
beforeEach(function () {
|
||||
collection.reset([{
|
||||
privacy: 'PUBLIC',
|
||||
title: 'Public',
|
||||
desc: 'Lorem ipsum',
|
||||
cssClass: 'is-green',
|
||||
selected: true
|
||||
}, {
|
||||
privacy: 'LINK',
|
||||
title: 'Link',
|
||||
desc: 'Yabadababa',
|
||||
cssClass: 'is-orange'
|
||||
}, {
|
||||
privacy: 'PASSWORD',
|
||||
title: 'Password',
|
||||
desc: 'Wadus'
|
||||
}, {
|
||||
privacy: 'PRIVATE',
|
||||
title: 'Private',
|
||||
desc: 'Funínculo',
|
||||
cssClass: 'is-red'
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should create a model for given data', function () {
|
||||
expect(collection.length).toEqual(4);
|
||||
expect(collection.at(0).get('title')).toEqual('Public');
|
||||
expect(collection.at(3).get('title')).toEqual('Private');
|
||||
});
|
||||
|
||||
it('should return the selected option', function () {
|
||||
collection.at(2).set({selected: true});
|
||||
expect(collection.selectedOption().get('title')).toEqual('Password');
|
||||
collection.at(3).set({selected: true});
|
||||
expect(collection.selectedOption().get('title')).toEqual('Private');
|
||||
});
|
||||
|
||||
it('should return the password option', function () {
|
||||
expect(collection.passwordOption().get('title')).toEqual('Password');
|
||||
});
|
||||
|
||||
it('should search the option passed', function () {
|
||||
expect(collection.searchByPrivacy('LINK').get('title')).toEqual('Link');
|
||||
});
|
||||
|
||||
it('should only allow one selection at a time', function () {
|
||||
expect(collection.pluck('selected')).toEqual([true, false, false, false]);
|
||||
|
||||
collection.last().set('selected', true);
|
||||
expect(collection.pluck('selected')).toEqual([false, false, false, true]);
|
||||
|
||||
collection.first().set('selected', true);
|
||||
expect(collection.pluck('selected')).toEqual([true, false, false, false]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
var Backbone = require('backbone');
|
||||
var PublishButtonView = require('builder/components/modals/publish/publish-button-view');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var UserModel = require('fixtures/builder/user-model.fixture.js');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
|
||||
describe('components/modals/publish/publish-button-view', function () {
|
||||
var view, visDefinitionModel, mapcapsCollection;
|
||||
|
||||
var createViewFn = function (options) {
|
||||
var customOptions = options || {};
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
visDefinitionModel = new VisDefinitionModel(
|
||||
{
|
||||
name: 'Foo Map',
|
||||
privacy: 'PUBLIC',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
permission: {}
|
||||
},
|
||||
{ configModel: configModel });
|
||||
|
||||
mapcapsCollection = new Backbone.Collection();
|
||||
|
||||
var view = new PublishButtonView({
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
mapcapsCollection: mapcapsCollection,
|
||||
configModel: configModel,
|
||||
userModel: UserModel(customOptions.userModel)
|
||||
});
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
view = createViewFn({
|
||||
userModel: {
|
||||
actions: {
|
||||
private_maps: true,
|
||||
private_tables: true
|
||||
}
|
||||
}
|
||||
});
|
||||
view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
view.remove();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
var publishButton = view.$('.js-button');
|
||||
expect(publishButton.text()).toContain('components.modals.publish.publish-btn');
|
||||
expect(view.$el.text()).toContain('components.modals.publish.share.unpublished');
|
||||
});
|
||||
|
||||
describe('_onUpdate', function () {
|
||||
it('should create map capture if privacy warning is not shown', function () {
|
||||
spyOn(view, '_shouldShowPrivacyWarning').and.returnValue(false);
|
||||
spyOn(view, '_createMapCap');
|
||||
|
||||
view._onUpdate();
|
||||
|
||||
expect(view._createMapCap).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create map capture if user accepts the privacy warning', function () {
|
||||
spyOn(view, '_shouldShowPrivacyWarning').and.returnValue(true);
|
||||
spyOn(view, '_createMapCap');
|
||||
spyOn(view, '_checkPrivacyChange').and.callFake(
|
||||
function (_, success) { success(); }
|
||||
);
|
||||
|
||||
view._onUpdate();
|
||||
|
||||
expect(view._checkPrivacyChange).toHaveBeenCalled();
|
||||
expect(view._createMapCap).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not create map capture if user dismisses the privacy warning', function () {
|
||||
spyOn(view, '_shouldShowPrivacyWarning').and.returnValue(true);
|
||||
spyOn(view, '_createMapCap');
|
||||
spyOn(view, '_checkPrivacyChange').and.callFake(
|
||||
function (_newPrivacyStatus, _confirm, dismiss) {
|
||||
if (dismiss) dismiss();
|
||||
}
|
||||
);
|
||||
|
||||
view._onUpdate();
|
||||
|
||||
expect(view._checkPrivacyChange).toHaveBeenCalled();
|
||||
expect(view._createMapCap).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('_checkPrivacyChange', function () {
|
||||
it('should open PrivacyWarningView', function (done) {
|
||||
view._checkPrivacyChange('PUBLIC');
|
||||
|
||||
var dialogView = document.querySelector('.Dialog');
|
||||
expect(dialogView.innerText).toContain('components.modals.privacy-warning.title.visualization.PUBLIC');
|
||||
|
||||
view.clean();
|
||||
|
||||
// Wait for the modal to close
|
||||
setTimeout(function () { done(); }, 250);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_shouldShowPrivacyWarning', function () {
|
||||
it('should return false if user cannot select premium options', function () {
|
||||
view = createViewFn({
|
||||
userModel: {
|
||||
actions: {
|
||||
private_maps: false,
|
||||
private_tables: false
|
||||
}
|
||||
}
|
||||
});
|
||||
visDefinitionModel.set('privacy', 'LINK');
|
||||
|
||||
expect(view._shouldShowPrivacyWarning()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if map is not published and privacy is set to *any* public state', function () {
|
||||
visDefinitionModel.set('privacy', 'LINK');
|
||||
|
||||
expect(view._shouldShowPrivacyWarning()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if map is published', function () {
|
||||
mapcapsCollection.add({
|
||||
created_at: '2016-06-21T15:30:06+00:00'
|
||||
});
|
||||
|
||||
expect(view._shouldShowPrivacyWarning()).toBe(false);
|
||||
|
||||
mapcapsCollection.reset([]);
|
||||
});
|
||||
|
||||
it('should return false if map is published and privacy is set to private', function () {
|
||||
visDefinitionModel.set('privacy', 'PRIVATE');
|
||||
mapcapsCollection.add({ created_at: '2016-06-21T15:30:06+00:00' });
|
||||
|
||||
expect(view._shouldShowPrivacyWarning()).toBe(false);
|
||||
|
||||
mapcapsCollection.reset([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
var Backbone = require('backbone');
|
||||
var PublishView = require('builder/components/modals/publish/publish-view');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var PrivacyCollection = require('builder/components/modals/publish/privacy-collection');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
|
||||
describe('components/modals/publish/publish-view', function () {
|
||||
var userModel;
|
||||
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*grantables.*'))
|
||||
.andReturn({ status: 200 });
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
userModel = new UserModel({
|
||||
id: 1,
|
||||
username: 'pepe',
|
||||
avatar_url: 'https://example.com/avatar.jpg',
|
||||
actions: {
|
||||
private_tables: true
|
||||
}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
userModel._organizationModel = new Backbone.Model({
|
||||
id: 1
|
||||
});
|
||||
|
||||
var collection = new PrivacyCollection([{
|
||||
privacy: 'PUBLIC',
|
||||
title: 'Public',
|
||||
desc: 'Lorem ipsum',
|
||||
cssClass: 'is-green',
|
||||
selected: true
|
||||
}, {
|
||||
privacy: 'LINK',
|
||||
title: 'Link',
|
||||
desc: 'Yabadababa',
|
||||
cssClass: 'is-orange'
|
||||
}, {
|
||||
privacy: 'PASSWORD',
|
||||
title: 'Password',
|
||||
desc: 'Wadus'
|
||||
}, {
|
||||
privacy: 'PRIVATE',
|
||||
title: 'Private',
|
||||
desc: 'Funínculo',
|
||||
cssClass: 'is-red'
|
||||
}]);
|
||||
|
||||
var mapcapsCollection = new Backbone.Collection([{
|
||||
created_at: '2016-06-21T15:30:06+00:00'
|
||||
}]);
|
||||
|
||||
var visDefinitionModel = new VisDefinitionModel({
|
||||
name: 'Foo Map',
|
||||
privacy: 'PUBLIC',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.view = new PublishView({
|
||||
mapcapsCollection: mapcapsCollection,
|
||||
modalModel: new Backbone.Model(),
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
privacyCollection: collection,
|
||||
userModel: userModel,
|
||||
configModel: configModel,
|
||||
isOwner: true,
|
||||
ownerName: 'matata'
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.remove();
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$el.html()).toContain('Foo Map');
|
||||
expect(this.view.$('.js-toggle').length).toBe(1);
|
||||
expect(this.view.$('.js-toggle').text()).toContain('PUBLIC');
|
||||
expect(this.view.$('.js-share-users').length).toBe(1);
|
||||
expect(this.view.$('.js-panes').length).toBe(1);
|
||||
expect(this.view.$('.js-menu').length).toBe(1);
|
||||
expect(this.view.$('.Publish-modalLink').length).toBe(2);
|
||||
});
|
||||
|
||||
it('should render properly in share in single mode', function () {
|
||||
this.view.mode = 'share';
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$el.html()).toContain('Foo Map');
|
||||
expect(this.view.$('.js-menu').length).toBe(0);
|
||||
expect(this.view.$('.Publish-modalLink').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should render properly for users without organization', function () {
|
||||
userModel._organizationModel = false;
|
||||
this.view.render();
|
||||
|
||||
expect(this.view.$el.html()).toContain('Foo Map');
|
||||
expect(this.view.$('.js-menu').length).toBe(0);
|
||||
expect(this.view.$('.js-share-users').length).toBe(0); // share badget
|
||||
expect(this.view.$('.Publish-modalLink').length).toBe(0); // it runs in single mode without tabs and share view
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var PrivacyView = require('builder/components/modals/publish/publish/publish-view');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
|
||||
describe('components/modals/publish/publish/publish-view', function () {
|
||||
var view;
|
||||
var mapcapsCollection;
|
||||
var visDefinitionModel;
|
||||
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
visDefinitionModel = new VisDefinitionModel({
|
||||
name: 'Foo Map',
|
||||
privacy: 'PRIVATE',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
var userModel = new UserModel({
|
||||
username: 'pepe',
|
||||
actions: {
|
||||
private_tables: true
|
||||
}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
mapcapsCollection = new Backbone.Collection([]);
|
||||
|
||||
view = new PrivacyView({
|
||||
mapcapsCollection: mapcapsCollection,
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
userModel: userModel
|
||||
});
|
||||
|
||||
view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
view.remove();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(view.$('.Card').length).toBe(2);
|
||||
expect(view.$('input').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should render properly when published and private', function () {
|
||||
mapcapsCollection.reset([{
|
||||
created_at: '2016-06-21T15:30:06+00:00'
|
||||
}]);
|
||||
expect(view.$('.Card').length).toBe(2);
|
||||
expect(view.$('.Card.is-disabled').length).toBe(2);
|
||||
expect(view.$('input').length).toBe(0); // it's private
|
||||
});
|
||||
|
||||
it('should render properly when published and public', function () {
|
||||
mapcapsCollection.reset([{
|
||||
created_at: '2016-06-21T15:30:06+00:00'
|
||||
}]);
|
||||
|
||||
visDefinitionModel.set({privacy: 'PUBLIC'});
|
||||
visDefinitionModel.trigger('sync');
|
||||
|
||||
expect(view.$('.Card').length).toBe(2);
|
||||
expect(view.$('.Card.is-disabled').length).toBe(0);
|
||||
expect(view.$('input').length).toBe(2);
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
var Backbone = require('backbone');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var ShareWithView = require('builder/components/modals/publish/share-with-view');
|
||||
|
||||
describe('components/modals/publish/share-with-view', function () {
|
||||
var view;
|
||||
var visDefinitionModel;
|
||||
var userModel;
|
||||
|
||||
beforeEach(function () {
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
userModel = new UserModel({
|
||||
id: 1,
|
||||
username: 'pepe',
|
||||
avatar_url: 'https://example.com/avatar.jpg',
|
||||
actions: {
|
||||
private_tables: true
|
||||
}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
visDefinitionModel = new VisDefinitionModel({
|
||||
name: 'Foo Map',
|
||||
privacy: 'PUBLIC',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
view = new ShareWithView({
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
userModel: userModel
|
||||
});
|
||||
|
||||
view.render();
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
it('should render properly', function () {
|
||||
// empty because people is 0 and the user has no org
|
||||
expect(view.$('.Share-user').length).toBe(0);
|
||||
expect(view.$el.html()).not.toContain('components.modals.publish.share.add-people');
|
||||
});
|
||||
|
||||
it('should render properly when inside org', function () {
|
||||
userModel._organizationModel = new Backbone.Model({
|
||||
id: 1
|
||||
});
|
||||
|
||||
spyOn(view, '_getPeople').and.returnValue(2);
|
||||
view.render();
|
||||
|
||||
expect(view.$('.Share-user').length).toBe(1);
|
||||
expect(view.$el.text()).toContain('+ 2');
|
||||
expect(view.$el.html()).not.toContain('components.modals.publish.share.add-people');
|
||||
});
|
||||
|
||||
it('should render properly when inside org and has an action', function () {
|
||||
userModel._organizationModel = new Backbone.Model({
|
||||
id: 1
|
||||
});
|
||||
|
||||
spyOn(view, '_getPeople').and.returnValue(0);
|
||||
|
||||
view = new ShareWithView({
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
userModel: userModel,
|
||||
clickPrivacyAction: jasmine.createSpy('actionCallback')
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
expect(view.$('.Share-user').length).toBe(0);
|
||||
expect(view.$el.html()).toContain('components.modals.publish.share.add-people');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
var Backbone = require('backbone');
|
||||
var ShareView = require('builder/components/modals/publish/share/share-view');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var OrganizationModel = require('builder/data/organization-model');
|
||||
|
||||
describe('components/modals/publish/share/share-view', function () {
|
||||
var onBack;
|
||||
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?://.*/grantables.*'))
|
||||
.andReturn({ status: 200 });
|
||||
|
||||
var configModel = new ConfigModel({
|
||||
base_url: '/u/pepe'
|
||||
});
|
||||
|
||||
var visDefinitionModel = new VisDefinitionModel({
|
||||
name: 'Foo Map',
|
||||
privacy: 'PUBLIC',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
var org = new OrganizationModel({
|
||||
id: 'org1',
|
||||
owner: {
|
||||
id: 'hello',
|
||||
username: 'dev',
|
||||
email: 'hello@hello'
|
||||
}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
spyOn(ShareView.prototype, '_onCancel');
|
||||
spyOn(ShareView.prototype, '_onSave');
|
||||
onBack = jasmine.createSpy('onBack');
|
||||
|
||||
this.view = new ShareView({
|
||||
modalModel: new Backbone.Model(),
|
||||
onBack: onBack,
|
||||
currentUserId: 'u1',
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
organization: org,
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.view.remove();
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$('.js-filters').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should not have any leaks', function () {
|
||||
expect(this.view).toHaveNoLeaks();
|
||||
});
|
||||
});
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
var Backbone = require('backbone');
|
||||
var _ = require('underscore');
|
||||
var RemoveDatasetView = require('builder/components/modals/remove-dataset/remove-dataset-view');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var TableModel = require('builder/data/table-model');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
|
||||
describe('modals/remove-dataset-view', function () {
|
||||
var modalModel = new Backbone.Model();
|
||||
var avatarBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC';
|
||||
var configData = {
|
||||
base_url: '/u/manolo',
|
||||
maps_api_template: 'http://{user}.localhost.lan:8181'
|
||||
};
|
||||
var userData = {
|
||||
id: '8c253a9a-94d8-4042-883c-3aa81285e5e6',
|
||||
username: 'cdb',
|
||||
organization: {
|
||||
display_name: 'Globex Corporation',
|
||||
name: 'globex',
|
||||
avatar_url: 'https://s3.amazonaws.com/com.cartodb.users-assets.staging/development/cdb/assets/20161028125910fake-company-logo.jpg',
|
||||
user_count: 25
|
||||
}
|
||||
};
|
||||
var tableDataWithNoDependentMaps = {
|
||||
name: 'NYC Graffiti sights',
|
||||
accessible_dependent_derived_maps: []
|
||||
};
|
||||
var dependentMap = {
|
||||
id: '5725afbe-9f51-11e6-af45-080027eb929e',
|
||||
name: 'Untitled Map',
|
||||
permission: {
|
||||
owner: {
|
||||
username: 'cdb'
|
||||
}
|
||||
},
|
||||
updated_at: '2016-10-31T10:03:58+00:00'
|
||||
};
|
||||
var visDataWithNoACL = {
|
||||
permission: {
|
||||
acl: []
|
||||
}
|
||||
};
|
||||
var visDataWithOrganizationACL = {
|
||||
permission: {
|
||||
acl: [{
|
||||
type: 'org',
|
||||
entity: {
|
||||
id: 'c210c579-0780-4ccd-83a8-7bf9fee11b34',
|
||||
name: 'globex',
|
||||
avatar_url: avatarBase64
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
var visDataWithGroupACL = {
|
||||
permission: {
|
||||
acl: [{
|
||||
type: 'group',
|
||||
entity: {
|
||||
users: [{
|
||||
username: 'Meowth',
|
||||
avatar_url: avatarBase64
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
var visModel;
|
||||
var configModel;
|
||||
var tableModel;
|
||||
var userModel;
|
||||
var view;
|
||||
|
||||
function createDependantACL (username) {
|
||||
return {
|
||||
type: 'user',
|
||||
entity: {
|
||||
username: username || 'pepe' + _.random(99999).toString(),
|
||||
avatar_url: avatarBase64
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createView (options) {
|
||||
var opts = options || {};
|
||||
var numberOfDependentMaps = opts.numberOfDependentMaps || 0;
|
||||
var organizationAffected = opts.organizationAffected || false;
|
||||
var numberOfDependentEntities = opts.numberOfDependentEntities || 0;
|
||||
var repeatAffectedEntity = opts.repeatAffectedEntity || false;
|
||||
var affectedGroup = opts.affectedGroup || false;
|
||||
var tableData;
|
||||
var visData;
|
||||
|
||||
configModel = new ConfigModel(configData);
|
||||
userModel = new UserModel(userData, { configModel: configModel });
|
||||
|
||||
if (numberOfDependentMaps > 0) {
|
||||
tableData = _.clone(tableDataWithNoDependentMaps);
|
||||
_.times(numberOfDependentMaps, function () {
|
||||
tableData.accessible_dependent_derived_maps.push(dependentMap);
|
||||
});
|
||||
} else {
|
||||
tableModel = new TableModel(tableDataWithNoDependentMaps, { parse: true, configModel: configModel });
|
||||
}
|
||||
|
||||
if (organizationAffected) {
|
||||
visModel = new VisDefinitionModel(visDataWithOrganizationACL, {
|
||||
configModel: configModel
|
||||
});
|
||||
} else if (affectedGroup) {
|
||||
visModel = new VisDefinitionModel(visDataWithGroupACL, {
|
||||
configModel: configModel
|
||||
});
|
||||
} else if (numberOfDependentEntities > 0) {
|
||||
visData = {
|
||||
permission: {
|
||||
acl: []
|
||||
}
|
||||
};
|
||||
_.times(numberOfDependentEntities, function () {
|
||||
visData.permission.acl.push(createDependantACL());
|
||||
});
|
||||
visData.permission.acl.push(createDependantACL(userData.username)); // To test if we filter ourselves
|
||||
if (repeatAffectedEntity) {
|
||||
visData.permission.acl.push(_.clone(visData.permission.acl[0])); // Repeat one user to test if we filter only uniques
|
||||
}
|
||||
visModel = new VisDefinitionModel(visData, {
|
||||
configModel: configModel
|
||||
});
|
||||
} else {
|
||||
visModel = new VisDefinitionModel(visDataWithNoACL, {
|
||||
configModel: configModel
|
||||
});
|
||||
}
|
||||
|
||||
return new RemoveDatasetView({
|
||||
modalModel: modalModel,
|
||||
userModel: userModel,
|
||||
visModel: visModel,
|
||||
tableModel: tableModel,
|
||||
configModel: configModel
|
||||
});
|
||||
}
|
||||
|
||||
describe('render', function () {
|
||||
it('Nothing affected, visualization and entities sections not shown', function () {
|
||||
// Arrange
|
||||
view = createView();
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('h2')[0].textContent.trim()).toEqual('dataset.delete.title');
|
||||
expect(view.$('.MapsList-item').length).toBe(0);
|
||||
expect(view.$('.ShareUser').length).toBe(0);
|
||||
expect(view.$('button.js-cancel > span')[0].textContent.trim()).toEqual('dataset.delete.cancel');
|
||||
expect(view.$('button.js-confirm > span')[0].textContent.trim()).toEqual('dataset.delete.confirm');
|
||||
});
|
||||
|
||||
it('1 visualization affected. Visualization gets properly rendered.', function () {
|
||||
// Arrange
|
||||
view = createView({ numberOfDependentMaps: 1 });
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-affectedVis > p')[0].textContent.trim()).toEqual('dataset.delete.affected-vis-count');
|
||||
expect(view.$('.js-affectedVis > ul > li').length).toBe(1);
|
||||
expect(view.$('.MapCard')[0].dataset['visId']).toEqual(dependentMap.id);
|
||||
expect(view.$('.MapCard')[0].dataset['visOwnerName']).toEqual(dependentMap.permission.owner.username);
|
||||
expect(view.$('.MapCard > a')[0].href).toBeTruthy();
|
||||
expect(view.$('.MapCard > a > img')[0].src).toBeTruthy();
|
||||
expect(view.$('.MapCard-content h3 > a')[0].href).toBeTruthy();
|
||||
expect(view.$('.MapCard-content h3 > a')[0].title).toEqual(dependentMap.name);
|
||||
expect(view.$('.MapCard-contentBodyTimeDiff')[0].textContent.trim()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('More vis affected than AFFECTED_VIS_COUNT. Text changed to extended one.', function () {
|
||||
// Arrange
|
||||
var maxAffectedVisCount = 3; // AFFECTED_VIS_COUNT
|
||||
view = createView({ numberOfDependentMaps: 4 });
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-affectedVis > p')[0].textContent.trim()).toEqual('dataset.delete.affected-vis-count-extended');
|
||||
expect(view.$('.js-affectedVis > ul > li').length).toBe(maxAffectedVisCount);
|
||||
});
|
||||
|
||||
it('Organization affected. Proper text and avatar rendered.', function () {
|
||||
// Arrange
|
||||
var userNode;
|
||||
view = createView({ organizationAffected: true });
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-affectedEntities > p')[0].textContent.trim()).toEqual('dataset.delete.whole-organization-affected');
|
||||
expect(view.$('.js-affectedEntities li').length).toBe(1);
|
||||
userNode = view.$('.js-affectedEntities li .Share-user')[0];
|
||||
expect(userNode.title).toEqual(userData.organization.display_name);
|
||||
expect(userNode.dataset['username']).toEqual(userData.organization.display_name);
|
||||
expect(userNode.style.backgroundImage.indexOf(userData.organization.avatar_url) > -1).toBe(true);
|
||||
});
|
||||
|
||||
it('1 user affected. Proper text and avatar rendered.', function () {
|
||||
// Arrange
|
||||
var userNode;
|
||||
var affectedEntity;
|
||||
view = createView({ numberOfDependentEntities: 1 });
|
||||
affectedEntity = view._visModel._permissionModel.get('acl')[0].entity;
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-affectedEntities > p')[0].textContent.trim()).toEqual('dataset.delete.affected-entities-count');
|
||||
expect(view.$('.js-affectedEntities li').length).toBe(1);
|
||||
userNode = view.$('.js-affectedEntities li .Share-user')[0];
|
||||
expect(userNode.title).toEqual(affectedEntity.username);
|
||||
expect(userNode.dataset['username']).toEqual(affectedEntity.username);
|
||||
expect(userNode.style.backgroundImage.indexOf(affectedEntity.avatar_url) > -1).toBe(true);
|
||||
});
|
||||
|
||||
it('More user affected than AFFECTED_ENTITIES_SAMPLE_COUNT. Text changed to extended.', function () {
|
||||
// Arrange
|
||||
var affectedEntitiesSampleCount = 20; // AFFECTED_ENTITIES_SAMPLE_COUNT
|
||||
view = createView({ numberOfDependentEntities: affectedEntitiesSampleCount + 1 });
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-affectedEntities > p')[0].textContent.trim()).toEqual('dataset.delete.affected-entities-count-extended');
|
||||
expect(view.$('.js-affectedEntities li').length).toBe(affectedEntitiesSampleCount);
|
||||
});
|
||||
|
||||
it('Affected entity repeated. Repeated entity gets filtered.', function () {
|
||||
// Arrange
|
||||
view = createView({
|
||||
numberOfDependentEntities: 2,
|
||||
repeatAffectedEntity: true
|
||||
});
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-affectedEntities li').length).toBe(2);
|
||||
});
|
||||
|
||||
it('Affected group. Users of that group get rendered.', function () {
|
||||
// Arrange
|
||||
view = createView({
|
||||
affectedGroup: true
|
||||
});
|
||||
|
||||
// Act
|
||||
view.render();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-affectedEntities li').length).toBe(visDataWithGroupACL.permission.acl[0].entity.users.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_runAction', function () {
|
||||
it('Renders loading view and destory has been set to the right success function.', function () {
|
||||
// Arrange
|
||||
var successFunction;
|
||||
view = createView();
|
||||
spyOn(view, '_renderLoadingView');
|
||||
spyOn(view, '_onSuccessDestroyDataset');
|
||||
spyOn(visModel, 'destroy').and.callFake(function (args) {
|
||||
successFunction = args.success;
|
||||
});
|
||||
|
||||
// Act
|
||||
view._runAction();
|
||||
successFunction();
|
||||
|
||||
// Assert
|
||||
expect(view._renderLoadingView).toHaveBeenCalled();
|
||||
expect(view._onSuccessDestroyDataset).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Destroy has been set to the right error function.', function () {
|
||||
// Arrange
|
||||
var errorFunction;
|
||||
view = createView();
|
||||
spyOn(view, '_onErrorDestroyDataset');
|
||||
spyOn(visModel, 'destroy').and.callFake(function (args) {
|
||||
errorFunction = args.error;
|
||||
});
|
||||
|
||||
// Act
|
||||
view._runAction();
|
||||
errorFunction(null, {});
|
||||
|
||||
// Assert
|
||||
expect(view._onErrorDestroyDataset).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('_renderLoadingView inserts the right HTML', function () {
|
||||
// Arrange
|
||||
view = createView();
|
||||
|
||||
// Act
|
||||
view._renderLoadingView();
|
||||
|
||||
// Assert
|
||||
expect(view.$('.js-loader').length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('_onErrorDestroyDataset inserts the right HTML', function () {
|
||||
// Arrange
|
||||
view = createView();
|
||||
|
||||
// Act
|
||||
view._onErrorDestroyDataset(null, {});
|
||||
|
||||
// Assert
|
||||
expect(view.$('i.CDB-IconFont-cockroach').length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var AnalysisDefinitionNodesCollection = require('builder/data/analysis-definition-nodes-collection');
|
||||
var AnalysisDefinitionsCollection = require('builder/data/analysis-definitions-collection');
|
||||
var ConfigModel = require('builder/data/config-model');
|
||||
var DeleteLayerConfirmationView = require('builder/components/modals/remove-layer/delete-layer-confirmation-view');
|
||||
var LayerDefinitionModel = require('builder/data/layer-definition-model');
|
||||
var LayerDefinitionsCollection = require('builder/data/layer-definitions-collection');
|
||||
var ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
var UserActions = require('builder/data/user-actions');
|
||||
var UserModel = require('builder/data/user-model');
|
||||
var VisDefinitionModel = require('builder/data/vis-definition-model');
|
||||
var WidgetDefinitionsCollection = require('builder/data/widget-definitions-collection');
|
||||
|
||||
describe('modals/delete-layer-confirmation-view', function () {
|
||||
var view;
|
||||
var modalModel;
|
||||
var userData;
|
||||
var configData;
|
||||
var configModel;
|
||||
var userModel;
|
||||
var analysisDefinitionNodesCollection;
|
||||
var layerModel;
|
||||
var layerDefinitionsCollection;
|
||||
var visDefinitionModel;
|
||||
var widgetDefinitionsCollection;
|
||||
var analysisDefinitionsCollection;
|
||||
var userActions;
|
||||
var modals;
|
||||
|
||||
modalModel = new Backbone.Model();
|
||||
|
||||
userData = {
|
||||
id: '8c253a9a-94d8-4042-883c-3aa81285e5e6',
|
||||
username: 'cdb'
|
||||
};
|
||||
|
||||
configData = {
|
||||
base_url: '/u/manolo',
|
||||
maps_api_template: 'http://{user}.localhost.lan:8181'
|
||||
};
|
||||
|
||||
configModel = new ConfigModel(configData);
|
||||
|
||||
userModel = new UserModel(userData, { configModel: configModel });
|
||||
|
||||
analysisDefinitionNodesCollection = new AnalysisDefinitionNodesCollection([], {
|
||||
configModel: configModel,
|
||||
userModel: userModel
|
||||
});
|
||||
|
||||
layerModel = new LayerDefinitionModel({
|
||||
id: 'map-123',
|
||||
kind: 'carto',
|
||||
options: {
|
||||
type: 'CartoDB',
|
||||
color: '#FABADA',
|
||||
table_name: 'foo_bar',
|
||||
name: 'foo',
|
||||
letter: 'a',
|
||||
source: 'map-123',
|
||||
table_name_alias: 'foo_foo_bar',
|
||||
query: 'SELECT * FROM foo',
|
||||
tile_style: 'asdasd',
|
||||
visible: true
|
||||
}
|
||||
}, {
|
||||
configModel: configModel,
|
||||
parse: true
|
||||
});
|
||||
|
||||
layerDefinitionsCollection = new LayerDefinitionsCollection([layerModel], {
|
||||
configModel: configModel,
|
||||
userModel: userModel,
|
||||
analysisDefinitionNodesCollection: analysisDefinitionNodesCollection,
|
||||
mapId: 'map-123',
|
||||
stateDefinitionModel: {}
|
||||
});
|
||||
|
||||
visDefinitionModel = new VisDefinitionModel({
|
||||
name: 'foo',
|
||||
privacy: 'LINK',
|
||||
updated_at: '2016-06-21T15:30:06+00:00',
|
||||
type: 'derived',
|
||||
tags: ['foo', 'bar'],
|
||||
permission: {}
|
||||
}, {
|
||||
configModel: configModel
|
||||
});
|
||||
|
||||
widgetDefinitionsCollection = new WidgetDefinitionsCollection([layerModel], {
|
||||
configModel: configModel,
|
||||
layerDefinitionsCollection: layerDefinitionsCollection,
|
||||
analysisDefinitionNodesCollection: analysisDefinitionNodesCollection,
|
||||
mapId: 'map-123'
|
||||
});
|
||||
|
||||
analysisDefinitionsCollection = new AnalysisDefinitionsCollection([layerModel], {
|
||||
configModel: configModel,
|
||||
vizId: 'viz-123',
|
||||
layerDefinitionsCollection: layerDefinitionsCollection,
|
||||
analysisDefinitionNodesCollection: analysisDefinitionNodesCollection
|
||||
});
|
||||
|
||||
userActions = new UserActions({
|
||||
userModel: userModel,
|
||||
analysisDefinitionNodesCollection: analysisDefinitionNodesCollection,
|
||||
analysisDefinitionsCollection: analysisDefinitionsCollection,
|
||||
layerDefinitionsCollection: layerDefinitionsCollection,
|
||||
widgetDefinitionsCollection: widgetDefinitionsCollection
|
||||
});
|
||||
|
||||
modals = new ModalsServiceModel();
|
||||
|
||||
function createViewFn (options) {
|
||||
var defaultOptions = {
|
||||
userActions: userActions,
|
||||
modals: modals,
|
||||
layerModel: layerModel,
|
||||
modalModel: modalModel,
|
||||
visDefinitionModel: visDefinitionModel,
|
||||
widgetDefinitionsCollection: widgetDefinitionsCollection
|
||||
};
|
||||
|
||||
return new DeleteLayerConfirmationView(_.extend(defaultOptions, options));
|
||||
}
|
||||
|
||||
describe('render', function () {
|
||||
it('should render properly', function () {
|
||||
view = createViewFn();
|
||||
view.render();
|
||||
|
||||
expect(view.$('h2')[0].textContent.trim()).toEqual('editor.layers.delete.title');
|
||||
expect(view.$('p')[0].textContent.trim()).toEqual('editor.layers.delete.desc');
|
||||
|
||||
expect(view.$('li').length).toEqual(3);
|
||||
expect(view.$('li')[0].textContent.trim()).toEqual('editor.layers.delete.link-to-export');
|
||||
|
||||
expect(view.$('button.js-cancel > span')[0].textContent.trim()).toEqual('editor.layers.delete.cancel');
|
||||
expect(view.$('button.js-confirm > span')[0].textContent.trim()).toEqual('editor.layers.delete.confirm');
|
||||
});
|
||||
|
||||
it('should show the name of the layer to be deleted', function () {
|
||||
spyOn(layerModel, 'getName').and.callThrough();
|
||||
|
||||
view = createViewFn();
|
||||
view.render();
|
||||
|
||||
expect(layerModel.getName).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user