gitbayTests/WebSessionTests.swift

36835f99e6d463f3e18c5c3fc3562bb92513f52b
gitbay-ios/gitbayTests/WebSessionTests.swift history · blame · raw

72 lines · 3045 bytes

6 symbols in this file
 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 func writes(_ stub: StubProtocol.Box) throws -> [[String]] {
16    try stub.seen.filter { $0.url.path().hasSuffix("/cmd") }.map {
17        let body = try #require(try JSONSerialization.jsonObject(with: $0.body) as? [String: Any])
18        return try #require(body["argv"] as? [String])
19    }
20}
21
22private let sessionsJSON = """
23    {"protocol_version":1,"data":[\
24    {"id":"a1b2c3d4e5f6","created_at":"2026-10-14T08:00:00.000Z","expires_at":"2026-11-13T08:00:00.000Z","last_used_at":"2026-10-15T09:00:00.000Z"},\
25    {"id":"0f9e8d7c6b5a","created_at":"2026-10-01T08:00:00.000Z","expires_at":"2026-10-31T08:00:00.000Z","last_used_at":"2026-10-01T08:00:00.000Z"}\
26    ],"exit_code":0}
27    """
28
29@MainActor
30struct WebSessionsViewModelTests {
31
32    @Test func listsSessionsNewestFirst() async throws {
33        let (client, stub) = try makeClient()
34        stub.enqueue(.init(status: 200, json: sessionsJSON))
35        let model = WebSessionsViewModel(client: client)
36        await model.load()
37
38        let sessions = try #require(model.state.value)
39        #expect(sessions.map(\.id) == ["a1b2c3d4e5f6", "0f9e8d7c6b5a"])
40        #expect(sessions[0].lastUsedAt > sessions[1].lastUsedAt)
41        #expect(stub.seen.first?.url.query() == "argv=web&argv=sessions&argv=list")
42    }
43
44    @Test func noSessionsIsAnEmptyState() async throws {
45        let (client, stub) = try makeClient()
46        stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":[],"exit_code":0}"#))
47        let model = WebSessionsViewModel(client: client)
48        await model.load()
49        guard case .empty = model.state else {
50            Issue.record("expected .empty, got \(model.state)")
51            return
52        }
53    }
54
55    @Test func revokeOneThenAll() async throws {
56        let (client, stub) = try makeClient()
57        stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"revoked":"a1b2c3d4e5f6"},"exit_code":0}"#, match: "cmd"))
58        stub.enqueue(.init(status: 200, json: sessionsJSON, match: "argv=list"))
59        stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"revoked":2},"exit_code":0}"#, match: "cmd"))
60        stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":[],"exit_code":0}"#, match: "argv=list"))
61        let model = WebSessionsViewModel(client: client)
62
63        await model.revoke(id: "a1b2c3d4e5f6")
64        await model.revokeAll()
65
66        #expect(try writes(stub) == [["web", "sessions", "revoke", "a1b2c3d4e5f6"], ["web", "sessions", "revoke", "--all"]])
67        guard case .empty = model.state else {
68            Issue.record("expected .empty after revoking all, got \(model.state)")
69            return
70        }
71    }
72}