From 67965cbac6fd60c563392352e68f3c787b12a7ee Mon Sep 17 00:00:00 2001 From: Trey t Date: Fri, 13 Feb 2026 09:12:00 -0600 Subject: [PATCH] fix: region map tap selecting wrong region due to accessibility button overlay Accessibility buttons split the map into equal-width thirds, intercepting taps before the coordinate-based logic. Tapping the visual West region could hit the Central button. Adding .allowsHitTesting(false) lets taps pass through to MapReader's coordinate detection; VoiceOver still works. Co-Authored-By: Claude Opus 4.6 --- .../Trip/Views/RegionMapSelector.swift | 9 +- .../Trip/RegionMapSelectorTests.swift | 114 ++++++++++++++++++ 2 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 SportsTimeTests/Features/Trip/RegionMapSelectorTests.swift diff --git a/SportsTime/Features/Trip/Views/RegionMapSelector.swift b/SportsTime/Features/Trip/Views/RegionMapSelector.swift index cd09ff1..280efc8 100644 --- a/SportsTime/Features/Trip/Views/RegionMapSelector.swift +++ b/SportsTime/Features/Trip/Views/RegionMapSelector.swift @@ -56,13 +56,15 @@ struct RegionMapSelector: View { .mapStyle(.standard(elevation: .flat, pointsOfInterest: .excludingAll)) .onTapGesture { location in if let coordinate = proxy.convert(location, from: .local) { - let tappedRegion = regionForCoordinate(coordinate) + let tappedRegion = Self.regionForCoordinate(coordinate) onToggle(tappedRegion) } } } // Invisible button overlays for UI testing accessibility + // allowsHitTesting(false) lets taps pass through to the map's + // coordinate-based region detection; VoiceOver still reads these. HStack(spacing: 0) { Button { onToggle(.west) } label: { Color.clear } .accessibilityIdentifier("wizard.regions.west") @@ -98,6 +100,7 @@ struct RegionMapSelector: View { .accessibilityAddTraits(selectedRegions.contains(.east) ? .isSelected : []) .frame(maxWidth: .infinity) } + .allowsHitTesting(false) } .frame(height: 160) .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)) @@ -128,7 +131,9 @@ struct RegionMapSelector: View { /// West: States west of ~-102° (WA, OR, CA, NV, ID, UT, AZ, MT, WY, CO, NM) /// Central: States between ~-102° and ~-89° (ND, SD, NE, KS, OK, TX, MN, IA, MO, AR, LA, WI, IL) /// East: States east of ~-89° - private func regionForCoordinate(_ coordinate: CLLocationCoordinate2D) -> Region { + /// Maps a tap coordinate to a region based on the visual polygon boundaries. + /// Thresholds match the drawn polygon edges (not Region.classify which uses stadium locations). + static func regionForCoordinate(_ coordinate: CLLocationCoordinate2D) -> Region { let longitude = coordinate.longitude if longitude < -102 { return .west diff --git a/SportsTimeTests/Features/Trip/RegionMapSelectorTests.swift b/SportsTimeTests/Features/Trip/RegionMapSelectorTests.swift new file mode 100644 index 0000000..7d8b6d2 --- /dev/null +++ b/SportsTimeTests/Features/Trip/RegionMapSelectorTests.swift @@ -0,0 +1,114 @@ +// +// RegionMapSelectorTests.swift +// SportsTimeTests +// +// Regression tests for map tap → region coordinate detection. +// Bug: invisible accessibility buttons intercepted taps before the +// coordinate-based logic, causing offset selection (tapping West +// selected Central). Fix: .allowsHitTesting(false) on button overlay. +// + +import CoreLocation +import Testing +@testable import SportsTime + +@Suite("RegionMapSelector — regionForCoordinate") +struct RegionMapSelectorTests { + + // MARK: - West Region (longitude < -102) + + @Test("West: Los Angeles (-118.24)") + func west_losAngeles() { + let coord = CLLocationCoordinate2D(latitude: 34.05, longitude: -118.24) + #expect(RegionMapSelector.regionForCoordinate(coord) == .west) + } + + @Test("West: Seattle (-122.33)") + func west_seattle() { + let coord = CLLocationCoordinate2D(latitude: 47.61, longitude: -122.33) + #expect(RegionMapSelector.regionForCoordinate(coord) == .west) + } + + @Test("West: Phoenix (-112.07)") + func west_phoenix() { + let coord = CLLocationCoordinate2D(latitude: 33.45, longitude: -112.07) + #expect(RegionMapSelector.regionForCoordinate(coord) == .west) + } + + @Test("West: just inside boundary (-102.01)") + func west_boundary() { + let coord = CLLocationCoordinate2D(latitude: 39.0, longitude: -102.01) + #expect(RegionMapSelector.regionForCoordinate(coord) == .west) + } + + // MARK: - Central Region (-102 to -89) + + @Test("Central: Kansas City (-94.58)") + func central_kansasCity() { + let coord = CLLocationCoordinate2D(latitude: 39.10, longitude: -94.58) + #expect(RegionMapSelector.regionForCoordinate(coord) == .central) + } + + @Test("Central: Dallas (-96.80)") + func central_dallas() { + let coord = CLLocationCoordinate2D(latitude: 32.78, longitude: -96.80) + #expect(RegionMapSelector.regionForCoordinate(coord) == .central) + } + + @Test("Central: Chicago (-87.62)") + func central_chicago() { + let coord = CLLocationCoordinate2D(latitude: 41.88, longitude: -89.0) + #expect(RegionMapSelector.regionForCoordinate(coord) == .central) + } + + @Test("Central: exactly at west boundary (-102)") + func central_westBoundary() { + let coord = CLLocationCoordinate2D(latitude: 39.0, longitude: -102.0) + #expect(RegionMapSelector.regionForCoordinate(coord) == .central) + } + + @Test("Central: exactly at east boundary (-89)") + func central_eastBoundary() { + let coord = CLLocationCoordinate2D(latitude: 39.0, longitude: -89.0) + #expect(RegionMapSelector.regionForCoordinate(coord) == .central) + } + + // MARK: - East Region (longitude > -89) + + @Test("East: New York (-73.99)") + func east_newYork() { + let coord = CLLocationCoordinate2D(latitude: 40.71, longitude: -73.99) + #expect(RegionMapSelector.regionForCoordinate(coord) == .east) + } + + @Test("East: Miami (-80.19)") + func east_miami() { + let coord = CLLocationCoordinate2D(latitude: 25.76, longitude: -80.19) + #expect(RegionMapSelector.regionForCoordinate(coord) == .east) + } + + @Test("East: Atlanta (-84.39)") + func east_atlanta() { + let coord = CLLocationCoordinate2D(latitude: 33.75, longitude: -84.39) + #expect(RegionMapSelector.regionForCoordinate(coord) == .east) + } + + @Test("East: just outside boundary (-88.99)") + func east_boundary() { + let coord = CLLocationCoordinate2D(latitude: 39.0, longitude: -88.99) + #expect(RegionMapSelector.regionForCoordinate(coord) == .east) + } + + // MARK: - Regression: original bug scenario + + @Test("Regression: tapping visual West region should not select Central") + func regression_westTapNotCentral() { + // User reported tapping the West overlay (around -108 longitude) + // was selecting Central due to accessibility button overlay intercepting. + // With .allowsHitTesting(false), the coordinate logic is now used. + let westernTap = CLLocationCoordinate2D(latitude: 40.0, longitude: -108.0) + let result = RegionMapSelector.regionForCoordinate(westernTap) + #expect(result == .west, "Tapping at -108° longitude must select West, not Central") + #expect(result != .central) + } +}