| @@ -182,6 +182,56 @@ struct IssueDetailColorsTests { |
| 182 | #expect(model.state.value?.number == 7) |
182 | #expect(model.state.value?.number == 7) |
| 183 | #expect(model.colors.hex("bug") == "#cf222e") |
183 | #expect(model.colors.hex("bug") == "#cf222e") |
| 184 | } |
184 | } |
| |
185 | |
| |
186 | /// Decoration must not take the screen down with it. |
| |
187 | @Test func issueStillLoadsWhenTheLabelReadFails() async throws { |
| |
188 | let (client, stub) = try makeClient() |
| |
189 | stub.enqueue(.init(status: 200, json: """ |
| |
190 | {"protocol_version":1,"data":{"number":7,"title":"a bug","state":"open",\ |
| |
191 | "author":"cmc","labels":["bug"],"created_at":"2026-09-01T00:00:00Z"},\ |
| |
192 | "exit_code":0} |
| |
193 | """, match: "argv=show")) |
| |
194 | stub.enqueue(.init(status: 403, json: """ |
| |
195 | {"protocol_version":1,"error":"denied","exit_code":4} |
| |
196 | """, match: "argv=label")) |
| |
197 | |
| |
198 | let model = IssueDetailViewModel(client: client, repoPath: "krz/gitbay", number: 7) |
| |
199 | await model.load() |
| |
200 | |
| |
201 | #expect(model.state.value?.number == 7) |
| |
202 | // Derived from the name, since nothing was stored. |
| |
203 | #expect(model.colors.hex("bug") == "#b93a86") |
| |
204 | } |
| |
205 | |
| |
206 | /// Regression test: `perform(argv:)` used to reload labels on every |
| |
207 | /// write. Labels rarely change mid-session, so the read must happen |
| |
208 | /// at most once per view model instance. |
| |
209 | @Test func aWriteDoesNotReissueLabelList() async throws { |
| |
210 | let (client, stub) = try makeClient() |
| |
211 | stub.enqueue(.init(status: 200, json: """ |
| |
212 | {"protocol_version":1,"data":{"number":7,"title":"a bug","state":"open",\ |
| |
213 | "author":"cmc","labels":["bug"],"created_at":"2026-09-01T00:00:00Z"},\ |
| |
214 | "exit_code":0} |
| |
215 | """, match: "argv=show")) |
| |
216 | stub.enqueue(.init(status: 200, json: labelListJSON, match: "argv=label")) |
| |
217 | |
| |
218 | let model = IssueDetailViewModel(client: client, repoPath: "krz/gitbay", number: 7) |
| |
219 | await model.load() |
| |
220 | |
| |
221 | stub.enqueue(.init(status: 200, json: """ |
| |
222 | {"protocol_version":1,"exit_code":0} |
| |
223 | """, match: "argv=close")) |
| |
224 | stub.enqueue(.init(status: 200, json: """ |
| |
225 | {"protocol_version":1,"data":{"number":7,"title":"a bug","state":"closed",\ |
| |
226 | "author":"cmc","labels":["bug"],"created_at":"2026-09-01T00:00:00Z"},\ |
| |
227 | "exit_code":0} |
| |
228 | """, match: "argv=show")) |
| |
229 | |
| |
230 | await model.close() |
| |
231 | |
| |
232 | let labelReads = stub.seen.filter { ($0.url.query() ?? "").contains("argv=label") } |
| |
233 | #expect(labelReads.count == 1) |
| |
234 | } |
| 185 | } |
235 | } |
| 186 | |
236 | |
| 187 | @MainActor |
237 | @MainActor |
| @@ -284,4 +334,19 @@ struct LabelListViewModelTests { |
| 284 | #expect(model.actionError?.isEmpty == false) |
334 | #expect(model.actionError?.isEmpty == false) |
| 285 | #expect(model.working == false) |
335 | #expect(model.working == false) |
| 286 | } |
336 | } |
| |
337 | |
| |
338 | @Test func aServerFailureSurfacesAsFailed() async throws { |
| |
339 | let (client, stub) = try makeClient() |
| |
340 | stub.enqueue(.init(status: 200, json: """ |
| |
341 | {"protocol_version":1,"error":"boom","exit_code":1} |
| |
342 | """)) |
| |
343 | let model = LabelListViewModel(client: client, repoPath: "krz/gitbay") |
| |
344 | |
| |
345 | await model.load() |
| |
346 | |
| |
347 | guard case .failed = model.state else { |
| |
348 | Testing.Issue.record("expected a failed state, got \(model.state)") |
| |
349 | return |
| |
350 | } |
| |
351 | } |
| 287 | } |
352 | } |