/
githubmirror
/
Leaflet
Обзор
Документация
Войти
/
githubmirror
/
Leaflet
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
spec/suites/layer/TooltipSpec.js
615 строк
21 KB
Iván Sánchez Ortega
Unit tests for preferCanvas (#10062)
08 янв 2026, 14:28
Не верифицирован
08 янв 2026, 14:28
cab16f4
Код
Авторство
О чём код?
import {expect} from 'chai'; import {CircleMarker, FeatureGroup, LayerGroup, LeafletMap, Marker, Polygon, Polyline, Rectangle, Tooltip} from 'leaflet'; import Hand from 'prosthetic-hand'; import sinon from 'sinon'; import UIEventSimulator from 'ui-event-simulator'; import {createContainer, removeMapContainer} from '../SpecHelper.js'; describe('Tooltip', () => { let container, map; const center = [55.8, 37.6]; beforeEach(() => { container = createContainer(); map = new LeafletMap(container); map.setView(center, 6); }); afterEach(() => { removeMapContainer(map, container); }); it('opens on marker pointerover and close on pointerout', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip'); UIEventSimulator.fire('pointerover', layer._icon, {relatedTarget: map._container}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fire('pointerout', layer._icon, {relatedTarget: map._container}); expect(map.hasLayer(layer._tooltip)).to.be.false; }); it('opens on marker focus and closes on blur', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip'); const element = layer.getElement(); UIEventSimulator.fire('focus', element); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fire('blur', element); expect(map.hasLayer(layer._tooltip)).to.be.false; }); it('opens on marker focus and closes on blur when first bound, then added to map', () => { const layer = new Marker(center); layer.bindTooltip('Tooltip').addTo(map); const element = layer.getElement(); UIEventSimulator.fire('focus', element); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fire('blur', element); expect(map.hasLayer(layer._tooltip)).to.be.false; }); it('opens on marker focus and closes on blur in layer group', () => { const marker1 = new Marker([41.18, 9.45], {description: 'Marker 1'}); const marker2 = new Marker([41.18, 9.46], {description: 'Marker 2'}); const group = new FeatureGroup([marker1, marker2]).addTo(map); group.bindTooltip(layer => `Group tooltip: ${layer.options.description}`); const element1 = marker1.getElement(); const element2 = marker2.getElement(); UIEventSimulator.fire('focus', element1); expect(map.hasLayer(group._tooltip)).to.be.true; expect(group._tooltip._container.innerHTML).to.equal('Group tooltip: Marker 1'); UIEventSimulator.fire('blur', element1); expect(map.hasLayer(group._tooltip)).to.be.false; UIEventSimulator.fire('focus', element2); expect(map.hasLayer(group._tooltip)).to.be.true; expect(group._tooltip._container.innerHTML).to.equal('Group tooltip: Marker 2'); UIEventSimulator.fire('blur', element2); expect(map.hasLayer(group._tooltip)).to.be.false; }); it('opens on marker focus and ignore layers without getElement function', () => { const marker1 = new Marker([41.18, 9.45]); const someLayerWithoutGetElement = new LayerGroup(); const group = new FeatureGroup([marker1, someLayerWithoutGetElement]).addTo(map); group.bindTooltip('Tooltip'); expect(() => { UIEventSimulator.fire('focus', marker1.getElement()); }).to.not.throw(); }); it('is mentioned in aria-describedby of a bound layer', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip'); const element = layer.getElement(); UIEventSimulator.fire('focus', element); const tooltip = layer.getTooltip(); expect(element.getAttribute('aria-describedby')).to.equal(tooltip._container.id); }); it('is mentioned in aria-describedby of a bound layer group', () => { const marker1 = new Marker([41.18, 9.45], {description: 'Marker 1'}); const marker2 = new Marker([41.18, 9.46], {description: 'Marker 2'}); const group = new FeatureGroup([marker1, marker2]).addTo(map); group.bindTooltip(layer => `Group tooltip: ${layer.options.description}`); const element = marker2.getElement(); UIEventSimulator.fire('focus', element); const tooltip = group.getTooltip(); expect(element.getAttribute('aria-describedby')).to.equal(tooltip._container.id); }); it('stays open on marker when permanent', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip', {permanent: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; }); it('can be added with bindTooltip before added to the map', () => { const layer = new Marker(center); layer.bindTooltip('Tooltip', {permanent: true}); expect(map.hasLayer(layer._tooltip)).to.be.false; layer.addTo(map); expect(map.hasLayer(layer._tooltip)).to.be.true; }); it('is removed when removing marker', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip', {permanent: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; layer.remove(); expect(map.hasLayer(layer._tooltip)).to.be.false; }); it('is not interactive by default', () => { const layer = new Marker(center).addTo(map); const spy = sinon.spy(); layer.bindTooltip('Tooltip', {permanent: true}); layer._tooltip.on('click', spy); UIEventSimulator.fire('click', layer._tooltip._container); expect(spy.called).to.be.false; }); it('can be made interactive', () => { const layer = new Marker(center).addTo(map); const spy = sinon.spy(); layer.bindTooltip('Tooltip', {permanent: true, interactive: true}); layer._tooltip.on('click', spy); UIEventSimulator.fire('click', layer._tooltip._container); expect(spy.calledOnce).to.be.true; }); it('events are propagated to bound layer', () => { const layer = new Marker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('Tooltip', {permanent: true, interactive: true}); UIEventSimulator.fire('click', layer._tooltip._container); expect(spy.calledOnce).to.be.true; }); it('has class leaflet-interactive', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip', {permanent: true, interactive: true}); expect(layer._tooltip._container.classList.contains('leaflet-interactive')).to.be.true; }); it('has not class leaflet-interactive', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip', {permanent: true}); expect(layer._tooltip._container.classList.contains('leaflet-interactive')).to.be.false; }); it('can be forced on left direction', () => { const layer = new Marker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('A long tooltip that should be displayed on the left', {permanent: true, direction: 'left', interactive: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fireAt('click', 150, 180); // Marker is on the map center, which is 400px large. expect(spy.calledOnce).to.be.true; }); it('honours offset on left direction', () => { const layer = new Marker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('A long tooltip that should be displayed on the left', {permanent: true, direction: 'left', interactive: true, offset: [-20, -20]}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fireAt('click', 150, 180); expect(spy.calledOnce).to.be.false; UIEventSimulator.fireAt('click', 130, 160); expect(spy.calledOnce).to.be.true; }); it('can be forced on top direction', () => { const layer = new CircleMarker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('A tooltip that should be displayed on the top', {permanent: true, direction: 'top', interactive: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fireAt('click', 200, 180); // Marker is on the map center, which is 400px large. expect(spy.calledOnce).to.be.true; }); it('honours offset on top direction', () => { const layer = new CircleMarker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('A tooltip that should be displayed on the top', {permanent: true, direction: 'top', interactive: true, offset: [-20, -20]}); UIEventSimulator.fireAt('click', 200, 180); expect(spy.calledOnce).to.be.false; UIEventSimulator.fireAt('click', 180, 150); expect(spy.calledOnce).to.be.true; }); it('can be forced on bottom direction', () => { const layer = new CircleMarker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('A tooltip that should be displayed on the top', {permanent: true, direction: 'bottom', interactive: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fireAt('click', 200, 220); // Marker is on the map center, which is 400px large. expect(spy.calledOnce).to.be.true; }); it('honours offset on bottom direction', () => { const layer = new CircleMarker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('A tooltip that should be displayed on the top', {permanent: true, direction: 'bottom', interactive: true, offset: [20, 20]}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fireAt('click', 200, 220); expect(spy.calledOnce).to.be.false; UIEventSimulator.fireAt('click', 220, 230); expect(spy.calledOnce).to.be.true; }); it('can be forced on center', () => { const layer = new Marker(center).addTo(map); const spy = sinon.spy(); layer.on('click', spy); layer.bindTooltip('A tooltip that should be displayed on the center', {permanent: true, direction: 'center', interactive: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fireAt('click', 150, 180); // Marker is on the map center, which is 400px large. expect(spy.calledOnce).to.be.true; }); it('honours opacity option', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip', {permanent: true, opacity: 0.57}); expect(layer._tooltip._container.style.opacity).to.eql('0.57'); }); it('can change opacity with setOpacity', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip', {permanent: true}); expect(layer._tooltip._container.style.opacity).to.eql('0.9'); layer._tooltip.setOpacity(0.57); expect(layer._tooltip._container.style.opacity).to.eql('0.57'); }); it('it should use a tooltip with a function as content with a FeatureGroup', () => { const marker1 = new Marker([55.8, 37.6], {description: 'I\'m marker 1.'}); const marker2 = new Marker([54.6, 38.2], {description: 'I\'m marker 2.'}); const group = new FeatureGroup([marker1, marker2]).addTo(map); group.bindTooltip(layer => layer.options.description); // toggle popup on marker1 UIEventSimulator.fire('pointerover', marker1._icon, {relatedTarget: map._container}); expect(map.hasLayer(group._tooltip)).to.be.true; expect(group._tooltip._container.innerHTML).to.equal('I\'m marker 1.'); // toggle popup on marker2 UIEventSimulator.fire('pointerover', marker2._icon, {relatedTarget: map._container}); expect(map.hasLayer(group._tooltip)).to.be.true; expect(group._tooltip._container.innerHTML).to.equal('I\'m marker 2.'); }); it('opens on polygon pointerover and close on pointerout', () => { const layer = new Polygon([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map); layer.bindTooltip('Tooltip'); UIEventSimulator.fire('pointerover', layer._path, {relatedTarget: map._container}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fire('pointerout', layer._path, {relatedTarget: map._container}); expect(map.hasLayer(layer._tooltip)).to.be.false; }); it('stays open on polygon when permanent', () => { const layer = new Polygon([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map); layer.bindTooltip('Tooltip', {permanent: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; }); it('can be added on polygon with bindTooltip before beind added to the map', () => { const layer = new Polygon([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]); layer.bindTooltip('Tooltip', {permanent: true}); expect(map.hasLayer(layer._tooltip)).to.be.false; layer.addTo(map); expect(map.hasLayer(layer._tooltip)).to.be.true; layer.remove(); expect(map.hasLayer(layer._tooltip)).to.be.false; layer.addTo(map); expect(map.hasLayer(layer._tooltip)).to.be.true; }); it('opens on polyline pointerover and close on pointerout', () => { const layer = new Polyline([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map); layer.bindTooltip('Tooltip'); UIEventSimulator.fire('pointerover', layer._path, {relatedTarget: map._container}); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fire('pointerout', layer._path, {relatedTarget: map._container}); expect(map.hasLayer(layer._tooltip)).to.be.false; }); it('stays open on polyline when permanent', () => { const layer = new Polyline([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]).addTo(map); layer.bindTooltip('Tooltip', {permanent: true}); expect(map.hasLayer(layer._tooltip)).to.be.true; }); it('can be added on polyline with bindTooltip before added to the map', () => { const layer = new Polyline([[55.8, 37.6], [55.9, 37.6], [55.8, 37.5]]); layer.bindTooltip('Tooltip', {permanent: true}); expect(map.hasLayer(layer._tooltip)).to.be.false; layer.addTo(map); expect(map.hasLayer(layer._tooltip)).to.be.true; layer.remove(); expect(map.hasLayer(layer._tooltip)).to.be.false; layer.addTo(map); expect(map.hasLayer(layer._tooltip)).to.be.true; }); it.skipIfNotTouch('is opened when tapping on touch', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip'); expect(map.hasLayer(layer._tooltip)).to.be.false; UIEventSimulator.fire('click', layer._icon); expect(map.hasLayer(layer._tooltip)).to.be.true; }); it.skipIfNotTouch('is closed if not permanent when clicking on the map elsewhere on touch', () => { const layer = new Marker(center).addTo(map); layer.bindTooltip('Tooltip'); UIEventSimulator.fire('click', layer._icon); expect(map.hasLayer(layer._tooltip)).to.be.true; UIEventSimulator.fire('click', map._container); expect(map.hasLayer(layer._tooltip)).to.be.false; }); it('opens with map.openTooltip', (done) => { map.on('tooltipopen', (e) => { expect(map.hasLayer(e.tooltip)).to.be.true; done(); }); map.openTooltip('Tooltip', center); }); it('map.openTooltip considers interactive option', () => { const spy = sinon.spy(); const tooltip = new Tooltip({interactive: true, permanent: true}) .setContent('Tooltip') .on('click', spy); map.openTooltip(tooltip, center); UIEventSimulator.fire('click', tooltip._container); expect(spy.calledOnce).to.be.true; }); it('can call closeTooltip while not on the map', () => { const layer = new Marker(center); layer.bindTooltip('Tooltip', {interactive: true}); layer.closeTooltip(); }); it('opens a tooltip and follow the pointer (sticky)', () => { const layer = new Rectangle([[58, 39.7], [54, 35.3]]).addTo(map); layer.bindTooltip('Sticky', {sticky: true}).openTooltip(); const tooltip = layer.getTooltip(); expect(tooltip.getLatLng().equals(layer.getCenter())).to.be.true; UIEventSimulator.fireAt('click', 120, 120); const latlng = map.containerPointToLatLng([120, 120]); expect(tooltip.getLatLng().equals(latlng)).to.be.true; }); it('opens a permanent tooltip and follow the pointer (sticky)', (done) => { const layer = new Rectangle([[58, 39.7], [54, 35.3]]).addTo(map); layer.bindTooltip('Sticky', {sticky: true, permanent: true}).openTooltip(); const tooltip = layer.getTooltip(); expect(tooltip.getLatLng().equals(layer.getCenter())).to.be.true; const hand = new Hand({ timing: 'fastframe', onStop() { const latlng = map.containerPointToLatLng([120, 120]); expect(tooltip.getLatLng().equals(latlng)).to.be.true; done(); } }); const toucher = hand.growFinger('pointer'); toucher.wait(100).moveTo(120, 120, 1000).wait(100); }); it('closes existent tooltip on new bindTooltip call', () => { const layer = new Marker(center).addTo(map); const eventSpy = sinon.spy(layer, 'unbindTooltip'); layer.bindTooltip('Tooltip1', {permanent: true}); const tooltip1 = layer.getTooltip(); layer.bindTooltip('Tooltip2').openTooltip(); layer.unbindTooltip.restore(); // unwrap the spy expect(map.hasLayer(tooltip1)).to.be.false; expect(eventSpy.calledOnce).to.be.true; }); it('don\'t opens the tooltip on marker pointerover while dragging map', (done) => { // Sometimes the pointer is moving faster then the map while dragging and then the marker can be hover and // the tooltip opened / closed. const layer = new Marker(center).addTo(map).bindTooltip('Tooltip'); const tooltip = layer.getTooltip(); // simulate map dragging map.dragging.moving = () => true; UIEventSimulator.fireAt('pointerover', 210, 195); expect(tooltip.isOpen()).to.be.false; // simulate map not dragging anymore map.dragging.moving = () => false; map.on('moveend', () => { expect(tooltip.isOpen()).to.be.false; UIEventSimulator.fireAt('pointerover', 210, 195); expect(tooltip.isOpen()).to.be.true; done(); }); // calls moveend and triggers openTooltip if the layer was added to the map map.setView(map.getCenter()); }); it('closes the tooltip on marker pointerout while dragging map and don\'t open it again', () => { // Sometimes the pointer is moving faster then the map while dragging and then the marker can be hover and // the tooltip opened / closed. const layer = new Marker(center).addTo(map).bindTooltip('Tooltip'); const tooltip = layer.getTooltip(); // open tooltip before "dragging map" UIEventSimulator.fireAt('pointerover', 210, 195); expect(tooltip.isOpen()).to.be.true; // simulate map dragging map.dragging.moving = () => true; UIEventSimulator.fire('pointerout', layer._icon, {relatedTarget: map._container}); expect(tooltip.isOpen()).to.be.false; // tooltip should not open again while dragging UIEventSimulator.fireAt('pointerover', 210, 195); expect(tooltip.isOpen()).to.be.false; }); it('opens the tooltip if the tooltip is loaded while the map is dragging.', () => { // simulate map dragging map.dragging.moving = () => true; // If tooltips are dynamically loaded while the map is dragging, they need // to be loaded when the dragging stops. const layer = new Marker(center).bindTooltip('Tooltip', {permanent: true}); map.addLayer(layer); // simulate map not dragging anymore map.dragging.moving = () => false; // Actually triggers both movestart and moveend. map.setView([51.505, -0.09], 13); // The tooltip is loaded now! expect(map.hasLayer(layer._tooltip)).to.be.true; const tooltip = layer.getTooltip(); expect(tooltip.isOpen()).to.be.true; }); it('opens tooltip with passed latlng position while initializing', () => { const tooltip = new Tooltip(center) .addTo(map); expect(map.hasLayer(tooltip)).to.be.true; }); it('opens tooltip with passed latlng and options position while initializing', () => { const tooltip = new Tooltip(center, {className: 'testClass'}) .addTo(map); expect(map.hasLayer(tooltip)).to.be.true; expect(tooltip.getElement().classList.contains('testClass')).to.be.true; }); it('adds tooltip with passed content in options while initializing', () => { const tooltip = new Tooltip(center, {content: 'Test'}) .addTo(map); expect(map.hasLayer(tooltip)).to.be.true; expect(tooltip.getContent()).to.equal('Test'); }); // Related to #8558 it('references the correct targets in tooltipopen event with multiple markers bound to same tooltip', () => { const marker1 = new Marker(center, {testId: 'markerA'}); const marker2 = new Marker([57.123076977278, 44.861962891635], {testId: 'markerB'}); map.addLayer(marker1); map.addLayer(marker2); const tooltip = new Tooltip().setContent('test'); const layer1 = marker1.bindTooltip(tooltip); const layer2 = marker2.bindTooltip(tooltip); const spy = sinon.spy(); const spy2 = sinon.spy(); layer1.on('tooltipopen', (e) => { spy(); expect(e.target.options.testId).to.eql('markerA'); }); layer2.on('tooltipopen', (e) => { spy2(); expect(e.target.options.testId).to.eql('markerB'); }); expect(spy.called).to.be.false; layer1.openTooltip().closeTooltip(); expect(spy.called).to.be.true; expect(spy2.called).to.be.false; layer2.openTooltip(); expect(spy2.called).to.be.true; }); it('removes focus listeners after unbinding tooltip from Layer', () => { const marker = new Marker([51.515, -0.09]).addTo(map); marker .bindTooltip('Tooltip that will be unbinded') .openTooltip(); expect(marker.getElement()._leaflet_focus_handler).to.be.not.undefined; marker.unbindTooltip(); expect(() => UIEventSimulator.fire('focus', marker.getElement())).to.not.throw(); expect(marker.getElement()._leaflet_focus_handler).to.be.undefined; }); it('removes focus listeners after unbinding tooltip from FeatureGroup', () => { const marker = new Marker([51.515, -0.09]); const layergroup = new FeatureGroup([marker]).addTo(map); layergroup .bindTooltip('Tooltip that will be unbinded in two seconds') .openTooltip(); expect(marker.getElement()._leaflet_focus_handler).to.be.not.undefined; layergroup.unbindTooltip(); expect(() => UIEventSimulator.fire('focus', marker.getElement())).to.not.throw(); expect(marker.getElement()._leaflet_focus_handler).to.be.undefined; }); });