-
Notifications
You must be signed in to change notification settings - Fork 230
[CI] Implement new cross-platform mock server #3914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
# Conflicts: # Gemfile.lock # README.md # StreamChat.xcodeproj/project.pbxproj # StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift # StreamChatUITestsAppUITests/Tests/StreamTestCase+Tags.swift # StreamChatUITestsAppUITests/Tests/UserDetails_Tests.swift # TestTools/StreamChatTestMockServer/Extensions/Dictionary.swift # TestTools/StreamChatTestMockServer/Extensions/String.swift # TestTools/StreamChatTestMockServer/Extensions/Swifter.swift # TestTools/StreamChatTestMockServer/MockServer/AttachmentResponses.swift # TestTools/StreamChatTestMockServer/MockServer/ChannelConfig.swift # TestTools/StreamChatTestMockServer/MockServer/ChannelResponses.swift # TestTools/StreamChatTestMockServer/MockServer/DeviceRemoteControl.swift # TestTools/StreamChatTestMockServer/MockServer/EventResponses.swift # TestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swift # TestTools/StreamChatTestMockServer/MockServer/MembersResponse.swift # TestTools/StreamChatTestMockServer/MockServer/MessageList.swift # TestTools/StreamChatTestMockServer/MockServer/MessageResponses.swift # TestTools/StreamChatTestMockServer/MockServer/MockServerAttributes.swift # TestTools/StreamChatTestMockServer/MockServer/ReactionResponses.swift # TestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swift # TestTools/StreamChatTestMockServer/MockServer/User.swift # TestTools/StreamChatTestMockServer/MockServer/WebsocketResponses.swift # TestTools/StreamChatTestMockServer/Swifter/DemoServer.swift # TestTools/StreamChatTestMockServer/Swifter/Errno.swift # TestTools/StreamChatTestMockServer/Swifter/Files.swift # TestTools/StreamChatTestMockServer/Swifter/HttpParser.swift # TestTools/StreamChatTestMockServer/Swifter/HttpRequest.swift # TestTools/StreamChatTestMockServer/Swifter/HttpResponse.swift # TestTools/StreamChatTestMockServer/Swifter/HttpRouter.swift # TestTools/StreamChatTestMockServer/Swifter/HttpServer.swift # TestTools/StreamChatTestMockServer/Swifter/HttpServerIO.swift # TestTools/StreamChatTestMockServer/Swifter/MimeTypes.swift # TestTools/StreamChatTestMockServer/Swifter/Process.swift # TestTools/StreamChatTestMockServer/Swifter/Scopes.swift # TestTools/StreamChatTestMockServer/Swifter/Socket+File.swift # TestTools/StreamChatTestMockServer/Swifter/Socket+Server.swift # TestTools/StreamChatTestMockServer/Swifter/Socket.swift # TestTools/StreamChatTestMockServer/Swifter/String+BASE64.swift # TestTools/StreamChatTestMockServer/Swifter/String+File.swift # TestTools/StreamChatTestMockServer/Swifter/String+Misc.swift # TestTools/StreamChatTestMockServer/Swifter/String+SHA1.swift # TestTools/StreamChatTestMockServer/Swifter/WebSockets.swift # TestTools/StreamChatTestMockServer/Utilities/TestData.swift # fastlane/Fastfile
📝 WalkthroughWalkthroughMigrate test infrastructure from an in-process Sinatra/Swifter mock server and JSON fixtures to a driver-based external mock server. Remove embedded Swifter server and many fixtures; introduce a driver-driven StreamMockServer client, new programmatic mock endpoints/types, update Fastlane/CI, robots, and test callsites to use HTTP driver endpoints. Changes
Sequence Diagram(s)sequenceDiagram
participant TestRunner as XCTest/Test Runner
participant MockClient as StreamMockServer (client)
participant MockDriver as Mock Server Driver (HTTP)
participant App as XCUIApplication / App
TestRunner->>MockClient: init(driverPort, testName)
MockClient->>MockDriver: GET /start?testName=...
MockDriver-->>MockClient: 200 OK { port, url }
TestRunner->>App: launch with env MOCK_SERVER_PORT
TestRunner->>MockClient: POST /<endpoint> (e.g., generateChannels, delayNewMessages)
MockClient->>MockDriver: POST /<endpoint> (JSON)
MockDriver->>App: trigger events / serve responses (via driver)
App-->>TestRunner: UI updates / assertions
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (1)**/*.swift📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (7)📓 Common learnings📚 Learning: 2025-11-25T12:17:18.459ZApplied to files:
📚 Learning: 2025-11-25T12:17:18.459ZApplied to files:
📚 Learning: 2025-11-25T12:17:18.459ZApplied to files:
📚 Learning: 2025-11-25T12:17:18.459ZApplied to files:
📚 Learning: 2025-11-25T12:17:18.459ZApplied to files:
📚 Learning: 2025-11-25T12:17:18.459ZApplied to files:
🧬 Code graph analysis (1)StreamChatUITestsAppUITests/Tests/MessageList_Tests.swift (10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🔇 Additional comments (11)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
StreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swift (1)
43-55: Use optional binding instead of force unwrap on the static property.While
StreamMockServer.portis initialized beforebackendHandler()runs in the current code flow, force unwrapping a static property that persists across tests is error-prone. Replace the force unwrap with optional binding to handle potential future changes and improve code robustness.🔒 Suggested fix
private func backendHandler() { + guard let port = StreamMockServer.port else { + XCTFail("StreamMockServer.port is not set") + return + } app.setEnvironmentVariables([ .websocketHost: "ws://localhost", .httpHost: "http://localhost", - .port: StreamMockServer.port! + .port: port ]) if useMockServer { app.setLaunchArguments(.useMockServer) } else if let switchApiKey { app.setEnvironmentVariables([.customApiKey: switchApiKey]) } }
🤖 Fix all issues with AI agents
In @StreamChatUITestsApp/ViewController.swift:
- Line 213: Replace the forced unwrap of
ProcessInfo.processInfo.environment["MOCK_SERVER_PORT"] with safe optional
handling: use guard let portString =
ProcessInfo.processInfo.environment["MOCK_SERVER_PORT"] to check presence, then
convert to an Int (guard let port = Int(portString)) and handle the failure path
(return, throw, use a sensible default, or call XCTFail with a clear message).
Update the binding currently named port so it is non‑optional after these guards
and ensure any downstream code that used the forced-unwrapped value uses this
safely unwrapped variable instead.
In @StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift:
- Around line 347-359: The test can crash when the message list is empty because
computing cells.count - 1 underflows; in assertFirstMessageIsVisible add a guard
that cells is not empty before calling messageCell(withIndex:), and if empty
call XCTFail with a clear message (include file and line) and return self so the
test fails gracefully; then compute the last index safely (e.g., let lastIndex =
cells.count - 1) and continue using messageCell(withIndex:) and the existing
assertions.
In @StreamChatUITestsAppUITests/Tests/Backend/Backend_Tests.swift:
- Line 10: Replace the hard-coded demo API key assigned to switchApiKey
("8br4watad788") with an obvious placeholder string (e.g., "YOUR_STREAM_KEY") so
test/example code does not contain real/demo credentials; update the assignment
to set switchApiKey to the placeholder and leave a comment if needed to indicate
where to obtain a real key for testing.
In @TestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swift:
- Around line 65-91: getRequest currently force-unwraps url in its default
parameter (baseUrl: String = url!), which can crash if url is nil; mirror the
postRequest fix: make baseUrl optional (e.g., baseUrl: String? = nil), then
inside getRequest resolve a safe base string by using the provided baseUrl or
falling back to the instance url only after safely unwrapping it (or return an
early default result when neither is present), and use that safe base value to
construct the URL for the request.
- Around line 34-63: The postRequest function currently force-unwraps the shared
property url via the default parameter baseUrl: String = url!, which can crash
if url is nil; change the signature to accept an optional baseUrl (e.g.,
baseUrl: String? = nil) and inside postRequest resolve a non-optional base using
let base = baseUrl ?? url and guard that base is non-nil (or return an explicit
error/status), then build the request with that safe base; remove the
force-unwrap and ensure you handle the missing-base case deterministically
before creating the URL and request.
In @TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift:
- Around line 179-189: Two methods are misspelled: rename pinMesage to
pinMessage and unpinMesage to unpinMessage in ParticipantRobot so the API is
clear; update the method declarations (preserve @discardableResult, return type
ParticipantRobot and the existing mockServer.postRequest(endpoint: "...") calls)
and then update any callers/tests to use the new names; keep the endpoint
strings ("participant/message?action=pin" and "...?action=unpin") unchanged.
- Around line 64-84: The code force-unwraps
ProcessInfo.processInfo.environment["SIMULATOR_UDID"] inside
ParticipantRobot.sendPushNotification which will crash outside a simulator;
replace the forced unwrap with a guard let udid =
ProcessInfo.processInfo.environment["SIMULATOR_UDID"] else {
fatalError("SIMULATOR_UDID not set: sendPushNotification requires a simulator
UDID") } (or preconditionFailure/log + return self if you prefer non-fatal
behavior) before building the endpoint and calling mockServer.postRequest so the
failure is reported with a clear message instead of an unexpected crash.
🧹 Nitpick comments (9)
.gitignore (1)
103-103: Add trailing slash for consistency with other directory entries.The mock server directory entry should follow the same pattern as other build/generated directories in the file (e.g.,
build/,.build/,Pods/on lines 14, 54, and 61).♻️ Proposed fix
-stream-chat-test-mock-server +stream-chat-test-mock-server/fastlane/Fastfile (1)
356-356: Consider removing redundant cleanup call.The
stop_mock_servercall on line 356 is only executed on localhost, but lines 366-367 unconditionally kill any process on port 4566 regardless of environment. The conditional stop adds an HTTP request overhead without clear benefit.♻️ Simplify cleanup logic
lane :start_mock_server do |options| mock_server_repo = 'stream-chat-test-mock-server' - stop_mock_server if is_localhost if options[:local_server]StreamChatUITestsAppUITests/Tests/PushNotification_Tests.swift (1)
80-141: Consider improving variable naming and assertion consistency.The test uses a variable named
messageto represent test scenario identifiers ("null", "empty", "42"), which can be confusing since these are also used as message content. Additionally, lines 137-139 use hardcoded strings instead of themessagevariables.♻️ Suggested improvements
Consider renaming variables to clarify their purpose and using them consistently in assertions:
WHEN("participant sends a message (push body param is nil)") { - let message = "null" + let testScenario = "null" participantRobot .sleep(1) - .sendMessage(message) + .sendMessage(testScenario) .sendPushNotification( - title: message, - body: message, + title: testScenario, + body: testScenario, bundleId: app.bundleId(), - rest: message + rest: testScenario ) } THEN("user does not receive a push notification") { userRobot.assertPushNotificationDoesNotAppear() } WHEN("participant sends a message (push body param is empty)") { - let message = "empty" + let testScenario = "empty" participantRobot - .sendMessage(message) + .sendMessage(testScenario) .sendPushNotification( - title: message, - body: message, + title: testScenario, + body: testScenario, bundleId: app.bundleId(), - rest: message + rest: testScenario ) } THEN("user does not receive a push notification") { userRobot.assertPushNotificationDoesNotAppear() } WHEN("participant sends a message (push body param contains incorrect type)") { - let message = "42" + let testScenario = "42" participantRobot - .sendMessage(message) + .sendMessage(testScenario) .sendPushNotification( - title: message, - body: message, + title: testScenario, + body: testScenario, bundleId: app.bundleId(), rest: "incorrect_type" ) }And update the assertions to use the variables:
THEN("message list updates") { + let firstScenario = "null" + let secondScenario = "empty" + let thirdScenario = "42" userRobot - .assertMessage("null", at: 2) - .assertMessage("empty", at: 1) - .assertMessage("42", at: 0) + .assertMessage(firstScenario, at: 2) + .assertMessage(secondScenario, at: 1) + .assertMessage(thirdScenario, at: 0) }Or extract these test scenarios as constants at the class level for better maintainability.
TestTools/StreamChatTestMockServer/MockServer/DataTypes.swift (1)
29-38: Consider making the computed property public or removing it.The
statuscomputed property isinternalwhile the enum ispublic. If external modules need to access the string value, they can userawValuedirectly, making thestatusproperty potentially redundant. The same applies toattachmentandreactionproperties in the other enums.♻️ Option: Remove redundant computed properties
If
rawValueis sufficient for all use cases:public enum MessageDeliveryStatus: String { case read case pending case sent case failed - - var status: String { - return rawValue - } }Similar changes for
AttachmentType.attachmentandReactionType.reaction.StreamChatUITestsAppUITests/Tests/ChannelList_Tests.swift (1)
42-45: Consider replacing sleep with an explicit synchronization mechanism.The hardcoded 2-second sleep could make the test brittle and slow. If the mock server provides a way to confirm message processing or delivery, prefer that over a fixed delay.
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (2)
15-46: URL-encode query parameter values to handle special characters.The
messagesTextandrepliesTextparameters are inserted directly into the query string without URL encoding. If these contain special characters (spaces,&,=, etc.), the endpoint URL will be malformed.♻️ Suggested fix using percent encoding
public func generateChannels( channelsCount: Int, messagesCount: Int = 0, repliesCount: Int = 0, attachments: Bool = false, messagesText: String? = nil, repliesText: String? = nil ) -> BackendRobot { waitForMockServerToStart() var messagesTextQueryParam = "" if let messagesText { - messagesTextQueryParam = "messages_text=\(messagesText)&" + let encoded = messagesText.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? messagesText + messagesTextQueryParam = "messages_text=\(encoded)&" } var repliesTextQueryParam = "" if let repliesText { - repliesTextQueryParam = "replies_text=\(repliesText)&" + let encoded = repliesText.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? repliesText + repliesTextQueryParam = "replies_text=\(encoded)&" }
95-120: Force-unwrap on static URL may crash if mock server hasn't been initialized.
StreamMockServer.url!on Line 98 will crash if the mock server was never initialized. WhilewaitForMockServerToStartis typically called after initialization, adding a guard or using optional binding would make this more defensive.♻️ Defensive guard
private func waitForMockServerToStart() { + guard let baseUrl = StreamMockServer.url else { + XCTFail("MockServer URL is not configured") + return + } let startTime = Date().timeIntervalSince1970 while Date().timeIntervalSince1970 - startTime < 5.0 { - var request = URLRequest(url: URL(string: "\(StreamMockServer.url!)/ping")!) + var request = URLRequest(url: URL(string: "\(baseUrl)/ping")!) request.httpMethod = "GET"TestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swift (2)
11-11: Remove unusedurlSessionproperty.The
urlSessionproperty is declared but never used;URLSession.sharedis used directly in the request methods.♻️ Remove unused property
public final class StreamMockServer { public nonisolated(unsafe) static var url: String? public nonisolated(unsafe) static var port: String? - private let urlSession: URLSession = URLSession.shared public static let jwtTimeout: UInt32 = 5
12-15: DuplicatejwtTimeoutdeclarations.
jwtTimeoutis declared both as a static property (Line 12) and an instance property (Line 15). This is redundant and could lead to confusion about which one to use.♻️ Remove duplicate instance property
public static let jwtTimeout: UInt32 = 5 public let udid = ProcessInfo.processInfo.environment["SIMULATOR_UDID"] ?? "" public let forbiddenWord: String = "wth" - public let jwtTimeout: UInt32 = 5
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
Gemfile.lockis excluded by!**/*.lock
📒 Files selected for processing (93)
.github/workflows/cron-checks.yml.github/workflows/smoke-checks.yml.github/workflows/sync-mock-server.yml.gitignoreGemfileREADME.mdStreamChat.xcodeproj/project.pbxprojStreamChatUITestsApp/ViewController.swiftStreamChatUITestsAppUITests/Pages/ChannelListPage.swiftStreamChatUITestsAppUITests/Pages/MessageListPage.swiftStreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftStreamChatUITestsAppUITests/Robots/UserRobot.swiftStreamChatUITestsAppUITests/Tests/Attachments_Tests.swiftStreamChatUITestsAppUITests/Tests/Authentication_Tests.swiftStreamChatUITestsAppUITests/Tests/Backend/Backend_Tests.swiftStreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swiftStreamChatUITestsAppUITests/Tests/ChannelList_Tests.swiftStreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swiftStreamChatUITestsAppUITests/Tests/MessageList_Tests.swiftStreamChatUITestsAppUITests/Tests/Performance/ChannelListScrollTime.swiftStreamChatUITestsAppUITests/Tests/Performance/MessageListScrollTime.swiftStreamChatUITestsAppUITests/Tests/PushNotification_Tests.swiftStreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swiftStreamChatUITestsAppUITests/Tests/Reactions_Tests.swiftStreamChatUITestsAppUITests/Tests/SlowMode_Tests.swiftStreamChatUITestsAppUITests/Tests/StreamTestCase+Tags.swiftStreamChatUITestsAppUITests/Tests/UserDetails_Tests.swiftTestTools/StreamChatTestMockServer/Extensions/Dictionary.swiftTestTools/StreamChatTestMockServer/Extensions/String.swiftTestTools/StreamChatTestMockServer/Extensions/Swifter.swiftTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_add_member.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_attachment.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_channel_creation.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_channel_removal.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_channels.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_events.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_member.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_message.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_message_ephemeral.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_reaction.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_truncate.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_unsplash_link.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/http_youtube_link.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/push_notification.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_events.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_events_channel.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_events_member.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_health_check.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_message.jsonTestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_reaction.jsonTestTools/StreamChatTestMockServer/MockServer/AttachmentResponses.swiftTestTools/StreamChatTestMockServer/MockServer/ChannelConfig.swiftTestTools/StreamChatTestMockServer/MockServer/ChannelResponses.swiftTestTools/StreamChatTestMockServer/MockServer/DataTypes.swiftTestTools/StreamChatTestMockServer/MockServer/DeviceRemoteControl.swiftTestTools/StreamChatTestMockServer/MockServer/EventResponses.swiftTestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swiftTestTools/StreamChatTestMockServer/MockServer/MembersResponse.swiftTestTools/StreamChatTestMockServer/MockServer/MessageList.swiftTestTools/StreamChatTestMockServer/MockServer/MessageResponses.swiftTestTools/StreamChatTestMockServer/MockServer/MockServerAttributes.swiftTestTools/StreamChatTestMockServer/MockServer/ReactionResponses.swiftTestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swiftTestTools/StreamChatTestMockServer/MockServer/User.swiftTestTools/StreamChatTestMockServer/MockServer/WebsocketResponses.swiftTestTools/StreamChatTestMockServer/Robots/BackendRobot.swiftTestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swiftTestTools/StreamChatTestMockServer/Swifter/DemoServer.swiftTestTools/StreamChatTestMockServer/Swifter/Errno.swiftTestTools/StreamChatTestMockServer/Swifter/Files.swiftTestTools/StreamChatTestMockServer/Swifter/HttpParser.swiftTestTools/StreamChatTestMockServer/Swifter/HttpRequest.swiftTestTools/StreamChatTestMockServer/Swifter/HttpResponse.swiftTestTools/StreamChatTestMockServer/Swifter/HttpRouter.swiftTestTools/StreamChatTestMockServer/Swifter/HttpServer.swiftTestTools/StreamChatTestMockServer/Swifter/HttpServerIO.swiftTestTools/StreamChatTestMockServer/Swifter/MimeTypes.swiftTestTools/StreamChatTestMockServer/Swifter/Process.swiftTestTools/StreamChatTestMockServer/Swifter/Scopes.swiftTestTools/StreamChatTestMockServer/Swifter/Socket+File.swiftTestTools/StreamChatTestMockServer/Swifter/Socket+Server.swiftTestTools/StreamChatTestMockServer/Swifter/Socket.swiftTestTools/StreamChatTestMockServer/Swifter/String+BASE64.swiftTestTools/StreamChatTestMockServer/Swifter/String+File.swiftTestTools/StreamChatTestMockServer/Swifter/String+Misc.swiftTestTools/StreamChatTestMockServer/Swifter/String+SHA1.swiftTestTools/StreamChatTestMockServer/Swifter/WebSockets.swiftTestTools/StreamChatTestMockServer/Utilities/TestData.swiftfastlane/Fastfilefastlane/sinatra.rbfastlane/sync_mock_server.rb
💤 Files with no reviewable changes (64)
- README.md
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_events.json
- TestTools/StreamChatTestMockServer/MockServer/MembersResponse.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_channel_creation.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_channel_removal.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_attachment.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_health_check.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_truncate.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_reaction.json
- TestTools/StreamChatTestMockServer/Swifter/Errno.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_message.json
- .github/workflows/sync-mock-server.yml
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_events_channel.json
- StreamChatUITestsAppUITests/Tests/StreamTestCase+Tags.swift
- TestTools/StreamChatTestMockServer/MockServer/MessageResponses.swift
- TestTools/StreamChatTestMockServer/MockServer/ChannelConfig.swift
- TestTools/StreamChatTestMockServer/Swifter/DemoServer.swift
- TestTools/StreamChatTestMockServer/MockServer/User.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_channels.json
- TestTools/StreamChatTestMockServer/Swifter/HttpParser.swift
- StreamChatUITestsAppUITests/Tests/UserDetails_Tests.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_unsplash_link.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_events_member.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/push_notification.json
- TestTools/StreamChatTestMockServer/Swifter/Socket+File.swift
- TestTools/StreamChatTestMockServer/Swifter/HttpResponse.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_events.json
- TestTools/StreamChatTestMockServer/Swifter/HttpRequest.swift
- TestTools/StreamChatTestMockServer/MockServer/ChannelResponses.swift
- fastlane/sinatra.rb
- TestTools/StreamChatTestMockServer/Extensions/String.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/ws_reaction.json
- TestTools/StreamChatTestMockServer/Swifter/Files.swift
- TestTools/StreamChatTestMockServer/Swifter/HttpRouter.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_member.json
- TestTools/StreamChatTestMockServer/MockServer/DeviceRemoteControl.swift
- Gemfile
- StreamChatUITestsAppUITests/Tests/Reactions_Tests.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_add_member.json
- TestTools/StreamChatTestMockServer/Swifter/String+BASE64.swift
- TestTools/StreamChatTestMockServer/Swifter/String+Misc.swift
- TestTools/StreamChatTestMockServer/Swifter/Socket+Server.swift
- TestTools/StreamChatTestMockServer/MockServer/MessageList.swift
- TestTools/StreamChatTestMockServer/Swifter/HttpServer.swift
- TestTools/StreamChatTestMockServer/Extensions/Dictionary.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_message_ephemeral.json
- TestTools/StreamChatTestMockServer/Swifter/HttpServerIO.swift
- TestTools/StreamChatTestMockServer/MockServer/WebsocketResponses.swift
- TestTools/StreamChatTestMockServer/Extensions/Swifter.swift
- TestTools/StreamChatTestMockServer/Swifter/String+SHA1.swift
- TestTools/StreamChatTestMockServer/MockServer/EventResponses.swift
- TestTools/StreamChatTestMockServer/Utilities/TestData.swift
- TestTools/StreamChatTestMockServer/MockServer/AttachmentResponses.swift
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_youtube_link.json
- TestTools/StreamChatTestMockServer/Fixtures/JSONs/http_message.json
- TestTools/StreamChatTestMockServer/Swifter/String+File.swift
- TestTools/StreamChatTestMockServer/Swifter/MimeTypes.swift
- TestTools/StreamChatTestMockServer/Swifter/Socket.swift
- fastlane/sync_mock_server.rb
- TestTools/StreamChatTestMockServer/MockServer/ReactionResponses.swift
- TestTools/StreamChatTestMockServer/Swifter/Process.swift
- TestTools/StreamChatTestMockServer/Swifter/WebSockets.swift
- TestTools/StreamChatTestMockServer/MockServer/MockServerAttributes.swift
- TestTools/StreamChatTestMockServer/Swifter/Scopes.swift
🧰 Additional context used
📓 Path-based instructions (1)
**/*.swift
📄 CodeRabbit inference engine (AGENTS.md)
**/*.swift: Write Swift code compatible with iOS deployment targets specified in Package.swift and podspec files; do not lower deployment targets without approval
Use SwiftLint with strict mode and respect .swiftlint.yml rules; justify and scope any exceptions rather than suppressing rules broadly
Run SwiftFormat for code formatting and respect repository-specific style conventions
Never commit API keys or customer data; use obvious placeholders (e.g., YOUR_STREAM_KEY) in example code
Follow the project's zero-warnings policy: fix new warnings and avoid introducing any
Files:
TestTools/StreamChatTestMockServer/MockServer/DataTypes.swiftStreamChatUITestsAppUITests/Tests/Performance/MessageListScrollTime.swiftStreamChatUITestsAppUITests/Tests/Attachments_Tests.swiftTestTools/StreamChatTestMockServer/Robots/BackendRobot.swiftStreamChatUITestsAppUITests/Tests/SlowMode_Tests.swiftStreamChatUITestsAppUITests/Tests/Backend/Backend_Tests.swiftStreamChatUITestsAppUITests/Tests/PushNotification_Tests.swiftStreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swiftStreamChatUITestsAppUITests/Tests/ChannelList_Tests.swiftTestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swiftStreamChatUITestsAppUITests/Pages/MessageListPage.swiftStreamChatUITestsAppUITests/Pages/ChannelListPage.swiftStreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swiftStreamChatUITestsApp/ViewController.swiftTestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swiftStreamChatUITestsAppUITests/Tests/Performance/ChannelListScrollTime.swiftStreamChatUITestsAppUITests/Robots/UserRobot.swiftStreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swiftStreamChatUITestsAppUITests/Tests/MessageList_Tests.swiftStreamChatUITestsAppUITests/Tests/Authentication_Tests.swiftStreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftTestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Tests/**/*.swift : Add or extend tests in the matching module's Tests/ folder for changes to StreamChat or StreamChatUI code, covering core models, API surfaces, and view controller behaviors; use fakes/mocks from test helpers provided by the repo
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Tests/**/*.swift : Add or extend tests in the matching module's Tests/ folder for changes to StreamChat or StreamChatUI code, covering core models, API surfaces, and view controller behaviors; use fakes/mocks from test helpers provided by the repo
Applied to files:
.github/workflows/cron-checks.ymlTestTools/StreamChatTestMockServer/MockServer/DataTypes.swiftStreamChatUITestsAppUITests/Tests/Performance/MessageListScrollTime.swiftStreamChatUITestsAppUITests/Tests/Attachments_Tests.swiftStreamChat.xcodeproj/project.pbxproj.github/workflows/smoke-checks.ymlTestTools/StreamChatTestMockServer/Robots/BackendRobot.swift.gitignoreStreamChatUITestsAppUITests/Tests/SlowMode_Tests.swiftStreamChatUITestsAppUITests/Tests/Backend/Backend_Tests.swiftStreamChatUITestsAppUITests/Tests/PushNotification_Tests.swiftStreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swiftStreamChatUITestsAppUITests/Tests/ChannelList_Tests.swiftTestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swiftStreamChatUITestsAppUITests/Pages/MessageListPage.swiftStreamChatUITestsAppUITests/Pages/ChannelListPage.swiftStreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swiftStreamChatUITestsApp/ViewController.swiftTestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swiftStreamChatUITestsAppUITests/Tests/Performance/ChannelListScrollTime.swiftStreamChatUITestsAppUITests/Robots/UserRobot.swiftStreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swiftStreamChatUITestsAppUITests/Tests/MessageList_Tests.swiftfastlane/FastfileStreamChatUITestsAppUITests/Tests/Authentication_Tests.swiftStreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftTestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Sources/StreamChat/**/*.swift : Ensure public API changes in StreamChat and StreamChatUI include inline documentation and migration notes
Applied to files:
TestTools/StreamChatTestMockServer/MockServer/DataTypes.swiftStreamChatUITestsAppUITests/Tests/Performance/MessageListScrollTime.swiftStreamChatUITestsAppUITests/Tests/Attachments_Tests.swiftStreamChat.xcodeproj/project.pbxprojTestTools/StreamChatTestMockServer/Robots/BackendRobot.swiftStreamChatUITestsAppUITests/Tests/SlowMode_Tests.swiftStreamChatUITestsAppUITests/Tests/PushNotification_Tests.swiftStreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swiftStreamChatUITestsAppUITests/Tests/ChannelList_Tests.swiftTestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swiftStreamChatUITestsAppUITests/Pages/MessageListPage.swiftStreamChatUITestsAppUITests/Pages/ChannelListPage.swiftStreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swiftStreamChatUITestsApp/ViewController.swiftTestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swiftStreamChatUITestsAppUITests/Tests/Performance/ChannelListScrollTime.swiftStreamChatUITestsAppUITests/Robots/UserRobot.swiftStreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swiftStreamChatUITestsAppUITests/Tests/MessageList_Tests.swiftStreamChatUITestsAppUITests/Tests/Authentication_Tests.swiftStreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftTestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Sources/StreamChatUI/**/*.swift : Ensure public API changes in StreamChatUI include inline documentation and migration notes
Applied to files:
TestTools/StreamChatTestMockServer/MockServer/DataTypes.swiftStreamChatUITestsAppUITests/Tests/Performance/MessageListScrollTime.swiftStreamChatUITestsAppUITests/Tests/Attachments_Tests.swiftStreamChat.xcodeproj/project.pbxprojTestTools/StreamChatTestMockServer/Robots/BackendRobot.swiftStreamChatUITestsAppUITests/Tests/SlowMode_Tests.swiftStreamChatUITestsAppUITests/Tests/PushNotification_Tests.swiftStreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swiftStreamChatUITestsAppUITests/Tests/ChannelList_Tests.swiftTestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swiftStreamChatUITestsAppUITests/Pages/MessageListPage.swiftStreamChatUITestsAppUITests/Pages/ChannelListPage.swiftStreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swiftStreamChatUITestsApp/ViewController.swiftTestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swiftStreamChatUITestsAppUITests/Tests/Performance/ChannelListScrollTime.swiftStreamChatUITestsAppUITests/Robots/UserRobot.swiftStreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swiftStreamChatUITestsAppUITests/Tests/MessageList_Tests.swiftStreamChatUITestsAppUITests/Tests/Authentication_Tests.swiftStreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftTestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Maintain high test coverage when changing code in the Stream iOS Chat SDK
Applied to files:
StreamChatUITestsAppUITests/Tests/Attachments_Tests.swiftStreamChat.xcodeproj/project.pbxprojTestTools/StreamChatTestMockServer/Robots/BackendRobot.swiftStreamChatUITestsAppUITests/Tests/SlowMode_Tests.swiftStreamChatUITestsAppUITests/Tests/PushNotification_Tests.swiftStreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swiftStreamChatUITestsAppUITests/Tests/ChannelList_Tests.swiftStreamChatUITestsAppUITests/Pages/MessageListPage.swiftStreamChatUITestsAppUITests/Pages/ChannelListPage.swiftStreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swiftTestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swiftStreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swiftStreamChatUITestsAppUITests/Robots/UserRobot.swiftStreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swiftStreamChatUITestsAppUITests/Tests/MessageList_Tests.swiftStreamChatUITestsAppUITests/Tests/Authentication_Tests.swiftStreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftTestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to CHANGELOG* : Update CHANGELOG entries for user-visible SDK changes in StreamChat and StreamChatUI
Applied to files:
StreamChat.xcodeproj/project.pbxproj.gitignoreStreamChatUITestsAppUITests/Tests/PushNotification_Tests.swiftStreamChatUITestsAppUITests/Pages/MessageListPage.swiftStreamChatUITestsAppUITests/Pages/ChannelListPage.swiftStreamChatUITestsAppUITests/Robots/UserRobot.swiftStreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swiftStreamChatUITestsAppUITests/Tests/MessageList_Tests.swiftStreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftTestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to **/*.swift : Never commit API keys or customer data; use obvious placeholders (e.g., YOUR_STREAM_KEY) in example code
Applied to files:
StreamChat.xcodeproj/project.pbxproj
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Prioritize backwards compatibility and API stability when changing code in the Stream iOS Chat SDK
Applied to files:
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: For UI changes in StreamChatUI, attach comparison screenshots (before/after) in pull requests where feasible
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Prefer additive changes and avoid breaking public APIs in StreamChat and StreamChatUI
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
🧬 Code graph analysis (13)
StreamChatUITestsAppUITests/Tests/Attachments_Tests.swift (4)
StreamChatUITestsAppUITests/Robots/UserRobot.swift (2)
login(20-24)openChannel(53-58)TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift (1)
uploadAttachment(191-195)TestTools/StreamChatTestTools/TestData/DummyData/MessageAttachmentPayload.swift (1)
file(72-86)StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (1)
assertFile(1127-1141)
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (1)
TestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swift (1)
postRequest(34-63)
StreamChatUITestsAppUITests/Tests/SlowMode_Tests.swift (1)
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (1)
generateChannels(15-46)
StreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swift (3)
StreamChatUITestsAppUITests/Robots/UserRobot.swift (1)
uploadGiphy(381-393)TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift (1)
uploadGiphy(149-153)TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (1)
generateChannels(15-46)
StreamChatUITestsAppUITests/Pages/MessageListPage.swift (1)
StreamChatUITestsAppUITests/Pages/ChannelListPage.swift (1)
statusCheckmark(58-67)
StreamChatUITestsAppUITests/Pages/ChannelListPage.swift (1)
StreamChatUITestsAppUITests/Pages/MessageListPage.swift (1)
statusCheckmark(211-220)
StreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swift (3)
StreamChatUITestsAppUITests/Tests/Backend/Backend_Tests.swift (1)
setUpWithError(8-12)StreamChatUITestsAppUITests/Tests/Performance/ChannelListScrollTime.swift (1)
setUpWithError(9-13)TestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swift (1)
setEnvironmentVariables(40-44)
StreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift (4)
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (2)
delayNewMessages(54-58)generateChannels(15-46)TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift (2)
readMessage(47-51)sendMessageInThread(100-108)StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (2)
assertMessageDeliveryStatus(567-577)assertMessageReadCount(579-595)StreamChatUITestsAppUITests/Robots/UserRobot.swift (5)
removeParticipant(513-519)sendMessageInThread(281-305)login(20-24)setConnectivity(545-550)openChannel(53-58)
StreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swift (3)
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (1)
delayNewMessages(54-58)TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift (2)
readMessage(47-51)sendMessageInThread(100-108)StreamChatUITestsAppUITests/Robots/UserRobot.swift (1)
sendMessageInThread(281-305)
StreamChatUITestsAppUITests/Robots/UserRobot.swift (4)
TestTools/StreamChatTestTools/Extensions/EndpoinPath+Equatable.swift (1)
_(9-53)Sources/StreamChat/Controllers/MessageController/MessageController.swift (2)
addReaction(720-742)deleteReaction(748-757)Sources/StreamChat/Workers/MessageUpdater.swift (4)
addReaction(583-629)addReaction(1169-1191)deleteReaction(636-660)deleteReaction(1257-1263)StreamChatUITestsAppUITests/Pages/MessageListPage.swift (3)
threadReplyCountButton(171-173)text(183-185)text(191-193)
StreamChatUITestsAppUITests/Tests/MessageList_Tests.swift (4)
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (1)
generateChannels(15-46)StreamChatUITestsAppUITests/Robots/UserRobot.swift (8)
sendMessage(94-112)sleep(67-72)scrollMessageListUpSlow(358-364)mentionParticipant(480-490)sendMessageInThread(281-305)openThread(224-237)uploadGiphy(381-393)deleteMessage(121-128)TestTools/StreamChatTestTools/Mocks/StreamChat/Workers/TypingEventsSender_Mock.swift (2)
startTyping(34-39)stopTyping(41-47)StreamChatUITestsAppUITests/Pages/ChannelListPage.swift (1)
name(38-40)
StreamChatUITestsAppUITests/Tests/Authentication_Tests.swift (3)
TestTools/StreamChatTestMockServer/Robots/BackendRobot.swift (5)
invalidateToken(65-68)invalidateTokenDate(70-73)invalidateTokenSignature(75-78)revokeToken(60-63)breakTokenGeneration(80-83)StreamChatUITestsAppUITests/Robots/UserRobot.swift (1)
login(20-24)StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (1)
assertConnectionStatus(173-183)
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (3)
StreamChatUITestsAppUITests/Pages/ChannelListPage.swift (1)
lastMessage(46-48)StreamChatUITestsAppUITests/Pages/MessageListPage.swift (4)
text(183-185)text(191-193)title(291-293)threadReplyCountButton(171-173)Sources/StreamChat/Models/ChatMessage.swift (1)
deliveryStatus(563-586)
🔇 Additional comments (61)
StreamChatUITestsAppUITests/Tests/Backend/Backend_Tests.swift (1)
9-9: LGTM: Property rename aligns with new mock server infrastructure.The change from
mockServerEnabledtouseMockServeris consistent with the broader refactoring to use the new cross-platform mock server. Disabling the mock server for backend integration tests is appropriate.fastlane/Fastfile (5)
22-22: LGTM! Port constant properly defined.The mock server driver port is clearly defined and consistently used throughout the mock server lifecycle lanes.
29-29: LGTM! Exclusion list updated correctly.The removal of
sync_mock_serverfrom the exclusion list is consistent with the migration away from Sinatra-based flows.
34-34: LGTM! Cleanup logic updated for new mock server.The migration from
stop_sinatratostop_mock_serveris correct and maintains proper cleanup after e2e mock tests.
375-381: LGTM! Cleanup with appropriate error handling.The stop lane correctly sends a stop request to the driver and gracefully handles errors. Silent error swallowing is acceptable here since this is a best-effort cleanup operation.
586-586: LGTM! E2E mock tests updated to use new server.The migration from
start_sinatratostart_mock_serveris correct and completes the transition to the driver-based mock server infrastructure.StreamChatUITestsApp/ViewController.swift (1)
213-214: Verify the new mock server endpoint supports the updated JWT request format.The JWT endpoint has been migrated from the previous format to
/jwt/get?platform=ios. Since the mock server implementation is external to this repository (as part of PR #3895's cross-platform mock server), confirm that the external mock server implementation includes this endpoint and returns JWT tokens in the format expected by the client.StreamChatUITestsAppUITests/Tests/SlowMode_Tests.swift (1)
131-131: LGTM! API parameter name updated correctly.The parameter name change from
counttochannelsCountaligns with the BackendRobot API update shown in the relevant code snippets, making the intent more explicit.TestTools/StreamChatTestMockServer/MockServer/LaunchArgument.swift (1)
37-37: LGTM! Improved Swift idiom.Using key path syntax (
\.rawValue) instead of a closure is more concise and idiomatic in modern Swift.StreamChatUITestsAppUITests/Tests/PushNotification_Tests.swift (3)
22-78: LGTM! Well-structured test simplification.The refactoring to use the
checkHappyPathhelper method reduces code duplication and improves test maintainability. Each test clearly expresses its intent through the helper's parameters.
143-171: LGTM! Well-designed helper method.The
checkHappyPathhelper method is well-refactored with:
- Clear, parameterized interface with sensible defaults
- Proper handling of optional
titleparameter- Clean conditional logic for assertions
This design reduces duplication across tests while maintaining flexibility.
8-14: Add documentation explaining the iOS 17 minimum requirement.The iOS 17 version check significantly reduces E2E test coverage (excluding iOS 14, 15, 16) but lacks explanation in the code. Unit tests for push notification functionality don't require iOS 17.
Please add a comment clarifying:
- Is iOS 17+ required due to push notification API changes or testing framework limitations?
- Are iOS 14-16 behaviors sufficiently covered by the unit tests (snoozePushNotifications, handleNotification, etc.)?
StreamChat.xcodeproj/project.pbxproj (1)
585-586: LGTM!The project file changes correctly integrate the new
DataTypes.swiftandLaunchArgument.swiftfiles into the MockServer group:
- UUID references are consistent across PBXBuildFile, PBXFileReference, PBXGroup, and PBXSourcesBuildPhase sections.
- Files are properly added to the StreamChatTestMockServer target's sources build phase.
Also applies to: 3593-3594, 6200-6201, 12353-12355
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (8)
6-6: LGTM on the import change.The import switch to
@testable import StreamChatCommonUIaligns with the mock server migration. This provides access to the necessary test infrastructure types.
38-56: LGTM on the new empty channel preview assertion.Clean implementation following the existing pattern with proper file/line forwarding for debugging.
94-110: Type migration looks good.The delivery status parameter now uses the fully-qualified
StreamChatTestMockServer.MessageDeliveryStatus?type, consistent with the mock server refactor across the test suite.
248-277: Push notification assertion signature updated correctly.The rename from
text/sendertotitle/bodybetter reflects the actual push notification structure. The assertion logic remains sound.
551-565: Consistent type migration for delivery status assertions.All delivery status methods now use
StreamChatTestMockServer.MessageDeliveryStatus?, maintaining consistency with the new mock server types.Also applies to: 567-577, 879-888
711-718: Good refactor to parameterize the user name.Removing the hardcoded user name and accepting it as a parameter improves test flexibility and reusability.
956-959: Improved thread reply count pluralization.The ternary for singular/plural ("1 Thread Reply" vs "N Thread Replies") is a nice UX improvement for test assertions.
1059-1064: Verify error message matches mock server implementation.The error message
"Sorry, command \(invalidCommand) doesn't exist. Try posting your message without the starting /"is hardcoded in the test assertion, but the mock server implementation that generates this response is not accessible in the repository. Manual verification against the actual mock server or its documentation is required to confirm this string matches the backend response exactly.StreamChatUITestsAppUITests/Tests/Performance/ChannelListScrollTime.swift (1)
9-13: LGTM on the property rename.The change from
mockServerEnabledtouseMockServeraligns with the test infrastructure refactor. Setting it tofalseis correct for performance tests that need the real backend.StreamChatUITestsAppUITests/Tests/Performance/MessageListScrollTime.swift (1)
10-14: LGTM on the API migration.The
generateChannelscall correctly uses the new parameter labels (channelsCount:,attachments:) matching the updatedBackendRobotsignature shown in the relevant code snippets.StreamChatUITestsAppUITests/Pages/ChannelListPage.swift (1)
58-67: LGTM on the type migration.The
statusCheckmarkfunction now acceptsStreamChatTestMockServer.MessageDeliveryStatus?, consistent with the parallel implementation inMessageListPage.swift. The logic remains unchanged.StreamChatUITestsAppUITests/Tests/Attachments_Tests.swift (2)
7-7: Historical note preserved.The comment about attachment tests freezing on iOS > 18 is useful context for future debugging.
50-63: LGTM on the new file upload test.The test follows the established pattern from
test_participantUploadsImageandtest_participantUploadsVideo. It correctly usesAttachmentType.filefrom the new mock server types and leverages the existingassertFilehelper.TestTools/StreamChatTestMockServer/MockServer/DataTypes.swift (2)
7-15: LGTM on AttachmentType enum.Clear and well-structured enum for test attachment types.
17-27: LGTM on ReactionType enum.The
lol = "haha"mapping is a nice touch to align with backend expectations while keeping a readable case name.StreamChatUITestsAppUITests/Pages/MessageListPage.swift (1)
211-220: LGTM on the type migration.The
statusCheckmarkfunction update is consistent withChannelListPage.swift. Both use the fully-qualifiedStreamChatTestMockServer.MessageDeliveryStatus?type with identical logic.StreamChatUITestsAppUITests/Tests/ChannelList_Tests.swift (4)
60-60: LGTM - parameter rename improves clarity.The parameter rename from
count:tochannelsCount:makes the API more explicit and self-documenting.
186-186: LGTM - method rename aligns with new API.The rename from
replyToMessageInThreadtosendMessageInThreadis consistent with the mock server migration and maintains the same functionality.
237-237: LGTM - consistent API usage.The
generateChannelsparameter update is consistent with the broader migration to the new mock server API.
261-286: Good test coverage for channel truncation without message.The new test case properly validates the edge case where a channel is truncated without a system message, ensuring both the message list and channel preview reflect the empty state correctly.
StreamChatUITestsAppUITests/Tests/Ephemeral_Messages_Tests.swift (3)
8-8: LGTM - helpful historical context.The NOTE comment documents a previously problematic behavior, providing useful context for future developers.
18-18: LGTM - uploadGiphy naming is more accurate.The rename from
sendGiphytouploadGiphybetter reflects the two-step process (upload then optionally send) and aligns with the new mock server API.Also applies to: 34-34, 79-79, 98-98, 117-117, 136-136
111-111: LGTM - consistent parameter naming.The parameter rename is consistent with the mock server API migration.
StreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift (5)
45-45: LGTM - improved API naming and signature.The rename from
delayServerResponse(byTimeInterval:)todelayNewMessages(by:)is more explicit about what's being delayed, and using integer seconds simplifies the API.Also applies to: 515-515
87-87: LGTM - simplified API removes timing concerns from test code.The rename from
readMessageAfterDelay()toreadMessage()simplifies the test API by moving delay handling to the mock server implementation.Also applies to: 109-109, 137-137, 267-267, 338-338, 388-388, 561-561, 583-583, 608-608
291-291: LGTM - consistent method rename.The rename from
replyToMessageInThreadtosendMessageInThreadis consistent with the mock server migration across all test files.Also applies to: 311-311, 335-335, 360-360, 385-385, 414-414, 442-442
143-143: LGTM - cleaner participant reference.Using
participantRobot.iddirectly eliminates the need for local variables and keeps the participant state centralized.Also applies to: 394-394, 611-611
304-304: LGTM - consistent parameter naming.The parameter rename is consistent with the mock server API migration.
StreamChatUITestsAppUITests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swift (3)
24-24: LGTM - consistent with mock server migration.The API changes in this file are consistent with the broader migration to the new mock server infrastructure.
97-97: LGTM - simplified read API.The change from
readMessageAfterDelay()toreadMessage()is consistent with the mock server migration.Also applies to: 222-222
166-166: LGTM - consistent thread message API.The rename from
replyToMessageInThreadtosendMessageInThreadis consistent with the mock server migration.Also applies to: 194-194, 219-219, 250-250, 275-275
StreamChatUITestsAppUITests/Tests/Authentication_Tests.swift (3)
13-101: Excellent test coverage for token invalidation scenarios.The six new test cases comprehensively cover token invalidation edge cases (generic, date, and signature invalidation) both before and after login. The tests follow the BDD pattern consistently and properly verify that the app successfully refreshes the token in each scenario.
107-107: LGTM - consistent API migration.The change from
server.revokeJwt()tobackendRobot.revokeToken()aligns with the mock server migration.
181-181: LGTM - improved API naming.The rename from
server.breakJwt()tobackendRobot.breakTokenGeneration()is more descriptive and aligns with the mock server migration.StreamChatUITestsAppUITests/Tests/QuotedReply_Tests.swift (1)
1-802: LGTM!The test file consistently migrates to the new mock server API surface:
generateChannels(count:)→generateChannels(channelsCount:)quoteMessage(..., toLastMessage:)→quoteMessage(..., last:)- Thread-specific helpers renamed appropriately (
quoteMessageInThread,quoteMessageWithAttachmentInThread, etc.)All test assertions remain logically correct after the API changes.
StreamChatUITestsAppUITests/Tests/MessageList_Tests.swift (1)
1-1061: LGTM!The test file correctly migrates to the new mock server APIs:
generateChannels(channelsCount:, messagesCount:, repliesCount:)signatureparticipantRobot.sendMessageInThread()replacesreplyToMessageInThread()participantRobot.startTyping()/stopTyping()for typing indicatorsuserRobot.mentionParticipant(participantRobot.id)with explicit userIdmockServer.forbiddenWordfor moderation testinguploadGiphy()replacessendGiphy()All test logic remains correct after the API changes.
StreamChatUITestsAppUITests/Robots/UserRobot.swift (5)
154-197: LGTM!The reaction handling is correctly updated to use
ReactionTypeenum instead ofTestData.Reactions. The switch statement handles all expected cases with a sensible default fallback to.like.
223-237: LGTM!The
openThreadmethod properly handles the newwaitForThreadIconparameter with conditional waiting behavior. The existence check and fallback to context menu is preserved.
282-305: LGTM!
sendMessageInThreadcorrectly implements thread reply functionality with thealsoSendInChannelcheckbox handling and delegates to the existingsendMessageimplementation.
382-416: LGTM!The rename from
sendGiphytouploadGiphyis consistently applied, and thereplyWithGiphyandreplyWithGiphyInThreadmethods correctly call the renamed method.
481-490: LGTM!
mentionParticipantnow correctly accepts auserIdparameter and constructs the mention text from it, enabling explicit control over which participant to mention.TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift (2)
7-62: LGTM!The
ParticipantRobotclass is cleanly structured with:
- Clear public API surface (
name,id, initializer)- Consistent endpoint-based interactions via
mockServer.postRequest()- Fluent API pattern with
@discardableResultreturns
100-247: LGTM!The threading, quoting, attachment, and reaction methods are well-organized with consistent patterns:
- Thread operations use
thread=truequery param- Quote operations use
quote_last=true/quote_first=true- Attachment operations use the
AttachmentType.attachmentproperty- Reaction operations use the
ReactionType.reactionpropertyStreamChatUITestsAppUITests/Tests/Base TestCase/StreamTestCase.swift (3)
14-15: LGTM: Clean test setup flags.The rename to
mockServerand the newuseMockServerflag provide clear control over test execution mode. The default oftruealigns with the PR objective to use the new mock server by default.
34-34: LGTM: Proper mock server cleanup.The teardown correctly stops the mock server after terminating the app, ensuring resources are released in the proper order.
22-28: The port "4566" is intentionally hardcoded as a shared port allocation driver, not as the mock server port itself. The StreamMockServer architecture dynamically allocates unique mock server ports per test (via thetestNameparameter), which already supports parallel test execution. No changes are needed—the current design properly handles concurrent test runs..github/workflows/cron-checks.yml (1)
83-83: Artifact path updated consistently across workflows.The log path change matches the update in
smoke-checks.ymland correctly reflects the migration to the new mock server infrastructure..github/workflows/smoke-checks.yml (1)
225-225: Artifact path correctly configured for mock server logs.The path change from
fastlane/sinatra_log.txttofastlane/stream-chat-test-mock-server/logs/*is verified. The mock server'sstart_mock_serverfastlane lane explicitly creates thelogsdirectory viaFileUtils.mkdir_p('logs')and writes the driver log tologs/driver.log, making the wildcard pattern appropriate for capturing all generated logs. The path is consistently applied across both smoke-checks.yml and cron-checks.yml workflows.
| lane :start_mock_server do |options| | ||
| mock_server_repo = 'stream-chat-test-mock-server' | ||
| stop_mock_server if is_localhost | ||
|
|
||
| if options[:local_server] | ||
| mock_server_repo = options[:local_server] | ||
| else | ||
| branch = options[:branch].to_s.empty? ? 'main' : options[:branch] | ||
| sh("rm -rf #{mock_server_repo}") if File.directory?(mock_server_repo) | ||
| sh("git clone -b #{branch} https://github.com/#{github_repo.split('/').first}/#{mock_server_repo}.git") | ||
| end | ||
|
|
||
| pids = sh("lsof -ti :#{mock_server_driver_port} || true", log: false).strip | ||
| sh("kill -9 #{pids} || true", log: false) unless pids.empty? | ||
|
|
||
| Dir.chdir(mock_server_repo) do | ||
| FileUtils.mkdir_p('logs') | ||
| sh("bundle exec ruby driver.rb #{mock_server_driver_port} > logs/driver.log 2>&1 &") | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add health check after starting the mock server.
The mock server is started in the background without verifying it's ready to accept connections. This could cause race conditions where tests begin before the server is fully initialized, leading to flaky test failures.
🔧 Suggested improvement
Add a health check loop after starting the server:
Dir.chdir(mock_server_repo) do
FileUtils.mkdir_p('logs')
sh("bundle exec ruby driver.rb #{mock_server_driver_port} > logs/driver.log 2>&1 &")
+
+ # Wait for server to be ready
+ max_attempts = 30
+ attempt = 0
+ server_ready = false
+
+ until server_ready || attempt >= max_attempts
+ begin
+ Net::HTTP.get_response(URI("http://localhost:#{mock_server_driver_port}/health"))
+ server_ready = true
+ UI.success("Mock server is ready on port #{mock_server_driver_port}")
+ rescue StandardError
+ attempt += 1
+ sleep(1)
+ end
+ end
+
+ UI.user_error!("Mock server failed to start within #{max_attempts} seconds") unless server_ready
endNote: This assumes the driver exposes a /health endpoint. Adjust the endpoint path based on your actual implementation.
Committable suggestion skipped: line range outside the PR's diff.
| override func setUpWithError() throws { | ||
| mockServerEnabled = false | ||
| useMockServer = false | ||
| switchApiKey = "8br4watad788" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
rg -n "8br4watad788" --type swiftRepository: GetStream/stream-chat-swift
Length of output: 369
🏁 Script executed:
# Check context around the DemoUsers.swift entry
rg -B 2 -A 2 "8br4watad788" demoapp --type swift
# Also search for comments about demo/test keys
rg -i "demo.*key|test.*key|apikey" DemoApp/Shared/DemoUsers.swift --type swift | head -20Repository: GetStream/stream-chat-swift
Length of output: 1208
This is a demo/test API key, but replace with an obvious placeholder per guidelines.
Confirmed: "8br4watad788" is a dedicated demo key (labeled "UIKit default" in DemoApiKeys). However, the coding guidelines require using obvious placeholders like YOUR_STREAM_KEY in test and example code, even for demo credentials. Update to use a placeholder instead.
🤖 Prompt for AI Agents
In @StreamChatUITestsAppUITests/Tests/Backend/Backend_Tests.swift at line 10,
Replace the hard-coded demo API key assigned to switchApiKey ("8br4watad788")
with an obvious placeholder string (e.g., "YOUR_STREAM_KEY") so test/example
code does not contain real/demo credentials; update the assignment to set
switchApiKey to the placeholder and leave a comment if needed to indicate where
to obtain a real key for testing.
| @discardableResult | ||
| public func postRequest( | ||
| baseUrl: String = url!, | ||
| endpoint: String, | ||
| body: Data = Data(), | ||
| async: Bool = false | ||
| ) -> (body: String, statusCode: Int) { | ||
| let url = URL(string: "\(baseUrl)/\(endpoint)")! | ||
| var request = URLRequest(url: url) | ||
| request.httpMethod = "POST" | ||
| request.httpBody = body | ||
| request.setValue("text/plain", forHTTPHeaderField: "Content-Type") | ||
| nonisolated(unsafe) var output = "" | ||
| nonisolated(unsafe) var statusCode = 0 | ||
|
|
||
| let semaphore: DispatchSemaphore? = async ? nil : DispatchSemaphore(value: 0) | ||
| let task = URLSession.shared.dataTask(with: request) { data, response, _ in | ||
| if let httpResponse = response as? HTTPURLResponse { | ||
| statusCode = httpResponse.statusCode | ||
| } | ||
| if let data = data, let string = String(data: data, encoding: .utf8) { | ||
| output = string | ||
| } | ||
| semaphore?.signal() | ||
| } | ||
| return newChannelList.first | ||
| } | ||
| } | ||
|
|
||
| // MARK: Config | ||
| task.resume() | ||
| semaphore?.wait() | ||
|
|
||
| public extension StreamMockServer { | ||
| func config(forChannelId id: String) -> ChannelConfig_Mock? { | ||
| channelConfigs.config(forChannelId: id, server: self) | ||
| return (output, statusCode) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Force-unwrap in default parameter value is unsafe.
The default value baseUrl: String = url! will crash at call-time if url is nil. Consider making it optional or using a guard inside the method.
🐛 Suggested fix
@discardableResult
public func postRequest(
- baseUrl: String = url!,
+ baseUrl: String? = nil,
endpoint: String,
body: Data = Data(),
async: Bool = false
) -> (body: String, statusCode: Int) {
+ guard let resolvedUrl = baseUrl ?? StreamMockServer.url else {
+ XCTFail("Mock server URL is not configured")
+ return ("", 0)
+ }
- let url = URL(string: "\(baseUrl)/\(endpoint)")!
+ let url = URL(string: "\(resolvedUrl)/\(endpoint)")!📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @discardableResult | |
| public func postRequest( | |
| baseUrl: String = url!, | |
| endpoint: String, | |
| body: Data = Data(), | |
| async: Bool = false | |
| ) -> (body: String, statusCode: Int) { | |
| let url = URL(string: "\(baseUrl)/\(endpoint)")! | |
| var request = URLRequest(url: url) | |
| request.httpMethod = "POST" | |
| request.httpBody = body | |
| request.setValue("text/plain", forHTTPHeaderField: "Content-Type") | |
| nonisolated(unsafe) var output = "" | |
| nonisolated(unsafe) var statusCode = 0 | |
| let semaphore: DispatchSemaphore? = async ? nil : DispatchSemaphore(value: 0) | |
| let task = URLSession.shared.dataTask(with: request) { data, response, _ in | |
| if let httpResponse = response as? HTTPURLResponse { | |
| statusCode = httpResponse.statusCode | |
| } | |
| if let data = data, let string = String(data: data, encoding: .utf8) { | |
| output = string | |
| } | |
| semaphore?.signal() | |
| } | |
| return newChannelList.first | |
| } | |
| } | |
| // MARK: Config | |
| task.resume() | |
| semaphore?.wait() | |
| public extension StreamMockServer { | |
| func config(forChannelId id: String) -> ChannelConfig_Mock? { | |
| channelConfigs.config(forChannelId: id, server: self) | |
| return (output, statusCode) | |
| } | |
| @discardableResult | |
| public func postRequest( | |
| baseUrl: String? = nil, | |
| endpoint: String, | |
| body: Data = Data(), | |
| async: Bool = false | |
| ) -> (body: String, statusCode: Int) { | |
| guard let resolvedUrl = baseUrl ?? StreamMockServer.url else { | |
| XCTFail("Mock server URL is not configured") | |
| return ("", 0) | |
| } | |
| let url = URL(string: "\(resolvedUrl)/\(endpoint)")! | |
| var request = URLRequest(url: url) | |
| request.httpMethod = "POST" | |
| request.httpBody = body | |
| request.setValue("text/plain", forHTTPHeaderField: "Content-Type") | |
| nonisolated(unsafe) var output = "" | |
| nonisolated(unsafe) var statusCode = 0 | |
| let semaphore: DispatchSemaphore? = async ? nil : DispatchSemaphore(value: 0) | |
| let task = URLSession.shared.dataTask(with: request) { data, response, _ in | |
| if let httpResponse = response as? HTTPURLResponse { | |
| statusCode = httpResponse.statusCode | |
| } | |
| if let data = data, let string = String(data: data, encoding: .utf8) { | |
| output = string | |
| } | |
| semaphore?.signal() | |
| } | |
| task.resume() | |
| semaphore?.wait() | |
| return (output, statusCode) | |
| } |
🤖 Prompt for AI Agents
In @TestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swift around
lines 34 - 63, The postRequest function currently force-unwraps the shared
property url via the default parameter baseUrl: String = url!, which can crash
if url is nil; change the signature to accept an optional baseUrl (e.g.,
baseUrl: String? = nil) and inside postRequest resolve a non-optional base using
let base = baseUrl ?? url and guard that base is non-nil (or return an explicit
error/status), then build the request with that safe base; remove the
force-unwrap and ensure you handle the missing-base case deterministically
before creating the URL and request.
| @discardableResult | ||
| public func getRequest( | ||
| baseUrl: String = url!, | ||
| endpoint: String, | ||
| async: Bool = false | ||
| ) -> (body: String, statusCode: Int) { | ||
| let url = URL(string: "\(baseUrl)/\(endpoint)")! | ||
| var request = URLRequest(url: url) | ||
| request.httpMethod = "GET" | ||
| nonisolated(unsafe) var output = "" | ||
| nonisolated(unsafe) var statusCode = 0 | ||
|
|
||
| let semaphore: DispatchSemaphore? = async ? nil : DispatchSemaphore(value: 0) | ||
| let task = URLSession.shared.dataTask(with: request) { data, response, _ in | ||
| if let httpResponse = response as? HTTPURLResponse { | ||
| statusCode = httpResponse.statusCode | ||
| } | ||
| if let data = data, let string = String(data: data, encoding: .utf8) { | ||
| output = string | ||
| } | ||
| semaphore?.signal() | ||
| } | ||
| task.resume() | ||
| semaphore?.wait() | ||
|
|
||
| setCooldown(in: &innerChannel) | ||
| channel[JSONKey.channel] = innerChannel | ||
| channels[channelIndex] = channel | ||
| json[JSONKey.channels] = channels | ||
| channelList = json | ||
| } | ||
|
|
||
| func setCooldown(in channel: inout [String: Any]) { | ||
| let cooldown = channelConfigs.coolDown | ||
| if cooldown.isEnabled { | ||
| channel[channelKey.cooldownDuration.rawValue] = cooldown.duration | ||
| var ownCapabilities = channel[channelKey.ownCapabilities.rawValue] as? [String] | ||
| ownCapabilities?.removeAll { $0 == ChannelCapability.skipSlowMode.rawValue } | ||
| channel[channelKey.ownCapabilities.rawValue] = ownCapabilities | ||
| } else { | ||
| channel[channelKey.cooldownDuration.rawValue] = nil | ||
| } | ||
| return (output, statusCode) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same force-unwrap issue in getRequest default parameter.
Apply the same fix as postRequest to avoid crashes when url is nil.
🤖 Prompt for AI Agents
In @TestTools/StreamChatTestMockServer/MockServer/StreamMockServer.swift around
lines 65 - 91, getRequest currently force-unwraps url in its default parameter
(baseUrl: String = url!), which can crash if url is nil; mirror the postRequest
fix: make baseUrl optional (e.g., baseUrl: String? = nil), then inside
getRequest resolve a safe base string by using the provided baseUrl or falling
back to the instance url only after safely unwrapping it (or return an early
default result when neither is present), and use that safe base value to
construct the URL for the request.
| @discardableResult | ||
| public func sendMessage( | ||
| _ text: String, | ||
| withPushNotification: Bool = false, | ||
| bundleIdForPushNotification: String = "", | ||
| waitForAppearance: Bool = true, | ||
| waitForChannelQuery: Bool = true, | ||
| waitBeforeSending: TimeInterval = 0, | ||
| file: StaticString = #filePath, | ||
| line: UInt = #line | ||
| ) -> Self { | ||
| if waitBeforeSending > 0 { | ||
| wait(waitBeforeSending) | ||
| public func sendPushNotification( | ||
| title: String?, | ||
| body: String, | ||
| bundleId: String, | ||
| rest: String? = nil | ||
| ) -> ParticipantRobot { | ||
| let udid = ProcessInfo.processInfo.environment["SIMULATOR_UDID"]! | ||
| var endpoint = "participant/push?" + | ||
| "bundle_id=\(bundleId)&" + | ||
| "udid=\(udid)&" + | ||
| "body=\(body)" | ||
| if let title { | ||
| endpoint += "&title=\(title)" | ||
| } | ||
|
|
||
| if waitForChannelQuery { | ||
| server.waitForChannelQueryUpdate() | ||
| } | ||
|
|
||
| startTyping() | ||
| stopTyping() | ||
|
|
||
| let messageId = TestData.uniqueId | ||
|
|
||
| server.websocketMessage( | ||
| text, | ||
| channelId: server.currentChannelId, | ||
| messageId: messageId, | ||
| eventType: .messageNew, | ||
| user: participant() | ||
| ) | ||
|
|
||
| if waitForAppearance { | ||
| server.waitForWebsocketMessage(withText: text) | ||
| } | ||
|
|
||
| if withPushNotification { | ||
| if let senderName = participant()?["name"] as? String { | ||
| server.pushNotification( | ||
| senderName: senderName, | ||
| text: text, | ||
| messageId: messageId, | ||
| cid: "\(ChannelType.messaging.rawValue):\(server.currentChannelId)", | ||
| targetBundleId: bundleIdForPushNotification | ||
| ) | ||
| } | ||
| if let rest { | ||
| endpoint += "&rest=\(rest)" | ||
| } | ||
| _ = mockServer.postRequest(endpoint: endpoint) | ||
| return self | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Force-unwrap on SIMULATOR_UDID environment variable.
Line 71 uses force-unwrap on SIMULATOR_UDID which will crash if run outside a simulator environment. Consider adding a guard with a meaningful error.
🐛 Suggested fix
public func sendPushNotification(
title: String?,
body: String,
bundleId: String,
rest: String? = nil
) -> ParticipantRobot {
- let udid = ProcessInfo.processInfo.environment["SIMULATOR_UDID"]!
+ guard let udid = ProcessInfo.processInfo.environment["SIMULATOR_UDID"] else {
+ assertionFailure("SIMULATOR_UDID environment variable not found - must run on simulator")
+ return self
+ }
var endpoint = "participant/push?" +🤖 Prompt for AI Agents
In @TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift around
lines 64 - 84, The code force-unwraps
ProcessInfo.processInfo.environment["SIMULATOR_UDID"] inside
ParticipantRobot.sendPushNotification which will crash outside a simulator;
replace the forced unwrap with a guard let udid =
ProcessInfo.processInfo.environment["SIMULATOR_UDID"] else {
fatalError("SIMULATOR_UDID not set: sendPushNotification requires a simulator
UDID") } (or preconditionFailure/log + return self if you prefer non-fatal
behavior) before building the endpoint and calling mockServer.postRequest so the
failure is reported with a clear message instead of an unexpected crash.
| @discardableResult | ||
| public func replyWithGiphy(toLastMessage: Bool = true) -> Self { | ||
| startTyping() | ||
| stopTyping() | ||
|
|
||
| let quotedMessage = toLastMessage ? server.lastMessage : server.firstMessage | ||
| let quotedMessageId = quotedMessage?[messageKey.id.rawValue] as? String | ||
| server.websocketMessage( | ||
| channelId: server.currentChannelId, | ||
| messageId: TestData.uniqueId, | ||
| messageType: .ephemeral, | ||
| eventType: .messageNew, | ||
| user: participant() | ||
| ) { message in | ||
| message?[messageKey.quotedMessageId.rawValue] = quotedMessageId | ||
| message?[messageKey.quotedMessage.rawValue] = quotedMessage | ||
| return message | ||
| } | ||
| public func pinMesage() -> ParticipantRobot { | ||
| _ = mockServer.postRequest(endpoint: "participant/message?action=pin") | ||
| return self | ||
| } | ||
|
|
||
| @discardableResult | ||
| public func replyWithGiphyInThread(toLastMessage: Bool = true, alsoSendInChannel: Bool = false) -> Self { | ||
| startTypingInThread() | ||
| stopTypingInThread() | ||
|
|
||
| let quotedMessage = toLastMessage ? server.lastMessageInThread : server.firstMessageInThread | ||
| let quotedMessageId = quotedMessage?[messageKey.id.rawValue] as? String | ||
| let parentId = threadParentId ?? (server.lastMessage?[messageKey.id.rawValue] as? String) | ||
| server.websocketMessage( | ||
| channelId: server.currentChannelId, | ||
| messageId: TestData.uniqueId, | ||
| parentId: parentId, | ||
| messageType: .ephemeral, | ||
| eventType: .messageNew, | ||
| user: participant() | ||
| ) { message in | ||
| message?[messageKey.parentId.rawValue] = parentId | ||
| message?[messageKey.showReplyInChannel.rawValue] = alsoSendInChannel | ||
| message?[messageKey.quotedMessageId.rawValue] = quotedMessageId | ||
| message?[messageKey.quotedMessage.rawValue] = quotedMessage | ||
| return message | ||
| } | ||
| public func unpinMesage() -> ParticipantRobot { | ||
| _ = mockServer.postRequest(endpoint: "participant/message?action=unpin") | ||
| return self | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in method names: pinMesage and unpinMesage.
The method names are missing an 's' — should be pinMessage and unpinMessage.
🐛 Proposed fix
@discardableResult
-public func pinMesage() -> ParticipantRobot {
+public func pinMessage() -> ParticipantRobot {
_ = mockServer.postRequest(endpoint: "participant/message?action=pin")
return self
}
@discardableResult
-public func unpinMesage() -> ParticipantRobot {
+public func unpinMessage() -> ParticipantRobot {
_ = mockServer.postRequest(endpoint: "participant/message?action=unpin")
return self
}🤖 Prompt for AI Agents
In @TestTools/StreamChatTestMockServer/Robots/ParticipantRobot.swift around
lines 179 - 189, Two methods are misspelled: rename pinMesage to pinMessage and
unpinMesage to unpinMessage in ParticipantRobot so the API is clear; update the
method declarations (preserve @discardableResult, return type ParticipantRobot
and the existing mockServer.postRequest(endpoint: "...") calls) and then update
any callers/tests to use the new names; keep the endpoint strings
("participant/message?action=pin" and "...?action=unpin") unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (1)
942-960: Use the localization constant instead of hardcoded English strings.Line 957 hardcodes the pluralization logic ("1 Thread Reply" vs "N Thread Replies"). While these strings currently match the English localization, the test should use the same localization method as the UI does:
Suggested fix
let expectedText = L10n.Message.Threads.count(replies)This ensures the test stays in sync with the localization strings defined in
Localizable.stringsdictand matches the approach used inChatMessageContentView.swiftline 710.
🤖 Fix all issues with AI agents
In @StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift:
- Around line 347-359: In assertFirstMessageIsVisible, guard that cells.count >
0 before computing let messageCell = messageCell(withIndex: cells.count - 1); if
count is 0 call XCTFail with a clear message (include file and line) and return
self to fail fast; this prevents passing -1 into messageCell(withIndex:) and
avoids undefined behavior when accessing cells.element(boundBy:).
🧹 Nitpick comments (1)
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (1)
249-277: Consider more specific assertions for push notification content.The current implementation uses
containschecks for both title and body. This could lead to false positives if there's overlap between the expected title and body strings (e.g., if title is a substring of body or vice versa).♻️ Optional refinement for more precise validation
If push notification structure allows, consider verifying that title and body appear in distinct UI elements:
let pushNotification = SpringBoard.notificationBanner.wait() XCTAssertTrue( pushNotification.exists, "Push notification should appear", file: file, line: line ) - -let pushNotificationContent = pushNotification.text -XCTAssertTrue( - pushNotificationContent.contains(body), - "\(pushNotificationContent) does not contain \(body)", - file: file, - line: line -) -XCTAssertTrue( - pushNotificationContent.contains(title), - "\(pushNotificationContent) does not contain \(title)", - file: file, - line: line -) + +// If SpringBoard exposes separate title/body elements, use those instead +let notificationTitle = pushNotification.staticTexts.matching(identifier: "NotificationTitle").firstMatch +let notificationBody = pushNotification.staticTexts.matching(identifier: "NotificationBody").firstMatch +XCTAssertEqual(notificationTitle.label, title, file: file, line: line) +XCTAssertEqual(notificationBody.label, body, file: file, line: line)Note: Only apply if SpringBoard notification banner exposes distinct elements for title and body.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
🧰 Additional context used
📓 Path-based instructions (1)
**/*.swift
📄 CodeRabbit inference engine (AGENTS.md)
**/*.swift: Write Swift code compatible with iOS deployment targets specified in Package.swift and podspec files; do not lower deployment targets without approval
Use SwiftLint with strict mode and respect .swiftlint.yml rules; justify and scope any exceptions rather than suppressing rules broadly
Run SwiftFormat for code formatting and respect repository-specific style conventions
Never commit API keys or customer data; use obvious placeholders (e.g., YOUR_STREAM_KEY) in example code
Follow the project's zero-warnings policy: fix new warnings and avoid introducing any
Files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Tests/**/*.swift : Add or extend tests in the matching module's Tests/ folder for changes to StreamChat or StreamChatUI code, covering core models, API surfaces, and view controller behaviors; use fakes/mocks from test helpers provided by the repo
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Maintain high test coverage when changing code in the Stream iOS Chat SDK
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Sources/StreamChat/**/*.swift : Ensure public API changes in StreamChat and StreamChatUI include inline documentation and migration notes
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Sources/StreamChatUI/**/*.swift : Ensure public API changes in StreamChatUI include inline documentation and migration notes
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Tests/**/*.swift : Add or extend tests in the matching module's Tests/ folder for changes to StreamChat or StreamChatUI code, covering core models, API surfaces, and view controller behaviors; use fakes/mocks from test helpers provided by the repo
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Sources/StreamChatUI/**/*.swift : Ensure public API changes in StreamChatUI include inline documentation and migration notes
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to Sources/StreamChat/**/*.swift : Ensure public API changes in StreamChat and StreamChatUI include inline documentation and migration notes
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Maintain high test coverage when changing code in the Stream iOS Chat SDK
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Applies to CHANGELOG* : Update CHANGELOG entries for user-visible SDK changes in StreamChat and StreamChatUI
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: For UI changes in StreamChatUI, attach comparison screenshots (before/after) in pull requests where feasible
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Prioritize backwards compatibility and API stability when changing code in the Stream iOS Chat SDK
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Prefer additive changes and avoid breaking public APIs in StreamChat and StreamChatUI
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
📚 Learning: 2025-11-25T12:17:18.459Z
Learnt from: CR
Repo: GetStream/stream-chat-swift PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T12:17:18.459Z
Learning: Mirror existing patterns in the nearest module when making changes to StreamChat or StreamChatUI
Applied to files:
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift
🔇 Additional comments (4)
StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift (4)
38-56: LGTM! New assertion follows existing patterns.The new
assertChannelPreviewIsEmptymethod correctly verifies that the channel preview displays "No messages".
712-718: LGTM! Parameterization improves test flexibility.Adding the
userNameparameter removes hardcoding and makes the assertion reusable across different test scenarios.
1053-1064: Hardcoded error message in test assertion lacks verification source.Line 1060 contains a hardcoded error message string used for test assertion. The exact message definition in the app code could not be located to verify whether this test string matches the actual implementation.
Consider:
- Locating where the app defines this error message and verifying the test string matches exactly
- If the message comes from a backend response or mock server, document that dependency
- If maintaining this message in multiple places, consider extracting to a shared constant or documenting the expected format
96-96: LGTM! Delivery status type migration is consistent.The migration from the old delivery status type to
StreamChatTestMockServer.MessageDeliveryStatus?is applied consistently across all relevant methods. The type is properly defined as a public enum inStreamChatTestMockServerand re-exported via@_exported importin the test setup, making it available across all test files.Also applies to: 553-553, 569-569, 881-881
|
|
||
| @discardableResult | ||
| func assertFirstMessageIsVisible( | ||
| _ text: String, | ||
| file: StaticString = #filePath, | ||
| line: UInt = #line | ||
| ) -> Self { | ||
| let messageCell = messageCell(withIndex: cells.count - 1, file: file, line: line) | ||
| let message = attributes.text(text, in: messageCell).wait() | ||
| let actualText = message.waitForText(text).text | ||
| XCTAssertEqual(text, actualText, file: file, line: line) | ||
| return self | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, find the messageCell(withIndex:) method to understand its bounds checking
rg -n "func messageCell\(" StreamChatUITestsAppUITests/Robots/ -A 10 --type swiftRepository: GetStream/stream-chat-swift
Length of output: 1153
🏁 Script executed:
# Check for cells.count - 1 patterns in the codebase
rg -n 'cells\.count\s*-\s*1' StreamChatUITestsAppUITests/ --type swift -C 2Repository: GetStream/stream-chat-swift
Length of output: 642
🏁 Script executed:
# Find the UserRobot+Asserts.swift file and check context around line 354
wc -l StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftRepository: GetStream/stream-chat-swift
Length of output: 134
🏁 Script executed:
# Get the full context of the assertFirstMessageIsVisible method and surrounding code
sed -n '340,365p' StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftRepository: GetStream/stream-chat-swift
Length of output: 1031
🏁 Script executed:
# Search for other assertions about first message to see if there are guards elsewhere
rg -n "assertFirstMessage|assertLastMessage|cells\.count" StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift --type swift | head -30Repository: GetStream/stream-chat-swift
Length of output: 782
🏁 Script executed:
# Get the complete messageCell implementation to see how it accesses cells
sed -n '190,220p' StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swiftRepository: GetStream/stream-chat-swift
Length of output: 1080
🏁 Script executed:
# Check if there are accessor implementations or actual cell access logic
rg -n "cells\[" StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift --type swift -B 2 -A 2Repository: GetStream/stream-chat-swift
Length of output: 53
🏁 Script executed:
# Check test usage patterns - look for assertFirstMessageIsVisible calls
rg -n "assertFirstMessageIsVisible" StreamChatUITestsAppUITests/ --type swift -B 3 -A 3Repository: GetStream/stream-chat-swift
Length of output: 2636
Add a guard check to prevent accessing negative cell indices.
Line 354 passes cells.count - 1 to messageCell(withIndex:) without validating that cells exist. When cells.count == 0, this results in index -1 being passed to cells.element(boundBy: -1), which causes unexpected behavior. Add an explicit guard to fail fast with a clear error message.
🛡️ Defensive check
@discardableResult
func assertFirstMessageIsVisible(
_ text: String,
file: StaticString = #filePath,
line: UInt = #line
) -> Self {
+ guard cells.count > 0 else {
+ XCTFail("No message cells available", file: file, line: line)
+ return self
+ }
let messageCell = messageCell(withIndex: cells.count - 1, file: file, line: line)
let message = attributes.text(text, in: messageCell).wait()
let actualText = message.waitForText(text).text
XCTAssertEqual(text, actualText, file: file, line: line)
return self
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @discardableResult | |
| func assertFirstMessageIsVisible( | |
| _ text: String, | |
| file: StaticString = #filePath, | |
| line: UInt = #line | |
| ) -> Self { | |
| let messageCell = messageCell(withIndex: cells.count - 1, file: file, line: line) | |
| let message = attributes.text(text, in: messageCell).wait() | |
| let actualText = message.waitForText(text).text | |
| XCTAssertEqual(text, actualText, file: file, line: line) | |
| return self | |
| } | |
| @discardableResult | |
| func assertFirstMessageIsVisible( | |
| _ text: String, | |
| file: StaticString = #filePath, | |
| line: UInt = #line | |
| ) -> Self { | |
| guard cells.count > 0 else { | |
| XCTFail("No message cells available", file: file, line: line) | |
| return self | |
| } | |
| let messageCell = messageCell(withIndex: cells.count - 1, file: file, line: line) | |
| let message = attributes.text(text, in: messageCell).wait() | |
| let actualText = message.waitForText(text).text | |
| XCTAssertEqual(text, actualText, file: file, line: line) | |
| return self | |
| } |
🤖 Prompt for AI Agents
In @StreamChatUITestsAppUITests/Robots/UserRobot+Asserts.swift around lines 347
- 359, In assertFirstMessageIsVisible, guard that cells.count > 0 before
computing let messageCell = messageCell(withIndex: cells.count - 1); if count is
0 call XCTFail with a clear message (include file and line) and return self to
fail fast; this prevents passing -1 into messageCell(withIndex:) and avoids
undefined behavior when accessing cells.element(boundBy:).
Generated by 🚫 Danger |
SDK Size
|
|



🔗 Issue Links
Resolve https://linear.app/stream/issue/IOS-932
🎯 Goal
Share mock server across mobile platforms.
🛠 Implementation
📝 Notes
v5branch, keeping them as they are to avoid overcomplicating this PR.🧪 Testing
On CI:
Locally:
Summary by CodeRabbit
Chores
Tests
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.