Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1/// Tests for Mutation Builder - uploadBlob mutation
2///
3/// Tests the uploadBlob mutation and BlobUploadResponse type with flat structure
4import gleam/dict
5import gleam/list
6import gleam/option.{None, Some}
7import gleeunit/should
8import lexicon_graphql/mutation/builder as mutation_builder
9import swell/schema
10import swell/value
11
12/// Test that uploadBlob mutation is added when factory is provided
13pub fn build_mutation_type_includes_upload_blob_test() {
14 // Create a simple upload blob resolver factory
15 let upload_factory = fn() {
16 fn(_ctx) {
17 Ok(
18 value.Object([
19 #("ref", value.String("bafkreiabc123")),
20 #("mime_type", value.String("image/jpeg")),
21 #("size", value.Int(12_345)),
22 ]),
23 )
24 }
25 }
26
27 // Build mutation type with uploadBlob factory
28 let mutation_build_result =
29 mutation_builder.build_mutation_type(
30 [],
31 dict.new(),
32 None,
33 None,
34 None,
35 Some(upload_factory),
36 None,
37 None,
38 )
39
40 // Verify the mutation type has uploadBlob field
41 let fields = schema.get_fields(mutation_build_result.mutation_type)
42 let has_upload_blob =
43 list.any(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
44
45 has_upload_blob
46 |> should.be_true()
47}
48
49/// Test that uploadBlob mutation is NOT added when factory is None
50pub fn build_mutation_type_without_upload_blob_test() {
51 // Build mutation type without uploadBlob factory
52 let mutation_build_result =
53 mutation_builder.build_mutation_type(
54 [],
55 dict.new(),
56 None,
57 None,
58 None,
59 None,
60 None,
61 None,
62 )
63
64 // Verify the mutation type does NOT have uploadBlob field
65 let fields = schema.get_fields(mutation_build_result.mutation_type)
66 let has_upload_blob =
67 list.any(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
68
69 has_upload_blob
70 |> should.be_false()
71}
72
73/// Test that uploadBlob mutation has correct arguments
74pub fn upload_blob_has_correct_arguments_test() {
75 // Create a simple factory
76 let upload_factory = fn() {
77 fn(_ctx) {
78 Ok(
79 value.Object([
80 #("ref", value.String("test")),
81 #("mime_type", value.String("test")),
82 #("size", value.Int(0)),
83 ]),
84 )
85 }
86 }
87
88 // Build mutation type
89 let mutation_build_result =
90 mutation_builder.build_mutation_type(
91 [],
92 dict.new(),
93 None,
94 None,
95 None,
96 Some(upload_factory),
97 None,
98 None,
99 )
100
101 // Get uploadBlob field
102 let fields = schema.get_fields(mutation_build_result.mutation_type)
103 let upload_blob_field =
104 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
105
106 case upload_blob_field {
107 Ok(field) -> {
108 let args = schema.field_arguments(field)
109 // Should have 2 arguments: data and mimeType
110 let has_data =
111 list.any(args, fn(arg) { schema.argument_name(arg) == "data" })
112 let has_mime_type =
113 list.any(args, fn(arg) { schema.argument_name(arg) == "mimeType" })
114
115 has_data |> should.be_true()
116 has_mime_type |> should.be_true()
117 list.length(args) |> should.equal(2)
118 }
119 Error(_) -> should.be_true(False)
120 }
121}
122
123/// Test that data argument is non-null String
124pub fn upload_blob_data_argument_is_non_null_string_test() {
125 let upload_factory = fn() {
126 fn(_ctx) {
127 Ok(
128 value.Object([
129 #("ref", value.String("test")),
130 #("mime_type", value.String("test")),
131 #("size", value.Int(0)),
132 ]),
133 )
134 }
135 }
136
137 let mutation_build_result =
138 mutation_builder.build_mutation_type(
139 [],
140 dict.new(),
141 None,
142 None,
143 None,
144 Some(upload_factory),
145 None,
146 None,
147 )
148
149 // Get uploadBlob field
150 let fields = schema.get_fields(mutation_build_result.mutation_type)
151 let upload_blob_field =
152 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
153
154 case upload_blob_field {
155 Ok(field) -> {
156 let args = schema.field_arguments(field)
157 let data_arg =
158 list.find(args, fn(arg) { schema.argument_name(arg) == "data" })
159
160 case data_arg {
161 Ok(arg) -> {
162 let arg_type = schema.argument_type(arg)
163 // Check if it's non-null
164 schema.is_non_null(arg_type) |> should.be_true()
165
166 // Check if inner type is string
167 case schema.inner_type(arg_type) {
168 Some(inner) -> {
169 schema.type_name(inner) |> should.equal("String")
170 }
171 None -> should.be_true(False)
172 }
173 }
174 Error(_) -> should.be_true(False)
175 }
176 }
177 Error(_) -> should.be_true(False)
178 }
179}
180
181/// Test that mimeType argument is non-null String
182pub fn upload_blob_mime_type_argument_is_non_null_string_test() {
183 let upload_factory = fn() {
184 fn(_ctx) {
185 Ok(
186 value.Object([
187 #("ref", value.String("test")),
188 #("mime_type", value.String("test")),
189 #("size", value.Int(0)),
190 ]),
191 )
192 }
193 }
194
195 let mutation_build_result =
196 mutation_builder.build_mutation_type(
197 [],
198 dict.new(),
199 None,
200 None,
201 None,
202 Some(upload_factory),
203 None,
204 None,
205 )
206
207 // Get uploadBlob field
208 let fields = schema.get_fields(mutation_build_result.mutation_type)
209 let upload_blob_field =
210 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
211
212 case upload_blob_field {
213 Ok(field) -> {
214 let args = schema.field_arguments(field)
215 let mime_type_arg =
216 list.find(args, fn(arg) { schema.argument_name(arg) == "mimeType" })
217
218 case mime_type_arg {
219 Ok(arg) -> {
220 let arg_type = schema.argument_type(arg)
221 // Check if it's non-null
222 schema.is_non_null(arg_type) |> should.be_true()
223
224 // Check if inner type is string
225 case schema.inner_type(arg_type) {
226 Some(inner) -> {
227 schema.type_name(inner) |> should.equal("String")
228 }
229 None -> should.be_true(False)
230 }
231 }
232 Error(_) -> should.be_true(False)
233 }
234 }
235 Error(_) -> should.be_true(False)
236 }
237}
238
239/// Test that uploadBlob returns non-null BlobUploadResponse
240pub fn upload_blob_return_type_is_non_null_blob_upload_response_test() {
241 let upload_factory = fn() {
242 fn(_ctx) {
243 Ok(
244 value.Object([
245 #("ref", value.String("test")),
246 #("mime_type", value.String("test")),
247 #("size", value.Int(0)),
248 ]),
249 )
250 }
251 }
252
253 let mutation_build_result =
254 mutation_builder.build_mutation_type(
255 [],
256 dict.new(),
257 None,
258 None,
259 None,
260 Some(upload_factory),
261 None,
262 None,
263 )
264
265 // Get uploadBlob field
266 let fields = schema.get_fields(mutation_build_result.mutation_type)
267 let upload_blob_field =
268 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
269
270 case upload_blob_field {
271 Ok(field) -> {
272 let return_type = schema.field_type(field)
273 // Check if it's non-null
274 schema.is_non_null(return_type) |> should.be_true()
275
276 // Check if inner type is BlobUploadResponse
277 case schema.inner_type(return_type) {
278 Some(inner) -> {
279 schema.type_name(inner) |> should.equal("BlobUploadResponse")
280 }
281 None -> should.be_true(False)
282 }
283 }
284 Error(_) -> should.be_true(False)
285 }
286}
287
288/// Test BlobUploadResponse type has ref field
289pub fn blob_upload_response_has_ref_field_test() {
290 let upload_factory = fn() {
291 fn(_ctx) {
292 Ok(
293 value.Object([
294 #("ref", value.String("test")),
295 #("mime_type", value.String("test")),
296 #("size", value.Int(0)),
297 ]),
298 )
299 }
300 }
301
302 let mutation_build_result =
303 mutation_builder.build_mutation_type(
304 [],
305 dict.new(),
306 None,
307 None,
308 None,
309 Some(upload_factory),
310 None,
311 None,
312 )
313
314 // Get uploadBlob field
315 let fields = schema.get_fields(mutation_build_result.mutation_type)
316 let upload_blob_field =
317 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
318
319 case upload_blob_field {
320 Ok(field) -> {
321 let return_type = schema.field_type(field)
322 case schema.inner_type(return_type) {
323 Some(blob_response_type) -> {
324 let response_fields = schema.get_fields(blob_response_type)
325 let has_ref =
326 list.any(response_fields, fn(f) { schema.field_name(f) == "ref" })
327 has_ref |> should.be_true()
328 }
329 None -> should.be_true(False)
330 }
331 }
332 Error(_) -> should.be_true(False)
333 }
334}
335
336/// Test BlobUploadResponse type has mimeType field
337pub fn blob_upload_response_has_mime_type_field_test() {
338 let upload_factory = fn() {
339 fn(_ctx) {
340 Ok(
341 value.Object([
342 #("ref", value.String("test")),
343 #("mime_type", value.String("test")),
344 #("size", value.Int(0)),
345 ]),
346 )
347 }
348 }
349
350 let mutation_build_result =
351 mutation_builder.build_mutation_type(
352 [],
353 dict.new(),
354 None,
355 None,
356 None,
357 Some(upload_factory),
358 None,
359 None,
360 )
361
362 // Get uploadBlob field
363 let fields = schema.get_fields(mutation_build_result.mutation_type)
364 let upload_blob_field =
365 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
366
367 case upload_blob_field {
368 Ok(field) -> {
369 let return_type = schema.field_type(field)
370 case schema.inner_type(return_type) {
371 Some(blob_response_type) -> {
372 let response_fields = schema.get_fields(blob_response_type)
373 let has_mime_type =
374 list.any(response_fields, fn(f) {
375 schema.field_name(f) == "mimeType"
376 })
377 has_mime_type |> should.be_true()
378 }
379 None -> should.be_true(False)
380 }
381 }
382 Error(_) -> should.be_true(False)
383 }
384}
385
386/// Test BlobUploadResponse type has size field
387pub fn blob_upload_response_has_size_field_test() {
388 let upload_factory = fn() {
389 fn(_ctx) {
390 Ok(
391 value.Object([
392 #("ref", value.String("test")),
393 #("mime_type", value.String("test")),
394 #("size", value.Int(0)),
395 ]),
396 )
397 }
398 }
399
400 let mutation_build_result =
401 mutation_builder.build_mutation_type(
402 [],
403 dict.new(),
404 None,
405 None,
406 None,
407 Some(upload_factory),
408 None,
409 None,
410 )
411
412 // Get uploadBlob field
413 let fields = schema.get_fields(mutation_build_result.mutation_type)
414 let upload_blob_field =
415 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
416
417 case upload_blob_field {
418 Ok(field) -> {
419 let return_type = schema.field_type(field)
420 case schema.inner_type(return_type) {
421 Some(blob_response_type) -> {
422 let response_fields = schema.get_fields(blob_response_type)
423 let has_size =
424 list.any(response_fields, fn(f) { schema.field_name(f) == "size" })
425 has_size |> should.be_true()
426 }
427 None -> should.be_true(False)
428 }
429 }
430 Error(_) -> should.be_true(False)
431 }
432}
433
434/// Test BlobUploadResponse has exactly 3 fields (no nested blob wrapper)
435pub fn blob_upload_response_has_three_fields_test() {
436 let upload_factory = fn() {
437 fn(_ctx) {
438 Ok(
439 value.Object([
440 #("ref", value.String("test")),
441 #("mime_type", value.String("test")),
442 #("size", value.Int(0)),
443 ]),
444 )
445 }
446 }
447
448 let mutation_build_result =
449 mutation_builder.build_mutation_type(
450 [],
451 dict.new(),
452 None,
453 None,
454 None,
455 Some(upload_factory),
456 None,
457 None,
458 )
459
460 // Get uploadBlob field
461 let fields = schema.get_fields(mutation_build_result.mutation_type)
462 let upload_blob_field =
463 list.find(fields, fn(field) { schema.field_name(field) == "uploadBlob" })
464
465 case upload_blob_field {
466 Ok(field) -> {
467 let return_type = schema.field_type(field)
468 case schema.inner_type(return_type) {
469 Some(blob_response_type) -> {
470 let response_fields = schema.get_fields(blob_response_type)
471 list.length(response_fields) |> should.equal(3)
472 }
473 None -> should.be_true(False)
474 }
475 }
476 Error(_) -> should.be_true(False)
477 }
478}