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 postedArgv(_ stub: StubProtocol.Box) throws -> [String] { let seen = try #require(stub.seen.first { $0.method == "POST" }) let body = try #require(try JSONSerialization.jsonObject(with: seen.body) as? [String: Any]) return try #require(body["argv"] as? [String]) } private func mrShow(queued: String = "") -> String { """ {"protocol_version":1,"data":{"number":5,"title":"t","state":"open","author":"krz",\ "source":"feat","target_ref":"main","head_sha":"abc","created_at":"2026-08-20T10:00:00.000Z"\ \(queued)},"exit_code":0} """ } private let ok = #"{"protocol_version":1,"data":{},"exit_code":0}"# @MainActor struct MergeWhenReadyTests { private func loaded(_ json: String) async throws -> (MRDetailViewModel, StubProtocol.Box) { let (client, stub) = try makeClient() stub.enqueue(.init(status: 200, json: json, match: "argv=show")) let model = MRDetailViewModel(client: client, repoPath: "krz/gitbay", number: 5) await model.load() return (model, stub) } @Test func aQueuedMergeDecodesWhoQueuedItAndWhy() async throws { let (model, _) = try await loaded(mrShow(queued: #","queued":{"by":"cmc","strategy":"ff","reason":"waiting on 1 approval","queued_at":"2026-08-21T10:00:00.000Z"}"#)) let queued = try #require(model.state.value?.queued) #expect(queued.by == "cmc") #expect(queued.strategy == "ff") #expect(queued.reason == "waiting on 1 approval") } @Test func noQueueDecodesAsNil() async throws { let (model, _) = try await loaded(mrShow()) #expect(model.state.value?.queued == nil) } @Test func mergeWhenReadyAddsTheFlagAndKeepsTheStrategy() async throws { let (model, stub) = try await loaded(mrShow()) stub.enqueue(.init(status: 200, json: ok, match: "cmd")) await model.merge(strategy: "ff", whenReady: true) #expect(try postedArgv(stub) == ["mr", "merge", "krz/gitbay", "5", "--strategy", "ff", "--when-ready"]) } @Test func cancellingTheQueueSendsCancelAlone() async throws { let (model, stub) = try await loaded(mrShow(queued: #","queued":{"by":"cmc","queued_at":"2026-08-21T10:00:00.000Z"}"#)) stub.enqueue(.init(status: 200, json: ok, match: "cmd")) await model.cancelQueuedMerge() #expect(try postedArgv(stub) == ["mr", "merge", "krz/gitbay", "5", "--cancel"]) } }