gitbayTests/RequiredContextsTests.swift

v1.8.0
gitbay-ios/gitbayTests/RequiredContextsTests.swift history · blame · raw

94 lines · 3614 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 func postedArgv(_ stub: StubProtocol.Box) throws -> [[String]] {
16    try stub.seen.filter { $0.method == "POST" }.map { seen in
17        let body = try #require(try JSONSerialization.jsonObject(with: seen.body) as? [String: Any])
18        return try #require(body["argv"] as? [String])
19    }
20}
21
22private let settingsJSON = """
23    {"protocol_version":1,"data":{"protected_branches":["main"],"require_checks":true,\
24    "required_contexts":["ci/test","ext/lint"]},"exit_code":0}
25    """
26
27private let repoShowJSON = """
28    {"protocol_version":1,"data":{"path":"krz/gitbay","description":"a forge",\
29    "visibility":"public","default_branch":"main"},"exit_code":0}
30    """
31
32private let ok = #"{"protocol_version":1,"data":{},"exit_code":0}"#
33
34@MainActor
35struct RequiredContextsTests {
36
37    private func loaded() async throws -> (RepoSettingsViewModel, StubProtocol.Box) {
38        let (client, stub) = try makeClient()
39        stub.enqueue(.init(status: 200, json: settingsJSON, match: "argv=settings"))
40        stub.enqueue(.init(status: 200, json: repoShowJSON, match: "argv=show&argv=krz"))
41        let model = RepoSettingsViewModel(client: client, repoPath: "krz/gitbay")
42        await model.load()
43        return (model, stub)
44    }
45
46    @Test func requiredContextsDecode() async throws {
47        let (model, _) = try await loaded()
48        #expect(model.state.value?.settings.contexts == ["ci/test", "ext/lint"])
49    }
50
51    @Test func addingAContextSendsTheWholeListWithItAppended() async throws {
52        let (model, stub) = try await loaded()
53        stub.enqueue(.init(status: 200, json: ok, match: "cmd"))
54
55        let cleared = await model.addRequiredContext(" ci/build ")
56
57        #expect(cleared)
58        #expect(try postedArgv(stub) == [["repo", "settings", "require-contexts", "krz/gitbay",
59                                          "ci/test", "ext/lint", "ci/build"]])
60    }
61
62    @Test func addingOneAlreadyListedSendsNothing() async throws {
63        let (model, stub) = try await loaded()
64
65        await model.addRequiredContext("ci/test")
66
67        #expect(try postedArgv(stub).isEmpty)
68    }
69
70    @Test func aRefusedContextIsNotClearedFromTheField() async throws {
71        let (model, stub) = try await loaded()
72        stub.enqueue(.init(status: 400, json: #"{"protocol_version":1,"error":"at most 20 required contexts","exit_code":2}"#, match: "cmd"))
73
74        let cleared = await model.addRequiredContext("ci/more")
75
76        #expect(!cleared)
77        #expect(model.actionError != nil)
78    }
79
80    @Test func removingTheLastContextSendsAnEmptyList() async throws {
81        let (client, stub) = try makeClient()
82        stub.enqueue(.init(status: 200, json: """
83            {"protocol_version":1,"data":{"require_checks":true,"required_contexts":["ci/test"]},"exit_code":0}
84            """, match: "argv=settings"))
85        stub.enqueue(.init(status: 200, json: repoShowJSON, match: "argv=show&argv=krz"))
86        let model = RepoSettingsViewModel(client: client, repoPath: "krz/gitbay")
87        await model.load()
88        stub.enqueue(.init(status: 200, json: ok, match: "cmd"))
89
90        await model.removeRequiredContext("ci/test")
91
92        #expect(try postedArgv(stub) == [["repo", "settings", "require-contexts", "krz/gitbay"]])
93    }
94}