馃寠 A GraphQL implementation in Gleam
1/// Tests for GraphQL Schema (Type System)
2///
3/// GraphQL spec Section 3 - Type System
4/// Defines types, fields, and schema structure
5import gleam/option.{None}
6import gleeunit/should
7import swell/schema
8import swell/value
9
10// Type system tests
11pub fn create_scalar_type_test() {
12 let string_type = schema.string_type()
13 should.equal(schema.type_name(string_type), "String")
14}
15
16pub fn create_object_type_test() {
17 let user_type =
18 schema.object_type("User", "A user in the system", [
19 schema.field("id", schema.id_type(), "User ID", fn(_ctx) {
20 Ok(value.String("123"))
21 }),
22 schema.field("name", schema.string_type(), "User name", fn(_ctx) {
23 Ok(value.String("Alice"))
24 }),
25 ])
26
27 should.equal(schema.type_name(user_type), "User")
28}
29
30pub fn create_non_null_type_test() {
31 let non_null_string = schema.non_null(schema.string_type())
32 should.be_true(schema.is_non_null(non_null_string))
33}
34
35pub fn create_list_type_test() {
36 let list_of_strings = schema.list_type(schema.string_type())
37 should.be_true(schema.is_list(list_of_strings))
38}
39
40pub fn create_schema_test() {
41 let query_type =
42 schema.object_type("Query", "Root query type", [
43 schema.field("hello", schema.string_type(), "Hello field", fn(_ctx) {
44 Ok(value.String("world"))
45 }),
46 ])
47
48 let graphql_schema = schema.schema(query_type, None)
49 should.equal(schema.query_type(graphql_schema), query_type)
50}
51
52pub fn field_with_arguments_test() {
53 let user_field =
54 schema.field_with_args(
55 "user",
56 schema.string_type(),
57 "Get user by ID",
58 [schema.argument("id", schema.id_type(), "User ID", None)],
59 fn(_ctx) { Ok(value.String("Alice")) },
60 )
61
62 should.equal(schema.field_name(user_field), "user")
63}
64
65pub fn enum_type_test() {
66 let role_enum =
67 schema.enum_type("Role", "User role", [
68 schema.enum_value("ADMIN", "Administrator"),
69 schema.enum_value("USER", "Regular user"),
70 ])
71
72 should.equal(schema.type_name(role_enum), "Role")
73}
74
75pub fn scalar_types_exist_test() {
76 // Built-in scalar types
77 let _string = schema.string_type()
78 let _int = schema.int_type()
79 let _float = schema.float_type()
80 let _boolean = schema.boolean_type()
81 let _id = schema.id_type()
82
83 should.be_true(True)
84}
85
86// Union type tests
87pub fn create_union_type_test() {
88 let post_type =
89 schema.object_type("Post", "A blog post", [
90 schema.field("title", schema.string_type(), "Post title", fn(_ctx) {
91 Ok(value.String("Hello"))
92 }),
93 ])
94
95 let comment_type =
96 schema.object_type("Comment", "A comment", [
97 schema.field("text", schema.string_type(), "Comment text", fn(_ctx) {
98 Ok(value.String("Nice post"))
99 }),
100 ])
101
102 let type_resolver = fn(_ctx: schema.Context) -> Result(String, String) {
103 Ok("Post")
104 }
105
106 let union_type =
107 schema.union_type(
108 "SearchResult",
109 "A search result",
110 [post_type, comment_type],
111 type_resolver,
112 )
113
114 should.equal(schema.type_name(union_type), "SearchResult")
115 should.be_true(schema.is_union(union_type))
116}
117
118pub fn union_possible_types_test() {
119 let post_type =
120 schema.object_type("Post", "A blog post", [
121 schema.field("title", schema.string_type(), "Post title", fn(_ctx) {
122 Ok(value.String("Hello"))
123 }),
124 ])
125
126 let comment_type =
127 schema.object_type("Comment", "A comment", [
128 schema.field("text", schema.string_type(), "Comment text", fn(_ctx) {
129 Ok(value.String("Nice post"))
130 }),
131 ])
132
133 let type_resolver = fn(_ctx: schema.Context) -> Result(String, String) {
134 Ok("Post")
135 }
136
137 let union_type =
138 schema.union_type(
139 "SearchResult",
140 "A search result",
141 [post_type, comment_type],
142 type_resolver,
143 )
144
145 let possible_types = schema.get_possible_types(union_type)
146 should.equal(possible_types, [post_type, comment_type])
147}
148
149pub fn resolve_union_type_test() {
150 let post_type =
151 schema.object_type("Post", "A blog post", [
152 schema.field("title", schema.string_type(), "Post title", fn(_ctx) {
153 Ok(value.String("Hello"))
154 }),
155 ])
156
157 let comment_type =
158 schema.object_type("Comment", "A comment", [
159 schema.field("text", schema.string_type(), "Comment text", fn(_ctx) {
160 Ok(value.String("Nice post"))
161 }),
162 ])
163
164 // Type resolver that examines the __typename field in the data
165 let type_resolver = fn(ctx: schema.Context) -> Result(String, String) {
166 case ctx.data {
167 None -> Error("No data")
168 option.Some(value.Object(fields)) -> {
169 case fields {
170 [#("__typename", value.String(type_name)), ..] -> Ok(type_name)
171 _ -> Error("No __typename field")
172 }
173 }
174 _ -> Error("Data is not an object")
175 }
176 }
177
178 let union_type =
179 schema.union_type(
180 "SearchResult",
181 "A search result",
182 [post_type, comment_type],
183 type_resolver,
184 )
185
186 // Create context with data that has __typename
187 let data =
188 value.Object([
189 #("__typename", value.String("Post")),
190 #("title", value.String("Test")),
191 ])
192 let ctx = schema.context(option.Some(data))
193 let result = schema.resolve_union_type(union_type, ctx)
194
195 case result {
196 Ok(resolved_type) -> should.equal(schema.type_name(resolved_type), "Post")
197 Error(_) -> should.be_true(False)
198 }
199}
200
201pub fn union_type_kind_test() {
202 let post_type =
203 schema.object_type("Post", "A blog post", [
204 schema.field("title", schema.string_type(), "Post title", fn(_ctx) {
205 Ok(value.String("Hello"))
206 }),
207 ])
208
209 let type_resolver = fn(_ctx: schema.Context) -> Result(String, String) {
210 Ok("Post")
211 }
212
213 let union_type =
214 schema.union_type(
215 "SearchResult",
216 "A search result",
217 [post_type],
218 type_resolver,
219 )
220
221 should.equal(schema.type_kind(union_type), "UNION")
222}