added tests

This commit is contained in:
Mauro Romito
2026-03-31 03:00:31 +02:00
committed by Mauro
parent d67c1a93db
commit f31c256037
3 changed files with 145 additions and 21 deletions
@@ -7,34 +7,26 @@
//
import Combine
import CoreLocation
@testable import ElementX
import Testing
@MainActor
struct LocationSharingScreenViewModelTests {
private let timelineProxy = TimelineProxyMock(.init())
private var viewModel: LocationSharingScreenViewModelProtocol
var timelineProxy: TimelineProxyMock!
var viewModel: LocationSharingScreenViewModel!
private var context: LocationSharingScreenViewModel.Context {
var context: LocationSharingScreenViewModel.Context {
viewModel.context
}
init() {
let viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
liveLocationSharingEnabled: true,
roomProxy: JoinedRoomProxyMock(.init()),
timelineController: MockTimelineController(timelineProxy: timelineProxy),
liveLocationManager: LiveLocationManagerMock(),
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock(),
mediaProvider: MediaProviderMock(configuration: .init()))
viewModel.state.bindings.isLocationAuthorized = true
self.viewModel = viewModel
AppSettings.resetAllSettings()
}
@Test
func userDidPan() {
mutating func userDidPan() {
setupViewModel()
#expect(context.viewState.isSharingUserLocation)
#expect(context.showsUserLocationMode == .showAndFollow)
context.send(viewAction: .userDidPan)
@@ -43,7 +35,8 @@ struct LocationSharingScreenViewModelTests {
}
@Test
func centerOnUser() {
mutating func centerOnUser() {
setupViewModel()
#expect(context.viewState.isSharingUserLocation)
context.showsUserLocationMode = .show
#expect(!context.viewState.isSharingUserLocation)
@@ -53,7 +46,8 @@ struct LocationSharingScreenViewModelTests {
}
@Test
func centerOnUserWithoutAuth() {
mutating func centerOnUserWithoutAuth() {
setupViewModel()
context.showsUserLocationMode = .hide
context.isLocationAuthorized = nil
context.send(viewAction: .centerToUser)
@@ -61,7 +55,8 @@ struct LocationSharingScreenViewModelTests {
}
@Test
func centerOnUserWithDeniedAuth() {
mutating func centerOnUserWithDeniedAuth() {
setupViewModel()
context.isLocationAuthorized = false
context.showsUserLocationMode = .hide
context.send(viewAction: .centerToUser)
@@ -70,7 +65,8 @@ struct LocationSharingScreenViewModelTests {
}
@Test
func errorMapping() {
mutating func errorMapping() {
setupViewModel()
let mapError = AlertInfo(locationSharingViewError: .mapError(.failedLoadingMap))
#expect(mapError.title == L10n.errorFailedLoadingMap(InfoPlistReader.main.bundleDisplayName))
let locationError = AlertInfo(locationSharingViewError: .mapError(.failedLocatingUser))
@@ -80,7 +76,8 @@ struct LocationSharingScreenViewModelTests {
}
@Test
func sendUserLocation() async throws {
mutating func sendUserLocation() async throws {
setupViewModel()
context.mapCenterLocation = .init(latitude: 0, longitude: 0)
context.geolocationUncertainty = 10
@@ -101,7 +98,8 @@ struct LocationSharingScreenViewModelTests {
}
@Test
func sendPickedLocation() async throws {
mutating func sendPickedLocation() async throws {
setupViewModel()
context.mapCenterLocation = .init(latitude: 0, longitude: 0)
context.isLocationAuthorized = nil
context.geolocationUncertainty = 10
@@ -121,4 +119,101 @@ struct LocationSharingScreenViewModelTests {
try await deferred.fulfill()
}
}
// MARK: - Live Location Authorization Tests
@Test
mutating func startLiveLocationWithDeniedAuth() {
setupViewModel(liveLocationManagerConfiguration: .init(authorizationStatus: .denied))
context.send(viewAction: .startLiveLocation)
#expect(context.alertInfo?.id == .missingAlwaysAuthorization)
}
@Test
mutating func startLiveLocationWithRestrictedAuth() {
setupViewModel(liveLocationManagerConfiguration: .init(authorizationStatus: .restricted))
context.send(viewAction: .startLiveLocation)
#expect(context.alertInfo?.id == .missingAlwaysAuthorization)
}
@Test
mutating func startLiveLocationWithAlwaysAuth() {
setupViewModel(liveLocationManagerConfiguration: .init(authorizationStatus: .authorizedAlways))
context.send(viewAction: .startLiveLocation)
#expect(context.alertInfo == nil)
}
@Test
mutating func startLiveLocationWithWhenInUseAuthAlreadyRequested() {
setupViewModel(liveLocationManagerConfiguration: .init(authorizationStatus: .authorizedWhenInUse,
requestAlwaysAuthorizationIfPossibleReturnValue: false))
context.send(viewAction: .startLiveLocation)
#expect(context.alertInfo?.id == .missingAlwaysAuthorization)
}
@Test
mutating func startLiveLocationWithWhenInUseAuthNotYetRequested() {
setupViewModel(liveLocationManagerConfiguration: .init(authorizationStatus: .authorizedWhenInUse,
requestAlwaysAuthorizationIfPossibleReturnValue: true))
context.send(viewAction: .startLiveLocation)
// The request can be made, so no alert should be shown — it waits for the user to respond to the system prompt
#expect(context.alertInfo == nil)
}
@Test
mutating func startLiveLocationWithNotDeterminedAuthTransitionsToWhenInUse() async {
let authorizationStatusSubject = CurrentValueSubject<CLAuthorizationStatus, Never>(.notDetermined)
let liveLocationManagerMock = LiveLocationManagerMock()
liveLocationManagerMock.underlyingAuthorizationStatus = .init(authorizationStatusSubject)
liveLocationManagerMock.requestAlwaysAuthorizationIfPossibleReturnValue = true
setupViewModel(liveLocationManagerMock: liveLocationManagerMock)
context.send(viewAction: .startLiveLocation)
// No alert yet — waiting for MapLibre to resolve the status to whenInUse
#expect(context.alertInfo == nil)
// Simulate MapLibre resolving the authorization to whenInUse, and confirm that the ViewModel
// recurses and calls requestAlwaysAuthorizationIfPossible as a result
await waitForConfirmation { confirmation in
liveLocationManagerMock.requestAlwaysAuthorizationIfPossibleClosure = {
confirmation()
return true
}
authorizationStatusSubject.send(.authorizedWhenInUse)
}
// The request was made, so no alert — waiting for the always authorization prompt response
#expect(context.alertInfo == nil)
}
// MARK: - Private
private mutating func setupViewModel(liveLocationManagerConfiguration: LiveLocationManagerMock.Configuration = .init()) {
timelineProxy = TimelineProxyMock(.init())
viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
liveLocationSharingEnabled: true,
roomProxy: JoinedRoomProxyMock(.init()),
timelineController: MockTimelineController(timelineProxy: timelineProxy),
liveLocationManager: LiveLocationManagerMock(liveLocationManagerConfiguration),
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock(),
mediaProvider: MediaProviderMock(configuration: .init()))
viewModel.state.bindings.isLocationAuthorized = true
}
private mutating func setupViewModel(liveLocationManagerMock: LiveLocationManagerMock) {
timelineProxy = TimelineProxyMock(.init())
viewModel = LocationSharingScreenViewModel(interactionMode: .picker,
mapURLBuilder: ServiceLocator.shared.settings.mapTilerConfiguration,
liveLocationSharingEnabled: true,
roomProxy: JoinedRoomProxyMock(.init()),
timelineController: MockTimelineController(timelineProxy: timelineProxy),
liveLocationManager: liveLocationManagerMock,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: UserIndicatorControllerMock(),
mediaProvider: MediaProviderMock(configuration: .init()))
viewModel.state.bindings.isLocationAuthorized = true
}
}