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([ '© CARTO' ]); 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', '© CARTO' ]); 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', '© CARTO' ]); 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', '© CARTO' ]); map.layers.remove(layer); expect(map.get('attribution')).toEqual([ 'attribution1', 'wadus', '© CARTO' ]); // 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', '© CARTO' ]); }); 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(); }); }); });