Initial commit
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('underscore');
|
||||
var AttributionView = require('../../../../src/geo/ui/attribution/attribution-view');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
|
||||
describe('geo/ui/attribution', function () {
|
||||
beforeEach(function () {
|
||||
// Disable defer
|
||||
spyOn(_, 'delay').and.callFake(function (func) { return function () { func.apply(this, arguments); }; });
|
||||
|
||||
this.keyEsc = function () {
|
||||
var e = $.Event('keydown');
|
||||
e.keyCode = 27; // ESC
|
||||
$(document).trigger(e);
|
||||
};
|
||||
|
||||
this.map = new Map(null, {
|
||||
layersFactory: {}
|
||||
});
|
||||
this.map.setMapViewSize({ x: 650, y: 1000 });
|
||||
spyOn(this.map, 'bind').and.callThrough();
|
||||
spyOn(AttributionView.prototype, 'render').and.callThrough();
|
||||
|
||||
this.view = new AttributionView({
|
||||
map: this.map
|
||||
});
|
||||
this.view.render();
|
||||
this.$button = this.view.$('.js-button');
|
||||
this.$text = this.view.$('.js-text');
|
||||
this.viewHasClass = function (className) {
|
||||
return this.view.$el.hasClass(className);
|
||||
};
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
it('should render properly', function () {
|
||||
expect(this.$button.length).toBe(1);
|
||||
expect(this.$text.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render expanded if map container is greater than 650px', function () {
|
||||
this.map.setMapViewSize({ x: 750, y: 1000 });
|
||||
this.view.render();
|
||||
expect(this.viewHasClass('CDB-Attribution')).toBeTruthy();
|
||||
expect(this.viewHasClass('is-active')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render collapsed if map container is smaller than 650px', function () {
|
||||
this.map.setMapViewSize({ x: 450, y: 1000 });
|
||||
this.view.render();
|
||||
expect(this.viewHasClass('CDB-Attribution')).toBeTruthy();
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should add GMaps properly when provider is not Leaflet', function () {
|
||||
expect(this.viewHasClass('CDB-Attribution--gmaps')).toBeFalsy();
|
||||
this.map.set('provider', 'gmaps');
|
||||
this.view.render();
|
||||
expect(this.viewHasClass('CDB-Attribution--gmaps')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('attributions change', function () {
|
||||
it('should render when it is visible', function () {
|
||||
this.$button.click(); // Making it visible
|
||||
this.map.trigger('change:attribution');
|
||||
expect(AttributionView.prototype.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render when it is not visible', function () {
|
||||
this.map.trigger('change:attribution');
|
||||
expect(AttributionView.prototype.render).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the attributions are displayed', function () {
|
||||
beforeEach(function () {
|
||||
this.$button.click();
|
||||
});
|
||||
|
||||
it('should have is-active class', function () {
|
||||
expect(this.viewHasClass('is-active')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should hide attributions text when js-button is clicked', function () {
|
||||
this.$button.click();
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should collapse the attributions when ESC is pressed', function () {
|
||||
this.keyEsc();
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when attributions are hidden', function () {
|
||||
beforeEach(function () {
|
||||
this.$button.click();
|
||||
this.keyEsc();
|
||||
});
|
||||
|
||||
it('shouldn\'t have is-active class', function () {
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show attributions text when js-button is clicked', function () {
|
||||
this.$button.click();
|
||||
expect(this.viewHasClass('is-active')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not respond to ESC', function () {
|
||||
this.keyEsc();
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not respond to clicks on the document', function () {
|
||||
$(document).trigger('click');
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,173 @@
|
||||
var InfowindowModel = require('../../../../src/geo/ui/infowindow-model');
|
||||
var InfowindowTemplate = require('../../../../src/geo/map/infowindow-template');
|
||||
|
||||
describe('geo/ui/infowindow-model', function () {
|
||||
it('should set a default template if template is empty', function () {
|
||||
var infowindowModel = new InfowindowModel({});
|
||||
|
||||
expect(infowindowModel.get('template')).toEqual(infowindowModel.DEFAULT_TEMPLATE);
|
||||
|
||||
infowindowModel = new InfowindowModel({ template: '' });
|
||||
|
||||
expect(infowindowModel.get('template')).toEqual(infowindowModel.DEFAULT_TEMPLATE);
|
||||
|
||||
infowindowModel = new InfowindowModel({ template: ' ' });
|
||||
|
||||
expect(infowindowModel.get('template')).toEqual(infowindowModel.DEFAULT_TEMPLATE);
|
||||
});
|
||||
|
||||
it('should NOT set a default template if template is present', function () {
|
||||
var infowindowModel = new InfowindowModel({ template: 'template' });
|
||||
|
||||
expect(infowindowModel.get('template')).toEqual('template');
|
||||
});
|
||||
|
||||
describe('.setContent', function () {
|
||||
it('should NOT include empty fields', function () {
|
||||
var infowindowModel = new InfowindowModel({ fields: [{ name: 'NAME', title: true }, { name: 'SOMETHING', title: true }] });
|
||||
infowindowModel.updateContent({ NAME: 'CartoDB' }, { showEmptyFields: false });
|
||||
|
||||
expect(infowindowModel.get('content').fields).toEqual([{ name: 'NAME', title: 'NAME', value: 'CartoDB', index: 0 }]);
|
||||
});
|
||||
|
||||
it('should include empty fields', function () {
|
||||
var infowindowModel = new InfowindowModel({ fields: [{ name: 'NAME', title: true }, { name: 'SOMETHING', title: true }] });
|
||||
infowindowModel.updateContent({ NAME: 'CartoDB' }, { showEmptyFields: true });
|
||||
|
||||
expect(infowindowModel.get('content').fields).toEqual([{ name: 'NAME', title: 'NAME', value: 'CartoDB', index: 0 }, { name: 'SOMETHING', title: 'SOMETHING', value: null, index: 1 }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.contentForFields', function () {
|
||||
it('should return the title and value of each field', function () {
|
||||
var attributes = { field1: 'value1' };
|
||||
var fields = [{ name: 'field1', title: true }];
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, {});
|
||||
|
||||
expect(content.fields.length).toEqual(1);
|
||||
expect(content.fields[0].title).toEqual('field1');
|
||||
expect(content.fields[0].value).toEqual('value1');
|
||||
});
|
||||
|
||||
it('should not return the title if not specified', function () {
|
||||
var attributes = { field1: 'value1' };
|
||||
var fields = [{ name: 'field1' }]; // Field doesn't have a title attribute
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, {});
|
||||
|
||||
expect(content.fields.length).toEqual(1);
|
||||
expect(content.fields[0].title).toEqual(null);
|
||||
});
|
||||
|
||||
it('should return the index of each field', function () {
|
||||
var attributes = { field1: 'value1', field2: 'value2' };
|
||||
var fields = [{ name: 'field1' }, { name: 'field2' }];
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, {});
|
||||
|
||||
expect(content.fields.length).toEqual(2);
|
||||
expect(content.fields[0].index).toEqual(0);
|
||||
expect(content.fields[1].index).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return empty fields', function () {
|
||||
var attributes = { field1: 'value1' };
|
||||
var fields = [{ name: 'field1' }, { name: 'field2' }];
|
||||
var options = { showEmptyFields: true };
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, options);
|
||||
|
||||
expect(content.fields.length).toEqual(2);
|
||||
expect(content.fields[0]).toEqual({
|
||||
name: 'field1',
|
||||
title: null,
|
||||
value: 'value1',
|
||||
index: 0
|
||||
});
|
||||
expect(content.fields[1]).toEqual({
|
||||
name: 'field2',
|
||||
title: null,
|
||||
value: null,
|
||||
index: 1
|
||||
});
|
||||
});
|
||||
|
||||
it('should not return empty fields', function () {
|
||||
var attributes = { field1: 'value1' };
|
||||
var fields = [{ name: 'field1' }, { name: 'field2' }];
|
||||
var options = { showEmptyFields: false };
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, options);
|
||||
|
||||
expect(content.fields.length).toEqual(1);
|
||||
expect(content.fields[0]).toEqual({
|
||||
name: 'field1',
|
||||
title: null,
|
||||
value: 'value1',
|
||||
index: 0
|
||||
});
|
||||
});
|
||||
|
||||
it('should not return fields with a null value', function () {
|
||||
var attributes = { field1: 'wadus', field2: null };
|
||||
var fields = [{ name: 'field1' }, { name: 'field2' }];
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, {});
|
||||
|
||||
expect(content.fields.length).toEqual(1);
|
||||
expect(content.fields[0]).toEqual({
|
||||
name: 'field1',
|
||||
title: null,
|
||||
value: 'wadus',
|
||||
index: 0
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the attributes as data', function () {
|
||||
var attributes = { field1: 'value1' };
|
||||
var fields = [{ name: 'field1' }];
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, {});
|
||||
|
||||
expect(content.data).toEqual(attributes);
|
||||
});
|
||||
|
||||
it('should return an empty field when no data is available', function () {
|
||||
var attributes = {};
|
||||
var fields = [{ name: 'field1' }, { name: 'field2' }];
|
||||
var content = InfowindowModel.contentForFields(attributes, fields, {});
|
||||
|
||||
expect(content.fields.length).toEqual(1);
|
||||
expect(content.fields[0]).toEqual({
|
||||
title: null,
|
||||
value: 'No data available',
|
||||
index: 0,
|
||||
type: 'empty'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setInfowindowTemplate', function () {
|
||||
it('should only pick and set specific attributes from the given template', function () {
|
||||
var infowindowModel = new InfowindowModel({ template: 'template' });
|
||||
infowindowModel.setInfowindowTemplate(new InfowindowTemplate({
|
||||
template: 'new_template',
|
||||
something: 'something'
|
||||
}));
|
||||
|
||||
expect(infowindowModel.get('template')).toEqual('new_template');
|
||||
expect(infowindowModel.get('something')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should reject attributes from the template that have a falsy value', function () {
|
||||
var infowindowModel = new InfowindowModel({ template: 'template' });
|
||||
infowindowModel.setInfowindowTemplate(new InfowindowTemplate({
|
||||
template: ''
|
||||
}));
|
||||
|
||||
// Attributes have NOT changed
|
||||
expect(infowindowModel.get('template')).toEqual('template');
|
||||
|
||||
infowindowModel.setInfowindowTemplate(new InfowindowTemplate({
|
||||
template: 'new_template'
|
||||
}));
|
||||
|
||||
// Atributtes have changed
|
||||
expect(infowindowModel.get('template')).toEqual('new_template');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,603 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var MapView = require('../../../../src/geo/map-view');
|
||||
var InfowindowModel = require('../../../../src/geo/ui/infowindow-model');
|
||||
var Infowindow = require('../../../../src/geo/ui/infowindow-view');
|
||||
|
||||
describe('geo/ui/infowindow-view', function () {
|
||||
var model, view, mapView, map;
|
||||
|
||||
beforeEach(function () {
|
||||
var container = $('<div>').css('height', '200px');
|
||||
|
||||
map = new Map(null, { layersFactory: {} });
|
||||
|
||||
mapView = new MapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerViewFactory: jasmine.createSpyObj('layerViewFactory', ['createLayerView']),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
model = new InfowindowModel({
|
||||
fields: [
|
||||
{ name: 'test1', position: 1, title: true },
|
||||
{ name: 'test2', position: 2, title: true }
|
||||
]
|
||||
});
|
||||
|
||||
view = new Infowindow({
|
||||
model: model,
|
||||
mapView: mapView
|
||||
});
|
||||
});
|
||||
|
||||
it('should add render when template changes', function () {
|
||||
spyOn(view, 'render');
|
||||
model.set('template', 'jaja');
|
||||
expect(view.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should change width of the infowindow when width attribute changes', function () {
|
||||
spyOn(view, 'render');
|
||||
view.model.set({
|
||||
'template': '<div class="js-infowindow"></div>',
|
||||
'width': 100
|
||||
});
|
||||
expect(view.$('.js-infowindow').css('width')).toBe('100px');
|
||||
});
|
||||
|
||||
it('shouldn\'t change width of the infowindow when width attribute is undefined', function () {
|
||||
spyOn(view, 'render');
|
||||
view.model.set({
|
||||
'template': '<div class="js-infowindow"></div>'
|
||||
});
|
||||
var previousWidth = view.$('.js-infowindow').css('width');
|
||||
|
||||
// Unset the width from the model
|
||||
view.model.unset('width');
|
||||
|
||||
// Width hasn't changed
|
||||
expect(view.$('.js-infowindow').css('width')).toBe(previousWidth);
|
||||
});
|
||||
|
||||
it('should change maxHeight of the infowindow when maxHeight attribute changes', function () {
|
||||
spyOn(view, 'render');
|
||||
view.model.set({
|
||||
template: '<div class="js-infowindow"><div class="js-content"></div></div>',
|
||||
maxHeight: 100
|
||||
});
|
||||
expect(view.$('.js-content').css('max-height')).toBe('100px');
|
||||
});
|
||||
|
||||
it('should render without alternative_name set', function () {
|
||||
var template = '<div class="js-infowindow">' +
|
||||
'<a href="#close" class="cartodb-popup-close-button close">x</a>' +
|
||||
'<div class="cartodb-popup-content-wrapper">' +
|
||||
'<div class="js-content">' +
|
||||
'<ul id="mylist"></ul>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="hook"></div>' +
|
||||
'</div>';
|
||||
|
||||
model.unset('alternative_names');
|
||||
model.set({
|
||||
content: {
|
||||
fields: [{
|
||||
title: 'test',
|
||||
value: true,
|
||||
position: 0,
|
||||
index: 0
|
||||
}]
|
||||
},
|
||||
template: template
|
||||
});
|
||||
|
||||
expect(view.render().$el.html().length).not.toBe(0);
|
||||
});
|
||||
|
||||
it('should render with alternative_name set', function () {
|
||||
model.set({
|
||||
content: {
|
||||
fields: [
|
||||
{ name: 'jamon1', title: 'jamon1_', value: 'jamon1' }
|
||||
]
|
||||
}
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('jamon1');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').text()).toEqual('jamon1_');
|
||||
});
|
||||
|
||||
it('should render without title', function () {
|
||||
model.set({
|
||||
content: {
|
||||
fields: [
|
||||
{ name: 'jamon1', title: null, value: 'jamon1' }
|
||||
]
|
||||
}
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('jamon1');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should convert value to string when it is a number', function () {
|
||||
model.set({
|
||||
content: {
|
||||
fields: [{
|
||||
title: 'jamon1',
|
||||
value: 0,
|
||||
index: 0
|
||||
}, {
|
||||
title: 'jamon2',
|
||||
value: 1,
|
||||
index: 1
|
||||
}]
|
||||
}
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('0');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').text()).toEqual('jamon1');
|
||||
var item2 = view.$el.find('.CDB-infowindow-listItem:nth-child(2)');
|
||||
expect(item2.find('.CDB-infowindow-title').text()).toEqual('1');
|
||||
expect(item2.find('.CDB-infowindow-subtitle').text()).toEqual('jamon2');
|
||||
});
|
||||
|
||||
it('should convert value to \'\' when it is undefined', function () {
|
||||
model.set({
|
||||
content: {
|
||||
fields: [{
|
||||
title: 'jamon', value: undefined
|
||||
}]
|
||||
}
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').text()).toEqual('jamon');
|
||||
});
|
||||
|
||||
it('should convert value to \'\' when it is null', function () {
|
||||
model.set('content', {
|
||||
fields: [{
|
||||
title: 'jamon',
|
||||
value: null
|
||||
}]
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').text()).toEqual('jamon');
|
||||
});
|
||||
|
||||
it('shouldn\'t convert the value if it is empty', function () {
|
||||
model.set('content', {
|
||||
fields: [{
|
||||
title: 'jamon',
|
||||
value: ''
|
||||
}]
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').text()).toEqual('jamon');
|
||||
});
|
||||
|
||||
it('should leave a string as it is', function () {
|
||||
model.set('content', {
|
||||
fields: [{
|
||||
title: 'jamon',
|
||||
value: 'jamon is testing'
|
||||
}]
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('jamon is testing');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').text()).toEqual('jamon');
|
||||
});
|
||||
|
||||
it('should convert value to string when it is a boolean', function () {
|
||||
model.set('content', {
|
||||
fields: [
|
||||
{ title: 'jamon1', value: false },
|
||||
{ title: 'jamon2', value: true }
|
||||
]
|
||||
}, { silent: true });
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.find('.CDB-infowindow-title').text()).toEqual('false');
|
||||
expect(item1.find('.CDB-infowindow-subtitle').text()).toEqual('jamon1');
|
||||
var item2 = view.$el.find('.CDB-infowindow-listItem:nth-child(2)');
|
||||
expect(item2.find('.CDB-infowindow-title').text()).toEqual('true');
|
||||
expect(item2.find('.CDB-infowindow-subtitle').text()).toEqual('jamon2');
|
||||
});
|
||||
|
||||
it('shouldn\'t convert the value if it is an object or an array', function () {
|
||||
var template = '<div class="js-infowindow">' +
|
||||
'<a href="#close" class="cartodb-popup-close-button close">x</a>' +
|
||||
'<div class="cartodb-popup-content-wrapper">' +
|
||||
'<div class="js-content">' +
|
||||
'<ul class="CDB-infowindow-listItem">{{#jamon1}}<li>{{jamon2}}, {{istrue}}, "{{isempty}}", {{isnum}}</li>{{/jamon1}}</ul>' +
|
||||
'<ul class="CDB-infowindow-listItem">{{#jamon3}}<li>{{.}}</li>{{/jamon3}}</ul>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="hook"></div>' +
|
||||
'</div>';
|
||||
|
||||
model.set({
|
||||
content: {
|
||||
fields: [
|
||||
{ name: 'jamon1', title: 'jamon1', value: [{ jamon2: 'jamon2', istrue: true, isempty: '', isnum: 9 }] },
|
||||
{ name: 'jamon3', title: 'jamon3', value: ['jamon4', 'jamon5'] }
|
||||
]
|
||||
},
|
||||
template: template,
|
||||
template_type: 'mustache'
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
var item1 = view.$el.find('.CDB-infowindow-listItem:nth-child(1)');
|
||||
expect(item1.text()).toContain('jamon2, true, "", 9');
|
||||
var item2 = view.$el.find('.CDB-infowindow-listItem:nth-child(2)');
|
||||
expect(item2.text()).toContain('jamon4jamon5');
|
||||
});
|
||||
|
||||
it('should close the infowindow when user clicks close button', function () {
|
||||
model.set({
|
||||
template: '<div><button class="js-close">X</button></div>'
|
||||
});
|
||||
view = new Infowindow({
|
||||
model: model,
|
||||
mapView: mapView
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
// Infowindow is visible
|
||||
model.set('visibility', true, { silent: true });
|
||||
expect(model.get('visibility')).toBe(true);
|
||||
|
||||
view.$('.js-close').click();
|
||||
|
||||
// Infowindow has been closed
|
||||
expect(model.get('visibility')).toBe(false);
|
||||
});
|
||||
|
||||
describe('custom template', function () {
|
||||
var model, view;
|
||||
|
||||
beforeEach(function () {
|
||||
var container = $('<div>').css('height', '200px');
|
||||
|
||||
map = new Map(null, { layersFactory: {} });
|
||||
|
||||
mapView = new MapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerViewFactory: jasmine.createSpyObj('layerViewFactory', ['createLayerView']),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
model = new InfowindowModel({
|
||||
template: '<div>{{ test1 }}</div>',
|
||||
fields: [
|
||||
{ title: 'test1', position: 1, value: 'x' },
|
||||
{ title: 'test2', position: 2, value: 'b' }
|
||||
]
|
||||
});
|
||||
|
||||
view = new Infowindow({
|
||||
model: model,
|
||||
mapView: mapView
|
||||
});
|
||||
});
|
||||
|
||||
it('should compile the template when changes', function () {
|
||||
view.model.set('template', '<div>{{test1}}</div>');
|
||||
expect(view.template({ test1: 'new' })).toEqual('<div>new</div>');
|
||||
});
|
||||
|
||||
it('should render properly when there is only a field without title', function () {
|
||||
view.model.set({
|
||||
template: ['{{#content.fields}}',
|
||||
'<li class="CDB-infowindow-listItem">',
|
||||
'{{#title}}<h5 class="CDB-infowindow-subtitle">{{title}}</h5>{{/title}}',
|
||||
'{{#value}}<h4 class="CDB-infowindow-title">{{{ value }}}</h4>{{/value}}',
|
||||
'{{^value}}<h4 class="CDB-infowindow-title">null</h4>{{/value}}',
|
||||
'</li>',
|
||||
'{{/content.fields}}'].join(' '),
|
||||
content: {
|
||||
fields: [
|
||||
{ name: 'test1', title: null, position: 0, value: 'jamon' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
view.render();
|
||||
expect(view.$el.html()).toContain('<li class="CDB-infowindow-listItem"> <h4 class="CDB-infowindow-title">jamon</h4> </li>');
|
||||
});
|
||||
|
||||
it('should render with alternative_name set', function () {
|
||||
view.model.set({
|
||||
template: ['{{#content.fields}}',
|
||||
'<li class="CDB-infowindow-listItem">',
|
||||
'{{#title}}<h5 class="CDB-infowindow-subtitle">{{title}}</h5>{{/title}}',
|
||||
'{{#value}}<h4 class="CDB-infowindow-title">{{{ value }}}</h4>{{/value}}',
|
||||
'{{^value}}<h4 class="CDB-infowindow-title">null</h4>{{/value}}',
|
||||
'</li>',
|
||||
'{{/content.fields}}'].join(' '),
|
||||
content: {
|
||||
fields: [
|
||||
{ name: 'test1', title: 'test1_', value: 'test1' }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
view.render();
|
||||
expect(view.$el.html()).toContain('<h5 class="CDB-infowindow-subtitle">test1_</h5> <h4 class="CDB-infowindow-title">test1</h4>');
|
||||
});
|
||||
|
||||
it('shouldn\'t sanitize the fields', function () {
|
||||
spyOn(view, '_sanitizeField');
|
||||
view.render();
|
||||
expect(view._sanitizeField).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should sanitize the template output by default', function () {
|
||||
view.model.set('template', 'no <iframe src="" onload="document.body.appendChild(document.createElement(\'script\')).src=\'http://localhost/xss.js\'"/> no');
|
||||
view.render();
|
||||
expect(view.$el.html()).toEqual('no ');
|
||||
});
|
||||
|
||||
it('should allow to override sanitization', function () {
|
||||
view.model.set({
|
||||
template: 'no <iframe src="" onload="document.body.appendChild(document.createElement(\'script\')).src=\'http://localhost/xss.js\'"/> no',
|
||||
sanitizeTemplate: false
|
||||
});
|
||||
view.render();
|
||||
expect(view.$el.html()).toEqual('no <iframe src="" onload="document.body.appendChild(document.createElement(\'script\')).src=\'http://localhost/xss.js\'"></iframe> no');
|
||||
|
||||
view.model.set('sanitizeTemplate', null);
|
||||
view.render();
|
||||
expect(view.$el.html()).toEqual('no <iframe src="" onload="document.body.appendChild(document.createElement(\'script\')).src=\'http://localhost/xss.js\'"></iframe> no');
|
||||
|
||||
var customSanitizeSpy = jasmine.createSpy('sanitizeTemplateSpy').and.returnValue('<p>custom sanitizied result</p>');
|
||||
view.model.set('sanitizeTemplate', customSanitizeSpy);
|
||||
expect(customSanitizeSpy).toHaveBeenCalledWith('no <iframe src="" onload="document.body.appendChild(document.createElement(\'script\')).src=\'http://localhost/xss.js\'"/> no');
|
||||
view.render();
|
||||
expect(view.$el.html()).toEqual('<p>custom sanitizied result</p>');
|
||||
|
||||
view.model.set('sanitizeTemplate', undefined);
|
||||
view.render();
|
||||
expect(view.$el.html()).toEqual('no ');
|
||||
});
|
||||
});
|
||||
|
||||
describe('image template', function () {
|
||||
var model, view, container, fields, fieldsWithoutURL, fieldsWithInvalidURL, url;
|
||||
|
||||
beforeEach(function () {
|
||||
container = $('<div>').css('height', '200px');
|
||||
url = 'http://fake.url/image.jpg';
|
||||
|
||||
fields = [
|
||||
{ title: 'test1', position: 1, value: 'http://fake.url/image.jpg' },
|
||||
{ title: 'test2', position: 2, value: 'b' }
|
||||
];
|
||||
|
||||
fieldsWithInvalidURL = [
|
||||
{ title: 'test1', position: 1, value: 'invalid_url' },
|
||||
{ title: 'test2', position: 2, value: 'b' }
|
||||
];
|
||||
|
||||
fieldsWithoutURL = [
|
||||
{ title: 'test1', position: 1, value: 'x' },
|
||||
{ title: 'test2', position: 2, value: 'b' }
|
||||
];
|
||||
|
||||
map = new Map(null, { layersFactory: {} });
|
||||
|
||||
mapView = new MapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerViewFactory: jasmine.createSpyObj('layerViewFactory', ['createLayerView']),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
model = new InfowindowModel({
|
||||
content: {
|
||||
fields: fields
|
||||
}
|
||||
});
|
||||
|
||||
view = new Infowindow({
|
||||
model: model,
|
||||
mapView: mapView
|
||||
});
|
||||
});
|
||||
|
||||
it('should get the cover url', function () {
|
||||
expect(view._getCoverURL()).toEqual(url);
|
||||
});
|
||||
|
||||
it('should validate the cover url', function () {
|
||||
var url = view._getCoverURL();
|
||||
expect(view._isValidURL(url)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should accept google chart URLS in the cover', function () {
|
||||
var url = 'http://chart.googleapis.com/chart?chxl=0:|1990%2F92|2001%2F03|2011%2F13&chxr=1,0,75&chxs=0,676767,11.5,0.5,lt,676767&chxt=x,y&chs=279x210&cht=lc&chco=FF0000&chds=0,69&chd=t:9.5,12.8,15.1,14.6,12.9,10.2,9.5,8.2,7.4,6.2,6,6.5,7.1,7.5,7.9,8,8.2,7.9,7.5,6.9,6.3,5.6&chg=-1,0,0,4&chls=1&chma=0,0,0,25&chm=B,EFEFEF,0,0,0&chtt=Malnourishment+in+&chts=676767,14';
|
||||
expect(view._isValidURL(url)).toEqual(true);
|
||||
});
|
||||
|
||||
it('shouldn\'t modify the height of the cover when there are several fields', function () {
|
||||
model.set('content', { fields: fieldsWithoutURL });
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover" style="height:123px"><div class="CDB-hook"></div></div>');
|
||||
expect(view._containsCover()).toEqual(true);
|
||||
expect(view.$('.js-cover').height()).toEqual(123);
|
||||
expect(view.$('.CDB-hook img').length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should add the image cover class in the custom template', function () {
|
||||
spyOn(view, '_loadCoverFromTemplate').and.callThrough();
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover" style="height: 123px"><img src="http://fake.url" style="height: 100px"></div><div class="CDB-hook"></div></div>');
|
||||
expect(view._loadCoverFromTemplate).toHaveBeenCalled();
|
||||
expect(view._containsCover()).toEqual(true);
|
||||
expect(view.$('.CDB-infowindow-media-item').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should setup the hook correctly', function () {
|
||||
spyOn(view, '_loadCoverFromUrl').and.callThrough();
|
||||
model.set('content', { fields: fields });
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover"></div><div class="CDB-hook"></div></div>');
|
||||
|
||||
expect(view._loadCoverFromUrl).toHaveBeenCalled();
|
||||
|
||||
view._onLoadImageSuccess();
|
||||
expect(view.$('.CDB-hook img').length).toEqual(1);
|
||||
expect(view.$('.CDB-hook img').attr('src')).toEqual('http://fake.url/image.jpg');
|
||||
});
|
||||
|
||||
it('should detect if the infowindow has a cover', function () {
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover"></div></div>');
|
||||
expect(view._containsCover()).toEqual(true);
|
||||
});
|
||||
|
||||
it('should render the loader for infowindows with cover', function () {
|
||||
model.set('content', { fields: fields });
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover"></div></div>');
|
||||
expect(view.$('.js-cover .js-loader').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should append the image', function () {
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover"></div></div>');
|
||||
expect(view.$('img').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('shouldn\'t append an image if it\'s not valid', function () {
|
||||
model.set('content', { fields: fieldsWithoutURL });
|
||||
model.set('template', '<div class="js-infowindow header" data-cover="true"><div class="js-cover"></div></div>');
|
||||
expect(view.$('img').length).toEqual(0);
|
||||
});
|
||||
|
||||
it('shouldn\'t append the image if the theme doesn\'t have cover', function () {
|
||||
model.set('content', { fields: fields });
|
||||
model.set('template', '<div class="js-cover"></div>');
|
||||
expect(view.$('img').length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should append a non-valid error message if the image is not valid', function () {
|
||||
model.set('content', { fields: fieldsWithInvalidURL });
|
||||
model.set('template', '<div class="js-infowindow header" data-cover="true"><div class="js-cover"></div></div>');
|
||||
expect(view.$el.find('.CDB-infowindow-fail').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add header class', function () {
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-header"></div></div>');
|
||||
expect(view.$el.find('.has-header').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add has-header-image class', function () {
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover"></div></div>');
|
||||
expect(view.$el.find('.has-header-image').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add has-fields class', function () {
|
||||
model.set('content', { fields: fields });
|
||||
model.set('template', '<div class="js-infowindow"><div class="js-content"></div></div>');
|
||||
expect(view.$el.find('.has-fields').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should load image hook if fields is 2 or less and image height is equal or less than content height', function () {
|
||||
model.set('template', '<div class="js-infowindow" data-cover="true"><div class="js-cover" style="height: 123px"><img src="http://fake.url" class="CDB-infowindow-media-item"></div><div class="CDB-hook"></div></div>');
|
||||
spyOn(view, '_loadImageHook').and.callThrough();
|
||||
|
||||
view.$el.height(100);
|
||||
view.$('.CDB-infowindow-media-item').height(200);
|
||||
view._onLoadImageSuccess();
|
||||
expect(view._loadImageHook).toHaveBeenCalled();
|
||||
|
||||
view.$('.CDB-infowindow-media-item').height(90);
|
||||
view._loadImageHook.calls.reset();
|
||||
view._onLoadImageSuccess();
|
||||
expect(view._loadImageHook).not.toHaveBeenCalled();
|
||||
|
||||
view.$('.CDB-infowindow-media-item').height(200);
|
||||
view._loadImageHook.calls.reset();
|
||||
fields.push({ title: 'test3', position: 3, value: 'c' });
|
||||
model.set('fields', fields);
|
||||
view._onLoadImageSuccess();
|
||||
expect(view._loadImageHook).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop the loader and show an error if url is invalid', function () {
|
||||
spyOn(view, '_stopCoverLoader').and.callThrough();
|
||||
spyOn(view, '_showInfowindowImageError').and.callThrough();
|
||||
model.set({
|
||||
fields: fieldsWithInvalidURL,
|
||||
template: '<div class="js-infowindow" data-cover="true"><div class="js-cover" style="height: 123px"><img src="invalid.url" style="height: 100px"></div><div class="CDB-hook"></div></div>'
|
||||
});
|
||||
view.render();
|
||||
expect(view._stopCoverLoader).toHaveBeenCalled();
|
||||
expect(view._showInfowindowImageError).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should stop the loader and show an error if url is invalid', function () {
|
||||
spyOn(view, '_stopCoverLoader').and.callThrough();
|
||||
spyOn(view, '_showInfowindowImageError').and.callThrough();
|
||||
model.set({
|
||||
fields: fieldsWithInvalidURL,
|
||||
template: '<div class="js-infowindow" data-cover="true"><div class="js-cover" style="height: 123px"><img src="invalid.url" style="height: 100px"></div><div class="CDB-hook"></div></div>'
|
||||
});
|
||||
view.render();
|
||||
expect(view._stopCoverLoader).toHaveBeenCalled();
|
||||
expect(view._showInfowindowImageError).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load the cover from template if it already contains the template', function () {
|
||||
spyOn(view, '_loadCoverFromTemplate').and.callThrough();
|
||||
model.set({
|
||||
fields: fieldsWithInvalidURL,
|
||||
template: '<div class="js-infowindow" data-cover="true"><div class="js-cover" style="height: 123px"><img src="http://fake.url" style="height: 100px"></div><div class="CDB-hook"></div></div>'
|
||||
});
|
||||
view.render();
|
||||
expect(view._loadCoverFromTemplate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load the cover from url if it doesn\'t contain the template', function () {
|
||||
spyOn(view, '_loadCoverFromUrl').and.callThrough();
|
||||
model.set({
|
||||
fields: fieldsWithInvalidURL,
|
||||
template: '<div class="js-infowindow" data-cover="true"><div class="CDB-hook"></div></div>'
|
||||
});
|
||||
view.render();
|
||||
expect(view._loadCoverFromUrl).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,132 @@
|
||||
var LegendViewBase = require('../../../../../../src/geo/ui/legends/base/legend-view-base.js');
|
||||
var LegendModelBase = require('../../../../../../src/geo/map/legends/legend-model-base.js');
|
||||
var createEngine = require('../../../../fixtures/engine.fixture.js');
|
||||
|
||||
var MyLegendModel = LegendModelBase.extend({
|
||||
TYPE: 'something',
|
||||
|
||||
isAvailable: function () {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
var MyLegendView = LegendViewBase.extend({
|
||||
_getCompiledTemplate: function () {
|
||||
return '<h1>It Works!</h1>';
|
||||
}
|
||||
});
|
||||
|
||||
describe('geo/ui/legends/legend-view-base.js', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
this.model = new MyLegendModel({
|
||||
title: 'My Beautiful Legend',
|
||||
preHTMLSnippet: '<p>before</p>',
|
||||
postHTMLSnippet: '<p>after</p>',
|
||||
visible: true
|
||||
}, {
|
||||
engine: engineMock
|
||||
});
|
||||
|
||||
this.myLegend = new MyLegendView({
|
||||
model: this.model,
|
||||
placeholderTemplate: function () {
|
||||
return '<p>Placeholder</p>';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('if model is loading', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'loading');
|
||||
this.myLegend.render();
|
||||
});
|
||||
|
||||
it('should mark legend as loading', function () {
|
||||
expect(this.myLegend.$el.hasClass('is-loading')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should only render a placeholder', function () {
|
||||
expect(this.myLegend.$el.html()).toEqual('<p>Placeholder</p>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('if model has errors', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'error');
|
||||
this.myLegend.render();
|
||||
});
|
||||
|
||||
it('should NOT mark legend as loading', function () {
|
||||
expect(this.myLegend.$el.hasClass('is-loading')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should render a placeholder', function () {
|
||||
expect(this.myLegend.$el.html()).toMatch('Placeholder');
|
||||
});
|
||||
|
||||
it('should render an error', function () {
|
||||
expect(this.myLegend.$el.html()).toMatch('Something went wrong');
|
||||
});
|
||||
});
|
||||
|
||||
describe('if model has been loaded and has no data', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'success');
|
||||
spyOn(this.model, 'isAvailable').and.returnValue(false);
|
||||
this.myLegend.render();
|
||||
});
|
||||
|
||||
it('should NOT mark legend as loading', function () {
|
||||
expect(this.myLegend.$el.hasClass('is-loading')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should render a placeholder', function () {
|
||||
expect(this.myLegend.$el.html()).toMatch('Placeholder');
|
||||
});
|
||||
|
||||
it('should render a warning', function () {
|
||||
expect(this.myLegend.$el.html()).toMatch('No data available');
|
||||
});
|
||||
});
|
||||
|
||||
describe('if model has been loaded and has data', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'success');
|
||||
this.myLegend.render();
|
||||
});
|
||||
|
||||
it('should NOT mark legend as loading', function () {
|
||||
expect(this.myLegend.$el.hasClass('is-loading')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should NOT render a placeholder', function () {
|
||||
expect(this.myLegend.$el.html()).not.toMatch('Placeholder');
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
var html = this.myLegend.$el.html().split('\n');
|
||||
expect(html[0]).toMatch('My Beautiful Legend');
|
||||
expect(html[1]).toEqual('<p>before</p>');
|
||||
expect(html[2]).toEqual('<h1>It Works!</h1>');
|
||||
expect(html[3]).toEqual('<p>after</p>');
|
||||
});
|
||||
|
||||
it('should sanitize preHTMLSnippet, compiled template and postHTMLSnippet', function () {
|
||||
this.model.set({
|
||||
preHTMLSnippet: '<p>before<script>alert("before");</script></p>',
|
||||
postHTMLSnippet: '<p>after<script>alert("after");</script></p>'
|
||||
});
|
||||
|
||||
spyOn(this.myLegend, '_getCompiledTemplate').and.returnValue('<h1>It Works!<script>alert("It Works!");</script></h1>');
|
||||
|
||||
this.myLegend.render();
|
||||
|
||||
var html = this.myLegend.$el.html().split('\n');
|
||||
expect(html[1]).toEqual('<p>before</p>');
|
||||
expect(html[2]).toEqual('<h1>It Works!</h1>');
|
||||
expect(html[3]).toEqual('<p>after</p>');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
var LegendViewBubble = require('../../../../../../src/geo/ui/legends/bubble/legend-view.js');
|
||||
var BubbleLegendModel = require('../../../../../../src/geo/map/legends/bubble-legend-model.js');
|
||||
var createEngine = require('../../../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/ui/legends/bubbles/legend-view.js', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
this.model = new BubbleLegendModel({
|
||||
title: 'Bubble',
|
||||
type: 'bubble',
|
||||
avg: 30,
|
||||
fillColor: '#fabada',
|
||||
postHTMLSnippet: '',
|
||||
preHTMLSnippet: '',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
sizes: [2, 4, 8],
|
||||
values: [5, 10, 20, 40],
|
||||
visible: true
|
||||
}, {
|
||||
engine: engineMock
|
||||
});
|
||||
|
||||
spyOn(this.model, 'isAvailable').and.returnValue(true);
|
||||
|
||||
this.legendView = new LegendViewBubble({
|
||||
model: this.model,
|
||||
placeholderTemplate: function () {
|
||||
return '<p>Placeholder</p>';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'success');
|
||||
this.legendView.render();
|
||||
});
|
||||
|
||||
it('should render bubbles', function () {
|
||||
expect(this.legendView.$('.js-bubbleItem').length).toBe(4);
|
||||
expect(this.legendView._calculateBubbleSizes()).toEqual([100, 50, 25]);
|
||||
});
|
||||
|
||||
it('should place avg properly', function () {
|
||||
// values: [5, 10, 20, 40];
|
||||
// range: [0, 25, 50, 100];
|
||||
|
||||
this.model.set('avg', 5); // at the beginning of range [0, 25]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(0);
|
||||
|
||||
this.model.set('avg', 7.5); // in the middle of range [0, 25]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(12.5);
|
||||
|
||||
this.model.set('avg', 10); // at the end of range [0, 25]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(25);
|
||||
|
||||
this.model.set('avg', 15); // in the middle of range [25, 50]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(37.5);
|
||||
|
||||
this.model.set('avg', 19); // almost at the top of [25, 50]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(25 + (50 - 25) * (9 / 10));
|
||||
|
||||
this.model.set('avg', 25); // in a quarter of range [50, 100]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(62.5);
|
||||
|
||||
this.model.set('avg', 30); // in the middle of range [50, 100]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(75); // (50 + (100 - 50) * 0.5)
|
||||
|
||||
this.model.set('avg', 35); // in the three quarter of range [50, 100]
|
||||
expect(this.legendView._calculateAverageSize()).toBe(87.5); // (50 + (100 - 50) * (15 / 20)
|
||||
|
||||
this.model.set('avg', 40);
|
||||
expect(this.legendView._calculateAverageSize()).toBe(100);
|
||||
});
|
||||
|
||||
it('should render custom labels properly', function () {
|
||||
this.model.set('topLabel', 'foo');
|
||||
expect(this.legendView.$('.Bubble-numbersItem').length).toBe(1);
|
||||
expect(this.legendView.$('.Bubble-numbersItem').eq(0).text()).toBe('foo');
|
||||
expect(this.legendView.$('.Bubble-average').length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
var CustomLegendViewChoropleth = require('../../../../../../src/geo/ui/legends/custom-choropleth/legend-view.js');
|
||||
var ChoroplethLegendModel = require('../../../../../../src/geo/map/legends/choropleth-legend-model.js');
|
||||
var createEngine = require('../../../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/ui/legends/custom-choropleth/legend-view.js', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
|
||||
this.model = new ChoroplethLegendModel({
|
||||
title: 'Foo',
|
||||
type: ' choropleth',
|
||||
postHTMLSnippet: '',
|
||||
preHTMLSnippet: '',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
leftLabel: 'low',
|
||||
rightLabel: 'high',
|
||||
colors: [
|
||||
{
|
||||
label: '1',
|
||||
value: '#ffc6c4'
|
||||
}, {
|
||||
label: '',
|
||||
value: '#ee919b'
|
||||
}, {
|
||||
label: '',
|
||||
value: '#cc607d'
|
||||
}, {
|
||||
label: '',
|
||||
value: '#9e3963'
|
||||
}, {
|
||||
label: '127',
|
||||
value: '#672044'
|
||||
}
|
||||
],
|
||||
visible: true
|
||||
}, {
|
||||
engine: engineMock
|
||||
});
|
||||
|
||||
spyOn(this.model, 'isAvailable').and.returnValue(true);
|
||||
|
||||
this.legendView = new CustomLegendViewChoropleth({
|
||||
model: this.model,
|
||||
placeholderTemplate: function () {
|
||||
return '<p>Placeholder</p>';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'success');
|
||||
this.legendView.render();
|
||||
});
|
||||
|
||||
it('should render choropleth', function () {
|
||||
expect(this.legendView.$('.Legend-choropleth').length).toBe(1);
|
||||
expect(this.legendView.$('h3').text()).toContain('Foo');
|
||||
expect(this.legendView.$('h3 ~ div p').length).toBe(2);
|
||||
expect(this.legendView.$('h3 ~ div p').length).toBe(2);
|
||||
expect(this.legendView.$('h3 ~ div p').eq(0).text()).toContain('low');
|
||||
expect(this.legendView.$('h3 ~ div p').eq(1).text()).toContain('high');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
var LegendViewChoropleth = require('../../../../../../src/geo/ui/legends/choropleth/legend-view.js');
|
||||
var ChoroplethLegendModel = require('../../../../../../src/geo/map/legends/choropleth-legend-model.js');
|
||||
var createEngine = require('../../../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/ui/legends/choropleth/legend-view.js', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
|
||||
this.model = new ChoroplethLegendModel({
|
||||
title: 'Foo',
|
||||
type: ' choropleth',
|
||||
avg: 64,
|
||||
postHTMLSnippet: '',
|
||||
preHTMLSnippet: '',
|
||||
prefix: '',
|
||||
suffix: '',
|
||||
colors: [
|
||||
{
|
||||
label: '1',
|
||||
value: '#ffc6c4'
|
||||
}, {
|
||||
label: '',
|
||||
value: '#ee919b'
|
||||
}, {
|
||||
label: '',
|
||||
value: '#cc607d'
|
||||
}, {
|
||||
label: '',
|
||||
value: '#9e3963'
|
||||
}, {
|
||||
label: '127',
|
||||
value: '#672044'
|
||||
}
|
||||
],
|
||||
min: 1,
|
||||
max: 127,
|
||||
visible: true
|
||||
}, {
|
||||
engine: engineMock
|
||||
});
|
||||
|
||||
spyOn(this.model, 'isAvailable').and.returnValue(true);
|
||||
|
||||
this.legendView = new LegendViewChoropleth({
|
||||
model: this.model,
|
||||
placeholderTemplate: function () {
|
||||
return '<p>Placeholder</p>';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'success');
|
||||
this.legendView.render();
|
||||
});
|
||||
|
||||
it('should render choropleth', function () {
|
||||
expect(this.legendView.$('.Legend-choropleth').length).toBe(1);
|
||||
expect(this.legendView.$('.Legend-choroplethAverage').length).toBe(1);
|
||||
expect(this.legendView.$('.Legend-choroplethAverage').text()).toContain('64');
|
||||
expect(this.legendView.$('h3').text()).toContain('Foo');
|
||||
expect(this.legendView.$('h3 ~ div p').length).toBe(2);
|
||||
expect(this.legendView.$('h3 ~ div p').length).toBe(2);
|
||||
expect(this.legendView.$('h3 ~ div p').eq(0).text()).toContain('1');
|
||||
expect(this.legendView.$('h3 ~ div p').eq(1).text()).toContain('127');
|
||||
});
|
||||
|
||||
it('should hide AVG if custom labels', function () {
|
||||
this.model.set('leftLabel', 'Bar');
|
||||
|
||||
expect(this.legendView.$('.Legend-choroplethAverage').length).toBe(0);
|
||||
expect(this.legendView.$('h3 ~ div p').eq(0).text()).toContain('Bar');
|
||||
expect(this.legendView.$('h3 ~ div p').eq(1).text()).toContain('127');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
var $ = require('jquery');
|
||||
var ImgLoaderView = require('../../../../../../src/geo/ui/legends/base/img-loader-view.js');
|
||||
|
||||
describe('geo/ui/legends/custom/img-loader-view', function () {
|
||||
var svgResponse = {
|
||||
status: 200,
|
||||
contentType: 'image/svg+xml',
|
||||
responseText: '<svg xmlns:a="genius.com" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"><path></path></svg>'
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
jasmine.Ajax.install();
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/logo.svg.*'))
|
||||
.andReturn(svgResponse);
|
||||
|
||||
this.svgUrl = 'http://image.io/logo.svg';
|
||||
this.color = '#cebada';
|
||||
|
||||
var $el = $('<div class="js-image-container" data-icon="' + this.svgUrl + '" data-color="' + this.color + '">');
|
||||
|
||||
this.imageClass = 'Legend-fillImageAsset';
|
||||
this.view = new ImgLoaderView({
|
||||
el: $el,
|
||||
imageClass: this.imageClass
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
describe('._loadImage', function () {
|
||||
it('should render resource if format is not SVG', function () {
|
||||
this.imgUrl = 'http://www.imageserver.com/image.png';
|
||||
|
||||
var $pngEl = $('<div class="js-image-container" data-icon="' + this.imgUrl + '" data-color="' + this.color + '">');
|
||||
|
||||
this.imageClass = 'Legend-fillImageAsset';
|
||||
var view = new ImgLoaderView({
|
||||
el: $pngEl,
|
||||
imageClass: this.imageClass
|
||||
});
|
||||
|
||||
view._loadImage();
|
||||
|
||||
var $img = view.$('img');
|
||||
var classes = $img.attr('class');
|
||||
var src = $img.attr('src');
|
||||
var crossOrigin = $img.attr('crossOrigin');
|
||||
$img.empty(); // To avoid DOM requests to the image file
|
||||
|
||||
expect(classes.indexOf('js-image') > -1).toBe(true);
|
||||
expect(classes.indexOf(this.imageClass) > -1).toBe(true);
|
||||
expect(src).toBe(this.imgUrl + '?req=markup');
|
||||
expect(crossOrigin).toBe('anonymous');
|
||||
});
|
||||
|
||||
it('should render SVG tag if resource is SVG file', function () {
|
||||
this.view._loadImage();
|
||||
|
||||
var $svg = this.view.$('svg');
|
||||
var classes = $svg.attr('class');
|
||||
var svgFill = $svg.css('fill').toLowerCase();
|
||||
var pathFill = $svg.find('path')[0].style['fill'].toLowerCase();
|
||||
|
||||
expect($svg.length).toBe(1);
|
||||
expect(classes.indexOf('js-image') > -1).toBe(true);
|
||||
expect(classes.indexOf(this.imageClass) > -1).toBe(true);
|
||||
expect(svgFill === 'rgb(206, 186, 218)' || svgFill === this.color).toBe(true);
|
||||
expect(pathFill).toBe('inherit');
|
||||
});
|
||||
});
|
||||
|
||||
describe('._requestImage', function () {
|
||||
var obj = {
|
||||
callback: function () {}
|
||||
};
|
||||
|
||||
it('successful caches the response and calls the callback', function () {
|
||||
var expectedUrl = this.svgUrl + '?req=ajax';
|
||||
spyOn(obj, 'callback');
|
||||
this.view._lastImage.url = null;
|
||||
this.view._lastImage.content = null;
|
||||
jasmine.Ajax.requests.reset();
|
||||
|
||||
this.view._requestImage(this.svgUrl, obj.callback);
|
||||
|
||||
expect(jasmine.Ajax.requests.mostRecent().url).toBe(expectedUrl);
|
||||
expect(obj.callback).toHaveBeenCalled();
|
||||
expect(this.view._lastImage.url).toBe(expectedUrl);
|
||||
expect(this.view._lastImage.content).toBeDefined();
|
||||
});
|
||||
|
||||
it('_requestImage with cached response, does not make an Ajax call and it calls the callback', function () {
|
||||
var expectedUrl = this.svgUrl + '?req=ajax';
|
||||
spyOn(obj, 'callback');
|
||||
|
||||
this.view._requestImage(this.svgUrl, obj.callback);
|
||||
jasmine.Ajax.requests.reset();
|
||||
this.view._requestImage(this.svgUrl, obj.callback);
|
||||
|
||||
expect(jasmine.Ajax.requests.mostRecent()).toBeUndefined();
|
||||
expect(obj.callback).toHaveBeenCalled();
|
||||
expect(this.view._lastImage.url).toBe(expectedUrl);
|
||||
expect(this.view._lastImage.content).toBeDefined();
|
||||
});
|
||||
|
||||
it('_requestImage with error response, throws an error', function () {
|
||||
this.view._lastImage.url = null;
|
||||
this.view._lastImage.content = null;
|
||||
jasmine.Ajax.stubRequest(new RegExp('^http(s)?.*/logo.svg.*'))
|
||||
.andReturn({ status: 500 });
|
||||
|
||||
var foo = function () {
|
||||
this.view._requestImage(this.svgUrl, obj.callback);
|
||||
};
|
||||
|
||||
expect(foo).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._isSVG', function () {
|
||||
it('behaves properly', function () {
|
||||
expect(this.view._isSVG('http://image.io/image.svg')).toBe(true);
|
||||
expect(this.view._isSVG('http://image.io/image.svg?req=ajax')).toBe(true);
|
||||
expect(this.view._isSVG('http://image.io/image.png')).toBe(false);
|
||||
expect(this.view._isSVG('http://image.io/image.png?req=markup')).toBe(false);
|
||||
expect(this.view._isSVG('')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
var LegendViewCustom = require('../../../../../../src/geo/ui/legends/custom/legend-view.js');
|
||||
var CustomLegendModel = require('../../../../../../src/geo/map/legends/custom-legend-model.js');
|
||||
var createEngine = require('../../../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/ui/legends/custom/legend-view.js', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
|
||||
this.model = new CustomLegendModel({
|
||||
title: 'Foo',
|
||||
type: 'custom',
|
||||
html: '',
|
||||
postHTMLSnippet: '',
|
||||
preHTMLSnippet: '',
|
||||
items: [
|
||||
{
|
||||
title: 'foo',
|
||||
color: '#ffc6c4'
|
||||
}, {
|
||||
title: 'bar',
|
||||
color: '#ff6600'
|
||||
}, {
|
||||
title: 'bar',
|
||||
color: '#ff6600',
|
||||
icon: 'https://s3.amazonaws.com/com.cartodb.users-assets.production/maki-icons/circle-stroked-18.svg'
|
||||
}
|
||||
],
|
||||
visible: true
|
||||
}, {
|
||||
engine: engineMock
|
||||
});
|
||||
|
||||
spyOn(this.model, 'isAvailable').and.returnValue(true);
|
||||
|
||||
this.legendView = new LegendViewCustom({
|
||||
model: this.model,
|
||||
placeholderTemplate: function () {
|
||||
return '<p>Placeholder</p>';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
beforeEach(function () {
|
||||
this.model.set('state', 'success');
|
||||
this.legendView.render();
|
||||
});
|
||||
|
||||
it('should render custom', function () {
|
||||
expect(this.legendView.$('li').length).toBe(3);
|
||||
expect(this.legendView.$('.Legend-categoryCircle').length).toBe(2);
|
||||
expect(this.legendView.$('.Legend-categoryIcon').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should render custom html', function () {
|
||||
this.model.set('html', '<ul><li>Foo</li></ul>');
|
||||
this.legendView.render();
|
||||
|
||||
expect(this.legendView.$('li').length).toBe(1);
|
||||
expect(this.legendView.$('.Legend-categoryCircle').length).toBe(0);
|
||||
expect(this.legendView.$('li').eq(0).text()).toContain('Foo');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,109 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var LayerLegendsView = require('../../../../../src/geo/ui/legends/layer-legends-view');
|
||||
var CartoDBLayer = require('../../../../../src/geo/map/cartodb-layer');
|
||||
|
||||
describe('geo/ui/legends/layer-legends-view', function () {
|
||||
beforeEach(function () {
|
||||
var engineMock = new Backbone.Model();
|
||||
engineMock.reload = jasmine.createSpy('reload');
|
||||
|
||||
this.settingsModel = new Backbone.Model({
|
||||
showLegends: true,
|
||||
showLayerSelector: true,
|
||||
layerSelectorEnabled: true
|
||||
});
|
||||
|
||||
this.cartoDBLayer = new CartoDBLayer({
|
||||
layer_name: 'CartoDB Layer #1',
|
||||
legends: [
|
||||
{ type: 'bubble', title: 'Bubble Legend' },
|
||||
{ type: 'category', title: 'Category Legend' }
|
||||
]
|
||||
}, { engine: engineMock });
|
||||
|
||||
this.tryContainerVisibility = jasmine.createSpy('tryContainerVisibility');
|
||||
|
||||
this.layerLegendsView = new LayerLegendsView({
|
||||
model: this.cartoDBLayer,
|
||||
settingsModel: this.settingsModel,
|
||||
tryContainerVisibility: this.tryContainerVisibility
|
||||
});
|
||||
|
||||
this.layerLegendsView.render();
|
||||
|
||||
$('body').append(this.layerLegendsView.$el);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.layerLegendsView.$el.remove();
|
||||
});
|
||||
|
||||
it('should render all legends', function () {
|
||||
// Legends of all types have been rendered
|
||||
expect(this.layerLegendsView.$('.CDB-Legend-item').length).toEqual(6);
|
||||
});
|
||||
|
||||
it('should trigger a "render" event when the view is rendered', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.layerLegendsView.on('render', callback);
|
||||
|
||||
this.layerLegendsView.render();
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update the name of the layer when it changes', function () {
|
||||
expect(this.layerLegendsView.$el.html()).toMatch('CartoDB Layer #1');
|
||||
|
||||
this.cartoDBLayer.set('layer_name', 'A NEW layer name');
|
||||
|
||||
expect(this.layerLegendsView.$el.html()).not.toMatch('CartoDB Layer #1');
|
||||
expect(this.layerLegendsView.$el.html()).toMatch('A NEW layer name');
|
||||
});
|
||||
|
||||
it('should hide/show the layer if check next to title is clicked', function () {
|
||||
expect(this.cartoDBLayer.isVisible()).toBeTruthy();
|
||||
|
||||
this.layerLegendsView.$('.js-toggle-layer').trigger('click');
|
||||
|
||||
expect(this.cartoDBLayer.isVisible()).toBeFalsy();
|
||||
|
||||
this.layerLegendsView.$('.js-toggle-layer').trigger('click');
|
||||
|
||||
expect(this.cartoDBLayer.isVisible()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should uncheck/check the check if layer is hidden/shown', function () {
|
||||
expect(this.layerLegendsView.$('.js-toggle-layer').is(':checked')).toBe(true);
|
||||
|
||||
this.cartoDBLayer.hide();
|
||||
|
||||
expect(this.layerLegendsView.$('.js-toggle-layer').is(':checked')).toBe(false);
|
||||
|
||||
this.cartoDBLayer.show();
|
||||
|
||||
expect(this.layerLegendsView.$('.js-toggle-layer').is(':checked')).toBe(true);
|
||||
});
|
||||
|
||||
it('should hide/show legend views when layer is hidden/shown', function () {
|
||||
this.cartoDBLayer.hide();
|
||||
expect(this.layerLegendsView.$('.js-legends').length).toBe(0);
|
||||
|
||||
this.cartoDBLayer.show();
|
||||
expect(this.layerLegendsView.$('.js-legends').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should be hidden if no legends are rendered', function () {
|
||||
spyOn(this.cartoDBLayer.legends, 'hasAnyLegend').and.returnValue(false);
|
||||
this.settingsModel.set('showLayerSelector', false);
|
||||
this.layerLegendsView.render();
|
||||
expect(this.layerLegendsView.$el.is(':empty')).toBe(true);
|
||||
});
|
||||
|
||||
it('should not render layer selector checkbox if not embed', function () {
|
||||
this.settingsModel.set('layerSelectorEnabled', false);
|
||||
this.layerLegendsView.render();
|
||||
expect(this.layerLegendsView.$('.js-toggle-layer').length).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
var Backbone = require('backbone');
|
||||
var LegendsView = require('../../../../../src/geo/ui/legends/legends-view');
|
||||
var TileLayer = require('../../../../../src/geo/map/tile-layer');
|
||||
var CartoDBLayer = require('../../../../../src/geo/map/cartodb-layer');
|
||||
var TorqueLayer = require('../../../../../src/geo/map/torque-layer');
|
||||
var LayersCollection = require('../../../../../src/geo/map/layers');
|
||||
var MockFactory = require('../../../../helpers/mockFactory');
|
||||
|
||||
describe('geo/ui/legends/legends-view', function () {
|
||||
beforeEach(function () {
|
||||
var engineMock = new Backbone.Model();
|
||||
engineMock.reload = jasmine.createSpy('reload');
|
||||
this.tileLayer = new TileLayer(null, { engine: {} });
|
||||
this.cartoDBLayer1 = new CartoDBLayer({
|
||||
source: MockFactory.createAnalysisModel({ id: 'a1' }),
|
||||
layer_name: 'CartoDB Layer #1',
|
||||
legends: []
|
||||
}, { engine: engineMock });
|
||||
this.cartoDBLayer2 = new CartoDBLayer({
|
||||
source: MockFactory.createAnalysisModel({ id: 'a2' }),
|
||||
layer_name: 'CartoDB Layer #2',
|
||||
legends: []
|
||||
}, { engine: engineMock });
|
||||
this.torqueLayer = new TorqueLayer({ layer_name: 'Torque Layer #3', legends: [] }, { engine: engineMock });
|
||||
|
||||
this.layersCollection = new LayersCollection([]);
|
||||
this.layersCollection.reset([this.tileLayer, this.cartoDBLayer1, this.cartoDBLayer2, this.torqueLayer]);
|
||||
|
||||
this.settingsModel = new Backbone.Model({
|
||||
showLegends: true,
|
||||
showLayerSelector: true,
|
||||
layerSelectorEnabled: true
|
||||
});
|
||||
|
||||
this.legendsView = new LegendsView({
|
||||
layersCollection: this.layersCollection,
|
||||
settingsModel: this.settingsModel
|
||||
});
|
||||
|
||||
this.legendsView.render();
|
||||
});
|
||||
|
||||
var getLayerLegendTitles = function (legendsView) {
|
||||
var titleElements = legendsView.$('.CDB-LayerLegends > .CDB-Text').get();
|
||||
return titleElements.map(function (element) { return element.textContent.trim(); });
|
||||
};
|
||||
|
||||
it('should render legends for CartoDB and torque layers', function () {
|
||||
expect(this.legendsView.$('.CDB-LayerLegends').length).toEqual(3);
|
||||
expect(getLayerLegendTitles(this.legendsView)).toEqual(['Torque Layer #3', 'CartoDB Layer #2', 'CartoDB Layer #1']);
|
||||
});
|
||||
|
||||
it('should re-render when a layer with legends is removed from the collection of layers', function () {
|
||||
this.cartoDBLayer1.remove();
|
||||
|
||||
expect(this.legendsView.$('.CDB-LayerLegends').length).toEqual(2);
|
||||
expect(getLayerLegendTitles(this.legendsView)).toEqual(['Torque Layer #3', 'CartoDB Layer #2']);
|
||||
});
|
||||
|
||||
it('should re-render when new layers with legends are added to the collection of layers', function () {
|
||||
this.cartoDBLayer1.remove();
|
||||
this.layersCollection.add(this.cartoDBLayer1, { at: 1 });
|
||||
|
||||
expect(this.legendsView.$('.CDB-LayerLegends').length).toEqual(3);
|
||||
expect(getLayerLegendTitles(this.legendsView)).toEqual(['Torque Layer #3', 'CartoDB Layer #2', 'CartoDB Layer #1']);
|
||||
});
|
||||
|
||||
it('should re-render when a layer with legends is moved', function () {
|
||||
expect(getLayerLegendTitles(this.legendsView)).toEqual(['Torque Layer #3', 'CartoDB Layer #2', 'CartoDB Layer #1']);
|
||||
|
||||
this.layersCollection.moveCartoDBLayer(2, 1);
|
||||
|
||||
expect(getLayerLegendTitles(this.legendsView)).toEqual(['Torque Layer #3', 'CartoDB Layer #1', 'CartoDB Layer #2']);
|
||||
});
|
||||
|
||||
it('should show legends if showLegends is true', function () {
|
||||
this.settingsModel.set('showLegends', true);
|
||||
expect(this.legendsView.$('.Legends').length).toBe(3);
|
||||
});
|
||||
|
||||
it('should hide legends if showLegends is false', function () {
|
||||
this.settingsModel.set('showLegends', false);
|
||||
expect(this.legendsView.$('.Legends').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should show layer selector if showLayerSelector is true', function () {
|
||||
this.settingsModel.set('showLayerSelector', true);
|
||||
expect(this.legendsView.$('input').length).toBe(3);
|
||||
});
|
||||
|
||||
it('should hide layer selector if showLayerSelector is false', function () {
|
||||
this.settingsModel.set('showLayerSelector', false);
|
||||
expect(this.legendsView.$('input').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should hide element if showLayerSelector changes to false and no legends are visible', function () {
|
||||
spyOn(this.cartoDBLayer1.legends, 'hasAnyLegend').and.returnValue(false);
|
||||
spyOn(this.cartoDBLayer2.legends, 'hasAnyLegend').and.returnValue(false);
|
||||
expect(this.legendsView.el.style.display).toEqual('block');
|
||||
this.settingsModel.set('showLayerSelector', false);
|
||||
expect(this.legendsView.el.style.display).toEqual('none');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('underscore');
|
||||
var LimitsView = require('../../../../src/geo/ui/limits/limits-view');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
|
||||
describe('geo/ui/limits', function () {
|
||||
beforeEach(function () {
|
||||
// Disable defer
|
||||
spyOn(_, 'delay').and.callFake(function (func) {
|
||||
return function () {
|
||||
func.apply(this, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
this.keyEsc = function () {
|
||||
var event = $.Event('keydown');
|
||||
event.keyCode = 27; // ESC
|
||||
$(document).trigger(event);
|
||||
};
|
||||
|
||||
this.map = new Map(null, {
|
||||
layersFactory: {}
|
||||
});
|
||||
spyOn(this.map, 'bind').and.callThrough();
|
||||
spyOn(LimitsView.prototype, 'render').and.callThrough();
|
||||
|
||||
this.view = new LimitsView({
|
||||
map: this.map
|
||||
});
|
||||
this.view.render();
|
||||
this.$button = this.view.$('.js-button');
|
||||
this.$text = this.view.$('.js-text');
|
||||
this.viewHasClass = function (className) {
|
||||
return this.view.$el.hasClass(className);
|
||||
};
|
||||
});
|
||||
|
||||
describe('render', function () {
|
||||
it('should render properly', function () {
|
||||
expect(this.$button.length).toBe(1);
|
||||
expect(this.$text.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the limits overlay is displayed', function () {
|
||||
beforeEach(function () {
|
||||
this.$button.click();
|
||||
});
|
||||
|
||||
it('should have .is-active class', function () {
|
||||
expect(this.viewHasClass('is-active')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should hide the overlay when .js-button is clicked', function () {
|
||||
this.$button.click();
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should hide the overlay when ESC is pressed', function () {
|
||||
this.keyEsc();
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should hide the overlay when user clicks on the document', function () {
|
||||
$(document).trigger('click');
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the limits overlay is hidden', function () {
|
||||
beforeEach(function () {
|
||||
this.$button.click();
|
||||
this.keyEsc();
|
||||
});
|
||||
|
||||
it('should not have .is-active class', function () {
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show the overlay when js-button is clicked', function () {
|
||||
this.$button.click();
|
||||
expect(this.viewHasClass('is-active')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should ignore the ESC key', function () {
|
||||
this.keyEsc();
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should ignore clicks in the document', function () {
|
||||
$(document).trigger('click');
|
||||
expect(this.viewHasClass('is-active')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,217 @@
|
||||
var Backbone = require('backbone');
|
||||
var OverlaysView = require('../../../../src/geo/ui/overlays-view.js');
|
||||
var Engine = require('../../../../src/engine');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('src/geo/ui/overlays-view.js', function () {
|
||||
var mapModelMock = new Backbone.Model();
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
this.overlaysCollection = new Backbone.Collection([
|
||||
{
|
||||
type: 'zoom',
|
||||
order: 2,
|
||||
options: {
|
||||
display: true
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'search',
|
||||
order: 1,
|
||||
options: {
|
||||
display: false
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'loader',
|
||||
order: 5,
|
||||
options: {
|
||||
display: true
|
||||
}
|
||||
}
|
||||
]);
|
||||
this.view = new OverlaysView({
|
||||
overlaysCollection: this.overlaysCollection,
|
||||
engine: engineMock,
|
||||
visView: new Backbone.View({
|
||||
model: new Backbone.Model({ showLimitErrors: false })
|
||||
}),
|
||||
mapModel: mapModelMock,
|
||||
mapView: new Backbone.View()
|
||||
});
|
||||
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should render existing overlays', function () {
|
||||
expect(this.view.$('.CDB-OverlayContainer').length).toEqual(1);
|
||||
|
||||
// Some overlays are grouped together in a container
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Zoom').length).toEqual(1);
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Search').length).toEqual(1);
|
||||
|
||||
// Some others are global
|
||||
expect(this.view.$('> .CDB-Loader').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should only show overlays with a truthy display option', function () {
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Zoom').length).toEqual(1);
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Search').length).toEqual(1);
|
||||
expect(this.view.$('> .CDB-Loader').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should re-render overlays when a new overlay is added', function () {
|
||||
this.overlaysCollection.add({ type: 'fullscreen' });
|
||||
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Zoom').length).toEqual(1);
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Search').length).toEqual(1);
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Fullscreen').length).toEqual(1);
|
||||
expect(this.view.$('> .CDB-Loader').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should re-render overlays when an overlay is removed', function () {
|
||||
this.overlaysCollection.remove(this.overlaysCollection.at(0));
|
||||
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Zoom').length).toEqual(0);
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Search').length).toEqual(1);
|
||||
expect(this.view.$('> .CDB-Loader').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should handle unknown overlay types properly', function () {
|
||||
this.overlaysCollection.add({ type: 'unknown' });
|
||||
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Zoom').length).toEqual(1);
|
||||
expect(this.view.$('.CDB-OverlayContainer > .CDB-Search').length).toEqual(1);
|
||||
expect(this.view.$('> .CDB-Loader').length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should toggle the loader overlay', function () {
|
||||
var loaderOverlay = this.view.$('> .CDB-Loader');
|
||||
expect(loaderOverlay.hasClass('is-visible')).toBeFalsy();
|
||||
|
||||
engineMock._eventEmmitter.trigger(Engine.Events.RELOAD_STARTED);
|
||||
expect(loaderOverlay.hasClass('is-visible')).toBeTruthy();
|
||||
|
||||
engineMock._eventEmmitter.trigger(Engine.Events.RELOAD_SUCCESS);
|
||||
expect(loaderOverlay.hasClass('is-visible')).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('._initBinds', function () {
|
||||
it('should call ._addLimitsOverlay on mapModel error:limit', function () {
|
||||
spyOn(this.view, '_addLimitsOverlay');
|
||||
this.view._initBinds();
|
||||
this.view._mapModel.trigger('error:limit');
|
||||
expect(this.view._addLimitsOverlay).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call ._addTilesOverlay on mapModel error:limit', function () {
|
||||
spyOn(this.view, '_addTilesOverlay');
|
||||
this.view._initBinds();
|
||||
this.view._mapModel.trigger('error:tile');
|
||||
expect(this.view._addTilesOverlay).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._areLimitsErrorsEnabled', function () {
|
||||
it('should return visModel showLimitErrors', function () {
|
||||
expect(this.view._areLimitsErrorsEnabled()).toBe(false);
|
||||
this.view._visView.model.set('showLimitErrors', true);
|
||||
expect(this.view._areLimitsErrorsEnabled()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._hasLimitsOverlay', function () {
|
||||
it('should return true if overlaysCollection has a limits overlay', function () {
|
||||
expect(this.view._hasLimitsOverlay()).toBe(false);
|
||||
this.view._overlaysCollection.add({ type: 'limits' });
|
||||
expect(this.view._hasLimitsOverlay()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._addLimitsOverlay', function () {
|
||||
describe('when visModel showLimitErrors is true', function () {
|
||||
beforeEach(function () {
|
||||
this.view._visView.model.set('showLimitErrors', true);
|
||||
});
|
||||
|
||||
it('should call ._removeTilesOverlay', function () {
|
||||
spyOn(this.view, '_removeTilesOverlay');
|
||||
this.view._mapModel.trigger('error:limit');
|
||||
expect(this.view._removeTilesOverlay).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add the overlay to the collection', function () {
|
||||
spyOn(this.view._overlaysCollection, 'add');
|
||||
this.view._mapModel.trigger('error:limit');
|
||||
expect(this.view._overlaysCollection.add).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add only one overlay of type limit', function () {
|
||||
spyOn(this.view._overlaysCollection, 'add').and.callThrough();
|
||||
this.view._mapModel.trigger('error:limit');
|
||||
this.view._mapModel.trigger('error:limit');
|
||||
expect(this.view._overlaysCollection.add.calls.count()).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when visModel showLimitErrors is false', function () {
|
||||
it('should not add the overlay to the collection', function () {
|
||||
spyOn(this.view._overlaysCollection, 'add');
|
||||
this.view._mapModel.trigger('error:limit');
|
||||
expect(this.view._overlaysCollection.add).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('._addTilesOverlay', function () {
|
||||
it('should add the overlay to the collection', function () {
|
||||
spyOn(this.view._overlaysCollection, 'add');
|
||||
this.view._mapModel.trigger('error:tile');
|
||||
expect(this.view._overlaysCollection.add).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add only one overlay of type tile', function () {
|
||||
spyOn(this.view._overlaysCollection, 'add').and.callThrough();
|
||||
this.view._mapModel.trigger('error:tile');
|
||||
this.view._mapModel.trigger('error:tile');
|
||||
expect(this.view._overlaysCollection.add.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
it('should not add the overlay if there is a limits overlay', function () {
|
||||
this.view._overlaysCollection.add({ type: 'limits' });
|
||||
spyOn(this.view._overlaysCollection, 'add');
|
||||
this.view._mapModel.trigger('error:tile');
|
||||
expect(this.view._overlaysCollection.add).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('._removeLimitsOverlay', function () {
|
||||
it('should remove the limits overlay from the collection', function () {
|
||||
spyOn(this.view._overlaysCollection, 'remove').and.callThrough();
|
||||
expect(this.view._overlaysCollection.length).toEqual(3);
|
||||
|
||||
this.view._overlaysCollection.add({ type: 'limits' });
|
||||
expect(this.view._overlaysCollection.length).toEqual(4);
|
||||
|
||||
this.view._removeLimitsOverlay();
|
||||
expect(this.view._overlaysCollection.remove).toHaveBeenCalled();
|
||||
expect(this.view._overlaysCollection.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._removeTilesOverlay', function () {
|
||||
it('should remove the tiles overlay from the collection', function () {
|
||||
spyOn(this.view._overlaysCollection, 'remove').and.callThrough();
|
||||
expect(this.view._overlaysCollection.length).toEqual(3);
|
||||
|
||||
this.view._overlaysCollection.add({ type: 'tiles' });
|
||||
expect(this.view._overlaysCollection.length).toEqual(4);
|
||||
|
||||
this.view._removeTilesOverlay();
|
||||
expect(this.view._overlaysCollection.remove).toHaveBeenCalled();
|
||||
expect(this.view._overlaysCollection.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,281 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var Search = require('../../../../src/geo/ui/search/search');
|
||||
|
||||
var mapboxGeocoder = require('../../../../src/geo/geocoder/mapbox-geocoder');
|
||||
var tomtomGeocoder = require('../../../../src/geo/geocoder/tomtom-geocoder');
|
||||
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var LeafletMapView = require('../../../../src/geo/leaflet/leaflet-map-view');
|
||||
var fakeEvent = {
|
||||
preventDefault: jasmine.createSpy()
|
||||
};
|
||||
|
||||
describe('geo/ui/search', function () {
|
||||
beforeEach(function () {
|
||||
this.$el = $('<div>')
|
||||
.attr('id', 'map')
|
||||
.height(500)
|
||||
.width(500);
|
||||
$('body').append(this.$el);
|
||||
this.map = new Map(null, { layersFactory: {} });
|
||||
this.mapView = new LeafletMapView({
|
||||
el: this.$el,
|
||||
mapModel: this.map,
|
||||
engine: new Backbone.Model(),
|
||||
layerViewFactory: jasmine.createSpyObj('layerViewFactory', ['createLayerView']),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
this.mapView.render();
|
||||
|
||||
this.view = new Search({
|
||||
model: this.map,
|
||||
mapView: this.mapView,
|
||||
token: 'a_valid_api_key'
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should use tomtom geocoder by default', function () {
|
||||
expect(this.view.geocoder).toBe(tomtomGeocoder);
|
||||
});
|
||||
|
||||
it('should allow changing geocoder easily', function () {
|
||||
var search = new Search({
|
||||
model: this.map,
|
||||
mapView: this.mapView,
|
||||
geocoderService: 'mapbox', // <<<
|
||||
token: 'a_valid_mapbox_api_key'
|
||||
});
|
||||
expect(search.geocoder).toBe(mapboxGeocoder);
|
||||
});
|
||||
|
||||
it('should render properly', function () {
|
||||
expect(this.view.$('.js-form').length).toBe(1);
|
||||
expect(this.view.$('.js-textInput').length).toBe(1);
|
||||
expect(this.view.$('input[type="submit"]').length).toBe(0);
|
||||
expect(this.view.$('span.loader').length).toBe(0);
|
||||
});
|
||||
|
||||
describe('onSubmit', function () {
|
||||
beforeEach(function () {
|
||||
this.result = {
|
||||
lat: 43.0,
|
||||
lon: -3.0,
|
||||
boundingbox: {
|
||||
south: 6.0,
|
||||
north: 4.0,
|
||||
west: 6.0,
|
||||
east: 4.0
|
||||
},
|
||||
type: undefined
|
||||
};
|
||||
// spyOn(this.view.geocoder, 'geocode').and.callThrough();
|
||||
spyOn(this.view.geocoder, 'geocode').and.returnValue(Promise.resolve([{
|
||||
center: [40.41889, -3.69194],
|
||||
type: 'localadmin'
|
||||
}]));
|
||||
this.view.$('.js-textInput').val('Madrid, Spain');
|
||||
});
|
||||
|
||||
it('should search with geocoder when form is submit', function () {
|
||||
this.view.$('.js-form').submit();
|
||||
expect(this.view.geocoder.geocode).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should change map center when geocoder returns any result', function (done) {
|
||||
var onCenterChangedSpy = jasmine.createSpy('onCenterChangedSpy');
|
||||
this.map.bind('change:center', onCenterChangedSpy, this.view);
|
||||
this.view._onSubmit(fakeEvent).then(function () {
|
||||
expect(onCenterChangedSpy).toHaveBeenCalled();
|
||||
this.map.unbind('change:center', onCenterChangedSpy, this.view);
|
||||
done();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
describe('result zoom', function () {
|
||||
function testZoom (context, featureType, expectedZoom, done) {
|
||||
context.view.geocoder.geocode.and.returnValue(Promise.resolve([{
|
||||
center: [43.0, -3],
|
||||
type: featureType
|
||||
}]));
|
||||
|
||||
context.view._onSubmit(fakeEvent).then(function () {
|
||||
expect(context.map.get('zoom')).toBe(expectedZoom);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
it('should zoom to 18 when search result is building type', function (done) {
|
||||
testZoom(this, 'building', 18, done);
|
||||
});
|
||||
|
||||
it('should zoom to 15 when search result is postal-area type', function (done) {
|
||||
testZoom(this, 'postal-area', 15, done);
|
||||
});
|
||||
|
||||
it('should zoom to 18 when search result is venue type', function (done) {
|
||||
testZoom(this, 'venue', 18, done);
|
||||
});
|
||||
|
||||
it('should zoom to 8 when search result is region type', function (done) {
|
||||
testZoom(this, 'region', 8, done);
|
||||
});
|
||||
|
||||
it('should zoom to 5 when search result is country type', function (done) {
|
||||
testZoom(this, 'country', 5, done);
|
||||
});
|
||||
|
||||
it('should zoom to 8 when search result is county type', function (done) {
|
||||
testZoom(this, 'county', 8, done);
|
||||
});
|
||||
|
||||
it('should zoom to 18 when search result is address type', function (done) {
|
||||
testZoom(this, 'address', 18, done);
|
||||
});
|
||||
|
||||
it('should zoom to 12 when search result is locality type', function (done) {
|
||||
testZoom(this, 'locality', 12, done);
|
||||
});
|
||||
|
||||
it('should zoom to 11 when search result is localadmin type', function (done) {
|
||||
testZoom(this, 'localadmin', 11, done);
|
||||
});
|
||||
|
||||
it('should zoom to 15 when search result is neighbourhood type', function (done) {
|
||||
testZoom(this, 'neighbourhood', 15, done);
|
||||
});
|
||||
|
||||
it('should zoom to 12 when search result is unknown type', function (done) {
|
||||
testZoom(this, 'whatever', 12, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('searchPin', function () {
|
||||
beforeEach(function () {
|
||||
this.view.options.searchPin = true;
|
||||
});
|
||||
|
||||
it('should add a pin and an infowindow when search is completed', function (done) {
|
||||
this.view._onSubmit(fakeEvent).then(function () {
|
||||
expect(this.view._searchPin).toBeDefined();
|
||||
expect(this.view._searchInfowindow).toBeDefined();
|
||||
done();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
it('should place pin in the feature center', function (done) {
|
||||
this.view._onSubmit(fakeEvent).then(function () {
|
||||
expect(this.view._searchPin.get('latlng')).toEqual([40.41889, -3.69194]);
|
||||
done();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
it('should display address in the search infowindow', function (done) {
|
||||
this.view._onSubmit(fakeEvent).then(function () {
|
||||
expect(this.view._searchInfowindow.$('.CDB-infowindow-title').text()).toBe('Madrid, Spain');
|
||||
done();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
it('should destroy/hide search pin when map is clicked', function (done) {
|
||||
var view = this.view;
|
||||
view._onSubmit(fakeEvent).then(function () {
|
||||
expect(view._searchPin).toBeDefined();
|
||||
expect(view._searchInfowindow).toBeDefined();
|
||||
this.mapView.trigger('click');
|
||||
setTimeout(function () {
|
||||
expect(view._searchPin).toBeUndefined();
|
||||
expect(view._searchInfowindow).toBeUndefined();
|
||||
done();
|
||||
}, 1000);
|
||||
}.bind(this));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('_initializeGeocoder', function () {
|
||||
it('should set geocoder from options if available', function () {
|
||||
this.view = new Search({
|
||||
model: this.map,
|
||||
mapView: this.mapView,
|
||||
geocoderService: 'mapbox',
|
||||
token: 'token_from_options'
|
||||
});
|
||||
|
||||
expect(this.view.geocoderService).toBe('mapbox');
|
||||
expect(this.view.token).toBe('token_from_options');
|
||||
});
|
||||
|
||||
it('should set geocoder from injected configuration if available', function () {
|
||||
spyOn(Search.prototype, '_getGeocodingInfoFromConfig').and.returnValue({
|
||||
provider: 'tomtom_fake',
|
||||
token: 'fakeAPIKey'
|
||||
});
|
||||
|
||||
this.view = new Search({
|
||||
model: this.map,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
expect(this.view.geocoderService).toBe('tomtom_fake');
|
||||
expect(this.view.token).toBe('fakeAPIKey');
|
||||
});
|
||||
|
||||
it('should set default geocoder if no configurations are available', function () {
|
||||
Object.defineProperty(window, 'tomtomApiKey', {
|
||||
value: 'fake_tomtom_key',
|
||||
writable: true
|
||||
});
|
||||
|
||||
this.view = new Search({
|
||||
model: this.map,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
expect(this.view.geocoderService).toBe('tomtom');
|
||||
expect(this.view.token).toBe('fake_tomtom_key');
|
||||
});
|
||||
});
|
||||
|
||||
describe('_getGeocodingInfoFromConfig', function () {
|
||||
it('should return an empty object if there is no geocoderConfiguration', function () {
|
||||
expect(this.view._getGeocodingInfoFromConfig()).toEqual({});
|
||||
});
|
||||
|
||||
it('should return provider and token from geocoderConfiguration', function () {
|
||||
var geocoderConfiguration = {
|
||||
provider: 'tomtom',
|
||||
tomtom: {
|
||||
search_bar_api_key: 'fakeAPIKey'
|
||||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(window, 'geocoderConfiguration', {
|
||||
value: geocoderConfiguration,
|
||||
writable: true
|
||||
});
|
||||
|
||||
expect(this.view._getGeocodingInfoFromConfig()).toEqual({
|
||||
provider: 'tomtom', token: 'fakeAPIKey'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined provider and token if no provider found in geocoderConfiguration', function () {
|
||||
var geocoderConfiguration = {};
|
||||
|
||||
Object.defineProperty(window, 'geocoderConfiguration', {
|
||||
value: geocoderConfiguration,
|
||||
writable: true
|
||||
});
|
||||
|
||||
expect(this.view._getGeocodingInfoFromConfig()).toEqual({
|
||||
provider: undefined, token: undefined
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.$el.remove();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,173 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var LeafletMapView = require('../../../../src/geo/leaflet/leaflet-map-view');
|
||||
var TooltipModel = require('../../../../src/geo/ui/tooltip-model');
|
||||
var TooltipView = require('../../../../src/geo/ui/tooltip-view');
|
||||
|
||||
describe('geo/ui/tooltip-view', function () {
|
||||
beforeEach(function () {
|
||||
this.container = $("<div id='map'>").css('height', '1000px');
|
||||
$('body').append(this.container);
|
||||
var map = new Map(null, { layersFactory: {} });
|
||||
this.mapView = new LeafletMapView({
|
||||
el: $('#map'),
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerViewFactory: jasmine.createSpyObj('layerViewFactory', ['createLayerView']),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
this.mapView.render();
|
||||
|
||||
this.layerView = new Backbone.View();
|
||||
this.tooltipModel = new TooltipModel({
|
||||
template: '{{#fields}}{{{ value }}},{{/fields}}'
|
||||
});
|
||||
this.tooltipView = new TooltipView({
|
||||
model: this.tooltipModel,
|
||||
layerView: this.layerView,
|
||||
mapView: this.mapView
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
$('#map').remove();
|
||||
});
|
||||
|
||||
it('should render fields in specified order', function () {
|
||||
this.tooltipModel.set('fields', [{
|
||||
name: 'test2'
|
||||
}, {
|
||||
name: 'test1'
|
||||
}, {
|
||||
name: 'huracan'
|
||||
}]);
|
||||
this.tooltipView.model.updateContent({
|
||||
test1: 'test1',
|
||||
test2: 'test2',
|
||||
huracan: 'huracan'
|
||||
});
|
||||
|
||||
expect(this.tooltipView.$el.html()).toEqual('test2,test1,huracan,');
|
||||
});
|
||||
|
||||
it('should use alternate_names ', function () {
|
||||
this.tooltipModel.set('template', '{{#fields}}{{{ title }}},{{/fields}}');
|
||||
|
||||
this.tooltipModel.set('fields', [{
|
||||
name: 'test2',
|
||||
title: true
|
||||
}, {
|
||||
name: 'test1',
|
||||
title: true
|
||||
}, {
|
||||
name: 'huracan',
|
||||
title: true
|
||||
}]);
|
||||
this.tooltipModel.set('alternative_names', {
|
||||
'test1': 'testnamed'
|
||||
});
|
||||
|
||||
this.tooltipView.model.updateContent({
|
||||
test1: 'test1',
|
||||
test2: 'test2',
|
||||
huracan: 'huracan'
|
||||
});
|
||||
|
||||
expect(this.tooltipView.$el.html()).toEqual('test2,testnamed,huracan,');
|
||||
});
|
||||
|
||||
it('should position the element correctly', function () {
|
||||
this.tooltipView.$el.css('width', '200px');
|
||||
this.tooltipView.$el.css('height', '20px');
|
||||
|
||||
this.tooltipModel.set('placement', 'bottom|right');
|
||||
this.tooltipModel.setPosition({ x: 10, y: 10 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('10px');
|
||||
expect(this.tooltipView.$el.css('left')).toBe('10px');
|
||||
|
||||
this.tooltipModel.set('placement', 'top|left');
|
||||
this.tooltipModel.setPosition({ x: 210, y: 40 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('20px');
|
||||
expect(this.tooltipView.$el.css('left')).toBe('10px');
|
||||
|
||||
this.tooltipModel.set('placement', 'middle|center');
|
||||
this.tooltipModel.setPosition({ x: 150, y: 30 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('20px');
|
||||
expect(this.tooltipView.$el.css('left')).toBe('50px');
|
||||
|
||||
// With offsets
|
||||
this.tooltipModel.set('placement', 'middle|center');
|
||||
this.tooltipModel.set('offset', [-10, -10]);
|
||||
this.tooltipModel.setPosition({ x: 0, y: 0 });
|
||||
this.tooltipModel.setPosition({ x: 150, y: 30 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('10px');
|
||||
expect(this.tooltipView.$el.css('left')).toBe('40px');
|
||||
});
|
||||
|
||||
describe('overflow positioning', function () {
|
||||
beforeEach(function () {
|
||||
$('#map').css('height', '100px');
|
||||
$('#map').css('width', '100px');
|
||||
this.tooltipView.$el.css('height', '80px');
|
||||
this.tooltipView.$el.css('width', '80px');
|
||||
this.mapView.invalidateSize();
|
||||
});
|
||||
|
||||
it('should position the element on top when bottom overflow occurs', function () {
|
||||
this.tooltipModel.set('placement', 'bottom|right');
|
||||
this.tooltipModel.setPosition({ x: 0, y: 90 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('10px');
|
||||
});
|
||||
|
||||
it('should position the element on the bottom when top overflow occurs', function () {
|
||||
this.tooltipModel.set('placement', 'top|right');
|
||||
this.tooltipModel.setPosition({ x: 0, y: 10 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('10px');
|
||||
});
|
||||
|
||||
it('should position the element on top/bottom when overflow vertically centered and overflow occurs', function () {
|
||||
this.tooltipModel.set('placement', 'middle|right');
|
||||
this.tooltipModel.setPosition({ x: 0, y: 90 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('10px');
|
||||
|
||||
this.tooltipModel.set('placement', 'middle|right');
|
||||
this.tooltipModel.setPosition({ x: 0, y: 10 });
|
||||
|
||||
expect(this.tooltipView.$el.css('top')).toBe('10px');
|
||||
});
|
||||
|
||||
it('should position the element on the left when right overflow occurs', function () {
|
||||
this.tooltipModel.set('placement', 'top|right');
|
||||
this.tooltipModel.setPosition({ x: 90, y: 10 });
|
||||
|
||||
expect(this.tooltipView.$el.css('left')).toBe('10px');
|
||||
});
|
||||
|
||||
it('should position the element on the right when left overflow occurs', function () {
|
||||
this.tooltipModel.set('placement', 'top|left');
|
||||
this.tooltipModel.setPosition({ x: 10, y: 10 });
|
||||
|
||||
expect(this.tooltipView.$el.css('left')).toBe('10px');
|
||||
});
|
||||
|
||||
it('should position the element on the left/right when horizontally centered and overflow occurs', function () {
|
||||
this.tooltipModel.set('placement', 'top|center');
|
||||
this.tooltipModel.setPosition({ x: 10, y: 10 });
|
||||
|
||||
expect(this.tooltipView.$el.css('left')).toBe('10px');
|
||||
|
||||
this.tooltipModel.set('placement', 'top|center');
|
||||
this.tooltipModel.setPosition({ x: 90, y: 10 });
|
||||
|
||||
expect(this.tooltipView.$el.css('left')).toBe('10px');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var Zoom = require('../../../../src/geo/ui/zoom/zoom-view');
|
||||
var Template = require('../../../../src/core/template');
|
||||
|
||||
describe('geo/ui/zoom', function () {
|
||||
beforeEach(function () {
|
||||
this.map = new Map(null, { layersFactory: {} });
|
||||
spyOn(this.map, 'bind').and.callThrough();
|
||||
spyOn(this.map, 'setZoom').and.callThrough();
|
||||
this.view = new Zoom({
|
||||
model: this.map,
|
||||
template: Template.compile(' ' +
|
||||
'<div class="CDB-Overlay">' +
|
||||
'<button class="CDB-Zoom-action CDB-Zoom-action--out js-zoomOut"></button>' +
|
||||
'<button class="CDB-Zoom-action CDB-Zoom-action--in js-zoomIn"></button>' +
|
||||
'</div>' +
|
||||
'<div class="CDB-Zoom-info">-</div>')
|
||||
});
|
||||
this.view.render();
|
||||
});
|
||||
|
||||
it('should have bindings when map zoom has any change', function () {
|
||||
expect(this.map.bind.calls.argsFor(0)[0]).toEqual('change:zoom change:minZoom change:maxZoom');
|
||||
expect(this.map.bind.calls.argsFor(0)[1]).toEqual(this.view._checkZoom);
|
||||
});
|
||||
|
||||
describe('zoom in', function () {
|
||||
beforeEach(function () {
|
||||
this.$zoomIn = this.view.$('.js-zoomIn');
|
||||
});
|
||||
|
||||
it('should zoom in when button is clicked', function () {
|
||||
this.$zoomIn.click();
|
||||
expect(this.map.setZoom).toHaveBeenCalled();
|
||||
expect(this.$zoomIn.hasClass('is-disabled')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not zoom in if max zoom is reached', function () {
|
||||
this.map.set({
|
||||
zoom: 3,
|
||||
maxZoom: 3
|
||||
});
|
||||
this.$zoomIn.click();
|
||||
expect(this.map.setZoom).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add a is-disabled class when it is not possible to zoom in', function () {
|
||||
this.map.set({
|
||||
zoom: 3,
|
||||
maxZoom: 3
|
||||
});
|
||||
expect(this.$zoomIn.hasClass('is-disabled')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('zoom out', function () {
|
||||
beforeEach(function () {
|
||||
this.$zoomOut = this.view.$('.js-zoomOut');
|
||||
});
|
||||
|
||||
it('should zoom out when button is clicked', function () {
|
||||
this.$zoomOut.click();
|
||||
expect(this.map.setZoom).toHaveBeenCalled();
|
||||
expect(this.$zoomOut.hasClass('is-disabled')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not zoom in if min zoom is reached', function () {
|
||||
this.map.set({
|
||||
zoom: 3,
|
||||
minZoom: 3
|
||||
});
|
||||
this.$zoomOut.click();
|
||||
expect(this.map.setZoom).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add a is-disabled class when it is not possible to zoom out', function () {
|
||||
this.map.set({
|
||||
zoom: 3,
|
||||
minZoom: 3
|
||||
});
|
||||
expect(this.$zoomOut.hasClass('is-disabled')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user