lib/leaflet/spec/suites/map/MapSpec.js in leaflet-js-0.6.beta4 vs lib/leaflet/spec/suites/map/MapSpec.js in leaflet-js-0.7.0

- old
+ new

@@ -27,21 +27,21 @@ describe("corner case checking", function () { it("throws an exception upon reinitialization", function () { var container = document.createElement('div'), map = new L.Map(container); expect(function () { - new L.Map(container); - }).to.throwException(function(e) { + L.map(container); + }).to.throwException(function (e) { expect(e.message).to.eql("Map container is already initialized."); }); map.remove(); }); it("throws an exception if a container is not found", function () { expect(function () { - new L.Map('nonexistentdivelement'); - }).to.throwException(function(e) { + L.map('nonexistentdivelement'); + }).to.throwException(function (e) { expect(e.message).to.eql("Map container not found."); }); map.remove(); }); }); @@ -70,15 +70,28 @@ expect(spy.called).to.not.be.ok(); }); }); describe('#getCenter', function () { - it ('throws if not set before', function () { + it('throws if not set before', function () { expect(function () { map.getCenter(); }).to.throwError(); }); + + it('returns a precise center when zoomed in after being set (#426)', function () { + var center = L.latLng(10, 10); + map.setView(center, 1); + map.setZoom(19); + expect(map.getCenter()).to.eql(center); + }); + + it('returns correct center after invalidateSize (#1919)', function () { + map.setView(L.latLng(10, 10), 1); + map.invalidateSize(); + expect(map.getCenter()).not.to.eql(L.latLng(10, 10)); + }); }); describe("#whenReady", function () { describe("when the map has not yet been loaded", function () { it("calls the callback when the map is loaded", function () { @@ -106,10 +119,16 @@ it("sets the view of the map", function () { expect(map.setView([51.505, -0.09], 13)).to.be(map); expect(map.getZoom()).to.be(13); expect(map.getCenter().distanceTo([51.505, -0.09])).to.be.lessThan(5); }); + it("can be passed without a zoom specified", function () { + map.setZoom(13); + expect(map.setView([51.605, -0.11])).to.be(map); + expect(map.getZoom()).to.be(13); + expect(map.getCenter().distanceTo([51.605, -0.11])).to.be.lessThan(5); + }); }); describe("#getBounds", function () { it("is safe to call from within a moveend callback during initial load (#1027)", function () { map.on("moveend", function () { @@ -118,63 +137,235 @@ map.setView([51.505, -0.09], 13); }); }); + describe('#setMaxBounds', function () { + it("aligns pixel-wise map view center with maxBounds center if it cannot move view bounds inside maxBounds (#1908)", function () { + var container = map.getContainer(); + // large view, cannot fit within maxBounds + container.style.width = container.style.height = "1000px"; + document.body.appendChild(container); + // maxBounds + var bounds = L.latLngBounds([51.5, -0.05], [51.55, 0.05]); + map.setMaxBounds(bounds, {animate: false}); + // set view outside + map.setView(L.latLng([53.0, 0.15]), 12, {animate: false}); + // get center of bounds in pixels + var boundsCenter = map.project(bounds.getCenter()).round(); + expect(map.project(map.getCenter()).round()).to.eql(boundsCenter); + document.body.removeChild(container); + }); + it("moves map view within maxBounds by changing one coordinate", function () { + var container = map.getContainer(); + // small view, can fit within maxBounds + container.style.width = container.style.height = "200px"; + document.body.appendChild(container); + // maxBounds + var bounds = L.latLngBounds([51, -0.2], [52, 0.2]); + map.setMaxBounds(bounds, {animate: false}); + // set view outside maxBounds on one direction only + // leaves untouched the other coordinate (that is not already centered) + var initCenter = [53.0, 0.1]; + map.setView(L.latLng(initCenter), 16, {animate: false}); + // one pixel coordinate hasn't changed, the other has + var pixelCenter = map.project(map.getCenter()).round(); + var pixelInit = map.project(initCenter).round(); + expect(pixelCenter.x).to.eql(pixelInit.x); + expect(pixelCenter.y).not.to.eql(pixelInit.y); + // the view is inside the bounds + expect(bounds.contains(map.getBounds())).to.be(true); + document.body.removeChild(container); + }); + }); + describe("#getMinZoom and #getMaxZoom", function () { + describe('#getMinZoom', function () { + it('returns 0 if not set by Map options or TileLayer options', function () { + var map = L.map(document.createElement('div')); + expect(map.getMinZoom()).to.be(0); + }); + }); + it("minZoom and maxZoom options overrides any minZoom and maxZoom set on layers", function () { - var c = document.createElement('div'), - map = L.map(c, { minZoom: 5, maxZoom: 10 }); - L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map); - L.tileLayer("{z}{x}{y}", { minZoom:5, maxZoom: 15 }).addTo(map); - expect(map.getMinZoom()).to.be(5); - expect(map.getMaxZoom()).to.be(10); + + var map = L.map(document.createElement('div'), {minZoom: 2, maxZoom: 20}); + + L.tileLayer("{z}{x}{y}", {minZoom: 4, maxZoom: 10}).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 6, maxZoom: 17}).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 22}).addTo(map); + + expect(map.getMinZoom()).to.be(2); + expect(map.getMaxZoom()).to.be(20); }); }); describe("#addLayer", function () { + it("calls layer.onAdd immediately if the map is ready", function () { + var layer = { onAdd: sinon.spy() }; + map.setView([0, 0], 0); + map.addLayer(layer); + expect(layer.onAdd.called).to.be.ok(); + }); + + it("calls layer.onAdd when the map becomes ready", function () { + var layer = { onAdd: sinon.spy() }; + map.addLayer(layer); + expect(layer.onAdd.called).not.to.be.ok(); + map.setView([0, 0], 0); + expect(layer.onAdd.called).to.be.ok(); + }); + + it("does not call layer.onAdd if the layer is removed before the map becomes ready", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }; + map.addLayer(layer); + map.removeLayer(layer); + map.setView([0, 0], 0); + expect(layer.onAdd.called).not.to.be.ok(); + }); + + it("fires a layeradd event immediately if the map is ready", function () { + var layer = { onAdd: sinon.spy() }, + spy = sinon.spy(); + map.on('layeradd', spy); + map.setView([0, 0], 0); + map.addLayer(layer); + expect(spy.called).to.be.ok(); + }); + + it("fires a layeradd event when the map becomes ready", function () { + var layer = { onAdd: sinon.spy() }, + spy = sinon.spy(); + map.on('layeradd', spy); + map.addLayer(layer); + expect(spy.called).not.to.be.ok(); + map.setView([0, 0], 0); + expect(spy.called).to.be.ok(); + }); + + it("does not fire a layeradd event if the layer is removed before the map becomes ready", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }, + spy = sinon.spy(); + map.on('layeradd', spy); + map.addLayer(layer); + map.removeLayer(layer); + map.setView([0, 0], 0); + expect(spy.called).not.to.be.ok(); + }); + + it("adds the layer before firing layeradd", function (done) { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }; + map.on('layeradd', function () { + expect(map.hasLayer(layer)).to.be.ok(); + done(); + }); + map.setView([0, 0], 0); + map.addLayer(layer); + }); + describe("When the first layer is added to a map", function () { it("fires a zoomlevelschange event", function () { var spy = sinon.spy(); map.on("zoomlevelschange", spy); expect(spy.called).not.to.be.ok(); - L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map); expect(spy.called).to.be.ok(); }); }); describe("when a new layer with greater zoomlevel coverage than the current layer is added to a map", function () { it("fires a zoomlevelschange event", function () { var spy = sinon.spy(); - L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map); map.on("zoomlevelschange", spy); expect(spy.called).not.to.be.ok(); - L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 15 }).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 15}).addTo(map); expect(spy.called).to.be.ok(); }); }); describe("when a new layer with the same or lower zoomlevel coverage as the current layer is added to a map", function () { it("fires no zoomlevelschange event", function () { var spy = sinon.spy(); - L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map); map.on("zoomlevelschange", spy); expect(spy.called).not.to.be.ok(); - L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map); expect(spy.called).not.to.be.ok(); - L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 5 }).addTo(map); + L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 5}).addTo(map); expect(spy.called).not.to.be.ok(); }); }); }); describe("#removeLayer", function () { + it("calls layer.onRemove if the map is ready", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }; + map.setView([0, 0], 0); + map.addLayer(layer); + map.removeLayer(layer); + expect(layer.onRemove.called).to.be.ok(); + }); + + it("does not call layer.onRemove if the layer was not added", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }; + map.setView([0, 0], 0); + map.removeLayer(layer); + expect(layer.onRemove.called).not.to.be.ok(); + }); + + it("does not call layer.onRemove if the map is not ready", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }; + map.addLayer(layer); + map.removeLayer(layer); + expect(layer.onRemove.called).not.to.be.ok(); + }); + + it("fires a layerremove event if the map is ready", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }, + spy = sinon.spy(); + map.on('layerremove', spy); + map.setView([0, 0], 0); + map.addLayer(layer); + map.removeLayer(layer); + expect(spy.called).to.be.ok(); + }); + + it("does not fire a layerremove if the layer was not added", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }, + spy = sinon.spy(); + map.on('layerremove', spy); + map.setView([0, 0], 0); + map.removeLayer(layer); + expect(spy.called).not.to.be.ok(); + }); + + it("does not fire a layerremove if the map is not ready", function () { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }, + spy = sinon.spy(); + map.on('layerremove', spy); + map.addLayer(layer); + map.removeLayer(layer); + expect(spy.called).not.to.be.ok(); + }); + + it("removes the layer before firing layerremove", function (done) { + var layer = { onAdd: sinon.spy(), onRemove: sinon.spy() }; + map.on('layerremove', function () { + expect(map.hasLayer(layer)).not.to.be.ok(); + done(); + }); + map.setView([0, 0], 0); + map.addLayer(layer); + map.removeLayer(layer); + }); + describe("when the last tile layer on a map is removed", function () { it("fires a zoomlevelschange event", function () { - map.whenReady(function(){ + map.whenReady(function () { var spy = sinon.spy(); - var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map); + var tl = L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map); map.on("zoomlevelschange", spy); expect(spy.called).not.to.be.ok(); map.removeLayer(tl); expect(spy.called).to.be.ok(); @@ -182,14 +373,14 @@ }); }); describe("when a tile layer is removed from a map and it had greater zoom level coverage than the remainding layer", function () { it("fires a zoomlevelschange event", function () { - map.whenReady(function(){ + map.whenReady(function () { var spy = sinon.spy(), - tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map), - t2 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 15 }).addTo(map); + tl = L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map), + t2 = L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 15}).addTo(map); map.on("zoomlevelschange", spy); expect(spy.called).to.not.be.ok(); map.removeLayer(t2); expect(spy.called).to.be.ok(); @@ -197,14 +388,14 @@ }); }); describe("when a tile layer is removed from a map it and it had lesser or the sa,e zoom level coverage as the remainding layer(s)", function () { it("fires no zoomlevelschange event", function () { - map.whenReady(function(){ - var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map), - t2 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map), - t3 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 5 }).addTo(map); + map.whenReady(function () { + var tl = L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map), + t2 = L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 10}).addTo(map), + t3 = L.tileLayer("{z}{x}{y}", {minZoom: 0, maxZoom: 5}).addTo(map); map.on("zoomlevelschange", spy); expect(spy).not.toHaveBeenCalled(); map.removeLayer(t2); expect(spy).not.toHaveBeenCalled(); @@ -237,8 +428,109 @@ spy = sinon.spy(); map.eachLayer(spy, map); expect(spy.thisValues[0]).to.eql(map); + }); + }); + + describe("#invalidateSize", function () { + var container, + origWidth = 100, + clock; + + beforeEach(function () { + container = map.getContainer(); + container.style.width = origWidth + "px"; + document.body.appendChild(container); + map.setView([0, 0], 0); + map.invalidateSize({pan: false}); + clock = sinon.useFakeTimers(); + }); + + afterEach(function () { + document.body.removeChild(container); + clock.restore(); + }); + + it("pans by the right amount when growing in 1px increments", function () { + container.style.width = (origWidth + 1) + "px"; + map.invalidateSize(); + expect(map._getMapPanePos().x).to.be(1); + + container.style.width = (origWidth + 2) + "px"; + map.invalidateSize(); + expect(map._getMapPanePos().x).to.be(1); + + container.style.width = (origWidth + 3) + "px"; + map.invalidateSize(); + expect(map._getMapPanePos().x).to.be(2); + }); + + it("pans by the right amount when shrinking in 1px increments", function () { + container.style.width = (origWidth - 1) + "px"; + map.invalidateSize(); + expect(map._getMapPanePos().x).to.be(0); + + container.style.width = (origWidth - 2) + "px"; + map.invalidateSize(); + expect(map._getMapPanePos().x).to.be(-1); + + container.style.width = (origWidth - 3) + "px"; + map.invalidateSize(); + expect(map._getMapPanePos().x).to.be(-1); + }); + + it("pans back to the original position after growing by an odd size and back", function () { + container.style.width = (origWidth + 5) + "px"; + map.invalidateSize(); + + container.style.width = origWidth + "px"; + map.invalidateSize(); + + expect(map._getMapPanePos().x).to.be(0); + }); + + it("emits no move event if the size has not changed", function () { + var spy = sinon.spy(); + map.on("move", spy); + + map.invalidateSize(); + + expect(spy.called).not.to.be.ok(); + }); + + it("emits a move event if the size has changed", function () { + var spy = sinon.spy(); + map.on("move", spy); + + container.style.width = (origWidth + 5) + "px"; + map.invalidateSize(); + + expect(spy.called).to.be.ok(); + }); + + it("emits a moveend event if the size has changed", function () { + var spy = sinon.spy(); + map.on("moveend", spy); + + container.style.width = (origWidth + 5) + "px"; + map.invalidateSize(); + + expect(spy.called).to.be.ok(); + }); + + it("debounces the moveend event if the debounceMoveend option is given", function () { + var spy = sinon.spy(); + map.on("moveend", spy); + + container.style.width = (origWidth + 5) + "px"; + map.invalidateSize({debounceMoveend: true}); + + expect(spy.called).not.to.be.ok(); + + clock.tick(200); + + expect(spy.called).to.be.ok(); }); }); });