Files
openclaw/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatToolActivityTests.swift
T
Peter Steinberger 4b46a14a54 feat(apple): show live subagent activity in chat (#121815)
* feat(apple): show live subagent activity in chat

* chore(apple): refresh native localization inventory
2026-08-10 21:50:13 -07:00

121 lines
3.8 KiB
Swift

import OpenClawKit
import Testing
@testable import OpenClawChatUI
@Suite("ChatToolActivity")
struct ChatToolActivityTests {
@Test func `pairs call and result by ID`() {
let items = ChatToolActivity.items(
calls: [self.content(type: "toolCall", id: "call-1", name: "exec")],
results: [self.content(type: "toolResult", text: "done", id: "call-1", name: "exec")])
#expect(items == [ChatToolActivityItem(
id: "call-1",
name: "exec",
arguments: nil,
details: nil,
resultText: "done",
isError: false,
isPending: false,
liveDiffStat: nil)])
}
@Test func `appends orphan result`() {
let items = ChatToolActivity.items(
calls: [],
results: [self.content(type: "toolResult", text: "orphaned", name: "read")])
#expect(items == [ChatToolActivityItem(
id: "result-0",
name: "read",
arguments: nil,
details: nil,
resultText: "orphaned",
isError: false,
isPending: false,
liveDiffStat: nil)])
}
@Test func `preserves call order`() {
let items = ChatToolActivity.items(
calls: [
self.content(type: "toolCall", id: "call-1", name: "read"),
self.content(type: "toolCall", id: "call-2", name: "write"),
],
results: [
self.content(type: "toolResult", text: "second", id: "call-2", name: "write"),
self.content(type: "toolResult", text: "first", id: "call-1", name: "read"),
])
#expect(items.map(\.id) == ["call-1", "call-2"])
#expect(items.map(\.resultText) == ["first", "second"])
}
@Test func `leaves call without result unexpandable`() {
let items = ChatToolActivity.items(
calls: [self.content(type: "toolCall", name: "search")],
results: [])
#expect(items == [ChatToolActivityItem(
id: "call-0",
name: "search",
arguments: nil,
details: nil,
resultText: nil,
isError: false,
isPending: false,
liveDiffStat: nil)])
}
@Test func `threads paired result details`() {
let details = AnyCodable(["diff": AnyCodable("+1 added")])
let items = ChatToolActivity.items(
calls: [self.content(type: "toolCall", id: "call-1", name: "edit")],
results: [self.content(
type: "toolResult",
text: "done",
id: "call-1",
name: "edit",
details: details)])
#expect(items.first?.details == details)
}
@Test func `threads paired and orphan result errors`() {
let paired = ChatToolActivity.items(
calls: [self.content(type: "toolCall", id: "call-1", name: "edit")],
results: [self.content(
type: "toolResult",
text: "failed",
id: "call-1",
name: "edit",
isError: true)])
let orphan = ChatToolActivity.items(
calls: [],
results: [self.content(type: "toolResult", text: "failed", isError: true)])
#expect(paired.first?.isError == true)
#expect(orphan.first?.isError == true)
}
private func content(
type: String,
text: String? = nil,
id: String? = nil,
name: String? = nil,
details: AnyCodable? = nil,
isError: Bool? = nil) -> OpenClawChatMessageContent
{
OpenClawChatMessageContent(
type: type,
text: text,
mimeType: nil,
fileName: nil,
content: nil,
id: id,
name: name,
details: details,
isError: isError)
}
}