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
@testable import Grain
import SwiftUI
import XCTest
/// The pieces of a profile header: the follower and gallery counts, and the
/// full-screen lightbox a profile picture opens into.
@MainActor
final class ProfileHeaderRenderTests: GrainTestCase {
private var account: TestAccount!
/// 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()
account = TestAccount()
MockURLProtocol.respondByPath(Fixtures.routes)
}
override func tearDown() async throws {
MockURLProtocol.handler = nil
account.restore()
try await super.tearDown()
}
// MARK: - Avatar lightbox
/// Tapping a profile picture opens it full screen with its own zoom state
/// and a swipe-to-dismiss.
func testRendersTheAvatarOverlay() {
ViewRender.render(
AvatarOverlay(url: "https://test.local/avatar.jpg", onDismiss: {}), settle: 0.3
)
}
/// An avatar URL the loader can't parse still has to put the overlay up —
/// otherwise the tap appears to do nothing.
func testRendersTheAvatarOverlayWithAnUnusableURL() {
ViewRender.render(AvatarOverlay(url: "", onDismiss: {}), settle: 0.2)
ViewRender.render(AvatarOverlay(url: "not a url", onDismiss: {}), settle: 0.2)
}
// MARK: - Profile stats
func testRendersEachProfileStat() {
for (count, label) in [(0, "galleries"), (1, "follower"), (1200, "followers")] {
ViewRender.render(StatView(count: count, label: label), settle: 0)
}
}
}