Skip to content

Commit ccf5522

Browse files
chrisgervangclaude
andcommitted
test(mapbox): Add tests for widget support in MapboxOverlay
- Add TestWidget class for testing widget integration - Test regular widgets render in deck container - Test widgets with viewId: 'mapbox' are wrapped as IControl - Test mixed widgets (regular + mapbox) - Test setProps updates widget controls - Test interleaved mode widget support - Update mock map to support control positions and hasControl Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 749433a commit ccf5522

2 files changed

Lines changed: 175 additions & 4 deletions

File tree

test/modules/mapbox/mapbox-gl-mock/map.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,23 @@ export default class Map extends Evented {
8383
return this.projection;
8484
}
8585

86-
addControl(control) {
87-
this._controls.push(control);
86+
addControl(control, position?) {
87+
this._controls.push({
88+
control,
89+
position: position || control.getDefaultPosition?.() || 'top-right'
90+
});
8891
control.onAdd(this);
8992
}
9093
removeControl(control) {
91-
const i = this._controls.indexOf(control);
94+
const i = this._controls.findIndex(c => c.control === control);
9295
if (i >= 0) {
9396
this._controls.splice(i, 1);
9497
control.onRemove(this);
9598
}
9699
}
100+
hasControl(control) {
101+
return this._controls.some(c => c.control === control);
102+
}
97103

98104
loaded() {
99105
return this._loaded;

test/modules/mapbox/mapbox-overlay.spec.ts

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,35 @@ import test from 'tape-promise/tape';
66

77
import {ScatterplotLayer} from '@deck.gl/layers';
88
import {MapboxOverlay} from '@deck.gl/mapbox';
9-
import {_GlobeView as GlobeView, MapView} from '@deck.gl/core';
9+
import {_GlobeView as GlobeView, MapView, Widget} from '@deck.gl/core';
10+
import type {WidgetPlacement} from '@deck.gl/core';
1011

1112
import {objectEqual} from './mapbox-layer.spec';
1213
import MockMapboxMap from './mapbox-gl-mock/map';
1314
import {DEFAULT_PARAMETERS} from './fixtures';
1415

16+
// Simple test widget for testing MapboxOverlay widget support
17+
class TestWidget extends Widget<{placement?: WidgetPlacement; viewId?: string | null}> {
18+
static defaultProps = {
19+
...Widget.defaultProps,
20+
id: 'test-widget',
21+
placement: 'top-left' as WidgetPlacement
22+
};
23+
24+
placement: WidgetPlacement = 'top-left';
25+
className = 'deck-test-widget';
26+
27+
constructor(props: {id?: string; placement?: WidgetPlacement; viewId?: string | null} = {}) {
28+
super(props);
29+
this.viewId = props.viewId ?? null;
30+
this.placement = props.placement ?? 'top-left';
31+
}
32+
33+
onRenderHTML(rootElement: HTMLElement): void {
34+
rootElement.textContent = this.id;
35+
}
36+
}
37+
1538
function sleep(milliseconds: number): Promise<void> {
1639
return new Promise(resolve => {
1740
setTimeout(resolve, milliseconds);
@@ -476,3 +499,145 @@ test('MapboxOverlay#renderLayersInGroups - setProps', t => {
476499
t.end();
477500
});
478501
});
502+
503+
// Widget support tests
504+
505+
test('MapboxOverlay#widgets - regular widgets render in deck container', t => {
506+
const map = new MockMapboxMap({
507+
center: {lng: -122.45, lat: 37.78},
508+
zoom: 14
509+
});
510+
511+
const widget = new TestWidget({id: 'regular-widget', placement: 'top-right'});
512+
const overlay = new MapboxOverlay({
513+
layers: [new ScatterplotLayer()],
514+
widgets: [widget]
515+
});
516+
517+
map.addControl(overlay);
518+
519+
t.ok(overlay._deck, 'Deck instance is created');
520+
t.is(overlay._widgetControls.length, 0, 'No widget controls for regular widgets');
521+
t.ok(overlay._deck.props.widgets.includes(widget), 'Widget is passed to Deck');
522+
523+
map.removeControl(overlay);
524+
t.notOk(overlay._deck, 'Deck instance is finalized');
525+
t.end();
526+
});
527+
528+
test('MapboxOverlay#widgets - viewId:mapbox widgets wrapped as IControl', t => {
529+
const map = new MockMapboxMap({
530+
center: {lng: -122.45, lat: 37.78},
531+
zoom: 14
532+
});
533+
534+
const widget = new TestWidget({id: 'mapbox-widget', viewId: 'mapbox', placement: 'top-right'});
535+
const overlay = new MapboxOverlay({
536+
layers: [new ScatterplotLayer()],
537+
widgets: [widget]
538+
});
539+
540+
map.addControl(overlay);
541+
542+
t.ok(overlay._deck, 'Deck instance is created');
543+
t.is(overlay._widgetControls.length, 1, 'Widget control is created');
544+
t.ok(map.hasControl(overlay._widgetControls[0]), 'Widget control is added to map');
545+
t.ok(widget.props._container, 'Widget _container is set');
546+
t.ok(overlay._deck.props.widgets.includes(widget), 'Widget is still passed to Deck for events');
547+
548+
map.removeControl(overlay);
549+
t.is(overlay._widgetControls.length, 0, 'Widget controls are cleaned up');
550+
t.notOk(overlay._deck, 'Deck instance is finalized');
551+
t.end();
552+
});
553+
554+
test('MapboxOverlay#widgets - mixed widgets', t => {
555+
const map = new MockMapboxMap({
556+
center: {lng: -122.45, lat: 37.78},
557+
zoom: 14
558+
});
559+
560+
const regularWidget = new TestWidget({id: 'regular', placement: 'top-left'});
561+
const mapboxWidget1 = new TestWidget({id: 'mapbox1', viewId: 'mapbox', placement: 'top-right'});
562+
const mapboxWidget2 = new TestWidget({
563+
id: 'mapbox2',
564+
viewId: 'mapbox',
565+
placement: 'bottom-right'
566+
});
567+
568+
const overlay = new MapboxOverlay({
569+
layers: [new ScatterplotLayer()],
570+
widgets: [regularWidget, mapboxWidget1, mapboxWidget2]
571+
});
572+
573+
map.addControl(overlay);
574+
575+
t.ok(overlay._deck, 'Deck instance is created');
576+
t.is(overlay._widgetControls.length, 2, 'Two widget controls for mapbox widgets');
577+
t.notOk(regularWidget.props._container, 'Regular widget _container is not set');
578+
t.ok(mapboxWidget1.props._container, 'Mapbox widget1 _container is set');
579+
t.ok(mapboxWidget2.props._container, 'Mapbox widget2 _container is set');
580+
581+
// All widgets passed to Deck
582+
t.is(overlay._deck.props.widgets.length, 3, 'All widgets passed to Deck');
583+
584+
map.removeControl(overlay);
585+
t.end();
586+
});
587+
588+
test('MapboxOverlay#widgets - setProps updates widget controls', t => {
589+
const map = new MockMapboxMap({
590+
center: {lng: -122.45, lat: 37.78},
591+
zoom: 14
592+
});
593+
594+
const widget1 = new TestWidget({id: 'widget1', viewId: 'mapbox', placement: 'top-right'});
595+
const overlay = new MapboxOverlay({
596+
layers: [new ScatterplotLayer()],
597+
widgets: [widget1]
598+
});
599+
600+
map.addControl(overlay);
601+
t.is(overlay._widgetControls.length, 1, 'Initial widget control created');
602+
603+
const widget2 = new TestWidget({id: 'widget2', viewId: 'mapbox', placement: 'bottom-left'});
604+
overlay.setProps({
605+
widgets: [widget2]
606+
});
607+
608+
t.is(overlay._widgetControls.length, 1, 'Widget control count updated');
609+
t.ok(widget2.props._container, 'New widget _container is set');
610+
611+
// Clear all widgets
612+
overlay.setProps({
613+
widgets: []
614+
});
615+
t.is(overlay._widgetControls.length, 0, 'Widget controls cleared');
616+
617+
map.removeControl(overlay);
618+
t.end();
619+
});
620+
621+
test('MapboxOverlay#widgets - interleaved mode', t => {
622+
const map = new MockMapboxMap({
623+
center: {lng: -122.45, lat: 37.78},
624+
zoom: 14
625+
});
626+
627+
const widget = new TestWidget({id: 'mapbox-widget', viewId: 'mapbox', placement: 'top-right'});
628+
const overlay = new MapboxOverlay({
629+
interleaved: true,
630+
layers: [new ScatterplotLayer()],
631+
widgets: [widget]
632+
});
633+
634+
map.addControl(overlay);
635+
636+
t.ok(overlay._deck, 'Deck instance is created');
637+
t.is(overlay._widgetControls.length, 1, 'Widget control is created in interleaved mode');
638+
t.ok(widget.props._container, 'Widget _container is set');
639+
640+
map.removeControl(overlay);
641+
t.is(overlay._widgetControls.length, 0, 'Widget controls are cleaned up');
642+
t.end();
643+
});

0 commit comments

Comments
 (0)