feat(healthchat): advertise the account status in settings

Pending approval and an incomplete profile were only visible in the
members tab, which a new user has no reason to open.
This commit is contained in:
Sedat Qaja
2026-10-09 14:39:33 +02:00
parent b70e77f7c5
commit d01d04846a
22 changed files with 349 additions and 2 deletions
@@ -0,0 +1,83 @@
//
// Copyright 2026 Novaloop AG
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
@testable import ElementX
import Foundation
import Testing
final class HealthChatAccountStatusLoaderTests {
private let apiService = HealthChatAPIServiceMock()
@Test
func reportsPendingApprovalForAnUnapprovedAccount() async throws {
apiService.ownProfileReturnValue = try .success(makeMember(isApproved: false))
#expect(await status() == .pendingApproval)
#expect(apiService.profileCompletenessCallsCount == 0)
}
@Test
func reportsTheIncompleteProfileMessage() async throws {
apiService.ownProfileReturnValue = try .success(makeMember(isApproved: true))
apiService.profileCompletenessReturnValue = try .success(makeCompleteness(isComplete: false,
message: "Profil unvollständig"))
#expect(await status() == .incompleteProfile(message: "Profil unvollständig"))
}
@Test
func reportsOKForAnApprovedAccountWithACompleteProfile() async throws {
apiService.ownProfileReturnValue = try .success(makeMember(isApproved: true))
apiService.profileCompletenessReturnValue = try .success(makeCompleteness(isComplete: true, message: nil))
#expect(await status() == .ok)
}
@Test
func reportsOKWhenTheServerWordsNoHint() async throws {
apiService.ownProfileReturnValue = try .success(makeMember(isApproved: true))
apiService.profileCompletenessReturnValue = try .success(makeCompleteness(isComplete: false, message: nil))
#expect(await status() == .ok)
}
@Test
func staysUnknownWhenTheProfileCannotBeRead() async {
apiService.ownProfileReturnValue = .failure(.networkFailure)
#expect(await status() == .unknown)
}
@Test
func staysUnknownWhenCompletenessCannotBeRead() async throws {
apiService.ownProfileReturnValue = try .success(makeMember(isApproved: true))
apiService.profileCompletenessReturnValue = .failure(.networkFailure)
#expect(await status() == .unknown)
}
// MARK: - Helpers
private func status() async -> HealthChatAccountStatus {
let loader = HealthChatAccountStatusLoader(apiService: apiService)
await loader.loadingTask?.value
return loader.status
}
private func makeMember(isApproved: Bool) throws -> HealthChatMember {
try JSONDecoder().decode(HealthChatMember.self, from: Data("""
{ "userId": "@alice:healthchat.ch", "isApproved": \(isApproved) }
""".utf8))
}
private func makeCompleteness(isComplete: Bool, message: String?) throws -> HealthChatProfileCompleteness {
let messageJSON = message.map { "\"\($0)\"" } ?? "null"
return try JSONDecoder().decode(HealthChatProfileCompleteness.self, from: Data("""
{ "isComplete": \(isComplete), "message": \(messageJSON) }
""".utf8))
}
}
@@ -178,6 +178,7 @@ struct SettingsScreenViewModelTests {
clientProxy = ClientProxyMock(.init(userID: "", status: status))
viewModel = SettingsScreenViewModel(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
appSettings: AppSettings.volatile(),
appHooks: AppHooks(),
isBugReportServiceEnabled: true,
isInSecondaryWindow: false,
userIndicatorController: UserIndicatorControllerMock())