-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added tests for typing indicators (WIP).
- Loading branch information
Showing
6 changed files
with
222 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import Ably | ||
@testable import AblyChat | ||
import Testing | ||
|
||
struct DefaultRoomTypingTests { | ||
// @spec CHA-T1 | ||
@Test | ||
func channelNameIsSetAsChatMessagesChannelName() async throws { | ||
// Given | ||
let channel = MockRealtimeChannel(name: "basketball::$chat::$typingIndicators") | ||
let featureChannel = MockFeatureChannel(channel: channel) | ||
|
||
// When | ||
let defaultTyping = DefaultTyping(featureChannel: featureChannel, roomID: "basketball", clientID: "mockClientId", logger: TestLogger(), timeout: 5) | ||
|
||
// Then | ||
#expect(defaultTyping.channel.name == "basketball::$chat::$typingIndicators") | ||
} | ||
|
||
// @spec CHA-T2 | ||
@Test | ||
func retrieveCurrentlyTypingClientIDs() async throws { | ||
// Given | ||
let typingPresence = MockRealtimePresence(["client1", "client2"].map { .init(clientId: $0) }) | ||
let channel = MockRealtimeChannel(name: "basketball::$chat::$typingIndicators", mockPresence: typingPresence) | ||
let featureChannel = MockFeatureChannel(channel: channel, resultOfWaitToBeAblePerformPresenceOperations: .success(())) | ||
let defaultTyping = DefaultTyping(featureChannel: featureChannel, roomID: "basketball", clientID: "mockClientId", logger: TestLogger(), timeout: 5) | ||
|
||
// When | ||
let typingInfo = try await defaultTyping.get() | ||
|
||
// Then | ||
#expect(typingInfo.sorted() == ["client1", "client2"]) | ||
} | ||
|
||
// @spec CHA-T4 | ||
// @spec CHA-T5 | ||
@Test | ||
func usersMayIndicateThatTheyHaveStartedTyping() async throws { | ||
// Given | ||
let typingPresence = MockRealtimePresence([]) | ||
let channel = MockRealtimeChannel(name: "basketball::$chat::$typingIndicators", mockPresence: typingPresence) | ||
let featureChannel = MockFeatureChannel(channel: channel, resultOfWaitToBeAblePerformPresenceOperations: .success(())) | ||
let defaultTyping = DefaultTyping(featureChannel: featureChannel, roomID: "basketball", clientID: "client1", logger: TestLogger(), timeout: 5) | ||
|
||
// CHA-T4 | ||
|
||
// When | ||
try await defaultTyping.start() | ||
|
||
// Then | ||
var typingInfo = try await defaultTyping.get() | ||
#expect(typingInfo == ["client1"]) | ||
|
||
// CHA-T5 | ||
|
||
// When | ||
try await defaultTyping.stop() | ||
|
||
// Then | ||
typingInfo = try await defaultTyping.get() | ||
#expect(typingInfo.isEmpty) | ||
} | ||
|
||
// @spec CHA-T6 | ||
@Test | ||
func usersMaySubscribeToTypingEvents() async throws { | ||
// Given | ||
let typingPresence = MockRealtimePresence([]) | ||
let channel = MockRealtimeChannel(name: "basketball::$chat::$typingIndicators", mockPresence: typingPresence) | ||
let featureChannel = MockFeatureChannel(channel: channel, resultOfWaitToBeAblePerformPresenceOperations: .success(())) | ||
let defaultTyping = DefaultTyping(featureChannel: featureChannel, roomID: "basketball", clientID: "client1", logger: TestLogger(), timeout: 5) | ||
|
||
// When | ||
let subscription = await defaultTyping.subscribe() | ||
subscription.emit(TypingEvent(currentlyTyping: ["client1"])) | ||
|
||
// Then | ||
let typingEvent = try #require(await subscription.first { _ in true }) | ||
#expect(typingEvent.currentlyTyping == ["client1"]) | ||
} | ||
|
||
// @spec CHA-T7 | ||
@Test | ||
func onDiscontinuity() async throws { | ||
// Given | ||
let typingPresence = MockRealtimePresence([]) | ||
let channel = MockRealtimeChannel(name: "basketball::$chat::$typingIndicators", mockPresence: typingPresence) | ||
let featureChannel = MockFeatureChannel(channel: channel, resultOfWaitToBeAblePerformPresenceOperations: .success(())) | ||
let defaultTyping = DefaultTyping(featureChannel: featureChannel, roomID: "basketball", clientID: "client1", logger: TestLogger(), timeout: 5) | ||
|
||
// When: The feature channel emits a discontinuity through `onDiscontinuity` | ||
let featureChannelDiscontinuity = DiscontinuityEvent(error: ARTErrorInfo.createUnknownError()) // arbitrary error | ||
let discontinuitySubscription = await defaultTyping.onDiscontinuity() | ||
await featureChannel.emitDiscontinuity(featureChannelDiscontinuity) | ||
|
||
// Then: The DefaultOccupancy instance emits this discontinuity through `onDiscontinuity` | ||
let discontinuity = try #require(await discontinuitySubscription.first { _ in true }) | ||
#expect(discontinuity == featureChannelDiscontinuity) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import Ably | ||
import AblyChat | ||
|
||
final class MockRealtimePresence: NSObject, @unchecked Sendable, RealtimePresenceProtocol { | ||
let syncComplete: Bool | ||
private var members: [ARTPresenceMessage] | ||
|
||
init(syncComplete: Bool = true, _ members: [ARTPresenceMessage]) { | ||
self.syncComplete = syncComplete | ||
self.members = members | ||
} | ||
|
||
func get(_ callback: @escaping ARTPresenceMessagesCallback) { | ||
callback(members, nil) | ||
} | ||
|
||
func get(_ query: ARTRealtimePresenceQuery, callback: @escaping ARTPresenceMessagesCallback) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func enter(_ data: Any?) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func enter(_ data: Any?, callback: ARTCallback? = nil) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func update(_ data: Any?) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func update(_ data: Any?, callback: ARTCallback? = nil) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func leave(_ data: Any?) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func leave(_ data: Any?, callback: ARTCallback? = nil) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func enterClient(_ clientId: String, data: Any?) { | ||
members.append(ARTPresenceMessage(clientId: clientId)) | ||
} | ||
|
||
func enterClient(_ clientId: String, data: Any?, callback: ARTCallback? = nil) { | ||
members.append(ARTPresenceMessage(clientId: clientId)) | ||
callback?(nil) | ||
} | ||
|
||
func updateClient(_ clientId: String, data: Any?) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func updateClient(_ clientId: String, data: Any?, callback: ARTCallback? = nil) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func leaveClient(_ clientId: String, data: Any?) { | ||
members.removeAll { $0.clientId == clientId } | ||
} | ||
|
||
func leaveClient(_ clientId: String, data: Any?, callback: ARTCallback? = nil) { | ||
members.removeAll { $0.clientId == clientId } | ||
} | ||
|
||
func subscribe(_ callback: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { | ||
ARTEventListener() | ||
} | ||
|
||
func subscribe(attachCallback onAttach: ARTCallback?, callback: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { | ||
ARTEventListener() | ||
} | ||
|
||
func subscribe(_ action: ARTPresenceAction, callback: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { | ||
ARTEventListener() | ||
} | ||
|
||
func subscribe(_ action: ARTPresenceAction, onAttach: ARTCallback?, callback: @escaping ARTPresenceMessageCallback) -> ARTEventListener? { | ||
ARTEventListener() | ||
} | ||
|
||
func unsubscribe() { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func unsubscribe(_ listener: ARTEventListener) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func unsubscribe(_ action: ARTPresenceAction, listener: ARTEventListener) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func history(_ callback: @escaping ARTPaginatedPresenceCallback) { | ||
fatalError("Not implemented") | ||
} | ||
|
||
func history(_ query: ARTRealtimeHistoryQuery?, callback: @escaping ARTPaginatedPresenceCallback) throws { | ||
fatalError("Not implemented") | ||
} | ||
} |