Initial commit
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var Layers = require('../../../src/geo/map/layers');
|
||||
var CartoDBLayer = require('../../../src/geo/map/cartodb-layer');
|
||||
var TileLayer = require('../../../src/geo/map/tile-layer');
|
||||
var TorqueLayer = require('../../../src/geo/map/torque-layer');
|
||||
var GMapsBaseLayer = require('../../../src/geo/map/gmaps-base-layer');
|
||||
var CartoDBLayerGroup = require('../../../src/geo/cartodb-layer-group');
|
||||
var createEngine = require('../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/cartodb-layer-group', function () {
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
this.layersCollection = new Layers();
|
||||
engineMock = createEngine();
|
||||
|
||||
this.cartoDBLayerGroup = new CartoDBLayerGroup({}, {
|
||||
layersCollection: this.layersCollection
|
||||
});
|
||||
});
|
||||
|
||||
describe('.fetchAttributes', function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
attributes: [
|
||||
'http://carto.com/1/attributes',
|
||||
'http://carto.com/2/attributes'
|
||||
]
|
||||
});
|
||||
|
||||
spyOn($, 'ajax').and.callFake(function (options) {
|
||||
options.success('attributes!');
|
||||
});
|
||||
});
|
||||
|
||||
it('should trigger a request to the right URL', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
|
||||
this.cartoDBLayerGroup.fetchAttributes(0, 1000, callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledWith('attributes!');
|
||||
expect($.ajax.calls.mostRecent().args[0].url).toEqual('http://carto.com/1/attributes/1000');
|
||||
});
|
||||
|
||||
it('should invoke the callback with null when the ajax request fails', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
|
||||
$.ajax.and.callFake(function (options) {
|
||||
options.error('error!');
|
||||
});
|
||||
|
||||
this.cartoDBLayerGroup.fetchAttributes(0, 1000, callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledWith(null);
|
||||
});
|
||||
|
||||
it('should append the api_key to urls', function () {
|
||||
this.cartoDBLayerGroup.set('apiKey', 'THE_API_KEY');
|
||||
|
||||
var callback = jasmine.createSpy('callback');
|
||||
|
||||
this.cartoDBLayerGroup.fetchAttributes(1, 1000, callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledWith('attributes!');
|
||||
expect($.ajax.calls.mostRecent().args[0].url).toEqual('http://carto.com/2/attributes/1000?api_key=THE_API_KEY');
|
||||
});
|
||||
|
||||
it('should append the auth_token to urls', function () {
|
||||
this.cartoDBLayerGroup.set('authToken', 'AUTH_TOKEN');
|
||||
|
||||
var callback = jasmine.createSpy('callback');
|
||||
|
||||
this.cartoDBLayerGroup.fetchAttributes(1, 1000, callback);
|
||||
|
||||
expect(callback).toHaveBeenCalledWith('attributes!');
|
||||
expect($.ajax.calls.mostRecent().args[0].url).toEqual('http://carto.com/2/attributes/1000?auth_token=AUTH_TOKEN');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getTileURLTemplate', function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayerGroup = new CartoDBLayerGroup({
|
||||
indexOfLayersInWindshaft: [1, 2]
|
||||
}, {
|
||||
layersCollection: this.layersCollection
|
||||
});
|
||||
|
||||
var otherLayer = new Backbone.Model();
|
||||
this.cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.layersCollection.reset([
|
||||
otherLayer,
|
||||
this.cartoDBLayer1,
|
||||
this.cartoDBLayer2
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return an empty array there are NO urls yet', function () {
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('');
|
||||
});
|
||||
|
||||
it('should return an empty array if there are NO tile URL templates', function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
tiles: ''
|
||||
});
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('');
|
||||
});
|
||||
|
||||
describe('png', function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
tiles: 'http://carto.com/{layerIndexes}/{z}/{x}/{y}.{format}'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an array with the tile URL templates', function () {
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('http://carto.com/1,2/{z}/{x}/{y}.png');
|
||||
});
|
||||
|
||||
it('should not include index of layers that are hidden', function () {
|
||||
this.cartoDBLayer1.set('visible', false);
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('http://carto.com/2/{z}/{x}/{y}.png');
|
||||
});
|
||||
|
||||
it('should return an empty array if all layers are hidden', function () {
|
||||
this.cartoDBLayer1.set('visible', false);
|
||||
this.cartoDBLayer2.set('visible', false);
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('');
|
||||
});
|
||||
|
||||
it('should return an empty string if there are no layer indexes', function () {
|
||||
spyOn(this.cartoDBLayerGroup, '_getIndexesOfVisibleMapnikLayers').and.returnValue('');
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('');
|
||||
});
|
||||
|
||||
it('should append the api_key to urls', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
apiKey: 'THE_API_KEY'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('http://carto.com/1,2/{z}/{x}/{y}.png?api_key=THE_API_KEY');
|
||||
});
|
||||
|
||||
it('should append the auth_token to urls', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
authToken: 'AUTH_TOKEN'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate()).toEqual('http://carto.com/1,2/{z}/{x}/{y}.png?auth_token=AUTH_TOKEN');
|
||||
});
|
||||
});
|
||||
|
||||
describe('mvt', function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
tiles: 'http://carto.com/{layerIndexes}/{z}/{x}/{y}.{format}'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a single tile URL template', function () {
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate('mvt')).toEqual('http://carto.com/mapnik/{z}/{x}/{y}.mvt');
|
||||
});
|
||||
|
||||
it('should return a single tile URL template if all layers are hidden', function () {
|
||||
this.cartoDBLayer1.set('visible', false);
|
||||
this.cartoDBLayer2.set('visible', false);
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate('mvt')).toEqual('http://carto.com/mapnik/{z}/{x}/{y}.mvt');
|
||||
});
|
||||
|
||||
it('should append the api_key to urls', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
apiKey: 'THE_API_KEY'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate('mvt')).toEqual('http://carto.com/mapnik/{z}/{x}/{y}.mvt?api_key=THE_API_KEY');
|
||||
});
|
||||
|
||||
it('should append the auth_token to urls', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
authToken: 'AUTH_TOKEN'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplate('mvt')).toEqual('http://carto.com/mapnik/{z}/{x}/{y}.mvt?auth_token=AUTH_TOKEN');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getTileURLTemplatesWithSubdomains', function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayerGroup = new CartoDBLayerGroup({
|
||||
indexOfLayersInWindshaft: [1, 2],
|
||||
urls: {
|
||||
tiles: 'http://carto.com/{layerIndexes}/{z}/{x}/{y}.{format}'
|
||||
}
|
||||
}, {
|
||||
layersCollection: this.layersCollection
|
||||
});
|
||||
|
||||
var otherLayer = new Backbone.Model();
|
||||
this.cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.layersCollection.reset([
|
||||
otherLayer,
|
||||
this.cartoDBLayer1,
|
||||
this.cartoDBLayer2
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return one URL when there are NO subdomains', function () {
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplatesWithSubdomains()).toEqual([ 'http://carto.com/1,2/{z}/{x}/{y}.png' ]);
|
||||
});
|
||||
|
||||
it('should include URLs for different subdomains', function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
tiles: 'http://{s}.carto.com/{layerIndexes}/{z}/{x}/{y}.{format}',
|
||||
subdomains: [ '0', '1', '2', '3' ]
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getTileURLTemplatesWithSubdomains()).toEqual([
|
||||
'http://0.carto.com/1,2/{z}/{x}/{y}.png',
|
||||
'http://1.carto.com/1,2/{z}/{x}/{y}.png',
|
||||
'http://2.carto.com/1,2/{z}/{x}/{y}.png',
|
||||
'http://3.carto.com/1,2/{z}/{x}/{y}.png'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.hasTileURLTemplates', function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.layersCollection.reset([
|
||||
this.cartoDBLayer1,
|
||||
this.cartoDBLayer2
|
||||
]);
|
||||
|
||||
this.cartoDBLayerGroup = new CartoDBLayerGroup({
|
||||
indexOfLayersInWindshaft: [1, 2]
|
||||
}, {
|
||||
layersCollection: this.layersCollection
|
||||
});
|
||||
});
|
||||
|
||||
it('should return false if there are NO urls yet', function () {
|
||||
expect(this.cartoDBLayerGroup.hasTileURLTemplates()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if there are NO tile URL templates', function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
tiles: ''
|
||||
});
|
||||
expect(this.cartoDBLayerGroup.hasTileURLTemplates()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if there are tile URL templates', function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
tiles: 'url1'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.hasTileURLTemplates()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getGridURLTemplatesWithSubdomains', function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayerGroup = new CartoDBLayerGroup({}, {
|
||||
layersCollection: this.layersCollection
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an empty array there are NO urls yet', function () {
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(0)).toEqual([]);
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(1)).toEqual([]);
|
||||
});
|
||||
|
||||
describe("when there're grid URLs", function () {
|
||||
beforeEach(function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
grids: [
|
||||
[ 'url1' ],
|
||||
[ 'url2' ]
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an array with the grid URL templates', function () {
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(0)).toEqual([ 'url1' ]);
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(1)).toEqual([ 'url2' ]);
|
||||
});
|
||||
|
||||
it('should append the api_key to urls', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
apiKey: 'THE_API_KEY'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(0)).toEqual([ 'url1?api_key=THE_API_KEY' ]);
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(1)).toEqual([ 'url2?api_key=THE_API_KEY' ]);
|
||||
});
|
||||
|
||||
it('should append the auth_token to urls', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
authToken: 'AUTH_TOKEN'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(0)).toEqual([ 'url1?auth_token=AUTH_TOKEN' ]);
|
||||
expect(this.cartoDBLayerGroup.getGridURLTemplatesWithSubdomains(1)).toEqual([ 'url2?auth_token=AUTH_TOKEN' ]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getAttributesBaseURL', function () {
|
||||
|
||||
});
|
||||
|
||||
describe('.getStaticImageURLTemplate', function () {
|
||||
beforeEach(function () {
|
||||
this.baseLayer = new TileLayer({}, { engine: engineMock });
|
||||
this.cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.torqueLayer = new TorqueLayer({}, { engine: engineMock });
|
||||
this.labelsLayer = new TileLayer({}, { engine: engineMock });
|
||||
|
||||
this.layersCollection.reset([
|
||||
this.baseLayer,
|
||||
this.cartoDBLayer1,
|
||||
this.cartoDBLayer2,
|
||||
this.torqueLayer,
|
||||
this.labelsLayer
|
||||
]);
|
||||
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
image: 'http://carto.com/image'
|
||||
});
|
||||
});
|
||||
|
||||
it('should include indexes of visible layers', function () {
|
||||
expect(this.cartoDBLayerGroup.getStaticImageURLTemplate()).toEqual('http://carto.com/image?layer=0,1,2,3,4');
|
||||
});
|
||||
|
||||
it('should not include hidden layers', function () {
|
||||
this.cartoDBLayer1.hide();
|
||||
this.torqueLayer.hide();
|
||||
|
||||
expect(this.cartoDBLayerGroup.getStaticImageURLTemplate()).toEqual('http://carto.com/image?layer=0,2,4');
|
||||
});
|
||||
|
||||
it('should ignore Google Maps base layers (Maps API is not aware of them)', function () {
|
||||
this.baseLayer = new GMapsBaseLayer(null);
|
||||
this.cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
this.cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.layersCollection.reset([
|
||||
this.baseLayer,
|
||||
this.cartoDBLayer1,
|
||||
this.cartoDBLayer2
|
||||
]);
|
||||
|
||||
expect(this.cartoDBLayerGroup.getStaticImageURLTemplate()).toEqual('http://carto.com/image?layer=0,1');
|
||||
});
|
||||
|
||||
it('should include api_key param', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
apiKey: 'THE_API_KEY'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getStaticImageURLTemplate()).toEqual('http://carto.com/image?layer=0,1,2,3,4&api_key=THE_API_KEY');
|
||||
});
|
||||
|
||||
it('should include auth_token param', function () {
|
||||
this.cartoDBLayerGroup.set({
|
||||
authToken: 'AUTH_TOKEN'
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getStaticImageURLTemplate()).toEqual('http://carto.com/image?layer=0,1,2,3,4&auth_token=AUTH_TOKEN');
|
||||
});
|
||||
|
||||
it('should include subdomains', function () {
|
||||
this.cartoDBLayerGroup.set('urls', {
|
||||
image: 'http://{s}.carto.com/image',
|
||||
subdomains: [ '0', '1' ]
|
||||
});
|
||||
|
||||
expect(this.cartoDBLayerGroup.getStaticImageURLTemplate()).toEqual('http://0.carto.com/image?layer=0,1,2,3,4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.addError', function () {
|
||||
it('should throw an error if the error does not have a type', function () {
|
||||
expect(this.cartoDBLayerGroup.addError).toThrow();
|
||||
});
|
||||
|
||||
it('should trigger an error with the specified type', function () {
|
||||
var called = '';
|
||||
|
||||
this.cartoDBLayerGroup.on('error:limit', function () {
|
||||
called = 'limit';
|
||||
});
|
||||
this.cartoDBLayerGroup.on('error:tile', function () {
|
||||
called = 'tile';
|
||||
});
|
||||
|
||||
this.cartoDBLayerGroup.addError({ type: 'limit' });
|
||||
expect(called).toEqual('limit');
|
||||
|
||||
this.cartoDBLayerGroup.addError({ type: 'tile' });
|
||||
expect(called).toEqual('tile');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,261 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"query": [
|
||||
"los",
|
||||
"angeles"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"id": "place.9962989141465270",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"place"
|
||||
],
|
||||
"relevance": 0.99,
|
||||
"properties": {
|
||||
"wikidata": "Q65"
|
||||
},
|
||||
"text": "Los Angeles",
|
||||
"place_name": "Los Angeles, California, United States",
|
||||
"bbox": [
|
||||
-118.529221009603,
|
||||
33.901599990108,
|
||||
-118.121099990025,
|
||||
34.1612200099034
|
||||
],
|
||||
"center": [
|
||||
-118.2439,
|
||||
34.0544
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-118.2439,
|
||||
34.0544
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "region.3591",
|
||||
"short_code": "US-CA",
|
||||
"wikidata": "Q99",
|
||||
"text": "California"
|
||||
},
|
||||
{
|
||||
"id": "country.3145",
|
||||
"short_code": "us",
|
||||
"wikidata": "Q30",
|
||||
"text": "United States"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "place.10952642230180310",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"place"
|
||||
],
|
||||
"relevance": 0.99,
|
||||
"properties": {
|
||||
"wikidata": "Q16910"
|
||||
},
|
||||
"text": "Los Ángeles",
|
||||
"place_name": "Los Ángeles, Bío Bío, Chile",
|
||||
"bbox": [
|
||||
-72.68248,
|
||||
-37.663862,
|
||||
-72.041277,
|
||||
-37.178368
|
||||
],
|
||||
"center": [
|
||||
-72.35,
|
||||
-37.46667
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-72.35,
|
||||
-37.46667
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "region.3552",
|
||||
"short_code": "CL-BI",
|
||||
"wikidata": "Q2170",
|
||||
"text": "Bío Bío"
|
||||
},
|
||||
{
|
||||
"id": "country.344",
|
||||
"short_code": "cl",
|
||||
"wikidata": "Q298",
|
||||
"text": "Chile"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poi.1611278850983920",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"poi"
|
||||
],
|
||||
"relevance": 0.99,
|
||||
"properties": {
|
||||
"address": "1 World Way",
|
||||
"category": "international airport, airport",
|
||||
"tel": "(310) 646-5252",
|
||||
"wikidata": "Q8731",
|
||||
"landmark": true,
|
||||
"maki": "airport"
|
||||
},
|
||||
"text": "Los Angeles International Airport",
|
||||
"place_name": "Los Angeles International Airport, 1 World Way, Los Angeles, California 90045, United States",
|
||||
"center": [
|
||||
-118.408056,
|
||||
33.9425
|
||||
],
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
-118.408056,
|
||||
33.9425
|
||||
],
|
||||
"type": "Point"
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "neighborhood.33720",
|
||||
"text": "Westchester"
|
||||
},
|
||||
{
|
||||
"id": "postcode.8081932850252730",
|
||||
"text": "90045"
|
||||
},
|
||||
{
|
||||
"id": "place.9962989141465270",
|
||||
"wikidata": "Q65",
|
||||
"text": "Los Angeles"
|
||||
},
|
||||
{
|
||||
"id": "region.3591",
|
||||
"short_code": "US-CA",
|
||||
"wikidata": "Q99",
|
||||
"text": "California"
|
||||
},
|
||||
{
|
||||
"id": "country.3145",
|
||||
"short_code": "us",
|
||||
"wikidata": "Q30",
|
||||
"text": "United States"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "neighborhood.2104633",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"neighborhood"
|
||||
],
|
||||
"relevance": 0.99,
|
||||
"properties": {},
|
||||
"text": "Los Angeles Heights - Keystone",
|
||||
"place_name": "Los Angeles Heights - Keystone, San Antonio, Texas 78201, United States",
|
||||
"bbox": [
|
||||
-98.534942,
|
||||
29.453364,
|
||||
-98.514652,
|
||||
29.485214
|
||||
],
|
||||
"center": [
|
||||
-98.52,
|
||||
29.47
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-98.52,
|
||||
29.47
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "postcode.7069290925572850",
|
||||
"text": "78201"
|
||||
},
|
||||
{
|
||||
"id": "place.7705127234253710",
|
||||
"wikidata": "Q975",
|
||||
"text": "San Antonio"
|
||||
},
|
||||
{
|
||||
"id": "region.3818",
|
||||
"short_code": "US-TX",
|
||||
"wikidata": "Q1439",
|
||||
"text": "Texas"
|
||||
},
|
||||
{
|
||||
"id": "country.3145",
|
||||
"short_code": "us",
|
||||
"wikidata": "Q30",
|
||||
"text": "United States"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poi.17555628334440500",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"poi"
|
||||
],
|
||||
"relevance": 0.99,
|
||||
"properties": {
|
||||
"address": "3939 S Figueroa St",
|
||||
"category": "stadium, arena",
|
||||
"tel": "(213) 747-7111",
|
||||
"wikidata": "Q849784",
|
||||
"landmark": true,
|
||||
"maki": "baseball"
|
||||
},
|
||||
"text": "Los Angeles Memorial Coliseum",
|
||||
"place_name": "Los Angeles Memorial Coliseum, 3939 S Figueroa St, Los Angeles, California 90037, United States",
|
||||
"center": [
|
||||
-118.287778,
|
||||
34.014167
|
||||
],
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
-118.287778,
|
||||
34.014167
|
||||
],
|
||||
"type": "Point"
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "neighborhood.293901",
|
||||
"text": "South Los Angeles"
|
||||
},
|
||||
{
|
||||
"id": "postcode.15612390715732530",
|
||||
"text": "90037"
|
||||
},
|
||||
{
|
||||
"id": "place.9962989141465270",
|
||||
"wikidata": "Q65",
|
||||
"text": "Los Angeles"
|
||||
},
|
||||
{
|
||||
"id": "region.3591",
|
||||
"short_code": "US-CA",
|
||||
"wikidata": "Q99",
|
||||
"text": "California"
|
||||
},
|
||||
{
|
||||
"id": "country.3145",
|
||||
"short_code": "us",
|
||||
"wikidata": "Q30",
|
||||
"text": "United States"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"attribution": "NOTICE: © 2017 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service (https://www.mapbox.com/about/maps/). This response and the information it contains may not be retained."
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"query": [
|
||||
"plaza",
|
||||
"de",
|
||||
"barcelos"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"id": "poi.10895640694945210",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"poi"
|
||||
],
|
||||
"relevance": 0.6666666666666666,
|
||||
"properties": {
|
||||
"landmark": true,
|
||||
"tel": "07524 914990",
|
||||
"category": "cafe, coffee, restaurant, tea, tea house",
|
||||
"address": "Ravensburger Straße 8"
|
||||
},
|
||||
"text": "Plaza",
|
||||
"place_name": "Plaza, Ravensburger Straße 8, Bad Waldsee, Baden-Württemberg 88339, Germany",
|
||||
"center": [
|
||||
9.754478,
|
||||
47.920347
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
9.754478,
|
||||
47.920347
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "postcode.11130053318616830",
|
||||
"text": "88339"
|
||||
},
|
||||
{
|
||||
"id": "place.11130053318505290",
|
||||
"wikidata": "Q515423",
|
||||
"text": "Bad Waldsee"
|
||||
},
|
||||
{
|
||||
"id": "region.3495",
|
||||
"short_code": "DE-BW",
|
||||
"wikidata": "Q985",
|
||||
"text": "Baden-Württemberg"
|
||||
},
|
||||
{
|
||||
"id": "country.3135",
|
||||
"short_code": "de",
|
||||
"wikidata": "Q183",
|
||||
"text": "Germany"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poi.13433334923344580",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"poi"
|
||||
],
|
||||
"relevance": 0.6666666666666666,
|
||||
"properties": {
|
||||
"landmark": true,
|
||||
"tel": "06403 74200",
|
||||
"category": "rail station, train station",
|
||||
"address": "Alte Heerstraße 27",
|
||||
"maki": "rail"
|
||||
},
|
||||
"text": "Platz",
|
||||
"place_name": "Platz, Alte Heerstraße 27, Bodolz, Bayern 88131, Germany",
|
||||
"center": [
|
||||
9.667166,
|
||||
47.567462
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
9.667166,
|
||||
47.567462
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "locality.13257312967514310",
|
||||
"wikidata": "Q11696975",
|
||||
"text": "Enzisweiler"
|
||||
},
|
||||
{
|
||||
"id": "postcode.7704245689115710",
|
||||
"text": "88131"
|
||||
},
|
||||
{
|
||||
"id": "place.11779142489218390",
|
||||
"wikidata": "Q552427",
|
||||
"text": "Bodolz"
|
||||
},
|
||||
{
|
||||
"id": "region.3186",
|
||||
"short_code": "DE-BY",
|
||||
"wikidata": "Q980",
|
||||
"text": "Bayern"
|
||||
},
|
||||
{
|
||||
"id": "country.3135",
|
||||
"short_code": "de",
|
||||
"wikidata": "Q183",
|
||||
"text": "Germany"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poi.11479188654945210",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"poi"
|
||||
],
|
||||
"relevance": 0.6666666666666666,
|
||||
"properties": {
|
||||
"landmark": true,
|
||||
"tel": "0921 5160544",
|
||||
"category": "restaurant",
|
||||
"address": "Kirchgasse 24",
|
||||
"maki": "restaurant"
|
||||
},
|
||||
"text": "Plaza",
|
||||
"place_name": "Plaza, Kirchgasse 24, Bayreuth, Bayern 95444, Germany",
|
||||
"center": [
|
||||
11.57395,
|
||||
49.94327
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
11.57395,
|
||||
49.94327
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "postcode.14977288459298330",
|
||||
"text": "95444"
|
||||
},
|
||||
{
|
||||
"id": "place.14796666081196300",
|
||||
"wikidata": "Q3923",
|
||||
"text": "Bayreuth"
|
||||
},
|
||||
{
|
||||
"id": "region.3186",
|
||||
"short_code": "DE-BY",
|
||||
"wikidata": "Q980",
|
||||
"text": "Bayern"
|
||||
},
|
||||
{
|
||||
"id": "country.3135",
|
||||
"short_code": "de",
|
||||
"wikidata": "Q183",
|
||||
"text": "Germany"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poi.9477875054945210",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"poi"
|
||||
],
|
||||
"relevance": 0.3333333333333333,
|
||||
"properties": {
|
||||
"landmark": true,
|
||||
"tel": "0226 344 306",
|
||||
"category": "restaurant",
|
||||
"maki": "restaurant"
|
||||
},
|
||||
"text": "Plaza",
|
||||
"place_name": "Plaza, Beringe, Limburg 5986, Netherlands",
|
||||
"center": [
|
||||
5.947389,
|
||||
51.337527
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
5.947389,
|
||||
51.337527
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "postcode.6633279068411020",
|
||||
"text": "5986"
|
||||
},
|
||||
{
|
||||
"id": "place.6017505065203911",
|
||||
"wikidata": "Q1878867",
|
||||
"text": "Beringe"
|
||||
},
|
||||
{
|
||||
"id": "region.213188",
|
||||
"short_code": "NL-LI",
|
||||
"wikidata": "Q1093",
|
||||
"text": "Limburg"
|
||||
},
|
||||
{
|
||||
"id": "country.3101",
|
||||
"short_code": "nl",
|
||||
"wikidata": "Q55",
|
||||
"text": "Netherlands"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "poi.6170918672945210",
|
||||
"type": "Feature",
|
||||
"place_type": [
|
||||
"poi"
|
||||
],
|
||||
"relevance": 0.3333333333333333,
|
||||
"properties": {
|
||||
"landmark": true,
|
||||
"tel": "0382 559413",
|
||||
"category": "hotel, lodging, motel",
|
||||
"address": "Via Togliatti 39"
|
||||
},
|
||||
"text": "Plaza",
|
||||
"place_name": "Plaza, Via Togliatti 39, San Martino Siccomario, Pavia 27028, Italy",
|
||||
"center": [
|
||||
9.130854,
|
||||
45.159336
|
||||
],
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
9.130854,
|
||||
45.159336
|
||||
]
|
||||
},
|
||||
"context": [
|
||||
{
|
||||
"id": "postcode.12821918527764180",
|
||||
"text": "27028"
|
||||
},
|
||||
{
|
||||
"id": "place.12821918528623280",
|
||||
"wikidata": "Q41026",
|
||||
"text": "San Martino Siccomario"
|
||||
},
|
||||
{
|
||||
"id": "region.3790",
|
||||
"short_code": "IT-PV",
|
||||
"wikidata": "Q16231",
|
||||
"text": "Pavia"
|
||||
},
|
||||
{
|
||||
"id": "country.333",
|
||||
"short_code": "it",
|
||||
"wikidata": "Q38",
|
||||
"text": "Italy"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"attribution": "NOTICE: © 2017 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service (https://www.mapbox.com/about/maps/). This response and the information it contains may not be retained."
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
var mapboxGeocoder = require('../../../../src/geo/geocoder/mapbox-geocoder');
|
||||
var TOKEN = 'fake_token';
|
||||
describe('mapbox-geocoder', function () {
|
||||
describe('.geocode', function () {
|
||||
it('should build the right fetch url (add address and access_token)', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return require('./mapbox-geocoder-response-0'); } }));
|
||||
mapboxGeocoder.geocode('fake_address', TOKEN).then(function (result) {
|
||||
var expectedFetchUrl = 'https://api.mapbox.com/geocoding/v5/mapbox.places-permanent/fake_address.json?access_token=fake_token';
|
||||
expect(window.fetch).toHaveBeenCalledWith(expectedFetchUrl);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should geocode a city location', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return require('./mapbox-geocoder-response-0'); } }));
|
||||
mapboxGeocoder.geocode('Vigo', TOKEN)
|
||||
.then(function (results) {
|
||||
expect(results).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a well formated response [example 0]', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return require('./mapbox-geocoder-response-0'); } }));
|
||||
mapboxGeocoder.geocode('Vigo', TOKEN)
|
||||
.then(function (result) {
|
||||
result = result[0];
|
||||
expect(result.center).toBeDefined();
|
||||
expect(result.center[0]).toEqual(34.0544);
|
||||
expect(result.center[1]).toEqual(-118.2439);
|
||||
// Bbox
|
||||
expect(result.boundingbox.south).toEqual(-118.529221009603);
|
||||
expect(result.boundingbox.west).toEqual(33.901599990108);
|
||||
expect(result.boundingbox.north).toEqual(-118.121099990025);
|
||||
expect(result.boundingbox.east).toEqual(34.1612200099034);
|
||||
// Type
|
||||
expect(result.type).toEqual('venue');
|
||||
done();
|
||||
}).catch(console.error);
|
||||
});
|
||||
|
||||
it('should return a well formated response when the response has no bbox [example 1]', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return require('./mapbox-geocoder-response-1'); } }));
|
||||
mapboxGeocoder.geocode('Plaza de Barcelos', TOKEN)
|
||||
.then(function (result) {
|
||||
result = result[0];
|
||||
expect(result.center).toBeDefined();
|
||||
expect(result.center[0]).toEqual(47.920347);
|
||||
expect(result.center[1]).toEqual(9.754478);
|
||||
// Bbox
|
||||
expect(result.bbox).toBeUndefined();
|
||||
// Type
|
||||
expect(result.type).toEqual('venue');
|
||||
done();
|
||||
}).catch(console.error);
|
||||
});
|
||||
|
||||
it('should return an empty array when the response is empty', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return { features: [] }; } }));
|
||||
mapboxGeocoder.geocode('Vigo', TOKEN)
|
||||
.then(function (result) {
|
||||
expect(result).toEqual([]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,445 @@
|
||||
{
|
||||
"summary": {
|
||||
"query": "santander",
|
||||
"queryType": "NON_NEAR",
|
||||
"queryTime": 39,
|
||||
"numResults": 10,
|
||||
"offset": 0,
|
||||
"totalResults": 24811,
|
||||
"fuzzyLevel": 1
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "ES/GEO/p0/7661",
|
||||
"score": 2.418,
|
||||
"entityType": "Municipality",
|
||||
"address": {
|
||||
"municipality": "Santander",
|
||||
"countrySecondarySubdivision": "Cantabria",
|
||||
"countrySubdivision": "Cantabria",
|
||||
"countryCode": "ES",
|
||||
"country": "Spain",
|
||||
"countryCodeISO3": "ESP",
|
||||
"freeformAddress": "Santander"
|
||||
},
|
||||
"position": {
|
||||
"lat": 43.46141,
|
||||
"lon": -3.8093
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 43.49482,
|
||||
"lon": -3.88905
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 43.43446,
|
||||
"lon": -3.76325
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 43.49482,
|
||||
"lon": -3.88905
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 43.43446,
|
||||
"lon": -3.76325
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-00007d2e35e3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "PH/GEO/p0/1587",
|
||||
"score": 2.382,
|
||||
"entityType": "Municipality",
|
||||
"address": {
|
||||
"municipality": "Santander",
|
||||
"countrySecondarySubdivision": "Cebu",
|
||||
"countrySubdivision": "Central Visayas",
|
||||
"countryCode": "PH",
|
||||
"country": "Philippines",
|
||||
"countryCodeISO3": "PHL",
|
||||
"freeformAddress": "Santander, Central Visayas"
|
||||
},
|
||||
"position": {
|
||||
"lat": 9.42242,
|
||||
"lon": 123.30378
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 9.47779,
|
||||
"lon": 123.29687
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 9.41298,
|
||||
"lon": 123.3632
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 9.47779,
|
||||
"lon": 123.29687
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 9.41298,
|
||||
"lon": 123.3632
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-000077378fa7"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "MX/GEO/p0/340",
|
||||
"score": 2.362,
|
||||
"entityType": "Municipality",
|
||||
"address": {
|
||||
"municipality": "Jiménez",
|
||||
"countrySubdivision": "Tamaulipas",
|
||||
"countryCode": "MX",
|
||||
"country": "Mexico",
|
||||
"countryCodeISO3": "MEX",
|
||||
"freeformAddress": "Jiménez"
|
||||
},
|
||||
"position": {
|
||||
"lat": 24.21378,
|
||||
"lon": -98.48187
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 24.47171,
|
||||
"lon": -98.72639
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 23.93939,
|
||||
"lon": -98.27799
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 24.47171,
|
||||
"lon": -98.72639
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 23.93939,
|
||||
"lon": -98.27799
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-00007737d289"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "CO/GEO/p0/252",
|
||||
"score": 2.36,
|
||||
"entityType": "Municipality",
|
||||
"address": {
|
||||
"municipality": "Puerto Santander",
|
||||
"countrySubdivision": "Norte de Santander",
|
||||
"countryCode": "CO",
|
||||
"country": "Colombia",
|
||||
"countryCodeISO3": "COL",
|
||||
"freeformAddress": "Puerto Santander, Norte de Santander"
|
||||
},
|
||||
"position": {
|
||||
"lat": 8.36227,
|
||||
"lon": -72.40896
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 8.38354,
|
||||
"lon": -72.4475
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 8.26839,
|
||||
"lon": -72.38042
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 8.38354,
|
||||
"lon": -72.4475
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 8.26839,
|
||||
"lon": -72.38042
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-00007d30e01c"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "CO/GEO/p0/888",
|
||||
"score": 2.358,
|
||||
"entityType": "Municipality",
|
||||
"address": {
|
||||
"municipality": "Santander",
|
||||
"countrySubdivision": "Amazonas",
|
||||
"countryCode": "CO",
|
||||
"country": "Colombia",
|
||||
"countryCodeISO3": "COL",
|
||||
"freeformAddress": "Santander, Amazonas"
|
||||
},
|
||||
"position": {
|
||||
"lat": -0.62217,
|
||||
"lon": -72.38281
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": -0.26464,
|
||||
"lon": -72.99754
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": -1.89121,
|
||||
"lon": -70.72647
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": -0.26464,
|
||||
"lon": -72.99754
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": -1.89121,
|
||||
"lon": -70.72647
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-00007d30ef7b"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "CO/GEO/p0/1010",
|
||||
"score": 2.341,
|
||||
"entityType": "Municipality",
|
||||
"address": {
|
||||
"municipality": "Santander de Quilichao",
|
||||
"countrySubdivision": "Cauca",
|
||||
"countryCode": "CO",
|
||||
"country": "Colombia",
|
||||
"countryCodeISO3": "COL",
|
||||
"freeformAddress": "Santander de Quilichao, Cauca"
|
||||
},
|
||||
"position": {
|
||||
"lat": 3.00879,
|
||||
"lon": -76.4859
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 3.1493,
|
||||
"lon": -76.61535
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 2.8461,
|
||||
"lon": -76.37358
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 3.1493,
|
||||
"lon": -76.61535
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 2.8461,
|
||||
"lon": -76.37358
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-00007d30eff7"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "CO/GEO/p0/6",
|
||||
"score": 2.255,
|
||||
"entityType": "CountrySubdivision",
|
||||
"address": {
|
||||
"countrySubdivision": "Santander",
|
||||
"countryCode": "CO",
|
||||
"country": "Colombia",
|
||||
"countryCodeISO3": "COL",
|
||||
"freeformAddress": "Santander"
|
||||
},
|
||||
"position": {
|
||||
"lat": 6.92507,
|
||||
"lon": -73.50153
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 8.14342,
|
||||
"lon": -74.52666
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 5.70671,
|
||||
"lon": -72.4764
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 8.14342,
|
||||
"lon": -74.52666
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 5.70671,
|
||||
"lon": -72.4764
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-000077374466"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "CO/GEO/p0/5",
|
||||
"score": 2.211,
|
||||
"entityType": "CountrySubdivision",
|
||||
"address": {
|
||||
"countrySubdivision": "Norte de Santander",
|
||||
"countryCode": "CO",
|
||||
"country": "Colombia",
|
||||
"countryCodeISO3": "COL",
|
||||
"freeformAddress": "Norte de Santander"
|
||||
},
|
||||
"position": {
|
||||
"lat": 8.08458,
|
||||
"lon": -72.84278
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 9.2961,
|
||||
"lon": -73.63743
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 6.87306,
|
||||
"lon": -72.04813
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 9.2961,
|
||||
"lon": -73.63743
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 6.87306,
|
||||
"lon": -72.04813
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "00005858-5800-1200-0000-000077374465"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "CO/GEO/p0/1668",
|
||||
"score": 2.177,
|
||||
"entityType": "MunicipalitySubdivision",
|
||||
"address": {
|
||||
"municipalitySubdivision": "Santander",
|
||||
"municipality": "Cali",
|
||||
"countrySubdivision": "Valle del Cauca",
|
||||
"countryCode": "CO",
|
||||
"country": "Colombia",
|
||||
"countryCodeISO3": "COL",
|
||||
"freeformAddress": "Cali Santander, Valle del Cauca"
|
||||
},
|
||||
"position": {
|
||||
"lat": 3.46266,
|
||||
"lon": -76.51554
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 3.4665,
|
||||
"lon": -76.52026
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 3.45905,
|
||||
"lon": -76.51054
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 3.4665,
|
||||
"lon": -76.52026
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 3.45905,
|
||||
"lon": -76.51054
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "0000434f-3300-3c00-0000-000065ec89e3"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Geography",
|
||||
"id": "CO/GEO/p0/2477",
|
||||
"score": 2.177,
|
||||
"entityType": "MunicipalitySubdivision",
|
||||
"address": {
|
||||
"municipalitySubdivision": "Santander",
|
||||
"municipality": "Medellín",
|
||||
"countrySubdivision": "Antioquia",
|
||||
"countryCode": "CO",
|
||||
"country": "Colombia",
|
||||
"countryCodeISO3": "COL",
|
||||
"freeformAddress": "Medellín Santander, Antioquia"
|
||||
},
|
||||
"position": {
|
||||
"lat": 6.30768,
|
||||
"lon": -75.57501
|
||||
},
|
||||
"viewport": {
|
||||
"topLeftPoint": {
|
||||
"lat": 6.31099,
|
||||
"lon": -75.57874
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 6.30185,
|
||||
"lon": -75.57128
|
||||
}
|
||||
},
|
||||
"boundingBox": {
|
||||
"topLeftPoint": {
|
||||
"lat": 6.31099,
|
||||
"lon": -75.57874
|
||||
},
|
||||
"btmRightPoint": {
|
||||
"lat": 6.30185,
|
||||
"lon": -75.57128
|
||||
}
|
||||
},
|
||||
"dataSources": {
|
||||
"geometry": {
|
||||
"id": "0000434f-3200-3c00-0000-000065a03d92"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
var tomtomGeocoder = require('../../../../src/geo/geocoder/tomtom-geocoder');
|
||||
var API_KEY = 'fake_api_key';
|
||||
describe('tomtom-geocoder', function () {
|
||||
describe('.geocode', function () {
|
||||
it('should build the right fetch url (add address and apiKey)', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return { results: [] }; } }));
|
||||
tomtomGeocoder.geocode('fake_address', API_KEY).then(function (result) {
|
||||
var expectedFetchUrl = 'https://api.tomtom.com/search/2/search/fake_address.json?key=fake_api_key';
|
||||
expect(window.fetch).toHaveBeenCalledWith(expectedFetchUrl);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should geocode a city location', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return require('./tomtom-geocoder-response-0'); } }));
|
||||
tomtomGeocoder.geocode('Santander', API_KEY)
|
||||
.then(function (results) {
|
||||
expect(results).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a well formated response [example 0]', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return require('./tomtom-geocoder-response-0'); } }));
|
||||
tomtomGeocoder.geocode('Santander', API_KEY)
|
||||
.then(function (results) {
|
||||
let bestCandidate = results[0];
|
||||
expect(bestCandidate.center).toBeDefined();
|
||||
expect(bestCandidate.center[0]).toEqual(43.46141); // lat
|
||||
expect(bestCandidate.center[1]).toEqual(-3.8093); // lon
|
||||
// Bbox
|
||||
expect(bestCandidate.boundingbox.south).toEqual(43.43446);
|
||||
expect(bestCandidate.boundingbox.west).toEqual(-3.88905);
|
||||
expect(bestCandidate.boundingbox.north).toEqual(43.49482);
|
||||
expect(bestCandidate.boundingbox.east).toEqual(-3.76325);
|
||||
// Type
|
||||
expect(bestCandidate.type).toEqual('localadmin');
|
||||
done();
|
||||
}).catch(console.error);
|
||||
});
|
||||
|
||||
it('should return an empty array when the response is empty', function (done) {
|
||||
spyOn(window, 'fetch').and.returnValue(Promise.resolve({ json: function () { return { results: [] }; } }));
|
||||
tomtomGeocoder.geocode('ABCDEFGHIJ', API_KEY)
|
||||
.then(function (result) {
|
||||
expect(result).toEqual([]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,148 @@
|
||||
var _ = require('underscore');
|
||||
var GeometryFactory = require('../../../../src/geo/geometry-models/geometry-factory');
|
||||
var Point = require('../../../../src/geo/geometry-models/point');
|
||||
var Polyline = require('../../../../src/geo/geometry-models/polyline');
|
||||
var Polygon = require('../../../../src/geo/geometry-models/polygon');
|
||||
var MultiPoint = require('../../../../src/geo/geometry-models/multi-point');
|
||||
var MultiPolygon = require('../../../../src/geo/geometry-models/multi-polygon');
|
||||
var MultiPolyline = require('../../../../src/geo/geometry-models/multi-polyline');
|
||||
|
||||
var geometryAsFeature = function (geometry) {
|
||||
return {
|
||||
'type': 'Feature',
|
||||
'properties': {},
|
||||
'geometry': geometry
|
||||
};
|
||||
};
|
||||
|
||||
describe('src/geo/geometry-models/geometry-factory', function () {
|
||||
describe('.createGeometryFromGeoJSON', function () {
|
||||
var pointGeometry = {
|
||||
'type': 'Point',
|
||||
'coordinates': [
|
||||
-3.779296875,
|
||||
40.245991504199026
|
||||
]
|
||||
};
|
||||
|
||||
_.each([ pointGeometry, geometryAsFeature(pointGeometry) ], function (geoJSON) {
|
||||
it('should create a point', function () {
|
||||
var geometry = GeometryFactory.createGeometryFromGeoJSON(geoJSON);
|
||||
|
||||
expect(geometry instanceof Point).toBeTruthy();
|
||||
expect(geometry.getCoordinates()).toEqual([ 40.245991504199026, -3.779296875 ]);
|
||||
});
|
||||
});
|
||||
|
||||
var polylineGeometry = {
|
||||
'type': 'LineString',
|
||||
'coordinates': [
|
||||
[
|
||||
-2.021484375,
|
||||
43.51668853502906
|
||||
],
|
||||
[
|
||||
3.6035156249999996,
|
||||
42.293564192170095
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
_.each([ polylineGeometry, geometryAsFeature(polylineGeometry) ], function (geoJSON) {
|
||||
it('should create a polyline', function () {
|
||||
var geometry = GeometryFactory.createGeometryFromGeoJSON(geoJSON);
|
||||
|
||||
expect(geometry instanceof Polyline).toBeTruthy();
|
||||
expect(geometry.getCoordinates()).toEqual([
|
||||
[ 43.51668853502906, -2.021484375 ],
|
||||
[ 42.293564192170095, 3.6035156249999996 ]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
var polygonGeometry = {
|
||||
'type': 'Polygon',
|
||||
'coordinates': [
|
||||
[
|
||||
[
|
||||
-8.96484375,
|
||||
41.918628865183045
|
||||
],
|
||||
[
|
||||
-7.84423828125,
|
||||
43.74728909225908
|
||||
],
|
||||
[
|
||||
-1.69189453125,
|
||||
43.34914966389313
|
||||
],
|
||||
[
|
||||
-8.96484375,
|
||||
41.918628865183045
|
||||
]
|
||||
]
|
||||
]
|
||||
};
|
||||
|
||||
_.each([ polygonGeometry, geometryAsFeature(polygonGeometry) ], function (geoJSON) {
|
||||
it('should create a polygon', function () {
|
||||
var geometry = GeometryFactory.createGeometryFromGeoJSON(geoJSON);
|
||||
|
||||
expect(geometry instanceof Polygon).toBeTruthy();
|
||||
expect(geometry.getCoordinates()).toEqual([
|
||||
[ 41.918628865183045, -8.96484375 ],
|
||||
[ 43.74728909225908, -7.84423828125 ],
|
||||
[ 43.34914966389313, -1.69189453125 ]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
var multiPointGeometry = {
|
||||
'type': 'MultiPoint',
|
||||
'coordinates': [ [100.0, 0.0], [101.0, 1.0] ]
|
||||
};
|
||||
|
||||
it('should create a multipoint', function () {
|
||||
var geometry = GeometryFactory.createGeometryFromGeoJSON(multiPointGeometry);
|
||||
|
||||
expect(geometry instanceof MultiPoint).toBeTruthy();
|
||||
expect(geometry.geometries.length).toEqual(2);
|
||||
expect(geometry.geometries.at(0).getCoordinates()).toEqual([ 0, 100 ]);
|
||||
expect(geometry.geometries.at(1).getCoordinates()).toEqual([ 1, 101 ]);
|
||||
});
|
||||
|
||||
var multiPolygonGeometry = {
|
||||
'type': 'MultiPolygon',
|
||||
'coordinates': [
|
||||
[ [ [102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0] ] ],
|
||||
[ [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ] ]
|
||||
]
|
||||
};
|
||||
|
||||
it('should create a multipolygon', function () {
|
||||
var geometry = GeometryFactory.createGeometryFromGeoJSON(multiPolygonGeometry);
|
||||
|
||||
expect(geometry instanceof MultiPolygon).toBeTruthy();
|
||||
expect(geometry.geometries.length).toEqual(2);
|
||||
expect(geometry.geometries.at(0).getCoordinates()).toEqual([ [ 2, 102 ], [ 2, 103 ], [ 3, 103 ], [ 3, 102 ] ]);
|
||||
expect(geometry.geometries.at(1).getCoordinates()).toEqual([ [ 0, 100 ], [ 0, 101 ], [ 1, 101 ], [ 1, 100 ] ]);
|
||||
});
|
||||
|
||||
var multiPolylineGeometry = {
|
||||
'type': 'MultiLineString',
|
||||
'coordinates': [
|
||||
[ [100.0, 0.0], [101.0, 1.0] ],
|
||||
[ [102.0, 2.0], [103.0, 3.0] ]
|
||||
]
|
||||
};
|
||||
|
||||
it('should create a multipolyline', function () {
|
||||
var geometry = GeometryFactory.createGeometryFromGeoJSON(multiPolylineGeometry);
|
||||
|
||||
expect(geometry instanceof MultiPolyline).toBeTruthy();
|
||||
expect(geometry.geometries.length).toEqual(2);
|
||||
expect(geometry.geometries.at(0).getCoordinates()).toEqual([ [ 0, 100 ], [ 1, 101 ] ]);
|
||||
expect(geometry.geometries.at(1).getCoordinates()).toEqual([ [ 2, 102 ], [ 3, 103 ] ]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
var MultiPoint = require('../../../../src/geo/geometry-models/multi-point');
|
||||
|
||||
describe('src/geo/geometry-models/multi-point', function () {
|
||||
beforeEach(function () {
|
||||
this.multiPoint = new MultiPoint(null, {
|
||||
latlngs: [
|
||||
[0, 1],
|
||||
[1, 2]
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
describe('.toGeoJSON', function () {
|
||||
it('should generate the GeoJSON correctly', function () {
|
||||
expect(this.multiPoint.toGeoJSON()).toEqual({
|
||||
type: 'MultiPoint',
|
||||
coordinates: [ [ 1, 0 ], [ 2, 1 ] ]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setCoordinatesFromGeoJSON', function () {
|
||||
it('should update the coordinates', function () {
|
||||
var newAndExpectedGeoJSON = {
|
||||
type: 'MultiPoint',
|
||||
coordinates: [ [ 0, 0 ], [ 10, 10 ] ]
|
||||
};
|
||||
this.multiPoint.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
expect(this.multiPoint.toGeoJSON()).toEqual(newAndExpectedGeoJSON);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
var MultiPolygon = require('../../../../src/geo/geometry-models/multi-polygon');
|
||||
|
||||
describe('src/geo/geometry-models/multi-polygon', function () {
|
||||
beforeEach(function () {
|
||||
this.multiPolygon = new MultiPolygon(null, {
|
||||
latlngs: [
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4]
|
||||
],
|
||||
[
|
||||
[0, 10],
|
||||
[10, 20],
|
||||
[20, 30],
|
||||
[30, 40]
|
||||
]
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
describe('.toGeoJSON', function () {
|
||||
it('should generate the GeoJSON correctly', function () {
|
||||
expect(this.multiPolygon.toGeoJSON()).toEqual({
|
||||
type: 'MultiPolygon',
|
||||
coordinates: [
|
||||
[
|
||||
[ [ 1, 0 ], [ 2, 1 ], [ 3, 2 ], [ 4, 3 ], [ 1, 0 ] ]
|
||||
], [
|
||||
[ [ 10, 0 ], [ 20, 10 ], [ 30, 20 ], [ 40, 30 ], [ 10, 0 ] ]
|
||||
]
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setCoordinatesFromGeoJSON', function () {
|
||||
it('should update the coordinates', function () {
|
||||
var newAndExpectedGeoJSON = {
|
||||
type: 'MultiPolygon',
|
||||
coordinates: [
|
||||
[
|
||||
[ [ 0, 0 ], [ 2, 1 ], [ 3, 2 ], [ 4, 3 ], [ 0, 0 ] ]
|
||||
], [
|
||||
[ [ 100, 0 ], [ 20, 10 ], [ 30, 20 ], [ 40, 30 ], [ 100, 0 ] ]
|
||||
]
|
||||
]
|
||||
};
|
||||
this.multiPolygon.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
expect(this.multiPolygon.toGeoJSON()).toEqual(newAndExpectedGeoJSON);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
var MultiPolyline = require('../../../../src/geo/geometry-models/multi-polyline');
|
||||
|
||||
describe('src/geo/geometry-models/multi-polyline', function () {
|
||||
beforeEach(function () {
|
||||
this.multiPolyline = new MultiPolyline(null, {
|
||||
latlngs: [
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4]
|
||||
],
|
||||
[
|
||||
[0, 10],
|
||||
[10, 20],
|
||||
[20, 30],
|
||||
[30, 40]
|
||||
]
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
describe('.toGeoJSON', function () {
|
||||
it('should generate the GeoJSON correctly', function () {
|
||||
expect(this.multiPolyline.toGeoJSON()).toEqual({
|
||||
type: 'MultiLineString',
|
||||
coordinates: [
|
||||
[
|
||||
[ 1, 0 ], [ 2, 1 ], [ 3, 2 ], [ 4, 3 ]
|
||||
], [
|
||||
[ 10, 0 ], [ 20, 10 ], [ 30, 20 ], [ 40, 30 ]
|
||||
]
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setCoordinatesFromGeoJSON', function () {
|
||||
it('should update the coordinates', function () {
|
||||
var newAndExpectedGeoJSON = {
|
||||
type: 'MultiLineString',
|
||||
coordinates: [
|
||||
[
|
||||
[ 100, 0 ], [ 2, 1 ], [ 3, 2 ], [ 40, 30 ]
|
||||
], [
|
||||
[ 100, 0 ], [ 20, 10 ], [ 30, 20 ], [ 40, 30 ]
|
||||
]
|
||||
]
|
||||
};
|
||||
this.multiPolyline.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
expect(this.multiPolyline.toGeoJSON()).toEqual(newAndExpectedGeoJSON);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
var Point = require('../../../../src/geo/geometry-models/point');
|
||||
|
||||
describe('src/geo/geometry-models/point', function () {
|
||||
beforeEach(function () {
|
||||
this.point = new Point({
|
||||
latlng: [100, 200]
|
||||
});
|
||||
});
|
||||
|
||||
describe('.toGeoJSON', function () {
|
||||
it('should generate the GeoJSON correctly', function () {
|
||||
expect(this.point.toGeoJSON()).toEqual({
|
||||
type: 'Point',
|
||||
coordinates: [ 200, 100 ]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setCoordinatesFromGeoJSON', function () {
|
||||
beforeEach(function () {
|
||||
this.changeCallback = jasmine.createSpy('changeCallback');
|
||||
this.point.on('change', this.changeCallback);
|
||||
});
|
||||
|
||||
describe('when given a GeoJSON with the same coordinates', function () {
|
||||
beforeEach(function () {
|
||||
var newAndExpectedGeoJSON = this.point.toGeoJSON();
|
||||
this.point.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
});
|
||||
|
||||
it('should NOT trigger a "change" event', function () {
|
||||
expect(this.changeCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a GeoJSON with different coordinates', function () {
|
||||
beforeEach(function () {
|
||||
var newAndExpectedGeoJSON = {
|
||||
type: 'Point',
|
||||
coordinates: [ 0, 300 ]
|
||||
};
|
||||
this.point.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
expect(this.point.toGeoJSON()).toEqual(newAndExpectedGeoJSON);
|
||||
});
|
||||
|
||||
it('should trigger a "change" event', function () {
|
||||
expect(this.changeCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update the coordinates', function () {
|
||||
expect(this.point.toGeoJSON()).toEqual({
|
||||
type: 'Point',
|
||||
coordinates: [ 0, 300 ]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
var Polygon = require('../../../../src/geo/geometry-models/polygon');
|
||||
|
||||
describe('src/geo/geometry-models/polygon', function () {
|
||||
beforeEach(function () {
|
||||
this.polygon = new Polygon(null, {
|
||||
latlngs: [
|
||||
[-1, 1], [1, 2], [3, 4]
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
describe('.toGeoJSON', function () {
|
||||
it('should generate the GeoJSON correctly', function () {
|
||||
expect(this.polygon.toGeoJSON()).toEqual({
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[ [ 1, -1 ], [ 2, 1 ], [ 4, 3 ], [ 1, -1 ] ]
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setCoordinatesFromGeoJSON', function () {
|
||||
beforeEach(function () {
|
||||
this.changeCallback = jasmine.createSpy('changeCallback');
|
||||
this.polygon.on('change', this.changeCallback);
|
||||
});
|
||||
|
||||
describe('when given a GeoJSON with the same coordinates', function () {
|
||||
beforeEach(function () {
|
||||
var newAndExpectedGeoJSON = this.polygon.toGeoJSON();
|
||||
this.polygon.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
});
|
||||
|
||||
it('should NOT trigger a "change" event', function () {
|
||||
expect(this.changeCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a GeoJSON with different coordinates', function () {
|
||||
beforeEach(function () {
|
||||
var newAndExpectedGeoJSON = {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[ [ 0, 0 ], [ 10, 10 ], [ 20, 20 ], [ 0, 0 ] ]
|
||||
]
|
||||
};
|
||||
this.polygon.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
expect(this.polygon.toGeoJSON()).toEqual(newAndExpectedGeoJSON);
|
||||
});
|
||||
|
||||
it('should trigger a "change" event', function () {
|
||||
expect(this.changeCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update the coordinates', function () {
|
||||
expect(this.polygon.toGeoJSON()).toEqual({
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[ [ 0, 0 ], [ 10, 10 ], [ 20, 20 ], [ 0, 0 ] ]
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
var Polyline = require('../../../../src/geo/geometry-models/polyline');
|
||||
|
||||
describe('src/geo/geometry-models/polyline', function () {
|
||||
beforeEach(function () {
|
||||
this.polyline = new Polyline(null, {
|
||||
latlngs: [
|
||||
[-1, 1], [1, 2], [3, 4]
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
describe('.toGeoJSON', function () {
|
||||
it('should generate the GeoJSON correctly', function () {
|
||||
expect(this.polyline.toGeoJSON()).toEqual({
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[ 1, -1 ], [ 2, 1 ], [ 4, 3 ]
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setCoordinatesFromGeoJSON', function () {
|
||||
beforeEach(function () {
|
||||
this.changeCallback = jasmine.createSpy('changeCallback');
|
||||
this.polyline.on('change', this.changeCallback);
|
||||
});
|
||||
|
||||
describe('when given a GeoJSON with the same coordinates', function () {
|
||||
beforeEach(function () {
|
||||
var newAndExpectedGeoJSON = this.polyline.toGeoJSON();
|
||||
this.polyline.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
});
|
||||
|
||||
it('should NOT trigger a "change" event', function () {
|
||||
expect(this.changeCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given a GeoJSON with different coordinates', function () {
|
||||
beforeEach(function () {
|
||||
var newAndExpectedGeoJSON = {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[ 0, 0 ], [ 1, 1 ], [ 2, 2 ]
|
||||
]
|
||||
};
|
||||
this.polyline.setCoordinatesFromGeoJSON(newAndExpectedGeoJSON);
|
||||
expect(this.polyline.toGeoJSON()).toEqual(newAndExpectedGeoJSON);
|
||||
});
|
||||
|
||||
it('should trigger a "change" event', function () {
|
||||
expect(this.changeCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update the coordinates', function () {
|
||||
expect(this.polyline.toGeoJSON()).toEqual({
|
||||
type: 'LineString',
|
||||
coordinates: [ [ 0, 0 ], [ 1, 1 ], [ 2, 2 ] ]
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
var _ = require('underscore');
|
||||
|
||||
var isCoordinateSimilar = function (coordinateA, coordinateB) {
|
||||
return coordinateA + 0.1 > coordinateB &&
|
||||
coordinateA - 0.1 < coordinateB;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
areCoordinatesSimilar: function (coordinatesA, coordinatesB) {
|
||||
return _.every(coordinatesA, function (coordinate, index) {
|
||||
return isCoordinateSimilar(coordinate.lat, coordinatesB[index].lat) &&
|
||||
isCoordinateSimilar(coordinate.lng, coordinatesB[index].lng);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var CoordinatesComparator = require('./coordinates-comparator');
|
||||
|
||||
module.exports = function (MapViewBase) {
|
||||
if (!MapViewBase) throw new Error('MapViewBase is required');
|
||||
|
||||
// We extend the specific MapView and add some methods to make
|
||||
// testing easier
|
||||
var MapView = MapViewBase.extend({
|
||||
initialize: function () {
|
||||
MapViewBase.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this._markers = [];
|
||||
this._paths = [];
|
||||
},
|
||||
|
||||
addMarker: function (marker) {
|
||||
MapViewBase.prototype.addMarker.apply(this, arguments);
|
||||
this._markers.push(marker);
|
||||
},
|
||||
|
||||
removeMarker: function (marker) {
|
||||
MapViewBase.prototype.removeMarker.apply(this, arguments);
|
||||
var index = this._markers.indexOf(marker);
|
||||
if (index >= 0) {
|
||||
this._markers.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
addPath: function (path) {
|
||||
MapViewBase.prototype.addPath.apply(this, arguments);
|
||||
this._paths.push(path);
|
||||
},
|
||||
|
||||
removePath: function (path) {
|
||||
MapViewBase.prototype.removePath.apply(this, arguments);
|
||||
var index = this._paths.indexOf(path);
|
||||
if (index >= 0) {
|
||||
this._paths.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
getMarkers: function () {
|
||||
return this._markers;
|
||||
},
|
||||
|
||||
getPaths: function () {
|
||||
return this._paths;
|
||||
},
|
||||
|
||||
findMarkerByLatLng: function (latlng) {
|
||||
var markers = this.getMarkers();
|
||||
return _.find(markers, function (marker) {
|
||||
return CoordinatesComparator.areCoordinatesSimilar([marker.getCoordinates()], [latlng]);
|
||||
}, this);
|
||||
}
|
||||
});
|
||||
|
||||
var map = new Map(null, {
|
||||
layersFactory: {}
|
||||
});
|
||||
return new MapView({
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: {}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
var GMapsMapView = require('../../../../../src/geo/gmaps/gmaps-map-view.js');
|
||||
var GMapsMultiPointView = require('../../../../../src/geo/geometry-views/gmaps/multi-point-view.js');
|
||||
var SharedTestsForMultiPointViews = require('../shared-tests-for-multi-point-views');
|
||||
|
||||
describe('src/geo/geometry-views/gmaps/multi-point-view.js', function () {
|
||||
SharedTestsForMultiPointViews.call(this, GMapsMapView, GMapsMultiPointView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var GMapsMapView = require('../../../../../src/geo/gmaps/gmaps-map-view.js');
|
||||
var GMapsMultiPolygonView = require('../../../../../src/geo/geometry-views/gmaps/multi-polygon-view.js');
|
||||
var SharedTestsForMultiPolygonViews = require('../shared-tests-for-multi-polygon-views');
|
||||
|
||||
describe('src/geo/geometry-views/gmaps/multi-polygon-view.js', function () {
|
||||
SharedTestsForMultiPolygonViews.call(this, GMapsMapView, GMapsMultiPolygonView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var GMapsMapView = require('../../../../../src/geo/gmaps/gmaps-map-view.js');
|
||||
var GMapsMultiPolylineView = require('../../../../../src/geo/geometry-views/gmaps/multi-polyline-view.js');
|
||||
var SharedTestsForMultiPolylineViews = require('../shared-tests-for-multi-polyline-views');
|
||||
|
||||
describe('src/geo/geometry-views/gmaps/multi-polygon-view.js', function () {
|
||||
SharedTestsForMultiPolylineViews.call(this, GMapsMapView, GMapsMultiPolylineView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var GMapsMapView = require('../../../../../src/geo/gmaps/gmaps-map-view.js');
|
||||
var GMapsPointView = require('../../../../../src/geo/geometry-views/gmaps/point-view.js');
|
||||
var SharedTestsForPointViews = require('../shared-tests-for-point-views');
|
||||
|
||||
describe('src/geo/geometry-views/gmaps/point-view.js', function () {
|
||||
SharedTestsForPointViews.call(this, GMapsMapView, GMapsPointView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var GMapsMapView = require('../../../../../src/geo/gmaps/gmaps-map-view.js');
|
||||
var GMapsPolygonView = require('../../../../../src/geo/geometry-views/gmaps/polygon-view.js');
|
||||
var SharedTestsForPolygonViews = require('../shared-tests-for-polygon-views');
|
||||
|
||||
describe('src/geo/geometry-views/gmaps/polygon-view.js', function () {
|
||||
SharedTestsForPolygonViews.call(this, GMapsMapView, GMapsPolygonView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var GMapsMapView = require('../../../../../src/geo/gmaps/gmaps-map-view.js');
|
||||
var GMapsPolylineView = require('../../../../../src/geo/geometry-views/gmaps/polyline-view.js');
|
||||
var SharedTestsForPolylineViews = require('../shared-tests-for-polyline-views');
|
||||
|
||||
describe('src/geo/geometry-views/gmaps/polyline-view.js', function () {
|
||||
SharedTestsForPolylineViews.call(this, GMapsMapView, GMapsPolylineView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var LeafletMapView = require('../../../../../src/geo/leaflet/leaflet-map-view.js');
|
||||
var LeafletMultiPointView = require('../../../../../src/geo/geometry-views/leaflet/multi-point-view.js');
|
||||
var SharedTestsForMultiPointViews = require('../shared-tests-for-multi-point-views');
|
||||
|
||||
describe('src/geo/geometry-views/leaflet/multi-point-view.js', function () {
|
||||
SharedTestsForMultiPointViews.call(this, LeafletMapView, LeafletMultiPointView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var LeafletMapView = require('../../../../../src/geo/leaflet/leaflet-map-view.js');
|
||||
var LeafletMultiPolygonView = require('../../../../../src/geo/geometry-views/leaflet/multi-polygon-view.js');
|
||||
var SharedTestsForMultiPolygonViews = require('../shared-tests-for-multi-polygon-views');
|
||||
|
||||
describe('src/geo/geometry-views/leaflet/multi-polygon-view.js', function () {
|
||||
SharedTestsForMultiPolygonViews.call(this, LeafletMapView, LeafletMultiPolygonView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var LeafletMapView = require('../../../../../src/geo/leaflet/leaflet-map-view.js');
|
||||
var LeafletMultiPolylineView = require('../../../../../src/geo/geometry-views/leaflet/multi-polyline-view.js');
|
||||
var SharedTestsForMultiPolylineViews = require('../shared-tests-for-multi-polyline-views');
|
||||
|
||||
describe('src/geo/geometry-views/leaflet/multi-polyline-view.js', function () {
|
||||
SharedTestsForMultiPolylineViews.call(this, LeafletMapView, LeafletMultiPolylineView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var LeafletMapView = require('../../../../../src/geo/leaflet/leaflet-map-view.js');
|
||||
var LeafletPointView = require('../../../../../src/geo/geometry-views/leaflet/point-view.js');
|
||||
var SharedTestsForPointViews = require('../shared-tests-for-point-views');
|
||||
|
||||
describe('src/geo/geometry-views/leaflet/point-view.js', function () {
|
||||
SharedTestsForPointViews.call(this, LeafletMapView, LeafletPointView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var LeafletMapView = require('../../../../../src/geo/leaflet/leaflet-map-view.js');
|
||||
var LeafletPolygonView = require('../../../../../src/geo/geometry-views/leaflet/polygon-view.js');
|
||||
var SharedTestsForPolygonViews = require('../shared-tests-for-polygon-views');
|
||||
|
||||
describe('src/geo/geometry-views/leaflet/polygon-view.js', function () {
|
||||
SharedTestsForPolygonViews.call(this, LeafletMapView, LeafletPolygonView);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
var LeafletMapView = require('../../../../../src/geo/leaflet/leaflet-map-view.js');
|
||||
var LeafletPolylineView = require('../../../../../src/geo/geometry-views/leaflet/polyline-view.js');
|
||||
var SharedTestsForPolylineViews = require('../shared-tests-for-polyline-views');
|
||||
|
||||
describe('src/geo/geometry-views/leaflet/polyline-view.js', function () {
|
||||
SharedTestsForPolylineViews.call(this, LeafletMapView, LeafletPolylineView);
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
var _ = require('underscore');
|
||||
|
||||
module.exports = function () {
|
||||
beforeEach(function () {
|
||||
spyOn(_, 'debounce').and.callFake(function (func) { return function () { func.apply(this, arguments); }; });
|
||||
|
||||
this.geometryView.render();
|
||||
});
|
||||
|
||||
describe('when the model is removed', function () {
|
||||
it('should remove each geometry', function () {
|
||||
this.geometry.geometries.each(function (polygon) {
|
||||
spyOn(polygon, 'remove');
|
||||
});
|
||||
|
||||
this.geometry.remove();
|
||||
|
||||
expect(this.geometry.geometries.all(function (geometry) {
|
||||
return geometry.remove.calls.count() === 1;
|
||||
})).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove the view', function () {
|
||||
spyOn(this.geometryView, 'remove');
|
||||
|
||||
this.geometry.remove();
|
||||
|
||||
expect(this.geometryView.remove).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
var MultiPoint = require('../../../../src/geo/geometry-models/multi-point');
|
||||
var SharedTestsForMultiGeometryViews = require('./shared-tests-for-multi-geometry-views');
|
||||
var createMapView = require('./create-map-view');
|
||||
|
||||
module.exports = function (MapView, MultiPointView) {
|
||||
beforeEach(function () {
|
||||
this.geometry = new MultiPoint(null, {
|
||||
latlngs: [
|
||||
[0, 1],
|
||||
[1, 2]
|
||||
]
|
||||
});
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.geometryView = new MultiPointView({
|
||||
model: this.geometry,
|
||||
mapView: this.mapView
|
||||
});
|
||||
});
|
||||
|
||||
SharedTestsForMultiGeometryViews.call(this);
|
||||
|
||||
it('should render the geometries', function () {
|
||||
expect(this.mapView.getMarkers().length).toEqual(2); // 2 points
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
var MultiPolygon = require('../../../../src/geo/geometry-models/multi-polygon');
|
||||
var SharedTestsForMultiGeometryViews = require('./shared-tests-for-multi-geometry-views');
|
||||
var createMapView = require('./create-map-view');
|
||||
|
||||
module.exports = function (MapView, MultiPolygonView) {
|
||||
beforeEach(function () {
|
||||
this.geometry = new MultiPolygon(null, {
|
||||
latlngs: [
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4]
|
||||
],
|
||||
[
|
||||
[0, 10],
|
||||
[10, 20],
|
||||
[20, 30],
|
||||
[30, 40]
|
||||
]
|
||||
]
|
||||
});
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.geometryView = new MultiPolygonView({
|
||||
model: this.geometry,
|
||||
mapView: this.mapView
|
||||
});
|
||||
});
|
||||
|
||||
SharedTestsForMultiGeometryViews.call(this);
|
||||
|
||||
it('should render the geometries', function () {
|
||||
expect(this.mapView.getPaths().length).toEqual(2); // 2 geometries
|
||||
expect(this.mapView.getMarkers().length).toEqual(8); // 4 markers for each geometry
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
var MultiPolyline = require('../../../../src/geo/geometry-models/multi-polyline');
|
||||
var SharedTestsForMultiGeometryViews = require('./shared-tests-for-multi-geometry-views');
|
||||
var createMapView = require('./create-map-view');
|
||||
|
||||
module.exports = function (MapView, MultiPolylineView) {
|
||||
beforeEach(function () {
|
||||
this.geometry = new MultiPolyline(null, {
|
||||
latlngs: [
|
||||
[
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4]
|
||||
],
|
||||
[
|
||||
[0, 10],
|
||||
[10, 20],
|
||||
[20, 30],
|
||||
[30, 40]
|
||||
]
|
||||
]
|
||||
});
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.geometryView = new MultiPolylineView({
|
||||
model: this.geometry,
|
||||
mapView: this.mapView
|
||||
});
|
||||
});
|
||||
|
||||
SharedTestsForMultiGeometryViews.call(this);
|
||||
|
||||
it('should render the geometries', function () {
|
||||
expect(this.mapView.getPaths().length).toEqual(2); // 2 geometries
|
||||
expect(this.mapView.getMarkers().length).toEqual(8); // 4 markers for each geometry
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,299 @@
|
||||
var _ = require('underscore');
|
||||
var Point = require('../../../../src/geo/geometry-models/point.js');
|
||||
var createMapView = require('./create-map-view');
|
||||
var CoordinatesComparator = require('./coordinates-comparator');
|
||||
|
||||
module.exports = function (Path, MapView, PathView) {
|
||||
beforeEach(function () {
|
||||
spyOn(_, 'debounce').and.callFake(function (func) { return function () { func.apply(this, arguments); }; });
|
||||
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.geometry = new Path(null, {
|
||||
latlngs: [
|
||||
[-1, 1], [1, 2], [3, 4]
|
||||
]
|
||||
});
|
||||
|
||||
this.geometryView = new PathView({
|
||||
model: this.geometry,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
this.geometryView.render();
|
||||
});
|
||||
|
||||
it('should render some markers and the path', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(1);
|
||||
expect(markers.length).toEqual(3); // 3 markers
|
||||
|
||||
expect(markers[0].getCoordinates()).toEqual({ lat: -1, lng: 1 });
|
||||
expect(markers[0].isDraggable()).toBe(false);
|
||||
|
||||
expect(markers[1].getCoordinates()).toEqual({ lat: 1, lng: 2 });
|
||||
expect(markers[1].isDraggable()).toBe(false);
|
||||
|
||||
expect(markers[2].getCoordinates()).toEqual({ lat: 3, lng: 4 });
|
||||
expect(markers[2].isDraggable()).toBe(false);
|
||||
|
||||
expect(paths[0].getCoordinates()).toEqual([
|
||||
{ lat: -1, lng: 1 }, { lat: 1, lng: 2 }, { lat: 3, lng: 4 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not render duplicated markers', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(1);
|
||||
expect(markers.length).toEqual(3); // 3 markers
|
||||
|
||||
this.geometry.setCoordinates([
|
||||
[-1, 1], [1, 2], [3, 4], [-1, 1]
|
||||
]);
|
||||
|
||||
paths = this.mapView.getPaths();
|
||||
markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(1);
|
||||
expect(markers.length).toEqual(4); // 4 markers
|
||||
});
|
||||
|
||||
describe('when the model is updated', function () {
|
||||
describe('when a point changed', function () {
|
||||
beforeEach(function () {
|
||||
this.geometry.points.at(0).set('latlng', [ -45, 45 ]);
|
||||
});
|
||||
|
||||
it("should update the path's latlng", function () {
|
||||
expect(this.geometry.getCoordinates()).toEqual([
|
||||
[ -45, 45 ], [ 1, 2 ], [ 3, 4 ]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when points are added', function () {
|
||||
beforeEach(function () {
|
||||
this.numberOfMarkersBefore = this.mapView.getMarkers().length;
|
||||
var point = new Point({
|
||||
latlng: [
|
||||
-40,
|
||||
40
|
||||
]
|
||||
});
|
||||
this.geometry.addPoint(point);
|
||||
});
|
||||
|
||||
it('should update the path\'s latlng', function () {
|
||||
expect(this.geometry.getCoordinates()).toEqual([
|
||||
[ -40, 40 ], [ -1, 1 ], [ 1, 2 ], [ 3, 4 ]
|
||||
]);
|
||||
});
|
||||
|
||||
it('should render a new marker', function () {
|
||||
var numberOfMarkersAfter = this.mapView.getMarkers().length;
|
||||
|
||||
expect(numberOfMarkersAfter).toEqual(this.numberOfMarkersBefore + 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the point triggers a dblclick event', function () {
|
||||
beforeEach(function () {
|
||||
this.geometry.setCoordinates([
|
||||
[ -10, 10 ], [ 10, 20 ], [ 30, 40 ]
|
||||
]);
|
||||
});
|
||||
|
||||
it('should remove the geometry point', function () {
|
||||
var pointToDelete = new Point({
|
||||
latlng: [ -40, 40 ]
|
||||
});
|
||||
|
||||
this.geometry.addPoint(pointToDelete);
|
||||
|
||||
expect(this.geometry.getCoordinates()).toEqual([
|
||||
[-40, 40], [ -10, 10 ], [ 10, 20 ], [ 30, 40 ]
|
||||
]);
|
||||
|
||||
pointToDelete.trigger('dblclick');
|
||||
|
||||
expect(this.geometry.getCoordinates()).toEqual([
|
||||
[ -10, 10 ], [ 10, 20 ], [ 30, 40 ]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when points are resetted,', function () {
|
||||
beforeEach(function () {
|
||||
this.geometry.setCoordinates([
|
||||
[ -10, 10 ], [ 10, 20 ], [ 30, 40 ]
|
||||
]);
|
||||
});
|
||||
|
||||
it("should update the path's latlng", function () {
|
||||
expect(this.geometry.getCoordinates()).toEqual([
|
||||
[ -10, 10 ], [ 10, 20 ], [ 30, 40 ]
|
||||
]);
|
||||
});
|
||||
|
||||
it('should render the right number of markers', function () {
|
||||
var numberOfMarkersAfter = this.mapView.getMarkers().length;
|
||||
expect(numberOfMarkersAfter).toEqual(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the model is removed', function () {
|
||||
it('should remove the markers and path from the map', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(1);
|
||||
expect(markers.length).toEqual(3); // 3 markers
|
||||
|
||||
this.geometry.remove();
|
||||
|
||||
paths = this.mapView.getPaths();
|
||||
markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(0);
|
||||
expect(markers.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should remove the view', function () {
|
||||
spyOn(this.geometryView, 'remove');
|
||||
|
||||
this.geometry.remove();
|
||||
|
||||
expect(this.geometryView.remove).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('expandable paths', function () {
|
||||
beforeEach(function (done) {
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.geometry = new Path({
|
||||
editable: true,
|
||||
expandable: true
|
||||
}, {
|
||||
latlngs: [
|
||||
[0, 0], [10, 0], [10, 10], [0, 10]
|
||||
]
|
||||
});
|
||||
|
||||
this.geometryView = new PathView({
|
||||
model: this.geometry,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
// Listen for the map to be ready
|
||||
this.mapView.onReady(function () {
|
||||
this.geometryView.render();
|
||||
|
||||
// Marker that we'll interact with in the tests
|
||||
this.middlePointMarker = this.mapView.findMarkerByLatLng({ lat: 5, lng: 0 });
|
||||
var markers = this.mapView.getMarkers();
|
||||
this.numberOfMarkersBefore = markers.length;
|
||||
|
||||
done();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
describe('when the model is removed', function () {
|
||||
it('should remove the markers, middle points, and path from the map', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(paths.length).not.toEqual(0);
|
||||
expect(markers.length).not.toEqual(0);
|
||||
|
||||
this.geometry.remove();
|
||||
|
||||
paths = this.mapView.getPaths();
|
||||
markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(0);
|
||||
expect(markers.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user mousedowns a middle point', function () {
|
||||
beforeEach(function () {
|
||||
expect(this.middlePointMarker.getIconURL()).toEqual(Point.MIDDLE_POINT_ICON_URL);
|
||||
|
||||
this.middlePointMarker.trigger('mousedown');
|
||||
});
|
||||
|
||||
it('should add a vertex to the geometry at [5, 0]', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
expect(paths.length).toEqual(1);
|
||||
|
||||
// Coordinates have different precissions and we just check they are similar
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(paths[0].getCoordinates(), [
|
||||
{ lat: 0, lng: 0 }, { lat: 5, lng: 0 }, { lat: 10, lng: 0 }, { lat: 10, lng: 10 }, { lat: 0, lng: 10 }
|
||||
])).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should change the icon of the middle point', function () {
|
||||
expect(this.middlePointMarker.getIconURL()).toEqual(Point.DEFAULT_ICON_URL);
|
||||
});
|
||||
|
||||
it('should add two middle points at [2.5] and [7.5, 0]', function () {
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(this.numberOfMarkersBefore + 2);
|
||||
|
||||
expect(this.mapView.findMarkerByLatLng({ lat: 2.5, lng: 0 })).toBeDefined();
|
||||
expect(this.mapView.findMarkerByLatLng({ lat: 7.5, lng: 0 })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should remove the markers, middle points, and path from the map when the model is removed', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(paths.length).not.toEqual(0);
|
||||
expect(markers.length).not.toEqual(0);
|
||||
|
||||
this.geometry.remove();
|
||||
|
||||
paths = this.mapView.getPaths();
|
||||
markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(0);
|
||||
expect(markers.length).toEqual(0);
|
||||
});
|
||||
|
||||
describe('when user drags a middle point', function () {
|
||||
beforeEach(function () {
|
||||
// Simulate a drag and drop to [5, -5]
|
||||
spyOn(this.middlePointMarker, 'getCoordinates').and.returnValue({ lat: 5, lng: -5 });
|
||||
this.middlePointMarker.trigger('dragstart');
|
||||
this.middlePointMarker.trigger('drag');
|
||||
this.middlePointMarker.trigger('dragend');
|
||||
});
|
||||
|
||||
it('should update the coordinates of the new vertex to [5, -5]', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
expect(paths.length).toEqual(1);
|
||||
expect(paths[0].getCoordinates()).toEqual([
|
||||
{ lat: 0, lng: 0 }, { lat: 5, lng: -5 }, { lat: 10, lng: 0 }, { lat: 10, lng: 10 }, { lat: 0, lng: 10 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should add two middle points at [2.5] and [7.5, 0]', function () {
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(this.numberOfMarkersBefore + 2); // Only two middle points have been added
|
||||
|
||||
expect(this.mapView.findMarkerByLatLng({ lat: 2.5, lng: -2.5 })).toBeDefined();
|
||||
expect(this.mapView.findMarkerByLatLng({ lat: 7.5, lng: -2.5 })).toBeDefined();
|
||||
});
|
||||
|
||||
it('should delete the new point after dblclick event', function () {
|
||||
this.middlePointMarker.trigger('mousedown');
|
||||
this.middlePointMarker.trigger('dblclick');
|
||||
var paths = this.mapView.getPaths();
|
||||
|
||||
expect(paths[0].getCoordinates()).toEqual([
|
||||
{ lat: 0, lng: 0 }, { lat: 10, lng: 0 }, { lat: 10, lng: 10 }, { lat: 0, lng: 10 }
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,191 @@
|
||||
var _ = require('underscore');
|
||||
var Point = require('../../../../src/geo/geometry-models/point.js');
|
||||
var createMapView = require('./create-map-view');
|
||||
|
||||
module.exports = function (MapView, PointView) {
|
||||
beforeEach(function () {
|
||||
spyOn(_, 'debounce').and.callFake(function (func) { return function () { func.apply(this, arguments); }; });
|
||||
|
||||
this.point = new Point({
|
||||
latlng: [
|
||||
-40,
|
||||
40
|
||||
]
|
||||
});
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.pointView = new PointView({
|
||||
model: this.point,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
this.pointView.render();
|
||||
});
|
||||
|
||||
it('should add a marker to the map', function () {
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(1);
|
||||
expect(markers[0].getCoordinates()).toEqual({
|
||||
lat: -40,
|
||||
lng: 40
|
||||
});
|
||||
expect(markers[0].isDraggable()).toBe(false);
|
||||
});
|
||||
|
||||
it('should add a marker to the map when the model gets a lat and lng', function () {
|
||||
this.point = new Point();
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.pointView = new PointView({
|
||||
model: this.point,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
this.pointView.render();
|
||||
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(0);
|
||||
|
||||
this.point.set('latlng', [ -45, 45 ]);
|
||||
|
||||
markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(1);
|
||||
});
|
||||
|
||||
describe('when the model is updated', function () {
|
||||
it("should update the marker's latlng", function () {
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(1);
|
||||
expect(markers[0].getCoordinates()).toEqual({
|
||||
lat: -40,
|
||||
lng: 40
|
||||
});
|
||||
|
||||
this.point.set('latlng', [ -45, 45 ]);
|
||||
|
||||
markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(1);
|
||||
expect(markers[0].getCoordinates()).toEqual({
|
||||
lat: -45,
|
||||
lng: 45
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the model is removed', function () {
|
||||
it('should remove the marker if model is removed', function () {
|
||||
expect(this.mapView.getMarkers().length).toEqual(1);
|
||||
|
||||
this.point.remove();
|
||||
|
||||
expect(this.mapView.getMarkers().length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should remove the view', function () {
|
||||
spyOn(this.pointView, 'remove');
|
||||
|
||||
this.point.remove();
|
||||
|
||||
expect(this.pointView.remove).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('editable points', function () {
|
||||
beforeEach(function () {
|
||||
this.point = new Point({
|
||||
latlng: [
|
||||
-40,
|
||||
40
|
||||
],
|
||||
editable: true
|
||||
});
|
||||
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.pointView = new PointView({
|
||||
model: this.point,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
this.pointView.render();
|
||||
this.marker = this.mapView.getMarkers()[0];
|
||||
});
|
||||
|
||||
it('should add an editable marker to the map', function () {
|
||||
expect(this.marker.isDraggable()).toBe(true);
|
||||
});
|
||||
|
||||
it("should update model's latlng when the marker is dragged & dropped", function () {
|
||||
spyOn(this.marker, 'getCoordinates').and.returnValue({
|
||||
lat: -90,
|
||||
lng: 90
|
||||
});
|
||||
|
||||
this.marker.trigger('dragstart');
|
||||
this.marker.trigger('drag');
|
||||
this.marker.trigger('dragend');
|
||||
|
||||
expect(this.point.getCoordinates()).toEqual([ -90, 90 ]);
|
||||
});
|
||||
|
||||
it("shouldn't update the marker's latlng while dragging", function () {
|
||||
this.marker.trigger('dragstart');
|
||||
|
||||
this.point.set('latlng', [
|
||||
-50,
|
||||
50
|
||||
]);
|
||||
|
||||
expect(this.marker.getCoordinates().lat).toEqual(-40);
|
||||
expect(this.marker.getCoordinates().lng).toEqual(40);
|
||||
|
||||
this.marker.trigger('drag');
|
||||
this.marker.trigger('dragend');
|
||||
|
||||
this.point.set('latlng', [
|
||||
-50,
|
||||
50
|
||||
]);
|
||||
|
||||
expect(this.marker.getCoordinates().lat).toEqual(-50);
|
||||
expect(this.marker.getCoordinates().lng).toEqual(50);
|
||||
});
|
||||
|
||||
it('should bind marker events', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
var marker = this.mapView.getMarkers()[0];
|
||||
|
||||
this.pointView.on('mousedown', callback);
|
||||
marker.trigger('mousedown');
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should unbind marker events when the view is cleaned', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
var marker = this.mapView.getMarkers()[0];
|
||||
|
||||
this.pointView.on('mousedown', callback);
|
||||
this.pointView.clean();
|
||||
|
||||
marker.trigger('mousedown');
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.clean', function () {
|
||||
it('should remove the marker from the map', function () {
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(1);
|
||||
|
||||
this.pointView.clean();
|
||||
|
||||
markers = this.mapView.getMarkers();
|
||||
expect(markers.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
var Polygon = require('../../../../src/geo/geometry-models/polygon');
|
||||
var SharedTestsForPathViews = require('./shared-tests-for-path-views');
|
||||
var createMapView = require('./create-map-view');
|
||||
var CoordinatesComparator = require('./coordinates-comparator');
|
||||
|
||||
module.exports = function (MapView, PathView) {
|
||||
SharedTestsForPathViews.call(this, Polygon, MapView, PathView);
|
||||
|
||||
describe('expandable polygons', function () {
|
||||
beforeEach(function (done) {
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.geometry = new Polygon({
|
||||
editable: true,
|
||||
expandable: true
|
||||
}, {
|
||||
latlngs: [
|
||||
[0, 0], [10, 0], [10, 10], [0, 10]
|
||||
]
|
||||
});
|
||||
|
||||
this.geometryView = new PathView({
|
||||
model: this.geometry,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
// Listen for the map to be ready
|
||||
this.mapView.onReady(function () {
|
||||
this.geometryView.render();
|
||||
|
||||
done();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
it('should render markers for each vertex, the path, and middle points', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(1);
|
||||
expect(markers.length).toEqual(8); // 4 markers + 4 middle points
|
||||
|
||||
// Markers
|
||||
expect(markers[0].getCoordinates()).toEqual({ lat: 0, lng: 0 });
|
||||
expect(markers[0].isDraggable()).toBe(true);
|
||||
|
||||
expect(markers[1].getCoordinates()).toEqual({ lat: 10, lng: 0 });
|
||||
expect(markers[1].isDraggable()).toBe(true);
|
||||
|
||||
expect(markers[2].getCoordinates()).toEqual({ lat: 10, lng: 10 });
|
||||
expect(markers[2].isDraggable()).toBe(true);
|
||||
|
||||
expect(markers[3].getCoordinates()).toEqual({ lat: 0, lng: 10 });
|
||||
expect(markers[3].isDraggable()).toBe(true);
|
||||
|
||||
// Middle points
|
||||
// Coordinates have different precissions and we just check they are similar
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(
|
||||
[ markers[4].getCoordinates() ],
|
||||
[ { lat: 5, lng: 0 } ])
|
||||
).toBeTruthy();
|
||||
expect(markers[4].isDraggable()).toBe(true);
|
||||
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(
|
||||
[ markers[5].getCoordinates() ],
|
||||
[ { lat: 10, lng: 5 } ])
|
||||
).toBeTruthy();
|
||||
expect(markers[5].isDraggable()).toBe(true);
|
||||
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(
|
||||
[ markers[6].getCoordinates() ],
|
||||
[ { lat: 5, lng: 10 } ])
|
||||
).toBeTruthy();
|
||||
expect(markers[6].isDraggable()).toBe(true);
|
||||
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(
|
||||
[ markers[7].getCoordinates() ],
|
||||
[ { lat: 0, lng: 5 } ])
|
||||
).toBeTruthy();
|
||||
expect(markers[7].isDraggable()).toBe(true);
|
||||
|
||||
expect(paths[0].getCoordinates()).toEqual([
|
||||
{ lat: 0, lng: 0 }, { lat: 10, lng: 0 }, { lat: 10, lng: 10 }, { lat: 0, lng: 10 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should re-render middle points when map is zoomed', function () {
|
||||
spyOn(this.mapView, 'removeMarker');
|
||||
spyOn(this.mapView, 'addMarker');
|
||||
|
||||
this.mapView.trigger('zoomend');
|
||||
|
||||
expect(this.mapView.removeMarker.calls.count()).toEqual(4);
|
||||
expect(this.mapView.addMarker.calls.count()).toEqual(4);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
var Polyline = require('../../../../src/geo/geometry-models/polyline');
|
||||
var SharedTestsForPathViews = require('./shared-tests-for-path-views');
|
||||
var createMapView = require('./create-map-view');
|
||||
var CoordinatesComparator = require('./coordinates-comparator');
|
||||
|
||||
module.exports = function (MapView, PathView) {
|
||||
SharedTestsForPathViews.call(this, Polyline, MapView, PathView);
|
||||
|
||||
describe('expandable polylines', function () {
|
||||
beforeEach(function (done) {
|
||||
this.mapView = createMapView(MapView);
|
||||
this.mapView.render();
|
||||
|
||||
this.geometry = new Polyline({
|
||||
editable: true,
|
||||
expandable: true
|
||||
}, {
|
||||
latlngs: [
|
||||
[0, 0], [10, 0], [10, 10], [0, 10]
|
||||
]
|
||||
});
|
||||
|
||||
this.geometryView = new PathView({
|
||||
model: this.geometry,
|
||||
mapView: this.mapView
|
||||
});
|
||||
|
||||
// Listen for the map to be ready
|
||||
this.mapView.onReady(function () {
|
||||
this.geometryView.render();
|
||||
|
||||
done();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
it('should render markers for each vertex, the path, and middle points', function () {
|
||||
var paths = this.mapView.getPaths();
|
||||
var markers = this.mapView.getMarkers();
|
||||
expect(paths.length).toEqual(1);
|
||||
expect(markers.length).toEqual(7); // 4 markers + 3 middle points
|
||||
|
||||
// Markers
|
||||
expect(markers[0].getCoordinates()).toEqual({ lat: 0, lng: 0 });
|
||||
expect(markers[0].isDraggable()).toBe(true);
|
||||
|
||||
expect(markers[1].getCoordinates()).toEqual({ lat: 10, lng: 0 });
|
||||
expect(markers[1].isDraggable()).toBe(true);
|
||||
|
||||
expect(markers[2].getCoordinates()).toEqual({ lat: 10, lng: 10 });
|
||||
expect(markers[2].isDraggable()).toBe(true);
|
||||
|
||||
expect(markers[3].getCoordinates()).toEqual({ lat: 0, lng: 10 });
|
||||
expect(markers[3].isDraggable()).toBe(true);
|
||||
|
||||
// Middle points
|
||||
// Coordinates have different precissions and we just check they are similar
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(
|
||||
[ markers[4].getCoordinates() ],
|
||||
[ { lat: 5, lng: 0 } ])
|
||||
).toBeTruthy();
|
||||
expect(markers[4].isDraggable()).toBe(true);
|
||||
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(
|
||||
[ markers[5].getCoordinates() ],
|
||||
[ { lat: 10, lng: 5 } ])
|
||||
).toBeTruthy();
|
||||
expect(markers[5].isDraggable()).toBe(true);
|
||||
|
||||
expect(CoordinatesComparator.areCoordinatesSimilar(
|
||||
[ markers[6].getCoordinates() ],
|
||||
[ { lat: 5, lng: 10 } ])
|
||||
).toBeTruthy();
|
||||
expect(markers[6].isDraggable()).toBe(true);
|
||||
|
||||
expect(paths[0].getCoordinates()).toEqual([
|
||||
{ lat: 0, lng: 0 }, { lat: 10, lng: 0 }, { lat: 10, lng: 10 }, { lat: 0, lng: 10 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should re-render middle points when map is zoomed', function () {
|
||||
spyOn(this.mapView, 'removeMarker');
|
||||
spyOn(this.mapView, 'addMarker');
|
||||
|
||||
this.mapView.trigger('zoomend');
|
||||
|
||||
expect(this.mapView.removeMarker.calls.count()).toEqual(3);
|
||||
expect(this.mapView.addMarker.calls.count()).toEqual(3);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,139 @@
|
||||
/* global google */
|
||||
var GoogleCartoDBLayerGroupClass = require('../../../../src/geo/gmaps/gmaps-cartodb-layer-group-view');
|
||||
var cartoLayerGroupViewTests = require('../shared-tests-for-carto-layer-group');
|
||||
var CartoDBLayer = require('../../../../src/geo/map/cartodb-layer');
|
||||
var LayersCollection = require('../../../../src/geo/map/layers');
|
||||
var CartoDBLayerGroup = require('../../../../src/geo/cartodb-layer-group');
|
||||
|
||||
describe('gmaps-cartodb-layer-group-view', function () {
|
||||
/**
|
||||
* Helper function used to get a google map in the shared tests.
|
||||
*/
|
||||
function createNativeMap (container) {
|
||||
// Create a leaflet map inside a container
|
||||
container.setAttribute('id', 'map');
|
||||
container.style.height = '200px';
|
||||
document.body.appendChild(container);
|
||||
var googleMap = new google.maps.Map(document.getElementById('map'), {
|
||||
zoom: 4,
|
||||
center: { lat: 47.84808037632246, lng: 14.2822265625 }
|
||||
});
|
||||
return googleMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function used to get the tiles in the shared tests
|
||||
*/
|
||||
function getTileUrl (layerGroupView) {
|
||||
return layerGroupView.options.tiles[0].replace('{s}', '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gmaps events and Leaflet events are different.
|
||||
*/
|
||||
var event = {
|
||||
da: { x: 121.8125, y: 94.56249999999997 },
|
||||
data: { name: 'fakeCityName', cartodb_id: 123 },
|
||||
e: { type: 'mousemove' },
|
||||
latLng: { lat: function () { return 42.48830197960228; }, lng: function () { return -8.701171875; } },
|
||||
layer: 0,
|
||||
pixel: { x: 243, y: 274 }
|
||||
};
|
||||
|
||||
// -- Shared tests for carto layer group
|
||||
cartoLayerGroupViewTests(createNativeMap, GoogleCartoDBLayerGroupClass, getTileUrl, event);
|
||||
|
||||
// -- Google maps specific tests
|
||||
describe('GMapsCartoDBLayerGroupView', function () {
|
||||
var nativeMap;
|
||||
var container;
|
||||
var cartoDbLayer0;
|
||||
var cartoDbLayer1;
|
||||
var layerGroupView0;
|
||||
var layerGroupView1;
|
||||
|
||||
var layerGroupModelMock;
|
||||
var layersCollection;
|
||||
|
||||
var engineMock = {
|
||||
on: jasmine.createSpy('on')
|
||||
};
|
||||
|
||||
var mapModelMock = {
|
||||
on: jasmine.createSpy('on'),
|
||||
isFeatureInteractivityEnabled: jasmine.createSpy('isFeatureInteractivityEnabled').and.returnValue(false)
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
container = document.createElement('div');
|
||||
nativeMap = createNativeMap(container);
|
||||
|
||||
cartoDbLayer0 = new CartoDBLayer({}, { engine: engineMock });
|
||||
cartoDbLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
layersCollection = new LayersCollection([cartoDbLayer0, cartoDbLayer1]);
|
||||
|
||||
layerGroupModelMock = new CartoDBLayerGroup({
|
||||
urls: {
|
||||
'subdomains': [0, 1, 2, 3],
|
||||
'tiles': 'http://{s}.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/{layerIndexes}/{z}/{x}/{y}.png',
|
||||
'grids': [
|
||||
[
|
||||
'http://0.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json',
|
||||
'http://1.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json',
|
||||
'http://2.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json',
|
||||
'http://3.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json'
|
||||
],
|
||||
[
|
||||
'http://0.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json',
|
||||
'http://1.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json',
|
||||
'http://2.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json',
|
||||
'http://3.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json'
|
||||
]
|
||||
],
|
||||
'attributes': [
|
||||
'http://ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/attributes',
|
||||
'http://ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/attributes'
|
||||
]
|
||||
},
|
||||
indexOfLayersInWindshaft: [1, 2]
|
||||
}, {
|
||||
layersCollection: layersCollection
|
||||
});
|
||||
|
||||
layerGroupView0 = new GoogleCartoDBLayerGroupClass(layerGroupModelMock, { nativeMap: nativeMap, mapModel: mapModelMock });
|
||||
layerGroupView1 = new GoogleCartoDBLayerGroupClass(layerGroupModelMock, { nativeMap: nativeMap, mapModel: mapModelMock });
|
||||
nativeMap.overlayMapTypes.push(layerGroupView0);
|
||||
nativeMap.overlayMapTypes.push(layerGroupView1);
|
||||
});
|
||||
|
||||
describe('._getOverlayIndex', function () {
|
||||
it('returns the index of the given layour group', function () {
|
||||
expect(layerGroupView0._getOverlayIndex()).toEqual(0);
|
||||
expect(layerGroupView1._getOverlayIndex()).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('._refreshView', function () {
|
||||
it('sets the layer group in the same position', function () {
|
||||
layerGroupView0._refreshView();
|
||||
|
||||
expect(nativeMap.overlayMapTypes.getAt(0)).toEqual(layerGroupView0);
|
||||
expect(nativeMap.overlayMapTypes.getAt(1)).toEqual(layerGroupView1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.remove', function () {
|
||||
it('removes the correct layer group', function () {
|
||||
layerGroupView0.remove();
|
||||
|
||||
expect(nativeMap.overlayMapTypes.getLength()).toEqual(1);
|
||||
expect(nativeMap.overlayMapTypes.getAt(0)).toEqual(layerGroupView1);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,156 @@
|
||||
/* global google */
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var GoogleMapsMapView = require('../../../../src/geo/gmaps/gmaps-map-view');
|
||||
|
||||
describe('geo/gmaps/gmaps-map-view', function () {
|
||||
var mapView;
|
||||
var map;
|
||||
var spy;
|
||||
var container;
|
||||
|
||||
beforeEach(function () {
|
||||
container = $('<div>').css('height', '200px');
|
||||
map = new Map(null, {
|
||||
layersFactory: {}
|
||||
});
|
||||
|
||||
spyOn(map, 'setMapViewSize').and.callThrough();
|
||||
spyOn(map, 'setPixelToLatLngConverter').and.callThrough();
|
||||
spyOn(map, 'setLatLngToPixelConverter').and.callThrough();
|
||||
|
||||
mapView = new GoogleMapsMapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
|
||||
mapView.render();
|
||||
|
||||
spy = jasmine.createSpyObj('spy', ['zoomChanged', 'centerChanged', 'scrollWheelChanged']);
|
||||
map.bind('change:zoom', spy.zoomChanged);
|
||||
map.bind('change:center', spy.centerChanged);
|
||||
map.bind('change:scrollwheel', spy.scrollWheelChanged);
|
||||
});
|
||||
|
||||
it('should change zoom', function () {
|
||||
mapView._setZoom(null, 10);
|
||||
expect(spy.zoomChanged).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should disable gmaps dragging and double click zooming when the map has drag disabled', function () {
|
||||
var container = $('<div>').css({
|
||||
'height': '200px',
|
||||
'width': '200px'
|
||||
});
|
||||
var map = new Map({
|
||||
drag: false
|
||||
}, {
|
||||
layersFactory: {}
|
||||
});
|
||||
var mapView = new GoogleMapsMapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
mapView.render();
|
||||
|
||||
expect(mapView._gmapsMap.get('draggable')).toBeFalsy();
|
||||
expect(mapView._gmapsMap.get('disableDoubleClickZoom')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should change center and zoom when bounds are changed', function (done) {
|
||||
var spy = jasmine.createSpy('change:center');
|
||||
mapView.getSize = function () { return {x: 200, y: 200}; };
|
||||
map.bind('change:center', spy);
|
||||
spyOn(mapView, '_setCenter');
|
||||
mapView._bindModel();
|
||||
|
||||
map.set({
|
||||
'view_bounds_ne': [1, 1],
|
||||
'view_bounds_sw': [-0.3, -1.2]
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
expect(mapView._setCenter).toHaveBeenCalled();
|
||||
done();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it('should "forward" a dragend event to the map model', function () {
|
||||
var container = $('<div>').css({
|
||||
'height': '200px',
|
||||
'width': '200px'
|
||||
});
|
||||
var map = new Map({
|
||||
drag: false
|
||||
}, {
|
||||
layersFactory: {}
|
||||
});
|
||||
var mapView = new GoogleMapsMapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
mapView.render();
|
||||
|
||||
spyOn(map, 'trigger');
|
||||
spyOn(mapView, 'trigger');
|
||||
|
||||
google.maps.event.trigger(mapView._gmapsMap, 'dragend');
|
||||
|
||||
expect(map.trigger).toHaveBeenCalledWith('moveend', jasmine.any(Object));
|
||||
|
||||
map.trigger.calls.reset();
|
||||
mapView.trigger.calls.reset();
|
||||
|
||||
google.maps.event.trigger(mapView._gmapsMap, 'zoom_changed');
|
||||
|
||||
expect(map.trigger).toHaveBeenCalledWith('moveend', jasmine.any(Object));
|
||||
|
||||
map.trigger.calls.reset();
|
||||
mapView.trigger.calls.reset();
|
||||
});
|
||||
|
||||
it('should set mapview size when bounds changes', function () {
|
||||
google.maps.event.trigger(mapView._gmapsMap, 'bounds_changed');
|
||||
expect(map.setMapViewSize).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('converters', function () {
|
||||
it('should set converters', function () {
|
||||
expect(map.setPixelToLatLngConverter).toHaveBeenCalled();
|
||||
expect(map.setLatLngToPixelConverter).toHaveBeenCalled();
|
||||
expect(map._pixelToLatLngConverter).toBeDefined();
|
||||
expect(map._latLngToPixelConverter).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call native methods', function () {
|
||||
spyOn(mapView.projector, 'latLngToPixel').and.callThrough();
|
||||
spyOn(mapView.projector, 'pixelToLatLng').and.callThrough();
|
||||
|
||||
var pixelToLatLng = map.pixelToLatLng();
|
||||
pixelToLatLng({x: 0, y: 0});
|
||||
expect(mapView.projector.pixelToLatLng).toHaveBeenCalled();
|
||||
|
||||
var latLngToPixel = map.latLngToPixel();
|
||||
latLngToPixel([0, 0]);
|
||||
expect(mapView.projector.latLngToPixel).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('listeners', function () {
|
||||
beforeEach(function (done) {
|
||||
// Listen for the map to be ready
|
||||
mapView.onReady(done);
|
||||
});
|
||||
|
||||
it('sets isReady to true if idle event is triggered', function () {
|
||||
expect(mapView._isReady).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var GoogleMapsMapView = require('../../../../src/geo/gmaps/gmaps-map-view');
|
||||
var GMapsLayerViewFactory = require('../../../../src/geo/gmaps/gmaps-layer-view-factory');
|
||||
var TorqueLayer = require('../../../../src/geo/map/torque-layer');
|
||||
var MockFactory = require('../../../helpers/mockFactory');
|
||||
var SharedTestsForTorqueLayer = require('../shared-tests-for-torque-layer');
|
||||
var torque = require('torque.js');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/gmaps/gmaps-torque-layer-view', function () {
|
||||
beforeEach(function () {
|
||||
var container = $('<div>').css('height', '200px');
|
||||
var engineMock = createEngine();
|
||||
this.map = new Map(null, {
|
||||
layersFactory: {}
|
||||
});
|
||||
spyOn(this.map, 'trigger');
|
||||
this.view = new GoogleMapsMapView({
|
||||
el: container,
|
||||
mapModel: this.map,
|
||||
engine: new Backbone.Model(),
|
||||
layerViewFactory: new GMapsLayerViewFactory(),
|
||||
layerGroupModel: new Backbone.Model(),
|
||||
showLimitErrors: false
|
||||
});
|
||||
|
||||
this.model = new TorqueLayer({
|
||||
type: 'torque',
|
||||
source: MockFactory.createAnalysisModel({ id: 'a0' }),
|
||||
cartocss: '#test {}',
|
||||
'torque-steps': 100
|
||||
}, { engine: engineMock });
|
||||
spyOn(torque, 'GMapsTorqueLayer').and.callThrough();
|
||||
this.map.addLayer(this.model);
|
||||
this.view = this.view._layerViews[this.model.cid];
|
||||
});
|
||||
|
||||
SharedTestsForTorqueLayer.call(this);
|
||||
|
||||
it('should apply TorqueLayer initialize method on the extended view with a bunch of attrs', function () {
|
||||
expect(torque.GMapsTorqueLayer).toHaveBeenCalled();
|
||||
|
||||
var attrs = torque.GMapsTorqueLayer.calls.argsFor(0)[0];
|
||||
expect(attrs.cartocss).toEqual(jasmine.any(String));
|
||||
});
|
||||
|
||||
describe('when GMapsTorqueLayer triggers tileError', function () {
|
||||
it('should trigger error:limit in mapModel if showLimitErrors is true', function () {
|
||||
this.view.showLimitErrors = true;
|
||||
this.view.nativeTorqueLayer.fire('tileError');
|
||||
var calls = this.map.trigger.calls.all();
|
||||
var types = calls.map(function (call) {
|
||||
return call.args[0];
|
||||
});
|
||||
expect(types).toContain('error:limit');
|
||||
});
|
||||
|
||||
it('should not trigger error:limit in mapModel if showLimitErrors is false', function () {
|
||||
this.view.nativeTorqueLayer.fire('tileError');
|
||||
var calls = this.map.trigger.calls.all();
|
||||
var types = calls.map(function (call) {
|
||||
return call.args[0];
|
||||
});
|
||||
expect(types).not.toContain('error:limit');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
// var $ = require('jquery');
|
||||
// var CartoDBLayerGMaps = require('../../../../src/geo/gmaps/cartodb-layer-gmaps');
|
||||
|
||||
// describe('CartoDBLayerGMaps: Hide funcionality', function() {
|
||||
// var div, map, cdb_layer;
|
||||
|
||||
// beforeEach(function() {
|
||||
// div = document.createElement('div');
|
||||
// div.setAttribute("id","map");
|
||||
// div.style.height = "100px";
|
||||
// div.style.width = "100px";
|
||||
|
||||
// map = new google.maps.Map(div, {
|
||||
// center: new google.maps.LatLng(51.505, -0.09),
|
||||
// disableDefaultUI: false,
|
||||
// zoom: 13,
|
||||
// mapTypeId: google.maps.MapTypeId.ROADMAP,
|
||||
// mapTypeControl: false
|
||||
// });
|
||||
|
||||
// cdb_layer = new CartoDBLayerGMaps({
|
||||
// map: map,
|
||||
// user_name:"examples",
|
||||
// tile_style: 'test',
|
||||
// table_name: 'earthquakes',
|
||||
// query: "SELECT * FROM {{table_name}}",
|
||||
// tile_style: "#{{table_name}}{marker-fill:#E25B5B}",
|
||||
// opacity:0.8,
|
||||
// interactivity: "cartodb_id, magnitude",
|
||||
// featureOver: function(ev,latlng,pos,data) {},
|
||||
// featureOut: function() {},
|
||||
// featureClick: function(ev,latlng,pos,data) {},
|
||||
// debug: true
|
||||
// });
|
||||
|
||||
// map.overlayMapTypes.setAt(0, cdb_layer);
|
||||
|
||||
// });
|
||||
|
||||
// it('if hides layers should work', function(done) {
|
||||
|
||||
// setTimeout(function () {
|
||||
// cdb_layer.hide();
|
||||
|
||||
// setTimeout(function() {
|
||||
// var $tile = $(div).find("img[gtilekey]").first()
|
||||
// , opacity = cdb_layer.options.opacity
|
||||
// , before_opacity = cdb_layer.options.previous_opacity;
|
||||
|
||||
// expect(cdb_layer.visible).toBeFalsy();
|
||||
// expect($tile.css("opacity")).toEqual('0');
|
||||
// expect(opacity).toEqual(0);
|
||||
// expect(before_opacity).not.toEqual(0);
|
||||
// done();
|
||||
// }, 500);
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
// it('If sets opacity to 0, layer should be visible', function(done) {
|
||||
// setTimeout(function () {
|
||||
// cdb_layer.setOpacity(0);
|
||||
// expect(cdb_layer.options.visible).toBeTruthy();
|
||||
// done();
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
// it('toggle layer from a visible state should work', function(done) {
|
||||
|
||||
// setTimeout(function () {
|
||||
// cdb_layer.hide();
|
||||
// visibility = cdb_layer.toggle();
|
||||
|
||||
// setTimeout(function() {
|
||||
// var $tile = $(div).find("img[gtilekey]").first()
|
||||
// , opacity = cdb_layer.options.opacity;
|
||||
|
||||
// expect(visibility).toBeTruthy();
|
||||
// expect(cdb_layer.visible).toBeTruthy();
|
||||
// expect($tile.css("opacity")).toEqual('0.99');
|
||||
// expect(opacity).toEqual(0.99);
|
||||
// done();
|
||||
// }, 500);
|
||||
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
// });
|
||||
@@ -0,0 +1,48 @@
|
||||
// var $ = require('jquery');
|
||||
// var CartoDBLayerGMaps = require('../../../../src/geo/gmaps/cartodb-layer-gmaps');
|
||||
|
||||
// describe('CartoDBLayerGMaps: Interaction funcionality', function() {
|
||||
// var div, map, cdb_layer;
|
||||
|
||||
// beforeEach(function() {
|
||||
// div = document.createElement('div');
|
||||
// div.setAttribute("id","map");
|
||||
// div.style.height = "100px";
|
||||
// div.style.width = "100px";
|
||||
|
||||
// map = new google.maps.Map(div, {
|
||||
// center: new google.maps.LatLng(51.505, -0.09),
|
||||
// disableDefaultUI: false,
|
||||
// zoom: 13,
|
||||
// mapTypeId: google.maps.MapTypeId.ROADMAP,
|
||||
// mapTypeControl: false
|
||||
// });
|
||||
|
||||
// cdb_layer = new CartoDBLayerGMaps({
|
||||
// map: map,
|
||||
// user_name:"examples",
|
||||
// table_name: 'country_colors',
|
||||
// tile_style: 'test',
|
||||
// opacity:0.8,
|
||||
// interactivity: "cartodb_id",
|
||||
// debug: true,
|
||||
// interaction: true
|
||||
// });
|
||||
|
||||
// map.overlayMapTypes.setAt(0, cdb_layer);
|
||||
// });
|
||||
|
||||
// it('If there is no interaction defined, shouldn\'t work and failed', function() {
|
||||
// // Fake a mouseover
|
||||
// $(div).trigger('mouseover');
|
||||
// expect(cdb_layer._manageOnEvents).toThrow();
|
||||
|
||||
// // Fake a mouseout
|
||||
// $(div).trigger('mouseout');
|
||||
// expect(cdb_layer._manageOffEvents).toThrow();
|
||||
|
||||
// // Fake a click
|
||||
// $(div).trigger('click');
|
||||
// expect(cdb_layer._manageOffEvents).toThrow();
|
||||
// });
|
||||
// });
|
||||
@@ -0,0 +1,73 @@
|
||||
// var $ = require('jquery');
|
||||
// var CartoDBLayerGMaps = require('../../../../src/geo/gmaps/cartodb-layer-gmaps');
|
||||
|
||||
// describe('CartoDBLayerGMaps: Opacity interaction', function() {
|
||||
// var div, map, cdb_layer;
|
||||
|
||||
// beforeEach(function() {
|
||||
// div = document.createElement('div');
|
||||
// div.setAttribute("id","map");
|
||||
// div.style.height = "100px";
|
||||
// div.style.width = "100px";
|
||||
|
||||
// map = new google.maps.Map(div, {
|
||||
// center: new google.maps.LatLng(51.505, -0.09),
|
||||
// disableDefaultUI: false,
|
||||
// zoom: 13,
|
||||
// mapTypeId: google.maps.MapTypeId.ROADMAP,
|
||||
// mapTypeControl: false
|
||||
// });
|
||||
|
||||
// cdb_layer = new CartoDBLayerGMaps({
|
||||
// map: map,
|
||||
// user_name:"examples",
|
||||
// table_name: 'earthquakes',
|
||||
// query: "SELECT * FROM {{table_name}}",
|
||||
// tile_style: "#{{table_name}}{marker-fill:#E25B5B}",
|
||||
// opacity: 0.8,
|
||||
// interactivity: "cartodb_id, magnitude",
|
||||
// featureOver: function(ev,latlng,pos,data) {},
|
||||
// featureOut: function() {},
|
||||
// featureClick: function(ev,latlng,pos,data) {},
|
||||
// debug: true
|
||||
// });
|
||||
// map.overlayMapTypes.setAt(0, cdb_layer);
|
||||
|
||||
// });
|
||||
|
||||
// xit('Layer opacity should be 0.8', function() {
|
||||
|
||||
// waits(500);
|
||||
|
||||
// runs(function () {
|
||||
// var $layer = $(div).find("img[gtilekey]").first()
|
||||
// , opacity = cdb_layer.options.opacity;
|
||||
|
||||
// expect(cdb_layer.options.visible).toBeTruthy();
|
||||
// expect($layer.css("opacity")).toEqual('0.8');//opacity.toString());
|
||||
// });
|
||||
// });
|
||||
|
||||
// xit('Opacity shouldn\'t change if it is not visible', function() {
|
||||
|
||||
// waits(500);
|
||||
|
||||
// runs(function() {
|
||||
// cdb_layer.hide();
|
||||
// cdb_layer.setOpacity(0.3);
|
||||
// map.overlayMapTypes.setAt(0, cdb_layer);
|
||||
// });
|
||||
|
||||
// waits(500);
|
||||
|
||||
// runs(function () {
|
||||
// var $layer = $(div).find("img[gtilekey]").first()
|
||||
// , opacity = cdb_layer.options.opacity
|
||||
// , before_opacity = cdb_layer.options.previous_opacity;
|
||||
|
||||
// expect(cdb_layer.options.visible).toBeFalsy();
|
||||
// expect($layer.css("opacity")).toEqual('0.3');
|
||||
// expect(before_opacity).toEqual(0.8);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
@@ -0,0 +1,86 @@
|
||||
// var $ = require('jquery');
|
||||
// var CartoDBLayerGMaps = require('../../../../src/geo/gmaps/cartodb-layer-gmaps');
|
||||
|
||||
// describe('CartoDBLayerGMaps: Show funcionality', function() {
|
||||
// var div, map, cdb_layer;
|
||||
|
||||
// beforeEach(function() {
|
||||
// div = document.createElement('div');
|
||||
// div.setAttribute("id","map");
|
||||
// div.style.height = "100px";
|
||||
// div.style.width = "100px";
|
||||
|
||||
// map = new google.maps.Map(div, {
|
||||
// center: new google.maps.LatLng(51.505, -0.09),
|
||||
// disableDefaultUI: false,
|
||||
// zoom: 13,
|
||||
// mapTypeId: google.maps.MapTypeId.ROADMAP,
|
||||
// mapTypeControl: false
|
||||
// });
|
||||
|
||||
// cdb_layer = new CartoDBLayerGMaps({
|
||||
// map: map,
|
||||
// user_name:"examples",
|
||||
// table_name: 'earthquakes',
|
||||
// query: "SELECT * FROM {{table_name}}",
|
||||
// tile_style: "#{{table_name}}{marker-fill:#E25B5B}",
|
||||
// opacity:0.8,
|
||||
// interactivity: "cartodb_id, magnitude",
|
||||
// featureOver: function(ev,latlng,pos,data) {},
|
||||
// featureOut: function() {},
|
||||
// featureClick: function(ev,latlng,pos,data) {},
|
||||
// debug: true
|
||||
// });
|
||||
// map.overlayMapTypes.setAt(0, cdb_layer);
|
||||
|
||||
// });
|
||||
|
||||
// it('If layer is visible, show shouldn\'t do anything', function(done) {
|
||||
// setTimeout(function () {
|
||||
// expect(cdb_layer.show).toThrow();
|
||||
// var opacity = cdb_layer.options.opacity;
|
||||
// expect(cdb_layer.options.visible).toBeTruthy();
|
||||
// done();
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
// it('Shows layer after hide it', function(done) {
|
||||
// setTimeout(function () {
|
||||
// cdb_layer.hide();
|
||||
// cdb_layer.show();
|
||||
// expect(cdb_layer.options.visible).toBeTruthy();
|
||||
// done();
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
// it('If hides layer and set an opacity greater than 0, layer shouln\'t be visible', function(done) {
|
||||
// setTimeout(function () {
|
||||
// cdb_layer.hide();
|
||||
// cdb_layer.setOpacity(0.2);
|
||||
// expect(cdb_layer.visible).toBeFalsy();
|
||||
// done();
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
// it('toggle layer from hidden state should work', function(done) {
|
||||
|
||||
// setTimeout(function () {
|
||||
// cdb_layer.show();
|
||||
// visibility = cdb_layer.toggle();
|
||||
|
||||
// setTimeout(function() {
|
||||
// var $tile = $(div).find("img[gtilekey]").first()
|
||||
// , opacity = cdb_layer.options.opacity
|
||||
// , before_opacity = cdb_layer.options.previous_opacity;
|
||||
|
||||
// expect(cdb_layer.visible).toBeFalsy();
|
||||
// expect(visibility).toBeFalsy();
|
||||
// expect($tile.css("opacity")).toEqual('0');
|
||||
// expect(opacity).toEqual(0);
|
||||
// expect(before_opacity).not.toEqual(0);
|
||||
// done();
|
||||
// }, 500);
|
||||
|
||||
// }, 500);
|
||||
// });
|
||||
// });
|
||||
@@ -0,0 +1,50 @@
|
||||
/* global L */
|
||||
var cartoLayerGroupViewTests = require('../shared-tests-for-carto-layer-group');
|
||||
var LeafletCartoDBLayerGroupView = require('../../../../src/geo/leaflet/leaflet-cartodb-layer-group-view');
|
||||
|
||||
describe('leaflet-cartodb-layer-group-view', function () {
|
||||
/**
|
||||
* Helper function used to get a map in the shared tests.
|
||||
*/
|
||||
function createNativeMap (container) {
|
||||
// Create a leaflet map inside a container
|
||||
container.setAttribute('id', 'map');
|
||||
container.style.height = '200px';
|
||||
document.body.appendChild(container);
|
||||
return L.map('map').setView([47.84808037632246, 14.2822265625], 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function used to get the tiles in the shared tests
|
||||
*/
|
||||
function getTileUrl (layerGroupView) {
|
||||
return layerGroupView.leafletLayer._url.replace('{s}', '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gmaps events and Leaflet events are different.
|
||||
*/
|
||||
var event = {
|
||||
containerPoint: { x: 264, y: 309 },
|
||||
data: {
|
||||
name: 'fakeCityName',
|
||||
cartodb_id: 123
|
||||
},
|
||||
e: {
|
||||
clientX: 696,
|
||||
clientY: 325,
|
||||
type: 'mousemove'
|
||||
},
|
||||
latlng: {
|
||||
lat: 42.293564192170095,
|
||||
lng: -8.173828125000002
|
||||
},
|
||||
layer: 0,
|
||||
layerPoint: { x: 264, y: 309 },
|
||||
originalEvent: {},
|
||||
target: {},
|
||||
type: 'mouseMove'
|
||||
};
|
||||
|
||||
cartoLayerGroupViewTests(createNativeMap, LeafletCartoDBLayerGroupView, getTileUrl, event);
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
var Backbone = require('backbone');
|
||||
var LeafletLayerView = require('../../../../src/geo/leaflet/leaflet-layer-view');
|
||||
|
||||
LeafletLayerView.prototype._createLeafletLayer = function () {
|
||||
return jasmine.createSpyObj('leafletLayer', ['redraw', 'on']);
|
||||
};
|
||||
|
||||
describe('leaflet-layer-view', function () {
|
||||
beforeEach(function () {
|
||||
this.layerModel = new Backbone.Model();
|
||||
spyOn(this.layerModel, 'bind');
|
||||
spyOn(this.layerModel, 'unbind');
|
||||
this.leafletMap = jasmine.createSpyObj('leafletMap', ['removeLayer']);
|
||||
this.layerView = new LeafletLayerView(this.layerModel, {
|
||||
nativeMap: this.leafletMap
|
||||
});
|
||||
this.leafletLayer = this.layerView.leafletLayer;
|
||||
});
|
||||
|
||||
it('should have a model change binding', function () {
|
||||
expect(this.layerModel.bind).toHaveBeenCalledWith('change', this.layerView._modelUpdated, this.layerView);
|
||||
});
|
||||
|
||||
describe('.remove', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.layerView, 'trigger');
|
||||
spyOn(this.layerView, 'unbind');
|
||||
this.layerView.remove();
|
||||
});
|
||||
|
||||
it('should remove layer from leaflet map', function () {
|
||||
expect(this.leafletMap.removeLayer).toHaveBeenCalledWith(this.leafletLayer);
|
||||
});
|
||||
|
||||
it('should trigger remove event', function () {
|
||||
expect(this.layerView.trigger).toHaveBeenCalledWith('remove', this.layerView);
|
||||
});
|
||||
|
||||
it('should unbind', function () {
|
||||
expect(this.layerModel.unbind).toHaveBeenCalledWith(null, null, this.layerView);
|
||||
expect(this.layerView.unbind).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.reload', function () {
|
||||
beforeEach(function () {
|
||||
this.layerView.reload();
|
||||
});
|
||||
|
||||
it('should redraw map', function () {
|
||||
expect(this.leafletLayer.redraw).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,253 @@
|
||||
var $ = require('jquery');
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var TileLayer = require('../../../../src/geo/map/tile-layer');
|
||||
var CartoDBLayer = require('../../../../src/geo/map/cartodb-layer');
|
||||
var PlainLayer = require('../../../../src/geo/map/plain-layer');
|
||||
var LayersCollection = require('../../../../src/geo/map/layers');
|
||||
var CartoDBLayerGroup = require('../../../../src/geo/cartodb-layer-group');
|
||||
var LeafletMapView = require('../../../../src/geo/leaflet/leaflet-map-view');
|
||||
var LeafletTiledLayerView = require('../../../../src/geo/leaflet/leaflet-tiled-layer-view');
|
||||
var LeafletPlainLayerView = require('../../../../src/geo/leaflet/leaflet-plain-layer-view');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/leaflet/leaflet-map-view', function () {
|
||||
var mapView;
|
||||
var map;
|
||||
var spy;
|
||||
var container;
|
||||
var layer;
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
container = $('<div>').css({
|
||||
'height': '200px',
|
||||
'width': '200px'
|
||||
});
|
||||
|
||||
map = new Map(null, {
|
||||
layersFactory: {},
|
||||
attribution: [ '© CARTO' ]
|
||||
});
|
||||
|
||||
spyOn(map, 'setMapViewSize').and.callThrough();
|
||||
spyOn(map, 'setPixelToLatLngConverter').and.callThrough();
|
||||
spyOn(map, 'setLatLngToPixelConverter').and.callThrough();
|
||||
|
||||
this.layerGroupModel = new CartoDBLayerGroup({}, { layersCollection: new LayersCollection() });
|
||||
spyOn(this.layerGroupModel, 'hasTileURLTemplates').and.returnValue(true);
|
||||
spyOn(this.layerGroupModel, 'getTileURLTemplate').and.returnValue('http://documentation.cartodb.com/api/v1/map/90e64f1b9145961af7ba36d71b887dd2:0/0/{z}/{x}/{y}.png');
|
||||
|
||||
mapView = new LeafletMapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: this.layerGroupModel
|
||||
});
|
||||
|
||||
mapView.render();
|
||||
|
||||
var layerURL = 'http://{s}.tiles.mapbox.com/v3/cartodb.map-1nh578vv/{z}/{x}/{y}.png';
|
||||
layer = new TileLayer({ urlTemplate: layerURL }, { engine: {} });
|
||||
|
||||
spy = jasmine.createSpyObj('spy', ['zoomChanged', 'centerChanged', 'keyboardChanged', 'changed']);
|
||||
map.bind('change:zoom', spy.zoomChanged);
|
||||
map.bind('change:keyboard', spy.keyboardChanged);
|
||||
map.bind('change:center', spy.centerChanged);
|
||||
map.bind('change', spy.changed);
|
||||
|
||||
engineMock = createEngine();
|
||||
});
|
||||
|
||||
it('should change bounds when center is set', function () {
|
||||
var spy = jasmine.createSpy('change:view_bounds_ne');
|
||||
spyOn(map, 'getViewBounds');
|
||||
map.bind('change:view_bounds_ne', spy);
|
||||
map.set('center', [10, 10]);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(map.getViewBounds).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should allow adding a layer', function () {
|
||||
map.addLayer(layer);
|
||||
expect(map.layers.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add layers on reset', function () {
|
||||
map.layers.reset([
|
||||
layer
|
||||
]);
|
||||
expect(map.layers.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should allow removing a layer', function () {
|
||||
map.addLayer(layer);
|
||||
map.removeLayer(layer);
|
||||
expect(map.layers.length).toEqual(0);
|
||||
expect(_.size(mapView._layerViews)).toEqual(0);
|
||||
});
|
||||
|
||||
it('should allow removing a layer by index', function () {
|
||||
map.addLayer(layer);
|
||||
map.removeLayerAt(0);
|
||||
expect(map.layers.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should allow removing a layer by Cid', function () {
|
||||
var cid = map.addLayer(layer);
|
||||
map.removeLayerByCid(cid);
|
||||
expect(map.layers.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should create a TiledLayerView when the layer is Tiled', function () {
|
||||
var lyr = map.addLayer(layer);
|
||||
var layerView = mapView.getLayerViewByLayerCid(lyr);
|
||||
expect(LeafletTiledLayerView.prototype.isPrototypeOf(layerView)).isPrototypeOf();
|
||||
});
|
||||
|
||||
it('should create a PlainLayer when the layer is cartodb', function () {
|
||||
layer = new PlainLayer(null, { engine: {} });
|
||||
var lyr = map.addLayer(layer);
|
||||
var layerView = mapView.getLayerViewByLayerCid(lyr);
|
||||
expect(layerView.setQuery).not.toEqual(LeafletPlainLayerView);
|
||||
});
|
||||
|
||||
it('should insert layers in specified order', function () {
|
||||
var tileLayer = new TileLayer({ urlTemplate: 'http://tilelayer1.com' }, { engine: {} });
|
||||
map.addLayer(tileLayer);
|
||||
|
||||
var tileLayer2 = new TileLayer({ urlTemplate: 'http://tilelayer2.com' }, { engine: {} });
|
||||
map.addLayer(tileLayer2, { at: 0 });
|
||||
|
||||
expect(mapView.getLayerViewByLayerCid(tileLayer.cid).leafletLayer.options.zIndex).toEqual(1);
|
||||
expect(mapView.getLayerViewByLayerCid(tileLayer2.cid).leafletLayer.options.zIndex).toEqual(0);
|
||||
});
|
||||
|
||||
it('should remove all layers when map view is cleaned', function () {
|
||||
var cartoDBLayer1 = new CartoDBLayer({ meta: { cartocss: '#layer {}' } }, { engine: engineMock });
|
||||
var cartoDBLayer2 = new CartoDBLayer({ meta: { cartocss: '#layer {}' } }, { engine: engineMock });
|
||||
var tileLayer = new TileLayer({ urlTemplate: 'test' }, { engine: {} });
|
||||
|
||||
map.addLayer(cartoDBLayer1);
|
||||
map.addLayer(cartoDBLayer2);
|
||||
map.addLayer(tileLayer);
|
||||
|
||||
expect(_.size(mapView._layerViews)).toEqual(3);
|
||||
|
||||
var layerGroupView = mapView.getLayerViewByLayerCid(cartoDBLayer1.cid);
|
||||
spyOn(layerGroupView, 'remove');
|
||||
|
||||
var tileLayerView = mapView.getLayerViewByLayerCid(tileLayer.cid);
|
||||
spyOn(tileLayerView, 'remove');
|
||||
|
||||
mapView.clean();
|
||||
|
||||
expect(_.size(mapView._layerViews)).toEqual(0);
|
||||
expect(layerGroupView.remove).toHaveBeenCalled();
|
||||
expect(tileLayerView.remove).toHaveBeenCalled();
|
||||
expect(mapView.layerGroupModel).not.toBeDefined();
|
||||
});
|
||||
|
||||
it("should not add a layer view when it can't be created", function () {
|
||||
var layer = new TileLayer({type: 'cartojs-test'}, { engine: {} });
|
||||
map.addLayer(layer);
|
||||
expect(_.size(mapView._layerViews)).toEqual(0);
|
||||
});
|
||||
|
||||
describe('attributions', function () {
|
||||
it('should not render Leaflet attributions', function () {
|
||||
var attributions = mapView.$el.find('.leaflet-control-attribution');
|
||||
expect(attributions.text()).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable leaflet dragging and double click zooming when the map has drag disabled', function () {
|
||||
var container = $('<div>').css({
|
||||
'height': '200px',
|
||||
'width': '200px'
|
||||
});
|
||||
var map = new Map({
|
||||
drag: false
|
||||
}, {
|
||||
layersFactory: {}
|
||||
});
|
||||
var mapView = new LeafletMapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
mapView.render();
|
||||
|
||||
expect(mapView._leafletMap.dragging.enabled()).toBeFalsy();
|
||||
expect(mapView._leafletMap.doubleClickZoom.enabled()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should "forward" a dragend event to the map model', function () {
|
||||
var container = $('<div>').css({
|
||||
'height': '200px',
|
||||
'width': '200px'
|
||||
});
|
||||
var map = new Map({
|
||||
drag: false
|
||||
}, {
|
||||
layersFactory: {}
|
||||
});
|
||||
var mapView = new LeafletMapView({
|
||||
el: container,
|
||||
mapModel: map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: new Backbone.Model()
|
||||
});
|
||||
mapView.render();
|
||||
|
||||
spyOn(map, 'trigger');
|
||||
|
||||
mapView._leafletMap.fire('moveend');
|
||||
|
||||
expect(map.trigger).toHaveBeenCalledWith('moveend', jasmine.any(Object));
|
||||
});
|
||||
|
||||
it('should update mapView size on resize', function () {
|
||||
mapView._leafletMap.fire('resize');
|
||||
expect(map.setMapViewSize).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('converters', function () {
|
||||
it('should set converters', function () {
|
||||
expect(map.setPixelToLatLngConverter).toHaveBeenCalled();
|
||||
expect(map.setLatLngToPixelConverter).toHaveBeenCalled();
|
||||
expect(map._pixelToLatLngConverter).toBeDefined();
|
||||
expect(map._latLngToPixelConverter).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call native methods', function () {
|
||||
spyOn(mapView._leafletMap, 'latLngToContainerPoint').and.callThrough();
|
||||
spyOn(mapView._leafletMap, 'containerPointToLatLng').and.callThrough();
|
||||
|
||||
var pixelToLatLng = map.pixelToLatLng();
|
||||
pixelToLatLng({x: 0, y: 0});
|
||||
expect(mapView._leafletMap.containerPointToLatLng).toHaveBeenCalled();
|
||||
|
||||
var latLngToPixel = map.latLngToPixel();
|
||||
latLngToPixel([0, 0]);
|
||||
expect(mapView._leafletMap.latLngToContainerPoint).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.invalidateSize', function () {
|
||||
it('should invalidate size in Leaflet and "re-center"', function () {
|
||||
spyOn(mapView._leafletMap, 'invalidateSize');
|
||||
spyOn(mapView._leafletMap, 'setView');
|
||||
var center = mapView.map.get('center');
|
||||
var zoom = mapView.map.get('zoom');
|
||||
|
||||
mapView.invalidateSize();
|
||||
|
||||
expect(mapView._leafletMap.setView).toHaveBeenCalledWith(center, zoom, jasmine.any(Object));
|
||||
expect(mapView._leafletMap.invalidateSize).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,132 @@
|
||||
var Backbone = require('backbone');
|
||||
var LeafletTiledLayerView = require('../../../../src/geo/leaflet/leaflet-tiled-layer-view');
|
||||
|
||||
describe('leaflet-tiled-layer-view', function () {
|
||||
describe('when does not support high resolution screens', function () {
|
||||
beforeEach(function () {
|
||||
this.layerModel = new Backbone.Model({
|
||||
urlTemplate: 'http://whatever.com',
|
||||
subdomains: 'a',
|
||||
opacity: 1,
|
||||
attribution: 'CARTO',
|
||||
errorTileUrl: 'http://matall.in',
|
||||
maxZoom: 10,
|
||||
minZoom: 0,
|
||||
tms: false
|
||||
});
|
||||
|
||||
this.leafletMap = jasmine.createSpy('leafletMap');
|
||||
this.layerView = new LeafletTiledLayerView(this.layerModel, {
|
||||
nativeMap: this.leafletMap
|
||||
});
|
||||
});
|
||||
|
||||
it('should have options set correctly', function () {
|
||||
expect(this.layerView.leafletLayer.options.subdomains).toEqual(['a']);
|
||||
expect(this.layerView.leafletLayer._url).toBe('http://whatever.com');
|
||||
expect(this.layerView.leafletLayer.options.attribution).toBe('CARTO');
|
||||
expect(this.layerView.leafletLayer.options.errorTileUrl).toBe('http://matall.in');
|
||||
expect(this.layerView.leafletLayer.options.maxZoom).toBe(10);
|
||||
expect(this.layerView.leafletLayer.options.minZoom).toBe(0);
|
||||
expect(this.layerView.leafletLayer.options.opacity).toBe(1);
|
||||
expect(this.layerView.leafletLayer.options.tms).toBeFalsy();
|
||||
});
|
||||
|
||||
describe('._modelUpdated', function () {
|
||||
beforeEach(function () {
|
||||
this.layerModel.set({
|
||||
subdomains: ['b'],
|
||||
urlTemplate: 'http://hello.com',
|
||||
attribution: 'carto',
|
||||
maxZoom: 12,
|
||||
minZoom: 1,
|
||||
tms: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should update several attributes', function () {
|
||||
expect(this.layerView.leafletLayer.options.subdomains).toEqual(['b']);
|
||||
expect(this.layerView.leafletLayer.options.attribution).toBe('carto');
|
||||
expect(this.layerView.leafletLayer.options.errorTileUrl).toBe('http://matall.in');
|
||||
expect(this.layerView.leafletLayer.options.maxZoom).toBe(12);
|
||||
expect(this.layerView.leafletLayer.options.minZoom).toBe(1);
|
||||
expect(this.layerView.leafletLayer.options.opacity).toBe(1);
|
||||
expect(this.layerView.leafletLayer.options.tms).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update url', function () {
|
||||
expect(this.layerView.leafletLayer._url).toBe('http://hello.com');
|
||||
});
|
||||
});
|
||||
|
||||
it('should trigger load and loading events', function () {
|
||||
var loadCallback = jasmine.createSpy('loadCallback');
|
||||
this.layerView.bind('load', loadCallback);
|
||||
this.layerView.leafletLayer.fire('load');
|
||||
expect(loadCallback).toHaveBeenCalled();
|
||||
|
||||
var loadingCallback = jasmine.createSpy('loadingCallback');
|
||||
this.layerView.bind('loading', loadingCallback);
|
||||
this.layerView.leafletLayer.fire('loading');
|
||||
expect(loadingCallback).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when supports high resolution screens', function () {
|
||||
beforeEach(function () {
|
||||
this.layerModel = new Backbone.Model({
|
||||
urlTemplate: 'http://whatever.com',
|
||||
urlTemplate2x: 'http://whatever.com2x',
|
||||
subdomains: 'a',
|
||||
opacity: 1,
|
||||
attribution: 'CARTO',
|
||||
errorTileUrl: 'http://matall.in',
|
||||
maxZoom: 10,
|
||||
minZoom: 0,
|
||||
tms: false
|
||||
});
|
||||
this.leafletMap = jasmine.createSpy('leafletMap');
|
||||
this.layerView = new LeafletTiledLayerView(this.layerModel, {
|
||||
nativeMap: this.leafletMap
|
||||
});
|
||||
});
|
||||
|
||||
describe('when is high resolution screen', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.layerView, '_isHdpi').and.returnValue(true);
|
||||
});
|
||||
|
||||
it('should update the model correctly if high resolution template is enabled', function () {
|
||||
this.layerModel.set({
|
||||
urlTemplate: 'http://hello.com',
|
||||
urlTemplate2x: 'http://hello.com2x'
|
||||
});
|
||||
|
||||
expect(this.layerView.leafletLayer._url).toBe('http://hello.com2x');
|
||||
});
|
||||
|
||||
it('should update the model correctly if high resolution template is not enabled', function () {
|
||||
this.layerModel.set({
|
||||
urlTemplate: 'http://hello.com'
|
||||
});
|
||||
|
||||
expect(this.layerView.leafletLayer._url).toBe('http://hello.com');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when it is not a high resolution screen', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.layerView, '_isHdpi').and.returnValue(false);
|
||||
});
|
||||
|
||||
it('should update the model correctly if high resolution template is enabled', function () {
|
||||
this.layerModel.set({
|
||||
urlTemplate: 'http://hello.com',
|
||||
urlTemplate2x: 'http://hello.com2x'
|
||||
});
|
||||
|
||||
expect(this.layerView.leafletLayer._url).toBe('http://hello.com');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
/* global L */
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var Map = require('../../../../src/geo/map');
|
||||
var LeafletMapView = require('../../../../src/geo/leaflet/leaflet-map-view');
|
||||
var LeafletLayerViewFactory = require('../../../../src/geo/leaflet/leaflet-layer-view-factory');
|
||||
var TorqueLayer = require('../../../../src/geo/map/torque-layer');
|
||||
var MockFactory = require('../../../helpers/mockFactory');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
var SharedTestsForTorqueLayer = require('../shared-tests-for-torque-layer');
|
||||
|
||||
describe('geo/leaflet/leaflet-torque-layer-view', function () {
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
var container = $('<div>').css({
|
||||
'height': '200px',
|
||||
'width': '200px'
|
||||
});
|
||||
engineMock = createEngine();
|
||||
this.map = new Map(null, {
|
||||
layersFactory: {}
|
||||
});
|
||||
spyOn(this.map, 'trigger');
|
||||
this.mapView = new LeafletMapView({
|
||||
el: container,
|
||||
mapModel: this.map,
|
||||
engine: new Backbone.Model(),
|
||||
layerViewFactory: new LeafletLayerViewFactory(),
|
||||
layerGroupModel: new Backbone.Model(),
|
||||
showLimitErrors: false
|
||||
});
|
||||
this.mapView.render();
|
||||
|
||||
spyOn(L.TorqueLayer.prototype, 'initialize').and.callThrough();
|
||||
|
||||
this.model = new TorqueLayer({
|
||||
source: MockFactory.createAnalysisModel({ id: 'a0' }),
|
||||
cartocss: 'Map {}',
|
||||
dynamic_cdn: 'dynamic-cdn-value'
|
||||
}, { engine: engineMock });
|
||||
this.map.addLayer(this.model);
|
||||
this.view = this.mapView._layerViews[this.model.cid];
|
||||
});
|
||||
|
||||
SharedTestsForTorqueLayer.call(this);
|
||||
|
||||
it('should reuse layer view', function () {
|
||||
this.view.check = 'testing';
|
||||
var newLayer = new TorqueLayer({
|
||||
source: MockFactory.createAnalysisModel({ id: 'a0' }),
|
||||
cartocss: 'Map {}',
|
||||
dynamic_cdn: 'dynamic-cdn-value'
|
||||
}, {
|
||||
engine: engineMock
|
||||
});
|
||||
this.map.layers.reset([ newLayer ]);
|
||||
|
||||
expect(this.mapView._layerViews[newLayer.cid].model).toEqual(newLayer);
|
||||
expect(this.mapView._layerViews[newLayer.cid].check).toEqual('testing');
|
||||
});
|
||||
|
||||
it('should apply Leaflet TorqueLayer initialize method on the extended view with a bunch of attrs', function () {
|
||||
expect(L.TorqueLayer.prototype.initialize).toHaveBeenCalled();
|
||||
|
||||
var attrs = L.TorqueLayer.prototype.initialize.calls.argsFor(0)[0];
|
||||
expect(attrs.cartocss).toEqual(jasmine.any(String));
|
||||
expect(attrs.dynamic_cdn).toEqual('dynamic-cdn-value');
|
||||
expect(attrs.instanciateCallback).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("should update providers's templateURL when urls change", function () {
|
||||
this.model.set('tileURLTemplates', [
|
||||
'http://pepe.carto.com/{z}/{x}/{y}.torque',
|
||||
'http://juan.carto.com/{z}/{x}/{y}.torque'
|
||||
]);
|
||||
|
||||
expect(this.view.leafletLayer.provider.templateUrl).toEqual('http://pepe.carto.com/{z}/{x}/{y}.torque');
|
||||
});
|
||||
|
||||
describe('when LeafletTorqueLayer triggers tileError', function () {
|
||||
it('should trigger error:limit in mapModel if showLimitErrors is true', function () {
|
||||
this.view.showLimitErrors = true;
|
||||
this.view.nativeTorqueLayer.fire('tileError');
|
||||
var calls = this.map.trigger.calls.all();
|
||||
var types = calls.map(function (call) {
|
||||
return call.args[0];
|
||||
});
|
||||
expect(types).toContain('error:limit');
|
||||
});
|
||||
|
||||
it('should not trigger error:limit in mapModel if showLimitErrors is false', function () {
|
||||
this.view.nativeTorqueLayer.fire('tileError');
|
||||
var calls = this.map.trigger.calls.all();
|
||||
var types = calls.map(function (call) {
|
||||
return call.args[0];
|
||||
});
|
||||
expect(types).not.toContain('error:limit');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,257 @@
|
||||
var $ = require('jquery');
|
||||
var Backbone = require('backbone');
|
||||
var createEngine = require('../fixtures/engine.fixture.js');
|
||||
var Map = require('../../../src/geo/map');
|
||||
var MapView = require('../../../src/geo/map-view');
|
||||
var TileLayer = require('../../../src/geo/map/tile-layer');
|
||||
var CartoDBLayer = require('../../../src/geo/map/cartodb-layer');
|
||||
var CartoDBLayerGroup = require('../../../src/geo/cartodb-layer-group');
|
||||
|
||||
var LayerGroupModel = CartoDBLayerGroup;
|
||||
|
||||
var fakeLayerViewFactory = {
|
||||
createLayerView: function () {
|
||||
var layerView = new Backbone.View();
|
||||
layerView.setCursor = jasmine.createSpy('setCursor');
|
||||
spyOn(layerView, 'remove');
|
||||
return layerView;
|
||||
}
|
||||
};
|
||||
|
||||
var MyMapView = MapView.extend({
|
||||
getSize: function () { return { x: 1000, y: 1000 }; },
|
||||
_getLayerViewFactory: function () {
|
||||
return fakeLayerViewFactory;
|
||||
},
|
||||
_createNativeMap: function () {}
|
||||
});
|
||||
|
||||
describe('core/geo/map-view', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
this.container = $('<div>').css('height', '200px');
|
||||
engineMock = createEngine();
|
||||
|
||||
this.map = new Map(null, {
|
||||
layersFactory: {}
|
||||
});
|
||||
|
||||
this.layerViewFactory = jasmine.createSpyObj('layerViewFactory', ['createLayerView']);
|
||||
this.mapView = new MyMapView({
|
||||
el: this.container,
|
||||
mapModel: this.map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: new LayerGroupModel(null, {
|
||||
layersCollection: this.map.layers
|
||||
})
|
||||
});
|
||||
spyOn(this.mapView, 'setCursor');
|
||||
spyOn(this.mapView, 'getNativeMap');
|
||||
spyOn(this.mapView, '_addLayerToMap');
|
||||
});
|
||||
|
||||
describe('.render', function () {
|
||||
it('should add layer views to the map', function () {
|
||||
var tileLayer = new TileLayer(null, { engine: {} });
|
||||
var cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.layers.reset([tileLayer, cartoDBLayer1, cartoDBLayer2]);
|
||||
|
||||
this.mapView = new MyMapView({
|
||||
el: this.container,
|
||||
mapModel: this.map,
|
||||
engine: new Backbone.Model(),
|
||||
layerGroupModel: new LayerGroupModel(null, {
|
||||
windshaftMap: this.windshaftMap,
|
||||
layersCollection: this.map.layers
|
||||
})
|
||||
});
|
||||
spyOn(this.mapView, 'getNativeMap');
|
||||
spyOn(this.mapView, '_addLayerToMap');
|
||||
|
||||
this.mapView.render();
|
||||
|
||||
expect(this.mapView._addLayerToMap.calls.count()).toEqual(2);
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(tileLayer.cid)).toBeDefined();
|
||||
|
||||
// Both CartoDBLayer layers share the same layer view
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid));
|
||||
|
||||
// Tile Layer has a different layer view
|
||||
expect(this.mapView.getLayerViewByLayerCid(tileLayer.cid)).not.toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid));
|
||||
});
|
||||
});
|
||||
|
||||
describe('bindings to map', function () {
|
||||
it('should fitBounds when view bounds change', function () {
|
||||
spyOn(this.map, 'fitBounds');
|
||||
|
||||
this.map.setBounds([ [0, 0], [180, 180] ]);
|
||||
expect(this.map.fitBounds).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('bindings to map.layers', function () {
|
||||
describe('when layers of map.layers are resetted', function () {
|
||||
it('should group CartoDB layers into a single layerView and add one layerView for each non-CartoDB layer', function () {
|
||||
var tileLayer = new TileLayer(null, { engine: {} });
|
||||
var cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.layers.reset([tileLayer, cartoDBLayer1, cartoDBLayer2]);
|
||||
expect(this.mapView._addLayerToMap.calls.count()).toEqual(2);
|
||||
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(tileLayer.cid)).toBeDefined();
|
||||
|
||||
// Both CartoDBLayer layers share the same layer view
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid));
|
||||
|
||||
// Tile Layer has a different layer view
|
||||
expect(this.mapView.getLayerViewByLayerCid(tileLayer.cid)).not.toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid));
|
||||
});
|
||||
|
||||
it('should trigger a "newLayerView" event for each new layerView', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.mapView.on('newLayerView', callback);
|
||||
|
||||
var tileLayer = new TileLayer(null, { engine: {} });
|
||||
var cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.layers.reset([tileLayer, cartoDBLayer1, cartoDBLayer2]);
|
||||
|
||||
expect(callback.calls.count()).toEqual(2);
|
||||
expect(callback.calls.argsFor(0)[0]).toEqual(this.mapView.getLayerViewByLayerCid(tileLayer.cid));
|
||||
expect(callback.calls.argsFor(1)[0]).toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when new layerModels are added to map.layers', function () {
|
||||
it('should add a new layer view to the map', function () {
|
||||
var layer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.addLayer(layer1);
|
||||
|
||||
var layerViewForLayer1 = this.mapView.getLayerViewByLayerCid(layer1.cid);
|
||||
expect(layerViewForLayer1).toBeDefined();
|
||||
expect(Object.keys(this.mapView._layerViews).length).toEqual(1);
|
||||
expect(this.mapView._addLayerToMap).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should group CartoDB layers into a single layerView', function () {
|
||||
var tileLayer = new TileLayer(null, { engine: {} });
|
||||
var cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.addLayer(tileLayer);
|
||||
expect(this.mapView._addLayerToMap).toHaveBeenCalled();
|
||||
this.mapView._addLayerToMap.calls.reset();
|
||||
|
||||
this.map.addLayer(cartoDBLayer1);
|
||||
expect(this.mapView._addLayerToMap).toHaveBeenCalled();
|
||||
this.mapView._addLayerToMap.calls.reset();
|
||||
|
||||
this.map.addLayer(cartoDBLayer2);
|
||||
expect(this.mapView._addLayerToMap).not.toHaveBeenCalled();
|
||||
|
||||
// There are only two layerViews cause the CartoDBLayers have been grouped
|
||||
expect(Object.keys(this.mapView._layerViews).length).toEqual(3);
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(tileLayer.cid)).toBeDefined();
|
||||
|
||||
// Both CartoDBLayer layers share the same layer view
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid));
|
||||
|
||||
// Tile Layer has a different layer view
|
||||
expect(this.mapView.getLayerViewByLayerCid(tileLayer.cid)).not.toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid));
|
||||
});
|
||||
|
||||
it('should trigger a "newLayerView" event for each new layerView', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.mapView.on('newLayerView', callback);
|
||||
|
||||
var tileLayer = new TileLayer(null, { engine: {} });
|
||||
var cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.addLayer(tileLayer);
|
||||
this.map.addLayer(cartoDBLayer1);
|
||||
this.map.addLayer(cartoDBLayer2);
|
||||
|
||||
expect(callback.calls.count()).toEqual(2);
|
||||
expect(callback.calls.argsFor(0)[0]).toEqual(this.mapView.getLayerViewByLayerCid(tileLayer.cid));
|
||||
expect(callback.calls.argsFor(1)[0]).toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when layerModels are removed from map.layers', function () {
|
||||
it('should should remove the corresponding layerView for layers that are rendered individually (not grouped)', function () {
|
||||
var tileLayer = new TileLayer(null, { engine: {} });
|
||||
|
||||
this.map.layers.reset([tileLayer]);
|
||||
|
||||
var tileLayerView = this.mapView.getLayerViewByLayerCid(tileLayer.cid);
|
||||
expect(tileLayerView).toBeDefined();
|
||||
|
||||
this.map.layers.remove(tileLayer);
|
||||
|
||||
// View for the tileLayer has been removed
|
||||
expect(tileLayerView.remove).toHaveBeenCalled();
|
||||
expect(this.mapView.getLayerViewByLayerCid(tileLayer.cid)).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should should only remove a group layerView when all grouped layerModels have been removed', function () {
|
||||
var cartoDBLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var cartoDBLayer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.layers.reset([cartoDBLayer1, cartoDBLayer2]);
|
||||
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid)).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).toEqual(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid));
|
||||
|
||||
var cartoDBLayerGroupView = this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid);
|
||||
|
||||
this.map.layers.remove(cartoDBLayer1);
|
||||
|
||||
// There's one more CartoDBLayer so the layer view has not been removed
|
||||
// this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)
|
||||
expect(cartoDBLayerGroupView.remove).not.toHaveBeenCalled();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer1.cid)).not.toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid)).toBeDefined();
|
||||
|
||||
this.map.layers.remove(cartoDBLayer2);
|
||||
|
||||
// There's one more CartoDBLayer so the layer view has not been removed
|
||||
expect(cartoDBLayerGroupView.remove).toHaveBeenCalled();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer2.cid)).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should be able to add a layer after removing it', function () {
|
||||
var cartoDBLayer = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
this.map.layers.reset([cartoDBLayer]);
|
||||
|
||||
var cartodbLayerView = this.mapView.getLayerViewByLayerCid(cartoDBLayer.cid);
|
||||
expect(cartodbLayerView).toBeDefined();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer.cid)).toBeDefined();
|
||||
|
||||
// Remove the layer
|
||||
this.map.layers.remove(cartoDBLayer);
|
||||
|
||||
// View for the cartodbLayer has been removed
|
||||
expect(cartodbLayerView.remove).toHaveBeenCalled();
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer.cid)).not.toBeDefined();
|
||||
|
||||
this.map.layers.add(cartoDBLayer);
|
||||
expect(this.mapView.getLayerViewByLayerCid(cartoDBLayer.cid)).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,510 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var PlainLayer = require('../../../src/geo/map/plain-layer');
|
||||
var CartoDBLayer = require('../../../src/geo/map/cartodb-layer');
|
||||
var TorqueLayer = require('../../../src/geo/map/torque-layer');
|
||||
var TileLayer = require('../../../src/geo/map/tile-layer');
|
||||
var WMSLayer = require('../../../src/geo/map/wms-layer');
|
||||
var GMapsBaseLayer = require('../../../src/geo/map/gmaps-base-layer');
|
||||
var LayersFactory = require('../../../src/vis/layers-factory');
|
||||
var AnalysisModel = require('../../../src/analysis/analysis-model');
|
||||
var createEngine = require('../fixtures/engine.fixture.js');
|
||||
|
||||
var Point = require('../../../src/geo/geometry-models/point');
|
||||
var Polyline = require('../../../src/geo/geometry-models/polyline');
|
||||
var Polygon = require('../../../src/geo/geometry-models/polygon');
|
||||
|
||||
var fakeLayersFactory = new LayersFactory({ engine: new Backbone.Model(), windshaftSettings: {} });
|
||||
|
||||
var createFakeAnalysis = function (attrs) {
|
||||
return new AnalysisModel(attrs, {
|
||||
engine: {},
|
||||
camshaftReference: {
|
||||
getParamNamesForAnalysisType: function () {}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var Map = require('../../../src/geo/map');
|
||||
|
||||
describe('core/geo/map', function () {
|
||||
var map;
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
this.map = map = new Map(null, { layersFactory: fakeLayersFactory });
|
||||
});
|
||||
|
||||
describe('.initialize', function () {
|
||||
it('should parse bounds and set attributes', function () {
|
||||
var map = new Map({ bounds: [[0, 1], [2, 3]] }, { layersFactory: fakeLayersFactory });
|
||||
|
||||
expect(map.get('view_bounds_sw')).toEqual([0, 1]);
|
||||
expect(map.get('view_bounds_ne')).toEqual([2, 3]);
|
||||
expect(map.get('bounds')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should set the center and zoom if no bounds are given', function () {
|
||||
var map = new Map({
|
||||
center: [41.40282319070747, 2.3435211181640625],
|
||||
zoom: 10
|
||||
},
|
||||
{
|
||||
layersFactory: fakeLayersFactory
|
||||
});
|
||||
|
||||
expect(map.get('center')).toEqual([41.40282319070747, 2.3435211181640625]);
|
||||
expect(map.get('original_center')).toEqual([41.40282319070747, 2.3435211181640625]);
|
||||
expect(map.get('zoom')).toEqual(10);
|
||||
});
|
||||
|
||||
it('should set the default center and zoom if no center and bounds are given', function () {
|
||||
var map = new Map(null, {
|
||||
layersFactory: fakeLayersFactory
|
||||
});
|
||||
|
||||
expect(map.get('center')).toEqual(map.defaults.center);
|
||||
expect(map.get('original_center')).toEqual(map.defaults.center);
|
||||
expect(map.get('zoom')).toEqual(map.defaults.zoom);
|
||||
});
|
||||
|
||||
it('should parse the center when given a string', function () {
|
||||
var map = new Map({
|
||||
center: '[41.40282319070747, 2.3435211181640625]'
|
||||
}, { layersFactory: fakeLayersFactory });
|
||||
|
||||
expect(map.get('center')).toEqual([41.40282319070747, 2.3435211181640625]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.addLayer', function () {
|
||||
it('should add a layer to the collection', function () {
|
||||
var layer = new Backbone.Model();
|
||||
map.addLayer(layer);
|
||||
expect(map.layers.models).toEqual([layer]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.removeLayer', function () {
|
||||
it('should allow removing a layer', function () {
|
||||
var layer = new Backbone.Model();
|
||||
map.addLayer(layer);
|
||||
map.removeLayer(layer);
|
||||
expect(map.layers.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.removeLayerAt', function () {
|
||||
it('should remove a layer by index', function () {
|
||||
var layer1 = new Backbone.Model();
|
||||
var layer2 = new Backbone.Model();
|
||||
map.addLayer(layer1);
|
||||
map.addLayer(layer2);
|
||||
|
||||
expect(map.layers.models).toEqual([layer1, layer2]);
|
||||
|
||||
map.removeLayerAt(0);
|
||||
|
||||
expect(map.layers.models).toEqual([layer2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.removeLayerByCid', function () {
|
||||
it('should allow removing a layer by Cid', function () {
|
||||
var layer1 = new Backbone.Model();
|
||||
var layer2 = new Backbone.Model();
|
||||
map.addLayer(layer1);
|
||||
map.addLayer(layer2);
|
||||
|
||||
expect(map.layers.models).toEqual([layer1, layer2]);
|
||||
|
||||
map.removeLayerByCid(layer1.cid);
|
||||
|
||||
expect(map.layers.models).toEqual([layer2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.enableScrollWheel & .disableScrollWheel', function () {
|
||||
it('should enable/disable the scroll wheel', function () {
|
||||
map.disableScrollWheel();
|
||||
expect(map.get('scrollwheel')).toEqual(false);
|
||||
|
||||
map.enableScrollWheel();
|
||||
expect(map.get('scrollwheel')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should raise only one change event on setBounds', function () {
|
||||
var c = 0;
|
||||
map.bind('change:view_bounds_ne', function () {
|
||||
c++;
|
||||
});
|
||||
map.setBounds([[1, 2], [1, 2]]);
|
||||
expect(c).toEqual(1);
|
||||
});
|
||||
|
||||
it('should not change center or zoom when the bounds are not ok', function () {
|
||||
var c = 0;
|
||||
map.bind('change:center', function () {
|
||||
c++;
|
||||
});
|
||||
map.setBounds([[1, 2], [1, 2]]);
|
||||
expect(c).toEqual(0);
|
||||
});
|
||||
|
||||
it('should not change bounds when map size is 0', function () {
|
||||
map.set('zoom', 10);
|
||||
var bounds = [[43.100982876188546, 35.419921875], [60.23981116999893, 69.345703125]];
|
||||
map.fitBounds(bounds, { x: 0, y: 0 });
|
||||
expect(map.get('zoom')).toEqual(10);
|
||||
});
|
||||
|
||||
it('should adjust zoom to layer', function () {
|
||||
expect(map.get('maxZoom')).toEqual(map.defaults.maxZoom);
|
||||
expect(map.get('minZoom')).toEqual(map.defaults.minZoom);
|
||||
|
||||
var layer = new PlainLayer({ minZoom: 5, maxZoom: 25 }, { engine: {} });
|
||||
map.layers.reset(layer);
|
||||
|
||||
expect(map.get('maxZoom')).toEqual(25);
|
||||
expect(map.get('minZoom')).toEqual(5);
|
||||
|
||||
layer = new PlainLayer({ minZoom: '7', maxZoom: '31' }, { engine: {} });
|
||||
map.layers.reset(layer);
|
||||
|
||||
expect(map.get('maxZoom')).toEqual(31);
|
||||
expect(map.get('minZoom')).toEqual(7);
|
||||
});
|
||||
|
||||
it("shouldn't set a NaN zoom", function () {
|
||||
var layer = new PlainLayer({ minZoom: NaN, maxZoom: NaN }, { engine: {} });
|
||||
map.layers.reset(layer);
|
||||
|
||||
expect(map.get('maxZoom')).toEqual(map.defaults.maxZoom);
|
||||
expect(map.get('minZoom')).toEqual(map.defaults.minZoom);
|
||||
});
|
||||
|
||||
it('should update the attributions of the map when layers are reset/added/removed', function () {
|
||||
map = new Map(null, { layersFactory: fakeLayersFactory });
|
||||
|
||||
// Map has the default CartoDB attribution
|
||||
expect(map.get('attribution')).toEqual([
|
||||
'© <a href="https://carto.com/attributions" target="_blank">CARTO</a>'
|
||||
]);
|
||||
|
||||
var layer1 = new CartoDBLayer({ attribution: 'attribution1' }, { engine: engineMock });
|
||||
var layer2 = new CartoDBLayer({ attribution: 'attribution1' }, { engine: engineMock });
|
||||
var layer3 = new CartoDBLayer({ attribution: 'wadus' }, { engine: engineMock });
|
||||
var layer4 = new CartoDBLayer({ attribution: '' }, { engine: engineMock });
|
||||
|
||||
map.layers.reset([layer1, layer2, layer3, layer4]);
|
||||
|
||||
// Attributions have been updated removing duplicated and empty attributions
|
||||
expect(map.get('attribution')).toEqual([
|
||||
'attribution1',
|
||||
'wadus',
|
||||
'© <a href="https://carto.com/attributions" target="_blank">CARTO</a>'
|
||||
]);
|
||||
|
||||
var layer = new CartoDBLayer({ attribution: 'attribution2' }, { engine: engineMock });
|
||||
|
||||
map.layers.add(layer);
|
||||
|
||||
// The attribution of the new layer has been appended before the default CartoDB attribution
|
||||
expect(map.get('attribution')).toEqual([
|
||||
'attribution1',
|
||||
'wadus',
|
||||
'attribution2',
|
||||
'© <a href="https://carto.com/attributions" target="_blank">CARTO</a>'
|
||||
]);
|
||||
|
||||
layer.set('attribution', 'new attribution');
|
||||
|
||||
// The attribution of the layer has been updated in the map
|
||||
expect(map.get('attribution')).toEqual([
|
||||
'attribution1',
|
||||
'wadus',
|
||||
'new attribution',
|
||||
'© <a href="https://carto.com/attributions" target="_blank">CARTO</a>'
|
||||
]);
|
||||
|
||||
map.layers.remove(layer);
|
||||
|
||||
expect(map.get('attribution')).toEqual([
|
||||
'attribution1',
|
||||
'wadus',
|
||||
'© <a href="https://carto.com/attributions" target="_blank">CARTO</a>'
|
||||
]);
|
||||
|
||||
// Addind a layer with the default attribution
|
||||
layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
map.layers.add(layer, { at: 0 });
|
||||
|
||||
// Default CartoDB only appears once and it's the last one
|
||||
expect(map.get('attribution')).toEqual([
|
||||
'attribution1',
|
||||
'wadus',
|
||||
'© <a href="https://carto.com/attributions" target="_blank">CARTO</a>'
|
||||
]);
|
||||
});
|
||||
|
||||
describe('Layer action methods', function () {
|
||||
beforeEach(function () {
|
||||
this.map.layers.add(new CartoDBLayer({}, { engine: engineMock }));
|
||||
this.map.layers.add(new PlainLayer(null, { engine: {} }));
|
||||
});
|
||||
|
||||
describe('.moveCartoDBLayer', function () {
|
||||
it('should provide a way to move CartoDB layers', function () {
|
||||
expect(this.map.moveCartoDBLayer).toBeDefined();
|
||||
});
|
||||
|
||||
it('should trigger an event in order to notify other elements', function () {
|
||||
var moveCartoDBLayer = jasmine.createSpy('moveCartoDBLayer', {});
|
||||
this.map.on('cartodbLayerMoved', moveCartoDBLayer);
|
||||
this.map.moveCartoDBLayer(0, 1);
|
||||
expect(moveCartoDBLayer).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Layer creation methods', function () {
|
||||
var testCases = [
|
||||
{
|
||||
createMethod: 'createCartoDBLayer',
|
||||
expectedLayerModelClass: CartoDBLayer,
|
||||
expectedLayerModelType: 'CartoDB',
|
||||
testAttributes: {
|
||||
source: createFakeAnalysis(),
|
||||
cartocss: 'else'
|
||||
}
|
||||
},
|
||||
{
|
||||
createMethod: 'createTorqueLayer',
|
||||
expectedLayerModelClass: TorqueLayer,
|
||||
expectedLayerModelType: 'torque',
|
||||
testAttributes: {
|
||||
source: createFakeAnalysis(),
|
||||
cartocss: 'else'
|
||||
}
|
||||
},
|
||||
{
|
||||
createMethod: 'createTileLayer',
|
||||
expectedLayerModelClass: TileLayer,
|
||||
expectedLayerModelType: 'Tiled',
|
||||
testAttributes: {
|
||||
urlTemplate: 'http://example.com'
|
||||
}
|
||||
},
|
||||
{
|
||||
createMethod: 'createWMSLayer',
|
||||
expectedLayerModelClass: WMSLayer,
|
||||
expectedLayerModelType: 'WMS',
|
||||
testAttributes: {
|
||||
urlTemplate: 'http://example.com'
|
||||
}
|
||||
},
|
||||
{
|
||||
createMethod: 'createGMapsBaseLayer',
|
||||
expectedLayerModelClass: GMapsBaseLayer,
|
||||
expectedLayerModelType: 'GMapsBase',
|
||||
testAttributes: {
|
||||
baseType: 'http://example.com'
|
||||
}
|
||||
},
|
||||
{
|
||||
createMethod: 'createPlainLayer',
|
||||
expectedLayerModelClass: PlainLayer,
|
||||
expectedLayerModelType: 'Plain',
|
||||
testAttributes: {
|
||||
color: '#FABADA'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
_.each(testCases, function (testCase) {
|
||||
describe('.' + testCase.createMethod, function () {
|
||||
it('should return a layer of the corresponding type', function () {
|
||||
var layer = this.map[testCase.createMethod](testCase.testAttributes);
|
||||
expect(layer instanceof testCase.expectedLayerModelClass).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set the right type', function () {
|
||||
var layer = this.map[testCase.createMethod](testCase.testAttributes);
|
||||
expect(layer.get('type')).toEqual(testCase.expectedLayerModelType);
|
||||
});
|
||||
|
||||
it('should add the layer model to the collection of layers', function () {
|
||||
var layer = this.map[testCase.createMethod](testCase.testAttributes);
|
||||
expect(this.map.layers.at(0)).toEqual(layer);
|
||||
});
|
||||
|
||||
it('should add the layer model at the given position', function () {
|
||||
var layer1 = this.map[testCase.createMethod](testCase.testAttributes);
|
||||
|
||||
var layer0 = this.map[testCase.createMethod](testCase.testAttributes, { at: 0 });
|
||||
var layer2 = this.map[testCase.createMethod](testCase.testAttributes, { at: 2 });
|
||||
|
||||
expect(this.map.layers.at(0)).toEqual(layer0);
|
||||
expect(this.map.layers.at(1)).toEqual(layer1);
|
||||
expect(this.map.layers.at(2)).toEqual(layer2);
|
||||
});
|
||||
|
||||
it('should remove the layer after it triggers a destroy event', function () {
|
||||
spyOn(this.map, '_removeLayerModelFromCollection');
|
||||
var layer = this.map[testCase.createMethod](testCase.testAttributes);
|
||||
layer.collection = {};
|
||||
var options = { silent: true };
|
||||
layer.trigger('destroy', layer, layer.collection, options);
|
||||
expect(this.map._removeLayerModelFromCollection).toHaveBeenCalledWith(layer, layer.collection, options);
|
||||
});
|
||||
});
|
||||
}, this);
|
||||
});
|
||||
|
||||
describe('.getLayerById', function () {
|
||||
beforeEach(function () {
|
||||
var layer1 = new CartoDBLayer({ id: 'xyz-123', attribution: 'attribution1' }, { engine: engineMock });
|
||||
|
||||
map.layers.reset(layer1);
|
||||
});
|
||||
|
||||
it('should return the corresponding model for given id', function () {
|
||||
expect(map.getLayerById('xyz-123')).toBeDefined();
|
||||
expect(map.getLayerById('meh')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.disableInteractivity', function () {
|
||||
it('should disable feature interactivity and popups', function () {
|
||||
this.map.enablePopups();
|
||||
this.map.enableFeatureInteractivity();
|
||||
|
||||
this.map.disableInteractivity();
|
||||
|
||||
expect(this.map.arePopupsEnabled()).toBeFalsy();
|
||||
expect(this.map.isFeatureInteractivityEnabled()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.enableInteractivity', function () {
|
||||
it('should enable feature interactivity and popups', function () {
|
||||
this.map.disablePopups();
|
||||
this.map.disableFeatureInteractivity();
|
||||
|
||||
this.map.enableInteractivity();
|
||||
|
||||
expect(this.map.arePopupsEnabled()).toBeTruthy();
|
||||
expect(this.map.isFeatureInteractivityEnabled()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('geometry management', function () {
|
||||
_.each({
|
||||
drawPoint: Point,
|
||||
drawPolyline: Polyline,
|
||||
drawPolygon: Polygon
|
||||
}, function (ExpectedGeometryClass, methodUnderTest) {
|
||||
it('.' + methodUnderTest + ' should trigger an event with the right geometry', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.map.on('enterDrawingMode', callback);
|
||||
|
||||
var geometry = this.map[methodUnderTest]();
|
||||
|
||||
expect(geometry instanceof ExpectedGeometryClass).toBeTruthy();
|
||||
expect(callback).toHaveBeenCalledWith(geometry);
|
||||
});
|
||||
});
|
||||
|
||||
it('.stopDrawingGeometry should trigger an event', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.map.on('exitDrawingMode', callback);
|
||||
|
||||
this.map.stopDrawingGeometry();
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('.editGeometry should trigger and event with the right geometry', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.map.on('enterEditMode', callback);
|
||||
|
||||
var geometry = this.map.editGeometry({
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [
|
||||
-3.779296875,
|
||||
40.245991504199026
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
expect(geometry instanceof Point).toBeTruthy();
|
||||
expect(callback).toHaveBeenCalledWith(geometry);
|
||||
});
|
||||
|
||||
it('.stopEditingGeometry should trigger an event', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.map.on('exitEditMode', callback);
|
||||
|
||||
this.map.stopEditingGeometry();
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getEstimatedFeatureCount', function () {
|
||||
it('should return the sum of the estimated feature count for each layer (1+2)', function () {
|
||||
map = new Map(null, { layersFactory: fakeLayersFactory });
|
||||
map.layers.getCartoDBLayers = function () {
|
||||
return [{
|
||||
getEstimatedFeatureCount: function () {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
{
|
||||
getEstimatedFeatureCount: function () {
|
||||
return 2;
|
||||
}
|
||||
}];
|
||||
};
|
||||
expect(map.getEstimatedFeatureCount()).toEqual(3);
|
||||
});
|
||||
it('should return the sum of the estimated feature count for each layer (3+0)', function () {
|
||||
map = new Map(null, { layersFactory: fakeLayersFactory });
|
||||
map.layers.getCartoDBLayers = function () {
|
||||
return [{
|
||||
getEstimatedFeatureCount: function () {
|
||||
return 3;
|
||||
}
|
||||
},
|
||||
{
|
||||
getEstimatedFeatureCount: function () {
|
||||
return 0;
|
||||
}
|
||||
}];
|
||||
};
|
||||
expect(map.getEstimatedFeatureCount()).toEqual(3);
|
||||
});
|
||||
it('should return undefined when some layer has no estimated feature count', function () {
|
||||
map = new Map(null, { layersFactory: fakeLayersFactory });
|
||||
map.layers.getCartoDBLayers = function () {
|
||||
return [{
|
||||
getEstimatedFeatureCount: function () {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
{
|
||||
getEstimatedFeatureCount: function () {
|
||||
return 2;
|
||||
}
|
||||
}];
|
||||
};
|
||||
expect(map.getEstimatedFeatureCount()).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,240 @@
|
||||
var _ = require('underscore');
|
||||
var CartoDBLayer = require('../../../../src/geo/map/cartodb-layer');
|
||||
var sharedTestsForInteractiveLayers = require('./shared-for-interactive-layers');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/map/cartodb-layer', function () {
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
});
|
||||
|
||||
sharedTestsForInteractiveLayers(CartoDBLayer);
|
||||
|
||||
it('should be type CartoDB', function () {
|
||||
var layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
expect(layer.get('type')).toEqual('CartoDB');
|
||||
});
|
||||
|
||||
it('should expose infowindow and tooltip properties', function () {
|
||||
var layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
expect(layer.infowindow).toBeDefined();
|
||||
expect(layer.tooltip).toBeDefined();
|
||||
});
|
||||
|
||||
describe('vis reloading', function () {
|
||||
var ATTRIBUTES = ['sql', 'source', 'sql_wrap', 'cartocss'];
|
||||
|
||||
_.each(ATTRIBUTES, function (attribute) {
|
||||
it("should reload the vis when '" + attribute + "' attribute changes", function () {
|
||||
var layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
layer.set(attribute, 'new_value');
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reload the map just once when multiple attributes change', function () {
|
||||
var layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
var newAttributes = {};
|
||||
_.each(ATTRIBUTES, function (attr, index) {
|
||||
newAttributes[attr] = 'new_value_' + index;
|
||||
});
|
||||
layer.set(newAttributes);
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
expect(engineMock.reload.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
describe('popups changes', function () {
|
||||
var layer;
|
||||
beforeEach(function () {
|
||||
layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
});
|
||||
|
||||
describe('infowindow bind', function () {
|
||||
it('should reload the map when infowindow fields are reset', function () {
|
||||
layer.infowindow.fields.reset([
|
||||
{
|
||||
'name': 'name',
|
||||
'title': true,
|
||||
'position': 1
|
||||
}
|
||||
]);
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload the map when infowindow fields are added', function () {
|
||||
layer.infowindow.fields.add({
|
||||
'name': 'name',
|
||||
'title': true,
|
||||
'position': 1
|
||||
});
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload the map when infowindow fields are removed', function () {
|
||||
layer.infowindow.fields.add({
|
||||
'name': 'name',
|
||||
'title': true,
|
||||
'position': 1
|
||||
});
|
||||
|
||||
engineMock.reload.calls.reset();
|
||||
|
||||
layer.infowindow.fields.add({
|
||||
'name': 'name',
|
||||
'title': true,
|
||||
'position': 1
|
||||
});
|
||||
|
||||
layer.infowindow.fields.remove(layer.infowindow.fields.at(0));
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('tooltip bind', function () {
|
||||
it('should reload the map when tooltip fields are reset', function () {
|
||||
layer.tooltip.fields.reset([
|
||||
{
|
||||
'name': 'hello',
|
||||
'title': false,
|
||||
'position': 1
|
||||
}
|
||||
]);
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload the map when tooltip fields are added', function () {
|
||||
layer.tooltip.fields.add({
|
||||
'name': 'pericamen',
|
||||
'title': false,
|
||||
'position': 1
|
||||
});
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload the map when tooltip fields are removed', function () {
|
||||
layer.tooltip.fields.add({
|
||||
'name': 'rename',
|
||||
'title': true,
|
||||
'position': 1
|
||||
});
|
||||
|
||||
engineMock.reload.calls.reset();
|
||||
|
||||
layer.tooltip.fields.add({
|
||||
'name': 'name',
|
||||
'title': true,
|
||||
'position': 1
|
||||
});
|
||||
|
||||
layer.tooltip.fields.remove(layer.tooltip.fields.at(0));
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.isInteractive', function () {
|
||||
var layer, infowindowSpy, tooltipSpy;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
infowindowSpy = spyOn(layer, '_hasInfowindowFields');
|
||||
tooltipSpy = spyOn(layer, '_hasTooltipFields');
|
||||
});
|
||||
|
||||
it('returns true if there are selected fields', function () {
|
||||
infowindowSpy.and.returnValue(true);
|
||||
tooltipSpy.and.returnValue(false);
|
||||
expect(layer.isInteractive()).toBe(true);
|
||||
|
||||
infowindowSpy.and.returnValue(false);
|
||||
tooltipSpy.and.returnValue(true);
|
||||
expect(layer.isInteractive()).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true if there are selected fields', function () {
|
||||
infowindowSpy.and.returnValue(false);
|
||||
tooltipSpy.and.returnValue(false);
|
||||
expect(layer.isInteractive()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getInteractiveColumnNames', function () {
|
||||
it("should return 'cartodb_id' and the names of the fields for infowindows and tooltips with no duplicates", function () {
|
||||
this.layer = new CartoDBLayer({
|
||||
infowindow: {
|
||||
fields: [
|
||||
{ name: 'a' },
|
||||
{ name: 'b' }
|
||||
]
|
||||
},
|
||||
tooltip: {
|
||||
fields: [
|
||||
{ name: 'b' },
|
||||
{ name: 'c' }
|
||||
]
|
||||
}
|
||||
}, { engine: engineMock });
|
||||
|
||||
expect(this.layer.getInteractiveColumnNames()).toEqual(['cartodb_id', 'a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it("should return the 'cartodb_id' if no fields are present", function () {
|
||||
this.layer = new CartoDBLayer({
|
||||
infowindow: {
|
||||
fields: []
|
||||
},
|
||||
tooltip: {
|
||||
fields: []
|
||||
}
|
||||
}, { engine: engineMock });
|
||||
|
||||
expect(this.layer.getInteractiveColumnNames()).toEqual(['cartodb_id']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getEstimatedFeatureCount', function () {
|
||||
var layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new CartoDBLayer({}, { engine: engineMock });
|
||||
});
|
||||
it('should return undefined when there is no meta information', function () {
|
||||
layer.set('meta', {
|
||||
stats: {}
|
||||
});
|
||||
expect(layer.getEstimatedFeatureCount()).toBeUndefined();
|
||||
});
|
||||
it('should return the number of features extracted from the meta-information when the layer is visible', function () {
|
||||
layer.show();
|
||||
layer.set('meta', {
|
||||
stats: {
|
||||
estimatedFeatureCount: 27
|
||||
}
|
||||
});
|
||||
expect(layer.getEstimatedFeatureCount()).toEqual(27);
|
||||
});
|
||||
it('should return the number of features extracted from the meta-information when the layer is invisible', function () {
|
||||
layer.hide();
|
||||
layer.set('meta', {
|
||||
stats: {
|
||||
estimatedFeatureCount: 27
|
||||
}
|
||||
});
|
||||
expect(layer.getEstimatedFeatureCount()).toEqual(27);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
var GMapsBaseLayer = require('../../../../src/geo/map/gmaps-base-layer');
|
||||
|
||||
describe('GMapsBaseLayer', function () {
|
||||
it('should be type GMapsBase', function () {
|
||||
var layer = new GMapsBaseLayer();
|
||||
expect(layer.get('type')).toEqual('GMapsBase');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
var InfowindowTemplate = require('../../../../src/geo/map/infowindow-template');
|
||||
|
||||
describe('geo/map/infowindow-template', function () {
|
||||
describe('.update', function () {
|
||||
beforeEach(function () {
|
||||
this.callback = jasmine.createSpy('callback');
|
||||
this.infowindowTemplate = new InfowindowTemplate({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
this.infowindowTemplate.fields.bind('reset', this.callback, this);
|
||||
});
|
||||
|
||||
it('should reset the fields when new fields are given', function () {
|
||||
this.infowindowTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 1 },
|
||||
{ name: 'Description', title: false, position: 2 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.infowindowTemplate.fields.toJSON()).toEqual([
|
||||
{ name: 'Name', title: true, position: 1 },
|
||||
{ name: 'Description', title: false, position: 2 }
|
||||
]);
|
||||
|
||||
expect(this.callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT reset the fields when given the same fields', function () {
|
||||
this.infowindowTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.infowindowTemplate.fields.toJSON()).toEqual([
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]);
|
||||
|
||||
expect(this.callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT reset the fields when given the same fields with different `position`', function () {
|
||||
this.infowindowTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 0 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.infowindowTemplate.fields.toJSON()).toEqual([
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]);
|
||||
|
||||
expect(this.callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reset the fields when given the same fields with different `position` and order', function () {
|
||||
this.infowindowTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 0 },
|
||||
{ name: 'Description', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.callback).toHaveBeenCalled();
|
||||
this.callback.calls.reset();
|
||||
|
||||
this.infowindowTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Description', title: true, position: 0 },
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clone alternative names', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.infowindowTemplate.bind('change', callback);
|
||||
|
||||
var alternativeNames = {
|
||||
'name': 'Nombre'
|
||||
};
|
||||
|
||||
this.infowindowTemplate.update({
|
||||
alternative_names: alternativeNames
|
||||
});
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
callback.calls.reset();
|
||||
|
||||
// Original object with names is changed
|
||||
alternativeNames.description = 'Descripción';
|
||||
|
||||
this.infowindowTemplate.update({
|
||||
alternative_names: alternativeNames
|
||||
});
|
||||
|
||||
// Change event has been triggered
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
var LayerModelBase = require('../../../../src/geo/map/layer-model-base');
|
||||
|
||||
var MyLayer = LayerModelBase.extend({});
|
||||
|
||||
describe('geo/map/layer-model-base.js', function () {
|
||||
beforeEach(function () {
|
||||
this.layer = new MyLayer();
|
||||
});
|
||||
|
||||
describe('.remove', function () {
|
||||
it('should trigger a destroy event with options', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
var collection = {};
|
||||
var option = { option: 'one' };
|
||||
|
||||
this.layer.bind('destroy', callback);
|
||||
this.layer.collection = collection;
|
||||
this.layer.remove(option);
|
||||
|
||||
expect(callback).toHaveBeenCalledWith(this.layer, this.layer.collection, option);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.update', function () {
|
||||
it('should set the attributes', function () {
|
||||
this.layer.update({
|
||||
a: 1,
|
||||
b: 2
|
||||
});
|
||||
|
||||
expect(this.layer.get('a')).toEqual(1);
|
||||
expect(this.layer.get('b')).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.show', function () {
|
||||
it('should set the visible attribute to true', function () {
|
||||
this.layer.set('visible', false);
|
||||
|
||||
this.layer.show();
|
||||
|
||||
expect(this.layer.get('visible')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.hide', function () {
|
||||
it('should set the visible attribute to false', function () {
|
||||
this.layer.set('visible', true);
|
||||
|
||||
this.layer.hide();
|
||||
|
||||
expect(this.layer.get('visible')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.toggle', function () {
|
||||
it('should toggel the visible attribute', function () {
|
||||
this.layer.set('visible', false);
|
||||
|
||||
this.layer.toggle();
|
||||
|
||||
expect(this.layer.get('visible')).toBeTruthy();
|
||||
|
||||
this.layer.toggle();
|
||||
|
||||
expect(this.layer.get('visible')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setOk', function () {
|
||||
it('should unset error attribute', function () {
|
||||
this.layer.set('error', 'error');
|
||||
this.layer.setOk();
|
||||
expect(this.layer.get('error')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.setError', function () {
|
||||
it('should set error attribute', function () {
|
||||
this.layer.setError('wadus');
|
||||
|
||||
expect(this.layer.get('error')).toEqual('wadus');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,164 @@
|
||||
var Layers = require('../../../../src/geo/map/layers');
|
||||
var PlainLayer = require('../../../../src/geo/map/plain-layer');
|
||||
var TileLayer = require('../../../../src/geo/map/tile-layer');
|
||||
var TorqueLayer = require('../../../../src/geo/map/torque-layer');
|
||||
var CartoDBLayer = require('../../../../src/geo/map/cartodb-layer');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/map/layers', function () {
|
||||
var layers;
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
layers = new Layers();
|
||||
});
|
||||
|
||||
it('should re-assign order when new layers are added to the collection', function () {
|
||||
var baseLayer = new TileLayer(null, { engine: {} });
|
||||
var layer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var layer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var layer3 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
// Sets the order to 0
|
||||
layers.add(baseLayer);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
|
||||
// Sets the order to 1
|
||||
layers.add(layer1);
|
||||
layers.add(layer2);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer1.get('order')).toEqual(1);
|
||||
expect(layer2.get('order')).toEqual(2);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2 ]);
|
||||
|
||||
// Sets the order to 1 and re-orders the rest of the layers
|
||||
layers.add(layer3, { at: 1 });
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer1.get('order')).toEqual(2);
|
||||
expect(layer2.get('order')).toEqual(3);
|
||||
expect(layer3.get('order')).toEqual(1);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2, 3 ]);
|
||||
|
||||
var torqueLayer = new TorqueLayer({}, { engine: engineMock });
|
||||
|
||||
// Torque layer should be at the top
|
||||
layers.add(torqueLayer);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer1.get('order')).toEqual(2);
|
||||
expect(layer2.get('order')).toEqual(3);
|
||||
expect(layer3.get('order')).toEqual(1);
|
||||
expect(torqueLayer.get('order')).toEqual(4);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2, 3, 4 ]);
|
||||
|
||||
var tiledLayer = new TileLayer(null, { engine: {} });
|
||||
|
||||
// Tiled layer should be at the top
|
||||
layers.add(tiledLayer);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer1.get('order')).toEqual(2);
|
||||
expect(layer2.get('order')).toEqual(3);
|
||||
expect(layer3.get('order')).toEqual(1);
|
||||
expect(torqueLayer.get('order')).toEqual(4);
|
||||
expect(tiledLayer.get('order')).toEqual(5);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2, 3, 4, 5 ]);
|
||||
|
||||
var layer4 = new CartoDBLayer({}, { engine: engineMock });
|
||||
layers.add(layer4);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer1.get('order')).toEqual(2);
|
||||
expect(layer2.get('order')).toEqual(3);
|
||||
expect(layer3.get('order')).toEqual(1);
|
||||
expect(layer4.get('order')).toEqual(4);
|
||||
expect(torqueLayer.get('order')).toEqual(5);
|
||||
expect(tiledLayer.get('order')).toEqual(6);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2, 3, 4, 5, 6 ]);
|
||||
});
|
||||
|
||||
it('should re-assign order when new layers are removed from the collection', function () {
|
||||
var baseLayer = new TileLayer(null, { engine: {} });
|
||||
var layer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var layer2 = new CartoDBLayer({}, { engine: engineMock });
|
||||
var torqueLayer = new TorqueLayer({}, { engine: engineMock });
|
||||
var labelsLayer = new TileLayer(null, { engine: {} });
|
||||
|
||||
// Sets the order to 0
|
||||
layers.add(baseLayer);
|
||||
layers.add(layer1);
|
||||
layers.add(layer2);
|
||||
layers.add(torqueLayer);
|
||||
layers.add(labelsLayer);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer1.get('order')).toEqual(1);
|
||||
expect(layer2.get('order')).toEqual(2);
|
||||
expect(torqueLayer.get('order')).toEqual(3);
|
||||
expect(labelsLayer.get('order')).toEqual(4);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2, 3, 4 ]);
|
||||
|
||||
layers.remove(layer1);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer2.get('order')).toEqual(1);
|
||||
expect(torqueLayer.get('order')).toEqual(2);
|
||||
expect(labelsLayer.get('order')).toEqual(3);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2, 3 ]);
|
||||
|
||||
layers.remove(torqueLayer);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer2.get('order')).toEqual(1);
|
||||
expect(labelsLayer.get('order')).toEqual(2);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1, 2 ]);
|
||||
|
||||
layers.remove(labelsLayer);
|
||||
|
||||
expect(baseLayer.get('order')).toEqual(0);
|
||||
expect(layer2.get('order')).toEqual(1);
|
||||
expect(layers.pluck('order')).toEqual([ 0, 1 ]);
|
||||
});
|
||||
|
||||
describe('.moveCartoDBLayer', function () {
|
||||
beforeEach(function () {
|
||||
layers.add(new PlainLayer({ name: 'Positron' }, { engine: {} }));
|
||||
layers.add(new CartoDBLayer({ title: 'CARTO' }, { engine: engineMock }));
|
||||
});
|
||||
|
||||
it('should move a layer from one position to other', function () {
|
||||
var movedLayer = layers.moveCartoDBLayer(1, 0);
|
||||
expect(layers.indexOf(movedLayer)).toBe(0);
|
||||
expect(movedLayer.get('title')).toBe('CARTO');
|
||||
|
||||
layers.add(new CartoDBLayer({ title: 'CARTO 2' }, { engine: engineMock }));
|
||||
movedLayer = layers.moveCartoDBLayer(2, 1);
|
||||
expect(layers.indexOf(movedLayer)).toBe(1);
|
||||
expect(movedLayer.get('title')).toBe('CARTO 2');
|
||||
});
|
||||
|
||||
it('should move a layer from one position to other', function () {
|
||||
spyOn(layers, 'trigger');
|
||||
|
||||
var movedLayer = layers.moveCartoDBLayer(1, 0);
|
||||
|
||||
expect(layers.trigger).toHaveBeenCalledWith('layerMoved', movedLayer);
|
||||
});
|
||||
|
||||
it('should not move anything if the position is the same', function () {
|
||||
var movedLayer = layers.moveCartoDBLayer(1, 1);
|
||||
expect(movedLayer).toBeFalsy();
|
||||
expect(layers.at(1).get('title')).toBe('CARTO');
|
||||
});
|
||||
|
||||
it('should not move the layer if it is not a CartoDB type', function () {
|
||||
var movedLayer = layers.moveCartoDBLayer(0, 1);
|
||||
expect(movedLayer).toBeFalsy();
|
||||
expect(layers.at(1).get('title')).toBe('CARTO');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
var LegendModelBase = require('../../../../../src/geo/map/legends/legend-model-base');
|
||||
var createEngine = require('../../../fixtures/engine.fixture.js');
|
||||
var Engine = require('../../../../../src/engine');
|
||||
var MyLegendModel = LegendModelBase.extend({ TYPE: 'type' });
|
||||
|
||||
describe('src/geo/map/legends/legend-model-base', function () {
|
||||
var engineMock;
|
||||
var legendModel;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
legendModel = new MyLegendModel({}, { engine: engineMock });
|
||||
});
|
||||
|
||||
it('should have a "loading" state', function () {
|
||||
expect(legendModel.isLoading()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should change state to "loading" when vis is reloading', function () {
|
||||
legendModel.set('state', 'something');
|
||||
expect(legendModel.isLoading()).toBeFalsy();
|
||||
engineMock._eventEmmitter.trigger(Engine.Events.RELOAD_STARTED);
|
||||
expect(legendModel.isLoading()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
var Legends = require('../../../../../src/geo/map/legends/legends');
|
||||
var createEngine = require('../../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/map/legends/legends', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
this.legends = new Legends([
|
||||
{
|
||||
type: 'bubble',
|
||||
title: 'Bubble Legend',
|
||||
pre_html: '<p>PRE Bubble Legend</p>',
|
||||
post_html: '<p>POST Bubble Legend</p>',
|
||||
definition: {
|
||||
color: '#FABADA'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
title: 'Categories Legend',
|
||||
pre_html: '<p>PRE Category Legend</p>',
|
||||
post_html: '<p>POST Category Legend</p>',
|
||||
definition: {
|
||||
prefix: 'prefix',
|
||||
suffix: 'suffix'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'choropleth',
|
||||
title: 'Choropleth Legend',
|
||||
pre_html: '<p>PRE Choropleth Legend</p>',
|
||||
post_html: '<p>POST Choropleth Legend</p>',
|
||||
definition: {
|
||||
prefix: 'prefix',
|
||||
suffix: 'suffix'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'custom',
|
||||
title: 'Custom Legend',
|
||||
pre_html: '<p>PRE Custom Legend</p>',
|
||||
post_html: '<p>POST Custom Legend</p>',
|
||||
definition: {
|
||||
categories: [
|
||||
{ type: 'color', name: 'Item 1', color: '#CACACA;' },
|
||||
{ type: 'color', name: 'Item 2', color: '#FABADA;' }
|
||||
]
|
||||
}
|
||||
}
|
||||
], {
|
||||
engine: engineMock
|
||||
});
|
||||
});
|
||||
|
||||
it('should initialize bubble legends correctly', function () {
|
||||
expect(this.legends.bubble.get('title')).toEqual('Bubble Legend');
|
||||
expect(this.legends.bubble.get('preHTMLSnippet')).toEqual('<p>PRE Bubble Legend</p>');
|
||||
expect(this.legends.bubble.get('postHTMLSnippet')).toEqual('<p>POST Bubble Legend</p>');
|
||||
expect(this.legends.bubble.get('fillColor')).toEqual('#FABADA');
|
||||
});
|
||||
|
||||
it('should initialize category legends correctly', function () {
|
||||
expect(this.legends.category.get('title')).toEqual('Categories Legend');
|
||||
expect(this.legends.category.get('preHTMLSnippet')).toEqual('<p>PRE Category Legend</p>');
|
||||
expect(this.legends.category.get('postHTMLSnippet')).toEqual('<p>POST Category Legend</p>');
|
||||
expect(this.legends.category.get('prefix')).toEqual('prefix');
|
||||
expect(this.legends.category.get('suffix')).toEqual('suffix');
|
||||
});
|
||||
|
||||
it('should initialize choropleth legends correctly', function () {
|
||||
expect(this.legends.choropleth.get('title')).toEqual('Choropleth Legend');
|
||||
expect(this.legends.choropleth.get('preHTMLSnippet')).toEqual('<p>PRE Choropleth Legend</p>');
|
||||
expect(this.legends.choropleth.get('postHTMLSnippet')).toEqual('<p>POST Choropleth Legend</p>');
|
||||
expect(this.legends.choropleth.get('prefix')).toEqual('prefix');
|
||||
expect(this.legends.choropleth.get('suffix')).toEqual('suffix');
|
||||
});
|
||||
|
||||
it('should initialize custom legends correctly', function () {
|
||||
expect(this.legends.custom.get('title')).toEqual('Custom Legend');
|
||||
expect(this.legends.custom.get('preHTMLSnippet')).toEqual('<p>PRE Custom Legend</p>');
|
||||
expect(this.legends.custom.get('postHTMLSnippet')).toEqual('<p>POST Custom Legend</p>');
|
||||
expect(this.legends.custom.get('items').length).toEqual(2);
|
||||
});
|
||||
|
||||
it("it should 'show' all legends that have data", function () {
|
||||
this.legends = new Legends([
|
||||
{
|
||||
type: 'bubble',
|
||||
title: 'Bubble Legend',
|
||||
pre_html: '<p>PRE Bubble Legend</p>',
|
||||
post_html: '<p>POST Bubble Legend</p>',
|
||||
definition: {
|
||||
color: '#FABADA'
|
||||
}
|
||||
}
|
||||
], {
|
||||
engine: engineMock
|
||||
});
|
||||
|
||||
expect(this.legends.bubble.isVisible()).toBeTruthy();
|
||||
expect(this.legends.category.isVisible()).toBeFalsy();
|
||||
|
||||
this.legends = new Legends([
|
||||
{
|
||||
type: 'category',
|
||||
title: 'Categories Legend',
|
||||
pre_html: '<p>PRE Category Legend</p>',
|
||||
post_html: '<p>POST Category Legend</p>',
|
||||
definition: {
|
||||
prefix: 'prefix',
|
||||
suffix: 'suffix'
|
||||
}
|
||||
}
|
||||
], {
|
||||
engine: engineMock
|
||||
});
|
||||
|
||||
expect(this.legends.bubble.isVisible()).toBeFalsy();
|
||||
expect(this.legends.category.isVisible()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
var StaticLegendModelBase = require('../../../../../src/geo/map/legends/static-legend-model-base');
|
||||
var createEngine = require('../../../fixtures/engine.fixture.js');
|
||||
var Engine = require('../../../../../src/engine');
|
||||
var MyLegendModel = StaticLegendModelBase.extend({ TYPE: 'type' });
|
||||
|
||||
describe('src/geo/map/legends/static-legend-model-base', function () {
|
||||
var engineMock;
|
||||
var legendModel;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
legendModel = new MyLegendModel({}, { engine: engineMock });
|
||||
});
|
||||
|
||||
it('should never change state to "loading" when vis is reloading', function () {
|
||||
legendModel.set('state', 'something');
|
||||
expect(legendModel.isLoading()).toBeFalsy();
|
||||
engineMock._eventEmmitter.trigger(Engine.Events.RELOAD_STARTED);
|
||||
expect(legendModel.isLoading()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
var _ = require('underscore');
|
||||
var PlainLayer = require('../../../../src/geo/map/plain-layer');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('PlainLayer', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
});
|
||||
|
||||
it('should be type plain', function () {
|
||||
var layer = new PlainLayer(null, { engine: engineMock });
|
||||
expect(layer.get('type')).toEqual('Plain');
|
||||
});
|
||||
|
||||
describe('vis reloading', function () {
|
||||
var ATTRIBUTES = ['color', 'image'];
|
||||
|
||||
_.each(ATTRIBUTES, function (attribute) {
|
||||
it("should reload the vis when '" + attribute + "' attribute changes", function () {
|
||||
var layer = new PlainLayer(null, { engine: engineMock });
|
||||
|
||||
layer.set(attribute, 'new_value');
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
var _ = require('underscore');
|
||||
var MockFactory = require('../../../helpers/mockFactory');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
module.exports = function (LayerModel) {
|
||||
var layer;
|
||||
var source;
|
||||
var engineMock;
|
||||
|
||||
beforeEach(function () {
|
||||
source = MockFactory.createAnalysisModel({ id: 'a0' });
|
||||
engineMock = createEngine();
|
||||
layer = new LayerModel({source: source}, { engine: engineMock });
|
||||
});
|
||||
|
||||
var METHODS = [
|
||||
'isVisible',
|
||||
'getName'
|
||||
];
|
||||
|
||||
_.each(METHODS, function (method) {
|
||||
it('should respond to .' + method, function () {
|
||||
expect(typeof layer[method] === 'function').toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('should have legends', function () {
|
||||
var legends = [
|
||||
{ type: 'bubble', title: 'My Bubble Legend' },
|
||||
{ type: 'category', title: 'My Category Legend' },
|
||||
{ type: 'choropleth', title: 'My Choropleth Legend' },
|
||||
{ type: 'custom', title: 'My Custom Legend' }
|
||||
];
|
||||
|
||||
layer = new LayerModel({ legends: legends }, { engine: engineMock });
|
||||
|
||||
expect(layer.get('legends')).toBeUndefined();
|
||||
expect(layer.legends.bubble.get('title')).toEqual('My Bubble Legend');
|
||||
expect(layer.legends.category.get('title')).toEqual('My Category Legend');
|
||||
expect(layer.legends.choropleth.get('title')).toEqual('My Choropleth Legend');
|
||||
expect(layer.legends.custom.get('title')).toEqual('My Custom Legend');
|
||||
});
|
||||
|
||||
describe('source references', function () {
|
||||
describe('when layer is initialized', function () {
|
||||
it('should mark source as referenced', function () {
|
||||
expect(source.isSourceOf(layer)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when layer is updated', function () {
|
||||
it('should unmark source and mark new source as referenced', function () {
|
||||
var oldSource = source;
|
||||
var newSource = MockFactory.createAnalysisModel({ id: 'a1' });
|
||||
|
||||
expect(oldSource.isSourceOf(layer)).toBe(true);
|
||||
expect(newSource.isSourceOf(layer)).toBe(false);
|
||||
|
||||
layer.setSource(newSource);
|
||||
|
||||
expect(oldSource.isSourceOf(layer)).toBe(false);
|
||||
expect(newSource.isSourceOf(layer)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when layer is removed', function () {
|
||||
it('should unmark source as referenced', function () {
|
||||
expect(source.isSourceOf(layer)).toBe(true);
|
||||
|
||||
layer.remove();
|
||||
|
||||
expect(source.isSourceOf(layer)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
var TileLayer = require('../../../../src/geo/map/tile-layer');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('TileLayer', function () {
|
||||
var engineMock;
|
||||
var layer;
|
||||
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
layer = new TileLayer(null, { engine: engineMock });
|
||||
});
|
||||
|
||||
it('should be type tiled', function () {
|
||||
expect(layer.get('type')).toEqual('Tiled');
|
||||
});
|
||||
|
||||
describe('vis reloading', function () {
|
||||
it("should reload the vis when 'urlTemplate' attribute changes", function () {
|
||||
layer.set('urlTemplate', 'new_value');
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
var TooltipTemplate = require('../../../../src/geo/map/tooltip-template');
|
||||
|
||||
describe('geo/map/tooltip-template', function () {
|
||||
describe('.update', function () {
|
||||
beforeEach(function () {
|
||||
this.callback = jasmine.createSpy('callback');
|
||||
this.tooltipTemplate = new TooltipTemplate({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
this.tooltipTemplate.fields.bind('reset', this.callback, this);
|
||||
});
|
||||
|
||||
it('should reset the fields when new fields are given', function () {
|
||||
this.tooltipTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 1 },
|
||||
{ name: 'Description', title: false, position: 2 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.tooltipTemplate.fields.toJSON()).toEqual([
|
||||
{ name: 'Name', title: true, position: 1 },
|
||||
{ name: 'Description', title: false, position: 2 }
|
||||
]);
|
||||
|
||||
expect(this.callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT reset the fields when given the same fields', function () {
|
||||
this.tooltipTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.tooltipTemplate.fields.toJSON()).toEqual([
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]);
|
||||
|
||||
expect(this.callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT reset the fields when given the same fields with different `position`', function () {
|
||||
this.tooltipTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 2 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.tooltipTemplate.fields.toJSON()).toEqual([
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]);
|
||||
|
||||
expect(this.callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reset the fields when given the same fields with different `position` and order', function () {
|
||||
this.tooltipTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Name', title: true, position: 0 },
|
||||
{ name: 'Description', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.callback).toHaveBeenCalled();
|
||||
this.callback.calls.reset();
|
||||
|
||||
this.tooltipTemplate.update({
|
||||
fields: [
|
||||
{ name: 'Description', title: true, position: 0 },
|
||||
{ name: 'Name', title: true, position: 1 }
|
||||
]
|
||||
});
|
||||
|
||||
expect(this.callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clone alternative names', function () {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
this.tooltipTemplate.bind('change', callback);
|
||||
|
||||
var alternativeNames = {
|
||||
'name': 'Nombre'
|
||||
};
|
||||
|
||||
this.tooltipTemplate.update({
|
||||
alternative_names: alternativeNames
|
||||
});
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
callback.calls.reset();
|
||||
|
||||
// Original object with names is changed
|
||||
alternativeNames.description = 'Descripción';
|
||||
|
||||
this.tooltipTemplate.update({
|
||||
alternative_names: alternativeNames
|
||||
});
|
||||
|
||||
// Change event has been triggered
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,100 @@
|
||||
var _ = require('underscore');
|
||||
var TorqueLayer = require('../../../../src/geo/map/torque-layer');
|
||||
var sharedTestsForInteractiveLayers = require('./shared-for-interactive-layers');
|
||||
var createEngine = require('../../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/map/torque-layer', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
engineMock = createEngine();
|
||||
});
|
||||
|
||||
sharedTestsForInteractiveLayers(TorqueLayer);
|
||||
|
||||
describe('vis reloading', function () {
|
||||
var ATTRIBUTES = ['sql', 'sql_wrap', 'source'];
|
||||
|
||||
_.each(ATTRIBUTES, function (attribute) {
|
||||
it("should reload the vis when '" + attribute + "' attribute changes", function () {
|
||||
var layer = new TorqueLayer({}, { engine: engineMock });
|
||||
|
||||
layer.set(attribute, 'new_value');
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reload the map just once when multiple attributes change', function () {
|
||||
var layer = new TorqueLayer({}, { engine: engineMock });
|
||||
|
||||
var newAttributes = {};
|
||||
_.each(ATTRIBUTES, function (attr, index) {
|
||||
newAttributes[attr] = 'new_value_' + index;
|
||||
});
|
||||
layer.set(newAttributes);
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
expect(engineMock.reload.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
it('should NOT reload the map when cartocss is set and it was previously empty', function () {
|
||||
var layer = new TorqueLayer({}, { engine: engineMock });
|
||||
|
||||
layer.set('cartocss', 'new_value');
|
||||
|
||||
expect(engineMock.reload).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT reload the map if cartocss property has changed and a reload is not needed', function () {
|
||||
var layer = new TorqueLayer({
|
||||
cartocss: 'Map { something: "a"; -torque-time-attribute: "column"; }'
|
||||
}, { engine: engineMock });
|
||||
|
||||
layer.set('cartocss', 'Map { something: "b"; -torque-time-attribute: "column"; }');
|
||||
|
||||
expect(engineMock.reload).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
_.each([
|
||||
'-torque-frame-count',
|
||||
'-torque-time-attribute',
|
||||
'-torque-aggregation-function',
|
||||
'-torque-data-aggregation',
|
||||
'-torque-resolution'
|
||||
], function (property) {
|
||||
it('should reload the map if cartocss attribute has changed and "' + property + '"" property has changed', function () {
|
||||
var layer = new TorqueLayer({
|
||||
cartocss: 'Map { something: "a"; ' + property + ': "valueA"; }'
|
||||
}, { engine: engineMock });
|
||||
|
||||
layer.set('cartocss', 'Map { something: "b"; ' + property + ': "valueB"; }');
|
||||
|
||||
expect(engineMock.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getAnimationDuration', function () {
|
||||
var layer;
|
||||
|
||||
beforeEach(function () {
|
||||
layer = new TorqueLayer({}, { engine: engineMock });
|
||||
});
|
||||
|
||||
it('should take the animation duration if it is defined', function () {
|
||||
var cartocss = 'Map { -torque-animation-duration: 22; }';
|
||||
expect(layer.getAnimationDuration(cartocss)).toBe(22);
|
||||
|
||||
cartocss = 'Map { -torque-animation-duration:15; }';
|
||||
expect(layer.getAnimationDuration(cartocss)).toBe(15);
|
||||
});
|
||||
|
||||
it('should take the defualt animation duration if the attribute isn\'t defined', function () {
|
||||
var cartocss = 'Map { -torque-animation-aggregation: cartodb_id; }';
|
||||
expect(layer.getAnimationDuration(cartocss)).toBe(30);
|
||||
|
||||
cartocss = 'Map { something: "a"; -torque-time-attribute: "column"; }';
|
||||
expect(layer.getAnimationDuration(cartocss)).toBe(30);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,254 @@
|
||||
var CartoDBLayer = require('../../../src/geo/map/cartodb-layer.js');
|
||||
var LayersCollection = require('../../../src/geo/map/layers.js');
|
||||
var CartoDBLayerGroup = require('../../../src/geo/cartodb-layer-group.js');
|
||||
|
||||
module.exports = function (createNativeMap, CartoLayerGroupViewClass, getTileUrl, event) {
|
||||
var nativeMap;
|
||||
var container;
|
||||
var cartoDbLayer0;
|
||||
var cartoDbLayer1;
|
||||
var layerGroupView;
|
||||
|
||||
var layerGroupModelMock;
|
||||
var layersCollection;
|
||||
|
||||
var engineMock = {
|
||||
on: jasmine.createSpy('on')
|
||||
};
|
||||
|
||||
var mapModelMock = {
|
||||
on: jasmine.createSpy('on'),
|
||||
isFeatureInteractivityEnabled: jasmine.createSpy('isFeatureInteractivityEnabled').and.returnValue(false)
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
container = document.createElement('div');
|
||||
nativeMap = createNativeMap(container);
|
||||
|
||||
cartoDbLayer0 = new CartoDBLayer({}, { engine: engineMock });
|
||||
cartoDbLayer1 = new CartoDBLayer({}, { engine: engineMock });
|
||||
|
||||
layersCollection = new LayersCollection([cartoDbLayer0, cartoDbLayer1]);
|
||||
|
||||
layerGroupModelMock = new CartoDBLayerGroup({
|
||||
urls: {
|
||||
'subdomains': [0, 1, 2, 3],
|
||||
'tiles': 'http://{s}.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/{layerIndexes}/{z}/{x}/{y}.png',
|
||||
'grids': [
|
||||
[
|
||||
'http://0.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json',
|
||||
'http://1.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json',
|
||||
'http://2.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json',
|
||||
'http://3.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/{z}/{x}/{y}.grid.json'
|
||||
],
|
||||
[
|
||||
'http://0.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json',
|
||||
'http://1.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json',
|
||||
'http://2.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json',
|
||||
'http://3.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/{z}/{x}/{y}.grid.json'
|
||||
]
|
||||
],
|
||||
'attributes': [
|
||||
'http://ashbu.cartocdn.com/documentation/api/v1/map/0123456789/0/attributes',
|
||||
'http://ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1/attributes'
|
||||
]
|
||||
},
|
||||
indexOfLayersInWindshaft: [1, 2]
|
||||
}, {
|
||||
layersCollection: layersCollection
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
document.body.removeChild(container);
|
||||
});
|
||||
|
||||
it('should set the right tile url', function () {
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
|
||||
var actual = getTileUrl(layerGroupView);
|
||||
var expected = 'http://0.ashbu.cartocdn.com/documentation/api/v1/map/0123456789/1,2/{z}/{x}/{y}.png';
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
describe('interactivity', function () {
|
||||
it('should not enable interaction when there are no interactive layers ', function () {
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
|
||||
expect(layerGroupView.interaction.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should enable interaction when there are no interactive layers but map model has enabled interaction ', function () {
|
||||
mapModelMock.isFeatureInteractivityEnabled.and.returnValue(true);
|
||||
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
|
||||
expect(layerGroupView.interaction.length).toEqual(2); // 2 interactive layers
|
||||
});
|
||||
|
||||
it('should enable interaction when there are interactive layers ', function () {
|
||||
mapModelMock.isFeatureInteractivityEnabled.and.returnValue(false);
|
||||
spyOn(cartoDbLayer0, 'isInteractive').and.returnValue(true);
|
||||
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
|
||||
expect(layerGroupView.interaction.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should disable interaction for the hidden layers', function () {
|
||||
mapModelMock.isFeatureInteractivityEnabled.and.returnValue(false);
|
||||
spyOn(cartoDbLayer0, 'isInteractive').and.returnValue(true);
|
||||
spyOn(cartoDbLayer1, 'isInteractive').and.returnValue(true);
|
||||
spyOn(cartoDbLayer1, 'isVisible').and.returnValue(false);
|
||||
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
|
||||
expect(layerGroupView.interaction.length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('event firing', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(cartoDbLayer0, 'isInteractive').and.returnValue(true);
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
});
|
||||
it('should trigger a "featureOver" event when interactivity class triggers a mousemove event with some data', function (done) {
|
||||
event.e.type = 'mousemove';
|
||||
|
||||
layerGroupView.on('featureOver', function (event) {
|
||||
expect(event.layer).toEqual(cartoDbLayer0);
|
||||
expect(event.layerIndex).toEqual(0);
|
||||
// Skip this test since the container point is computed with a wrong window offset.
|
||||
// expect(event.position).toEqual({ x: 264, y: 309 });
|
||||
// expect(event.latlng).toEqual([42.293564192170095, -8.173828125000002]);
|
||||
expect(event.feature.name).toEqual('fakeCityName');
|
||||
expect(event.feature.cartodb_id).toEqual(123);
|
||||
done();
|
||||
});
|
||||
|
||||
layerGroupView.interaction[0]._eventEmitter.dispatchEvent('mousemove', event);
|
||||
});
|
||||
|
||||
it('should trigger a "featureClick" event when interactivity class triggers a "click" event', function (done) {
|
||||
event.e.type = 'click';
|
||||
|
||||
layerGroupView.on('featureClick', function (event) {
|
||||
expect(event.layer).toEqual(cartoDbLayer0);
|
||||
expect(event.layerIndex).toEqual(0);
|
||||
// Skip this test since the container point is computed with a wrong window offset.
|
||||
// expect(event.position).toEqual({ x: 264, y: 309 });
|
||||
// expect(event.latlng).toEqual([42.293564192170095, -8.173828125000002]);
|
||||
expect(event.feature.name).toEqual('fakeCityName');
|
||||
expect(event.feature.cartodb_id).toEqual(123);
|
||||
done();
|
||||
});
|
||||
|
||||
layerGroupView.interaction[0]._eventEmitter.dispatchEvent('click', event);
|
||||
});
|
||||
|
||||
it('should trigger a "featureOut" event when interactivity triggers a featureOut event', function (done) {
|
||||
event.e.type = 'mousemove';
|
||||
|
||||
layerGroupView.on('featureOut', function (event) {
|
||||
expect(event.layer).toEqual(cartoDbLayer0);
|
||||
expect(event.layerIndex).toEqual(0);
|
||||
// Skip this test since the container point is computed with a wrong window offset.
|
||||
// expect(event.position).toEqual({ x: 264, y: 309 });
|
||||
// expect(event.latlng).toEqual([42.293564192170095, -8.173828125000002]);
|
||||
done();
|
||||
});
|
||||
|
||||
layerGroupView.interaction[0]._eventEmitter.dispatchEvent('featureout', event);
|
||||
});
|
||||
|
||||
it('should trigger a "featureError" event when interactivity triggers a featureOut event', function (done) {
|
||||
pending('Not implemented yet');
|
||||
layerGroupView.on('featureError', function (event) {
|
||||
expect(event.layer).toEqual(cartoDbLayer0);
|
||||
expect(event.layerIndex).toEqual(0);
|
||||
// Skip this test since the container point is computed with a wrong window offset.
|
||||
// expect(event.position).toEqual({ x: 264, y: 309 });
|
||||
// expect(event.latlng).toEqual([42.293564192170095, -8.173828125000002]);
|
||||
done();
|
||||
});
|
||||
|
||||
layerGroupView.interaction[0]._eventEmitter.dispatchEvent('error', event);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when new urls are set', function () {
|
||||
it('should set the URL template', function () {
|
||||
layerGroupModelMock.set('urls', {
|
||||
'subdomains': [0, 1, 2, 3],
|
||||
'tiles': 'http://{s}.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/{layerIndexes}/{z}/{x}/{y}.png',
|
||||
'grids': [
|
||||
[
|
||||
'http://0.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/0/{z}/{x}/{y}.grid.json',
|
||||
'http://1.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/0/{z}/{x}/{y}.grid.json',
|
||||
'http://2.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/0/{z}/{x}/{y}.grid.json',
|
||||
'http://3.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/0/{z}/{x}/{y}.grid.json'
|
||||
],
|
||||
[
|
||||
'http://0.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/1/{z}/{x}/{y}.grid.json',
|
||||
'http://1.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/1/{z}/{x}/{y}.grid.json',
|
||||
'http://2.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/1/{z}/{x}/{y}.grid.json',
|
||||
'http://3.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/1/{z}/{x}/{y}.grid.json'
|
||||
]
|
||||
],
|
||||
'attributes': [
|
||||
'http://ashbu.cartocdn.com/documentation/api/v1/map/9876543210/0/attributes',
|
||||
'http://ashbu.cartocdn.com/documentation/api/v1/map/9876543210/1/attributes'
|
||||
]
|
||||
});
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
|
||||
var actual = getTileUrl(layerGroupView);
|
||||
var expected = 'http://0.ashbu.cartocdn.com/documentation/api/v1/map/9876543210/1,2/{z}/{x}/{y}.png';
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when there aren't tile URLS", function () {
|
||||
it('should fetch empty tiles', function () {
|
||||
layerGroupModelMock.set('urls', {
|
||||
'tiles': '',
|
||||
'grids': [],
|
||||
'attributes': [
|
||||
'http://ashbu.cartocdn.com/documentation/api/v1/map/9876543210/0/attributes'
|
||||
]
|
||||
});
|
||||
|
||||
layerGroupView = new CartoLayerGroupViewClass(layerGroupModelMock, {
|
||||
nativeMap: nativeMap,
|
||||
mapModel: mapModelMock
|
||||
});
|
||||
|
||||
var actual = getTileUrl(layerGroupView);
|
||||
var expected = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Shared behavior for all torque layer view.
|
||||
*
|
||||
* Should be called in the context of a torque-layer spec, e.g.:
|
||||
* SharedTestsForTorqueLayer.call(this);
|
||||
*
|
||||
* Expects this.view to be present as an instance of the torque layer view,
|
||||
* and should be re-created between each test run (i.e. create it in the beforeEach closure).
|
||||
*/
|
||||
module.exports = function () {
|
||||
describe('(shared tests for a torque layer view)', function () {
|
||||
beforeEach(function () {
|
||||
this.nativeTorqueLayer = this.view.nativeTorqueLayer;
|
||||
});
|
||||
|
||||
it('should setup initial values on model', function () {
|
||||
expect(this.view.model.get('step')).toEqual(0);
|
||||
expect(this.view.model.get('time')).toBeDefined(); // number of Date? varies between leaflet and gmaps
|
||||
expect(this.view.model.get('steps')).toEqual(100);
|
||||
expect(this.view.model.get('isRunning')).toBe(true);
|
||||
});
|
||||
|
||||
describe('when step attr changes on model', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.nativeTorqueLayer, 'play');
|
||||
spyOn(this.nativeTorqueLayer, 'pause');
|
||||
});
|
||||
|
||||
it('should pause/play', function () {
|
||||
this.view.model.set('isRunning', false);
|
||||
expect(this.nativeTorqueLayer.play).not.toHaveBeenCalled();
|
||||
expect(this.nativeTorqueLayer.pause).toHaveBeenCalled();
|
||||
this.view.model.set('isRunning', true);
|
||||
expect(this.nativeTorqueLayer.play).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when step attr changes on model', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.nativeTorqueLayer, 'setStep');
|
||||
this.view.model.set('step', 123);
|
||||
});
|
||||
|
||||
it('should setStep when step attr changes on model', function () {
|
||||
expect(this.nativeTorqueLayer.setStep).toHaveBeenCalledWith(123);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when steps attr changes on model', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.nativeTorqueLayer, 'setSteps');
|
||||
this.view.model.set('steps', 512);
|
||||
});
|
||||
|
||||
it('should setSteps when steps attr changes on model', function () {
|
||||
expect(this.nativeTorqueLayer.setSteps).toHaveBeenCalledWith(512);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when renderRange attr changes on model', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.nativeTorqueLayer, 'renderRange');
|
||||
spyOn(this.nativeTorqueLayer, 'resetRenderRange');
|
||||
});
|
||||
|
||||
it('should update renderRange if there are values', function () {
|
||||
this.view.model.set('renderRange', {start: 0, end: 100});
|
||||
expect(this.nativeTorqueLayer.renderRange).toHaveBeenCalledWith(0, 100);
|
||||
expect(this.nativeTorqueLayer.resetRenderRange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reset renderRange if there are no values set', function () {
|
||||
this.view.model.set('renderRange', null);
|
||||
expect(this.nativeTorqueLayer.resetRenderRange).toHaveBeenCalled();
|
||||
|
||||
this.nativeTorqueLayer.resetRenderRange.calls.reset();
|
||||
this.view.model.set('renderRange', {});
|
||||
expect(this.nativeTorqueLayer.resetRenderRange).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when change:time is fired', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.nativeTorqueLayer, 'setStep');
|
||||
spyOn(this.nativeTorqueLayer, 'renderRange');
|
||||
this.nativeTorqueLayer.fire('change:time', {
|
||||
step: 1,
|
||||
time: 9000,
|
||||
start: 0,
|
||||
end: 100
|
||||
});
|
||||
});
|
||||
|
||||
it('should update model', function () {
|
||||
expect(this.view.model.get('step')).toEqual(1);
|
||||
expect(this.view.model.get('time')).toEqual(9000);
|
||||
expect(this.view.model.get('renderRange')).toEqual({start: 0, end: 100});
|
||||
});
|
||||
|
||||
it('should not call view methods again', function () {
|
||||
expect(this.nativeTorqueLayer.setStep).not.toHaveBeenCalled();
|
||||
expect(this.nativeTorqueLayer.renderRange).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when change:steps is fired', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.nativeTorqueLayer, 'setSteps');
|
||||
this.nativeTorqueLayer.fire('change:steps', {steps: 1234});
|
||||
});
|
||||
|
||||
it('should update model', function () {
|
||||
expect(this.view.model.get('steps')).toEqual(1234);
|
||||
});
|
||||
|
||||
it('should not call view methods again', function () {
|
||||
expect(this.nativeTorqueLayer.setSteps).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when play/pause is triggered', function () {
|
||||
beforeEach(function () {
|
||||
spyOn(this.view.model, 'pause').and.callThrough();
|
||||
spyOn(this.view.model, 'play').and.callThrough();
|
||||
spyOn(this.nativeTorqueLayer, 'pause').and.callThrough();
|
||||
spyOn(this.nativeTorqueLayer, 'play').and.callThrough();
|
||||
});
|
||||
|
||||
it('should call model play/pause when triggered on view', function () {
|
||||
this.nativeTorqueLayer.pause();
|
||||
expect(this.view.model.pause).toHaveBeenCalled();
|
||||
expect(this.nativeTorqueLayer.pause.calls.count()).toEqual(1); // verify that view is not called again
|
||||
|
||||
this.nativeTorqueLayer.play();
|
||||
expect(this.view.model.play).toHaveBeenCalled();
|
||||
expect(this.nativeTorqueLayer.play.calls.count()).toEqual(1); // verify that view is not called again
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when cartocss attr changes on model', function () {
|
||||
beforeEach(function () {
|
||||
this.nativeTorqueLayer = this.view.nativeTorqueLayer;
|
||||
spyOn(this.nativeTorqueLayer, 'setCartoCSS');
|
||||
});
|
||||
|
||||
it('should set the new cartoCSS on the torque layer', function () {
|
||||
this.view.model.set('cartocss', '#layer { marker-fill: whatever; }');
|
||||
expect(this.nativeTorqueLayer.setCartoCSS).toHaveBeenCalledWith('#layer { marker-fill: whatever; }');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when tileURLTemplates and subdomains attrs change on model', function () {
|
||||
beforeEach(function () {
|
||||
this.nativeTorqueLayer = this.view.nativeTorqueLayer;
|
||||
this.nativeTorqueLayer.provider = {
|
||||
subdomains: [ '0', '1', '2' ],
|
||||
options: {},
|
||||
_setReady: function () {}
|
||||
};
|
||||
});
|
||||
|
||||
it('should set the new urlTemplate and subdomains on the torque provider', function () {
|
||||
this.view.model.set('tileURLTemplates', [ 'http://example.com/{z}/{x}/{y}.torque' ]);
|
||||
expect(this.nativeTorqueLayer.provider.templateUrl).toEqual('http://example.com/{z}/{x}/{y}.torque');
|
||||
expect(this.nativeTorqueLayer.provider.subdomains).toEqual([ '0', '1', '2' ]);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
var Backbone = require('backbone');
|
||||
var TorqueLayer = require('../../../src/geo/map/torque-layer');
|
||||
var TorqueLayerViewBase = require('../../../src/geo/torque-layer-view-base');
|
||||
var _ = require('underscore');
|
||||
var createEngine = require('../fixtures/engine.fixture.js');
|
||||
|
||||
describe('geo/torque-layer-base-view', function () {
|
||||
var engineMock;
|
||||
beforeEach(function () {
|
||||
spyOn(TorqueLayerViewBase, '_cartoCSSChanged').and.callThrough();
|
||||
spyOn(TorqueLayerViewBase, '_onUpdateDuration').and.callThrough();
|
||||
|
||||
engineMock = createEngine();
|
||||
this.model = new TorqueLayer({
|
||||
type: 'torque',
|
||||
table_name: 'table',
|
||||
sql_wrap: 'select * from (<%= sql %>) as _cdbfromsqlwrap',
|
||||
query_wrapper: 'select * from (<%= sql %>) as _cdbfromquerywrapper',
|
||||
cartocss: 'Map {}',
|
||||
dynamic_cdn: 'dynamic-cdn-value'
|
||||
}, { engine: engineMock });
|
||||
});
|
||||
|
||||
describe('_getQuery', function () {
|
||||
describe('without source', function () {
|
||||
it('should take sql_wrap in case it is defined', function () {
|
||||
var query = TorqueLayerViewBase._getQuery(this.model);
|
||||
expect(query).toBe('select * from (select * from table) as _cdbfromsqlwrap');
|
||||
});
|
||||
|
||||
it('should not take query_wrapper in case sql_wrap is not defined', function () {
|
||||
this.model.unset('sql_wrap');
|
||||
var query = TorqueLayerViewBase._getQuery(this.model);
|
||||
expect(query).toBe('select * from table');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with source', function () {
|
||||
var sourceMock = new Backbone.Model({
|
||||
query: 'select * from new_table'
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
this.model.set('source', sourceMock);
|
||||
});
|
||||
|
||||
it('should take sql_wrap in case it is defined', function () {
|
||||
var query = TorqueLayerViewBase._getQuery(this.model);
|
||||
expect(query).toBe('select * from (select * from new_table) as _cdbfromsqlwrap');
|
||||
});
|
||||
|
||||
it('should not take query_wrapper in case sql_wrap is not defined', function () {
|
||||
this.model.unset('sql_wrap');
|
||||
var query = TorqueLayerViewBase._getQuery(this.model);
|
||||
expect(query).toBe('select * from new_table');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.model.unset('source');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('_initBinds', function () {
|
||||
var test;
|
||||
|
||||
beforeEach(function () {
|
||||
var FakeObj = function () {};
|
||||
FakeObj.prototype = _.extend(
|
||||
{
|
||||
stopListening: function () {}
|
||||
},
|
||||
Backbone.Events,
|
||||
TorqueLayerViewBase
|
||||
);
|
||||
|
||||
test = new FakeObj();
|
||||
test.model = this.model;
|
||||
test.nativeTorqueLayer = {
|
||||
setCartoCSS: function () {},
|
||||
animator: {
|
||||
duration: function () {}
|
||||
}
|
||||
};
|
||||
spyOn(test.nativeTorqueLayer.animator, 'duration');
|
||||
test._onModel();
|
||||
});
|
||||
|
||||
it('should apply cartocss to native torque layer', function () {
|
||||
this.model.set('cartocss', 'Map { -torque-animation-duration: 30 }');
|
||||
expect(TorqueLayerViewBase._cartoCSSChanged).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should change animation durator when customDuration changes', function () {
|
||||
this.model.set('customDuration', 10);
|
||||
expect(TorqueLayerViewBase._onUpdateDuration).toHaveBeenCalled();
|
||||
expect(test.nativeTorqueLayer.animator.duration).toHaveBeenCalledWith(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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