import XCTest import UIKit /// Actual normal chat and Agent views, using only the loopback contract fixture. @MainActor final class AgentPolishUITests: XCTestCase { let app = XCUIApplication() override func setUp() async throws { continueAfterFailure = false XCUIDevice.shared.orientation = .portrait try await control(["action": "reset", "count": 0]) app.launchArguments = ["-sybil.ios.apiBaseURL", "http://127.0.0.1:8799/api", "-sybil.ios.adminToken", "fixture-token"] } override func tearDown() async throws { app.terminate() } private func control(_ body: [String: Any]) async throws { var request = URLRequest(url: URL(string: "http://127.0.0.1:8799/control")!) request.httpMethod = "POST"; request.httpBody = try JSONSerialization.data(withJSONObject: body) request.setValue("application/json", forHTTPHeaderField: "Content-Type") let (_, response) = try await URLSession.shared.data(for: request) XCTAssertEqual((response as? HTTPURLResponse)?.statusCode, 200) } private func sidebar() { if !app.buttons["agent-sidebar"].isHittable { XCTAssertTrue(app.buttons["Show sidebar"].waitForExistence(timeout: 15)) app.buttons["Show sidebar"].tap() } } private func openChat() { sidebar() let chat = app.buttons.containing(NSPredicate(format: "label CONTAINS %@", "Transcript fade comparison")).firstMatch XCTAssertTrue(chat.waitForExistence(timeout: 8)); chat.tap() XCTAssertTrue(app.buttons["chat-attach"].waitForExistence(timeout: 8)) } private func openAgent() { sidebar(); app.buttons["agent-sidebar"].tap() XCTAssertTrue(app.buttons["agent-attach"].waitForExistence(timeout: 8)) } private func capture(_ name: String) { let shot = XCTAttachment(screenshot: XCUIScreen.main.screenshot()) shot.name = name; shot.lifetime = .keepAlways; add(shot) } func testSharedAttachmentControlAndPickerFlows() async throws { try await control(["action": "transcript-comparison"]) app.launch(); openChat() let normal = app.buttons["chat-attach"] XCTAssertEqual(normal.label, "Attach file"); XCTAssertTrue(normal.isEnabled) let normalSize = normal.frame.size let normalLabel = normal.label XCTAssertGreaterThanOrEqual(normalSize.width, 44); XCTAssertGreaterThanOrEqual(normalSize.height, 44) capture("polish-normal-attachment-control") normal.tap(); app.buttons["Files"].tap() XCTAssertTrue(app.buttons["Cancel"].firstMatch.waitForExistence(timeout: 5)); app.buttons["Cancel"].firstMatch.tap() normal.tap(); app.buttons["Photo Library"].tap() XCTAssertTrue(app.buttons["Cancel"].firstMatch.waitForExistence(timeout: 5)); app.buttons["Cancel"].firstMatch.tap() openAgent() let agent = app.buttons["agent-attach"] XCTAssertEqual(agent.label, normalLabel); XCTAssertTrue(agent.isEnabled) XCTAssertEqual(agent.frame.size.width, normalSize.width, accuracy: 1) XCTAssertEqual(agent.frame.size.height, normalSize.height, accuracy: 1) // Same row as the prompt, including the minimum VoiceOver/touch target. XCTAssertEqual(agent.frame.maxY, app.buttons["agent-send"].frame.maxY, accuracy: 1) capture("polish-agent-attachment-control") agent.tap(); app.buttons["Files"].tap() XCTAssertTrue(app.buttons["Cancel"].firstMatch.waitForExistence(timeout: 5)); app.buttons["Cancel"].firstMatch.tap() agent.tap(); app.buttons["Photo Library"].tap() XCTAssertTrue(app.buttons["Cancel"].firstMatch.waitForExistence(timeout: 5)); app.buttons["Cancel"].firstMatch.tap() } func testUserAssistantMultilineParagraphMetricsInBothWorkspaces() async throws { try await compareMetrics(user: "User first\nUser second\n\nUser paragraph", peer: "Peer first \nPeer second\n\nPeer paragraph", name: "multiline-paragraphs") } func testPastedParagraphMetricsInBothWorkspaces() async throws { try await compareMetrics(user: "User first\r\nUser second\r\n \r\nUser paragraph", peer: "Peer first \nPeer second\n\t\nPeer paragraph", name: "pasted-paragraphs") } private func compareMetrics(user: String, peer: String, name: String) async throws { try await control(["action": "presentation-samples", "messages": [ ["role": "user", "content": user], ["role": "assistant", "content": peer]]]) app.launch(); openChat() let normal = try metrics() capture("polish-normal-" + name) openAgent() let agent = try metrics() XCTAssertEqual(normal.0, agent.0, accuracy: 1) XCTAssertEqual(normal.1, agent.1, accuracy: 1) capture("polish-agent-" + name) } private func metrics() throws -> (CGFloat, CGFloat) { let user = app.staticTexts["User first\nUser second"] let peer = app.staticTexts["Peer first\nPeer second"] XCTAssertTrue(user.waitForExistence(timeout: 8)); XCTAssertTrue(peer.waitForExistence(timeout: 8)) let userParagraph = app.staticTexts["User paragraph"], peerParagraph = app.staticTexts["Peer paragraph"] XCTAssertTrue(userParagraph.exists); XCTAssertTrue(peerParagraph.exists) XCTAssertEqual(user.frame.height, peer.frame.height, accuracy: 1) let gap = userParagraph.frame.minY - user.frame.maxY XCTAssertEqual(gap, peerParagraph.frame.minY - peer.frame.maxY, accuracy: 1) XCTAssertGreaterThan(gap, 0) return (user.frame.height, gap) } func testLiteralUserAndSemanticAssistantMarkdown() async throws { try await control(["action": "presentation-samples", "messages": [ ["role": "user", "content": "**literal bold** `literal code`\n- literal item\n[not a link](https://example.invalid)"], ["role": "assistant", "content": "Soft break\ncontinues here.\n\n**Real bold** and [Local link](http://127.0.0.1:8799).\n\n- First item\n- Second item\n\n```swift\nlet value = 42\n```"]]]) app.launch(); openChat() assertMarkdownSemantics(); capture("polish-normal-literal-and-markdown") openAgent() assertMarkdownSemantics(); capture("polish-agent-literal-and-markdown") try await control(["action": "long-tool"]) XCTAssertFalse(app.staticTexts["Local tool output"].exists) } private func assertMarkdownSemantics() { XCTAssertTrue(app.staticTexts.containing(NSPredicate(format: "label CONTAINS %@", "**literal bold**")).firstMatch.waitForExistence(timeout: 8)) XCTAssertTrue(app.staticTexts.containing(NSPredicate(format: "label CONTAINS %@", "[not a link](https://example.invalid)")).firstMatch.exists) XCTAssertTrue(app.staticTexts.containing(NSPredicate(format: "label CONTAINS %@", "First item")).firstMatch.exists) XCTAssertTrue(app.staticTexts.containing(NSPredicate(format: "label CONTAINS %@", "let value = 42")).firstMatch.exists) XCTAssertTrue(app.links["Local link"].exists) } }