import Foundation import Testing @testable import gitbay private func makeClient() throws -> (GitbayClient, StubProtocol.Box) { let box = StubProtocol.box() let client = GitbayClient( instance: try GitbayInstance(url: "https://gitbay.org"), token: "test-token", session: box.session() ) return (client, box) } private func writes(_ stub: StubProtocol.Box) throws -> [[String]] { try stub.seen.filter { $0.url.path().hasSuffix("/cmd") }.map { let body = try #require(try JSONSerialization.jsonObject(with: $0.body) as? [String: Any]) return try #require(body["argv"] as? [String]) } } private let sessionsJSON = """ {"protocol_version":1,"data":[\ {"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"},\ {"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"}\ ],"exit_code":0} """ @MainActor struct WebSessionsViewModelTests { @Test func listsSessionsNewestFirst() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 200, json: sessionsJSON)) let model = WebSessionsViewModel(client: client) await model.load() let sessions = try #require(model.state.value) #expect(sessions.map(\.id) == ["a1b2c3d4e5f6", "0f9e8d7c6b5a"]) #expect(sessions[0].lastUsedAt > sessions[1].lastUsedAt) #expect(stub.seen.first?.url.query() == "argv=web&argv=sessions&argv=list") } @Test func noSessionsIsAnEmptyState() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":[],"exit_code":0}"#)) let model = WebSessionsViewModel(client: client) await model.load() guard case .empty = model.state else { Issue.record("expected .empty, got \(model.state)") return } } @Test func revokeOneThenAll() async throws { let (client, stub) = try makeClient() stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"revoked":"a1b2c3d4e5f6"},"exit_code":0}"#, match: "cmd")) stub.enqueue(.init(status: 200, json: sessionsJSON, match: "argv=list")) stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":{"revoked":2},"exit_code":0}"#, match: "cmd")) stub.enqueue(.init(status: 200, json: #"{"protocol_version":1,"data":[],"exit_code":0}"#, match: "argv=list")) let model = WebSessionsViewModel(client: client) await model.revoke(id: "a1b2c3d4e5f6") await model.revokeAll() #expect(try writes(stub) == [["web", "sessions", "revoke", "a1b2c3d4e5f6"], ["web", "sessions", "revoke", "--all"]]) guard case .empty = model.state else { Issue.record("expected .empty after revoking all, got \(model.state)") return } } }