mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Add HealthChat API and extended profile services (#9)
Expose OpenID tokens and homeserver credentials from the client proxy, and add fork-only services for the HealthChat member directory backend (api.healthchat.ch) plus a service that reads MSC4133 extended profile fields directly from the homeserver. Groundwork for the members tab and the profile screens. Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// 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 HealthChatAPIModelsTests {
|
||||
@Test
|
||||
func decodesMemberFromFullJSON() throws {
|
||||
let json = """
|
||||
{
|
||||
"userId": "@alice:healthchat.ch",
|
||||
"displayName": "Dr. Alice Alpha",
|
||||
"avatarMxcUrl": "mxc://healthchat.ch/abc123",
|
||||
"title": "Dr. med.",
|
||||
"firstName": "Alice",
|
||||
"lastName": "Alpha",
|
||||
"specialty": "Physiotherapie",
|
||||
"practiceName": "Praxis Alpha",
|
||||
"businessCity": "Zürich",
|
||||
"businessEmail": "praxis@example.ch",
|
||||
"businessTel": "+41 44 123 45 67",
|
||||
"furtherInfo": "Info",
|
||||
"street": "Friedaustrasse",
|
||||
"houseNumber": "17",
|
||||
"postalCode": "8003",
|
||||
"website": "https://example.ch",
|
||||
"isApproved": true,
|
||||
"someFutureField": { "nested": true }
|
||||
}
|
||||
"""
|
||||
|
||||
let member = try JSONDecoder().decode(HealthChatMember.self, from: Data(json.utf8))
|
||||
|
||||
#expect(member.userID == "@alice:healthchat.ch")
|
||||
#expect(member.id == "@alice:healthchat.ch")
|
||||
#expect(member.displayName == "Dr. Alice Alpha")
|
||||
#expect(member.avatarURL == URL(string: "mxc://healthchat.ch/abc123"))
|
||||
#expect(member.title == "Dr. med.")
|
||||
#expect(member.firstName == "Alice")
|
||||
#expect(member.lastName == "Alpha")
|
||||
#expect(member.specialty == "Physiotherapie")
|
||||
#expect(member.practiceName == "Praxis Alpha")
|
||||
#expect(member.businessCity == "Zürich")
|
||||
#expect(member.businessEmail == "praxis@example.ch")
|
||||
#expect(member.businessTel == "+41 44 123 45 67")
|
||||
#expect(member.furtherInfo == "Info")
|
||||
#expect(member.street == "Friedaustrasse")
|
||||
#expect(member.houseNumber == "17")
|
||||
#expect(member.postalCode == "8003")
|
||||
#expect(member.website == "https://example.ch")
|
||||
#expect(member.isApproved)
|
||||
}
|
||||
|
||||
@Test
|
||||
func decodesMinimalMemberWithDefaults() throws {
|
||||
let json = """
|
||||
{ "userId": "@bob:healthchat.ch" }
|
||||
"""
|
||||
|
||||
let member = try JSONDecoder().decode(HealthChatMember.self, from: Data(json.utf8))
|
||||
|
||||
#expect(member.userID == "@bob:healthchat.ch")
|
||||
#expect(member.displayName == nil)
|
||||
#expect(member.avatarURL == nil)
|
||||
#expect(member.isApproved)
|
||||
}
|
||||
|
||||
@Test
|
||||
func emptyStringsBecomeNil() throws {
|
||||
let json = """
|
||||
{
|
||||
"userId": "@bob:healthchat.ch",
|
||||
"displayName": "",
|
||||
"avatarMxcUrl": "",
|
||||
"businessTel": ""
|
||||
}
|
||||
"""
|
||||
|
||||
let member = try JSONDecoder().decode(HealthChatMember.self, from: Data(json.utf8))
|
||||
|
||||
#expect(member.displayName == nil)
|
||||
#expect(member.avatarURL == nil)
|
||||
#expect(member.businessTel == nil)
|
||||
}
|
||||
|
||||
@Test
|
||||
func decodesMembersResponse() throws {
|
||||
let json = """
|
||||
{
|
||||
"users": [{ "userId": "@alice:healthchat.ch" }],
|
||||
"totalCount": 1,
|
||||
"searchQuery": "",
|
||||
"isApproved": true,
|
||||
"pendingMessage": null
|
||||
}
|
||||
"""
|
||||
|
||||
let response = try JSONDecoder().decode(HealthChatMembersResponse.self, from: Data(json.utf8))
|
||||
|
||||
#expect(response.users.count == 1)
|
||||
#expect(response.users.first?.userID == "@alice:healthchat.ch")
|
||||
#expect(response.isApproved)
|
||||
#expect(response.pendingMessage == nil)
|
||||
}
|
||||
|
||||
@Test
|
||||
func decodesPendingMembersResponse() throws {
|
||||
let json = """
|
||||
{
|
||||
"users": [],
|
||||
"isApproved": false,
|
||||
"pendingMessage": "Ihr Konto wird geprüft"
|
||||
}
|
||||
"""
|
||||
|
||||
let response = try JSONDecoder().decode(HealthChatMembersResponse.self, from: Data(json.utf8))
|
||||
|
||||
#expect(response.users.isEmpty)
|
||||
#expect(!response.isApproved)
|
||||
#expect(response.pendingMessage == "Ihr Konto wird geprüft")
|
||||
}
|
||||
|
||||
@Test
|
||||
func profileUpdateEncodesOnlySetFields() throws {
|
||||
var update = HealthChatProfileUpdate()
|
||||
update.businessTel = "+41 44 123 45 67"
|
||||
update.specialty = "Physiotherapie"
|
||||
update.furtherInfo = ""
|
||||
|
||||
let data = try JSONEncoder().encode(update)
|
||||
let object = try #require(JSONSerialization.jsonObject(with: data) as? [String: Any])
|
||||
|
||||
#expect(object.keys.sorted() == ["businessTel", "furtherInfo", "specialty"])
|
||||
#expect(object["businessTel"] as? String == "+41 44 123 45 67")
|
||||
#expect(object["specialty"] as? String == "Physiotherapie")
|
||||
#expect(object["furtherInfo"] as? String == "")
|
||||
}
|
||||
|
||||
@Test
|
||||
func decodesProfileCompleteness() throws {
|
||||
let json = """
|
||||
{
|
||||
"isComplete": false,
|
||||
"missingFields": ["Fachgebiet", "Ort"],
|
||||
"message": "Profil unvollständig",
|
||||
"hasProfilePhoto": true
|
||||
}
|
||||
"""
|
||||
|
||||
let completeness = try JSONDecoder().decode(HealthChatProfileCompleteness.self, from: Data(json.utf8))
|
||||
|
||||
#expect(!completeness.isComplete)
|
||||
#expect(completeness.missingFields == ["Fachgebiet", "Ort"])
|
||||
#expect(completeness.message == "Profil unvollständig")
|
||||
#expect(completeness.hasProfilePhoto)
|
||||
}
|
||||
|
||||
@Test
|
||||
func decodesProfileCompletenessWithDefaults() throws {
|
||||
let completeness = try JSONDecoder().decode(HealthChatProfileCompleteness.self, from: Data("{}".utf8))
|
||||
|
||||
#expect(!completeness.isComplete)
|
||||
#expect(completeness.missingFields.isEmpty)
|
||||
#expect(completeness.message == nil)
|
||||
#expect(!completeness.hasProfilePhoto)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user