gitbayTests/DashboardViewModelTests.swift

v1.12.0
gitbay-ios/gitbayTests/DashboardViewModelTests.swift history · blame · raw

94 lines · 3786 bytes

 1import Foundation
 2import Testing
 3@testable import gitbay
 4
 5private func makeClient() throws -> (GitbayClient, StubProtocol.Box) {
 6    let box = StubProtocol.box()
 7    let client = GitbayClient(
 8        instance: try GitbayInstance(url: "https://gitbay.org"),
 9        token: "test-token",
10        session: box.session()
11    )
12    return (client, box)
13}
14
15private let dashboardJSON = """
16    {"protocol_version":1,"data":{\
17    "review_queue":[{"repo":"krz/gitbay-ios","number":3,"title":"adopt aggregate","author":"cmc",\
18    "state":"open","updated_at":"2026-08-27T10:00:00.000Z"}],\
19    "pinned":[{"path":"krz/gitbay","visibility":"public","description":"a CLI-first git forge"}],\
20    "open_mrs":[{"repo":"krz/gitbay-ios","number":3,"title":"adopt aggregate","author":"cmc",\
21    "state":"open","updated_at":"2026-08-27T10:00:00.000Z"}],\
22    "assigned_issues":[{"repo":"krz/gitbay","number":11,"title":"iOS app","author":"krz",\
23    "state":"open","updated_at":"2026-08-26T10:00:00.000Z"}],\
24    "open_issues":[{"repo":"krz/gitbay","number":11,"title":"iOS app","author":"krz",\
25    "state":"open","updated_at":"2026-08-26T10:00:00.000Z"}],\
26    "recent_activity":[{"id":7,"repo":"krz/gitbay-ios","actor":"cmc","kind":"mr.merged",\
27    "data":{"number":2},"created_at":"2026-08-27T10:30:00.000Z"}],\
28    "builds":[{"repo":"krz/gitbay","number":9,"job":"ci","status":"success",\
29    "sha":"65ba14e0000000000000","ref":"refs/heads/main",\
30    "created_at":"2026-08-27T09:00:00.000Z","finished_at":"2026-08-27T09:05:00.000Z"}],\
31    "unread":3},\
32    "exit_code":0}
33    """
34
35private let emptyDashboardJSON = """
36    {"protocol_version":1,"data":{"pinned":[],"open_mrs":[],"assigned_issues":[],"builds":[]},\
37    "exit_code":0}
38    """
39
40@MainActor
41struct DashboardViewModelTests {
42
43    @Test func oneReadFillsEverySection() async throws {
44        let (client, stub) = try makeClient()
45        stub.enqueue(.init(status: 200, json: dashboardJSON))
46        let model = DashboardViewModel(client: client)
47
48        await model.load()
49
50        let data = try #require(model.state.value)
51        #expect(data.pinned.map(\.path) == ["krz/gitbay"])
52        #expect(data.reviewQueue.map(\.id) == ["krz/gitbay-ios#3"])
53        #expect(data.openMRs.map(\.id) == ["krz/gitbay-ios#3"])
54        #expect(data.assignedIssues.first?.number == 11)
55        #expect(data.openIssues.first?.number == 11)
56        #expect(data.recentActivity.first?.phrase == "merged !2")
57        #expect(data.builds.first?.status == "success")
58        #expect(data.unread == 3)
59        // The whole screen cost exactly one request.
60        #expect(stub.seen.count == 1)
61        #expect(stub.seen.first?.url.query() == "argv=dashboard")
62    }
63
64    @Test func emptyAggregateStillLoads() async throws {
65        let (client, stub) = try makeClient()
66        stub.enqueue(.init(status: 200, json: emptyDashboardJSON))
67        let model = DashboardViewModel(client: client)
68
69        await model.load()
70
71        let data = try #require(model.state.value)
72        #expect(data.pinned.isEmpty)
73        #expect(data.openMRs.isEmpty)
74        #expect(data.reviewQueue.isEmpty)
75        #expect(data.openIssues.isEmpty)
76        #expect(data.recentActivity.isEmpty)
77    }
78
79    @Test func aFailureIsTheScreensState() async throws {
80        let (client, stub) = try makeClient()
81        stub.enqueue(.init(status: 500, json:
82            #"{"protocol_version":1,"error":"boom","exit_code":1}"#))
83        stub.enqueue(.init(status: 500, json:
84            #"{"protocol_version":1,"error":"boom","exit_code":1}"#))
85        let model = DashboardViewModel(client: client)
86
87        await model.load()
88
89        guard case .failed = model.state else {
90            Issue.record("expected .failed, got \(model.state)")
91            return
92        }
93    }
94}