Skip to content

Commit 43aa423

Browse files
committed
test(realtime): add tests for Message and RealtimeClient
1 parent afd835b commit 43aa423

File tree

8 files changed

+321
-231
lines changed

8 files changed

+321
-231
lines changed

Sources/Realtime/Message.swift

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import Foundation
2222

2323
/// Data that is received from the Server.
24-
public struct Message: Sendable {
24+
public struct Message: Sendable, Hashable {
2525
/// Reference number. Empty if missing
2626
public let ref: String
2727

@@ -40,17 +40,15 @@ public struct Message: Sendable {
4040

4141
/// Message payload
4242
public var payload: Payload {
43-
guard let response = rawPayload["response"] as? Payload
44-
else { return rawPayload }
45-
return response
43+
rawPayload["response"]?.objectValue ?? rawPayload
4644
}
4745

4846
/// Convenience accessor. Equivalent to getting the status as such:
4947
/// ```swift
5048
/// message.payload["status"]
5149
/// ```
5250
public var status: PushStatus? {
53-
(rawPayload["status"] as? String).flatMap(PushStatus.init(rawValue:))
51+
rawPayload["status"]?.stringValue.flatMap(PushStatus.init(rawValue:))
5452
}
5553

5654
init(
@@ -66,21 +64,40 @@ public struct Message: Sendable {
6664
rawPayload = payload
6765
self.joinRef = joinRef
6866
}
67+
}
68+
69+
extension Message: Decodable {
70+
public init(from decoder: Decoder) throws {
71+
var container = try decoder.unkeyedContainer()
72+
73+
let joinRef = try container.decodeIfPresent(String.self)
74+
let ref = try container.decodeIfPresent(String.self)
75+
let topic = try container.decode(String.self)
76+
let event = try container.decode(String.self)
77+
let payload = try container.decode(Payload.self)
78+
self.init(
79+
ref: ref ?? "",
80+
topic: topic,
81+
event: event,
82+
payload: payload,
83+
joinRef: joinRef
84+
)
85+
}
86+
}
6987

70-
init?(json: [Any?]) {
71-
guard json.count > 4 else { return nil }
72-
joinRef = json[0] as? String
73-
ref = json[1] as? String ?? ""
88+
extension Message: Encodable {
89+
public func encode(to encoder: Encoder) throws {
90+
var container = encoder.unkeyedContainer()
7491

75-
if let topic = json[2] as? String,
76-
let event = json[3] as? String,
77-
let payload = json[4] as? Payload
78-
{
79-
self.topic = topic
80-
self.event = event
81-
rawPayload = payload
92+
if let joinRef {
93+
try container.encode(joinRef)
8294
} else {
83-
return nil
95+
try container.encodeNil()
8496
}
97+
98+
try container.encode(ref)
99+
try container.encode(topic)
100+
try container.encode(event)
101+
try container.encode(payload)
85102
}
86103
}

Sources/Realtime/PhoenixTransport.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public protocol PhoenixTransportDelegate {
8989

9090
- Parameter message: Message received from the server
9191
*/
92-
func onMessage(message: String)
92+
func onMessage(message: Data)
9393

9494
/**
9595
Notified when the `Transport` closes.
@@ -276,10 +276,11 @@ open class URLSessionTransport: NSObject, PhoenixTransport, URLSessionWebSocketD
276276
switch result {
277277
case let .success(message):
278278
switch message {
279-
case .data:
280-
print("Data received. This method is unsupported by the Client")
279+
case let .data(data):
280+
self?.delegate?.onMessage(message: data)
281281
case let .string(text):
282-
self?.delegate?.onMessage(message: text)
282+
let data = Data(text.utf8)
283+
self?.delegate?.onMessage(message: data)
283284
default:
284285
fatalError("Unknown result was received. [\(result)]")
285286
}

Sources/Realtime/Push.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,13 @@ public class Push {
9494
startTimeout()
9595
sent = true
9696
channel?.socket?.push(
97-
topic: channel?.topic ?? "",
98-
event: event,
99-
payload: payload,
100-
ref: ref,
101-
joinRef: channel?.joinRef
97+
message: Message(
98+
ref: ref ?? "",
99+
topic: channel?.topic ?? "",
100+
event: event,
101+
payload: payload,
102+
joinRef: channel?.joinRef
103+
)
102104
)
103105
}
104106

@@ -222,7 +224,7 @@ public class Push {
222224
guard let refEvent else { return }
223225

224226
var mutPayload = payload
225-
mutPayload["status"] = status.rawValue
227+
mutPayload["status"] = .string(status.rawValue)
226228

227229
channel?.trigger(event: refEvent, payload: mutPayload)
228230
}

Sources/Realtime/RealtimeChannel.swift

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,15 @@ public struct RealtimeChannelOptions {
9090
}
9191

9292
/// Parameters used to configure the channel
93-
var params: [String: [String: Any]] {
93+
var params: [String: AnyJSON] {
9494
[
9595
"config": [
9696
"presence": [
97-
"key": presenceKey ?? "",
97+
"key": .string(presenceKey ?? ""),
9898
],
9999
"broadcast": [
100-
"ack": broadcastAcknowledge,
101-
"self": broadcastSelf,
100+
"ack": .bool(broadcastAcknowledge),
101+
"self": .bool(broadcastSelf),
102102
],
103103
],
104104
]
@@ -185,7 +185,7 @@ public class RealtimeChannel {
185185
/// - parameter topic: Topic of the RealtimeChannel
186186
/// - parameter params: Optional. Parameters to send when joining.
187187
/// - parameter socket: Socket that the channel is a part of
188-
init(topic: String, params: [String: Any] = [:], socket: RealtimeClient) {
188+
init(topic: String, params: [String: AnyJSON] = [:], socket: RealtimeClient) {
189189
state = ChannelState.closed
190190
self.topic = topic
191191
subTopic = topic.replacingOccurrences(of: "realtime:", with: "")
@@ -381,22 +381,27 @@ public class RealtimeChannel {
381381
self.timeout = safeTimeout
382382
}
383383

384-
let broadcast = (params["config"] as? [String: any Sendable])?["broadcast"]
385-
let presence = (params["config"] as? [String: any Sendable])?["presence"]
384+
let broadcast = params["config"]?.objectValue?["broadcast"]
385+
let presence = params["config"]?.objectValue?["presence"]
386386

387387
var accessTokenPayload: Payload = [:]
388+
388389
var config: Payload = [
389-
"postgres_changes": bindings["postgres_changes"]?.map(\.filter) ?? [],
390+
"postgres_changes": .array(
391+
(bindings["postgres_changes"]?.map(\.filter) ?? []).map { filter in
392+
AnyJSON.object(filter.mapValues(AnyJSON.string))
393+
}
394+
),
390395
]
391396

392397
config["broadcast"] = broadcast
393398
config["presence"] = presence
394399

395400
if let accessToken = socket?.accessToken {
396-
accessTokenPayload["access_token"] = accessToken
401+
accessTokenPayload["access_token"] = .string(accessToken)
397402
}
398403

399-
params["config"] = config
404+
params["config"] = .object(config)
400405

401406
joinedOnce = true
402407
rejoin()
@@ -411,8 +416,8 @@ public class RealtimeChannel {
411416
self.socket?.setAuth(self.socket?.accessToken)
412417
}
413418

414-
guard let serverPostgresFilters = message
415-
.payload["postgres_changes"] as? [[String: any Sendable]]
419+
guard let serverPostgresFilters = message.payload["postgres_changes"]?.arrayValue?
420+
.compactMap(\.objectValue)
416421
else {
417422
callback?(.subscribed, nil)
418423
return
@@ -432,17 +437,17 @@ public class RealtimeChannel {
432437

433438
let serverPostgresFilter = serverPostgresFilters[i]
434439

435-
if serverPostgresFilter["event"] as? String == event,
436-
serverPostgresFilter["schema"] as? String == schema,
437-
serverPostgresFilter["table"] as? String == table,
438-
serverPostgresFilter["filter"] as? String == filter
440+
if serverPostgresFilter["event"]?.stringValue == event,
441+
serverPostgresFilter["schema"]?.stringValue == schema,
442+
serverPostgresFilter["table"]?.stringValue == table,
443+
serverPostgresFilter["filter"]?.stringValue == filter
439444
{
440445
newPostgresBindings.append(
441446
Binding(
442447
type: clientPostgresBinding.type,
443448
filter: clientPostgresBinding.filter,
444449
callback: clientPostgresBinding.callback,
445-
id: (serverPostgresFilter["id"] as? Int).flatMap(String.init)
450+
id: serverPostgresFilter["id"]?.numberValue.map { Int($0) }.flatMap(String.init)
446451
)
447452
)
448453
} else {
@@ -481,7 +486,7 @@ public class RealtimeChannel {
481486
type: .presence,
482487
payload: [
483488
"event": "track",
484-
"payload": payload,
489+
"payload": .object(payload),
485490
],
486491
opts: opts
487492
)
@@ -643,9 +648,9 @@ public class RealtimeChannel {
643648
opts: Payload = [:]
644649
) async -> ChannelResponse {
645650
var payload = payload
646-
payload["type"] = type.rawValue
651+
payload["type"] = .string(type.rawValue)
647652
if let event {
648-
payload["event"] = event
653+
payload["event"] = .string(event)
649654
}
650655

651656
if !canPush, type == .broadcast {
@@ -681,14 +686,14 @@ public class RealtimeChannel {
681686
return await withCheckedContinuation { continuation in
682687
let push = self.push(
683688
type.rawValue, payload: payload,
684-
timeout: (opts["timeout"] as? TimeInterval) ?? self.timeout
689+
timeout: opts["timeout"]?.numberValue ?? self.timeout
685690
)
686691

687-
if let type = payload["type"] as? String, type == "broadcast",
688-
let config = self.params["config"] as? [String: any Sendable],
689-
let broadcast = config["broadcast"] as? [String: any Sendable]
692+
if let type = payload["type"]?.stringValue, type == "broadcast",
693+
let config = self.params["config"]?.objectValue,
694+
let broadcast = config["broadcast"]?.objectValue
690695
{
691-
let ack = broadcast["ack"] as? Bool
696+
let ack = broadcast["ack"]?.boolValue
692697
if ack == nil || ack == false {
693698
continuation.resume(returning: .ok)
694699
return
@@ -848,13 +853,14 @@ public class RealtimeChannel {
848853
let bindEvent = bind.filter["event"]?.lowercased()
849854

850855
if let bindId = bind.id.flatMap(Int.init) {
851-
let ids = message.payload["ids"] as? [Int] ?? []
852-
let data = message.payload["data"] as? [String: any Sendable] ?? [:]
853-
let type = data["type"] as? String
856+
let ids = (message.payload["ids"]?.arrayValue ?? []).compactMap(\.numberValue)
857+
.map(Int.init)
858+
let data = message.payload["data"]?.objectValue ?? [:]
859+
let type = data["type"]?.stringValue
854860
return ids.contains(bindId) && (bindEvent == "*" || bindEvent == type?.lowercased())
855861
}
856862

857-
let messageEvent = message.payload["event"] as? String
863+
let messageEvent = message.payload["event"]?.stringValue
858864
return bindEvent == "*" || bindEvent == messageEvent?.lowercased()
859865
}
860866

0 commit comments

Comments
 (0)