From 5a3b81446e7d3edaadcc2b591897e4df03ee25da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Mon, 27 Oct 2025 13:25:23 +0200 Subject: [PATCH 01/12] Use dictionary approach to use multiple multiple maps at once. --- .../Components/Pages/Indoor/Index.razor | 2 +- .../Animations/AnimationService.cs | 57 +++-- .../Controls/Control.cs | 1 + .../Controls/FullScreenControl.cs | 9 +- .../Controls/GeolocationControl.cs | 9 +- .../Controls/OverviewMapControl.cs | 2 +- .../Data/BaseSource.cs | 43 ++-- .../Data/DataSource.cs | 6 +- .../Data/Grid/GriddedDataSource.cs | 14 +- .../Drawing/DrawingManager.cs | 17 +- src/AzureMapsControl.Components/Extensions.cs | 15 +- .../Indoor/IIndoorService.cs | 21 +- .../Indoor/IndoorManager.cs | 1 + .../Indoor/IndoorService.cs | 32 ++- .../Layers/Layer.cs | 3 +- .../Map/AzureMap.razor | 242 ++++++++++-------- .../Map/IMapAdderService.cs | 2 + .../Map/IMapService.cs | 19 +- src/AzureMapsControl.Components/Map/Map.cs | 77 ++++-- .../Map/MapService.cs | 60 ++++- .../Markers/HtmlMarker.cs | 3 +- .../Popups/Popup.cs | 11 +- .../typescript/animations/animation.ts | 44 ++-- .../typescript/controls/fullscreen-control.ts | 22 +- .../controls/geolocation-control.ts | 22 +- .../controls/overviewmap-control.ts | 4 +- .../typescript/core/core.ts | 215 +++++++++------- .../typescript/drawing/drawing.ts | 76 ++++-- .../typescript/html-markers/html-marker.ts | 10 +- .../typescript/indoor/indoor.ts | 4 +- .../typescript/layers/layer.ts | 4 +- .../typescript/popups/popup.ts | 22 +- .../typescript/sources/datasource.ts | 12 +- .../typescript/sources/gridded-datasource.ts | 28 +- .../typescript/sources/source.ts | 100 ++++++-- 35 files changed, 770 insertions(+), 439 deletions(-) diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Indoor/Index.razor b/samples/AzureMapsControl.Sample/Components/Pages/Indoor/Index.razor index fc203ad..e1033c0 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Indoor/Index.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Indoor/Index.razor @@ -32,7 +32,7 @@ TilesetId = Configuration["Indoor:TilesetId"] }; - var indoorManager = await IndoorService.CreateIndoorManagerAsync(options, AzureMapsControl.Components.Indoor.IndoorManagerEventActivationFlags.All()); + var indoorManager = await IndoorService.CreateIndoorManagerAsync(eventArgs.Map.Id, options, AzureMapsControl.Components.Indoor.IndoorManagerEventActivationFlags.All()); indoorManager.OnFacilityChanged += eventArgs => { diff --git a/src/AzureMapsControl.Components/Animations/AnimationService.cs b/src/AzureMapsControl.Components/Animations/AnimationService.cs index ba39355..ea422bc 100644 --- a/src/AzureMapsControl.Components/Animations/AnimationService.cs +++ b/src/AzureMapsControl.Components/Animations/AnimationService.cs @@ -39,6 +39,12 @@ public async ValueTask MoveAlongPathAsync(LineString pa Require.NotNull(pin, nameof(pin)); Require.NotNull(pinSource, nameof(pinSource)); + // Ensure both sources belong to the same map + if (pathSource.MapId != pinSource.MapId) + { + throw new ArgumentException("Path source and pin source must belong to the same map"); + } + _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "PathId", path.Id); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "pathSource", pathSource.Id); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "PinId", pin.Id); @@ -46,7 +52,7 @@ public async ValueTask MoveAlongPathAsync(LineString pa _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "Options", options); var animation = new MoveAlongPathAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), animation.Id, path.Id, pathSource.Id, pin.Id, pinSource.Id, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), pathSource.MapId, animation.Id, path.Id, pathSource.Id, pin.Id, pinSource.Id, options); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -59,13 +65,19 @@ public async ValueTask MoveAlongPathAsync(LineString pa Require.NotNull(pathSource, nameof(pathSource)); Require.NotNull(pin, nameof(pin)); + // Ensure path source and marker belong to the same map + if (pathSource.MapId != pin.MapId) + { + throw new ArgumentException("Path source and HTML marker must belong to the same map"); + } + _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "PathId", path.Id); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "PathSource", pathSource.Id); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "PinId", pin.Id); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_MoveAlongPath, "Options", options); var animation = new MoveAlongPathAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), animation.Id, path.Id, pathSource.Id, pin.Id, null, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), pathSource.MapId, animation.Id, path.Id, pathSource.Id, pin.Id, null, options); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -84,7 +96,7 @@ public async ValueTask MoveAlongPathAsync(IEnumerable

MoveAlongPathAsync(IEnumerable

SnakelineAsync(LineString line, Data _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_Snakeline, "Options", options); var animation = new SnakeLineAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Snakeline.ToAnimationNamespace(), animation.Id, line.Id, source.Id, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Snakeline.ToAnimationNamespace(), source.MapId, animation.Id, line.Id, source.Id, options); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -133,7 +145,7 @@ public async ValueTask FlowingDashedLineAsync(LineL _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_FlowingDashedLine, "Options", options); var animation = new FlowingDashedLineAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.FlowingDashedLine.ToAnimationNamespace(), animation.Id, layer.Id, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.FlowingDashedLine.ToAnimationNamespace(), layer.MapId, animation.Id, layer.Id, options); return animation; } @@ -143,14 +155,29 @@ public async ValueTask DropMarkersAsync(IEnumerable m.MapId != mapId)) + { + throw new ArgumentException("All HTML markers must belong to the same map"); + } + _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_DropMarkers, "Markers", markers); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_DropMarkers, "Height", height); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_DropMarkers, "Options", options); - _mapService.Map.HtmlMarkers = (_mapService.Map.HtmlMarkers ?? Array.Empty()).Concat(markers); - var parameters = _mapService.Map.GetHtmlMarkersCreationParameters(markers); + var targetMap = _mapService.GetMap(mapId); + targetMap.HtmlMarkers = (targetMap.HtmlMarkers ?? Array.Empty()).Concat(markers); + + var parameters = targetMap.GetHtmlMarkersCreationParameters(markers); var animation = new DropMarkersAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.DropMarkers.ToAnimationNamespace(), animation.Id, parameters.MarkerOptions, height, options, parameters.InvokeHelper); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.DropMarkers.ToAnimationNamespace(), mapId, animation.Id, parameters.MarkerOptions, height, options, parameters.InvokeHelper); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -190,7 +217,7 @@ public async ValueTask DropAsync(IEnumerable points, Data _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_Drop, "Options", options); var animation = new DropAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Drop.ToAnimationNamespace(), animation.Id, points, source.Id, height, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Drop.ToAnimationNamespace(), source.MapId, animation.Id, points, source.Id, height, options); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -217,7 +244,7 @@ public async ValueTask SetCoordinatesAsync( _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_SetCoordinates, "Options", options); var animation = new SetCoordinatesAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), animation.Id, geometry.Id, source.Id, newCoordinates, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), source.MapId, animation.Id, geometry.Id, source.Id, newCoordinates, options); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -234,7 +261,7 @@ public async ValueTask SetCoordinatesAsync(HtmlMarker _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_SetCoordinates, "Options", options); var animation = new SetCoordinatesAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), animation.Id, marker.Id, null, newCoordinates, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), marker.MapId, animation.Id, marker.Id, null, newCoordinates, options); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -254,7 +281,7 @@ public async ValueTask MorphAsync(Geometry geometry, DataSou _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_SetCoordinates, "Options", options); var animation = new MorphAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Morph.ToAnimationNamespace(), animation.Id, geometry.Id, source.Id, newGeometry, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Morph.ToAnimationNamespace(), source.MapId, animation.Id, geometry.Id, source.Id, newGeometry, options); animation.Disposed = options.DisposeOnComplete.GetValueOrDefault(); return animation; } @@ -273,7 +300,7 @@ public async ValueTask MoveAlongRouteAsync(IEnumerable _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_SetCoordinates, "Options", options); var animation = new MoveAlongRouteAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), animation.Id, points, pinSource.Id, pin.Id, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), pinSource.MapId, animation.Id, points, pinSource.Id, pin.Id, options); return animation; } @@ -289,7 +316,7 @@ public async ValueTask MoveAlongRouteAsync(IEnumerable _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AnimationService_SetCoordinates, "Options", options); var animation = new MoveAlongRouteAnimation(Guid.NewGuid().ToString(), _jsRuntime); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), animation.Id, points, null, pin.Id, options); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), pin.MapId, animation.Id, points, null, pin.Id, options); return animation; } } diff --git a/src/AzureMapsControl.Components/Controls/Control.cs b/src/AzureMapsControl.Components/Controls/Control.cs index 60b5cec..2898bff 100644 --- a/src/AzureMapsControl.Components/Controls/Control.cs +++ b/src/AzureMapsControl.Components/Controls/Control.cs @@ -14,6 +14,7 @@ public abstract class Control internal abstract string Type { get; } internal abstract int Order { get; } internal Guid Id { get; } + internal string MapId { get; set; } ///

/// Position of the control diff --git a/src/AzureMapsControl.Components/Controls/FullScreenControl.cs b/src/AzureMapsControl.Components/Controls/FullScreenControl.cs index d74f800..a81aa7e 100644 --- a/src/AzureMapsControl.Components/Controls/FullScreenControl.cs +++ b/src/AzureMapsControl.Components/Controls/FullScreenControl.cs @@ -61,7 +61,7 @@ public async ValueTask DisposeAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), Id); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), MapId, Id.ToString()); Disposed = true; OnDisposed?.Invoke(); } @@ -88,7 +88,7 @@ public async ValueTask SetOptionsAsync(Action update) update(Options); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), Id, Options); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), MapId, Id.ToString(), Options); } /// @@ -105,7 +105,7 @@ public async ValueTask IsFullScreenAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JsRuntime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), Id); + return await JsRuntime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), MapId, Id.ToString()); } internal async ValueTask AddEventsAsync() @@ -117,7 +117,8 @@ internal async ValueTask AddEventsAsync() Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.FullScreenControl_AddEventsAsync, $"Events: {_eventFlags.EnabledEvents}"); await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.AddEvents.ToFullScreenControlNamespace(), - Id, + MapId, + Id.ToString(), _eventFlags.EnabledEvents, DotNetObjectReference.Create(_eventInvokeHelper)); } diff --git a/src/AzureMapsControl.Components/Controls/GeolocationControl.cs b/src/AzureMapsControl.Components/Controls/GeolocationControl.cs index a71056c..f599bb9 100644 --- a/src/AzureMapsControl.Components/Controls/GeolocationControl.cs +++ b/src/AzureMapsControl.Components/Controls/GeolocationControl.cs @@ -58,7 +58,7 @@ public async ValueTask> GetLastKnownPositionAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JsRuntime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), Id); + return await JsRuntime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), MapId, Id.ToString()); } /// @@ -75,7 +75,7 @@ public async ValueTask DisposeAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), Id); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), MapId, Id.ToString()); Disposed = true; OnDisposed?.Invoke(); } @@ -102,7 +102,7 @@ public async ValueTask SetOptionsAsync(Action update) update(Options); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), Id, Options); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), MapId, Id.ToString(), Options); } internal async ValueTask AddEventsAsync() @@ -114,7 +114,8 @@ internal async ValueTask AddEventsAsync() Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.GeolocationControl_AddEventsAsync, $"Events: {_eventFlags.EnabledEvents}"); await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.AddEvents.ToGeolocationControlNamespace(), - Id, + MapId, + Id.ToString(), _eventFlags.EnabledEvents, DotNetObjectReference.Create(_eventInvokeHelper)); } diff --git a/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs b/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs index 6f87f85..2e59c66 100644 --- a/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs +++ b/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs @@ -58,7 +58,7 @@ public async ValueTask SetOptionsAsync(Action update) Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.OverviewMapControl_UpdateAsync, $"Id: {Id}"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.OverviewMapControl_UpdateAsync, $"Type: {Type}"); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), Id, Options); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), MapId, Id.ToString(), Options); } } diff --git a/src/AzureMapsControl.Components/Data/BaseSource.cs b/src/AzureMapsControl.Components/Data/BaseSource.cs index eb26b17..c91531b 100644 --- a/src/AzureMapsControl.Components/Data/BaseSource.cs +++ b/src/AzureMapsControl.Components/Data/BaseSource.cs @@ -19,6 +19,7 @@ internal ILogger Logger { get; set; } internal IMapJsRuntime JSRuntime { get; set; } + internal string MapId { get; set; } public bool Disposed { get; private set; } @@ -53,7 +54,7 @@ public async ValueTask AddAsync(JsonDocument json) EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatureCollection.ToSourceNamespace(), Id, json); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatureCollection.ToSourceNamespace(), MapId, Id, json); } /// @@ -87,7 +88,7 @@ public async ValueTask RemoveAsync(IEnumerable ids) Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Source_RemoveAsync, "Removing geometries from data source"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_RemoveAsync, $"Id: {Id} | Ids: {string.Join('|', ids)}"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), Id, ids); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), MapId, Id, ids); } } @@ -177,7 +178,7 @@ public async ValueTask ImportDataFromUrlAsync(string url) EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.ImportDataFromUrl.ToSourceNamespace(), Id, url); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.ImportDataFromUrl.ToSourceNamespace(), MapId, Id, url); } /// @@ -196,7 +197,7 @@ public async ValueTask ClearAsync() _shapes = null; _features = null; - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToSourceNamespace(), Id); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToSourceNamespace(), MapId, Id); } /// @@ -213,7 +214,7 @@ public async ValueTask DisposeAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), Id); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), MapId, Id); Disposed = true; } @@ -231,7 +232,7 @@ public async ValueTask GetOptionsAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - Options = await JSRuntime.InvokeAsync(Constants.JsConstants.Methods.Source.GetOptions.ToSourceNamespace(), Id); + Options = await JSRuntime.InvokeAsync(Constants.JsConstants.Methods.Source.GetOptions.ToSourceNamespace(), MapId, Id); return Options; } @@ -255,7 +256,7 @@ public async ValueTask SetOptionsAsync(Action update) update(Options); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), Id, Options); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), MapId, Id, Options); } /// @@ -285,49 +286,49 @@ protected async ValueTask AddShapesAsync(IEnumerable shapes) if (lineStrings.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{lineStrings.Count()} linestrings will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), Id, lineStrings); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), MapId, Id, lineStrings); } var multiLineStrings = shapes.OfType>(); if (multiLineStrings.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiLineStrings.Count()} multilinestrings will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), Id, multiLineStrings); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), MapId, Id, multiLineStrings); } var multiPoints = shapes.OfType>(); if (multiPoints.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPoints.Count()} multipoints will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), Id, multiPoints); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), MapId, Id, multiPoints); } var multiPolygons = shapes.OfType>(); if (multiPolygons.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPolygons.Count()} multipolygons will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), Id, multiPolygons); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), MapId, Id, multiPolygons); } var points = shapes.OfType>(); if (points.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{points.Count()} points will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), Id, points); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), MapId, Id, points); } var polygons = shapes.OfType>(); if (polygons.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{polygons.Count()} polygons will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), Id, polygons); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), MapId, Id, polygons); } var routePoints = shapes.OfType>(); if (routePoints.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{routePoints.Count()} route points will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), Id, routePoints); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), MapId, Id, routePoints); } _shapes.AddRange(shapes); @@ -360,49 +361,49 @@ protected async ValueTask AddFeaturesAsync(IEnumerable features) if (lineStrings.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{lineStrings.Count()} linestrings will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), Id, lineStrings); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), MapId, Id, lineStrings); } var multiLineStrings = features.OfType>(); if (multiLineStrings.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiLineStrings.Count()} multilinestrings will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), Id, multiLineStrings); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), MapId, Id, multiLineStrings); } var multiPoints = features.OfType>(); if (multiPoints.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPoints.Count()} multipoints will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), Id, multiPoints); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), MapId, Id, multiPoints); } var multiPolygons = features.OfType>(); if (multiPolygons.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPolygons.Count()} multipolygons will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), Id, multiPolygons); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), MapId, Id, multiPolygons); } var points = features.OfType>(); if (points.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{points.Count()} points will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), Id, points); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), MapId, Id, points); } var polygons = features.OfType>(); if (polygons.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{polygons.Count()} polygons will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), Id, polygons); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), MapId, Id, polygons); } var routePoints = features.OfType>(); if (routePoints.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{routePoints.Count()} route points will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), Id, routePoints); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), MapId, Id, routePoints); } _features.AddRange(features); diff --git a/src/AzureMapsControl.Components/Data/DataSource.cs b/src/AzureMapsControl.Components/Data/DataSource.cs index f096b6c..8be758e 100644 --- a/src/AzureMapsControl.Components/Data/DataSource.cs +++ b/src/AzureMapsControl.Components/Data/DataSource.cs @@ -89,7 +89,7 @@ public async ValueTask>> GetShapesAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetShapes.ToDatasourceNamespace(), Id); + return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetShapes.ToDatasourceNamespace(), MapId, Id); } /// @@ -110,7 +110,7 @@ public async ValueTask>> GetClusterLeavesAsync(int EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetClusterLeaves.ToDatasourceNamespace(), Id, clusterId, limit, offset); + return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetClusterLeaves.ToDatasourceNamespace(), MapId, Id, clusterId, limit, offset); } /// @@ -127,7 +127,7 @@ public async ValueTask GetClusterExpansionZoomAsync(int clusterId) EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JSRuntime.InvokeAsync(Constants.JsConstants.Methods.Datasource.GetClusterExpansionZoom.ToDatasourceNamespace(), Id, clusterId); + return await JSRuntime.InvokeAsync(Constants.JsConstants.Methods.Datasource.GetClusterExpansionZoom.ToDatasourceNamespace(), MapId, Id, clusterId); } internal void DispatchEvent(DataSourceEventArgs eventArgs) diff --git a/src/AzureMapsControl.Components/Data/Grid/GriddedDataSource.cs b/src/AzureMapsControl.Components/Data/Grid/GriddedDataSource.cs index 3e9bd29..dcc106c 100644 --- a/src/AzureMapsControl.Components/Data/Grid/GriddedDataSource.cs +++ b/src/AzureMapsControl.Components/Data/Grid/GriddedDataSource.cs @@ -79,7 +79,7 @@ public async ValueTask>> GetCellChildrenAsync(string EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetCellChildren.ToGriddedDatasourceNamespace(), Id, cellId); + return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetCellChildren.ToGriddedDatasourceNamespace(), MapId, Id, cellId); } /// @@ -96,7 +96,7 @@ public async ValueTask>> GetGridCellsAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetGridCells.ToGriddedDatasourceNamespace(), Id); + return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetGridCells.ToGriddedDatasourceNamespace(), MapId, Id); } /// @@ -113,7 +113,7 @@ public async ValueTask>> GetPointsAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetPoints.ToGriddedDatasourceNamespace(), Id); + return await JSRuntime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetPoints.ToGriddedDatasourceNamespace(), MapId, Id); } /// @@ -131,7 +131,7 @@ public async ValueTask SetPointsAsync(JsonDocument featureCollection) EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeatureCollectionPoints.ToGriddedDatasourceNamespace(), Id, featureCollection); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeatureCollectionPoints.ToGriddedDatasourceNamespace(), MapId, Id, featureCollection); } /// @@ -149,7 +149,7 @@ public async ValueTask SetPointsAsync(IEnumerable> features) EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeaturePoints.ToGriddedDatasourceNamespace(), Id, features); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeaturePoints.ToGriddedDatasourceNamespace(), MapId, Id, features); } /// @@ -167,7 +167,7 @@ public async ValueTask SetPointsAsync(IEnumerable points) EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetPoints.ToGriddedDatasourceNamespace(), Id, points); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetPoints.ToGriddedDatasourceNamespace(), MapId, Id, points); } /// @@ -185,7 +185,7 @@ public async ValueTask SetPointsAsync(IEnumerable> shapes) EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetShapePoints.ToGriddedDatasourceNamespace(), Id, shapes); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetShapePoints.ToGriddedDatasourceNamespace(), MapId, Id, shapes); } } } diff --git a/src/AzureMapsControl.Components/Drawing/DrawingManager.cs b/src/AzureMapsControl.Components/Drawing/DrawingManager.cs index 1fe6879..b473851 100644 --- a/src/AzureMapsControl.Components/Drawing/DrawingManager.cs +++ b/src/AzureMapsControl.Components/Drawing/DrawingManager.cs @@ -18,6 +18,7 @@ public sealed class DrawingManager { internal IMapJsRuntime JSRuntime { get; set; } internal ILogger Logger { get; set; } + internal string MapId { get; set; } public bool Disposed { get; private set; } /// @@ -51,49 +52,49 @@ public async ValueTask AddShapesAsync(IEnumerable shapes) if (lineStrings.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{lineStrings.Count()} linestrings will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), lineStrings); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), MapId, lineStrings); } var multiLineStrings = shapes.OfType>(); if (multiLineStrings.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiLineStrings.Count()} multilinestrings will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), multiLineStrings); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), MapId, multiLineStrings); } var multiPoints = shapes.OfType>(); if (multiPoints.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPoints.Count()} multipoints will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), multiPoints); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), MapId, multiPoints); } var multiPolygons = shapes.OfType>(); if (multiPolygons.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPolygons.Count()} multipolygons will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), multiPolygons); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), MapId, multiPolygons); } var points = shapes.OfType>(); if (points.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{points.Count()} points will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), points); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), MapId, points); } var polygons = shapes.OfType>(); if (polygons.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{polygons.Count()} polygons will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), polygons); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), MapId, polygons); } var routePoints = shapes.OfType>(); if (routePoints.Any()) { Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{routePoints.Count()} route points will be added"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), routePoints); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), MapId, routePoints); } _sourceShapes.AddRange(shapes); @@ -113,7 +114,7 @@ public async ValueTask ClearAsync() EnsureNotDisposed(); _sourceShapes = null; - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToDrawingNamespace()); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToDrawingNamespace(), MapId); } /// diff --git a/src/AzureMapsControl.Components/Extensions.cs b/src/AzureMapsControl.Components/Extensions.cs index 635691e..b8267dc 100644 --- a/src/AzureMapsControl.Components/Extensions.cs +++ b/src/AzureMapsControl.Components/Extensions.cs @@ -23,7 +23,7 @@ public static class Extensions /// Configuration /// Services [ExcludeFromCodeCoverage] - public static IServiceCollection AddAzureMapsControl(this IServiceCollection services, Action configure) + public static IServiceCollection AddAzureMapsControl(this IServiceCollection services, Action configure = null) { services .AddScoped() @@ -33,10 +33,15 @@ public static IServiceCollection AddAzureMapsControl(this IServiceCollection ser .AddScoped() .AddScoped() .AddScoped() - .AddScoped() - .AddOptions() - .Configure(configure) - .Validate(configuration => configuration.Validate(), "The given AzureMapsConfiguration is invalid"); + .AddScoped(); + + if (configure != null) + { + services + .AddOptions() + .Configure(configure) + .Validate(configuration => configuration.Validate(), "The given AzureMapsConfiguration is invalid"); + } return services; } diff --git a/src/AzureMapsControl.Components/Indoor/IIndoorService.cs b/src/AzureMapsControl.Components/Indoor/IIndoorService.cs index d3f2c04..c3ac8a9 100644 --- a/src/AzureMapsControl.Components/Indoor/IIndoorService.cs +++ b/src/AzureMapsControl.Components/Indoor/IIndoorService.cs @@ -7,16 +7,35 @@ public interface IIndoorService /// /// Create an instance of IndoorManager /// + /// ID of the map to associate the indoor manager with /// Options of the indoor manager /// Indoor Manager - ValueTask CreateIndoorManagerAsync(IndoorManagerOptions options); + ValueTask CreateIndoorManagerAsync(string mapId, IndoorManagerOptions options); /// /// Create an instance of IndoorManager /// + /// ID of the map to associate the indoor manager with + /// Options of the indoor manager + /// Events which will be triggered by the IndoorManager + /// Indoor Manager + ValueTask CreateIndoorManagerAsync(string mapId, IndoorManagerOptions options, IndoorManagerEventActivationFlags eventFlags); + + /// + /// Create an instance of IndoorManager (legacy method for backward compatibility) + /// + /// Options of the indoor manager + /// Indoor Manager + [System.Obsolete("Use CreateIndoorManagerAsync(mapId, options) instead for multi-map support")] + ValueTask CreateIndoorManagerAsync(IndoorManagerOptions options); + + /// + /// Create an instance of IndoorManager (legacy method for backward compatibility) + /// /// Options of the indoor manager /// Events which will be triggered by the IndoorManager /// Indoor Manager + [System.Obsolete("Use CreateIndoorManagerAsync(mapId, options, eventFlags) instead for multi-map support")] ValueTask CreateIndoorManagerAsync(IndoorManagerOptions options, IndoorManagerEventActivationFlags eventFlags); } } diff --git a/src/AzureMapsControl.Components/Indoor/IndoorManager.cs b/src/AzureMapsControl.Components/Indoor/IndoorManager.cs index 1d0d009..9191392 100644 --- a/src/AzureMapsControl.Components/Indoor/IndoorManager.cs +++ b/src/AzureMapsControl.Components/Indoor/IndoorManager.cs @@ -20,6 +20,7 @@ public sealed class IndoorManager private readonly IndoorManagerEventHelper _eventHelper; public bool Disposed { get; private set; } + internal string MapId { get; set; } internal IndoorManagerEventHelper EventHelper => _eventHelper; diff --git a/src/AzureMapsControl.Components/Indoor/IndoorService.cs b/src/AzureMapsControl.Components/Indoor/IndoorService.cs index c6712e0..af199c3 100644 --- a/src/AzureMapsControl.Components/Indoor/IndoorService.cs +++ b/src/AzureMapsControl.Components/Indoor/IndoorService.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using AzureMapsControl.Components.Logger; + using AzureMapsControl.Components.Map; using AzureMapsControl.Components.Runtime; using Microsoft.Extensions.Logging; @@ -12,24 +13,45 @@ internal class IndoorService : IIndoorService { private readonly IMapJsRuntime _jsRuntime; private readonly ILogger _logger; + private readonly IMapService _mapService; - public IndoorService(IMapJsRuntime jsRuntime, ILogger logger) + public IndoorService(IMapJsRuntime jsRuntime, ILogger logger, IMapService mapService) { _jsRuntime = jsRuntime; _logger = logger; + _mapService = mapService; } - public async ValueTask CreateIndoorManagerAsync(IndoorManagerOptions options) => await CreateIndoorManagerAsync(options, null); + public async ValueTask CreateIndoorManagerAsync(string mapId, IndoorManagerOptions options) => await CreateIndoorManagerAsync(mapId, options, null); - public async ValueTask CreateIndoorManagerAsync(IndoorManagerOptions options, IndoorManagerEventActivationFlags eventFlags) + public async ValueTask CreateIndoorManagerAsync(string mapId, IndoorManagerOptions options, IndoorManagerEventActivationFlags eventFlags) { _logger.LogAzureMapsControlInfo(AzureMapLogEvent.IndoorService_CreateIndoorManagerAsync, "IndoorService - CreateIndoorManagerAsync"); + _logger.LogAzureMapsControlDebug(AzureMapLogEvent.IndoorService_CreateIndoorManagerAsync, "MapId", mapId); _logger.LogAzureMapsControlDebug(AzureMapLogEvent.IndoorService_CreateIndoorManagerAsync, "Options", options); _logger.LogAzureMapsControlDebug(AzureMapLogEvent.IndoorService_CreateIndoorManagerAsync, "EventFlags", eventFlags); - var indoorManager = new IndoorManager(_jsRuntime, _logger); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), indoorManager.Id, options, eventFlags?.EnabledEvents, DotNetObjectReference.Create(indoorManager.EventHelper)); + var indoorManager = new IndoorManager(_jsRuntime, _logger) { + MapId = mapId + }; + + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), mapId, indoorManager.Id, options, eventFlags?.EnabledEvents, DotNetObjectReference.Create(indoorManager.EventHelper)); return indoorManager; } + + // Legacy methods for backward compatibility + [System.Obsolete("Use CreateIndoorManagerAsync(mapId, options) instead for multi-map support")] + public async ValueTask CreateIndoorManagerAsync(IndoorManagerOptions options) { + // Get the current map ID from MapService instead of using hardcoded "default" + var mapId = _mapService.Map?.Id ?? "default"; + return await CreateIndoorManagerAsync(mapId, options, null); + } + + [System.Obsolete("Use CreateIndoorManagerAsync(mapId, options, eventFlags) instead for multi-map support")] + public async ValueTask CreateIndoorManagerAsync(IndoorManagerOptions options, IndoorManagerEventActivationFlags eventFlags) { + // Get the current map ID from MapService instead of using hardcoded "default" + var mapId = _mapService.Map?.Id ?? "default"; + return await CreateIndoorManagerAsync(mapId, options, eventFlags); + } } } diff --git a/src/AzureMapsControl.Components/Layers/Layer.cs b/src/AzureMapsControl.Components/Layers/Layer.cs index a0824dd..d2b8f9e 100644 --- a/src/AzureMapsControl.Components/Layers/Layer.cs +++ b/src/AzureMapsControl.Components/Layers/Layer.cs @@ -20,6 +20,7 @@ public abstract class Layer public LayerEventActivationFlags EventActivationFlags { get; set; } internal LayerType Type { get; private set; } + internal string MapId { get; set; } public event LayerMouseEvent OnClick; public event LayerMouseEvent OnContextMenu; @@ -156,7 +157,7 @@ public async ValueTask SetOptionsAsync(Action update) update(Options); - await _mapJsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Layer.SetOptions.ToLayerNamespace(), Id, Options); + await _mapJsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Layer.SetOptions.ToLayerNamespace(), MapId, Id, Options); } internal override LayerOptions GetLayerOptions() => Options; diff --git a/src/AzureMapsControl.Components/Map/AzureMap.razor b/src/AzureMapsControl.Components/Map/AzureMap.razor index e8a68e6..5575571 100644 --- a/src/AzureMapsControl.Components/Map/AzureMap.razor +++ b/src/AzureMapsControl.Components/Map/AzureMap.razor @@ -1,4 +1,5 @@ @namespace AzureMapsControl.Components.Map +@implements IAsyncDisposable @using AzureMapsControl.Components.Atlas @using AzureMapsControl.Components.Configuration @@ -8,7 +9,7 @@ @using Microsoft.JSInterop @using Microsoft.Extensions.Options -@inject IOptions Configuration +@inject IOptions GlobalConfiguration @inject IMapAdderService MapService @inject IMapJsRuntime JSRuntime @inject Microsoft.Extensions.Logging.ILogger Logger @@ -20,13 +21,18 @@ #region Fields private MapEventInvokeHelper _mapEventInvokeHelper; - private string _id; #endregion #region Parameters + /// + /// Azure Maps configuration options for this map instance. + /// + [Parameter] + public AzureMapsConfiguration Configuration { get; set; } + /// /// The options for setting the map control's camera. /// @@ -420,15 +426,23 @@ Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_OnInitialized, "AzureMap - OnAfterRenderAsync", firstRender); if (firstRender) { + // Use the Configuration parameter if provided, otherwise fall back to GlobalConfiguration + var mapConfiguration = Configuration ?? GlobalConfiguration?.Value; + + if (mapConfiguration == null) + { + throw new InvalidOperationException("Configuration parameter is required. Please provide an AzureMapsConfiguration instance either via the Configuration parameter or GlobalConfiguration."); + } + var enabledEvents = (EventActivationFlags ?? MapEventActivationFlags.None().Enable(MapEventType.Ready)).EnabledEvents; Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_OnInitialized, $"Adding map"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_OnInitialized, $"Id: {Id}"); - Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_OnInitialized, $"AuthType: {Configuration.Value.AuthType}"); - Logger?.LogAzureMapsControlTrace(AzureMapLogEvent.AzureMap_OnInitialized, $"AadAppId: {Configuration.Value.AadAppId} | AadTenant: {Configuration.Value.AadTenant} | ClientId: {Configuration.Value.ClientId} | SubscriptionKey: {Configuration.Value.SubscriptionKey}"); + Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_OnInitialized, $"AuthType: {mapConfiguration.AuthType}"); + Logger?.LogAzureMapsControlTrace(AzureMapLogEvent.AzureMap_OnInitialized, $"AadAppId: {mapConfiguration.AadAppId} | AadTenant: {mapConfiguration.AadTenant} | ClientId: {mapConfiguration.ClientId} | SubscriptionKey: {mapConfiguration.SubscriptionKey}"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_OnInitialized, $"Events: {string.Join('|', enabledEvents)}"); await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddMap.ToCoreNamespace(), Id, - Configuration.Value, + mapConfiguration, ServiceOptions, enabledEvents, DotNetObjectReference.Create(_mapEventInvokeHelper)); @@ -436,41 +450,54 @@ await base.OnAfterRenderAsync(firstRender); } + public async ValueTask DisposeAsync() + { + var map = MapService.GetMap(Id); + if (map != null) + { + await MapService.RemoveMapAsync(map.Id); + } + } + #endregion #region Drawing Toolbar private async ValueTask DrawingToolbarEventReceivedAsync(AzureMapsControl.Components.Drawing.DrawingToolbarJsEventArgs drawingToolbarEvent) { + var map = MapService.GetMap(Id); Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Received drawing toolbar event"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, $"Type: {drawingToolbarEvent.Type}"); - MapService.Map.DispatchDrawingToolbarEvent(drawingToolbarEvent); - switch (drawingToolbarEvent.Type) + if (map != null) { - case "drawingchanged": - Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingChanged"); - await OnDrawingChanged.InvokeAsync(new Drawing.DrawingToolbarEventArgs(MapService.Map, drawingToolbarEvent)); - break; - - case "drawingchanging": - Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingChanging"); - await OnDrawingChanging.InvokeAsync(new Drawing.DrawingToolbarEventArgs(MapService.Map, drawingToolbarEvent)); - break; - - case "drawingcomplete": - Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingComplete"); - await OnDrawingComplete.InvokeAsync(new Drawing.DrawingToolbarEventArgs(MapService.Map, drawingToolbarEvent)); - break; - - case "drawingmodechanged": - Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingModeChanged"); - await OnDrawingModeChanged.InvokeAsync(new Drawing.DrawingToolbarModeEventArgs(MapService.Map, drawingToolbarEvent)); - break; - - case "drawingstarted": - Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingStarted"); - await OnDrawingStarted.InvokeAsync(new MapEventArgs(MapService.Map, drawingToolbarEvent.Type)); - break; + map.DispatchDrawingToolbarEvent(drawingToolbarEvent); + switch (drawingToolbarEvent.Type) + { + case "drawingchanged": + Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingChanged"); + await OnDrawingChanged.InvokeAsync(new Drawing.DrawingToolbarEventArgs(map, drawingToolbarEvent)); + break; + + case "drawingchanging": + Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingChanging"); + await OnDrawingChanging.InvokeAsync(new Drawing.DrawingToolbarEventArgs(map, drawingToolbarEvent)); + break; + + case "drawingcomplete": + Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingComplete"); + await OnDrawingComplete.InvokeAsync(new Drawing.DrawingToolbarEventArgs(map, drawingToolbarEvent)); + break; + + case "drawingmodechanged": + Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingModeChanged"); + await OnDrawingModeChanged.InvokeAsync(new Drawing.DrawingToolbarModeEventArgs(map, drawingToolbarEvent)); + break; + + case "drawingstarted": + Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DrawingToolbarEvent, "Emitting OnDrawingStarted"); + await OnDrawingStarted.InvokeAsync(new MapEventArgs(map, drawingToolbarEvent.Type)); + break; + } } } @@ -480,18 +507,19 @@ private async ValueTask HtmlMarkerEventReceivedAsync(AzureMapsControl.Components.Markers.HtmlMarkerJsEventArgs htmlMarkerEvent) { + var map = MapService.GetMap(Id); Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_HtmlMarkerEventReceivedAsync, "Received html marker event"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_HtmlMarkerEventReceivedAsync, $"Id: {htmlMarkerEvent.MarkerId} | Type: {htmlMarkerEvent.Type}"); - if (MapService.Map.HtmlMarkers != null) + if (map?.HtmlMarkers != null) { - var htmlMarker = MapService.Map.HtmlMarkers.First(marker => marker.Id == htmlMarkerEvent.MarkerId); + var htmlMarker = map.HtmlMarkers.First(marker => marker.Id == htmlMarkerEvent.MarkerId); if (htmlMarker != null) { await Task.Run(() => { Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_HtmlMarkerEventReceivedAsync, "Dispatching html marker event"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_HtmlMarkerEventReceivedAsync, $"Id: {htmlMarkerEvent.MarkerId} | Type: {htmlMarkerEvent.Type}"); - htmlMarker.DispatchEvent(MapService.Map, htmlMarkerEvent); + htmlMarker.DispatchEvent(map, htmlMarkerEvent); }); } } @@ -503,15 +531,16 @@ private async ValueTask LayerEventReceivedAsync(MapJsEventArgs eventArgs) { + var map = MapService.GetMap(Id); Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_LayerEventReceivedAsync, "Layer event received"); - var layer = MapService.Map.Layers.FirstOrDefault(l => l.Id == eventArgs.LayerId); + var layer = map?.Layers?.FirstOrDefault(l => l.Id == eventArgs.LayerId); if (layer != null) { await Task.Run(() => { Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_LayerEventReceivedAsync, "Dispatching layer event"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_LayerEventReceivedAsync, $"Id: {layer.Id} | Type: {eventArgs.Type}"); - layer.DispatchEvent(MapService.Map, eventArgs); + layer.DispatchEvent(map, eventArgs); }); } } @@ -528,12 +557,13 @@ { Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Setting map options"); await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetOptions.ToCoreNamespace(), + Id, CameraOptions, StyleOptions, UserInteractionOptions, TrafficOptions); - await MapService.AddMapAsync(new Map(Id, + var map = new Map(Id, JSRuntime, Logger, new Drawing.DrawingToolbarEventInvokeHelper(DrawingToolbarEventReceivedAsync), @@ -548,204 +578,208 @@ StyleOptions = StyleOptions, UserInteractionOptions = UserInteractionOptions, TrafficOptions = TrafficOptions - }); + }; + + await MapService.AddMapAsync(map); - await MapService.Map.AddControlsAsync(Controls); - await MapService.Map.AddHtmlMarkersAsync(HtmlMarkers); - await MapService.Map.AddDrawingToolbarAsync(DrawingToolbarOptions); + await map.AddControlsAsync(Controls); + await map.AddHtmlMarkersAsync(HtmlMarkers); + await map.AddDrawingToolbarAsync(DrawingToolbarOptions); + } await DispatchMapEventAsync(mapEvent); } private async ValueTask DispatchMapEventAsync(MapJsEventArgs mapEvent) { + var map = MapService.GetMap(Id); if (EventActivationFlags != null && EventActivationFlags.EnabledEvents != null && EventActivationFlags.EnabledEvents.Contains(mapEvent.Type) - && MapService.Map is not null) + && map is not null) { - MapService.Map.DispatchEvent(mapEvent); + map.DispatchEvent(mapEvent); switch (mapEvent.Type) { case "boxzoomend": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnBoxZoomEnd"); - await OnBoxZoomEnd.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnBoxZoomEnd.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "boxzoomstart": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnBoxZoomStart"); - await OnBoxZoomStart.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnBoxZoomStart.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "click": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnClick"); - await OnClick.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnClick.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "contextmenu": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnContextMenu"); - await OnContextMenu.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnContextMenu.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "data": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnData"); - await OnData.InvokeAsync(new MapDataEventArgs(MapService.Map, mapEvent)); + await OnData.InvokeAsync(new MapDataEventArgs(map, mapEvent)); break; case "dblclick": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnDblClick"); - await OnDblClick.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnDblClick.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "drag": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnDrag"); - await OnDrag.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnDrag.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "dragend": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnDragEnd"); - await OnDragEnd.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnDragEnd.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "dragstart": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnDragStart"); - await OnDragStart.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnDragStart.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "error": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnError"); - await OnError.InvokeAsync(new MapErrorEventArgs(MapService.Map, mapEvent)); + await OnError.InvokeAsync(new MapErrorEventArgs(map, mapEvent)); break; case "idle": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnIdle"); - await OnIdle.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnIdle.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "layeradded": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnLayerAdded"); - await OnLayerAdded.InvokeAsync(new MapLayerEventArgs(MapService.Map, mapEvent)); + await OnLayerAdded.InvokeAsync(new MapLayerEventArgs(map, mapEvent)); break; case "layerremoved": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnLayerRemoved"); - await OnLayerRemoved.InvokeAsync(new MapLayerEventArgs(MapService.Map, mapEvent)); + await OnLayerRemoved.InvokeAsync(new MapLayerEventArgs(map, mapEvent)); break; case "load": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnLoad"); - await OnLoad.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnLoad.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "mousedown": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMouseDown"); - await OnMouseDown.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnMouseDown.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "mousemove": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMouseMove"); - await OnMouseMove.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnMouseMove.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "mouseout": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMouseOut"); - await OnMouseOut.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnMouseOut.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "mouseover": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMouseOver"); - await OnMouseOver.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnMouseOver.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "mouseup": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMouseUp"); - await OnMouseUp.InvokeAsync(new MapMouseEventArgs(MapService.Map, mapEvent)); + await OnMouseUp.InvokeAsync(new MapMouseEventArgs(map, mapEvent)); break; case "move": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMove"); - await OnMove.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnMove.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "moveend": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMoveEnd"); - await OnMoveEnd.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnMoveEnd.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "movestart": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnMoveStart"); - await OnMoveStart.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnMoveStart.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "pitch": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnPitch"); - await OnPitch.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnPitch.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "pitchend": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnPitchEnd"); - await OnPitchEnd.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnPitchEnd.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "pitchstart": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnPitchStart"); - await OnPitchStart.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnPitchStart.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "ready": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnReady"); - await OnReady.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnReady.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "render": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnRender"); - await OnRender.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnRender.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "resize": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnResize"); - await OnResize.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnResize.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "rotate": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnRotate"); - await OnRotate.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnRotate.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "rotateend": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnRotateEnd"); - await OnRotateEnd.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnRotateEnd.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "rotatestart": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnRotateStart"); - await OnRotateStart.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnRotateStart.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "sourceadded": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnSourceAdded"); - await OnSourceAdded.InvokeAsync(new MapSourceEventArgs(MapService.Map, mapEvent)); + await OnSourceAdded.InvokeAsync(new MapSourceEventArgs(map, mapEvent)); break; case "sourcedata": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnSourceData"); - await OnSourceData.InvokeAsync(new MapDataEventArgs(MapService.Map, mapEvent)); + await OnSourceData.InvokeAsync(new MapDataEventArgs(map, mapEvent)); break; case "sourceremoved": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnSourceRemoved"); - await OnSourceRemoved.InvokeAsync(new MapSourceEventArgs(MapService.Map, mapEvent)); + await OnSourceRemoved.InvokeAsync(new MapSourceEventArgs(map, mapEvent)); break; case "styledata": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnStyleData"); - await OnStyleData.InvokeAsync(new MapStyleDataEventArgs(MapService.Map, mapEvent)); + await OnStyleData.InvokeAsync(new MapStyleDataEventArgs(map, mapEvent)); break; case "styleimagemissing": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnStyleImageMissing"); - await OnStyleImageMissing.InvokeAsync(new MapMessageEventArgs(MapService.Map, mapEvent)); + await OnStyleImageMissing.InvokeAsync(new MapMessageEventArgs(map, mapEvent)); break; case "tokenacquired": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnTokenAcquired"); - await OnTokenAcquired.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnTokenAcquired.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "touchcancel": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnTouchCancel"); - await OnTouchCancel.InvokeAsync(new MapTouchEventArgs(MapService.Map, mapEvent)); + await OnTouchCancel.InvokeAsync(new MapTouchEventArgs(map, mapEvent)); break; case "touchend": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnTouchEnd"); - await OnTouchEnd.InvokeAsync(new MapTouchEventArgs(MapService.Map, mapEvent)); + await OnTouchEnd.InvokeAsync(new MapTouchEventArgs(map, mapEvent)); break; case "touchmove": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnTouchMove"); - await OnTouchMove.InvokeAsync(new MapTouchEventArgs(MapService.Map, mapEvent)); + await OnTouchMove.InvokeAsync(new MapTouchEventArgs(map, mapEvent)); break; case "touchstart": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnTouchStart"); - await OnTouchStart.InvokeAsync(new MapTouchEventArgs(MapService.Map, mapEvent)); + await OnTouchStart.InvokeAsync(new MapTouchEventArgs(map, mapEvent)); break; case "wheel": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnWheel"); - await OnWheel.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnWheel.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "zoom": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnZoom"); - await OnZoom.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnZoom.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "zoomend": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnZoomEnd"); - await OnZoomEnd.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnZoomEnd.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; case "zoomstart": Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_MapEventReceivedAsync, "Emitting OnZoomStart"); - await OnZoomStart.InvokeAsync(new MapEventArgs(MapService.Map, mapEvent.Type)); + await OnZoomStart.InvokeAsync(new MapEventArgs(map, mapEvent.Type)); break; } } @@ -757,15 +791,19 @@ private async ValueTask PopupEventReceivedAsync(AzureMapsControl.Components.Popups.PopupEventArgs eventArgs) { + var map = MapService.GetMap(Id); Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_PopupEventReceivedAsync, "Received popup event"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_PopupEventReceivedAsync, $"Id: {eventArgs.Id} | Type: {eventArgs.Type}"); - await Task.Run( - () => + if (map?.Popups != null) { - Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_PopupEventReceivedAsync, "Dispatching popup event"); - Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_PopupEventReceivedAsync, $"Id: {eventArgs.Id} | Type: {eventArgs.Type}"); - MapService.Map.Popups.First(popup => popup.Id == eventArgs.Id).DispatchEvent(eventArgs); - }); + await Task.Run( + () => + { + Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_PopupEventReceivedAsync, "Dispatching popup event"); + Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_PopupEventReceivedAsync, $"Id: {eventArgs.Id} | Type: {eventArgs.Type}"); + map.Popups.First(popup => popup.Id == eventArgs.Id).DispatchEvent(eventArgs); + }); + } } #endregion @@ -774,15 +812,19 @@ private async ValueTask DataSourceEventReceivedAsync(AzureMapsControl.Components.Data.DataSourceEventArgs eventArgs) { + var map = MapService.GetMap(Id); Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DataSourceEventReceivedAsync, "AzureMap - DataSourceEventReceived"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_DataSourceEventReceivedAsync, $"Id: {eventArgs.Id} | Type: {eventArgs.Type}"); - await Task.Run( - () => + if (map?.Sources != null) { - Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DataSourceEventReceivedAsync, "Dispatching datasource event"); - Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_DataSourceEventReceivedAsync, $"Id: {eventArgs.Id} | Type: {eventArgs.Type}"); - MapService.Map.Sources.OfType().First(dataSource => dataSource.Id == dataSource.Id).DispatchEvent(eventArgs); - }); + await Task.Run( + () => + { + Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_DataSourceEventReceivedAsync, "Dispatching datasource event"); + Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.AzureMap_DataSourceEventReceivedAsync, $"Id: {eventArgs.Id} | Type: {eventArgs.Type}"); + map.Sources.OfType().First(dataSource => dataSource.Id == eventArgs.Id).DispatchEvent(eventArgs); + }); + } } #endregion diff --git a/src/AzureMapsControl.Components/Map/IMapAdderService.cs b/src/AzureMapsControl.Components/Map/IMapAdderService.cs index 9de4ff2..2f89da5 100644 --- a/src/AzureMapsControl.Components/Map/IMapAdderService.cs +++ b/src/AzureMapsControl.Components/Map/IMapAdderService.cs @@ -5,5 +5,7 @@ internal interface IMapAdderService : IMapService { ValueTask AddMapAsync(Map map); + + ValueTask RemoveMapAsync(string mapId); } } diff --git a/src/AzureMapsControl.Components/Map/IMapService.cs b/src/AzureMapsControl.Components/Map/IMapService.cs index 9922287..bc10585 100644 --- a/src/AzureMapsControl.Components/Map/IMapService.cs +++ b/src/AzureMapsControl.Components/Map/IMapService.cs @@ -1,14 +1,29 @@ namespace AzureMapsControl.Components.Map { + using System.Collections.Generic; + public interface IMapService { /// - /// The map + /// The maps indexed by their ID + /// + IReadOnlyDictionary Maps { get; } + + /// + /// Get a specific map by its ID + /// + /// The ID of the map to retrieve + /// The map instance or null if not found + Map GetMap(string mapId); + + /// + /// The latest map added to the service + /// deprecated: use GetMap with specific ID instead /// Map Map { get; } /// - /// Triggered when the ready event has been triggered on the map + /// Triggered when the ready event has been triggered on a map /// event MapReadyEvent OnMapReadyAsync; } diff --git a/src/AzureMapsControl.Components/Map/Map.cs b/src/AzureMapsControl.Components/Map/Map.cs index 5fa2910..9bc0c85 100644 --- a/src/AzureMapsControl.Components/Map/Map.cs +++ b/src/AzureMapsControl.Components/Map/Map.cs @@ -185,13 +185,19 @@ public async ValueTask AddControlsAsync(IEnumerable controls) _controls = new List(); } + // Inject MapId into all controls for multi-map support + foreach (var control in controls) + { + control.MapId = Id; + } + _controls.AddRange(controls); _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_AddControlsAsync, $"Adding controls", Controls); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_AddControlsAsync, $"{Controls.Count()} controls will be added: {string.Join('|', Controls.Select(co => co.Type))}"); //Ordering the controls is necessary if the controls contain an OverviewMapControl. This one needs to be added last, otherwise the controls added after it will be added to the overlay. //Following : https://github.com/Azure-Samples/azure-maps-overview-map/issues/1 - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), Controls?.OrderBy(control => control.Order)); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), Id, Controls?.OrderBy(control => control.Order)); var overviewMapControls = controls.OfType(); if (overviewMapControls.Any()) @@ -264,8 +270,10 @@ public async ValueTask AddSourceAsync(TSource source) where TSource : S { dataSource.Logger = _logger; dataSource.JSRuntime = _jsRuntime; + dataSource.MapId = Id; await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), + Id, source.Id, source.GetSourceOptions(), source.SourceType.ToString(), @@ -278,9 +286,11 @@ await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.To { griddedDataSource.Logger = _logger; griddedDataSource.JSRuntime = _jsRuntime; + griddedDataSource.MapId = Id; } await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), + Id, source.Id, source.GetSourceOptions(), source.SourceType.ToString()); @@ -306,7 +316,7 @@ public async ValueTask RemoveDataSourceAsync(string id) var dataSource = _sources?.SingleOrDefault(ds => ds.Id == id); if (dataSource != null) { - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), id); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), Id, id); _sources.Remove(dataSource); } } @@ -319,7 +329,7 @@ public async ValueTask ClearDataSourcesAsync() { _sources = null; _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_ClearSourcesAsync, $"Clearing sources"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearSources.ToCoreNamespace()); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearSources.ToCoreNamespace(), Id); } #endregion @@ -338,6 +348,7 @@ public async ValueTask AddDrawingToolbarAsync(DrawingToolbarOptions drawingToolb _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_AddDrawingToolbarAsync, "Adding drawing toolbar"); DrawingToolbarOptions = drawingToolbarOptions; await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), + Id, new DrawingToolbarCreationOptions { Buttons = drawingToolbarOptions.Buttons?.Select(button => button.ToString()).ToArray(), ContainerId = drawingToolbarOptions.ContainerId, @@ -356,7 +367,8 @@ await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawin DotNetObjectReference.Create(_drawingToolbarEventInvokeHelper)); DrawingManager = new DrawingManager() { JSRuntime = _jsRuntime, - Logger = _logger + Logger = _logger, + MapId = Id }; } } @@ -378,6 +390,7 @@ public async ValueTask UpdateDrawingToolbarAsync(DrawingToolbarUpdateOptions dra DrawingToolbarOptions.Style = drawingToolbarUpdateOptions.Style; DrawingToolbarOptions.Visible = drawingToolbarUpdateOptions.Visible; await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.UpdateDrawingToolbar.ToDrawingNamespace(), + Id, new DrawingToolbarCreationOptions { Buttons = DrawingToolbarOptions.Buttons?.Select(button => button.ToString()).ToArray(), ContainerId = DrawingToolbarOptions.ContainerId, @@ -398,7 +411,7 @@ public async ValueTask RemoveDrawingToolbarAsync() _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_RemoveDrawingToolbarAsync, "Removing drawing toolbar"); if (DrawingToolbarOptions != null) { - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.RemoveDrawingToolbar.ToDrawingNamespace()); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.RemoveDrawingToolbar.ToDrawingNamespace(), Id); DrawingToolbarOptions = null; DrawingManager?.Dispose(); DrawingManager = null; @@ -456,6 +469,7 @@ public async ValueTask AddHtmlMarkersAsync(IEnumerable markers) _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_AddHtmlMarkersAsync, $"{markers.Count()} new html markers will be added"); var parameters = GetHtmlMarkersCreationParameters(markers); await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), + Id, parameters.MarkerOptions, parameters.InvokeHelper); @@ -464,6 +478,7 @@ await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarke marker.JSRuntime = _jsRuntime; marker.PopupInvokeHelper = _popupInvokeHelper; marker.Logger = _logger; + marker.MapId = Id; marker.OnPopupToggled += () => { if (_popups == null) @@ -481,6 +496,7 @@ await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarke { marker.Options.Popup.JSRuntime = _jsRuntime; marker.Options.Popup.Logger = _logger; + marker.Options.Popup.MapId = Id; marker.Options.Popup.OnRemoved += () => RemovePopup(marker.Options.Popup.Id); if (marker.Options.Popup.Options.OpenOnAdd.GetValueOrDefault()) @@ -528,6 +544,7 @@ public async ValueTask UpdateHtmlMarkersAsync(IEnumerable upda _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_UpdateHtmlMarkersAsync, $"Ids: {string.Join('|', updates.Select(h => h.Marker.Id))}"); await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.UpdateHtmlMarkers.ToCoreNamespace(), + Id, updates.Select(update => new HtmlMarkerCreationOptions { Id = update.Marker.Id, Options = update.Options, @@ -594,6 +611,10 @@ await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.UpdateHtmlMa { marker.Options.Popup.Logger = _logger; } + if (marker.Options.Popup.MapId == null) + { + marker.Options.Popup.MapId = Id; + } } } } @@ -619,7 +640,7 @@ public async ValueTask RemoveHtmlMarkersAsync(IEnumerable markers) _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_RemoveHtmlMarkersAsync, $"{markers.Count()} html markers will be removed"); var ids = markers.Select(marker => marker.Id); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_RemoveHtmlMarkersAsync, $"Ids: {string.Join('|', ids)}"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveHtmlMarkers.ToCoreNamespace(), ids); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveHtmlMarkers.ToCoreNamespace(), Id, ids); } } @@ -631,7 +652,7 @@ public async ValueTask ClearHtmlMarkersAsync() { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_ClearHtmlMarkersAsync, "Clearing html markers"); HtmlMarkers = null; - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearHtmlMarkers.ToCoreNamespace()); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearHtmlMarkers.ToCoreNamespace(), Id); } #endregion @@ -671,11 +692,13 @@ public async ValueTask AddLayerAsync(T layer, string before) where T : Layer } _layers.Add(layer); + layer.MapId = Id; layer.AddInterop(_jsRuntime, _logger); _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_AddLayerAsync, "Adding layer"); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_AddLayerAsync, $"Id: {layer.Id} | Type: {layer.Type} | Events: {string.Join('|', layer.EventActivationFlags.EnabledEvents)} | Before: {before}"); await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), + Id, layer.Id, before, layer.Type.ToString(), @@ -718,7 +741,7 @@ public async ValueTask RemoveLayersAsync(IEnumerable layerIds) { var layerIdsToRemove = layers.Select(l => l.Id); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_RemoveLayersAsync, $"Ids: {string.Join('|', layerIds)}"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), layerIdsToRemove); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), Id, layerIdsToRemove); _layers.RemoveAll(l => layerIds.Contains(l.Id)); } } @@ -731,7 +754,7 @@ public async ValueTask ClearLayersAsync() { _layers = null; _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_ClearLayersAsync, "Clearing layers"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearLayers.ToCoreNamespace()); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearLayers.ToCoreNamespace(), Id); } #endregion @@ -749,7 +772,7 @@ public async ValueTask ClearMapAsync() HtmlMarkers = null; _popups = null; _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AzureMap_ClearMapAsync, "Clearing map"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearMap.ToCoreNamespace()); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearMap.ToCoreNamespace(), Id); } /// @@ -785,7 +808,7 @@ public async ValueTask SetCameraOptionsAsync(Action configure) } _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_SetCameraOptionsAsync, "Setting camera options"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), CameraOptions); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), Id, CameraOptions); } /// @@ -795,7 +818,7 @@ public async ValueTask SetCameraOptionsAsync(Action configure) public async ValueTask GetCameraOptionsAsync() { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_GetCameraOptionsAsync, "Map - GetCameraOptionsAsync"); - CameraOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetCamera.ToCoreNamespace()); + CameraOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetCamera.ToCoreNamespace(), Id); return CameraOptions; } @@ -806,7 +829,7 @@ public async ValueTask GetCameraOptionsAsync() public async ValueTask GetStyleOptionsAsync() { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_GetStyleOptionsAsync, "Map - GetStyleOptionsAsync"); - StyleOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetStyle.ToCoreNamespace()); + StyleOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetStyle.ToCoreNamespace(), Id); return StyleOptions; } @@ -817,7 +840,7 @@ public async ValueTask GetStyleOptionsAsync() public async ValueTask GetTrafficOptionsAsync() { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_GetTrafficOptionsAsync, "Map - GetTrafficOptionsAsync"); - TrafficOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetTraffic.ToCoreNamespace()); + TrafficOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetTraffic.ToCoreNamespace(), Id); return TrafficOptions; } @@ -828,7 +851,7 @@ public async ValueTask GetTrafficOptionsAsync() public async ValueTask GetUserInteractionOptionsAsync() { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_GetUserInteractionOptionsAsync, "Map - GetUserInteractionOptionsAsync"); - UserInteractionOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetUserInteraction.ToCoreNamespace()); + UserInteractionOptions = await _jsRuntime.InvokeAsync(Constants.JsConstants.Methods.Core.GetUserInteraction.ToCoreNamespace(), Id); return UserInteractionOptions; } @@ -845,7 +868,7 @@ public async ValueTask SetStyleOptionsAsync(Action configure) } configure.Invoke(StyleOptions); _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_SetStyleOptionsAsync, "Setting style options"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetStyleOptions.ToCoreNamespace(), StyleOptions); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetStyleOptions.ToCoreNamespace(), Id, StyleOptions); } /// @@ -861,7 +884,7 @@ public async ValueTask SetUserInteractionAsync(Action co } configure.Invoke(UserInteractionOptions); _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_SetUserInteractionAsync, "Setting user interaction options"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetUserInteraction.ToCoreNamespace(), UserInteractionOptions); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetUserInteraction.ToCoreNamespace(), Id, UserInteractionOptions); } /// @@ -877,7 +900,7 @@ public async ValueTask SetTrafficOptionsAsync(Action configure) } configure.Invoke(TrafficOptions); _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_SetTrafficAsync, "Setting traffic options"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetTraffic.ToCoreNamespace(), TrafficOptions); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetTraffic.ToCoreNamespace(), Id, TrafficOptions); } internal void DispatchEvent(MapJsEventArgs eventArgs) @@ -1050,10 +1073,11 @@ public async ValueTask AddPopupAsync(Popup popup) _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_AddPopupAsync, "Map - AddPopupAsync"); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_AddPopupAsync, $"Id: {popup.Id}"); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_AddPopupAsync, $"Events: {string.Join('|', popup.EventActivationFlags.EnabledEvents)}"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), popup.Id, popup.Options, popup.EventActivationFlags.EnabledEvents, DotNetObjectReference.Create(_popupInvokeHelper)); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), Id, popup.Id, popup.Options, popup.EventActivationFlags.EnabledEvents, DotNetObjectReference.Create(_popupInvokeHelper)); popup.JSRuntime = _jsRuntime; popup.Logger = _logger; + popup.MapId = Id; popup.OnRemoved += () => RemovePopup(popup.Id); @@ -1092,6 +1116,7 @@ public async ValueTask AddPopupAsync(Popup popup, PopupTemplate template, IDicti _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_AddPopupAsync, $"Properties: {string.Join('|', properties.Select(kvp => kvp.Key + " : " + kvp.Value))}"); await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopupWithTemplate.ToCoreNamespace(), + Id, popup.Id, popup.Options, properties, @@ -1102,6 +1127,7 @@ await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopupWith popup.JSRuntime = _jsRuntime; popup.Logger = _logger; + popup.MapId = Id; popup.OnRemoved += () => RemovePopup(popup.Id); @@ -1137,7 +1163,7 @@ public async ValueTask ClearPopupsAsync() { _popups = null; _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Map_ClearPopupsAsync, "Clearing popups"); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearPopups.ToCoreNamespace()); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearPopups.ToCoreNamespace(), Id); } private void RemovePopup(string id) @@ -1171,7 +1197,7 @@ public async ValueTask CreateImageFromTemplateAsync(string id, string templateNa _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_CreateImageFromTemplate, "Secondary color", secondaryColor); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Map_CreateImageFromTemplate, "Scale", scale); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.CreateImageFromTemplate.ToCoreNamespace(), new MapImageTemplate { + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.CreateImageFromTemplate.ToCoreNamespace(), Id, new MapImageTemplate { Id = id, TemplateName = templateName, Color = color, @@ -1195,7 +1221,7 @@ public async ValueTask SetCanvasStylePropertyAsync(string property, string value Require.NotNullOrWhiteSpace(property, nameof(property)); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperty.ToCoreNamespace(), property, value); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperty.ToCoreNamespace(), Id, property, value); } /// @@ -1214,7 +1240,7 @@ public async ValueTask SetCanvasStylePropertiesAsync(IReadOnlyDictionary !string.IsNullOrWhiteSpace(property.Key)); if (definedProperties.Any()) { - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), definedProperties); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), Id, definedProperties); } } @@ -1233,7 +1259,7 @@ public async ValueTask SetCanvasContainerStylePropertyAsync(string property, str Require.NotNullOrWhiteSpace(property, nameof(property)); - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperty.ToCoreNamespace(), property, value); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperty.ToCoreNamespace(), Id, property, value); } /// @@ -1252,9 +1278,8 @@ public async ValueTask SetCanvasContainerStylePropertiesAsync(IReadOnlyDictionar var definedProperties = properties.Where(property => !string.IsNullOrWhiteSpace(property.Key)); if (definedProperties.Any()) { - await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), definedProperties); + await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), Id, definedProperties); } } - } } diff --git a/src/AzureMapsControl.Components/Map/MapService.cs b/src/AzureMapsControl.Components/Map/MapService.cs index 969d9ed..593dd94 100644 --- a/src/AzureMapsControl.Components/Map/MapService.cs +++ b/src/AzureMapsControl.Components/Map/MapService.cs @@ -1,37 +1,83 @@ namespace AzureMapsControl.Components.Map { + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Linq; using System.Threading.Tasks; using AzureMapsControl.Components.Logger; using Microsoft.Extensions.Logging; - public delegate ValueTask MapReadyEvent(); + public delegate ValueTask MapReadyEvent(Map map); internal class MapService : IMapAdderService { private readonly ILogger _logger; + private readonly ConcurrentDictionary _maps = new(); + private string _latestMapId; - public Map Map - { - get; - private set; + public IReadOnlyDictionary Maps => _maps; + + // Backward compatibility: return the most recently added map or first available map + public Map Map + { + get + { + if (!string.IsNullOrEmpty(_latestMapId) && _maps.ContainsKey(_latestMapId)) + { + return _maps[_latestMapId]; + } + + if (_maps.Count > 0) + { + return _maps.Values.First(); + } + + return null; + } } public MapService(ILogger logger) => _logger = logger; public event MapReadyEvent OnMapReadyAsync; + public Map GetMap(string mapId) + { + return _maps.TryGetValue(mapId, out var map) ? map : null; + } + public async ValueTask AddMapAsync(Map map) { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.MapService_AddMapAsync, "Adding instance of map"); - Map = map; + _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.MapService_AddMapAsync, $"Map ID: {map.Id}"); + + _maps.AddOrUpdate(map.Id, map, (key, oldValue) => map); + _latestMapId = map.Id; // Track the most recently added map if (OnMapReadyAsync != null) { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.MapService_AddMapAsync, "Emitting OnMapReadyAsync"); - await OnMapReadyAsync.Invoke(); + await OnMapReadyAsync.Invoke(map); } } + public async ValueTask RemoveMapAsync(string mapId) + { + _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.MapService_AddMapAsync, "Removing map instance"); + _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.MapService_AddMapAsync, $"Map ID: {mapId}"); + + if (_maps.TryRemove(mapId, out var removedMap)) + { + // If we're removing the latest map, update the latest map ID + if (_latestMapId == mapId) + { + _latestMapId = _maps.Keys.FirstOrDefault(); + } + + _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.MapService_AddMapAsync, "Map removed successfully"); + } + + await ValueTask.CompletedTask; + } } } diff --git a/src/AzureMapsControl.Components/Markers/HtmlMarker.cs b/src/AzureMapsControl.Components/Markers/HtmlMarker.cs index d3d2cf6..d96c184 100644 --- a/src/AzureMapsControl.Components/Markers/HtmlMarker.cs +++ b/src/AzureMapsControl.Components/Markers/HtmlMarker.cs @@ -24,6 +24,7 @@ public sealed class HtmlMarker internal IMapJsRuntime JSRuntime { get; set; } internal PopupInvokeHelper PopupInvokeHelper { get; set; } internal ILogger Logger { get; set; } + internal string MapId { get; set; } /// /// Options of the marker @@ -151,7 +152,7 @@ public async ValueTask TogglePopupAsync() throw new Exceptions.ComponentNotAddedToMapException(); } - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.HtmlMarker.TogglePopup.ToHtmlMarkerNamespace(), Id, Options.Popup.Id, Options.Popup.EventActivationFlags.EnabledEvents, DotNetObjectReference.Create(PopupInvokeHelper)); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.HtmlMarker.TogglePopup.ToHtmlMarkerNamespace(), MapId, Id, Options.Popup.Id, Options.Popup.EventActivationFlags.EnabledEvents, DotNetObjectReference.Create(PopupInvokeHelper)); Options.Popup.HasBeenToggled = true; Options.Popup.IsRemoved = false; OnPopupToggled?.Invoke(); diff --git a/src/AzureMapsControl.Components/Popups/Popup.cs b/src/AzureMapsControl.Components/Popups/Popup.cs index 99eef18..1f47037 100644 --- a/src/AzureMapsControl.Components/Popups/Popup.cs +++ b/src/AzureMapsControl.Components/Popups/Popup.cs @@ -24,6 +24,7 @@ public class Popup internal IMapJsRuntime JSRuntime { get; set; } internal ILogger Logger { get; set; } + internal string MapId { get; set; } public string Id { get; } @@ -71,7 +72,7 @@ public virtual async ValueTask OpenAsync() EnsureJsRuntimeExists(); EnsureNotRemoved(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Open.ToPopupNamespace(), Id); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Open.ToPopupNamespace(), MapId, Id); } /// @@ -88,7 +89,7 @@ public virtual async ValueTask CloseAsync() EnsureJsRuntimeExists(); EnsureNotRemoved(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Close.ToPopupNamespace(), Id); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Close.ToPopupNamespace(), MapId, Id); } /// @@ -105,7 +106,7 @@ public virtual async ValueTask RemoveAsync() EnsureJsRuntimeExists(); EnsureNotRemoved(); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), Id); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), MapId, Id); OnRemoved?.Invoke(); IsRemoved = true; @@ -147,7 +148,7 @@ public virtual async ValueTask SetOptionsAsync(Action update) update.Invoke(Options); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Popup_SetOptionsAsync, $"Id: {Id}"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.SetOptions.ToPopupNamespace(), Id, Options); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.SetOptions.ToPopupNamespace(), MapId, Id, Options); } /// @@ -178,7 +179,7 @@ public async ValueTask ApplyTemplateAsync(PopupTemplate template, IDictionary kvp.Key + " : " + kvp.Value))}"); - await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.ApplyTemplate.ToPopupNamespace(), Id, Options, properties, template); + await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.ApplyTemplate.ToPopupNamespace(), MapId, Id, Options, properties, template); } internal void DispatchEvent(PopupEventArgs eventArgs) diff --git a/src/AzureMapsControl.Components/typescript/animations/animation.ts b/src/AzureMapsControl.Components/typescript/animations/animation.ts index 1416455..5e2fbd3 100644 --- a/src/AzureMapsControl.Components/typescript/animations/animation.ts +++ b/src/AzureMapsControl.Components/typescript/animations/animation.ts @@ -12,13 +12,14 @@ export class Animation { private static readonly _animations = new Map(); - public static drop(animationId: string, + public static drop(mapId: string, + animationId: string, shapes: Geometry[], datasourceId: string, height: number, options: azanimations.PlayableAnimationOptions): void { - const map = Core.getMap(); + const map = Core.getMap(mapId); const source = map.sources.getById(datasourceId) as azmaps.source.DataSource; const animation = azanimations.animations.drop(shapes, source, height, options); @@ -28,18 +29,19 @@ export class Animation { } } - public static dropMarkers(animationId: string, + public static dropMarkers(mapId: string, + animationId: string, markerOptions: HtmlMarkerDefinition[], height: number, options: azanimations.PlayableAnimationOptions, eventInvokeHelper: EventHelper): void { - const map = Core.getMap(); + const map = Core.getMap(mapId); const markers: azmaps.HtmlMarker[] = []; markerOptions.forEach(markerOption => { const marker = Core.getHtmlMarkerFromDefinition(markerOption); markers.push(marker); if (markerOption.events) { - Core.attachEventsToHtmlMarker(marker, markerOption.events, eventInvokeHelper); + Core.attachEventsToHtmlMarker(mapId, marker, markerOption.events, eventInvokeHelper); } }); @@ -50,13 +52,14 @@ export class Animation { } } - public static setCoordinates(animationId: string, + public static setCoordinates(mapId: string, + animationId: string, shapeId: string, datasourceId: string, newCoordinates: azmaps.data.Position | azmaps.data.Position[] | azmaps.data.Position[][] | azmaps.data.Position[][][], options: azanimations.PathAnimationOptions | azanimations.MapPathAnimationOptions): void { - const map = Core.getMap(); + const map = Core.getMap(mapId); const shape = datasourceId ? (map.sources.getById(datasourceId) as azmaps.source.DataSource).getShapeById(shapeId) @@ -68,11 +71,12 @@ export class Animation { } } - public static snakeline(animationId: string, + public static snakeline(mapId: string, + animationId: string, lineId: string, dataSourceId: string, options: azanimations.PathAnimationOptions | azanimations.MapPathAnimationOptions): void { - const source = Core.getMap().sources.getById(dataSourceId) as azmaps.source.DataSource; + const source = Core.getMap(mapId).sources.getById(dataSourceId) as azmaps.source.DataSource; const shape = source.getShapeById(lineId); const animation = azanimations.animations.snakeline(shape, options); @@ -81,13 +85,14 @@ export class Animation { } } - public static moveAlongPath(animationId: string, + public static moveAlongPath(mapId: string, + animationId: string, line: string | azmaps.data.Position[], lineSourceId: string, pinId: string, pinSourceId: string, options: azanimations.PathAnimationOptions | azanimations.MapPathAnimationOptions): void { - const map = Core.getMap(); + const map = Core.getMap(mapId); let path: azmaps.data.Position[] | azmaps.data.LineString | azmaps.Shape = null; if (typeof line === 'string') { @@ -112,12 +117,13 @@ export class Animation { } } - public static moveAlongRoute(animationId: string, + public static moveAlongRoute(mapId: string, + animationId: string, routePoints: RoutePoint[], pinSourceId: string, pinId: string, options: azanimations.RoutePathAnimationOptions): void { - const map = Core.getMap(); + const map = Core.getMap(mapId); let shape: azmaps.Shape | azmaps.HtmlMarker = null; if (pinSourceId) { @@ -135,11 +141,12 @@ export class Animation { this._animations.set(animationId, azanimations.animations.moveAlongRoute(route, shape, options)); } - public static flowingDashedLine(animationId: string, + public static flowingDashedLine(mapId: string, + animationId: string, lineLayerId: string, options: azanimations.MovingDashLineOptions): void { - const layer = Core.getMap().layers.getLayerById(lineLayerId) as azmaps.layer.LineLayer; + const layer = Core.getMap(mapId).layers.getLayerById(lineLayerId) as azmaps.layer.LineLayer; this._animations.set( animationId, @@ -147,13 +154,14 @@ export class Animation { ); } - public static morph(animationId: string, + public static morph(mapId: string, + animationId: string, shapeId: string, datasourceId: string, newGeometry: Geometry, options: azanimations.PlayableAnimationOptions): void { - const map = Core.getMap(); + const map = Core.getMap(mapId); const shape = (map.sources.getById(datasourceId) as azmaps.source.DataSource).getShapeById(shapeId); const animation = azanimations.animations.morph( @@ -163,7 +171,7 @@ export class Animation { ); if (!options.disposeOnComplete) { - this, this._animations.set(animationId, animation); + this._animations.set(animationId, animation); } } diff --git a/src/AzureMapsControl.Components/typescript/controls/fullscreen-control.ts b/src/AzureMapsControl.Components/typescript/controls/fullscreen-control.ts index ff3d452..06b0cf0 100644 --- a/src/AzureMapsControl.Components/typescript/controls/fullscreen-control.ts +++ b/src/AzureMapsControl.Components/typescript/controls/fullscreen-control.ts @@ -8,21 +8,21 @@ export class FullscreenControl { return await Promise.resolve(fullscreencontrol.control.FullscreenControl.isSupported()); } - public static dispose(id: string): void { - this._getFullscreenControl(id).dispose(); + public static dispose(mapId: string, controlId: string): void { + this._getFullscreenControl(mapId, controlId).dispose(); } - public static setOptions(id: string, options: fullscreencontrol.FullscreenControlOptions): void { - this._getFullscreenControl(id).setOptions(options); + public static setOptions(mapId: string, controlId: string, options: fullscreencontrol.FullscreenControlOptions): void { + this._getFullscreenControl(mapId, controlId).setOptions(options); } - public static async isFullscreen(id: string): Promise { - return await Promise.resolve(this._getFullscreenControl(id).isFullscreen()); + public static async isFullscreen(mapId: string, controlId: string): Promise { + return await Promise.resolve(this._getFullscreenControl(mapId, controlId).isFullscreen()); } - public static addEvents(controlId: string, events: string[], eventHelper: EventHelper): void { - const control = this._getFullscreenControl(controlId); - const map = Core.getMap(); + public static addEvents(mapId: string, controlId: string, events: string[], eventHelper: EventHelper): void { + const control = this._getFullscreenControl(mapId, controlId); + const map = Core.getMap(mapId); events.forEach(event => { map.events.add(event as any, control, (_: any) => { @@ -31,8 +31,8 @@ export class FullscreenControl { }) } - private static _getFullscreenControl(controlId: string): fullscreencontrol.control.FullscreenControl { - return Core.getMap().controls.getControls().find(ctrl => (ctrl as any).amc && (ctrl as any).amc.id === controlId) as fullscreencontrol.control.FullscreenControl; + private static _getFullscreenControl(mapId: string, controlId: string): fullscreencontrol.control.FullscreenControl { + return Core.getMap(mapId).controls.getControls().find(ctrl => (ctrl as any).amc && (ctrl as any).amc.id === controlId) as fullscreencontrol.control.FullscreenControl; } } \ No newline at end of file diff --git a/src/AzureMapsControl.Components/typescript/controls/geolocation-control.ts b/src/AzureMapsControl.Components/typescript/controls/geolocation-control.ts index 7272c90..abac81d 100644 --- a/src/AzureMapsControl.Components/typescript/controls/geolocation-control.ts +++ b/src/AzureMapsControl.Components/typescript/controls/geolocation-control.ts @@ -6,8 +6,8 @@ import { GeolocationEventArgs } from './geolocation-event-args'; export class GeolocationControl { - public static getLastKnownPosition(controlId: string): Feature { - const position = this._getGeolocationControl(controlId).getLastKnownPosition(); + public static getLastKnownPosition(mapId: string, controlId: string): Feature { + const position = this._getGeolocationControl(mapId, controlId).getLastKnownPosition(); return { geometry: position.geometry, properties: Core.formatProperties(position.properties) @@ -18,17 +18,17 @@ export class GeolocationControl { return await geolocationcontrol.control.GeolocationControl.isSupported(); } - public static dispose(controlId: string): void { - this._getGeolocationControl(controlId).dispose(); + public static dispose(mapId: string, controlId: string): void { + this._getGeolocationControl(mapId, controlId).dispose(); } - public static setOptions(controlId: string, options: geolocationcontrol.GeolocationControlOptions): void { - this._getGeolocationControl(controlId).setOptions(options); + public static setOptions(mapId: string, controlId: string, options: geolocationcontrol.GeolocationControlOptions): void { + this._getGeolocationControl(mapId, controlId).setOptions(options); } - public static addEvents(controlId: string, events: string[], eventHelper: EventHelper): void { - const control = this._getGeolocationControl(controlId); - const map = Core.getMap(); + public static addEvents(mapId: string, controlId: string, events: string[], eventHelper: EventHelper): void { + const control = this._getGeolocationControl(mapId, controlId); + const map = Core.getMap(mapId); events.forEach(event => { map.events.add(event as any, control, (args: any) => { @@ -46,8 +46,8 @@ export class GeolocationControl { }) } - private static _getGeolocationControl(controlId: string): geolocationcontrol.control.GeolocationControl { - return Core.getMap().controls.getControls().find(ctrl => (ctrl as any).amc && (ctrl as any).amc.id === controlId) as geolocationcontrol.control.GeolocationControl; + private static _getGeolocationControl(mapId: string, controlId: string): geolocationcontrol.control.GeolocationControl { + return Core.getMap(mapId).controls.getControls().find(ctrl => (ctrl as any).amc && (ctrl as any).amc.id === controlId) as geolocationcontrol.control.GeolocationControl; } } \ No newline at end of file diff --git a/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts b/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts index c226747..e1ec76b 100644 --- a/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts +++ b/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts @@ -2,7 +2,7 @@ import * as overviewmap from 'azure-maps-control-overviewmap'; import { Core } from '../core/core'; export class OverviewMapControl { - public static setOptions(controlId: string, options: overviewmap.OverviewMapOptions): void { - (Core.getMap().controls.getControls().find(ctrl => (ctrl as any).amc && (ctrl as any).amc.id === controlId) as overviewmap.control.OverviewMap).setOptions(options); + public static setOptions(mapId: string, controlId: string, options: overviewmap.OverviewMapOptions): void { + (Core.getMap(mapId).controls.getControls().find(ctrl => (ctrl as any).amc && (ctrl as any).amc.id === controlId) as overviewmap.control.OverviewMap).setOptions(options); } } \ No newline at end of file diff --git a/src/AzureMapsControl.Components/typescript/core/core.ts b/src/AzureMapsControl.Components/typescript/core/core.ts index 12976ba..0313cbe 100644 --- a/src/AzureMapsControl.Components/typescript/core/core.ts +++ b/src/AzureMapsControl.Components/typescript/core/core.ts @@ -19,11 +19,25 @@ import { DataSourceEventArgs } from '../sources/datasource-event-args'; import * as griddeddatasource from 'azure-maps-gridded-data-source'; export class Core { - private static readonly _popups: Map = new Map(); + private static readonly _maps: Map = new Map(); + private static readonly _popups: Map> = new Map>(); - private static _map: azmaps.Map; + public static getMap(mapId: string): azmaps.Map { + if (!this._maps.has(mapId)) { + throw new Error(`Map with ID '${mapId}' not found`); + } + return this._maps.get(mapId); + } + + private static getOrCreatePopupCollection(mapId: string): Map { + if (!this._popups.has(mapId)) { + this._popups.set(mapId, new Map()); + } + return this._popups.get(mapId); + } - public static addControls(controls: Control[]): void { + public static addControls(mapId: string, controls: Control[]): void { + const map = this.getMap(mapId); controls.forEach(control => { let mapControl: azmaps.Control; switch (control.type) { @@ -56,24 +70,25 @@ export class Core { (mapControl as any).amc = { id: control.id }; - this._map.controls.add(mapControl, { + map.controls.add(mapControl, { position: control.position }); }); } - public static addHtmlMarkers(htmlMarkerDefinitions: HtmlMarkerDefinition[], + public static addHtmlMarkers(mapId: string, htmlMarkerDefinitions: HtmlMarkerDefinition[], eventHelper: EventHelper): void { + const map = this.getMap(mapId); htmlMarkerDefinitions.forEach(htmlMarkerDefinition => { const marker = this.getHtmlMarkerFromDefinition(htmlMarkerDefinition); if (htmlMarkerDefinition.events) { htmlMarkerDefinition.events.forEach(htmlMarkerEvent => { - this._map.events.add(htmlMarkerEvent as any, marker, event => { + map.events.add(htmlMarkerEvent as any, marker, event => { eventHelper.invokeMethodAsync('NotifyEventAsync', toMarkerEvent(event, (marker as any).amc.id)); }); }); } - this._map.markers.add(marker); + map.markers.add(marker); }); } @@ -102,20 +117,23 @@ export class Core { return marker; } - public static attachEventsToHtmlMarker(marker: azmaps.HtmlMarker, events: string[], eventHelper: EventHelper): void { + public static attachEventsToHtmlMarker(mapId: string, marker: azmaps.HtmlMarker, events: string[], eventHelper: EventHelper): void { + const map = this.getMap(mapId); events.forEach(htmlMarkerEvent => { - this._map.events.add(htmlMarkerEvent as any, marker, event => { + map.events.add(htmlMarkerEvent as any, marker, event => { eventHelper.invokeMethodAsync('NotifyEventAsync', toMarkerEvent(event, (marker as any).amc.id)); }); }); } - public static addLayer(id: string, + public static addLayer(mapId: string, + id: string, before: string, layerType: LayerType, layerOptions: azmaps.LayerOptions, enabledEvents: string[], eventHelper: EventHelper): void { + const map = this.getMap(mapId); let layer: azmaps.layer.Layer; switch (layerType) { case 'tileLayer': @@ -127,32 +145,32 @@ export class Core { break; case 'bubbleLayer': - layer = new azmaps.layer.BubbleLayer(this._map.sources.getById(layerOptions.source), id, layerOptions); + layer = new azmaps.layer.BubbleLayer(map.sources.getById(layerOptions.source), id, layerOptions); break; case 'heatmapLayer': - layer = new azmaps.layer.HeatMapLayer(this._map.sources.getById(layerOptions.source), id, layerOptions); + layer = new azmaps.layer.HeatMapLayer(map.sources.getById(layerOptions.source), id, layerOptions); break; case 'lineLayer': - layer = new azmaps.layer.LineLayer(this._map.sources.getById(layerOptions.source), id, layerOptions); + layer = new azmaps.layer.LineLayer(map.sources.getById(layerOptions.source), id, layerOptions); break; case 'polygonExtrusionLayer': - layer = new azmaps.layer.PolygonExtrusionLayer(this._map.sources.getById(layerOptions.source), id, layerOptions); + layer = new azmaps.layer.PolygonExtrusionLayer(map.sources.getById(layerOptions.source), id, layerOptions); break; case 'polygonLayer': - layer = new azmaps.layer.PolygonLayer(this._map.sources.getById(layerOptions.source), id, layerOptions); + layer = new azmaps.layer.PolygonLayer(map.sources.getById(layerOptions.source), id, layerOptions); break; case 'symbolLayer': - layer = new azmaps.layer.SymbolLayer(this._map.sources.getById(layerOptions.source), id, layerOptions); + layer = new azmaps.layer.SymbolLayer(map.sources.getById(layerOptions.source), id, layerOptions); break; } if (layer) { enabledEvents.forEach(layerEvent => { - this._map.events.add(layerEvent as any, layer, (e: any) => { + map.events.add(layerEvent as any, layer, (e: any) => { eventHelper.invokeMethodAsync('NotifyEventAsync', { type: layerEvent, layerId: layer.getId(), @@ -166,7 +184,7 @@ export class Core { }); }); - this._map.layers.add(layer, before); + map.layers.add(layer, before); } } @@ -197,7 +215,11 @@ export class Core { }) } - const map = new azmaps.Map(mapId, serviceOptions); + const mapOptions: azmaps.ServiceOptions & azmaps.StyleOptions & azmaps.UserInteractionOptions & (azmaps.CameraOptions | azmaps.CameraBoundsOptions) = { + ...serviceOptions, + }; + + const map = new azmaps.Map(mapId, mapOptions); if (enabledEvents.includes('error')) { map.events.add('error', event => { @@ -209,7 +231,7 @@ export class Core { } map.events.addOnce('ready', event => { - this._map = map; + this._maps.set(mapId, map); eventHelper.invokeMethodAsync('NotifyEventAsync', { type: event.type }); mapEvents.filter(value => enabledEvents.includes(value)).forEach(value => { @@ -295,13 +317,16 @@ export class Core { }); } - public static addPopup(id: string, options: azmaps.PopupOptions, events: string[], eventHelper: EventHelper): void { + public static addPopup(mapId: string, id: string, options: azmaps.PopupOptions, events: string[], eventHelper: EventHelper): void { + const map = this.getMap(mapId); + const popupCollection = this.getOrCreatePopupCollection(mapId); + const popup = new azmaps.Popup(options); - this._popups.set(id, popup); - this._map.popups.add(popup); + popupCollection.set(id, popup); + map.popups.add(popup); events.forEach(key => { - this._map.events.add(key as any, popup, () => { + map.events.add(key as any, popup, () => { eventHelper.invokeMethodAsync('NotifyEventAsync', { type: key, id: id @@ -314,22 +339,26 @@ export class Core { } } - public static addPopupWithTemplate(id: string, + public static addPopupWithTemplate(mapId: string, + id: string, options: azmaps.PopupOptions, properties: { [key: string]: any }, template: azmaps.PopupTemplate, events: string[], eventHelper: EventHelper): void { options.content = azmaps.PopupTemplate.applyTemplate(Core.formatProperties(properties), template); - this.addPopup(id, options, events, eventHelper); + this.addPopup(mapId, id, options, events, eventHelper); } - public static addSource(id: string, options: azmaps.DataSourceOptions | azmaps.VectorTileSourceOptions | griddeddatasource.GriddedDataSourceOptions, type: SourceType, events: string[], eventHelper: EventHelper): void { + public static addSource(mapId: string, id: string, options: azmaps.DataSourceOptions | azmaps.VectorTileSourceOptions | griddeddatasource.GriddedDataSourceOptions, type: SourceType, events: string[], eventHelper: EventHelper): void { + const map = this.getMap(mapId); + if (type === 'datasource') { const dataSource = new azmaps.source.DataSource(id, options); - this._map.sources.add(dataSource); + map.sources.add(dataSource); + events?.forEach(event => { - this._map.events.add(event, dataSource, (e: azmaps.source.DataSource | azmaps.Shape[]) => { + map.events.add(event, dataSource, (e: azmaps.source.DataSource | azmaps.Shape[]) => { const args: DataSourceEventArgs = { type: event, id @@ -342,66 +371,66 @@ export class Core { }); }); } else if (type === 'vectortilesource') { - this._map.sources.add(new azmaps.source.VectorTileSource(id, options)); + map.sources.add(new azmaps.source.VectorTileSource(id, options)); } else if (type === 'griddeddatasource') { const griddedDatasource = new griddeddatasource.source.GriddedDataSource(id, options); - this._map.sources.add(griddedDatasource); + map.sources.add(griddedDatasource); } } - public static clearHtmlMarkers(): void { - this._map.markers.clear(); - } - - public static clearLayers(): void { - this._map.layers.clear(); + public static clearHtmlMarkers(mapId: string): void { + this.getMap(mapId).markers.clear(); } - public static clearPopups(): void { - this._map.popups.clear(); - this._popups.clear(); + public static clearLayers(mapId: string): void { + this.getMap(mapId).layers.clear(); } - public static clearSources(): void { - this._map.sources.clear(); + public static clearPopups(mapId: string): void { + this.getMap(mapId).popups.clear(); + this._popups.delete(mapId); } - public static clearMap(): void { - this._map.clear(); - this._popups.clear(); + public static clearSources(mapId: string): void { + this.getMap(mapId).sources.clear(); } - public static getMap(): azmaps.Map { - return this._map; + public static clearMap(mapId: string): void { + this.getMap(mapId).clear(); + this._popups.delete(mapId); } - public static getPopup(id: string): azmaps.Popup { - return this._popups.has(id) ? this._popups.get(id) : null; + public static getPopup(mapId: string, id: string): azmaps.Popup { + const popupCollection = this._popups.get(mapId); + return popupCollection?.get(id) || null; } - public static getPopups(): Map { - return this._popups; + public static getPopups(mapId: string): Map { + return this._popups.get(mapId) || new Map(); } - public static removeHtmlMarkers(markerIds: string[]): void { - this._map.markers.remove(this._map.markers.getMarkers().filter(marker => markerIds.includes((marker as any).amc.id))); + public static removeHtmlMarkers(mapId: string, markerIds: string[]): void { + this.getMap(mapId).markers.remove(this.getMap(mapId).markers.getMarkers().filter(marker => markerIds.includes((marker as any).amc.id))); } - public static removeLayers(ids: string[]): void { - this._map.layers.remove(ids); + public static removeLayers(mapId: string, ids: string[]): void { + this.getMap(mapId).layers.remove(ids); } - public static removeSource(id: string): void { - this._map.sources.remove(id); + public static removeSource(mapId: string, id: string): void { + this.getMap(mapId).sources.remove(id); } - public static removePopup(id: string): void { - if (this._popups.has(id)) { - this._popups.delete(id); + public static removePopup(mapId: string, id: string): void { + const popupCollection = this._popups.get(mapId); + if (popupCollection?.has(id)) { + const popup = popupCollection.get(id); + this.getMap(mapId).popups.remove(popup); + popupCollection.delete(id); } } - public static setCameraOptions(cameraOptions: (azmaps.CameraOptions | azmaps.CameraBoundsOptions) & azmaps.AnimationOptions): void { + public static setCameraOptions(mapId: string, cameraOptions: (azmaps.CameraOptions | azmaps.CameraBoundsOptions) & azmaps.AnimationOptions): void { const options: (azmaps.CameraOptions | azmaps.CameraBoundsOptions) & azmaps.AnimationOptions = { bearing: cameraOptions.bearing, centerOffset: cameraOptions.centerOffset, @@ -424,32 +453,32 @@ export class Core { options.zoom = cameraOptions.zoom; } - this._map.setCamera(options); + this.getMap(mapId).setCamera(options); } - public static setOptions(cameraOptions: azmaps.CameraOptions, + public static setOptions(mapId: string, cameraOptions: azmaps.CameraOptions, styleOptions: azmaps.StyleOptions, userInteractionOptions: azmaps.UserInteractionOptions, trafficOptions: azmaps.TrafficOptions): void { - this.setCameraOptions(cameraOptions); - this.setStyleOptions(styleOptions); - this.setUserInteraction(userInteractionOptions); - this.setTraffic(trafficOptions); + this.setCameraOptions(mapId, cameraOptions); + this.setStyleOptions(mapId, styleOptions); + this.setUserInteraction(mapId, userInteractionOptions); + this.setTraffic(mapId, trafficOptions); } - public static setStyleOptions(styleOptions: azmaps.StyleOptions): void { - this._map.setStyle(styleOptions); + public static setStyleOptions(mapId: string, styleOptions: azmaps.StyleOptions): void { + this.getMap(mapId).setStyle(styleOptions); } - public static setTraffic(trafficOptions: azmaps.TrafficOptions): void { - this._map.setTraffic(trafficOptions); + public static setTraffic(mapId: string, trafficOptions: azmaps.TrafficOptions): void { + this.getMap(mapId).setTraffic(trafficOptions); } - public static setUserInteraction(userInteractionOptions: azmaps.UserInteractionOptions): void { - this._map.setUserInteraction(userInteractionOptions); + public static setUserInteraction(mapId: string, userInteractionOptions: azmaps.UserInteractionOptions): void { + this.getMap(mapId).setUserInteraction(userInteractionOptions); } - public static updateHtmlMarkers(htmlMarkerOptions: HtmlMarkerDefinition[]): void { + public static updateHtmlMarkers(mapId: string, htmlMarkerOptions: HtmlMarkerDefinition[]): void { htmlMarkerOptions.forEach(htmlMarkerOption => { const options: azmaps.HtmlMarkerOptions = {}; if (htmlMarkerOption.options.anchor) { @@ -483,12 +512,12 @@ export class Core { options.popup = new azmaps.Popup(htmlMarkerOption.popupOptions.options); } - this._map.markers.getMarkers().find(marker => (marker as any).amc.id === htmlMarkerOption.id).setOptions(options); + this.getMap(mapId).markers.getMarkers().find(marker => (marker as any).amc.id === htmlMarkerOption.id).setOptions(options); }); } - public static createImageFromTemplate(imageTemplate: MapImageTemplate): void { - this._map.imageSprite.createFromTemplate( + public static createImageFromTemplate(mapId: string, imageTemplate: MapImageTemplate): void { + this.getMap(mapId).imageSprite.createFromTemplate( imageTemplate.id, imageTemplate.templateName, imageTemplate.color, @@ -497,34 +526,34 @@ export class Core { ); } - public static setCanvasStyleProperty(property: string, value: string): void { - this._map.getCanvas().style.setProperty(property, value); + public static setCanvasStyleProperty(mapId: string, property: string, value: string): void { + this.getMap(mapId).getCanvas().style.setProperty(property, value); } - public static setCanvasStyleProperties(properties: { key: string, value: string }[]): void { - const canvas = this._map.getCanvas(); + public static setCanvasStyleProperties(mapId: string, properties: { key: string, value: string }[]): void { + const canvas = this.getMap(mapId).getCanvas(); properties.forEach(property => { canvas.style.setProperty(property.key, property.value); }); } - public static setCanvasContainerStyleProperty(property: string, value: string): void { - this._map.getCanvasContainer().style.setProperty(property, value); + public static setCanvasContainerStyleProperty(mapId: string, property: string, value: string): void { + this.getMap(mapId).getCanvasContainer().style.setProperty(property, value); } - public static setCanvasContainerStyleProperties(properties: { key: string, value: string }[]): void { - const canvasContainer = this._map.getCanvasContainer(); + public static setCanvasContainerStyleProperties(mapId: string, properties: { key: string, value: string }[]): void { + const canvasContainer = this.getMap(mapId).getCanvasContainer(); properties.forEach(property => { canvasContainer.style.setProperty(property.key, property.value); }); } - public static getCamera(): azmaps.CameraOptions & azmaps.CameraBoundsOptions { - return this._map.getCamera(); + public static getCamera(mapId: string): azmaps.CameraOptions & azmaps.CameraBoundsOptions { + return this.getMap(mapId).getCamera(); } - public static getStyle(): azmaps.StyleOptions { - const style = this._map.getStyle(); + public static getStyle(mapId: string): azmaps.StyleOptions { + const style = this.getMap(mapId).getStyle(); return { autoResize: style.autoResize, language: style.language, @@ -540,16 +569,16 @@ export class Core { }; } - public static getTraffic(): azmaps.TrafficOptions { - const traffic = this._map.getTraffic(); + public static getTraffic(mapId: string): azmaps.TrafficOptions { + const traffic = this.getMap(mapId).getTraffic(); return { flow: traffic.flow, incidents: traffic.incidents }; } - public static getUserInteraction(): azmaps.UserInteractionOptions { - const userInteraction = this._map.getUserInteraction(); + public static getUserInteraction(mapId: string): azmaps.UserInteractionOptions { + const userInteraction = this.getMap(mapId).getUserInteraction(); return { boxZoomInteraction: userInteraction.boxZoomInteraction, dblClickZoomInteraction: userInteraction.dblClickZoomInteraction, diff --git a/src/AzureMapsControl.Components/typescript/drawing/drawing.ts b/src/AzureMapsControl.Components/typescript/drawing/drawing.ts index 69120bf..d91655f 100644 --- a/src/AzureMapsControl.Components/typescript/drawing/drawing.ts +++ b/src/AzureMapsControl.Components/typescript/drawing/drawing.ts @@ -8,11 +8,11 @@ import { GeometryBuilder } from '../geometries/geometry-builder'; export class Drawing { - private static _toolbar: azdrawings.control.DrawingToolbar; - private static _drawingManager: azdrawings.drawing.DrawingManager; + private static _toolbars: Map = new Map(); + private static _drawingManagers: Map = new Map(); - public static addDrawingToolbar(drawingToolbarOptions: azdrawings.DrawingToolbarOptions & azdrawings.DrawingManagerOptions & { events: string[] }, eventHelper: EventHelper): void { - this._toolbar = new azdrawings.control.DrawingToolbar({ + public static addDrawingToolbar(mapId: string, drawingToolbarOptions: azdrawings.DrawingToolbarOptions & azdrawings.DrawingManagerOptions & { events: string[] }, eventHelper: EventHelper): void { + const toolbar = new azdrawings.control.DrawingToolbar({ buttons: drawingToolbarOptions.buttons, containerId: drawingToolbarOptions.containerId, numColumns: drawingToolbarOptions.numColumns, @@ -26,7 +26,7 @@ export class Drawing { interactionType: drawingToolbarOptions.interactionType, mode: drawingToolbarOptions.mode, shapeDraggingEnabled: drawingToolbarOptions.shapeDraggingEnabled, - toolbar: this._toolbar + toolbar: toolbar }; if (drawingToolbarOptions.dragHandleStyle) { @@ -57,11 +57,15 @@ export class Drawing { }); } - const map = Core.getMap(); - this._drawingManager = new azdrawings.drawing.DrawingManager(map, drawingManagerOptions); + const map = Core.getMap(mapId); + const drawingManager = new azdrawings.drawing.DrawingManager(map, drawingManagerOptions); + + this._toolbars.set(mapId, toolbar); + this._drawingManagers.set(mapId, drawingManager); + if (drawingToolbarOptions.events) { drawingToolbarOptions.events.forEach(drawingToolbarEvent => { - map.events.add(drawingToolbarEvent as any, this._drawingManager, (e: any) => { + map.events.add(drawingToolbarEvent as any, drawingManager, (e: any) => { if (drawingToolbarEvent === 'drawingmodechanged') { eventHelper.invokeMethodAsync('NotifyEventAsync', { type: drawingToolbarEvent, @@ -80,31 +84,47 @@ export class Drawing { } } - public static removeDrawingToolbar(): void { - this._drawingManager.dispose(); - Core.getMap().controls.remove(this._toolbar); - this._drawingManager = null; - this._toolbar = null; + public static removeDrawingToolbar(mapId: string): void { + const drawingManager = this._drawingManagers.get(mapId); + const toolbar = this._toolbars.get(mapId); + + if (drawingManager) { + drawingManager.dispose(); + this._drawingManagers.delete(mapId); + } + + if (toolbar) { + Core.getMap(mapId).controls.remove(toolbar); + this._toolbars.delete(mapId); + } } - public static updateDrawingToolbar(drawingToolbarOptions: azdrawings.DrawingToolbarOptions): void { - this._toolbar.setOptions({ - buttons: drawingToolbarOptions.buttons, - containerId: drawingToolbarOptions.containerId, - numColumns: drawingToolbarOptions.numColumns, - position: drawingToolbarOptions.position, - style: drawingToolbarOptions.style, - visible: drawingToolbarOptions.visible - }); + public static updateDrawingToolbar(mapId: string, drawingToolbarOptions: azdrawings.DrawingToolbarOptions): void { + const toolbar = this._toolbars.get(mapId); + if (toolbar) { + toolbar.setOptions({ + buttons: drawingToolbarOptions.buttons, + containerId: drawingToolbarOptions.containerId, + numColumns: drawingToolbarOptions.numColumns, + position: drawingToolbarOptions.position, + style: drawingToolbarOptions.style, + visible: drawingToolbarOptions.visible + }); + } } - public static addShapes(shapes: Shape[]): void { - const mapsShapes = shapes.map(shape => GeometryBuilder.buildShape(shape)); - this._drawingManager.getSource().add(mapsShapes); + public static addShapes(mapId: string, shapes: Shape[]): void { + const drawingManager = this._drawingManagers.get(mapId); + if (drawingManager) { + const mapsShapes = shapes.map(shape => GeometryBuilder.buildShape(shape)); + drawingManager.getSource().add(mapsShapes); + } } - public static clear(): void { - this._drawingManager.getSource().clear(); + public static clear(mapId: string): void { + const drawingManager = this._drawingManagers.get(mapId); + if (drawingManager) { + drawingManager.getSource().clear(); + } } - } \ No newline at end of file diff --git a/src/AzureMapsControl.Components/typescript/html-markers/html-marker.ts b/src/AzureMapsControl.Components/typescript/html-markers/html-marker.ts index be52999..f9f9ad1 100644 --- a/src/AzureMapsControl.Components/typescript/html-markers/html-marker.ts +++ b/src/AzureMapsControl.Components/typescript/html-markers/html-marker.ts @@ -4,14 +4,15 @@ import { MapEventArgs } from '../map/map-event-args'; export class HtmlMarker { - public static togglePopup(id: string, + public static togglePopup(mapId: string, + markerId: string, popupId: string, events: string[], eventHelper: EventHelper): void { - const map = Core.getMap(); - const popups = Core.getPopups(); - const marker = map.markers.getMarkers().find((m: any) => m.amc.id === id); + const map = Core.getMap(mapId); + const popups = Core.getPopups(mapId); + const marker = map.markers.getMarkers().find((m: any) => m.amc.id === markerId); marker.togglePopup(); if (!popups.has(popupId)) { @@ -28,5 +29,4 @@ export class HtmlMarker { }); } } - } \ No newline at end of file diff --git a/src/AzureMapsControl.Components/typescript/indoor/indoor.ts b/src/AzureMapsControl.Components/typescript/indoor/indoor.ts index 488f922..61168d1 100644 --- a/src/AzureMapsControl.Components/typescript/indoor/indoor.ts +++ b/src/AzureMapsControl.Components/typescript/indoor/indoor.ts @@ -8,7 +8,7 @@ export class Indoor { private static readonly _indoorManagers = new Map(); - public static createIndoorManager(id: string, options: IndoorManagerOptions, events: string[], eventHelper: EventHelper): void { + public static createIndoorManager(mapId: string, id: string, options: IndoorManagerOptions, events: string[], eventHelper: EventHelper): void { let levelControl: indoor.control.LevelControl; if (options.levelControl) { levelControl = new indoor.control.LevelControl(options.levelControl.options); @@ -21,7 +21,7 @@ export class Indoor { options.geography = 'us'; } - const map = Core.getMap(); + const map = Core.getMap(mapId); const indoorManager = new indoor.indoor.IndoorManager(map, { levelControl, statesetId: options.statesetId, diff --git a/src/AzureMapsControl.Components/typescript/layers/layer.ts b/src/AzureMapsControl.Components/typescript/layers/layer.ts index 6531dca..1d26539 100644 --- a/src/AzureMapsControl.Components/typescript/layers/layer.ts +++ b/src/AzureMapsControl.Components/typescript/layers/layer.ts @@ -2,8 +2,8 @@ import { Core } from '../core/core'; export class Layer { - public static setOptions(layerId: string, options: unknown): void { - const layer = Core.getMap().layers.getLayerById(layerId) as any; + public static setOptions(mapId: string, layerId: string, options: unknown): void { + const layer = Core.getMap(mapId).layers.getLayerById(layerId) as any; layer.setOptions(options); } diff --git a/src/AzureMapsControl.Components/typescript/popups/popup.ts b/src/AzureMapsControl.Components/typescript/popups/popup.ts index 213a549..4234bbc 100644 --- a/src/AzureMapsControl.Components/typescript/popups/popup.ts +++ b/src/AzureMapsControl.Components/typescript/popups/popup.ts @@ -3,30 +3,30 @@ import { Core } from '../core/core'; export class Popup { - public static close(id: string): void { - const popup = Core.getPopup(id); + public static close(mapId: string, popupId: string): void { + const popup = Core.getPopup(mapId, popupId); if (popup) { popup.close(); } } - public static open(id: string): void { - const popup = Core.getPopup(id); + public static open(mapId: string, popupId: string): void { + const popup = Core.getPopup(mapId, popupId); if (popup) { popup.open(); } } - public static remove(id: string): void { - const popup = Core.getPopup(id); + public static remove(mapId: string, popupId: string): void { + const popup = Core.getPopup(mapId, popupId); if (popup) { popup.remove(); - Core.removePopup(id); + Core.removePopup(mapId, popupId); } } - public static setOptions(id: string, options: azmaps.PopupOptions): void { - const popup = Core.getPopup(id); + public static setOptions(mapId: string, popupId: string, options: azmaps.PopupOptions): void { + const popup = Core.getPopup(mapId, popupId); if (popup) { const popupOptions = { draggable: options.draggable, @@ -42,8 +42,8 @@ export class Popup { } } - public static applyTemplate(id: string, options: azmaps.PopupOptions, properties: { [key: string]: any }, template: azmaps.PopupTemplate): void { + public static applyTemplate(mapId: string, popupId: string, options: azmaps.PopupOptions, properties: { [key: string]: any }, template: azmaps.PopupTemplate): void { options.content = azmaps.PopupTemplate.applyTemplate(properties, template); - this.setOptions(id, options); + this.setOptions(mapId, popupId, options); } } \ No newline at end of file diff --git a/src/AzureMapsControl.Components/typescript/sources/datasource.ts b/src/AzureMapsControl.Components/typescript/sources/datasource.ts index fb23d5b..2f268dd 100644 --- a/src/AzureMapsControl.Components/typescript/sources/datasource.ts +++ b/src/AzureMapsControl.Components/typescript/sources/datasource.ts @@ -4,14 +4,14 @@ import { Shape, Feature } from '../geometries/geometry'; export class Datasource { - public static getShapes(id: string): Shape[] { - const shapes = (Core.getMap().sources.getById(id) as azmaps.source.DataSource).getShapes(); + public static getShapes(mapId: string, datasourceId: string): Shape[] { + const shapes = (Core.getMap(mapId).sources.getById(datasourceId) as azmaps.source.DataSource).getShapes(); return shapes?.map(shape => Core.getSerializableShape(shape)); } - public static async getClusterLeaves(datasourceId: string, clusterId: number, limit: number, offset: number): Promise<(Shape | Feature)[]> { + public static async getClusterLeaves(mapId: string, datasourceId: string, clusterId: number, limit: number, offset: number): Promise<(Shape | Feature)[]> { return new Promise(resolve => { - (Core.getMap().sources.getById(datasourceId) as azmaps.source.DataSource).getClusterLeaves(clusterId, limit, offset).then(clusterLeaves => { + (Core.getMap(mapId).sources.getById(datasourceId) as azmaps.source.DataSource).getClusterLeaves(clusterId, limit, offset).then(clusterLeaves => { const resultLeaves = clusterLeaves.map(leaf => { if (leaf instanceof azmaps.Shape) { @@ -28,9 +28,9 @@ export class Datasource { }); } - public static async getClusterExpansionZoom(datasourceId: string, clusterId: number): Promise { + public static async getClusterExpansionZoom(mapId: string, datasourceId: string, clusterId: number): Promise { return new Promise(resolve => { - (Core.getMap().sources.getById(datasourceId) as azmaps.source.DataSource).getClusterExpansionZoom(clusterId).then(zoom => { + (Core.getMap(mapId).sources.getById(datasourceId) as azmaps.source.DataSource).getClusterExpansionZoom(clusterId).then(zoom => { resolve(zoom); }); }); diff --git a/src/AzureMapsControl.Components/typescript/sources/gridded-datasource.ts b/src/AzureMapsControl.Components/typescript/sources/gridded-datasource.ts index 4b9a24a..34fb404 100644 --- a/src/AzureMapsControl.Components/typescript/sources/gridded-datasource.ts +++ b/src/AzureMapsControl.Components/typescript/sources/gridded-datasource.ts @@ -6,39 +6,39 @@ import { GeometryBuilder } from '../geometries/geometry-builder'; export class GriddedDatasource { - public static getCellChildren(sourceId: string, cellId: string): Feature[] { - return (Core.getMap().sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource) + public static getCellChildren(mapId: string, sourceId: string, cellId: string): Feature[] { + return (Core.getMap(mapId).sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource) .getCellChildren(cellId) .map(feature => Core.getSerializableFeature(feature)); } - public static getGridCells(sourceId: string): Feature[] { - return (Core.getMap().sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource) + public static getGridCells(mapId: string, sourceId: string): Feature[] { + return (Core.getMap(mapId).sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource) .getGridCells().features.map(feature => Core.getSerializableFeature(feature)); } - public static getPoints(sourceId: string): Feature[] { - return (Core.getMap().sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource) + public static getPoints(mapId: string, sourceId: string): Feature[] { + return (Core.getMap(mapId).sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource) .getPoints().features.map(feature => Core.getSerializableFeature(feature)); } - public static setFeatureCollectionPoints(sourceId: string, featureCollection: azmaps.data.FeatureCollection): void { - (Core.getMap().sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(featureCollection); + public static setFeatureCollectionPoints(mapId: string, sourceId: string, featureCollection: azmaps.data.FeatureCollection): void { + (Core.getMap(mapId).sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(featureCollection); } - public static setFeaturePoints(sourceId: string, features: Feature[]): void { + public static setFeaturePoints(mapId: string, sourceId: string, features: Feature[]): void { const points = features.map(feature => GeometryBuilder.buildFeature(feature) as azmaps.data.Feature); - (Core.getMap().sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(points); + (Core.getMap(mapId).sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(points); } - public static setPoints(sourceId: string, geometries: Geometry[]): void { + public static setPoints(mapId: string, sourceId: string, geometries: Geometry[]): void { const points = geometries.map(geometry => GeometryBuilder.buildPoint(geometry)); - (Core.getMap().sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(points); + (Core.getMap(mapId).sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(points); } - public static setShapePoints(sourceId: string, shapes: Shape[]): void { + public static setShapePoints(mapId: string, sourceId: string, shapes: Shape[]): void { const points = shapes.map(shape => GeometryBuilder.buildShape(shape)); - (Core.getMap().sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(points); + (Core.getMap(mapId).sources.getById(sourceId) as azmapsgriddeddatasource.source.GriddedDataSource).setPoints(points); } } \ No newline at end of file diff --git a/src/AzureMapsControl.Components/typescript/sources/source.ts b/src/AzureMapsControl.Components/typescript/sources/source.ts index adc05f6..d2d9715 100644 --- a/src/AzureMapsControl.Components/typescript/sources/source.ts +++ b/src/AzureMapsControl.Components/typescript/sources/source.ts @@ -5,42 +5,104 @@ import { GeometryBuilder } from '../geometries/geometry-builder'; export class Source { - public static addShapes(id: string, shapes: Shape[]): void { + public static addShapes(mapId: string, sourceId: string, shapes: Shape[]): void { const mapsShapes = shapes.map(shape => GeometryBuilder.buildShape(shape)); - (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).add(mapsShapes); + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + source.add(mapsShapes); } - public static addFeatures(id: string, features: Feature[]): void { + public static addFeatures(mapId: string, sourceId: string, features: Feature[]): void { const mapsFeatures = features.map(feature => GeometryBuilder.buildFeature(feature)); - (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).add(mapsFeatures); + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + source.add(mapsFeatures); } - public static addFeatureCollection(id: string, featureCollection: azmaps.data.FeatureCollection): void { - (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).add(featureCollection); + public static addFeatureCollection(mapId: string, sourceId: string, featureCollection: azmaps.data.FeatureCollection): void { + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + source.add(featureCollection); } - public static clear(id: string): void { - (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).clear(); + public static clear(mapId: string, sourceId: string): void { + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + source.clear(); } - public static async importDataFromUrl(id: string, url: string): Promise { - return await (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).importDataFromUrl(url); + public static async importDataFromUrl(mapId: string, sourceId: string, url: string): Promise { + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + return await source.importDataFromUrl(url); } - public static remove(id: string, geometryIds: string[]): void { - (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).remove(geometryIds); + public static remove(mapId: string, sourceId: string, geometryIds: string[]): void { + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + source.remove(geometryIds); } - public static dispose(id: string): void { - (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).dispose(); + public static dispose(mapId: string, sourceId: string): void { + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + source.dispose(); } - public static getOptions(id: string): azmaps.DataSourceOptions { - return (Core.getMap().sources.getById(id) as (azmaps.source.DataSource)).getOptions(); + public static getOptions(mapId: string, sourceId: string): azmaps.DataSourceOptions { + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + return source.getOptions(); } - public static setOptions(id: string, options: azmaps.DataSourceOptions): void { - ((Core.getMap().sources.getById(id)) as (azmaps.source.DataSource)).setOptions(options); + public static setOptions(mapId: string, sourceId: string, options: azmaps.DataSourceOptions): void { + const map = Core.getMap(mapId); + const source = map.sources.getById(sourceId) as azmaps.source.DataSource; + + if (!source) { + throw new Error(`Data source with Id '${sourceId}' not found in map '${mapId}'.`); + } + + source.setOptions(options); } - } \ No newline at end of file From 995dc122a902830067a765596a556f61da5565da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Tue, 28 Oct 2025 09:57:34 +0200 Subject: [PATCH 02/12] Fix moving dashed line sample link. --- samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor b/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor index 4a0e462..ff54792 100644 --- a/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor +++ b/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor @@ -34,7 +34,7 @@ Move marker along path
  • - Moving dashed line + Moving dashed line
  • Set coordinates From 28bb97aa99b9fe92f15e559db581c8cc6da99789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Tue, 28 Oct 2025 10:11:13 +0200 Subject: [PATCH 03/12] Fix missing map id in dropped markers. --- .../Animations/AnimationService.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/AzureMapsControl.Components/Animations/AnimationService.cs b/src/AzureMapsControl.Components/Animations/AnimationService.cs index ea422bc..0259846 100644 --- a/src/AzureMapsControl.Components/Animations/AnimationService.cs +++ b/src/AzureMapsControl.Components/Animations/AnimationService.cs @@ -149,6 +149,26 @@ public async ValueTask FlowingDashedLineAsync(LineL return animation; } + public ValueTask DropMarkersAsync(string mapId, IEnumerable markers, decimal? height = null, DropMarkersAnimationOptions options = default) + { + foreach (var marker in markers) + { + if (marker.JSRuntime == null) + { + marker.JSRuntime = _jsRuntime; + } + if (marker.Logger == null) + { + marker.Logger = _logger; + } + if (marker.MapId == null) + { + marker.MapId = mapId; + } + } + return DropMarkersAsync(markers, height, options); + } + public async ValueTask DropMarkersAsync(IEnumerable markers, decimal? height = null, DropMarkersAnimationOptions options = default) { _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.AnimationService_DropMarkers, "Calling DropMarkersAsync"); @@ -161,8 +181,30 @@ public async ValueTask DropMarkersAsync(IEnumerable m.MapId != mapId)) { throw new ArgumentException("All HTML markers must belong to the same map"); From 29bcc646be9aabf38fc1fa14ffd638e230ce4fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Wed, 29 Oct 2025 09:51:53 +0200 Subject: [PATCH 04/12] Update tests to use the map ids --- .../Animations/AnimationService.cs | 110 +++-- .../Controls/FullScreenControl.cs | 42 +- .../Controls/GeolocationControl.cs | 39 +- .../Controls/OverviewMapControl.cs | 151 ++++--- .../Data/DataSource.cs | 356 +++++++++------- .../Data/Grid/GriddedDataSource.cs | 282 ++++++------ .../Drawing/DrawingManager.cs | 86 +++- .../Indoor/IndoorService.cs | 90 +++- .../Layers/Layer.cs | 8 +- .../Map/Map.cs | 403 ++++++++++-------- .../Map/MapService.cs | 2 +- .../Markers/HtmlMarker.cs | 16 +- .../Popups/HtmlMarkerPopup.cs | 37 +- .../Popups/Popup.cs | 73 ++-- 14 files changed, 1028 insertions(+), 667 deletions(-) diff --git a/tests/AzureMapsControl.Components.Tests/Animations/AnimationService.cs b/tests/AzureMapsControl.Components.Tests/Animations/AnimationService.cs index 35db777..292b36f 100644 --- a/tests/AzureMapsControl.Components.Tests/Animations/AnimationService.cs +++ b/tests/AzureMapsControl.Components.Tests/Animations/AnimationService.cs @@ -26,6 +26,7 @@ public class AnimationServiceTests private readonly Mock _jsRuntimeMock = new(); private readonly Mock> _loggerServiceMock = new(); private readonly Mock _mapServiceMock = new(); + private readonly string _testMapId = "test-map-id"; private readonly AnimationService _animationService; @@ -38,6 +39,8 @@ public async Task Should_Snakeline_Async(bool disposeOnComplete) { var line = new LineString(); var source = new DataSource(); + // Set the MapId on the source as would happen when added to map + source.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(source, _testMapId); var options = new SnakeLineAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -47,7 +50,7 @@ public async Task Should_Snakeline_Async(bool disposeOnComplete) Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Snakeline.ToAnimationNamespace(), result.Id, line.Id, source.Id, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Snakeline.ToAnimationNamespace(), _testMapId, result.Id, line.Id, source.Id, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -81,8 +84,10 @@ public async Task Should_MoveAlongPath_LineStringAndPoint_DisposeOnComplete_Asyn { var line = new LineString(); var lineSource = new DataSource(); + lineSource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(lineSource, _testMapId); var pin = new Point(); var pinSource = new DataSource(); + pinSource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(pinSource, _testMapId); var options = new MoveAlongPathAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -92,7 +97,7 @@ public async Task Should_MoveAlongPath_LineStringAndPoint_DisposeOnComplete_Asyn Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), result.Id, line.Id, lineSource.Id, pin.Id, pinSource.Id, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), _testMapId, result.Id, line.Id, lineSource.Id, pin.Id, pinSource.Id, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -155,7 +160,9 @@ public async Task Should_MoveAlongPath_LineStringAndHtmlMarker_Async(bool dispos { var line = new LineString(); var lineSource = new DataSource(); + lineSource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(lineSource, _testMapId); var pin = new HtmlMarker(new HtmlMarkerOptions()); + pin.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(pin, _testMapId); var options = new MoveAlongPathAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -165,7 +172,7 @@ public async Task Should_MoveAlongPath_LineStringAndHtmlMarker_Async(bool dispos Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), result.Id, line.Id, lineSource.Id, pin.Id, null, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), _testMapId, result.Id, line.Id, lineSource.Id, pin.Id, null, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -213,6 +220,7 @@ public async Task Should_MoveAlongPath_PositionsAndPoint_Async(bool disposeOnCom var line = new Position[] { new Position() }; var pin = new Point(); var pinSource = new DataSource(); + pinSource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(pinSource, _testMapId); var options = new MoveAlongPathAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -222,7 +230,7 @@ public async Task Should_MoveAlongPath_PositionsAndPoint_Async(bool disposeOnCom Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), result.Id, line, null, pin.Id, pinSource.Id, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), _testMapId, result.Id, line, null, pin.Id, pinSource.Id, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -269,6 +277,7 @@ public async Task Should_MoveAlongPath_PositionsAndHtmlMarkers_Async(bool dispos { var line = new Position[] { new Position() }; var pin = new HtmlMarker(new HtmlMarkerOptions()); + pin.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(pin, _testMapId); var options = new MoveAlongPathAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -278,7 +287,7 @@ public async Task Should_MoveAlongPath_PositionsAndHtmlMarkers_Async(bool dispos Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), result.Id, line, null, pin.Id, null, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongPath.ToAnimationNamespace(), _testMapId, result.Id, line, null, pin.Id, null, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -308,13 +317,14 @@ public async Task Should_ThrowArgumentNullException_MoveAlongPath_PositionsAndHt public async Task Should_FlowingDashedLine_Async() { var layer = new LineLayer(); + layer.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(layer, _testMapId); var options = new MovingDashLineOptions(); var result = await _animationService.FlowingDashedLineAsync(layer, options); Assert.IsType(result); Assert.NotNull(result.Id); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.FlowingDashedLine.ToAnimationNamespace(), result.Id, layer.Id, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.FlowingDashedLine.ToAnimationNamespace(), _testMapId, result.Id, layer.Id, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -334,9 +344,12 @@ public async Task Should_FlowingDashedLine_ThrowArgumentNullExceptionAsync() public async Task Should_DropMarkers_Async(bool disposeOnComplete) { var map = new Map("id", htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(null)); + _mapServiceMock.Setup(mapService => mapService.GetMap("id")).Returns(map); _mapServiceMock.Setup(mapService => mapService.Map).Returns(map); var marker1 = new HtmlMarker(new HtmlMarkerOptions()); + marker1.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(marker1, "id"); var marker2 = new HtmlMarker(new HtmlMarkerOptions()); + marker2.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(marker2, "id"); var height = 1m; var options = new DropMarkersAnimationOptions { DisposeOnComplete = disposeOnComplete @@ -346,17 +359,18 @@ public async Task Should_DropMarkers_Async(bool disposeOnComplete) Assert.IsType(result); Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - Assert.Contains(_mapServiceMock.Object.Map.HtmlMarkers, marker => marker.Id == marker1.Id && marker.Options == marker1.Options); - Assert.Contains(_mapServiceMock.Object.Map.HtmlMarkers, marker => marker.Id == marker2.Id && marker.Options == marker2.Options); + Assert.Contains(map.HtmlMarkers, marker => marker.Id == marker1.Id && marker.Options == marker1.Options); + Assert.Contains(map.HtmlMarkers, marker => marker.Id == marker2.Id && marker.Options == marker2.Options); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.DropMarkers.ToAnimationNamespace(), It.Is(parameters => - parameters[0] as string == result.Id - && parameters[1] is IEnumerable - && (parameters[1] as IEnumerable).Any(marker => marker.Id == marker1.Id && marker.Options == marker1.Options) - && (parameters[1] as IEnumerable).Any(marker => marker.Id == marker2.Id && marker.Options == marker2.Options) - && parameters[2] as decimal? == height - && parameters[3] is DropMarkersAnimationOptions - && parameters[4] is DotNetObjectReference + parameters[0] as string == map.Id + && parameters[1] as string == result.Id + && parameters[2] is IEnumerable + && (parameters[2] as IEnumerable).Any(marker => marker.Id == marker1.Id && marker.Options == marker1.Options) + && (parameters[2] as IEnumerable).Any(marker => marker.Id == marker2.Id && marker.Options == marker2.Options) + && parameters[3] as decimal? == height + && parameters[4] is DropMarkersAnimationOptions + && parameters[5] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -377,8 +391,10 @@ public async Task Should_DropMarkers_ThrowArgumentNullExceptionAsync() public async Task Should_DropMarker_Async(bool disposeOnComplete) { var map = new Map("id", htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(null)); + _mapServiceMock.Setup(mapService => mapService.GetMap("id")).Returns(map); _mapServiceMock.Setup(mapService => mapService.Map).Returns(map); var marker1 = new HtmlMarker(new HtmlMarkerOptions()); + marker1.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(marker1, "id"); var height = 1m; var options = new DropMarkersAnimationOptions { DisposeOnComplete = disposeOnComplete @@ -389,15 +405,16 @@ public async Task Should_DropMarker_Async(bool disposeOnComplete) Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - Assert.Contains(_mapServiceMock.Object.Map.HtmlMarkers, marker => marker.Id == marker1.Id && marker.Options == marker1.Options); + Assert.Contains(map.HtmlMarkers, marker => marker.Id == marker1.Id && marker.Options == marker1.Options); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.DropMarkers.ToAnimationNamespace(), It.Is(parameters => - parameters[0] as string == result.Id - && parameters[1] is IEnumerable - && (parameters[1] as IEnumerable).Any(marker => marker.Id == marker1.Id && marker.Options == marker1.Options) - && parameters[2] as decimal? == height - && parameters[3] is DropMarkersAnimationOptions - && parameters[4] is DotNetObjectReference + parameters[0] as string == map.Id + && parameters[1] as string == result.Id + && parameters[2] is IEnumerable + && (parameters[2] as IEnumerable).Any(marker => marker.Id == marker1.Id && marker.Options == marker1.Options) + && parameters[3] as decimal? == height + && parameters[4] is DropMarkersAnimationOptions + && parameters[5] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -423,13 +440,8 @@ public async Task Should_GroupAnimations_Async() Assert.IsType(result); Assert.NotNull((result as GroupAnimation).Id); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.GroupAnimations.ToAnimationNamespace(), It.Is(parameters => - parameters[0] as string == result.Id - && parameters[1] is IEnumerable - && (parameters[1] as IEnumerable).Contains(animation1.Id) - && (parameters[1] as IEnumerable).Contains(animation2.Id) - && parameters[2] is GroupAnimationOptions - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.GroupAnimations.ToAnimationNamespace(), result.Id, It.Is>(animationIds => + animationIds.Contains(animation1.Id) && animationIds.Contains(animation2.Id)), options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -452,6 +464,7 @@ public async Task Should_DropMultiple_Async(bool disposeOnComplete) var point2 = new Point(); var points = new[] { point, point2 }; var datasource = new DataSource(); + datasource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(datasource, _testMapId); var options = new DropAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -462,7 +475,7 @@ public async Task Should_DropMultiple_Async(bool disposeOnComplete) Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Drop.ToAnimationNamespace(), result.Id, points, datasource.Id, height, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Drop.ToAnimationNamespace(), _testMapId, result.Id, points, datasource.Id, height, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -500,6 +513,7 @@ public async Task Should_Drop_Async(bool disposeOnComplete) { var point = new Point(); var datasource = new DataSource(); + datasource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(datasource, _testMapId); var options = new DropAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -511,12 +525,13 @@ public async Task Should_Drop_Async(bool disposeOnComplete) Assert.Equal(disposeOnComplete, result.Disposed); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Drop.ToAnimationNamespace(), It.Is(parameters => - parameters[0] as string == result.Id - && parameters[1] is IEnumerable - && (parameters[1] as IEnumerable).Contains(point) - && parameters[2] as string == datasource.Id - && parameters[3] as decimal? == height - && parameters[4] is DropAnimationOptions + parameters[0] as string == _testMapId + && parameters[1] as string == result.Id + && parameters[2] is IEnumerable + && (parameters[2] as IEnumerable).Contains(point) + && parameters[3] as string == datasource.Id + && parameters[4] as decimal? == height + && parameters[5] is DropAnimationOptions )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -553,6 +568,7 @@ public async Task Should_SetCoordinatesAsync(bool disposeOnComplete) { var point = new Point(); var datasource = new DataSource(); + datasource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(datasource, _testMapId); var options = new SetCoordinatesAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -563,7 +579,7 @@ public async Task Should_SetCoordinatesAsync(bool disposeOnComplete) Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), result.Id, point.Id, datasource.Id, newCoordinates, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), _testMapId, result.Id, point.Id, datasource.Id, newCoordinates, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -574,7 +590,7 @@ public async Task Should_SetCoordinates_ThrowArgumentNullException_PointCaseAsyn var options = new SetCoordinatesAnimationOptions(); var newCoordinates = new Position(); - await Assert.ThrowsAnyAsync(async() => await _animationService.SetCoordinatesAsync(null, datasource, newCoordinates, options)); + await Assert.ThrowsAnyAsync(async () => await _animationService.SetCoordinatesAsync(null, datasource, newCoordinates, options)); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -609,6 +625,7 @@ public async Task Should_SetCoordinates_ThrowArgumentNullException_NewCoordinate public async Task Should_SetCoordinates_HtmlMarker_Async(bool disposeOnComplete) { var marker = new HtmlMarker(new HtmlMarkerOptions()); + marker.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(marker, _testMapId); var options = new SetCoordinatesAnimationOptions { DisposeOnComplete = disposeOnComplete }; @@ -619,7 +636,7 @@ public async Task Should_SetCoordinates_HtmlMarker_Async(bool disposeOnComplete) Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), result.Id, marker.Id, null, newCoordinates, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.SetCoordinates.ToAnimationNamespace(), _testMapId, result.Id, marker.Id, null, newCoordinates, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -652,6 +669,7 @@ public async Task Should_Morph_Async(bool disposeOnComplete) { var geometry = new Point(); var dataSource = new DataSource(); + dataSource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(dataSource, _testMapId); var newGeometry = new Polygon(); var options = new MorphAnimationOptions { DisposeOnComplete = disposeOnComplete @@ -663,7 +681,7 @@ public async Task Should_Morph_Async(bool disposeOnComplete) Assert.NotNull(result.Id); Assert.Equal(disposeOnComplete, result.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Morph.ToAnimationNamespace(), result.Id, geometry.Id, dataSource.Id, newGeometry, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.Morph.ToAnimationNamespace(), _testMapId, result.Id, geometry.Id, dataSource.Id, newGeometry, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -674,7 +692,7 @@ public async Task Should_Morph_ThrowArgumentNullException_GeometryCaseAsync() var newGeometry = new Polygon(); var options = new MorphAnimationOptions(); - await Assert.ThrowsAnyAsync(async() => await _animationService.MorphAsync(null, dataSource, newGeometry, options)); + await Assert.ThrowsAnyAsync(async () => await _animationService.MorphAsync(null, dataSource, newGeometry, options)); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -709,6 +727,7 @@ public async Task Should_MoveAlongRoute_Async() { var routePoints = new List(); var dataSource = new DataSource(); + dataSource.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(dataSource, _testMapId); var pin = new Point(); var options = new RoutePathAnimationOptions(); @@ -716,7 +735,7 @@ public async Task Should_MoveAlongRoute_Async() Assert.IsType(result); Assert.NotNull(result.Id); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), result.Id, routePoints, dataSource.Id, pin.Id, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), _testMapId, result.Id, routePoints, dataSource.Id, pin.Id, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -727,7 +746,7 @@ public async Task Should_MoveAlongRoute_ThrowArgumentNullException_RoutePointsCa var pin = new Point(); var options = new RoutePathAnimationOptions(); - await Assert.ThrowsAnyAsync(async() => await _animationService.MoveAlongRouteAsync(null, pin, dataSource, options)); + await Assert.ThrowsAnyAsync(async () => await _animationService.MoveAlongRouteAsync(null, pin, dataSource, options)); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -761,13 +780,14 @@ public async Task Should_MoveAlongRoute_HtmlMarker_Async() { var routePoints = new List(); var pin = new HtmlMarker(new HtmlMarkerOptions()); + pin.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(pin, _testMapId); var options = new RoutePathAnimationOptions(); var result = await _animationService.MoveAlongRouteAsync(routePoints, pin, options); Assert.IsType(result); Assert.NotNull(result.Id); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), result.Id, routePoints, null, pin.Id, options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Animation.MoveAlongRoute.ToAnimationNamespace(), _testMapId, result.Id, routePoints, null, pin.Id, options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -777,7 +797,7 @@ public async Task Should_MoveAlongRoute_HtmlMarker_ThrowArgumentNullException_Ro var pin = new HtmlMarker(new HtmlMarkerOptions()); var options = new RoutePathAnimationOptions(); - await Assert.ThrowsAnyAsync(async() => await _animationService.MoveAlongRouteAsync(null, pin, options)); + await Assert.ThrowsAnyAsync(async () => await _animationService.MoveAlongRouteAsync(null, pin, options)); _jsRuntimeMock.VerifyNoOtherCalls(); } diff --git a/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs b/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs index e31d97d..bdf014c 100644 --- a/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs +++ b/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs @@ -75,6 +75,7 @@ public class FullScreenControlTests { private readonly Mock _jsRuntimeMock = new(); private readonly Mock _loggerMock = new(); + private readonly string _testMapId = "test-map-id"; [Fact] public async Task Should_DisposeAsync() @@ -83,6 +84,8 @@ public async Task Should_DisposeAsync() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); var eventTriggered = false; control.OnDisposed += () => eventTriggered = true; @@ -91,7 +94,7 @@ public async Task Should_DisposeAsync() Assert.True(control.Disposed); Assert.True(eventTriggered); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), control.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -114,6 +117,8 @@ public async Task Should_NotDisposeTwice_Async() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); var eventTriggered = false; control.OnDisposed += () => eventTriggered = true; @@ -124,7 +129,7 @@ public async Task Should_NotDisposeTwice_Async() Assert.True(control.Disposed); Assert.True(eventTriggered); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), control.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -135,12 +140,14 @@ public async Task Should_SetOptionsAsync() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.SetOptionsAsync(options => options.Container = "container"); Assert.Equal("container", control.Options.Container); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), control.Id, control.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString(), control.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -151,12 +158,14 @@ public async Task Should_SetOptions_NoOptionsCase_Async() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.SetOptionsAsync(options => options.Container = "container"); Assert.Equal("container", control.Options.Container); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), control.Id, control.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString(), control.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -178,11 +187,13 @@ public async Task Should_NotSetOptions_DisposedCase_Async() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.SetOptionsAsync(options => options.Container = "container")); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), control.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -195,11 +206,13 @@ public async Task Should_GetIsFullScreenAsync() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); var result = await control.IsFullScreenAsync(); Assert.Equal(isFullScreen, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), control.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -221,11 +234,13 @@ public async Task Should_NotGetIsFullScreen_DisposedCase_Async() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.IsFullScreenAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), control.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -236,15 +251,18 @@ public async Task Should_AddEvents_Async() JsRuntime = _jsRuntimeMock.Object, Logger = _loggerMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.AddEventsAsync(); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.AddEvents.ToFullScreenControlNamespace(), It.Is(parameters => - (parameters[0] as Guid?).GetValueOrDefault() == control.Id - && parameters[1] is IEnumerable - && (parameters[1] as IEnumerable).Single() == FullScreenEventType.FullScreenChanged.ToString() - && parameters[2] is DotNetObjectReference - )), Times.Once); + parameters[0] as string == _testMapId + && parameters[1] as string == control.Id.ToString() + && parameters[2] is IEnumerable + && (parameters[2] as IEnumerable).Single() == FullScreenEventType.FullScreenChanged.ToString() + && parameters[3] is DotNetObjectReference + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } diff --git a/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs b/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs index ff6cf60..e2f6c63 100644 --- a/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs +++ b/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs @@ -21,6 +21,7 @@ public class GeolocationControlTests { private readonly Mock _mapJsRuntimeMock = new Mock(); + private readonly string _testMapId = "test-map-id"; [Fact] public async Task Should_GetLastKnowPositionAsync() @@ -31,11 +32,13 @@ public async Task Should_GetLastKnowPositionAsync() var control = new GeolocationControl() { JsRuntime = _mapJsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); var result = await control.GetLastKnownPositionAsync(); Assert.Equal(feature, result); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), control.Id), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -45,11 +48,13 @@ public async Task Should_NotGetLastKnowPosition_IfAlreadyDisposed_Async() var control = new GeolocationControl() { JsRuntime = _mapJsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.GetLastKnownPositionAsync()); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), control.Id), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -69,6 +74,8 @@ public async Task Should_DisposeAsync() var control = new GeolocationControl() { JsRuntime = _mapJsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); var disposedCalled = false; control.OnDisposed += () => disposedCalled = true; @@ -77,7 +84,7 @@ public async Task Should_DisposeAsync() Assert.True(control.Disposed); Assert.True(disposedCalled); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), control.Id), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -87,10 +94,13 @@ public async Task Should_NotDispose_IfAlreadyDisposed_Async() var control = new GeolocationControl() { JsRuntime = _mapJsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); + await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.DisposeAsync()); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), control.Id), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -109,12 +119,14 @@ public async Task Should_SetOptions_Async() var control = new GeolocationControl() { JsRuntime = _mapJsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.SetOptionsAsync(options => options.CalculateMissingValues = true); Assert.True(control.Options.CalculateMissingValues); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), control.Id, control.Options), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString(), control.Options), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -124,11 +136,13 @@ public async Task Should_NotSetOptions_DisposedCase_Async() var control = new GeolocationControl() { JsRuntime = _mapJsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.SetOptionsAsync(options => options.CalculateMissingValues = true)); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), control.Id), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -148,15 +162,18 @@ public async Task Should_AddEvents_Async() var control = new GeolocationControl(eventFlags: GeolocationEventActivationFlags.None().Enable(GeolocationEventType.GeolocationError)) { JsRuntime = _mapJsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.AddEventsAsync(); _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.AddEvents.ToGeolocationControlNamespace(), It.Is(parameters => - (parameters[0] as Guid?).GetValueOrDefault() == control.Id - && parameters[1] is IEnumerable - && (parameters[1] as IEnumerable).Single() == GeolocationEventType.GeolocationError.ToString() - && parameters[2] is DotNetObjectReference - )), Times.Once); + parameters[0] as string == _testMapId + && parameters[1] as string == control.Id.ToString() + && parameters[2] is IEnumerable + && (parameters[2] as IEnumerable).Single() == GeolocationEventType.GeolocationError.ToString() + && parameters[3] is DotNetObjectReference +)), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } diff --git a/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs b/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs index 27529ea..67a110c 100644 --- a/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs +++ b/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs @@ -16,6 +16,7 @@ public class OverviewMapControlTests { private readonly Mock _jsRuntimeMock = new(); + private readonly string _testMapId = "test-map-id"; [Fact] public void Should_Create() @@ -37,13 +38,16 @@ public async Task Should_UpdateAsync() var control = new OverviewMapControl(options, position) { JsRuntime = _jsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.UpdateAsync(options => options.Interactive = true); Assert.True(options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - (parameters[0] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() - && (parameters[1] as OverviewMapControlOptions) == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && parameters[1] as string == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -65,13 +69,16 @@ public async Task Should_SetOptionsAsync() var control = new OverviewMapControl(options, position) { JsRuntime = _jsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.SetOptionsAsync(options => options.Interactive = true); Assert.True(options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - (parameters[0] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() - && (parameters[1] as OverviewMapControlOptions) == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && parameters[1] as string == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -91,13 +98,16 @@ public async Task Should_UpdateAsyncWithDefaultOptionsAsync() var control = new OverviewMapControl { JsRuntime = _jsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.UpdateAsync(options => options.Interactive = true); Assert.True(control.Options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - (parameters[0] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() - && (parameters[1] as OverviewMapControlOptions) == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && parameters[1] as string == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -107,13 +117,16 @@ public async Task Should_SetOptionsAsyncWithDefaultOptionsAsync() var control = new OverviewMapControl { JsRuntime = _jsRuntimeMock.Object }; + // Set the MapId on the control as would happen when added to map + control.GetType().GetProperty("MapId", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(control, _testMapId); await control.SetOptionsAsync(options => options.Interactive = true); Assert.True(control.Options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - (parameters[0] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() - && (parameters[1] as OverviewMapControlOptions) == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && parameters[1] as string == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } } @@ -153,36 +166,36 @@ public void Should_WriteWithControlStyle() }, ControlPosition.BottomLeft); var expectedJson = "{" - + "\"id\":\"" + control.Id + "\"" - + ",\"type\":\"" + control.Type + "\"" - + ",\"position\":\"" + control.Position.ToString() + "\"" - + ",\"options\":{" - + "\"height\":" + control.Options.Height.Value - + ",\"interactive\":" + control.Options.Interactive.Value - + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" - + ",\"markerOptions\":{" - + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" - + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" - + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value - + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" - + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" - + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" + + "\"id\":\"" + control.Id + "\"" + + ",\"type\":\"" + control.Type + "\"" + + ",\"position\":\"" + control.Position.ToString() + "\"" + + ",\"options\":{" + + "\"height\":" + control.Options.Height.Value + + ",\"interactive\":" + control.Options.Interactive.Value + + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" + + ",\"markerOptions\":{" + + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" + + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" + + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value + + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" + + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" + + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" + ",\"secondaryColor\":\"" + control.Options.MarkerOptions.SecondaryColor.ToString() + "\"" - + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" - + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value - + "}" - + ",\"minimized\":" + control.Options.Minimized.Value + + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" + + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value + + "}" + + ",\"minimized\":" + control.Options.Minimized.Value + ",\"overlay\":\"" + control.Options.Overlay.ToString() + "\"" - + ",\"showToggle\":" + control.Options.ShowToggle.Value - + ",\"style\":\"" + control.Options.Style.FirstChoice.ToString() + "\"" + + ",\"showToggle\":" + control.Options.ShowToggle.Value + + ",\"style\":\"" + control.Options.Style.FirstChoice.ToString() + "\"" + ",\"syncBearingPitch\":" + control.Options.SyncBearingPitch.Value - + ",\"syncZoom\":" + control.Options.SyncZoom.Value - + ",\"visible\":" + control.Options.Visible.Value - + ",\"width\":" + control.Options.Width.Value - + ",\"zoom\":" + control.Options.Zoom.Value - + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value - + "}" - + "}"; + + ",\"syncZoom\":" + control.Options.SyncZoom.Value + + ",\"visible\":" + control.Options.Visible.Value + + ",\"width\":" + control.Options.Width.Value + + ",\"zoom\":" + control.Options.Zoom.Value + + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value + + "}" + + "}"; TestAndAssertWrite(control, expectedJson); } @@ -218,36 +231,36 @@ public void Should_WriteWithCssStyle() }, ControlPosition.BottomLeft); var expectedJson = "{" - + "\"id\":\"" + control.Id + "\"" - + ",\"type\":\"" + control.Type + "\"" - + ",\"position\":\"" + control.Position.ToString() + "\"" - + ",\"options\":{" - + "\"height\":" + control.Options.Height.Value - + ",\"interactive\":" + control.Options.Interactive.Value - + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" - + ",\"markerOptions\":{" - + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" - + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" - + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value - + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" - + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" - + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" - + ",\"secondaryColor\":\"" + control.Options.MarkerOptions.SecondaryColor.ToString() + "\"" - + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" - + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value - + "}" - + ",\"minimized\":" + control.Options.Minimized.Value - + ",\"overlay\":\"" + control.Options.Overlay.ToString() + "\"" - + ",\"showToggle\":" + control.Options.ShowToggle.Value - + ",\"style\":\"" + control.Options.Style.SecondChoice + "\"" - + ",\"syncBearingPitch\":" + control.Options.SyncBearingPitch.Value - + ",\"syncZoom\":" + control.Options.SyncZoom.Value - + ",\"visible\":" + control.Options.Visible.Value - + ",\"width\":" + control.Options.Width.Value - + ",\"zoom\":" + control.Options.Zoom.Value - + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value - + "}" - + "}"; + + "\"id\":\"" + control.Id + "\"" + + ",\"type\":\"" + control.Type + "\"" + + ",\"position\":\"" + control.Position.ToString() + "\"" + + ",\"options\":{" + + "\"height\":" + control.Options.Height.Value + + ",\"interactive\":" + control.Options.Interactive.Value + + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" + + ",\"markerOptions\":{" + + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" + + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" + + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value + + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" + + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" + + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" + + ",\"secondaryColor\":\"" + control.Options.MarkerOptions.SecondaryColor.ToString() + "\"" + + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" + + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value + + "}" + + ",\"minimized\":" + control.Options.Minimized.Value + + ",\"overlay\":\"" + control.Options.Overlay.ToString() + "\"" + + ",\"showToggle\":" + control.Options.ShowToggle.Value + + ",\"style\":\"" + control.Options.Style.SecondChoice + "\"" + + ",\"syncBearingPitch\":" + control.Options.SyncBearingPitch.Value + + ",\"syncZoom\":" + control.Options.SyncZoom.Value + + ",\"visible\":" + control.Options.Visible.Value + + ",\"width\":" + control.Options.Width.Value + + ",\"zoom\":" + control.Options.Zoom.Value + + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value + + "}" + + "}"; TestAndAssertWrite(control, expectedJson); } diff --git a/tests/AzureMapsControl.Components.Tests/Data/DataSource.cs b/tests/AzureMapsControl.Components.Tests/Data/DataSource.cs index b9b4495..cff9c29 100644 --- a/tests/AzureMapsControl.Components.Tests/Data/DataSource.cs +++ b/tests/AzureMapsControl.Components.Tests/Data/DataSource.cs @@ -20,6 +20,7 @@ public class DataSourceTests { private readonly Mock _jsRuntimeMock = new(); + private const string TestMapId = "test-map-id"; [Theory] [InlineData(null)] @@ -51,7 +52,7 @@ public void Should_HaveIdAffected() [Fact] public async Task Should_AddShapes_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shapes = new List { new Shape(new Point()), @@ -74,39 +75,45 @@ public async Task Should_AddShapes_Async() Assert.Contains(shapes[6], dataSource.Shapes); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Exactly(7)); _jsRuntimeMock.VerifyNoOtherCalls(); } - [Fact] public async Task Should_NotAddShapes_NotAddedToMapCase_Async() { @@ -124,7 +131,7 @@ public async Task Should_NotAddShapes_NotAddedToMapCase_Async() [Fact] public async Task Should_NotAddShapes_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); var shapes = new List { @@ -133,15 +140,14 @@ public async Task Should_NotAddShapes_DisposedCase_Async() await Assert.ThrowsAnyAsync(async () => await dataSource.AddAsync(shapes)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } - [Fact] public async Task Should_AddLineStringsShapes_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shapes = new List { new Shape(new LineString()), @@ -154,8 +160,9 @@ public async Task Should_AddLineStringsShapes_Async() Assert.Contains(shapes[1], dataSource.Shapes); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -163,7 +170,7 @@ public async Task Should_AddLineStringsShapes_Async() [Fact] public async Task Should_AddFeatures_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var features = new List { new Feature(), @@ -186,32 +193,39 @@ public async Task Should_AddFeatures_Async() Assert.Contains(features[6], dataSource.Features); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> - )), Times.Once); + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> + )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Exactly(7)); @@ -235,7 +249,7 @@ public async Task Should_NotAddFeatures_NotAddedToMapCase_Async() [Fact] public async Task Should_NotAddFeatures_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); var features = new List { @@ -244,14 +258,14 @@ public async Task Should_NotAddFeatures_DisposedCase_Async() await Assert.ThrowsAnyAsync(async () => await dataSource.AddAsync(features)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_AddFeatures_ParamsVersionAsync() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point = new Feature(); var lineString = new Feature(); @@ -272,32 +286,39 @@ public async Task Should_AddFeatures_ParamsVersionAsync() Assert.Contains(routePoint, dataSource.Features); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Exactly(7)); @@ -307,7 +328,7 @@ public async Task Should_AddFeatures_ParamsVersionAsync() [Fact] public async Task Should_AddShapes_Params_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point0 = new Shape(new Point()); var point1 = new Shape(new Point()); @@ -318,8 +339,9 @@ public async Task Should_AddShapes_Params_Async() Assert.Contains(point1, dataSource.Shapes); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -327,7 +349,7 @@ public async Task Should_AddShapes_Params_Async() [Fact] public async Task Should_NotCallAddCallbackIfGeometriesAreEmpty_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.AddAsync(new List()); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -337,7 +359,7 @@ public async Task Should_NotCallAddCallbackIfGeometriesAreEmpty_Async() public async Task Should_NotCallAddCallbackIfGeometriesAreNull_Async() { IEnumerable shapes = null; - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.AddAsync(shapes); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -346,15 +368,16 @@ public async Task Should_NotCallAddCallbackIfGeometriesAreNull_Async() [Fact] public async Task Should_ImportDataFromUrl_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; const string url = "someurl"; await dataSource.ImportDataFromUrlAsync(url); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.ImportDataFromUrl.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] as string == url + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] as string == url )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -374,21 +397,21 @@ public async Task Should_NotImportDataFromUrl_NotAddedToMapCase_Async() [Fact] public async Task Should_NotImportDataFromUrl_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); const string url = "someurl"; await Assert.ThrowsAnyAsync(async () => await dataSource.ImportDataFromUrlAsync(url)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapes_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List { point1, point2 }; @@ -401,16 +424,17 @@ public async Task Should_RemoveShapes_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveFeatures_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List { point1, point2 }; @@ -423,16 +447,17 @@ public async Task Should_RemoveFeatures_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapes_EnumerableVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List { point1, point2 }; @@ -445,16 +470,17 @@ public async Task Should_RemoveShapes_EnumerableVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveFeatures_EnumerableVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List { point1, point2 }; @@ -467,16 +493,17 @@ public async Task Should_RemoveFeatures_EnumerableVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapes_IdsVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List { point1, point2 }; @@ -489,16 +516,17 @@ public async Task Should_RemoveShapes_IdsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveFeatures_IdsVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List { point1, point2 }; @@ -511,16 +539,17 @@ public async Task Should_RemoveFeatures_IdsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapesAndFeatures_IdsVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var point3 = new Shape("point3", new Point()); @@ -541,17 +570,18 @@ public async Task Should_RemoveShapesAndFeatures_IdsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Contains(point1.Id) - && (parameters[1] as IEnumerable).Contains(point3.Id) - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Contains(point1.Id) + && (parameters[2] as IEnumerable).Contains(point3.Id) + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapes_IdsEnumerableVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List { point1, point2 }; @@ -564,16 +594,17 @@ public async Task Should_RemoveShapes_IdsEnumerableVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveFeatures_IdsEnumerableVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List { point1, point2 }; @@ -586,16 +617,17 @@ public async Task Should_RemoveFeatures_IdsEnumerableVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_NotRemoveShapes_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); @@ -609,7 +641,7 @@ public async Task Should_NotRemoveShapes_Async() [Fact] public async Task Should_NotRemoveFeatures_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); @@ -623,7 +655,7 @@ public async Task Should_NotRemoveFeatures_Async() [Fact] public async Task Should_NotRemoveShape_NullCheck_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); await dataSource.RemoveAsync(point1); @@ -634,7 +666,7 @@ public async Task Should_NotRemoveShape_NullCheck_Async() [Fact] public async Task Should_NotRemoveShapesNorFeatures_NullCheck_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -653,7 +685,7 @@ public async Task Should_NotRemoveShapesNorFeatures_NullCheck_Async() [Fact] public async Task Should_NotRemoveShapesButOnlyFeatures_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -667,16 +699,17 @@ public async Task Should_NotRemoveShapesButOnlyFeatures_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == feature.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == feature.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_NotRemoveFeaturesButOnlyShapes_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -690,16 +723,17 @@ public async Task Should_NotRemoveFeaturesButOnlyShapes_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == shape.Id - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == shape.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapesAndFeatures_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -713,17 +747,18 @@ public async Task Should_RemoveShapesAndFeatures_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Contains(shape.Id) - && (parameters[1] as IEnumerable).Contains(feature.Id) - )), Times.Once); + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Contains(shape.Id) + && (parameters[2] as IEnumerable).Contains(feature.Id) + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_ClearDataSource_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point2 = new Shape("point2", new Point()); var feature = new Feature("point1", new Point()); @@ -736,7 +771,7 @@ public async Task Should_ClearDataSource_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -753,22 +788,22 @@ public async Task Should_ClearDataSource_NotAddedToMapCase_Async() [Fact] public async Task Should_ClearDataSource_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.ClearAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_DisposeAsync() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); Assert.True(dataSource.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -785,10 +820,10 @@ public async Task Should_NotDispose_NotAddedToMapCase_Async() [Fact] public async Task Should_NotDispose_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.DisposeAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -797,13 +832,13 @@ public async Task Should_GetOptionsAsync() { var options = new DataSourceOptions(); _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var result = await dataSource.GetOptionsAsync(); Assert.Equal(options, result); Assert.Equal(options, dataSource.Options); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Source.GetOptions.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Source.GetOptions.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -820,10 +855,10 @@ public async Task Should_NotGetOptions_NotAddedToMapCase_Async() [Fact] public async Task Should_NotGetOptions_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.GetOptionsAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -832,12 +867,12 @@ public async Task Should_GetShapesAsync() { var shapes = Array.Empty>(); _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync>>(It.IsAny(), It.IsAny())).ReturnsAsync(shapes); - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var result = await dataSource.GetShapesAsync(); Assert.Equal(shapes, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetShapes.ToDatasourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetShapes.ToDatasourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -854,10 +889,10 @@ public async Task Should_NotGetShapes_NotAddedToMapCase_Async() [Fact] public async Task Should_NotGetShapes_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.GetShapesAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -930,11 +965,11 @@ public void Should_Dispatch_SourceRemoved() public async Task Should_AddJson_Async() { var shapes = Array.Empty>(); - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.AddAsync("{}"); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatureCollection.ToSourceNamespace(), dataSource.Id, It.IsAny()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatureCollection.ToSourceNamespace(), TestMapId, dataSource.Id, It.IsAny()), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -942,7 +977,7 @@ public async Task Should_AddJson_Async() public async Task Should_NotAddInvalidJson_Async() { var shapes = Array.Empty>(); - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await Assert.ThrowsAnyAsync(async () => await dataSource.AddAsync("{")); @@ -961,10 +996,10 @@ public async Task Should_NotAddJson_NotAddedToMapCase_Async() [Fact] public async Task Should_NotAddJson_DisposedCase_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.AddAsync("{}")); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -972,13 +1007,13 @@ public async Task Should_NotAddJson_DisposedCase_Async() public async Task Should_AddJson_JsonVersion_Async() { var shapes = Array.Empty>(); - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var jsonDocument = JsonDocument.Parse("{}"); await dataSource.AddAsync(jsonDocument); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatureCollection.ToSourceNamespace(), dataSource.Id, jsonDocument), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatureCollection.ToSourceNamespace(), TestMapId, dataSource.Id, jsonDocument), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -995,11 +1030,11 @@ public async Task Should_NotAddJson_NotAddedToMapCase_JsonVersion_Async() [Fact] public async Task Should_NotAddJson_DisposedCase_JsonVersion_Async() { - var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new DataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); var jsonDocument = JsonDocument.Parse("{}"); await Assert.ThrowsAnyAsync(async () => await dataSource.AddAsync(jsonDocument)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1008,6 +1043,7 @@ public async Task Should_SetOptionsAsync() { var datasource = new DataSource { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, Options = new DataSourceOptions { Buffer = 1 } @@ -1017,7 +1053,7 @@ public async Task Should_SetOptionsAsync() Assert.Equal(1, datasource.Options.Buffer); Assert.Equal(2, datasource.Options.ClusterMaxZoom); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), datasource.Id, datasource.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), TestMapId, datasource.Id, datasource.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1025,13 +1061,14 @@ public async Task Should_SetOptionsAsync() public async Task Should_SetOptions_NoInitialValueAsync() { var datasource = new DataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.SetOptionsAsync(options => options.ClusterMaxZoom = 2); Assert.Equal(2, datasource.Options.ClusterMaxZoom); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), datasource.Id, datasource.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), TestMapId, datasource.Id, datasource.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1049,13 +1086,14 @@ public async Task Should_NotSetOptions_NotAddedToMapCase_Async() public async Task Should_NotSetOptions_DisposedCase_Async() { var datasource = new DataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await datasource.SetOptionsAsync(options => options.ClusterMaxZoom = 2)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1063,7 +1101,8 @@ public async Task Should_NotSetOptions_DisposedCase_Async() public async Task Should_GetClusterLeaves() { var datasource = new DataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var expected = Enumerable.Empty>(); @@ -1076,7 +1115,7 @@ public async Task Should_GetClusterLeaves() Assert.Equal(expected, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetClusterLeaves.ToDatasourceNamespace(), datasource.Id, clusterId, limit, offset), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.Datasource.GetClusterLeaves.ToDatasourceNamespace(), TestMapId, datasource.Id, clusterId, limit, offset), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1094,14 +1133,15 @@ public async Task Should_NotGetClusterLeaves_NotAddedToMapCase() public async Task Should_NotGetClusterLeaves_DisposedCase() { var datasource = new DataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); await Assert.ThrowsAsync(async () => await datasource.GetClusterLeavesAsync(1, 2, 3)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1109,7 +1149,8 @@ public async Task Should_NotGetClusterLeaves_DisposedCase() public async Task Should_GetClusterExpansionZoom() { var datasource = new DataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var expected = 2; @@ -1120,7 +1161,7 @@ public async Task Should_GetClusterExpansionZoom() Assert.Equal(expected, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Datasource.GetClusterExpansionZoom.ToDatasourceNamespace(), datasource.Id, clusterId), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Datasource.GetClusterExpansionZoom.ToDatasourceNamespace(), TestMapId, datasource.Id, clusterId), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1138,14 +1179,15 @@ public async Task Should_NotGetClusterExpansionZoom_NotAddedToMapCase() public async Task Should_NotGetClusterExpansionZoom_DisposedCase() { var datasource = new DataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); await Assert.ThrowsAsync(async () => await datasource.GetClusterExpansionZoomAsync(1)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } } diff --git a/tests/AzureMapsControl.Components.Tests/Data/Grid/GriddedDataSource.cs b/tests/AzureMapsControl.Components.Tests/Data/Grid/GriddedDataSource.cs index 1745795..b64cf4f 100644 --- a/tests/AzureMapsControl.Components.Tests/Data/Grid/GriddedDataSource.cs +++ b/tests/AzureMapsControl.Components.Tests/Data/Grid/GriddedDataSource.cs @@ -17,6 +17,7 @@ public class GriddedDataSourceTests { private readonly Mock _jsRuntimeMock = new(); + private const string TestMapId = "test-map-id"; [Theory] [InlineData(null)] @@ -48,7 +49,7 @@ public void Should_HaveIdAffected() [Fact] public async Task Should_AddShapes_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shapes = new List> { new Shape(new Point()) @@ -59,8 +60,9 @@ public async Task Should_AddShapes_Async() Assert.Contains(shapes[0], dataSource.Shapes); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -84,7 +86,7 @@ public async Task Should_NotAddShapes_NotAddedToMapCase_Async() [Fact] public async Task Should_NotAddShapes_DisposedCase_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); var shapes = new List> { @@ -93,14 +95,14 @@ public async Task Should_NotAddShapes_DisposedCase_Async() await Assert.ThrowsAnyAsync(async () => await dataSource.AddAsync(shapes)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_AddFeatures_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var features = new List> { new Feature() @@ -111,8 +113,9 @@ public async Task Should_AddFeatures_Async() Assert.Contains(features[0], dataSource.Features); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -134,7 +137,7 @@ public async Task Should_NotAddFeatures_NotAddedToMapCase_Async() [Fact] public async Task Should_NotAddFeatures_DisposedCase_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); var features = new List> { @@ -143,14 +146,14 @@ public async Task Should_NotAddFeatures_DisposedCase_Async() await Assert.ThrowsAnyAsync(async () => await dataSource.AddAsync(features)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_AddFeatures_ParamsVersionAsync() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point = new Feature(); @@ -159,8 +162,9 @@ public async Task Should_AddFeatures_ParamsVersionAsync() Assert.Contains(point, dataSource.Features); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -168,7 +172,7 @@ public async Task Should_AddFeatures_ParamsVersionAsync() [Fact] public async Task Should_AddShapes_Params_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point0 = new Shape(new Point()); var point1 = new Shape(new Point()); @@ -179,8 +183,9 @@ public async Task Should_AddShapes_Params_Async() Assert.Contains(point1, dataSource.Shapes); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] is IEnumerable> + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && parameters[2] is IEnumerable> )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -188,7 +193,7 @@ public async Task Should_AddShapes_Params_Async() [Fact] public async Task Should_NotCallAddCallbackIfGeometriesAreEmpty_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.AddAsync(new List>()); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -198,7 +203,7 @@ public async Task Should_NotCallAddCallbackIfGeometriesAreEmpty_Async() public async Task Should_NotCallAddCallbackIfGeometriesAreNull_Async() { IEnumerable> shapes = null; - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.AddAsync(shapes); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -221,21 +226,21 @@ public async Task Should_NotImportDataFromUrl_NotAddedToMapCase_Async() [Fact] public async Task Should_NotImportDataFromUrl_DisposedCase_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); const string url = "someurl"; await Assert.ThrowsAnyAsync(async () => await dataSource.ImportDataFromUrlAsync(url)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapes_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List> { point1, point2 }; @@ -248,8 +253,9 @@ public async Task Should_RemoveShapes_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -257,7 +263,7 @@ public async Task Should_RemoveShapes_Async() [Fact] public async Task Should_RemoveFeatures_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List> { point1, point2 }; @@ -270,8 +276,9 @@ public async Task Should_RemoveFeatures_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -279,7 +286,7 @@ public async Task Should_RemoveFeatures_Async() [Fact] public async Task Should_RemoveShapes_EnumerableVersion_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List> { point1, point2 }; @@ -292,8 +299,9 @@ public async Task Should_RemoveShapes_EnumerableVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -301,7 +309,7 @@ public async Task Should_RemoveShapes_EnumerableVersion_Async() [Fact] public async Task Should_RemoveFeatures_EnumerableVersion_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List> { point1, point2 }; @@ -314,8 +322,9 @@ public async Task Should_RemoveFeatures_EnumerableVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -323,7 +332,7 @@ public async Task Should_RemoveFeatures_EnumerableVersion_Async() [Fact] public async Task Should_RemoveShapes_IdsVersion_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List> { point1, point2 }; @@ -336,8 +345,9 @@ public async Task Should_RemoveShapes_IdsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id + parameters => parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -345,7 +355,7 @@ public async Task Should_RemoveShapes_IdsVersion_Async() [Fact] public async Task Should_RemoveFeatures_IdsVersion_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List> { point1, point2 }; @@ -357,17 +367,18 @@ public async Task Should_RemoveFeatures_IdsVersion_Async() Assert.Contains(point2, dataSource.Features); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapesAndFeatures_IdsVersion_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var point3 = new Shape("point3", new Point()); @@ -387,18 +398,19 @@ public async Task Should_RemoveShapesAndFeatures_IdsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Contains(point1.Id) - && (parameters[1] as IEnumerable).Contains(point3.Id) - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Contains(point1.Id) + && (parameters[2] as IEnumerable).Contains(point3.Id) + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapes_IdsEnumerableVersion_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); var shapes = new List> { point1, point2 }; @@ -410,17 +422,18 @@ public async Task Should_RemoveShapes_IdsEnumerableVersion_Async() Assert.Contains(point2, dataSource.Shapes); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveFeatures_IdsEnumerableVersion_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); var features = new List> { point1, point2 }; @@ -432,17 +445,18 @@ public async Task Should_RemoveFeatures_IdsEnumerableVersion_Async() Assert.Contains(point2, dataSource.Features); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == point1.Id - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == point1.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_NotRemoveShapes_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); var point2 = new Shape("point2", new Point()); @@ -456,7 +470,7 @@ public async Task Should_NotRemoveShapes_Async() [Fact] public async Task Should_NotRemoveFeatures_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Feature("point1", new Point()); var point2 = new Feature("point2", new Point()); @@ -470,7 +484,7 @@ public async Task Should_NotRemoveFeatures_Async() [Fact] public async Task Should_NotRemoveShape_NullCheck_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point1 = new Shape("point1", new Point()); await dataSource.RemoveAsync(point1); @@ -481,7 +495,7 @@ public async Task Should_NotRemoveShape_NullCheck_Async() [Fact] public async Task Should_NotRemoveShapesNorFeatures_NullCheck_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -500,7 +514,7 @@ public async Task Should_NotRemoveShapesNorFeatures_NullCheck_Async() [Fact] public async Task Should_NotRemoveShapesButOnlyFeatures_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -513,17 +527,18 @@ public async Task Should_NotRemoveShapesButOnlyFeatures_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == feature.Id - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == feature.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_NotRemoveFeaturesButOnlyShapes_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -536,17 +551,18 @@ public async Task Should_NotRemoveFeaturesButOnlyShapes_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Single() == shape.Id - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Single() == shape.Id + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemoveShapesAndFeatures_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var shape = new Shape("point1", new Point()); var feature = new Feature("point2", new Point()); @@ -559,18 +575,19 @@ public async Task Should_RemoveShapesAndFeatures_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is( - parameters => parameters[0] as string == dataSource.Id - && (parameters[1] as IEnumerable).Contains(shape.Id) - && (parameters[1] as IEnumerable).Contains(feature.Id) - )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Remove.ToSourceNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] as string == dataSource.Id + && (parameters[2] as IEnumerable).Contains(shape.Id) + && (parameters[2] as IEnumerable).Contains(feature.Id) + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_ClearDataSource_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var point2 = new Shape("point2", new Point()); var feature = new Feature("point1", new Point()); @@ -583,7 +600,7 @@ public async Task Should_ClearDataSource_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToSourceNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddFeatures.ToSourceNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -600,22 +617,22 @@ public async Task Should_ClearDataSource_NotAddedToMapCase_Async() [Fact] public async Task Should_ClearDataSource_DisposedCase_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.ClearAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_DisposeAsync() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); Assert.True(dataSource.Disposed); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -632,10 +649,10 @@ public async Task Should_NotDispose_NotAddedToMapCase_Async() [Fact] public async Task Should_NotDispose_DisposedCase_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.DisposeAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -644,13 +661,13 @@ public async Task Should_GetOptionsAsync() { var options = new GriddedDataSourceOptions(); _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; var result = await dataSource.GetOptionsAsync(); Assert.Equal(options, result); Assert.Equal(options, dataSource.Options); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Source.GetOptions.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Source.GetOptions.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -667,10 +684,10 @@ public async Task Should_NotGetOptions_NotAddedToMapCase_Async() [Fact] public async Task Should_NotGetOptions_DisposedCase_Async() { - var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object }; + var dataSource = new GriddedDataSource() { JSRuntime = _jsRuntimeMock.Object, MapId = TestMapId }; await dataSource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await dataSource.GetOptionsAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -679,6 +696,7 @@ public async Task Should_SetOptionsAsync() { var datasource = new GriddedDataSource { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, Options = new GriddedDataSourceOptions { CellWidth = 1 } @@ -688,7 +706,7 @@ public async Task Should_SetOptionsAsync() Assert.Equal(1, datasource.Options.CellWidth); Assert.Equal(2, datasource.Options.CenterLatitude); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), datasource.Id, datasource.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), TestMapId, datasource.Id, datasource.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -696,13 +714,14 @@ public async Task Should_SetOptionsAsync() public async Task Should_SetOptions_NoInitialValueAsync() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.SetOptionsAsync(options => options.CenterLatitude = 2); Assert.Equal(2, datasource.Options.CenterLatitude); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), datasource.Id, datasource.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.SetOptions.ToSourceNamespace(), TestMapId, datasource.Id, datasource.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -720,13 +739,14 @@ public async Task Should_NotSetOptions_NotAddedToMapCase_Async() public async Task Should_NotSetOptions_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await datasource.SetOptionsAsync(options => options.CenterLatitude = 2)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -734,19 +754,20 @@ public async Task Should_NotSetOptions_DisposedCase_Async() public async Task Should_GetCellChildren_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var cellChildren = System.ArraySegment>.Empty; _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync>>(It.IsAny(), It.IsAny())) - .ReturnsAsync(cellChildren); + .ReturnsAsync(cellChildren); var cellId = "cellId"; var result = await datasource.GetCellChildrenAsync(cellId); Assert.Equal(cellChildren, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetCellChildren.ToGriddedDatasourceNamespace(), datasource.Id, cellId), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetCellChildren.ToGriddedDatasourceNamespace(), TestMapId, datasource.Id, cellId), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -764,13 +785,14 @@ public async Task Should_NotGetCellChildren_NotAddedToMapCase_Async() public async Task Should_NotGetCellChildren_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await datasource.GetCellChildrenAsync("cellId")); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -778,17 +800,18 @@ public async Task Should_NotGetCellChildren_DisposedCase_Async() public async Task Should_GetGridCells_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var gridCells = System.ArraySegment>.Empty; _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync>>(It.IsAny(), It.IsAny())) - .ReturnsAsync(gridCells); + .ReturnsAsync(gridCells); var result = await datasource.GetGridCellsAsync(); Assert.Equal(gridCells, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetGridCells.ToGriddedDatasourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetGridCells.ToGriddedDatasourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -806,13 +829,14 @@ public async Task Should_NotGetGridCells_NotAddedToMapCase_Async() public async Task Should_NotGetGridCells_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await datasource.GetGridCellsAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -820,17 +844,18 @@ public async Task Should_NotGetGridCells_DisposedCase_Async() public async Task Should_GetPoints_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var points = System.ArraySegment>.Empty; _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync>>(It.IsAny(), It.IsAny())) - .ReturnsAsync(points); + .ReturnsAsync(points); var result = await datasource.GetPointsAsync(); Assert.Equal(points, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetPoints.ToGriddedDatasourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync>>(Constants.JsConstants.Methods.GriddedDatasource.GetPoints.ToGriddedDatasourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -848,13 +873,14 @@ public async Task Should_NotGetPoint_NotAddedToMapCase_Async() public async Task Should_NotGetPoints_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await datasource.GetPointsAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -862,13 +888,14 @@ public async Task Should_NotGetPoints_DisposedCase_Async() public async Task Should_SetPoints_WithFeatureCollection_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var featureCollection = JsonDocument.Parse("{}"); await datasource.SetPointsAsync(featureCollection); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeatureCollectionPoints.ToGriddedDatasourceNamespace(), datasource.Id, featureCollection), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeatureCollectionPoints.ToGriddedDatasourceNamespace(), TestMapId, datasource.Id, featureCollection), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -887,14 +914,15 @@ public async Task Should_NotSetPoints_WithFeatureCollection_NotAddedToMapCase_As public async Task Should_NotSetPoints_WithFeatureCollection_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); var featureCollection = JsonDocument.Parse("{}"); await Assert.ThrowsAnyAsync(async () => await datasource.SetPointsAsync(featureCollection)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -902,13 +930,14 @@ public async Task Should_NotSetPoints_WithFeatureCollection_DisposedCase_Async() public async Task Should_SetPoints_WithFeaturePoints_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var features = new Feature[] { new Feature() }; await datasource.SetPointsAsync(features); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeaturePoints.ToGriddedDatasourceNamespace(), datasource.Id, features), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetFeaturePoints.ToGriddedDatasourceNamespace(), TestMapId, datasource.Id, features), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -927,14 +956,15 @@ public async Task Should_NotSetPoints_WithFeaturePoints_NotAddedToMapCase_Async( public async Task Should_NotSetPoints_WithFeaturePoints_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); var features = new Feature[] { new Feature() }; await Assert.ThrowsAnyAsync(async () => await datasource.SetPointsAsync(features)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -942,13 +972,14 @@ public async Task Should_NotSetPoints_WithFeaturePoints_DisposedCase_Async() public async Task Should_SetPoints_WithPoints_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var points = new Point[] { new Point() }; await datasource.SetPointsAsync(points); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetPoints.ToGriddedDatasourceNamespace(), datasource.Id, points), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetPoints.ToGriddedDatasourceNamespace(), TestMapId, datasource.Id, points), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -967,14 +998,15 @@ public async Task Should_NotSetPoints_WithPoints_NotAddedToMapCase_Async() public async Task Should_NotSetPoints_WithPoints_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); var points = new Point[] { new Point() }; await Assert.ThrowsAnyAsync(async () => await datasource.SetPointsAsync(points)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -982,13 +1014,14 @@ public async Task Should_NotSetPoints_WithPoints_DisposedCase_Async() public async Task Should_SetPoints_WithShapes_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var shapes = new Shape[] { new Shape() }; await datasource.SetPointsAsync(shapes); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetShapePoints.ToGriddedDatasourceNamespace(), datasource.Id, shapes), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GriddedDatasource.SetShapePoints.ToGriddedDatasourceNamespace(), TestMapId, datasource.Id, shapes), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1007,14 +1040,15 @@ public async Task Should_NotSetPoints_WithShapes_NotAddedToMapCase_Async() public async Task Should_NotSetPoints_WithShapes_DisposedCase_Async() { var datasource = new GriddedDataSource { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await datasource.DisposeAsync(); var shapes = new Shape[] { new Shape() }; await Assert.ThrowsAnyAsync(async () => await datasource.SetPointsAsync(shapes)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), datasource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Dispose.ToSourceNamespace(), TestMapId, datasource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } } diff --git a/tests/AzureMapsControl.Components.Tests/Drawing/DrawingManager.cs b/tests/AzureMapsControl.Components.Tests/Drawing/DrawingManager.cs index f6eab30..35ecda4 100644 --- a/tests/AzureMapsControl.Components.Tests/Drawing/DrawingManager.cs +++ b/tests/AzureMapsControl.Components.Tests/Drawing/DrawingManager.cs @@ -20,12 +20,13 @@ public class DrawingManagerTests { private readonly Mock _jsRuntimeMock = new(); private readonly Mock _loggerMock = new(); + private const string TestMapId = "test-map-id"; [Fact] public void Should_HaveDefaultProperties() { var drawingManager = new DrawingManager(); - + Assert.False(drawingManager.Disposed); Assert.Null(drawingManager.JSRuntime); Assert.Null(drawingManager.Logger); @@ -45,7 +46,7 @@ public async Task Should_AddShapes_AllSupportedGeometryTypes_Async() { var drawingManager = CreateInitializedDrawingManager(); - var shapes = new List + var shapes = new List { new Shape(new Point()), new Shape(new LineString()), @@ -58,13 +59,41 @@ public async Task Should_AddShapes_AllSupportedGeometryTypes_Async() await drawingManager.AddShapesAsync(shapes); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.IsAny()), Times.Exactly(7)); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -75,7 +104,7 @@ public async Task Should_AddMultipleShapesOfSameType_Async() { var drawingManager = CreateInitializedDrawingManager(); - var shapes = new List + var shapes = new List { new Shape(new Point()), new Shape(new Point()), @@ -84,7 +113,11 @@ public async Task Should_AddMultipleShapesOfSameType_Async() await drawingManager.AddShapesAsync(shapes); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 3)), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 3 + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -105,9 +138,21 @@ public async Task Should_HandleMixedGeometryTypes_InSingleCall_Async() await drawingManager.AddShapesAsync(shapes); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 2)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1)), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 3)), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 2 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1 + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 3 + )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.IsAny()), Times.Exactly(3)); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -128,7 +173,11 @@ public async Task Should_HandleLargeNumberOfShapes_Efficiently_Async() await drawingManager.AddShapesAsync(shapes); // Should still only make one call per geometry type - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is>>(s => s.Count() == 1000)), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.Is(parameters => + parameters[0] as string == TestMapId + && parameters[1] is IEnumerable> + && (parameters[1] as IEnumerable>).Count() == 1000 + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -159,7 +208,7 @@ public async Task Should_ClearShapes_Async() await drawingManager.ClearAsync(); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToDrawingNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToDrawingNamespace(), TestMapId), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -213,7 +262,7 @@ public async Task Should_ClearInternalState_WhenCleared_Async() Assert.Single(sourceShapes); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), It.IsAny()), Times.Exactly(2)); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToDrawingNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToDrawingNamespace(), TestMapId), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -296,7 +345,8 @@ private DrawingManager CreateInitializedDrawingManager() { return new DrawingManager() { JSRuntime = _jsRuntimeMock.Object, - Logger = _loggerMock.Object + Logger = _loggerMock.Object, + MapId = TestMapId }; } diff --git a/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs b/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs index 0f90895..b3c0a29 100644 --- a/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs +++ b/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using AzureMapsControl.Components.Indoor; + using AzureMapsControl.Components.Map; using AzureMapsControl.Components.Runtime; using Microsoft.Extensions.Logging; @@ -18,15 +19,84 @@ public class IndoorServiceTests { private readonly Mock _jsRuntime = new(); private readonly Mock> _logger = new(); + private readonly Mock _mapService = new(); + private const string TestMapId = "test-map-id"; + [Fact] + public async Task Should_CreateIndoorManager_WithMapId_Async() + { + var options = new IndoorManagerOptions(); + + var service = new IndoorService(_jsRuntime.Object, _logger.Object, _mapService.Object); + var indoorManager = await service.CreateIndoorManagerAsync(TestMapId, options); + + Assert.NotNull(indoorManager); + + _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.Is(parameters => + (parameters[0] as string) == TestMapId + && (parameters[1] as string) == indoorManager.Id + && object.Equals(parameters[2], options) + && parameters[3] == null + && parameters[4] is DotNetObjectReference + )), Times.Once); + _jsRuntime.VerifyNoOtherCalls(); + } + + [Fact] + public async Task Should_CreateIndoorManagerWithEvents_WithMapId_Async() + { + var options = new IndoorManagerOptions(); + var eventFlags = IndoorManagerEventActivationFlags.None().Enable(IndoorManagerEventType.FacilityChanged); + + var service = new IndoorService(_jsRuntime.Object, _logger.Object, _mapService.Object); + var indoorManager = await service.CreateIndoorManagerAsync(TestMapId, options, eventFlags); + + Assert.NotNull(indoorManager); + + _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.Is(parameters => + (parameters[0] as string) == TestMapId + && (parameters[1] as string) == indoorManager.Id + && object.Equals(parameters[2], options) + && parameters[3] is IEnumerable + && (parameters[3] as IEnumerable).Single() == "facilitychanged" + && parameters[4] is DotNetObjectReference + )), Times.Once); + _jsRuntime.VerifyNoOtherCalls(); + } + + [Fact] + public async Task Should_CreateIndoorManagerWithEvents_NullEventsCase_WithMapId_Async() + { + var options = new IndoorManagerOptions(); + + var service = new IndoorService(_jsRuntime.Object, _logger.Object, _mapService.Object); + var indoorManager = await service.CreateIndoorManagerAsync(TestMapId, options, null); + + Assert.NotNull(indoorManager); + + _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.Is(parameters => + (parameters[0] as string) == TestMapId + && (parameters[1] as string) == indoorManager.Id + && object.Equals(parameters[2], options) + && parameters[3] == null + && parameters[4] is DotNetObjectReference + )), Times.Once); + _jsRuntime.VerifyNoOtherCalls(); + } + + // Legacy method tests (for backward compatibility) [Fact] public async Task Should_CreateIndoorManager_Async() { var options = new IndoorManagerOptions(); - var service = new IndoorService(_jsRuntime.Object, _logger.Object); + // Create a real Map instance instead of mocking it since Map is sealed + var map = new AzureMapsControl.Components.Map.Map("test-map"); + _mapService.Setup(x => x.Map).Returns(map); + + var service = new IndoorService(_jsRuntime.Object, _logger.Object, _mapService.Object); Assert.NotNull(await service.CreateIndoorManagerAsync(options)); - _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.IsAny(), options, null, It.IsAny>()), Times.Once); + _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.IsAny(), It.IsAny(), options, null, It.IsAny>()), Times.Once); _jsRuntime.VerifyNoOtherCalls(); } @@ -34,10 +104,14 @@ public async Task Should_CreateIndoorManager_Async() public async Task Should_CreateIndoorManagerWithEvents_Async() { var options = new IndoorManagerOptions(); - var service = new IndoorService(_jsRuntime.Object, _logger.Object); + // Create a real Map instance instead of mocking it since Map is sealed + var map = new AzureMapsControl.Components.Map.Map("test-map"); + _mapService.Setup(x => x.Map).Returns(map); + + var service = new IndoorService(_jsRuntime.Object, _logger.Object, _mapService.Object); Assert.NotNull(await service.CreateIndoorManagerAsync(options, IndoorManagerEventActivationFlags.None().Enable(IndoorManagerEventType.FacilityChanged))); - _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.IsAny(), options, It.Is>(events => events.Single() == "facilitychanged"), It.IsAny>()), Times.Once); + _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.IsAny(), It.IsAny(), options, It.Is>(events => events.Single() == "facilitychanged"), It.IsAny>()), Times.Once); _jsRuntime.VerifyNoOtherCalls(); } @@ -45,10 +119,14 @@ public async Task Should_CreateIndoorManagerWithEvents_Async() public async Task Should_CreateIndoorManagerWithEvents_NullEventsCase_Async() { var options = new IndoorManagerOptions(); - var service = new IndoorService(_jsRuntime.Object, _logger.Object); + // Create a real Map instance instead of mocking it since Map is sealed + var map = new AzureMapsControl.Components.Map.Map("test-map"); + _mapService.Setup(x => x.Map).Returns(map); + + var service = new IndoorService(_jsRuntime.Object, _logger.Object, _mapService.Object); Assert.NotNull(await service.CreateIndoorManagerAsync(options, null)); - _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.IsAny(), options, null, It.IsAny>()), Times.Once); + _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.IsAny(), It.IsAny(), options, null, It.IsAny>()), Times.Once); _jsRuntime.VerifyNoOtherCalls(); } } diff --git a/tests/AzureMapsControl.Components.Tests/Layers/Layer.cs b/tests/AzureMapsControl.Components.Tests/Layers/Layer.cs index 0f56d8c..372d4c1 100644 --- a/tests/AzureMapsControl.Components.Tests/Layers/Layer.cs +++ b/tests/AzureMapsControl.Components.Tests/Layers/Layer.cs @@ -28,12 +28,13 @@ public async Task SetOptionsAsync_Should_CallInteropAsync() { var layer = new DummyLayer { _mapJsRuntime = _jsRuntimeMock.Object, + MapId = "test-map-id", Options = new DummyLayerOptions { } }; await layer.SetOptionsAsync(options => options.MinZoom = 2); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Layer.SetOptions.ToLayerNamespace(), layer.Id, layer.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Layer.SetOptions.ToLayerNamespace(), layer.MapId, layer.Id, layer.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); Assert.Equal(2, layer.Options.MinZoom); @@ -43,10 +44,11 @@ public async Task SetOptionsAsync_Should_CallInteropAsync() public async Task SetOptionsAsync_Should_ThrowLayerOptionsNullExceptionAsync() { var layer = new DummyLayer { - _mapJsRuntime = _jsRuntimeMock.Object + _mapJsRuntime = _jsRuntimeMock.Object, + MapId = "test-map-id" }; await layer.SetOptionsAsync(options => options.MinZoom = 2); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Layer.SetOptions.ToLayerNamespace(), layer.Id, layer.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Layer.SetOptions.ToLayerNamespace(), layer.MapId, layer.Id, layer.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); Assert.Equal(2, layer.Options.MinZoom); } diff --git a/tests/AzureMapsControl.Components.Tests/Map/Map.cs b/tests/AzureMapsControl.Components.Tests/Map/Map.cs index a468a28..b896ef1 100644 --- a/tests/AzureMapsControl.Components.Tests/Map/Map.cs +++ b/tests/AzureMapsControl.Components.Tests/Map/Map.cs @@ -50,7 +50,7 @@ public void Should_BeInitialized() public async Task Should_AddControls_Async() { var controls = new List { - new CompassControl() + new CompassControl() }; const string id = "id"; @@ -59,8 +59,8 @@ public async Task Should_AddControls_Async() await map.AddControlsAsync(controls); Assert.Equal(controls, map.Controls); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), It.Is>( - ctrls => ctrls.Single() == controls.Single())), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), id, It.Is>( + ctrls => ctrls.Single() == controls.Single())), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -69,7 +69,7 @@ public async Task Should_AddOrderedControls_Async() { var controls = new List { new OverviewMapControl(), - new CompassControl() + new CompassControl() }; const string id = "id"; @@ -78,8 +78,8 @@ public async Task Should_AddOrderedControls_Async() await map.AddControlsAsync(controls); Assert.Equal(controls, map.Controls); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), It.Is>( - ctrls => ctrls.First() == controls.ElementAt(1) && ctrls.ElementAt(1) == controls.First())), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), id, It.Is>( + ctrls => ctrls.First() == controls.ElementAt(1) && ctrls.ElementAt(1) == controls.First())), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -118,7 +118,7 @@ public async Task Should_AddControls_ParamsVersion_Async() await map.AddControlsAsync(control); Assert.Single(map.Controls); Assert.Contains(control, map.Controls); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), It.Is>( + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), id, It.Is>( ctrls => ctrls.Single() == control)), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -139,8 +139,9 @@ public async Task Should_AddHtmlMarkers_Async() Assert.Equal(markers[1].PopupInvokeHelper, popupInvokeHelper); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable && (parameters[0] as IEnumerable).Count() == 2 - && parameters[1] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 + && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -167,14 +168,16 @@ public async Task Should_AddHtmlMarkers_WithPopup_WithAutoOpenAsync() Assert.Equal(marker.JSRuntime, _jsRuntimeMock.Object); Assert.Equal(marker.PopupInvokeHelper, popupInvokeHelper); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable && (parameters[0] as IEnumerable).Count() == 1 - && parameters[1] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 1 + && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.HtmlMarker.TogglePopup.ToHtmlMarkerNamespace(), It.Is(parameters => - parameters[0] as string == marker.Id - && parameters[1] as string == marker.Options.Popup.Id - && parameters[2] is IEnumerable - && parameters[3] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == marker.Id + && parameters[2] as string == marker.Options.Popup.Id + && parameters[3] is IEnumerable + && parameters[4] is DotNetObjectReference ))); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -195,8 +198,9 @@ public async Task Should_AddHtmlMarkers_ParamsVersion_Async() Assert.Equal(marker1.PopupInvokeHelper, popupInvokeHelper); Assert.Equal(marker2.PopupInvokeHelper, popupInvokeHelper); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable && (parameters[0] as IEnumerable).Count() == 2 - && parameters[1] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 + && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -209,8 +213,9 @@ public async Task Should_UpdateHtmlMarkers_Async() await map.UpdateHtmlMarkersAsync(updates); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.UpdateHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters.Single() is IEnumerable - && (parameters.Single() as IEnumerable).Count() == updates.Count) + parameters[0] as string == "id" + && parameters[1] is IEnumerable + && (parameters[1] as IEnumerable).Count() == updates.Count) ), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -233,9 +238,10 @@ public async Task Should_UpdateHtmlMarkers_ParamsVersion_Async() await map.UpdateHtmlMarkersAsync(update1, update2); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.UpdateHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters.Single() is IEnumerable - && (parameters.Single() as IEnumerable).Count() == 2) - ), Times.Once); + parameters[0] as string == "id" + && parameters[1] is IEnumerable + && (parameters[1] as IEnumerable).Count() == 2) + ), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -258,8 +264,9 @@ public async Task Shoud_NotRemoveAnyHtmlMarkers_Null_Async() await map.RemoveHtmlMarkersAsync(null); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable && (parameters[0] as IEnumerable).Count() == 1 - && parameters[1] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 1 + && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -278,12 +285,14 @@ public async Task Shoud_RemoveAnyHtmlMarkers_Async() Assert.Contains(htmlMarker2, map.HtmlMarkers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable && (parameters[0] as IEnumerable).Count() == 2 - && parameters[1] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 + && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters.Single() is IEnumerable && (parameters[0] as IEnumerable).Single() == htmlMarker.Id) - ), Times.Once); + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Single() == htmlMarker.Id) + ), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -301,11 +310,13 @@ public async Task Shoud_RemoveAnyHtmlMarkers_ParamsVersion_Async() Assert.Contains(htmlMarker2, map.HtmlMarkers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable && (parameters[0] as IEnumerable).Count() == 2 - && parameters[1] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 + && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters.Single() is IEnumerable && (parameters[0] as IEnumerable).Single() == htmlMarker.Id) + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Single() == htmlMarker.Id) ), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -320,9 +331,10 @@ public async Task Should_AddDrawingToolbar_Async() Assert.Equal(drawingToolbarOptions, map.DrawingToolbarOptions); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] is DrawingToolbarCreationOptions - && parameters[1] is DotNetObjectReference - )), Times.Once); + parameters[0] as string == "id" + && parameters[1] is DrawingToolbarCreationOptions + && parameters[2] is DotNetObjectReference + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -350,12 +362,14 @@ public async Task Should_UpdateDrawingToolbar_Async() Assert.Equal(updateDrawingToolbarOptions.Visible, map.DrawingToolbarOptions.Visible); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] is DrawingToolbarCreationOptions - && parameters[1] is DotNetObjectReference - )), Times.Once); + parameters[0] as string == "id" + && parameters[1] is DrawingToolbarCreationOptions + && parameters[2] is DotNetObjectReference + )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.UpdateDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters.Single() is DrawingToolbarCreationOptions - )), Times.Once); + parameters[0] as string == "id" + && parameters[1] is DrawingToolbarCreationOptions + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -368,9 +382,10 @@ public async Task Should_NotUpdateDrawingToolbar_NullCaseAsync() await map.UpdateDrawingToolbarAsync(null); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] is DrawingToolbarCreationOptions - && parameters[1] is DotNetObjectReference - )), Times.Once); + parameters[0] as string == "id" + && parameters[1] is DrawingToolbarCreationOptions + && parameters[2] is DotNetObjectReference + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -384,10 +399,11 @@ public async Task Should_RemoveDrawingToolbar_Async() Assert.Null(map.DrawingToolbarOptions); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] is DrawingToolbarCreationOptions - && parameters[1] is DotNetObjectReference - )), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.RemoveDrawingToolbar.ToDrawingNamespace()), Times.Once); + parameters[0] as string == "id" + && parameters[1] is DrawingToolbarCreationOptions + && parameters[2] is DotNetObjectReference + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.RemoveDrawingToolbar.ToDrawingNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -412,12 +428,13 @@ public async Task Should_AddALayer_Async() Assert.Contains(layer, map.Layers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == layer.Id - && parameters[1] == null - && parameters[2] as string == layer.Type.ToString() - && parameters[3] == null - && parameters[4] is IEnumerable && (parameters[4] as IEnumerable).Count() == 0 - && parameters[5] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == layer.Id + && parameters[2] == null + && parameters[3] as string == layer.Type.ToString() + && parameters[4] == null + && parameters[5] is IEnumerable && (parameters[5] as IEnumerable).Count() == 0 + && parameters[6] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -445,12 +462,13 @@ public async Task Should_AddALayerWithBefore_Async() Assert.Contains(layer, map.Layers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == layer.Id - && parameters[1] as string == before - && parameters[2] as string == layer.Type.ToString() - && parameters[3] == null - && parameters[4] is IEnumerable && (parameters[4] as IEnumerable).Count() == 0 - && parameters[5] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == layer.Id + && parameters[2] as string == before + && parameters[3] as string == layer.Type.ToString() + && parameters[4] == null + && parameters[5] is IEnumerable && (parameters[5] as IEnumerable).Count() == 0 + && parameters[6] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -465,12 +483,13 @@ public async Task Should_NotAddLayerWithSameId_Async() await Assert.ThrowsAnyAsync(async () => await map.AddLayerAsync(layer)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == layer.Id - && parameters[1] == null - && parameters[2] as string == layer.Type.ToString() - && parameters[3] == null - && parameters[4] is IEnumerable && (parameters[4] as IEnumerable).Count() == 0 - && parameters[5] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == layer.Id + && parameters[2] == null + && parameters[3] as string == layer.Type.ToString() + && parameters[4] == null + && parameters[5] is IEnumerable && (parameters[5] as IEnumerable).Count() == 0 + && parameters[6] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -491,7 +510,8 @@ public async Task Should_RemoveOneLayer_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable + parameters[0] as string == "id" + && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -512,7 +532,8 @@ public async Task Should_RemoveMultipleLayers_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable + parameters[0] as string == "id" + && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -533,7 +554,8 @@ public async Task Should_RemoveMultipleLayers_ParamsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable + parameters[0] as string == "id" + && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -554,7 +576,8 @@ public async Task Should_RemoveMultipleLayers_ViaId_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable + parameters[0] as string == "id" + && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -575,7 +598,8 @@ public async Task Should_RemoveMultipleLayers_ViaId_ParamsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable + parameters[0] as string == "id" + && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -595,11 +619,12 @@ public async Task Should_AddDataSource_Async() Assert.Equal(_loggerMock.Object, dataSource.Logger); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] == null - && parameters[2] as string == dataSource.SourceType.ToString() - && (parameters[3] as IEnumerable).Single() == DataSourceEventType.DataAdded.ToString() - && parameters[4] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == dataSource.Id + && parameters[2] == null + && parameters[3] as string == dataSource.SourceType.ToString() + && (parameters[4] as IEnumerable).Single() == DataSourceEventType.DataAdded.ToString() + && parameters[5] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -615,9 +640,10 @@ public async Task Should_AddVectorTileSourceAsync() Assert.Single(map.Sources, source); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == source.Id - && parameters[1] == null - && parameters[2] as string == source.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == source.Id + && parameters[2] == null + && parameters[3] as string == source.SourceType.ToString() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -631,9 +657,10 @@ public async Task Should_NotAddDataSource_Async() await map.AddSourceAsync(dataSource); await Assert.ThrowsAnyAsync(async () => await map.AddSourceAsync(dataSource)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] == null - && parameters[2] as string == dataSource.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == dataSource.Id + && parameters[2] == null + && parameters[3] as string == dataSource.SourceType.ToString() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -662,16 +689,18 @@ public async Task Should_RemoveDataSource_Async() Assert.Contains(dataSource2, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] == null - && parameters[2] as string == dataSource.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == dataSource.Id + && parameters[2] == null + && parameters[3] as string == dataSource.SourceType.ToString() )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource2.Id - && parameters[1] == null - && parameters[2] as string == dataSource2.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == dataSource2.Id + && parameters[2] == null + && parameters[3] as string == dataSource2.SourceType.ToString() )), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), "id", dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -689,9 +718,10 @@ public async Task Should_NotRemoveDataSource_Async() Assert.Contains(dataSource, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] == null - && parameters[2] as string == dataSource.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == dataSource.Id + && parameters[2] == null + && parameters[3] as string == dataSource.SourceType.ToString() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -711,16 +741,18 @@ public async Task Should_RemoveDataSource_ViaId_Async() Assert.Contains(dataSource2, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] == null - && parameters[2] as string == dataSource.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == dataSource.Id + && parameters[2] == null + && parameters[3] as string == dataSource.SourceType.ToString() )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource2.Id - && parameters[1] == null - && parameters[2] as string == dataSource2.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == dataSource2.Id + && parameters[2] == null + && parameters[3] as string == dataSource2.SourceType.ToString() )), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), "id", dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -738,9 +770,10 @@ public async Task Should_NotRemoveDataSource_ViaId_Async() Assert.Contains(dataSource, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == dataSource.Id - && parameters[1] == null - && parameters[2] as string == dataSource.SourceType.ToString() + parameters[0] as string == "id" + && parameters[1] as string == dataSource.Id + && parameters[2] == null + && parameters[3] as string == dataSource.SourceType.ToString() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -769,7 +802,7 @@ public async Task Should_ClearMap_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearMap.ToCoreNamespace(), It.IsAny()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearMap.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -783,7 +816,7 @@ public async Task Should_ClearLayers_Async() Assert.Null(map.Layers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearLayers.ToCoreNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearLayers.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -796,7 +829,7 @@ public async Task Should_ClearDataSources_Async() await map.ClearDataSourcesAsync(); Assert.Null(map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearSources.ToCoreNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearSources.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -811,10 +844,11 @@ public async Task Should_ClearHtmlMarkers_Async() Assert.Null(map.HtmlMarkers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] is IEnumerable && (parameters[0] as IEnumerable).Count() == 1 - && parameters[1] is DotNetObjectReference - )), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearHtmlMarkers.ToCoreNamespace()), Times.Once); + parameters[0] as string == "id" + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 1 + && parameters[2] is DotNetObjectReference + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearHtmlMarkers.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -828,10 +862,11 @@ public async Task Should_AddPopup_Async() Assert.Contains(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && parameters[1] as PopupOptions == popup.Options - && parameters[2] is IEnumerable - && parameters[3] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == popup.Id + && parameters[2] as PopupOptions == popup.Options + && parameters[3] is IEnumerable + && parameters[4] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -853,10 +888,11 @@ public async Task Should_NotAddTwiceTheSamePopup_Async() await Assert.ThrowsAnyAsync(async () => await map.AddPopupAsync(popup)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && parameters[1] as PopupOptions == popup.Options - && parameters[2] is IEnumerable - && parameters[3] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == popup.Id + && parameters[2] as PopupOptions == popup.Options + && parameters[3] is IEnumerable + && parameters[4] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -873,12 +909,13 @@ public async Task Should_AddPopupWithTemplate_Async() Assert.Contains(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopupWithTemplate.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && parameters[1] as PopupOptions == popup.Options - && parameters[2] is IDictionary - && parameters[3] is PopupTemplate - && parameters[4] is IEnumerable - && parameters[5] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == popup.Id + && parameters[2] as PopupOptions == popup.Options + && parameters[3] is IDictionary + && parameters[4] is PopupTemplate + && parameters[5] is IEnumerable + && parameters[6] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -924,12 +961,13 @@ public async Task Should_NotAddTwiceTheSamePopupWithTemplate_Async() await Assert.ThrowsAnyAsync(async () => await map.AddPopupAsync(popup, popupTemplate, properties)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopupWithTemplate.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && parameters[1] as PopupOptions == popup.Options - && parameters[2] is IDictionary - && parameters[3] is PopupTemplate - && parameters[4] is IEnumerable - && parameters[5] is DotNetObjectReference + parameters[0] as string == "id" + && parameters[1] as string == popup.Id + && parameters[2] as PopupOptions == popup.Options + && parameters[3] is IDictionary + && parameters[4] is PopupTemplate + && parameters[5] is IEnumerable + && parameters[6] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -946,7 +984,7 @@ public async Task Should_RemovePopup_Async() Assert.DoesNotContain(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), "id", popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -962,7 +1000,7 @@ public async Task Should_RemovePopup_IdVersion_Async() Assert.DoesNotContain(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), "id", popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -988,7 +1026,7 @@ public async Task Should_ClearPopups_Async() Assert.Null(map.Popups); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearPopups.ToCoreNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearPopups.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); } @@ -1005,7 +1043,8 @@ public async Task Should_UpdateCameraOptions_Async() await map.SetCameraOptionsAsync(options => options.Center = center); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as CameraOptions).Duration == 10 && (parameters[0] as CameraOptions).Center.Longitude == 10 && (parameters[0] as CameraOptions).Center.Latitude == 10 + parameters[0] as string == "id" + && (parameters[1] as CameraOptions).Duration == 10 && (parameters[1] as CameraOptions).Center.Longitude == 10 && (parameters[1] as CameraOptions).Center.Latitude == 10 )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1024,7 +1063,8 @@ public async Task Should_UpdateCameraOptions_WithCenter_Async() await map.SetCameraOptionsAsync(options => options.Center = center); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as CameraOptions).Duration == 10 && (parameters[0] as CameraOptions).Center.Longitude == 10 && (parameters[0] as CameraOptions).Center.Latitude == 10 + parameters[0] as string == "id" + && (parameters[1] as CameraOptions).Duration == 10 && (parameters[1] as CameraOptions).Center.Longitude == 10 && (parameters[1] as CameraOptions).Center.Latitude == 10 )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1046,10 +1086,11 @@ await map.SetCameraOptionsAsync(options => { }); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as CameraOptions).Duration == 10 && (parameters[0] as CameraOptions).Center == null && (parameters[0] as CameraOptions).Bounds.West == -10 - && (parameters[0] as CameraOptions).Bounds.South == 10 - && (parameters[0] as CameraOptions).Bounds.East == 10 - && (parameters[0] as CameraOptions).Bounds.North == -10 + parameters[0] as string == "id" + && (parameters[1] as CameraOptions).Duration == 10 && (parameters[1] as CameraOptions).Center == null && (parameters[1] as CameraOptions).Bounds.West == -10 + && (parameters[1] as CameraOptions).Bounds.South == 10 + && (parameters[1] as CameraOptions).Bounds.East == 10 + && (parameters[1] as CameraOptions).Bounds.North == -10 )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1062,7 +1103,8 @@ public async Task Should_UpdateCameraOptions_NoCameraOptionsDefined_Async() await map.SetCameraOptionsAsync(options => options.Center = center); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as CameraOptions).Center.Longitude == 10 && (parameters[0] as CameraOptions).Center.Latitude == 10 + parameters[0] as string == "id" + && (parameters[1] as CameraOptions).Center.Longitude == 10 && (parameters[1] as CameraOptions).Center.Latitude == 10 )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1080,7 +1122,8 @@ public async Task Should_UpdateStyleOptions_Async() await map.SetStyleOptionsAsync(options => options.Language = language); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetStyleOptions.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as StyleOptions).AutoResize && (parameters[0] as StyleOptions).Language == "fr" + parameters[0] as string == "id" + && (parameters[1] as StyleOptions).AutoResize && (parameters[1] as StyleOptions).Language == "fr" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1093,7 +1136,8 @@ public async Task Should_UpdateStyleOptions_NoStyleOptionsDefined_Async() await map.SetStyleOptionsAsync(options => options.Language = language); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetStyleOptions.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as StyleOptions).Language == "fr" + parameters[0] as string == "id" + && (parameters[1] as StyleOptions).Language == "fr" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1111,7 +1155,8 @@ public async Task Should_UpdateUserInteraction_Async() await map.SetUserInteractionAsync(options => options.DblclickZoomInteraction = dblClickZoomInteraction); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetUserInteraction.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as UserInteractionOptions).BoxZoomInteraction.GetValueOrDefault() && (parameters[0] as UserInteractionOptions).DblclickZoomInteraction.GetValueOrDefault() + parameters[0] as string == "id" + && (parameters[1] as UserInteractionOptions).BoxZoomInteraction.GetValueOrDefault() && (parameters[1] as UserInteractionOptions).DblclickZoomInteraction.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1124,7 +1169,8 @@ public async Task Should_UpdateUserInteraction_NoUserInteractionDefined_Async() await map.SetUserInteractionAsync(options => options.DblclickZoomInteraction = dblClickZoomInteraction); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetUserInteraction.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as UserInteractionOptions).DblclickZoomInteraction.GetValueOrDefault() + parameters[0] as string == "id" + && (parameters[1] as UserInteractionOptions).DblclickZoomInteraction.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1142,7 +1188,8 @@ public async Task Should_UpdateTrafficInteraction_Async() await map.SetTrafficOptionsAsync(options => options.Incidents = incidents); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetTraffic.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as TrafficOptions).Flow.ToString() == TrafficFlow.Absolute.ToString() && (parameters[0] as TrafficOptions).Incidents.GetValueOrDefault() + parameters[0] as string == "id" + && (parameters[1] as TrafficOptions).Flow.ToString() == TrafficFlow.Absolute.ToString() && (parameters[1] as TrafficOptions).Incidents.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1155,7 +1202,8 @@ public async Task Should_UpdateTrafficInteraction_NoTrafficOptionsDefined_Async( await map.SetTrafficOptionsAsync(options => options.Incidents = incidents); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetTraffic.ToCoreNamespace(), It.Is(parameters => - (parameters[0] as TrafficOptions).Incidents.GetValueOrDefault() + parameters[0] as string == "id" + && (parameters[1] as TrafficOptions).Incidents.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1716,12 +1764,13 @@ public async Task Should_CreateImageFromTemplateAsync() await map.CreateImageFromTemplateAsync("imageId", "templateName", "color", "secondaryColor", 1m); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.CreateImageFromTemplate.ToCoreNamespace(), It.Is(parameters => - parameters[0] is MapImageTemplate - && ((MapImageTemplate)parameters[0]).Id == "imageId" - && ((MapImageTemplate)parameters[0]).TemplateName == "templateName" - && ((MapImageTemplate)parameters[0]).Color == "color" - && ((MapImageTemplate)parameters[0]).SecondaryColor == "secondaryColor" - && ((MapImageTemplate)parameters[0]).Scale == 1m + parameters[0] as string == "id" + && parameters[1] is MapImageTemplate + && ((MapImageTemplate)parameters[1]).Id == "imageId" + && ((MapImageTemplate)parameters[1]).TemplateName == "templateName" + && ((MapImageTemplate)parameters[1]).Color == "color" + && ((MapImageTemplate)parameters[1]).SecondaryColor == "secondaryColor" + && ((MapImageTemplate)parameters[1]).Scale == 1m )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1732,7 +1781,7 @@ public async Task Should_SetCanvasStylePropertyAsync() var map = new Map("id", _jsRuntimeMock.Object); await map.SetCanvasStylePropertyAsync("property", "value"); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperty.ToCoreNamespace(), "property", "value"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperty.ToCoreNamespace(), "id", "property", "value"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1758,9 +1807,9 @@ public async Task Should_SetCanvasStylePropertiesAsync() await map.SetCanvasStylePropertiesAsync(properties); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), It.Is>>(dictionary => + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1780,15 +1829,15 @@ public async Task Should_SetOnlyDefinedCanvasProperties_Async() var map = new Map("id", _jsRuntimeMock.Object); var properties = new Dictionary { - { "cursor", "hand" }, - { "", "value" }, - { " ", "value" }, - }; + { "cursor", "hand" }, + { "", "value" }, + { " ", "value" }, + }; await map.SetCanvasStylePropertiesAsync(properties); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), It.Is>>(dictionary => + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1810,7 +1859,7 @@ public async Task Should_NotSetCanvasProperties_NoDefinedPropertiesCase_Async() var properties = new Dictionary { { "", "value" }, - { " ", "value" }, + { " ", "value" }, }; await map.SetCanvasStylePropertiesAsync(properties); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1822,7 +1871,7 @@ public async Task Should_SetCanvasContainerStylePropertyAsync() var map = new Map("id", _jsRuntimeMock.Object); await map.SetCanvasContainerStylePropertyAsync("property", "value"); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperty.ToCoreNamespace(), "property", "value"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperty.ToCoreNamespace(), "id", "property", "value"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1848,9 +1897,9 @@ public async Task Should_SetCanvasContainerStylePropertiesAsync() await map.SetCanvasContainerStylePropertiesAsync(properties); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), It.Is>>(dictionary => + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1870,15 +1919,15 @@ public async Task Should_SetOnlyDefinedCanvasContainerProperties_Async() var map = new Map("id", _jsRuntimeMock.Object); var properties = new Dictionary { - { "cursor", "hand" }, - { "", "value" }, - { " ", "value" }, - }; + { "cursor", "hand" }, + { "", "value" }, + { " ", "value" }, + }; await map.SetCanvasContainerStylePropertiesAsync(properties); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), It.Is>>(dictionary => + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1900,7 +1949,7 @@ public async Task Should_NotSetCanvasContainerProperties_NoDefinedPropertiesCase var properties = new Dictionary { { "", "value" }, - { " ", "value" }, + { " ", "value" }, }; await map.SetCanvasContainerStylePropertiesAsync(properties); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1910,14 +1959,14 @@ public async Task Should_NotSetCanvasContainerProperties_NoDefinedPropertiesCase public async Task Should_GetCameraOptionsAsync() { var options = new CameraOptions(); - _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny())).ReturnsAsync(options); + _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); var map = new Map("id", _jsRuntimeMock.Object); var result = await map.GetCameraOptionsAsync(); Assert.Equal(options, map.CameraOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetCamera.ToCoreNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetCamera.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1925,14 +1974,14 @@ public async Task Should_GetCameraOptionsAsync() public async Task Should_GetStyleOptionsAsync() { var options = new StyleOptions(); - _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny())).ReturnsAsync(options); + _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); var map = new Map("id", _jsRuntimeMock.Object); var result = await map.GetStyleOptionsAsync(); Assert.Equal(options, map.StyleOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetStyle.ToCoreNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetStyle.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1940,14 +1989,14 @@ public async Task Should_GetStyleOptionsAsync() public async Task Should_GetTrafficOptionsAsync() { var options = new TrafficOptions(); - _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny())).ReturnsAsync(options); + _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); var map = new Map("id", _jsRuntimeMock.Object); var result = await map.GetTrafficOptionsAsync(); Assert.Equal(options, map.TrafficOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetTraffic.ToCoreNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetTraffic.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1955,14 +2004,14 @@ public async Task Should_GetTrafficOptionsAsync() public async Task Should_GetUserInteractionOptionsAsync() { var options = new UserInteractionOptions(); - _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny())).ReturnsAsync(options); + _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); var map = new Map("id", _jsRuntimeMock.Object); var result = await map.GetUserInteractionOptionsAsync(); Assert.Equal(options, map.UserInteractionOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetUserInteraction.ToCoreNamespace()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetUserInteraction.ToCoreNamespace(), "id"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } } diff --git a/tests/AzureMapsControl.Components.Tests/Map/MapService.cs b/tests/AzureMapsControl.Components.Tests/Map/MapService.cs index a200ac8..8d049d0 100644 --- a/tests/AzureMapsControl.Components.Tests/Map/MapService.cs +++ b/tests/AzureMapsControl.Components.Tests/Map/MapService.cs @@ -25,7 +25,7 @@ public async Task Should_AddMapAndTriggerOnReady_Async() var eventReceived = false; - service.OnMapReadyAsync += async () => eventReceived = true; + service.OnMapReadyAsync += async (Map map) => eventReceived = true; await service.AddMapAsync(map); diff --git a/tests/AzureMapsControl.Components.Tests/Markers/HtmlMarker.cs b/tests/AzureMapsControl.Components.Tests/Markers/HtmlMarker.cs index c369589..7dfeea0 100644 --- a/tests/AzureMapsControl.Components.Tests/Markers/HtmlMarker.cs +++ b/tests/AzureMapsControl.Components.Tests/Markers/HtmlMarker.cs @@ -17,6 +17,7 @@ public class HtmlMarkerTests { private readonly Mock _jsRuntime = new Mock(); + private const string TestMapId = "test-map-id"; [Fact] public void Should_HaveDefaultIdAndDeactivatedEvents() @@ -246,7 +247,8 @@ public async Task Should_TogglePopupAsync() } }) { JSRuntime = _jsRuntime.Object, - PopupInvokeHelper = popupInvokeHelper + PopupInvokeHelper = popupInvokeHelper, + MapId = TestMapId }; marker.OnPopupToggled += () => assertEvent = true; @@ -256,10 +258,11 @@ public async Task Should_TogglePopupAsync() Assert.False(marker.Options.Popup.IsRemoved); _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.HtmlMarker.TogglePopup.ToHtmlMarkerNamespace(), It.Is(parameters => - parameters[0] as string == marker.Id - && parameters[1] as string == marker.Options.Popup.Id - && parameters[2] is IEnumerable - && parameters[3] is DotNetObjectReference + parameters[0] as string == TestMapId + && parameters[1] as string == marker.Id + && parameters[2] as string == marker.Options.Popup.Id + && parameters[3] is IEnumerable + && parameters[4] is DotNetObjectReference ))); _jsRuntime.VerifyNoOtherCalls(); } @@ -271,7 +274,8 @@ public async Task Should_Not_TogglePopupAsync() var popupInvokeHelper = new PopupInvokeHelper(null); var marker = new HtmlMarker(new HtmlMarkerOptions()) { JSRuntime = _jsRuntime.Object, - PopupInvokeHelper = popupInvokeHelper + PopupInvokeHelper = popupInvokeHelper, + MapId = TestMapId }; marker.OnPopupToggled += () => assertEvent = true; diff --git a/tests/AzureMapsControl.Components.Tests/Popups/HtmlMarkerPopup.cs b/tests/AzureMapsControl.Components.Tests/Popups/HtmlMarkerPopup.cs index 8dde308..6a5d4c5 100644 --- a/tests/AzureMapsControl.Components.Tests/Popups/HtmlMarkerPopup.cs +++ b/tests/AzureMapsControl.Components.Tests/Popups/HtmlMarkerPopup.cs @@ -12,6 +12,7 @@ public class HtmlMarkerPopupTests { private readonly Mock _jsRuntimeMock = new(); + private const string TestMapId = "test-map-id"; [Theory] [InlineData(null)] @@ -47,11 +48,12 @@ public async Task Should_OpenAsync() { var popup = new HtmlMarkerPopup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, HasBeenToggled = true }; await popup.OpenAsync(); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Open.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Open.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -71,7 +73,8 @@ public async Task Should_NotOpen_NotAddedToMapCase_Async() public async Task Should_Not_OpenAsync() { var popup = new HtmlMarkerPopup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await popup.OpenAsync(); @@ -83,10 +86,11 @@ public async Task Should_CloseAsync() { var popup = new HtmlMarkerPopup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, HasBeenToggled = true }; await popup.CloseAsync(); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Close.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Close.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -106,7 +110,8 @@ public async Task Should_NotClose_NotAddedToMap_Async() public async Task Should_Not_CloseAsync() { var popup = new HtmlMarkerPopup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await popup.CloseAsync(); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -118,6 +123,7 @@ public async Task Should_RemoveAsync() var assertRemoveEvent = false; var popup = new HtmlMarkerPopup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, HasBeenToggled = true }; popup.OnRemoved += () => assertRemoveEvent = true; @@ -125,7 +131,7 @@ public async Task Should_RemoveAsync() Assert.True(assertRemoveEvent); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -145,7 +151,8 @@ public async Task Should_Not_RemoveAsync() { var assertRemoveEvent = false; var popup = new HtmlMarkerPopup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; popup.OnRemoved += () => assertRemoveEvent = true; await popup.RemoveAsync(); @@ -161,6 +168,7 @@ public async Task Should_NotRemoveTwice_Async() var assertRemoveEvent = false; var popup = new HtmlMarkerPopup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, HasBeenToggled = true }; popup.OnRemoved += () => assertRemoveEvent = true; @@ -168,7 +176,7 @@ public async Task Should_NotRemoveTwice_Async() await Assert.ThrowsAnyAsync(async () => await popup.RemoveAsync()); Assert.True(assertRemoveEvent); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -177,6 +185,7 @@ public async Task Should_Update_Async() { var popup = new HtmlMarkerPopup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, HasBeenToggled = true }; var updatedContent = "updatedContent"; @@ -184,8 +193,9 @@ public async Task Should_Update_Async() Assert.Equal(updatedContent, popup.Options.Content); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.SetOptions.ToPopupNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && (parameters[1] as PopupOptions).Content == "updatedContent" + parameters[0] as string == TestMapId + && parameters[1] as string == popup.Id + && (parameters[2] as PopupOptions).Content == "updatedContent" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -209,6 +219,7 @@ public async Task Should_SetOptions_Async() { var popup = new HtmlMarkerPopup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, HasBeenToggled = true }; var updatedContent = "updatedContent"; @@ -216,8 +227,9 @@ public async Task Should_SetOptions_Async() Assert.Equal(updatedContent, popup.Options.Content); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.SetOptions.ToPopupNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && (parameters[1] as PopupOptions).Content == "updatedContent" + parameters[0] as string == TestMapId + && parameters[1] as string == popup.Id + && (parameters[2] as PopupOptions).Content == "updatedContent" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -240,7 +252,8 @@ public async Task Should_NotSetOptions_NotAddedToMapCase_Async() public async Task Should_Not_Update_Async() { var popup = new HtmlMarkerPopup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var updatedContent = "updatedContent"; await popup.UpdateAsync(options => options.Content = updatedContent); diff --git a/tests/AzureMapsControl.Components.Tests/Popups/Popup.cs b/tests/AzureMapsControl.Components.Tests/Popups/Popup.cs index 5f68631..a2dade3 100644 --- a/tests/AzureMapsControl.Components.Tests/Popups/Popup.cs +++ b/tests/AzureMapsControl.Components.Tests/Popups/Popup.cs @@ -16,6 +16,7 @@ public class PopupTests { private readonly Mock _jsRuntimeMock = new(); + private const string TestMapId = "test-map-id"; [Theory] [InlineData(null)] @@ -50,11 +51,12 @@ public void Should_BeInitialized() public async Task Should_OpenAsync() { var popup = new Popup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await popup.OpenAsync(); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Open.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Open.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -73,6 +75,7 @@ public async Task Should_NotOpen_RemovedCase_Async() { var popup = new Popup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, IsRemoved = true }; @@ -85,10 +88,11 @@ public async Task Should_NotOpen_RemovedCase_Async() public async Task Should_CloseAsync() { var popup = new Popup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; await popup.CloseAsync(); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Close.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Close.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -105,6 +109,7 @@ public async Task Should_NotClose_RemovedCase_Async() { var popup = new Popup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, IsRemoved = true }; await Assert.ThrowsAnyAsync(async () => await popup.CloseAsync()); @@ -116,14 +121,15 @@ public async Task Should_RemoveAsync() { var assertRemoveEvent = false; var popup = new Popup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; popup.OnRemoved += () => assertRemoveEvent = true; await popup.RemoveAsync(); Assert.True(assertRemoveEvent); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -140,14 +146,15 @@ public async Task Should_NotRemoveTwice_Async() { var assertRemoveEvent = false; var popup = new Popup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; popup.OnRemoved += () => assertRemoveEvent = true; await popup.RemoveAsync(); await Assert.ThrowsAnyAsync(async () => await popup.RemoveAsync()); Assert.True(assertRemoveEvent); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), TestMapId, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -155,15 +162,17 @@ public async Task Should_NotRemoveTwice_Async() public async Task Should_Update_Async() { var popup = new Popup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var updatedContent = "updatedContent"; await popup.UpdateAsync(options => options.Content = updatedContent); Assert.Equal(updatedContent, popup.Options.Content); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.SetOptions.ToPopupNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && (parameters[1] as PopupOptions).Content == "updatedContent" + parameters[0] as string == TestMapId + && parameters[1] as string == popup.Id + && (parameters[2] as PopupOptions).Content == "updatedContent" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -183,6 +192,7 @@ public async Task Should_NotUpdate_RemovedCase_Async() { var popup = new Popup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, IsRemoved = true }; var updatedContent = "updatedContent"; @@ -195,15 +205,17 @@ public async Task Should_NotUpdate_RemovedCase_Async() public async Task Should_SetOptions_Async() { var popup = new Popup(new PopupOptions()) { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var updatedContent = "updatedContent"; await popup.SetOptionsAsync(options => options.Content = updatedContent); Assert.Equal(updatedContent, popup.Options.Content); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.SetOptions.ToPopupNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && (parameters[1] as PopupOptions).Content == "updatedContent" + parameters[0] as string == TestMapId + && parameters[1] as string == popup.Id + && (parameters[2] as PopupOptions).Content == "updatedContent" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -223,6 +235,7 @@ public async Task Should_NotSetOptions_RemovedCase_Async() { var popup = new Popup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, IsRemoved = true }; var updatedContent = "updatedContent"; @@ -305,7 +318,8 @@ public void Should_DispatchCloseEvent() public async Task Should_ApplyTemplateAsync() { var popup = new Popup() { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var template = new PopupTemplate(); @@ -316,10 +330,11 @@ public async Task Should_ApplyTemplateAsync() Assert.NotNull(popup.Options); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.ApplyTemplate.ToPopupNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && parameters[1] as PopupOptions == popup.Options - && parameters[2] as Dictionary == properties - && parameters[3] as PopupTemplate == template + parameters[0] as string == TestMapId + && parameters[1] as string == popup.Id + && parameters[2] as PopupOptions == popup.Options + && parameters[3] as Dictionary == properties + && parameters[4] as PopupTemplate == template )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -343,6 +358,7 @@ public async Task Should_NotApplyTemplate_RemovedCaseAsync() { var popup = new Popup() { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, IsRemoved = true }; var template = new PopupTemplate(); @@ -358,7 +374,8 @@ public async Task Should_NotApplyTemplate_RemovedCaseAsync() public async Task Should_NotApplyTemplateWithNullPropertiesAsync() { var popup = new Popup() { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var template = new PopupTemplate(); @@ -373,7 +390,8 @@ public async Task Should_NotApplyTemplateWithNullPropertiesAsync() public async Task Should_ApplyTemplateWithOptionsAsync() { var popup = new Popup() { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var template = new PopupTemplate(); @@ -384,10 +402,11 @@ public async Task Should_ApplyTemplateWithOptionsAsync() Assert.Equal("fillColor", popup.Options.FillColor); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.ApplyTemplate.ToPopupNamespace(), It.Is(parameters => - parameters[0] as string == popup.Id - && parameters[1] as PopupOptions == popup.Options - && parameters[2] as Dictionary == properties - && parameters[3] as PopupTemplate == template + parameters[0] as string == TestMapId + && parameters[1] as string == popup.Id + && parameters[2] as PopupOptions == popup.Options + && parameters[3] as Dictionary == properties + && parameters[4] as PopupTemplate == template )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -411,6 +430,7 @@ public async Task Should_NotApplyTemplateWithOptions_RemovedCaseAsync() { var popup = new Popup() { JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId, IsRemoved = true }; var template = new PopupTemplate(); @@ -426,7 +446,8 @@ public async Task Should_NotApplyTemplateWithOptions_RemovedCaseAsync() public async Task Should_NotApplyTemplateWithOptionsWithNullPropertiesAsync() { var popup = new Popup() { - JSRuntime = _jsRuntimeMock.Object + JSRuntime = _jsRuntimeMock.Object, + MapId = TestMapId }; var template = new PopupTemplate(); From 2d2b13446db2a8bab00084d40184f311a718ee4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Wed, 29 Oct 2025 14:17:34 +0200 Subject: [PATCH 05/12] Make samples more resilient on timing issues. --- .../Components/Pages/Animations/Drop.razor | 4 + .../Components/Pages/Animations/Morph.razor | 4 + .../Components/Pages/Controls/Basic.razor | 2 +- .../Pages/Controls/OverviewMap.razor | 28 ++++- .../Pages/Layers/BubbleLayerOnReady.razor | 4 + .../Pages/Layers/HeatmapLayerOnReady.razor | 9 ++ .../Pages/Layers/ImageLayerOnReady.razor | 4 + .../Components/Pages/Layers/LayerRemove.razor | 4 + .../Pages/Layers/LineLayerOnReady.razor | 111 ++++++++++-------- .../Layers/PolygonExtrusionLayerOnReady.razor | 9 ++ .../Pages/Layers/PolygonLayerOnReady.razor | 11 +- .../Pages/Layers/SymbolLayerOnReady.razor | 42 ++++--- .../Layers/SymbolLayerWithFeatures.razor | 9 ++ .../Pages/Layers/TileLayerOnReady.razor | 4 + .../Pages/Layers/VectorTileSource.razor | 9 ++ .../Pages/Popups/NoDefinedTemplate.razor | 4 + .../Pages/Popups/PopupOnReady.razor | 5 + .../Components/Pages/Popups/ReusePopup.razor | 4 + .../Sources/ExtrudedGriddedDatasource.razor | 11 +- .../Sources/GriddedDatasourceOptions.razor | 9 ++ .../Controls/OverviewMapControl.cs | 4 +- 21 files changed, 217 insertions(+), 74 deletions(-) diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Animations/Drop.razor b/samples/AzureMapsControl.Sample/Components/Pages/Animations/Drop.razor index 3e2d284..f52d0f1 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Animations/Drop.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Animations/Drop.razor @@ -23,6 +23,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + _dataSource = new AzureMapsControl.Components.Data.DataSource(); await eventArgs.Map.AddSourceAsync(_dataSource); diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Animations/Morph.razor b/samples/AzureMapsControl.Sample/Components/Pages/Animations/Morph.razor index a541c82..5f67e29 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Animations/Morph.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Animations/Morph.razor @@ -134,6 +134,10 @@ { _map = eventArgs.Map; + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + _datasource = new AzureMapsControl.Components.Data.DataSource(); await _map.AddSourceAsync(_datasource); await _datasource.AddAsync(_geometry1); diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Controls/Basic.razor b/samples/AzureMapsControl.Sample/Components/Pages/Controls/Basic.razor index 36cc91f..82e8805 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Controls/Basic.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Controls/Basic.razor @@ -6,7 +6,7 @@ CameraOptions="new CameraOptions { Type = AzureMapsControl.Components.Map.CameraType.Fly }" Controls="new AzureMapsControl.Components.Controls.Control[] { - new AzureMapsControl.Components.Controls.ZoomControl(new AzureMapsControl.Components.Controls.ZoomControlOptions { Style = AzureMapsControl.Components.Controls.ControlStyle.Dark }, AzureMapsControl.Components.Controls.ControlPosition.TopLeft), + new AzureMapsControl.Components.Controls.ZoomControl(new AzureMapsControl.Components.Controls.ZoomControlOptions { Style = AzureMapsControl.Components.Controls.ControlStyle.Dark }, AzureMapsControl.Components.Controls.ControlPosition.TopLeft), new AzureMapsControl.Components.Controls.PitchControl(new AzureMapsControl.Components.Controls.PitchControlOptions { Style = AzureMapsControl.Components.Controls.ControlStyle.Dark }, AzureMapsControl.Components.Controls.ControlPosition.TopRight), new AzureMapsControl.Components.Controls.CompassControl(new AzureMapsControl.Components.Controls.CompassControlOptions { Style = AzureMapsControl.Components.Controls.ControlStyle.Dark }, AzureMapsControl.Components.Controls.ControlPosition.BottomLeft), new AzureMapsControl.Components.Controls.StyleControl(new AzureMapsControl.Components.Controls.StyleControlOptions { Style = AzureMapsControl.Components.Controls.ControlStyle.Dark, MapStyles = MapStyle.All() }, AzureMapsControl.Components.Controls.ControlPosition.BottomRight) diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Controls/OverviewMap.razor b/samples/AzureMapsControl.Sample/Components/Pages/Controls/OverviewMap.razor index bf559b3..1f71760 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Controls/OverviewMap.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Controls/OverviewMap.razor @@ -1,6 +1,7 @@ @page "/Controls/OverviewMap" @rendermode InteractiveServer +@using AzureMapsControl.Components.Controls @using AzureMapsControl.Components.Map + EventActivationFlags="MapEventActivationFlags.None().Enable(MapEventType.StyleData).Enable(MapEventType.Ready)" + OnStyleData="OnStyleData" + OnReady="OnMapReady"/> @code { + private bool _mapReady = false; + private MapStyle? _style; + private OverviewMapControl? _overviewControl; + + public async void OnMapReady(MapEventArgs eventArgs) + { + _mapReady = true; + SetStyle(); + } + public async void OnStyleData(MapStyleDataEventArgs eventArgs) { - var overviewControl = eventArgs.Map.Controls?.OfType()?.FirstOrDefault(); - if(overviewControl is not null) + _overviewControl = eventArgs.Map.Controls?.OfType()?.FirstOrDefault(); + _style = eventArgs.Style; + SetStyle(); + } + + private async void SetStyle() + { + if (_mapReady && _overviewControl != null && _style.HasValue) { - await overviewControl.SetOptionsAsync(options => options.MapStyle = eventArgs.Style); + await _overviewControl.SetOptionsAsync(options => options.MapStyle = _style.Value); } } } \ No newline at end of file diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/BubbleLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/BubbleLayerOnReady.razor index a05f554..5929b24 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/BubbleLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/BubbleLayerOnReady.razor @@ -16,6 +16,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var dataSource = new AzureMapsControl.Components.Data.DataSource(_datasourceId) { EventActivationFlags = AzureMapsControl.Components.Data.DataSourceEventActivationFlags.None() diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/HeatmapLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/HeatmapLayerOnReady.razor index b683b1a..3c47666 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/HeatmapLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/HeatmapLayerOnReady.razor @@ -22,6 +22,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var dataSource = new AzureMapsControl.Components.Data.DataSource(_datasourceId); await eventArgs.Map.AddSourceAsync(dataSource); await dataSource.ImportDataFromUrlAsync("https://services1.arcgis.com/0MSEUqKaxRlEPj5g/arcgis/rest/services/ncov_cases/FeatureServer/1/query?where=1%3D1&f=geojson&outFields=*"); @@ -29,6 +33,11 @@ public async Task OnDatasourceAdded(MapSourceEventArgs eventArgs) { + if( eventArgs.Source.Id != _datasourceId) + { + return; + } + var weightExpressionJsonString = "[\"get\", \"Confirmed\"]"; var layer = new AzureMapsControl.Components.Layers.HeatmapLayer diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/ImageLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/ImageLayerOnReady.razor index beb0366..91bcd67 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/ImageLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/ImageLayerOnReady.razor @@ -12,6 +12,10 @@ @code { public async Task OnMapReady(MapEventArgs events) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await events.Map.AddSourceAsync(dummyDataSource); + var layer = new AzureMapsControl.Components.Layers.ImageLayer { Options = new AzureMapsControl.Components.Layers.ImageLayerOptions("https://ngazuremaps.blob.core.windows.net/images/munich_1858.jpg", new AzureMapsControl.Components.Atlas.Position[] { diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/LayerRemove.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/LayerRemove.razor index 4dab616..d5cd025 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/LayerRemove.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/LayerRemove.razor @@ -12,6 +12,10 @@ @code { public async Task OnMapReady(MapEventArgs events) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await events.Map.AddSourceAsync(dummyDataSource); + var layer = new AzureMapsControl.Components.Layers.TileLayer { Options = new AzureMapsControl.Components.Layers.TileLayerOptions("https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/{z}/{x}/{y}.png"), diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/LineLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/LineLayerOnReady.razor index 504003a..6a3abaa 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/LineLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/LineLayerOnReady.razor @@ -23,6 +23,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var dataSource = new AzureMapsControl.Components.Data.DataSource(_dataSourceId) { Options = new AzureMapsControl.Components.Data.DataSourceOptions @@ -31,62 +35,71 @@ } }; await eventArgs.Map.AddSourceAsync(dataSource); - - await dataSource.AddAsync(new AzureMapsControl.Components.Atlas.Shape( - new AzureMapsControl.Components.Atlas.LineString(new[] { - new AzureMapsControl.Components.Atlas.Position(11.575454, 48.137392), - new AzureMapsControl.Components.Atlas.Position(11.576029, 48.137094), - new AzureMapsControl.Components.Atlas.Position(11.577248, 48.138912), - new AzureMapsControl.Components.Atlas.Position(11.578434, 48.138737), - new AzureMapsControl.Components.Atlas.Position(11.578826, 48.139409), - new AzureMapsControl.Components.Atlas.Position(11.580140, 48.139179), - new AzureMapsControl.Components.Atlas.Position(11.581237, 48.141555), - new AzureMapsControl.Components.Atlas.Position(11.581155, 48.141852), - new AzureMapsControl.Components.Atlas.Position(11.581990, 48.143534), - new AzureMapsControl.Components.Atlas.Position(11.583355, 48.143896), - new AzureMapsControl.Components.Atlas.Position(11.583662, 48.144258) - }), - new Dictionary() - { - { "Color", "#00FF00" } - })); - - await dataSource.AddAsync(new AzureMapsControl.Components.Atlas.Shape( - new AzureMapsControl.Components.Atlas.LineString(new[] { - new AzureMapsControl.Components.Atlas.Position(11.585458, 48.145596), - new AzureMapsControl.Components.Atlas.Position(11.587910, 48.145779), - new AzureMapsControl.Components.Atlas.Position(11.589632, 48.146608), - new AzureMapsControl.Components.Atlas.Position(11.590771, 48.148219), - new AzureMapsControl.Components.Atlas.Position(11.591979, 48.150743), - new AzureMapsControl.Components.Atlas.Position(11.592885, 48.150611), - new AzureMapsControl.Components.Atlas.Position(11.593161, 48.150874), - new AzureMapsControl.Components.Atlas.Position(11.593594, 48.151084), - new AzureMapsControl.Components.Atlas.Position(11.594028, 48.151803), - new AzureMapsControl.Components.Atlas.Position(11.592281, 48.152074) - }), - new Dictionary() - { - { "Color", "#FF0000" } - })); } public async Task OnDatasourceAdded(MapSourceEventArgs eventArgs) { - var layer = new AzureMapsControl.Components.Layers.LineLayer + if (eventArgs.Source.Id == _dataSourceId) { - Options = new AzureMapsControl.Components.Layers.LineLayerOptions + var dataSource = eventArgs.Map.Sources.OfType() + .FirstOrDefault(s => s.Id == _dataSourceId); + + if (dataSource != null) { - Source = _dataSourceId, - StrokeWidth = new AzureMapsControl.Components.Atlas.ExpressionOrNumber(6), - StrokeColor = new AzureMapsControl.Components.Atlas.ExpressionOrString( - new AzureMapsControl.Components.Atlas.Expression[] + await dataSource.AddAsync(new AzureMapsControl.Components.Atlas.Shape( + new AzureMapsControl.Components.Atlas.LineString(new[] { + new AzureMapsControl.Components.Atlas.Position(11.575454, 48.137392), + new AzureMapsControl.Components.Atlas.Position(11.576029, 48.137094), + new AzureMapsControl.Components.Atlas.Position(11.577248, 48.138912), + new AzureMapsControl.Components.Atlas.Position(11.578434, 48.138737), + new AzureMapsControl.Components.Atlas.Position(11.578826, 48.139409), + new AzureMapsControl.Components.Atlas.Position(11.580140, 48.139179), + new AzureMapsControl.Components.Atlas.Position(11.581237, 48.141555), + new AzureMapsControl.Components.Atlas.Position(11.581155, 48.141852), + new AzureMapsControl.Components.Atlas.Position(11.581990, 48.143534), + new AzureMapsControl.Components.Atlas.Position(11.583355, 48.143896), + new AzureMapsControl.Components.Atlas.Position(11.583662, 48.144258) + }), + new Dictionary() + { + { "Color", "#00FF00" } + })); + + await dataSource.AddAsync(new AzureMapsControl.Components.Atlas.Shape( + new AzureMapsControl.Components.Atlas.LineString(new[] { + new AzureMapsControl.Components.Atlas.Position(11.585458, 48.145596), + new AzureMapsControl.Components.Atlas.Position(11.587910, 48.145779), + new AzureMapsControl.Components.Atlas.Position(11.589632, 48.146608), + new AzureMapsControl.Components.Atlas.Position(11.590771, 48.148219), + new AzureMapsControl.Components.Atlas.Position(11.591979, 48.150743), + new AzureMapsControl.Components.Atlas.Position(11.592885, 48.150611), + new AzureMapsControl.Components.Atlas.Position(11.593161, 48.150874), + new AzureMapsControl.Components.Atlas.Position(11.593594, 48.151084), + new AzureMapsControl.Components.Atlas.Position(11.594028, 48.151803), + new AzureMapsControl.Components.Atlas.Position(11.592281, 48.152074) + }), + new Dictionary() + { + { "Color", "#FF0000" } + })); + + var layer = new AzureMapsControl.Components.Layers.LineLayer + { + Options = new AzureMapsControl.Components.Layers.LineLayerOptions { - new AzureMapsControl.Components.Atlas.ExpressionOrString("get"), - new AzureMapsControl.Components.Atlas.ExpressionOrString("Color") - }) - } - }; + Source = _dataSourceId, + StrokeWidth = new AzureMapsControl.Components.Atlas.ExpressionOrNumber(6), + StrokeColor = new AzureMapsControl.Components.Atlas.ExpressionOrString( + new AzureMapsControl.Components.Atlas.Expression[] + { + new AzureMapsControl.Components.Atlas.ExpressionOrString("get"), + new AzureMapsControl.Components.Atlas.ExpressionOrString("Color") + }) + } + }; - await eventArgs.Map.AddLayerAsync(layer); + await eventArgs.Map.AddLayerAsync(layer); + } + } } } \ No newline at end of file diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonExtrusionLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonExtrusionLayerOnReady.razor index 325683a..600f4b2 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonExtrusionLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonExtrusionLayerOnReady.razor @@ -16,6 +16,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var dataSource = new AzureMapsControl.Components.Data.DataSource(_datasourceId); await eventArgs.Map.AddSourceAsync(dataSource); @@ -24,6 +28,11 @@ public async Task OnDatasourceAdded(MapSourceEventArgs eventArgs) { + if (eventArgs.Source.Id != _datasourceId) + { + return; + } + var fillColorExpressionJsonString = "[\"step\", [\"get\", \"DENSITY\"], \"#00ff80\", 10, \"#09e076\", 20, \"#0bbf67\", 50, \"#f7e305\", 100, \"#f7c707\", 200, \"#f78205\", 500, \"#f75e05\", 1000, \"#f72505\", 10000, \"#6b0a05\"]"; var heightExpressionJsonString = "[\"interpolate\", [\"linear\"], [\"get\", \"DENSITY\"], 0, 100, 1200, 960000]"; diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonLayerOnReady.razor index 7faa0db..ec07092 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/PolygonLayerOnReady.razor @@ -16,6 +16,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var dataSource = new AzureMapsControl.Components.Data.DataSource(_dataSourceId); await eventArgs.Map.AddSourceAsync(dataSource); @@ -33,8 +37,13 @@ await dataSource.AddAsync(new AzureMapsControl.Components.Atlas.Shape(polygon)); } - public async Task OnDatasourceAdded(MapEventArgs sourceEventArgs) + public async Task OnDatasourceAdded(MapSourceEventArgs sourceEventArgs) { + if (sourceEventArgs.Source.Id != _dataSourceId) + { + return; + } + var layer = new AzureMapsControl.Components.Layers.PolygonLayer { EventActivationFlags = AzureMapsControl.Components.Layers.LayerEventActivationFlags.None().Enable(AzureMapsControl.Components.Layers.LayerEventType.Click), diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerOnReady.razor index 182a6fd..02c5674 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerOnReady.razor @@ -15,25 +15,20 @@ private readonly string _blueDatasourceId = "blueDatasource"; private readonly string _redDatasourceId = "redDatasource"; + private AzureMapsControl.Components.Data.DataSource? blueDataSource; + private AzureMapsControl.Components.Data.DataSource? redDataSource; + public async Task OnMapReady(MapEventArgs events) { - var blueDataSource = new AzureMapsControl.Components.Data.DataSource(_blueDatasourceId); - await events.Map.AddSourceAsync(blueDataSource); + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await events.Map.AddSourceAsync(dummyDataSource); - var redDataSource = new AzureMapsControl.Components.Data.DataSource(_redDatasourceId); + redDataSource = new AzureMapsControl.Components.Data.DataSource(_redDatasourceId); await events.Map.AddSourceAsync(redDataSource); - var bluePoints = new List(); - var redPoints = new List(); - - for (var i = 0; i < 10; i++) - { - bluePoints.Add(new AzureMapsControl.Components.Atlas.Shape(new AzureMapsControl.Components.Atlas.Point(new AzureMapsControl.Components.Atlas.Position(i * 5, i * 5)))); - redPoints.Add(new AzureMapsControl.Components.Atlas.Shape(new AzureMapsControl.Components.Atlas.Point(new AzureMapsControl.Components.Atlas.Position(i * -5, i * 5)))); - } - - await blueDataSource.AddAsync(bluePoints); - await redDataSource.AddAsync(redPoints); + blueDataSource = new AzureMapsControl.Components.Data.DataSource(_blueDatasourceId); + await events.Map.AddSourceAsync(blueDataSource); } public async Task OnDatasourceAdded(MapSourceEventArgs eventArgs) @@ -46,8 +41,25 @@ } }; - if (eventArgs.Source.Id == _redDatasourceId) + if (eventArgs.Source.Id == _blueDatasourceId && blueDataSource != null) { + var bluePoints = new List(); + for (var i = 0; i < 10; i++) + { + bluePoints.Add(new AzureMapsControl.Components.Atlas.Shape(new AzureMapsControl.Components.Atlas.Point(new AzureMapsControl.Components.Atlas.Position(i * 5, i * 5)))); + } + await blueDataSource.AddAsync(bluePoints); + } + + if (eventArgs.Source.Id == _redDatasourceId && redDataSource != null) + { + var redPoints = new List(); + for (var i = 0; i < 10; i++) + { + redPoints.Add(new AzureMapsControl.Components.Atlas.Shape(new AzureMapsControl.Components.Atlas.Point(new AzureMapsControl.Components.Atlas.Position(i * -5, i * 5)))); + } + await redDataSource.AddAsync(redPoints); + layer.Options.IconOptions = new AzureMapsControl.Components.Layers.IconOptions { Image = new AzureMapsControl.Components.Atlas.ExpressionOrString("pin-red") diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerWithFeatures.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerWithFeatures.razor index 4e3339a..6efbc9a 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerWithFeatures.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/SymbolLayerWithFeatures.razor @@ -15,6 +15,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var datasource = new AzureMapsControl.Components.Data.DataSource(_datasourceId); await eventArgs.Map.AddSourceAsync(datasource); @@ -30,6 +34,11 @@ public async Task OnDatasourceAdded(MapSourceEventArgs sourceEventArgs) { + if (sourceEventArgs.Source.Id != _datasourceId) + { + return; + } + var textFieldExpressionJsonString = "[\"format\", [\"get\", \"title\"], {\"text-font\": [\"literal\", [\"StandardFont-Bold\"]], \"font-scale\": 1.25}, \"\\n\", {}, [\"get\", \"subtitle\"], {\"font-scale\": 0.75}]"; var layer = new AzureMapsControl.Components.Layers.SymbolLayer diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/TileLayerOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/TileLayerOnReady.razor index b88980e..80ce2d7 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/TileLayerOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/TileLayerOnReady.razor @@ -12,6 +12,10 @@ @code { public async Task OnMapReady(MapEventArgs events) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await events.Map.AddSourceAsync(dummyDataSource); + var layer = new AzureMapsControl.Components.Layers.TileLayer { Options = new AzureMapsControl.Components.Layers.TileLayerOptions("https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/{z}/{x}/{y}.png"), diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Layers/VectorTileSource.razor b/samples/AzureMapsControl.Sample/Components/Pages/Layers/VectorTileSource.razor index 2d94c35..de8397a 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Layers/VectorTileSource.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Layers/VectorTileSource.razor @@ -22,6 +22,10 @@ public async Task OnMapReady(MapEventArgs events) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await events.Map.AddSourceAsync(dummyDataSource); + var source = new AzureMapsControl.Components.Data.VectorTileSource(_sourceId) { Options = new AzureMapsControl.Components.Data.VectorTileSourceOptions @@ -38,6 +42,11 @@ public async Task OnDatasourceAdded(MapSourceEventArgs eventArgs) { + if (eventArgs.Source.Id != _sourceId) + { + return; + } + var layer = new AzureMapsControl.Components.Layers.LineLayer { Options = new AzureMapsControl.Components.Layers.LineLayerOptions diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Popups/NoDefinedTemplate.razor b/samples/AzureMapsControl.Sample/Components/Pages/Popups/NoDefinedTemplate.razor index cce4d10..99b59af 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Popups/NoDefinedTemplate.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Popups/NoDefinedTemplate.razor @@ -17,6 +17,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var datasource = new AzureMapsControl.Components.Data.DataSource(); await eventArgs.Map.AddSourceAsync(datasource); diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Popups/PopupOnReady.razor b/samples/AzureMapsControl.Sample/Components/Pages/Popups/PopupOnReady.razor index bcd6706..0aa2a66 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Popups/PopupOnReady.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Popups/PopupOnReady.razor @@ -29,6 +29,11 @@ public async Task OnMapReady(MapEventArgs eventArgs) { var popupTemplate = "
    {name}
    {description}
    "; + + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var datasource = new AzureMapsControl.Components.Data.DataSource(); await eventArgs.Map.AddSourceAsync(datasource); diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Popups/ReusePopup.razor b/samples/AzureMapsControl.Sample/Components/Pages/Popups/ReusePopup.razor index 8da7cc0..c7962ea 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Popups/ReusePopup.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Popups/ReusePopup.razor @@ -28,6 +28,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var popupTemplate = "
    {name}
    {description}
    "; var datasource = new AzureMapsControl.Components.Data.DataSource { diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Sources/ExtrudedGriddedDatasource.razor b/samples/AzureMapsControl.Sample/Components/Pages/Sources/ExtrudedGriddedDatasource.razor index 8840613..0a2d16f 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Sources/ExtrudedGriddedDatasource.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Sources/ExtrudedGriddedDatasource.razor @@ -57,6 +57,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + var source = new AzureMapsControl.Components.Data.Grid.GriddedDataSource(_datasourceId) { Options = new AzureMapsControl.Components.Data.Grid.GriddedDataSourceOptions @@ -70,11 +74,16 @@ }; await eventArgs.Map.AddSourceAsync(source); - await source.ImportDataFromUrlAsync("https://azuremapscodesamples.azurewebsites.net/Common/data/geojson/address.json"); + await source.ImportDataFromUrlAsync("https://samples.azuremaps.com/data/geojson/address.json"); } public async Task OnSourceAdded(MapSourceEventArgs eventArgs) { + if (eventArgs.Source.Id != _datasourceId) + { + return; + } + var steppedExpJsonString = "[\"step\", [\"get\", \"point_count\"], \"#ffffb2\", 100, \"#fecc5c\", 200, \"#fd8d3c\", 300, \"#f03b20\", 400, \"#bd0026\"]"; var heightExp = "[\"interpolate\", [\"linear\"], [\"get\", \"point_count\"], 1, 10, 1000, 5000]"; var filterExp = "[\"==\", [\"get\", \"cell_id\"], \"\"]"; diff --git a/samples/AzureMapsControl.Sample/Components/Pages/Sources/GriddedDatasourceOptions.razor b/samples/AzureMapsControl.Sample/Components/Pages/Sources/GriddedDatasourceOptions.razor index 2e78b62..d4c738a 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/Sources/GriddedDatasourceOptions.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/Sources/GriddedDatasourceOptions.razor @@ -191,6 +191,10 @@ public async Task OnMapReady(MapEventArgs eventArgs) { + var dummyDataSourceId = "_empty"; + var dummyDataSource = new AzureMapsControl.Components.Data.DataSource(dummyDataSourceId); + await eventArgs.Map.AddSourceAsync(dummyDataSource); + _map = eventArgs.Map; _datasource = new AzureMapsControl.Components.Data.Grid.GriddedDataSource(_datasourceId) { @@ -208,6 +212,11 @@ public async Task OnSourceAdded(MapSourceEventArgs eventArgs) { + if (eventArgs.Source.Id != _datasourceId) + { + return; + } + _layer = new AzureMapsControl.Components.Layers.PolygonLayer { Options = new AzureMapsControl.Components.Layers.PolygonLayerOptions diff --git a/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs b/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs index 2e59c66..d0c3dde 100644 --- a/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs +++ b/src/AzureMapsControl.Components/Controls/OverviewMapControl.cs @@ -58,7 +58,7 @@ public async ValueTask SetOptionsAsync(Action update) Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.OverviewMapControl_UpdateAsync, $"Id: {Id}"); Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.OverviewMapControl_UpdateAsync, $"Type: {Type}"); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), MapId, Id.ToString(), Options); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), MapId, Id, Options); } } @@ -158,7 +158,7 @@ internal static void Write(Utf8JsonWriter writer, OverviewMapControl value) } if (value.Options.Style is not null) { - writer.WriteString("style", value.Options.Style.HasFirstChoice ? value.Options.Style.FirstChoice.ToString() : value.Options.Style.SecondChoice); + writer.WriteString("style", value.Options.Style.HasFirstChoice ? value.Options.Style.FirstChoice.ToString() : value.Options.Style.SecondChoice?.ToString() ?? "auto"); } if (value.Options.SyncBearingPitch.HasValue) { From ca5014898e2e845789829fd3df9a2faf6aaca9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Wed, 29 Oct 2025 14:19:22 +0200 Subject: [PATCH 06/12] Add sample pages and components for multiple simultaneous maps. --- .../Components/Layout/NavMenu.razor | 8 +- .../Components/Pages/MultipleMaps.razor | 139 ++++++++++++++++++ .../Components/Shared/FloatingMapPopup.razor | 116 +++++++++++++++ .../Components/Shared/MapPopupButton.razor | 70 +++++++++ 4 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor create mode 100644 samples/AzureMapsControl.Sample/Components/Shared/FloatingMapPopup.razor create mode 100644 samples/AzureMapsControl.Sample/Components/Shared/MapPopupButton.razor diff --git a/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor b/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor index ff54792..f98f11d 100644 --- a/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor +++ b/samples/AzureMapsControl.Sample/Components/Layout/NavMenu.razor @@ -1,4 +1,6 @@ -
  • + Multiple Maps + diff --git a/samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor b/samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor new file mode 100644 index 0000000..cda7e27 --- /dev/null +++ b/samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor @@ -0,0 +1,139 @@ +@page "/MultipleMaps" +@page "/MultipleMaps/Inline" +@rendermode InteractiveServer + +@using AzureMapsControl.Components.Map +@using AzureMapsControl.Components.Atlas +@using AzureMapsControl.Sample.Components.Shared +@inject IJSRuntime JSRuntime + +
    +
    +
    +

    Multiple Maps Demo

    +
    +
    + +
    +
    +
    +
    +
    Map 1 - Road View (Munich)
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    Map 2 - Satellite View (Munich)
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    Map 3 - Dark View (New York)
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    Map 4 - Grayscale View (London)
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + + +@code { + private CameraOptions munichCameraOptions = new CameraOptions + { + Type = CameraType.Fly, + Center = new Position(11.581990, 48.143534), + Zoom = 10 + }; + + private CameraOptions newYorkCameraOptions = new CameraOptions + { + Type = CameraType.Fly, + Center = new Position(-74.0060, 40.7128), + Zoom = 10 + }; + + private CameraOptions londonCameraOptions = new CameraOptions + { + Type = CameraType.Fly, + Center = new Position(-0.1276, 51.5074), + Zoom = 10 + }; + + private StyleOptions roadStyleOptions = new StyleOptions + { + Style = MapStyle.Road, + ShowLogo = false, + ShowFeedbackLink = false + }; + + private StyleOptions satelliteStyleOptions = new StyleOptions + { + Style = MapStyle.SatelliteRoadLabels, + ShowLogo = false, + ShowFeedbackLink = false + }; + + private StyleOptions darkStyleOptions = new StyleOptions + { + Style = MapStyle.Night, + ShowLogo = false, + ShowFeedbackLink = false + }; + + private StyleOptions grayscaleStyleOptions = new StyleOptions + { + Style = MapStyle.GrayscaleDark, + ShowLogo = false, + ShowFeedbackLink = false + }; +} \ No newline at end of file diff --git a/samples/AzureMapsControl.Sample/Components/Shared/FloatingMapPopup.razor b/samples/AzureMapsControl.Sample/Components/Shared/FloatingMapPopup.razor new file mode 100644 index 0000000..5a7694e --- /dev/null +++ b/samples/AzureMapsControl.Sample/Components/Shared/FloatingMapPopup.razor @@ -0,0 +1,116 @@ +@rendermode InteractiveServer +@using AzureMapsControl.Components.Map +@using AzureMapsControl.Components.Atlas + +@if (IsVisible) +{ +
    + + +
    +} + + + +@code { + [Parameter] public bool IsVisible { get; set; } = false; + [Parameter] public EventCallback IsVisibleChanged { get; set; } + [Parameter] public string Title { get; set; } = "Map Popup"; + [Parameter] public string MapId { get; set; } = "popup-map"; + [Parameter] public CameraOptions? CameraOptions { get; set; } + [Parameter] public StyleOptions? StyleOptions { get; set; } + [Parameter] public int Left { get; set; } = 100; + [Parameter] public int Top { get; set; } = 100; + [Parameter] public int Width { get; set; } = 500; + [Parameter] public int Height { get; set; } = 400; + + private bool IsMaximized = false; + + private string GetPopupStyle() + { + if (IsMaximized) + { + return "position: fixed; left: 0; top: 0; width: 100vw; height: 100vh; z-index: 1050; background: white; border: 2px solid #dee2e6; border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); display: flex; flex-direction: column;"; + } + return $"position: fixed; left: {Left}px; top: {Top}px; width: {Width}px; height: {Height}px; z-index: 1050; background: white; border: 2px solid #dee2e6; border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); display: flex; flex-direction: column;"; + } + + private async Task Close() + { + IsVisible = false; + await IsVisibleChanged.InvokeAsync(IsVisible); + } + + private void ToggleMaximize() + { + IsMaximized = !IsMaximized; + StateHasChanged(); + } +} \ No newline at end of file diff --git a/samples/AzureMapsControl.Sample/Components/Shared/MapPopupButton.razor b/samples/AzureMapsControl.Sample/Components/Shared/MapPopupButton.razor new file mode 100644 index 0000000..4eafd5f --- /dev/null +++ b/samples/AzureMapsControl.Sample/Components/Shared/MapPopupButton.razor @@ -0,0 +1,70 @@ +@rendermode InteractiveServer +@using AzureMapsControl.Components.Map +@using AzureMapsControl.Components.Atlas +@using AzureMapsControl.Sample.Components.Shared +@inject IJSRuntime JSRuntime + + + + + + + + +@code { + private bool popup1Visible = false; + private bool popup2Visible = false; + + private StyleOptions roadStyleOptions = new StyleOptions + { + Style = MapStyle.Road, + ShowLogo = false, + ShowFeedbackLink = false + }; + + private StyleOptions satelliteStyleOptions = new StyleOptions + { + Style = MapStyle.SatelliteRoadLabels, + ShowLogo = false, + ShowFeedbackLink = false + }; + + private CameraOptions tokyoCameraOptions = new CameraOptions + { + Type = CameraType.Fly, + Center = new Position(139.6917, 35.6895), + Zoom = 10 + }; + + private CameraOptions parisCameraOptions = new CameraOptions + { + Type = CameraType.Fly, + Center = new Position(2.3522, 48.8566), + Zoom = 10 + }; + + private async Task ShowFloatingMap() + { + if (popup2Visible) + { + popup1Visible = true; + } + else + { + popup2Visible = true; + } + StateHasChanged(); + } +} \ No newline at end of file From 96a401e7d59700996d52e9790c00672046cd6cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Mon, 3 Nov 2025 11:03:31 +0200 Subject: [PATCH 07/12] Fix map height turning 0. --- .../Components/Pages/MultipleMaps.razor | 5 ----- src/AzureMapsControl.Components/Map/AzureMap.razor | 5 ++++- src/AzureMapsControl.Components/typescript/core/core.ts | 6 ++++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor b/samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor index cda7e27..f166807 100644 --- a/samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor +++ b/samples/AzureMapsControl.Sample/Components/Pages/MultipleMaps.razor @@ -80,11 +80,6 @@ .map-container { height: 400px; } - - .map-container .atlas-map { - height: 100% !important; - width: 100% !important; - } @code { diff --git a/src/AzureMapsControl.Components/Map/AzureMap.razor b/src/AzureMapsControl.Components/Map/AzureMap.razor index 5575571..c2c16a9 100644 --- a/src/AzureMapsControl.Components/Map/AzureMap.razor +++ b/src/AzureMapsControl.Components/Map/AzureMap.razor @@ -14,7 +14,7 @@ @inject IMapJsRuntime JSRuntime @inject Microsoft.Extensions.Logging.ILogger Logger -
    +
    @code { @@ -444,6 +444,9 @@ Id, mapConfiguration, ServiceOptions, + CameraOptions, + StyleOptions, + UserInteractionOptions, enabledEvents, DotNetObjectReference.Create(_mapEventInvokeHelper)); } diff --git a/src/AzureMapsControl.Components/typescript/core/core.ts b/src/AzureMapsControl.Components/typescript/core/core.ts index 0313cbe..119304c 100644 --- a/src/AzureMapsControl.Components/typescript/core/core.ts +++ b/src/AzureMapsControl.Components/typescript/core/core.ts @@ -191,6 +191,9 @@ export class Core { public static addMap(mapId: string, configuration: Configuration, serviceOptions: azmaps.ServiceOptions, + cameraOptions: azmaps.CameraOptions | azmaps.CameraBoundsOptions, + styleOptions: azmaps.StyleOptions, + userInteractionOptions: azmaps.UserInteractionOptions, enabledEvents: string[], eventHelper: EventHelper): void { @@ -217,6 +220,9 @@ export class Core { const mapOptions: azmaps.ServiceOptions & azmaps.StyleOptions & azmaps.UserInteractionOptions & (azmaps.CameraOptions | azmaps.CameraBoundsOptions) = { ...serviceOptions, + ...cameraOptions, + ...styleOptions, + ...userInteractionOptions }; const map = new azmaps.Map(mapId, mapOptions); From 34956f049a08264af16840de9fabeb5fc56efe48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Mon, 3 Nov 2025 11:06:58 +0200 Subject: [PATCH 08/12] Fix issue with overviewmap sometimes not changing style with the map. --- .../typescript/controls/overviewmap-control.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts b/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts index e1ec76b..4c49ad2 100644 --- a/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts +++ b/src/AzureMapsControl.Components/typescript/controls/overviewmap-control.ts @@ -3,6 +3,9 @@ import { Core } from '../core/core'; export class OverviewMapControl { public static setOptions(mapId: string, controlId: string, options: overviewmap.OverviewMapOptions): void { + if(options.style == null || options.style["indexOf"] == null){ + options.style = "auto"; + } (Core.getMap(mapId).controls.getControls().find(ctrl => (ctrl as any).amc && (ctrl as any).amc.id === controlId) as overviewmap.control.OverviewMap).setOptions(options); } } \ No newline at end of file From c229466a83f0dfe791300bf2864466c8b48ee180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Tue, 4 Nov 2025 14:21:19 +0200 Subject: [PATCH 09/12] Undo unnecessary edits. --- .../Controls/FullScreenControl.cs | 8 +- .../Controls/GeolocationControl.cs | 8 +- .../Map/AzureMap.razor | 3 - .../typescript/core/core.ts | 12 +- .../Controls/FullScreenControl.cs | 22 +-- .../Controls/GeolocationControl.cs | 24 +-- .../Controls/OverviewMapControl.cs | 146 +++++++++--------- .../Indoor/IndoorService.cs | 4 +- 8 files changed, 107 insertions(+), 120 deletions(-) diff --git a/src/AzureMapsControl.Components/Controls/FullScreenControl.cs b/src/AzureMapsControl.Components/Controls/FullScreenControl.cs index a81aa7e..f096e28 100644 --- a/src/AzureMapsControl.Components/Controls/FullScreenControl.cs +++ b/src/AzureMapsControl.Components/Controls/FullScreenControl.cs @@ -61,7 +61,7 @@ public async ValueTask DisposeAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), MapId, Id.ToString()); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), MapId, Id); Disposed = true; OnDisposed?.Invoke(); } @@ -88,7 +88,7 @@ public async ValueTask SetOptionsAsync(Action update) update(Options); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), MapId, Id.ToString(), Options); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), MapId, Id, Options); } /// @@ -105,7 +105,7 @@ public async ValueTask IsFullScreenAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JsRuntime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), MapId, Id.ToString()); + return await JsRuntime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), MapId, Id); } internal async ValueTask AddEventsAsync() @@ -118,7 +118,7 @@ internal async ValueTask AddEventsAsync() await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.AddEvents.ToFullScreenControlNamespace(), MapId, - Id.ToString(), + Id, _eventFlags.EnabledEvents, DotNetObjectReference.Create(_eventInvokeHelper)); } diff --git a/src/AzureMapsControl.Components/Controls/GeolocationControl.cs b/src/AzureMapsControl.Components/Controls/GeolocationControl.cs index f599bb9..54c7b81 100644 --- a/src/AzureMapsControl.Components/Controls/GeolocationControl.cs +++ b/src/AzureMapsControl.Components/Controls/GeolocationControl.cs @@ -58,7 +58,7 @@ public async ValueTask> GetLastKnownPositionAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - return await JsRuntime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), MapId, Id.ToString()); + return await JsRuntime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), MapId, Id); } /// @@ -75,7 +75,7 @@ public async ValueTask DisposeAsync() EnsureJsRuntimeExists(); EnsureNotDisposed(); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), MapId, Id.ToString()); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), MapId, Id); Disposed = true; OnDisposed?.Invoke(); } @@ -102,7 +102,7 @@ public async ValueTask SetOptionsAsync(Action update) update(Options); - await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), MapId, Id.ToString(), Options); + await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), MapId, Id, Options); } internal async ValueTask AddEventsAsync() @@ -115,7 +115,7 @@ internal async ValueTask AddEventsAsync() await JsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.AddEvents.ToGeolocationControlNamespace(), MapId, - Id.ToString(), + Id, _eventFlags.EnabledEvents, DotNetObjectReference.Create(_eventInvokeHelper)); } diff --git a/src/AzureMapsControl.Components/Map/AzureMap.razor b/src/AzureMapsControl.Components/Map/AzureMap.razor index c2c16a9..96e0ec3 100644 --- a/src/AzureMapsControl.Components/Map/AzureMap.razor +++ b/src/AzureMapsControl.Components/Map/AzureMap.razor @@ -444,9 +444,6 @@ Id, mapConfiguration, ServiceOptions, - CameraOptions, - StyleOptions, - UserInteractionOptions, enabledEvents, DotNetObjectReference.Create(_mapEventInvokeHelper)); } diff --git a/src/AzureMapsControl.Components/typescript/core/core.ts b/src/AzureMapsControl.Components/typescript/core/core.ts index 119304c..82558af 100644 --- a/src/AzureMapsControl.Components/typescript/core/core.ts +++ b/src/AzureMapsControl.Components/typescript/core/core.ts @@ -191,9 +191,6 @@ export class Core { public static addMap(mapId: string, configuration: Configuration, serviceOptions: azmaps.ServiceOptions, - cameraOptions: azmaps.CameraOptions | azmaps.CameraBoundsOptions, - styleOptions: azmaps.StyleOptions, - userInteractionOptions: azmaps.UserInteractionOptions, enabledEvents: string[], eventHelper: EventHelper): void { @@ -218,14 +215,7 @@ export class Core { }) } - const mapOptions: azmaps.ServiceOptions & azmaps.StyleOptions & azmaps.UserInteractionOptions & (azmaps.CameraOptions | azmaps.CameraBoundsOptions) = { - ...serviceOptions, - ...cameraOptions, - ...styleOptions, - ...userInteractionOptions - }; - - const map = new azmaps.Map(mapId, mapOptions); + const map = new azmaps.Map(mapId, serviceOptions); if (enabledEvents.includes('error')) { map.events.add('error', event => { diff --git a/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs b/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs index bdf014c..373fe89 100644 --- a/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs +++ b/tests/AzureMapsControl.Components.Tests/Controls/FullScreenControl.cs @@ -94,7 +94,7 @@ public async Task Should_DisposeAsync() Assert.True(control.Disposed); Assert.True(eventTriggered); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -129,7 +129,7 @@ public async Task Should_NotDisposeTwice_Async() Assert.True(control.Disposed); Assert.True(eventTriggered); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -147,7 +147,7 @@ public async Task Should_SetOptionsAsync() Assert.Equal("container", control.Options.Container); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString(), control.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), _testMapId, control.Id, control.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -165,7 +165,7 @@ public async Task Should_SetOptions_NoOptionsCase_Async() Assert.Equal("container", control.Options.Container); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString(), control.Options), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.SetOptions.ToFullScreenControlNamespace(), _testMapId, control.Id, control.Options), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -193,7 +193,7 @@ public async Task Should_NotSetOptions_DisposedCase_Async() await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.SetOptionsAsync(options => options.Container = "container")); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -212,7 +212,7 @@ public async Task Should_GetIsFullScreenAsync() var result = await control.IsFullScreenAsync(); Assert.Equal(isFullScreen, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.FullScreenControl.IsFullScreen.ToFullScreenControlNamespace(), _testMapId, control.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -240,7 +240,7 @@ public async Task Should_NotGetIsFullScreen_DisposedCase_Async() await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.IsFullScreenAsync()); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.Dispose.ToFullScreenControlNamespace(), _testMapId, control.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -257,10 +257,10 @@ public async Task Should_AddEvents_Async() await control.AddEventsAsync(); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.FullScreenControl.AddEvents.ToFullScreenControlNamespace(), It.Is(parameters => - parameters[0] as string == _testMapId - && parameters[1] as string == control.Id.ToString() - && parameters[2] is IEnumerable - && (parameters[2] as IEnumerable).Single() == FullScreenEventType.FullScreenChanged.ToString() + parameters[0] as string == _testMapId + && (parameters[1] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() + && parameters[2] is IEnumerable + && (parameters[2] as IEnumerable).Single() == FullScreenEventType.FullScreenChanged.ToString() && parameters[3] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); diff --git a/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs b/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs index e2f6c63..1a8b8d1 100644 --- a/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs +++ b/tests/AzureMapsControl.Components.Tests/Controls/GeolocationControl.cs @@ -38,7 +38,7 @@ public async Task Should_GetLastKnowPositionAsync() var result = await control.GetLastKnownPositionAsync(); Assert.Equal(feature, result); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeAsync>(Constants.JsConstants.Methods.GeolocationControl.GetLastKnownPosition.ToGeolocationControlNamespace(), _testMapId, control.Id), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -54,7 +54,7 @@ public async Task Should_NotGetLastKnowPosition_IfAlreadyDisposed_Async() await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.GetLastKnownPositionAsync()); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -84,7 +84,7 @@ public async Task Should_DisposeAsync() Assert.True(control.Disposed); Assert.True(disposedCalled); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -100,7 +100,7 @@ public async Task Should_NotDispose_IfAlreadyDisposed_Async() await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.DisposeAsync()); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -126,7 +126,7 @@ public async Task Should_SetOptions_Async() Assert.True(control.Options.CalculateMissingValues); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString(), control.Options), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.SetOptions.ToGeolocationControlNamespace(), _testMapId, control.Id, control.Options), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -142,7 +142,7 @@ public async Task Should_NotSetOptions_DisposedCase_Async() await control.DisposeAsync(); await Assert.ThrowsAnyAsync(async () => await control.SetOptionsAsync(options => options.CalculateMissingValues = true)); - _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id.ToString()), Times.Once); + _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.Dispose.ToGeolocationControlNamespace(), _testMapId, control.Id), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } @@ -168,12 +168,12 @@ public async Task Should_AddEvents_Async() await control.AddEventsAsync(); _mapJsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.GeolocationControl.AddEvents.ToGeolocationControlNamespace(), It.Is(parameters => - parameters[0] as string == _testMapId - && parameters[1] as string == control.Id.ToString() - && parameters[2] is IEnumerable - && (parameters[2] as IEnumerable).Single() == GeolocationEventType.GeolocationError.ToString() - && parameters[3] is DotNetObjectReference -)), Times.Once); + parameters[0] as string == _testMapId + && (parameters[1] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() + && parameters[2] is IEnumerable + && (parameters[2] as IEnumerable).Single() == GeolocationEventType.GeolocationError.ToString() + && parameters[3] is DotNetObjectReference + )), Times.Once); _mapJsRuntimeMock.VerifyNoOtherCalls(); } diff --git a/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs b/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs index 67a110c..37ca18b 100644 --- a/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs +++ b/tests/AzureMapsControl.Components.Tests/Controls/OverviewMapControl.cs @@ -44,10 +44,10 @@ public async Task Should_UpdateAsync() await control.UpdateAsync(options => options.Interactive = true); Assert.True(options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - parameters[0] as string == _testMapId - && parameters[1] as string == control.Id.ToString() - && parameters[2] as OverviewMapControlOptions == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && (parameters[1] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -75,10 +75,10 @@ public async Task Should_SetOptionsAsync() await control.SetOptionsAsync(options => options.Interactive = true); Assert.True(options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - parameters[0] as string == _testMapId - && parameters[1] as string == control.Id.ToString() - && parameters[2] as OverviewMapControlOptions == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && (parameters[1] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -104,10 +104,10 @@ public async Task Should_UpdateAsyncWithDefaultOptionsAsync() await control.UpdateAsync(options => options.Interactive = true); Assert.True(control.Options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - parameters[0] as string == _testMapId - && parameters[1] as string == control.Id.ToString() - && parameters[2] as OverviewMapControlOptions == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && (parameters[1] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -123,10 +123,10 @@ public async Task Should_SetOptionsAsyncWithDefaultOptionsAsync() await control.SetOptionsAsync(options => options.Interactive = true); Assert.True(control.Options.Interactive); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.OverviewMapControl.SetOptions.ToOverviewMapControlNamespace(), It.Is(parameters => - parameters[0] as string == _testMapId - && parameters[1] as string == control.Id.ToString() - && parameters[2] as OverviewMapControlOptions == control.Options - )), Times.Once); + parameters[0] as string == _testMapId + && (parameters[1] as Guid?).GetValueOrDefault().ToString() == control.Id.ToString() + && parameters[2] as OverviewMapControlOptions == control.Options + )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } } @@ -166,36 +166,36 @@ public void Should_WriteWithControlStyle() }, ControlPosition.BottomLeft); var expectedJson = "{" - + "\"id\":\"" + control.Id + "\"" - + ",\"type\":\"" + control.Type + "\"" - + ",\"position\":\"" + control.Position.ToString() + "\"" - + ",\"options\":{" - + "\"height\":" + control.Options.Height.Value - + ",\"interactive\":" + control.Options.Interactive.Value - + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" - + ",\"markerOptions\":{" - + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" - + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" - + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value - + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" - + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" - + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" + + "\"id\":\"" + control.Id + "\"" + + ",\"type\":\"" + control.Type + "\"" + + ",\"position\":\"" + control.Position.ToString() + "\"" + + ",\"options\":{" + + "\"height\":" + control.Options.Height.Value + + ",\"interactive\":" + control.Options.Interactive.Value + + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" + + ",\"markerOptions\":{" + + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" + + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" + + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value + + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" + + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" + + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" + ",\"secondaryColor\":\"" + control.Options.MarkerOptions.SecondaryColor.ToString() + "\"" - + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" - + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value - + "}" - + ",\"minimized\":" + control.Options.Minimized.Value + + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" + + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value + + "}" + + ",\"minimized\":" + control.Options.Minimized.Value + ",\"overlay\":\"" + control.Options.Overlay.ToString() + "\"" - + ",\"showToggle\":" + control.Options.ShowToggle.Value - + ",\"style\":\"" + control.Options.Style.FirstChoice.ToString() + "\"" + + ",\"showToggle\":" + control.Options.ShowToggle.Value + + ",\"style\":\"" + control.Options.Style.FirstChoice.ToString() + "\"" + ",\"syncBearingPitch\":" + control.Options.SyncBearingPitch.Value - + ",\"syncZoom\":" + control.Options.SyncZoom.Value - + ",\"visible\":" + control.Options.Visible.Value - + ",\"width\":" + control.Options.Width.Value - + ",\"zoom\":" + control.Options.Zoom.Value - + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value - + "}" - + "}"; + + ",\"syncZoom\":" + control.Options.SyncZoom.Value + + ",\"visible\":" + control.Options.Visible.Value + + ",\"width\":" + control.Options.Width.Value + + ",\"zoom\":" + control.Options.Zoom.Value + + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value + + "}" + + "}"; TestAndAssertWrite(control, expectedJson); } @@ -231,36 +231,36 @@ public void Should_WriteWithCssStyle() }, ControlPosition.BottomLeft); var expectedJson = "{" - + "\"id\":\"" + control.Id + "\"" - + ",\"type\":\"" + control.Type + "\"" - + ",\"position\":\"" + control.Position.ToString() + "\"" - + ",\"options\":{" - + "\"height\":" + control.Options.Height.Value - + ",\"interactive\":" + control.Options.Interactive.Value - + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" - + ",\"markerOptions\":{" - + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" - + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" - + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value - + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" - + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" - + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" - + ",\"secondaryColor\":\"" + control.Options.MarkerOptions.SecondaryColor.ToString() + "\"" - + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" - + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value - + "}" - + ",\"minimized\":" + control.Options.Minimized.Value - + ",\"overlay\":\"" + control.Options.Overlay.ToString() + "\"" - + ",\"showToggle\":" + control.Options.ShowToggle.Value - + ",\"style\":\"" + control.Options.Style.SecondChoice + "\"" - + ",\"syncBearingPitch\":" + control.Options.SyncBearingPitch.Value - + ",\"syncZoom\":" + control.Options.SyncZoom.Value - + ",\"visible\":" + control.Options.Visible.Value - + ",\"width\":" + control.Options.Width.Value - + ",\"zoom\":" + control.Options.Zoom.Value - + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value - + "}" - + "}"; + + "\"id\":\"" + control.Id + "\"" + + ",\"type\":\"" + control.Type + "\"" + + ",\"position\":\"" + control.Position.ToString() + "\"" + + ",\"options\":{" + + "\"height\":" + control.Options.Height.Value + + ",\"interactive\":" + control.Options.Interactive.Value + + ",\"mapStyle\":\"" + control.Options.MapStyle.ToString() + "\"" + + ",\"markerOptions\":{" + + "\"anchor\":\"" + control.Options.MarkerOptions.Anchor.ToString() + "\"" + + ",\"color\":\"" + control.Options.MarkerOptions.Color.ToString() + "\"" + + ",\"draggable\":" + control.Options.MarkerOptions.Draggable.Value + + ",\"htmlContent\":\"" + control.Options.MarkerOptions.HtmlContent.ToString() + "\"" + + ",\"pixelOffset\":[" + control.Options.MarkerOptions.PixelOffset.X + "," + control.Options.MarkerOptions.PixelOffset.Y + "]" + + ",\"position\":[" + control.Options.MarkerOptions.Position.Longitude + "," + control.Options.MarkerOptions.Position.Latitude + "," + control.Options.MarkerOptions.Position.Elevation.Value + "]" + + ",\"secondaryColor\":\"" + control.Options.MarkerOptions.SecondaryColor.ToString() + "\"" + + ",\"text\":\"" + control.Options.MarkerOptions.Text.ToString() + "\"" + + ",\"visible\":" + control.Options.MarkerOptions.Visible.Value + + "}" + + ",\"minimized\":" + control.Options.Minimized.Value + + ",\"overlay\":\"" + control.Options.Overlay.ToString() + "\"" + + ",\"showToggle\":" + control.Options.ShowToggle.Value + + ",\"style\":\"" + control.Options.Style.SecondChoice + "\"" + + ",\"syncBearingPitch\":" + control.Options.SyncBearingPitch.Value + + ",\"syncZoom\":" + control.Options.SyncZoom.Value + + ",\"visible\":" + control.Options.Visible.Value + + ",\"width\":" + control.Options.Width.Value + + ",\"zoom\":" + control.Options.Zoom.Value + + ",\"zoomOffset\":" + control.Options.ZoomOffset.Value + + "}" + + "}"; TestAndAssertWrite(control, expectedJson); } diff --git a/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs b/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs index b3c0a29..10e5ec0 100644 --- a/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs +++ b/tests/AzureMapsControl.Components.Tests/Indoor/IndoorService.cs @@ -34,9 +34,9 @@ public async Task Should_CreateIndoorManager_WithMapId_Async() _jsRuntime.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Indoor.CreateIndoorManager.ToIndoorNamespace(), It.Is(parameters => (parameters[0] as string) == TestMapId - && (parameters[1] as string) == indoorManager.Id + && (parameters[1] as string) == indoorManager.Id && object.Equals(parameters[2], options) - && parameters[3] == null + && parameters[3] == null && parameters[4] is DotNetObjectReference )), Times.Once); _jsRuntime.VerifyNoOtherCalls(); From d5b13f61b906d5ee86265e6371d070dd46395702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Tue, 4 Nov 2025 15:29:20 +0200 Subject: [PATCH 10/12] Clean up map tests. --- .../Map/Map.cs | 345 ++++++++++-------- 1 file changed, 201 insertions(+), 144 deletions(-) diff --git a/tests/AzureMapsControl.Components.Tests/Map/Map.cs b/tests/AzureMapsControl.Components.Tests/Map/Map.cs index b896ef1..5475cd8 100644 --- a/tests/AzureMapsControl.Components.Tests/Map/Map.cs +++ b/tests/AzureMapsControl.Components.Tests/Map/Map.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Linq; - using System.Text; using System.Threading.Tasks; using AzureMapsControl.Components.Atlas; @@ -50,7 +49,7 @@ public void Should_BeInitialized() public async Task Should_AddControls_Async() { var controls = new List { - new CompassControl() + new CompassControl() }; const string id = "id"; @@ -60,7 +59,7 @@ public async Task Should_AddControls_Async() Assert.Equal(controls, map.Controls); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), id, It.Is>( - ctrls => ctrls.Single() == controls.Single())), Times.Once); + ctrls => ctrls.Single() == controls.Single())), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -69,7 +68,7 @@ public async Task Should_AddOrderedControls_Async() { var controls = new List { new OverviewMapControl(), - new CompassControl() + new CompassControl() }; const string id = "id"; @@ -79,7 +78,7 @@ public async Task Should_AddOrderedControls_Async() Assert.Equal(controls, map.Controls); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddControls.ToCoreNamespace(), id, It.Is>( - ctrls => ctrls.First() == controls.ElementAt(1) && ctrls.ElementAt(1) == controls.First())), Times.Once); + ctrls => ctrls.First() == controls.ElementAt(1) && ctrls.ElementAt(1) == controls.First())), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -126,9 +125,10 @@ public async Task Should_AddControls_ParamsVersion_Async() [Fact] public async Task Should_AddHtmlMarkers_Async() { + const string id = "id"; var markers = new List { new HtmlMarker(null), new HtmlMarker(null) }; var popupInvokeHelper = new PopupInvokeHelper(null); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask), popupInvokeHelper: popupInvokeHelper); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask), popupInvokeHelper: popupInvokeHelper); await map.AddHtmlMarkersAsync(markers); Assert.Contains(markers[0], map.HtmlMarkers); @@ -139,7 +139,7 @@ public async Task Should_AddHtmlMarkers_Async() Assert.Equal(markers[1].PopupInvokeHelper, popupInvokeHelper); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 && parameters[2] is DotNetObjectReference )), Times.Once); @@ -149,6 +149,7 @@ public async Task Should_AddHtmlMarkers_Async() [Fact] public async Task Should_AddHtmlMarkers_WithPopup_WithAutoOpenAsync() { + const string id = "id"; var assertEvent = false; var popup = new HtmlMarkerPopup(new PopupOptions { OpenOnAdd = true @@ -160,7 +161,7 @@ public async Task Should_AddHtmlMarkers_WithPopup_WithAutoOpenAsync() marker.OnPopupToggled += () => assertEvent = true; var popupInvokeHelper = new PopupInvokeHelper(null); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask), popupInvokeHelper: popupInvokeHelper); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask), popupInvokeHelper: popupInvokeHelper); await map.AddHtmlMarkersAsync(marker); Assert.True(assertEvent); @@ -168,12 +169,12 @@ public async Task Should_AddHtmlMarkers_WithPopup_WithAutoOpenAsync() Assert.Equal(marker.JSRuntime, _jsRuntimeMock.Object); Assert.Equal(marker.PopupInvokeHelper, popupInvokeHelper); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 1 && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.HtmlMarker.TogglePopup.ToHtmlMarkerNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == marker.Id && parameters[2] as string == marker.Options.Popup.Id && parameters[3] is IEnumerable @@ -185,10 +186,11 @@ public async Task Should_AddHtmlMarkers_WithPopup_WithAutoOpenAsync() [Fact] public async Task Should_AddHtmlMarkers_ParamsVersion_Async() { + const string id = "id"; var marker1 = new HtmlMarker(null); var marker2 = new HtmlMarker(null); var popupInvokeHelper = new PopupInvokeHelper(null); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask), popupInvokeHelper: popupInvokeHelper); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask), popupInvokeHelper: popupInvokeHelper); await map.AddHtmlMarkersAsync(marker1, marker2); Assert.Contains(marker1, map.HtmlMarkers); @@ -198,7 +200,7 @@ public async Task Should_AddHtmlMarkers_ParamsVersion_Async() Assert.Equal(marker1.PopupInvokeHelper, popupInvokeHelper); Assert.Equal(marker2.PopupInvokeHelper, popupInvokeHelper); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 && parameters[2] is DotNetObjectReference )), Times.Once); @@ -208,12 +210,13 @@ public async Task Should_AddHtmlMarkers_ParamsVersion_Async() [Fact] public async Task Should_UpdateHtmlMarkers_Async() { + const string id = "id"; var updates = new List { new HtmlMarkerUpdate(new HtmlMarker(null, null), null), new HtmlMarkerUpdate(new HtmlMarker(null, null), null) }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object); await map.UpdateHtmlMarkersAsync(updates); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.UpdateHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == updates.Count) ), Times.Once); @@ -232,13 +235,14 @@ public async Task Should_NotUpdateHtmlMarkers_NullCaseAsync() [Fact] public async Task Should_UpdateHtmlMarkers_ParamsVersion_Async() { + const string id = "id"; var update1 = new HtmlMarkerUpdate(new HtmlMarker(null, null), null); var update2 = new HtmlMarkerUpdate(new HtmlMarker(null, null), null); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object); await map.UpdateHtmlMarkersAsync(update1, update2); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.UpdateHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2) ), Times.Once); @@ -257,14 +261,15 @@ public async Task Shoud_NotRemoveAnyHtmlMarkers_Async() [Fact] public async Task Shoud_NotRemoveAnyHtmlMarkers_Null_Async() { - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); var htmlMarker = new HtmlMarker(null); await map.AddHtmlMarkersAsync(htmlMarker); await map.RemoveHtmlMarkersAsync(null); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 1 && parameters[2] is DotNetObjectReference )), Times.Once); @@ -274,10 +279,11 @@ public async Task Shoud_NotRemoveAnyHtmlMarkers_Null_Async() [Fact] public async Task Shoud_RemoveAnyHtmlMarkers_Async() { + const string id = "id"; var htmlMarker = new HtmlMarker(null); var htmlMarker2 = new HtmlMarker(null); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddHtmlMarkersAsync(new List { htmlMarker, htmlMarker2 }); await map.RemoveHtmlMarkersAsync(htmlMarker); @@ -285,24 +291,25 @@ public async Task Shoud_RemoveAnyHtmlMarkers_Async() Assert.Contains(htmlMarker2, map.HtmlMarkers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" - && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Single() == htmlMarker.Id) - ), Times.Once); + parameters[0] as string == id + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Single() == htmlMarker.Id) + ), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Shoud_RemoveAnyHtmlMarkers_ParamsVersion_Async() { + const string id = "id"; var htmlMarker = new HtmlMarker(null); var htmlMarker2 = new HtmlMarker(null); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddHtmlMarkersAsync(htmlMarker, htmlMarker2); await map.RemoveHtmlMarkersAsync(htmlMarker); @@ -310,12 +317,12 @@ public async Task Shoud_RemoveAnyHtmlMarkers_ParamsVersion_Async() Assert.Contains(htmlMarker2, map.HtmlMarkers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 2 && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Single() == htmlMarker.Id) ), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -324,14 +331,15 @@ public async Task Shoud_RemoveAnyHtmlMarkers_ParamsVersion_Async() [Fact] public async Task Should_AddDrawingToolbar_Async() { + const string id = "id"; var drawingToolbarOptions = new DrawingToolbarOptions(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddDrawingToolbarAsync(drawingToolbarOptions); Assert.Equal(drawingToolbarOptions, map.DrawingToolbarOptions); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is DrawingToolbarCreationOptions && parameters[2] is DotNetObjectReference )), Times.Once); @@ -341,6 +349,7 @@ public async Task Should_AddDrawingToolbar_Async() [Fact] public async Task Should_UpdateDrawingToolbar_Async() { + const string id = "id"; var drawingToolbarOptions = new DrawingToolbarOptions(); var updateDrawingToolbarOptions = new DrawingToolbarUpdateOptions { Buttons = new List(), @@ -350,7 +359,7 @@ public async Task Should_UpdateDrawingToolbar_Async() Style = DrawingToolbarStyle.Dark, Visible = false }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddDrawingToolbarAsync(drawingToolbarOptions); await map.UpdateDrawingToolbarAsync(updateDrawingToolbarOptions); @@ -362,12 +371,12 @@ public async Task Should_UpdateDrawingToolbar_Async() Assert.Equal(updateDrawingToolbarOptions.Visible, map.DrawingToolbarOptions.Visible); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is DrawingToolbarCreationOptions && parameters[2] is DotNetObjectReference )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.UpdateDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is DrawingToolbarCreationOptions )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -376,13 +385,14 @@ public async Task Should_UpdateDrawingToolbar_Async() [Fact] public async Task Should_NotUpdateDrawingToolbar_NullCaseAsync() { + const string id = "id"; var drawingToolbarOptions = new DrawingToolbarOptions(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddDrawingToolbarAsync(drawingToolbarOptions); await map.UpdateDrawingToolbarAsync(null); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is DrawingToolbarCreationOptions && parameters[2] is DotNetObjectReference )), Times.Once); @@ -392,14 +402,15 @@ public async Task Should_NotUpdateDrawingToolbar_NullCaseAsync() [Fact] public async Task Should_RemoveDrawingToolbar_Async() { - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddDrawingToolbarAsync(new DrawingToolbarOptions()); await map.RemoveDrawingToolbarAsync(); Assert.Null(map.DrawingToolbarOptions); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawingToolbar.ToDrawingNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is DrawingToolbarCreationOptions && parameters[2] is DotNetObjectReference )), Times.Once); @@ -421,14 +432,15 @@ public async Task Should_NotRemoveDrawingToolbar_Async() [Fact] public async Task Should_AddALayer_Async() { + const string id = "id"; var layer = new BubbleLayer(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer); Assert.Contains(layer, map.Layers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == layer.Id && parameters[2] == null && parameters[3] as string == layer.Type.ToString() @@ -454,15 +466,16 @@ public async Task Should_NotAddALayer_NullCaseAsync() [Fact] public async Task Should_AddALayerWithBefore_Async() { + const string id = "id"; var layer = new BubbleLayer(); const string before = "before"; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer, before); Assert.Contains(layer, map.Layers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == layer.Id && parameters[2] as string == before && parameters[3] as string == layer.Type.ToString() @@ -476,14 +489,15 @@ public async Task Should_AddALayerWithBefore_Async() [Fact] public async Task Should_NotAddLayerWithSameId_Async() { + const string id = "id"; var layer = new BubbleLayer(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer); await Assert.ThrowsAnyAsync(async () => await map.AddLayerAsync(layer)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == layer.Id && parameters[2] == null && parameters[3] as string == layer.Type.ToString() @@ -497,10 +511,11 @@ public async Task Should_NotAddLayerWithSameId_Async() [Fact] public async Task Should_RemoveOneLayer_Async() { + const string id = "id"; var layer1 = new BubbleLayer(); var layer2 = new BubbleLayer(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer1); await map.AddLayerAsync(layer2); await map.RemoveLayersAsync(layer1); @@ -510,7 +525,7 @@ public async Task Should_RemoveOneLayer_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -519,10 +534,11 @@ public async Task Should_RemoveOneLayer_Async() [Fact] public async Task Should_RemoveMultipleLayers_Async() { + const string id = "id"; var layer1 = new BubbleLayer(); var layer2 = new BubbleLayer(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer1); await map.AddLayerAsync(layer2); await map.RemoveLayersAsync(new List { layer1, layer2 }); @@ -532,7 +548,7 @@ public async Task Should_RemoveMultipleLayers_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -541,10 +557,11 @@ public async Task Should_RemoveMultipleLayers_Async() [Fact] public async Task Should_RemoveMultipleLayers_ParamsVersion_Async() { + const string id = "id"; var layer1 = new BubbleLayer(); var layer2 = new BubbleLayer(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer1); await map.AddLayerAsync(layer2); await map.RemoveLayersAsync(layer1, layer2); @@ -554,7 +571,7 @@ public async Task Should_RemoveMultipleLayers_ParamsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -563,10 +580,11 @@ public async Task Should_RemoveMultipleLayers_ParamsVersion_Async() [Fact] public async Task Should_RemoveMultipleLayers_ViaId_Async() { + const string id = "id"; var layer1 = new BubbleLayer(); var layer2 = new BubbleLayer(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer1); await map.AddLayerAsync(layer2); await map.RemoveLayersAsync(new List { layer1.Id, layer2.Id }); @@ -576,7 +594,7 @@ public async Task Should_RemoveMultipleLayers_ViaId_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -585,10 +603,11 @@ public async Task Should_RemoveMultipleLayers_ViaId_Async() [Fact] public async Task Should_RemoveMultipleLayers_ViaId_ParamsVersion_Async() { + const string id = "id"; var layer1 = new BubbleLayer(); var layer2 = new BubbleLayer(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(layer1); await map.AddLayerAsync(layer2); await map.RemoveLayersAsync(layer1.Id, layer2.Id); @@ -598,7 +617,7 @@ public async Task Should_RemoveMultipleLayers_ViaId_ParamsVersion_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Exactly(2)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveLayers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is IEnumerable )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -607,11 +626,12 @@ public async Task Should_RemoveMultipleLayers_ViaId_ParamsVersion_Async() [Fact] public async Task Should_AddDataSource_Async() { + const string id = "id"; var dataSource = new DataSource { EventActivationFlags = DataSourceEventActivationFlags.None().Enable(DataSourceEventType.DataAdded) }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); await map.AddSourceAsync(dataSource); Assert.Single(map.Sources, dataSource); @@ -619,7 +639,7 @@ public async Task Should_AddDataSource_Async() Assert.Equal(_loggerMock.Object, dataSource.Logger); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource.Id && parameters[2] == null && parameters[3] as string == dataSource.SourceType.ToString() @@ -632,15 +652,16 @@ public async Task Should_AddDataSource_Async() [Fact] public async Task Should_AddVectorTileSourceAsync() { + const string id = "id"; var source = new VectorTileSource(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object); await map.AddSourceAsync(source); Assert.Single(map.Sources, source); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == source.Id && parameters[2] == null && parameters[3] as string == source.SourceType.ToString() @@ -651,13 +672,14 @@ public async Task Should_AddVectorTileSourceAsync() [Fact] public async Task Should_NotAddDataSource_Async() { + const string id = "id"; var dataSource = new DataSource(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); await map.AddSourceAsync(dataSource); await Assert.ThrowsAnyAsync(async () => await map.AddSourceAsync(dataSource)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource.Id && parameters[2] == null && parameters[3] as string == dataSource.SourceType.ToString() @@ -677,9 +699,10 @@ public async Task Should_NotAddDataSource_NullCaseAsync() [Fact] public async Task Should_RemoveDataSource_Async() { + const string id = "id"; var dataSource = new DataSource(); var dataSource2 = new DataSource(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); await map.AddSourceAsync(dataSource); await map.AddSourceAsync(dataSource2); @@ -689,27 +712,28 @@ public async Task Should_RemoveDataSource_Async() Assert.Contains(dataSource2, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource.Id && parameters[2] == null && parameters[3] as string == dataSource.SourceType.ToString() )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource2.Id && parameters[2] == null && parameters[3] as string == dataSource2.SourceType.ToString() )), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), "id", dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), id, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_NotRemoveDataSource_Async() { + const string id = "id"; var dataSource = new DataSource(); var dataSource2 = new DataSource(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); await map.AddSourceAsync(dataSource); await map.RemoveDataSourceAsync(dataSource2); @@ -718,7 +742,7 @@ public async Task Should_NotRemoveDataSource_Async() Assert.Contains(dataSource, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource.Id && parameters[2] == null && parameters[3] as string == dataSource.SourceType.ToString() @@ -729,9 +753,10 @@ public async Task Should_NotRemoveDataSource_Async() [Fact] public async Task Should_RemoveDataSource_ViaId_Async() { + const string id = "id"; var dataSource = new DataSource(); var dataSource2 = new DataSource(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); await map.AddSourceAsync(dataSource); await map.AddSourceAsync(dataSource2); @@ -741,27 +766,28 @@ public async Task Should_RemoveDataSource_ViaId_Async() Assert.Contains(dataSource2, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource.Id && parameters[2] == null && parameters[3] as string == dataSource.SourceType.ToString() )), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource2.Id && parameters[2] == null && parameters[3] as string == dataSource2.SourceType.ToString() )), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), "id", dataSource.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.RemoveSource.ToCoreNamespace(), id, dataSource.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_NotRemoveDataSource_ViaId_Async() { + const string id = "id"; var dataSource = new DataSource(); var dataSource2 = new DataSource(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); await map.AddSourceAsync(dataSource); await map.RemoveDataSourceAsync(dataSource2.Id); @@ -770,7 +796,7 @@ public async Task Should_NotRemoveDataSource_ViaId_Async() Assert.Contains(dataSource, map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == dataSource.Id && parameters[2] == null && parameters[3] as string == dataSource.SourceType.ToString() @@ -781,7 +807,8 @@ public async Task Should_NotRemoveDataSource_ViaId_Async() [Fact] public async Task Should_ClearMap_Async() { - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask), + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, new DrawingToolbarEventInvokeHelper(eventArgs => ValueTask.CompletedTask), new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask), new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask), new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask), @@ -802,41 +829,44 @@ public async Task Should_ClearMap_Async() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.IsAny()), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearMap.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearMap.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_ClearLayers_Async() { - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, layerEventInvokeHelper: new LayerEventInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddLayerAsync(new BubbleLayer()); await map.ClearLayersAsync(); Assert.Null(map.Layers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddLayer.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearLayers.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearLayers.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_ClearDataSources_Async() { - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, dataSourceEventInvokeHelper: new DataSourceEventInvokeHelper(_ => ValueTask.CompletedTask)); await map.AddSourceAsync(new DataSource()); await map.ClearDataSourcesAsync(); Assert.Null(map.Sources); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddSource.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearSources.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearSources.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_ClearHtmlMarkers_Async() { - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, htmlMarkerInvokeHelper: new HtmlMarkerInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddHtmlMarkersAsync(new HtmlMarker(null)); await map.ClearHtmlMarkersAsync(); @@ -844,25 +874,26 @@ public async Task Should_ClearHtmlMarkers_Async() Assert.Null(map.HtmlMarkers); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddHtmlMarkers.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" - && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 1 - && parameters[2] is DotNetObjectReference - )), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearHtmlMarkers.ToCoreNamespace(), "id"), Times.Once); + parameters[0] as string == id + && parameters[1] is IEnumerable && (parameters[1] as IEnumerable).Count() == 1 + && parameters[2] is DotNetObjectReference + )), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearHtmlMarkers.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_AddPopup_Async() { + const string id = "id"; var popup = new Popup(new PopupOptions()); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddPopupAsync(popup); Assert.Contains(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == popup.Id && parameters[2] as PopupOptions == popup.Options && parameters[3] is IEnumerable @@ -882,13 +913,14 @@ public async Task Should_NotAddPopup_NullCaseAsync() [Fact] public async Task Should_NotAddTwiceTheSamePopup_Async() { + const string id = "id"; var popup = new Popup(new PopupOptions()); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddPopupAsync(popup); await Assert.ThrowsAnyAsync(async () => await map.AddPopupAsync(popup)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == popup.Id && parameters[2] as PopupOptions == popup.Options && parameters[3] is IEnumerable @@ -900,16 +932,17 @@ public async Task Should_NotAddTwiceTheSamePopup_Async() [Fact] public async Task Should_AddPopupWithTemplate_Async() { + const string id = "id"; var popup = new Popup(new PopupOptions()); var popupTemplate = new PopupTemplate(); var properties = new Dictionary(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddPopupAsync(popup, popupTemplate, properties); Assert.Contains(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopupWithTemplate.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == popup.Id && parameters[2] as PopupOptions == popup.Options && parameters[3] is IDictionary @@ -953,15 +986,16 @@ public async Task Should_NotAddPopupWithTemplate_NullPropertiesCaseAsync() [Fact] public async Task Should_NotAddTwiceTheSamePopupWithTemplate_Async() { + const string id = "id"; var popup = new Popup(new PopupOptions()); var popupTemplate = new PopupTemplate(); var properties = new Dictionary(); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddPopupAsync(popup, popupTemplate, properties); await Assert.ThrowsAnyAsync(async () => await map.AddPopupAsync(popup, popupTemplate, properties)); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopupWithTemplate.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] as string == popup.Id && parameters[2] as PopupOptions == popup.Options && parameters[3] is IDictionary @@ -975,32 +1009,34 @@ public async Task Should_NotAddTwiceTheSamePopupWithTemplate_Async() [Fact] public async Task Should_RemovePopup_Async() { + const string id = "id"; var popup = new Popup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddPopupAsync(popup); await map.RemovePopupAsync(popup); Assert.DoesNotContain(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), "id", popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), id, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_RemovePopup_IdVersion_Async() { + const string id = "id"; var popup = new Popup(new PopupOptions()) { JSRuntime = _jsRuntimeMock.Object }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddPopupAsync(popup); await map.RemovePopupAsync(popup.Id); Assert.DoesNotContain(popup, map.Popups); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), "id", popup.Id), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Popup.Remove.ToPopupNamespace(), id, popup.Id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1019,31 +1055,33 @@ public async Task Should_NotRemovePopup_Async() [Fact] public async Task Should_ClearPopups_Async() { + const string id = "id"; var popup = new Popup(new PopupOptions()); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object, popupInvokeHelper: new PopupInvokeHelper(eventArgs => ValueTask.CompletedTask)); await map.AddPopupAsync(popup); await map.ClearPopupsAsync(); Assert.Null(map.Popups); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearPopups.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.ClearPopups.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.AddPopup.ToCoreNamespace(), It.IsAny()), Times.Once); } [Fact] public async Task Should_UpdateCameraOptions_Async() { + const string id = "id"; var center = new Position(10, 10); var initialCameraOptions = new CameraOptions { Duration = 10 }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object) { + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object) { CameraOptions = initialCameraOptions }; await map.SetCameraOptionsAsync(options => options.Center = center); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as CameraOptions).Duration == 10 && (parameters[1] as CameraOptions).Center.Longitude == 10 && (parameters[1] as CameraOptions).Center.Latitude == 10 )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1052,18 +1090,19 @@ public async Task Should_UpdateCameraOptions_Async() [Fact] public async Task Should_UpdateCameraOptions_WithCenter_Async() { + const string id = "id"; var center = new Position(10, 10); var initialCameraOptions = new CameraOptions { Duration = 10 }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object) { + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object) { CameraOptions = initialCameraOptions }; await map.SetCameraOptionsAsync(options => options.Center = center); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as CameraOptions).Duration == 10 && (parameters[1] as CameraOptions).Center.Longitude == 10 && (parameters[1] as CameraOptions).Center.Latitude == 10 )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1072,11 +1111,12 @@ public async Task Should_UpdateCameraOptions_WithCenter_Async() [Fact] public async Task Should_UpdateCameraOptions_WithBounds_Async() { + const string id = "id"; var bounds = new BoundingBox(-10, 10, 10, -10); var initialCameraOptions = new CameraOptions { Duration = 10 }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object) { + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object) { CameraOptions = initialCameraOptions }; @@ -1086,7 +1126,7 @@ await map.SetCameraOptionsAsync(options => { }); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as CameraOptions).Duration == 10 && (parameters[1] as CameraOptions).Center == null && (parameters[1] as CameraOptions).Bounds.West == -10 && (parameters[1] as CameraOptions).Bounds.South == 10 && (parameters[1] as CameraOptions).Bounds.East == 10 @@ -1098,12 +1138,13 @@ await map.SetCameraOptionsAsync(options => { [Fact] public async Task Should_UpdateCameraOptions_NoCameraOptionsDefined_Async() { + const string id = "id"; var center = new Position(10, 10); - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object); await map.SetCameraOptionsAsync(options => options.Center = center); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCameraOptions.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as CameraOptions).Center.Longitude == 10 && (parameters[1] as CameraOptions).Center.Latitude == 10 )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1112,17 +1153,18 @@ public async Task Should_UpdateCameraOptions_NoCameraOptionsDefined_Async() [Fact] public async Task Should_UpdateStyleOptions_Async() { + const string id = "id"; var language = "fr"; var initialStyleOptions = new StyleOptions { AutoResize = true }; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object) { + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object) { StyleOptions = initialStyleOptions }; await map.SetStyleOptionsAsync(options => options.Language = language); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetStyleOptions.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as StyleOptions).AutoResize && (parameters[1] as StyleOptions).Language == "fr" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1131,12 +1173,13 @@ public async Task Should_UpdateStyleOptions_Async() [Fact] public async Task Should_UpdateStyleOptions_NoStyleOptionsDefined_Async() { + const string id = "id"; var language = "fr"; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object); await map.SetStyleOptionsAsync(options => options.Language = language); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetStyleOptions.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as StyleOptions).Language == "fr" )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1145,17 +1188,18 @@ public async Task Should_UpdateStyleOptions_NoStyleOptionsDefined_Async() [Fact] public async Task Should_UpdateUserInteraction_Async() { + const string id = "id"; var initialUserInteractionOptions = new UserInteractionOptions { BoxZoomInteraction = true }; var dblClickZoomInteraction = true; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object) { + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object) { UserInteractionOptions = initialUserInteractionOptions }; await map.SetUserInteractionAsync(options => options.DblclickZoomInteraction = dblClickZoomInteraction); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetUserInteraction.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as UserInteractionOptions).BoxZoomInteraction.GetValueOrDefault() && (parameters[1] as UserInteractionOptions).DblclickZoomInteraction.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1164,12 +1208,13 @@ public async Task Should_UpdateUserInteraction_Async() [Fact] public async Task Should_UpdateUserInteraction_NoUserInteractionDefined_Async() { + const string id = "id"; var dblClickZoomInteraction = true; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object); await map.SetUserInteractionAsync(options => options.DblclickZoomInteraction = dblClickZoomInteraction); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetUserInteraction.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as UserInteractionOptions).DblclickZoomInteraction.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1178,17 +1223,18 @@ public async Task Should_UpdateUserInteraction_NoUserInteractionDefined_Async() [Fact] public async Task Should_UpdateTrafficInteraction_Async() { + const string id = "id"; var initialTrafficOptions = new TrafficOptions { Flow = TrafficFlow.Absolute }; var incidents = true; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object) { + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object) { TrafficOptions = initialTrafficOptions }; await map.SetTrafficOptionsAsync(options => options.Incidents = incidents); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetTraffic.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as TrafficOptions).Flow.ToString() == TrafficFlow.Absolute.ToString() && (parameters[1] as TrafficOptions).Incidents.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1197,12 +1243,13 @@ public async Task Should_UpdateTrafficInteraction_Async() [Fact] public async Task Should_UpdateTrafficInteraction_NoTrafficOptionsDefined_Async() { + const string id = "id"; var incidents = true; - var map = new Map("id", _jsRuntimeMock.Object, _loggerMock.Object); + var map = new Map(id, _jsRuntimeMock.Object, _loggerMock.Object); await map.SetTrafficOptionsAsync(options => options.Incidents = incidents); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetTraffic.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && (parameters[1] as TrafficOptions).Incidents.GetValueOrDefault() )), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1760,11 +1807,12 @@ public void Should_DispatchDrawingStartedEvent() [Fact] public async Task Should_CreateImageFromTemplateAsync() { - var map = new Map("id", _jsRuntimeMock.Object); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object); await map.CreateImageFromTemplateAsync("imageId", "templateName", "color", "secondaryColor", 1m); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.CreateImageFromTemplate.ToCoreNamespace(), It.Is(parameters => - parameters[0] as string == "id" + parameters[0] as string == id && parameters[1] is MapImageTemplate && ((MapImageTemplate)parameters[1]).Id == "imageId" && ((MapImageTemplate)parameters[1]).TemplateName == "templateName" @@ -1778,10 +1826,11 @@ public async Task Should_CreateImageFromTemplateAsync() [Fact] public async Task Should_SetCanvasStylePropertyAsync() { - var map = new Map("id", _jsRuntimeMock.Object); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object); await map.SetCanvasStylePropertyAsync("property", "value"); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperty.ToCoreNamespace(), "id", "property", "value"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperty.ToCoreNamespace(), id, "property", "value"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1800,14 +1849,15 @@ public async Task Should_NotSetCanvasStyleProperty_InvalidProperty_Async(string [Fact] public async Task Should_SetCanvasStylePropertiesAsync() { - var map = new Map("id", _jsRuntimeMock.Object); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object); var properties = new Dictionary { { "cursor", "hand" } }; await map.SetCanvasStylePropertiesAsync(properties); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), id, It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1826,16 +1876,17 @@ public async Task Should_NotSetCanvasStyleProperties_NullCase_Async() [Fact] public async Task Should_SetOnlyDefinedCanvasProperties_Async() { - var map = new Map("id", _jsRuntimeMock.Object); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object); var properties = new Dictionary { - { "cursor", "hand" }, - { "", "value" }, - { " ", "value" }, - }; + { "cursor", "hand" }, + { "", "value" }, + { " ", "value" }, + }; await map.SetCanvasStylePropertiesAsync(properties); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), id, It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1868,10 +1919,11 @@ public async Task Should_NotSetCanvasProperties_NoDefinedPropertiesCase_Async() [Fact] public async Task Should_SetCanvasContainerStylePropertyAsync() { - var map = new Map("id", _jsRuntimeMock.Object); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object); await map.SetCanvasContainerStylePropertyAsync("property", "value"); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperty.ToCoreNamespace(), "id", "property", "value"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperty.ToCoreNamespace(), id, "property", "value"), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1916,16 +1968,17 @@ public async Task Should_NotSetCanvasContainerStyleProperties_NullCase_Async() [Fact] public async Task Should_SetOnlyDefinedCanvasContainerProperties_Async() { - var map = new Map("id", _jsRuntimeMock.Object); + const string id = "id"; + var map = new Map(id, _jsRuntimeMock.Object); var properties = new Dictionary { - { "cursor", "hand" }, - { "", "value" }, - { " ", "value" }, - }; + { "cursor", "hand" }, + { "", "value" }, + { " ", "value" }, + }; await map.SetCanvasContainerStylePropertiesAsync(properties); - _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => + _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), id, It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1949,7 +2002,7 @@ public async Task Should_NotSetCanvasContainerProperties_NoDefinedPropertiesCase var properties = new Dictionary { { "", "value" }, - { " ", "value" }, + { " ", "value" }, }; await map.SetCanvasContainerStylePropertiesAsync(properties); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1958,60 +2011,64 @@ public async Task Should_NotSetCanvasContainerProperties_NoDefinedPropertiesCase [Fact] public async Task Should_GetCameraOptionsAsync() { + const string id = "id"; var options = new CameraOptions(); _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); - var map = new Map("id", _jsRuntimeMock.Object); + var map = new Map(id, _jsRuntimeMock.Object); var result = await map.GetCameraOptionsAsync(); Assert.Equal(options, map.CameraOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetCamera.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetCamera.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_GetStyleOptionsAsync() { + const string id = "id"; var options = new StyleOptions(); _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); - var map = new Map("id", _jsRuntimeMock.Object); + var map = new Map(id, _jsRuntimeMock.Object); var result = await map.GetStyleOptionsAsync(); Assert.Equal(options, map.StyleOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetStyle.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetStyle.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_GetTrafficOptionsAsync() { + const string id = "id"; var options = new TrafficOptions(); _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); - var map = new Map("id", _jsRuntimeMock.Object); + var map = new Map(id, _jsRuntimeMock.Object); var result = await map.GetTrafficOptionsAsync(); Assert.Equal(options, map.TrafficOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetTraffic.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetTraffic.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } [Fact] public async Task Should_GetUserInteractionOptionsAsync() { + const string id = "id"; var options = new UserInteractionOptions(); _jsRuntimeMock.Setup(runtime => runtime.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(options); - var map = new Map("id", _jsRuntimeMock.Object); + var map = new Map(id, _jsRuntimeMock.Object); var result = await map.GetUserInteractionOptionsAsync(); Assert.Equal(options, map.UserInteractionOptions); Assert.Equal(options, result); - _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetUserInteraction.ToCoreNamespace(), "id"), Times.Once); + _jsRuntimeMock.Verify(runtime => runtime.InvokeAsync(Constants.JsConstants.Methods.Core.GetUserInteraction.ToCoreNamespace(), id), Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } } From 18fd8e6c776666571466df6517fcc5e81df0a889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Tue, 4 Nov 2025 15:56:11 +0200 Subject: [PATCH 11/12] Add test cases for multiple maps. --- .../Map/Map.cs | 10 +- .../Map/MapServiceMultipleMaps.cs | 204 ++++++++++++++++++ 2 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs diff --git a/tests/AzureMapsControl.Components.Tests/Map/Map.cs b/tests/AzureMapsControl.Components.Tests/Map/Map.cs index 5475cd8..d4a82a0 100644 --- a/tests/AzureMapsControl.Components.Tests/Map/Map.cs +++ b/tests/AzureMapsControl.Components.Tests/Map/Map.cs @@ -1859,7 +1859,7 @@ public async Task Should_SetCanvasStylePropertiesAsync() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), id, It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1888,7 +1888,7 @@ public async Task Should_SetOnlyDefinedCanvasProperties_Async() await map.SetCanvasStylePropertiesAsync(properties); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasStyleProperties.ToCoreNamespace(), id, It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1910,7 +1910,7 @@ public async Task Should_NotSetCanvasProperties_NoDefinedPropertiesCase_Async() var properties = new Dictionary { { "", "value" }, - { " ", "value" }, + { " ", "value" }, }; await map.SetCanvasStylePropertiesAsync(properties); _jsRuntimeMock.VerifyNoOtherCalls(); @@ -1951,7 +1951,7 @@ public async Task Should_SetCanvasContainerStylePropertiesAsync() _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), "id", It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } @@ -1980,7 +1980,7 @@ public async Task Should_SetOnlyDefinedCanvasContainerProperties_Async() await map.SetCanvasContainerStylePropertiesAsync(properties); _jsRuntimeMock.Verify(runtime => runtime.InvokeVoidAsync(Constants.JsConstants.Methods.Core.SetCanvasContainerStyleProperties.ToCoreNamespace(), id, It.Is>>(dictionary => dictionary.Single().Key == "cursor" && dictionary.Single().Value == "hand")) - , Times.Once); + , Times.Once); _jsRuntimeMock.VerifyNoOtherCalls(); } diff --git a/tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs b/tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs new file mode 100644 index 0000000..d9aa128 --- /dev/null +++ b/tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs @@ -0,0 +1,204 @@ +namespace AzureMapsControl.Components.Tests.Map +{ + using System.Linq; + using System.Threading.Tasks; + + using AzureMapsControl.Components.Map; + + using Xunit; + + public class MapServiceMultipleMapsTests + { + [Fact] + public async Task Should_AddMultipleMaps_Async() + { + var map1 = new Map("map1"); + var map2 = new Map("map2"); + var map3 = new Map("map3"); + var service = new MapService(null); + + await service.AddMapAsync(map1); + await service.AddMapAsync(map2); + await service.AddMapAsync(map3); + + Assert.Equal(3, service.Maps.Count); + Assert.Equal(map1, service.GetMap("map1")); + Assert.Equal(map2, service.GetMap("map2")); + Assert.Equal(map3, service.GetMap("map3")); + Assert.Equal(map3, service.Map); // Latest added map + } + + [Fact] + public async Task Should_HandleAddingMapWithSameId_Async() + { + var map1 = new Map("map-id"); + var map2 = new Map("map-id"); // Same ID + var service = new MapService(null); + + await service.AddMapAsync(map1); + await service.AddMapAsync(map2); + + Assert.Single(service.Maps); + Assert.Equal(map2, service.GetMap("map-id")); // Should replace first map + Assert.Equal(map2, service.Map); + } + + [Fact] + public async Task Should_RemoveMap_Async() + { + var map1 = new Map("map1"); + var map2 = new Map("map2"); + var service = new MapService(null); + + await service.AddMapAsync(map1); + await service.AddMapAsync(map2); + await service.RemoveMapAsync("map1"); + + Assert.Single(service.Maps); + Assert.Null(service.GetMap("map1")); + Assert.Equal(map2, service.GetMap("map2")); + } + + [Fact] + public async Task Should_RemoveLatestMap_AndUpdateLatestMapPointer_Async() + { + var map1 = new Map("map1"); + var map2 = new Map("map2"); + var service = new MapService(null); + + await service.AddMapAsync(map1); + await service.AddMapAsync(map2); + + Assert.Equal(map2, service.Map); // map2 is latest + + await service.RemoveMapAsync("map2"); + + Assert.Single(service.Maps); + Assert.Null(service.GetMap("map2")); + // After removing latest, service.Map should fall back to remaining map + Assert.Equal(map1, service.Map); + } + + [Fact] + public async Task Should_RemoveNonExistentMap_WithoutError_Async() + { + var map1 = new Map("map1"); + var service = new MapService(null); + + await service.AddMapAsync(map1); + await service.RemoveMapAsync("non-existent-id"); + + Assert.Single(service.Maps); + Assert.Equal(map1, service.GetMap("map1")); + } + + [Fact] + public async Task Should_HandleRemoveAllMaps_Async() + { + var map1 = new Map("map1"); + var map2 = new Map("map2"); + var service = new MapService(null); + + await service.AddMapAsync(map1); + await service.AddMapAsync(map2); + await service.RemoveMapAsync("map1"); + await service.RemoveMapAsync("map2"); + + Assert.Empty(service.Maps); + Assert.Null(service.Map); + } + + [Fact] + public async Task Should_AddMapAfterRemoval_Async() + { + var map1 = new Map("map1"); + var map2 = new Map("map2"); + var map3 = new Map("map1"); // Same ID as removed map + var service = new MapService(null); + + await service.AddMapAsync(map1); + await service.AddMapAsync(map2); + await service.RemoveMapAsync("map1"); + await service.AddMapAsync(map3); + + Assert.Equal(2, service.Maps.Count); + Assert.Equal(map3, service.GetMap("map1")); + Assert.Equal(map2, service.GetMap("map2")); + Assert.Equal(map3, service.Map); // Latest added + } + + [Fact] + public async Task Should_HandleConcurrentAdditions_Async() + { + var service = new MapService(null); + var maps = Enumerable.Range(1, 10).Select(i => new Map($"map{i}")).ToList(); + + var tasks = maps.Select(map => service.AddMapAsync(map)); + await Task.WhenAll(tasks.Select(t => t.AsTask())); + + Assert.Equal(10, service.Maps.Count); + foreach (var map in maps) + { + Assert.Equal(map, service.GetMap(map.Id)); + } + } + + [Fact] + public async Task Should_TriggerOnMapReadyForEachMap_Async() + { + var map1 = new Map("map1"); + var map2 = new Map("map2"); + var service = new MapService(null); + + var readyMaps = new System.Collections.Generic.List(); + + service.OnMapReadyAsync += async (map) => { + readyMaps.Add(map.Id); + await ValueTask.CompletedTask; + }; + + await service.AddMapAsync(map1); + await service.AddMapAsync(map2); + + Assert.Equal(2, readyMaps.Count); + Assert.Contains("map1", readyMaps); + Assert.Contains("map2", readyMaps); + } + + [Fact] + public void Should_ReturnNull_WhenNoMapsExist() + { + var service = new MapService(null); + + Assert.Null(service.Map); + Assert.Empty(service.Maps); + } + + [Fact] + public async Task Should_ReturnNull_ForNonExistentMapId() + { + var service = new MapService(null); + await service.AddMapAsync(new Map("map1")); + + var result = service.GetMap("non-existent-id"); + + Assert.Null(result); + } + + [Fact] + public async Task Should_HandleRapidAddRemoveSequence_Async() + { + var service = new MapService(null); + + for (int i = 0; i < 5; i++) + { + var map = new Map($"map{i}"); + await service.AddMapAsync(map); + await service.RemoveMapAsync($"map{i}"); + } + + Assert.Empty(service.Maps); + Assert.Null(service.Map); + } + } +} From 6dd8bc6e5b8f7df86fe3a9261a11cb059920c279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roope=20Herpi=C3=B6?= Date: Wed, 5 Nov 2025 09:30:44 +0200 Subject: [PATCH 12/12] Minor cleanup. --- .../Map/IMapAdderService.cs | 4 ++-- src/AzureMapsControl.Components/Map/MapService.cs | 13 +++++-------- .../Map/MapServiceMultipleMaps.cs | 4 ++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/AzureMapsControl.Components/Map/IMapAdderService.cs b/src/AzureMapsControl.Components/Map/IMapAdderService.cs index 2f89da5..8bff2f4 100644 --- a/src/AzureMapsControl.Components/Map/IMapAdderService.cs +++ b/src/AzureMapsControl.Components/Map/IMapAdderService.cs @@ -4,8 +4,8 @@ internal interface IMapAdderService : IMapService { - ValueTask AddMapAsync(Map map); + public ValueTask AddMapAsync(Map map); - ValueTask RemoveMapAsync(string mapId); + public ValueTask RemoveMapAsync(string mapId); } } diff --git a/src/AzureMapsControl.Components/Map/MapService.cs b/src/AzureMapsControl.Components/Map/MapService.cs index 593dd94..3886d26 100644 --- a/src/AzureMapsControl.Components/Map/MapService.cs +++ b/src/AzureMapsControl.Components/Map/MapService.cs @@ -23,12 +23,12 @@ public Map Map { get { - if (!string.IsNullOrEmpty(_latestMapId) && _maps.ContainsKey(_latestMapId)) + if (!string.IsNullOrEmpty(_latestMapId) && _maps.TryGetValue(_latestMapId, out var map)) { - return _maps[_latestMapId]; + return map; } - if (_maps.Count > 0) + if (!_maps.IsEmpty) { return _maps.Values.First(); } @@ -41,10 +41,7 @@ public Map Map public event MapReadyEvent OnMapReadyAsync; - public Map GetMap(string mapId) - { - return _maps.TryGetValue(mapId, out var map) ? map : null; - } + public Map GetMap(string mapId) => _maps.TryGetValue(mapId, out var map) ? map : null; public async ValueTask AddMapAsync(Map map) { @@ -66,7 +63,7 @@ public async ValueTask RemoveMapAsync(string mapId) _logger?.LogAzureMapsControlInfo(AzureMapLogEvent.MapService_AddMapAsync, "Removing map instance"); _logger?.LogAzureMapsControlDebug(AzureMapLogEvent.MapService_AddMapAsync, $"Map ID: {mapId}"); - if (_maps.TryRemove(mapId, out var removedMap)) + if (_maps.TryRemove(mapId, out _)) { // If we're removing the latest map, update the latest map ID if (_latestMapId == mapId) diff --git a/tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs b/tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs index d9aa128..d83f368 100644 --- a/tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs +++ b/tests/AzureMapsControl.Components.Tests/Map/MapServiceMultipleMaps.cs @@ -175,7 +175,7 @@ public void Should_ReturnNull_WhenNoMapsExist() } [Fact] - public async Task Should_ReturnNull_ForNonExistentMapId() + public async Task Should_ReturnNull_ForNonExistentMapId_Async() { var service = new MapService(null); await service.AddMapAsync(new Map("map1")); @@ -190,7 +190,7 @@ public async Task Should_HandleRapidAddRemoveSequence_Async() { var service = new MapService(null); - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { var map = new Map($"map{i}"); await service.AddMapAsync(map);