Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1/// Tests for GraphQL-WS protocol implementation
2///
3/// Tests the GraphQL-WS (WebSocket) protocol message handling
4import gleam/dict
5import gleam/option.{Some}
6import gleeunit
7import gleeunit/should
8import graphql/ws
9
10pub fn main() {
11 gleeunit.main()
12}
13
14// Test: Parse connection_init message
15pub fn parse_connection_init_test() {
16 let json_str =
17 "{\"type\":\"connection_init\",\"payload\":{\"Authorization\":\"Bearer token123\"}}"
18
19 case ws.parse_message(json_str) {
20 Ok(ws.ConnectionInit(payload)) -> {
21 case dict.get(payload, "Authorization") {
22 Ok("Bearer token123") -> should.be_true(True)
23 _ -> should.fail()
24 }
25 }
26 _ -> should.fail()
27 }
28}
29
30// Test: Parse connection_init without payload
31pub fn parse_connection_init_no_payload_test() {
32 let json_str = "{\"type\":\"connection_init\"}"
33
34 case ws.parse_message(json_str) {
35 Ok(ws.ConnectionInit(payload)) -> {
36 dict.size(payload)
37 |> should.equal(0)
38 }
39 _ -> should.fail()
40 }
41}
42
43// Test: Parse subscribe message
44pub fn parse_subscribe_message_test() {
45 let json_str =
46 "{\"id\":\"1\",\"type\":\"subscribe\",\"payload\":{\"query\":\"subscription { postCreated { text } }\"}}"
47
48 case ws.parse_message(json_str) {
49 Ok(ws.Subscribe(id, query, _vars)) -> {
50 id |> should.equal("1")
51 query |> should.equal("subscription { postCreated { text } }")
52 }
53 _ -> should.fail()
54 }
55}
56
57// Test: Parse subscribe message with variables
58pub fn parse_subscribe_with_variables_test() {
59 let json_str =
60 "{\"id\":\"1\",\"type\":\"subscribe\",\"payload\":{\"query\":\"subscription { postCreated { text } }\",\"variables\":\"{}\"}}"
61
62 case ws.parse_message(json_str) {
63 Ok(ws.Subscribe(id, query, vars)) -> {
64 id |> should.equal("1")
65 query |> should.equal("subscription { postCreated { text } }")
66 vars |> should.equal(Some("{}"))
67 }
68 _ -> should.fail()
69 }
70}
71
72// Test: Parse ping message
73pub fn parse_ping_message_test() {
74 let json_str = "{\"type\":\"ping\"}"
75
76 case ws.parse_message(json_str) {
77 Ok(ws.Ping) -> should.be_true(True)
78 _ -> should.fail()
79 }
80}
81
82// Test: Parse pong message
83pub fn parse_pong_message_test() {
84 let json_str = "{\"type\":\"pong\"}"
85
86 case ws.parse_message(json_str) {
87 Ok(ws.Pong) -> should.be_true(True)
88 _ -> should.fail()
89 }
90}
91
92// Test: Parse complete message
93pub fn parse_complete_message_test() {
94 let json_str = "{\"id\":\"1\",\"type\":\"complete\"}"
95
96 case ws.parse_message(json_str) {
97 Ok(ws.Complete(id)) -> {
98 id |> should.equal("1")
99 }
100 _ -> should.fail()
101 }
102}
103
104// Test: Format connection_ack message
105pub fn format_connection_ack_test() {
106 let message = ws.ConnectionAck
107
108 let json_str = ws.format_message(message)
109
110 // Should produce valid JSON with type "connection_ack"
111 json_str |> should.equal("{\"type\":\"connection_ack\"}")
112}
113
114// Test: Format next message with data
115pub fn format_next_message_test() {
116 let data_json = "{\"data\":{\"postCreated\":{\"text\":\"Hello\"}}}"
117
118 let message = ws.Next("1", data_json)
119
120 let json_str = ws.format_message(message)
121
122 // Should contain id, type "next", and payload
123 json_str
124 |> should.equal(
125 "{\"id\":\"1\",\"type\":\"next\",\"payload\":" <> data_json <> "}",
126 )
127}
128
129// Test: Format error message
130pub fn format_error_message_test() {
131 let message = ws.ErrorMessage("1", "Syntax error")
132
133 let json_str = ws.format_message(message)
134
135 // Should contain id, type "error", and payload with message
136 json_str
137 |> should.equal(
138 "{\"id\":\"1\",\"type\":\"error\",\"payload\":[{\"message\":\"Syntax error\"}]}",
139 )
140}
141
142// Test: Format error message with quotes
143pub fn format_error_message_with_quotes_test() {
144 let message = ws.ErrorMessage("1", "Field \"text\" not found")
145
146 let json_str = ws.format_message(message)
147
148 // Should escape quotes in error message
149 json_str
150 |> should.equal(
151 "{\"id\":\"1\",\"type\":\"error\",\"payload\":[{\"message\":\"Field \\\"text\\\" not found\"}]}",
152 )
153}
154
155// Test: Format complete message
156pub fn format_complete_message_test() {
157 let message = ws.Complete("1")
158
159 let json_str = ws.format_message(message)
160
161 json_str |> should.equal("{\"id\":\"1\",\"type\":\"complete\"}")
162}
163
164// Test: Format pong message
165pub fn format_pong_message_test() {
166 let message = ws.Pong
167
168 let json_str = ws.format_message(message)
169
170 json_str |> should.equal("{\"type\":\"pong\"}")
171}
172
173// Test: Invalid JSON should return error
174pub fn parse_invalid_json_test() {
175 let json_str = "not valid json"
176
177 case ws.parse_message(json_str) {
178 Error(_) -> should.be_true(True)
179 Ok(_) -> should.fail()
180 }
181}
182
183// Test: Unknown message type should return error
184pub fn parse_unknown_type_test() {
185 let json_str = "{\"type\":\"unknown_message_type\"}"
186
187 case ws.parse_message(json_str) {
188 Error(_) -> should.be_true(True)
189 Ok(_) -> should.fail()
190 }
191}
192
193// Test: Missing required fields should return error
194pub fn parse_subscribe_missing_id_test() {
195 let json_str = "{\"type\":\"subscribe\",\"payload\":{}}"
196
197 case ws.parse_message(json_str) {
198 Error(_) -> should.be_true(True)
199 Ok(_) -> should.fail()
200 }
201}