1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
@testable import Grain
import SwiftUI
import XCTest
/// ProfileView is the largest view in the app and none of it was reachable from
/// the existing suite. These render it in each of the states it branches on so
/// the layout code runs at all.
@MainActor
final class ProfileViewRenderTests: GrainTestCase {
private var keychain: KeychainGuard!
/// Async overrides: the synchronous `setUp`/`tearDown` are nonisolated, so
/// touching main-actor state from them warns.
override func setUp() async throws {
try await super.setUp()
keychain = KeychainGuard(userDID: "did:plc:test")
}
override func tearDown() async throws {
MockURLProtocol.handler = nil
keychain.restore()
try await super.tearDown()
}
private static let profileJSON = """
{
"cid": "bafycid",
"did": "did:plc:test",
"handle": "tester.grain.social",
"displayName": "Tester",
"description": "A test profile with a description long enough to wrap.",
"followersCount": 12,
"followsCount": 34,
"galleryCount": 5,
"createdAt": "2025-01-01T00:00:00Z"
}
"""
func testRendersOwnProfile() {
MockURLProtocol.respondWithJSON(Self.profileJSON)
let env = TestEnvironment()
ViewRender.render(
ProfileView(client: env.client, did: "did:plc:test", isRoot: true)
.withTestEnvironment(env)
)
}
func testRendersOtherUsersProfile() {
MockURLProtocol.respondWithJSON(Self.profileJSON)
let env = TestEnvironment()
ViewRender.render(
ProfileView(client: env.client, did: "did:plc:someone-else", isRoot: false)
.withTestEnvironment(env)
)
}
/// The empty/failed load path renders a different branch than the loaded one.
func testRendersWhenTheProfileFailsToLoad() {
MockURLProtocol.respondWithError(statusCode: 500)
let env = TestEnvironment()
ViewRender.render(
ProfileView(client: env.client, did: "did:plc:test", isRoot: true)
.withTestEnvironment(env)
)
}
}