Skip to content

Commit b1e12f5

Browse files
Merge pull request #117 from samisuteria/federation-parsing
add tests for federation schema parsing
2 parents 95d27ec + ec9d18f commit b1e12f5

File tree

1 file changed

+338
-0
lines changed

1 file changed

+338
-0
lines changed
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
@testable import GraphQL
2+
import XCTest
3+
4+
final class FederationTests: XCTestCase {
5+
func testFederationSampleSchema() throws {
6+
// Confirm that the Apollo test schema can be parsed as expected https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/main/COMPATIBILITY.md
7+
let source =
8+
"""
9+
extend schema
10+
@link(
11+
url: "https://specs.apollo.dev/federation/v2.0",
12+
import: [
13+
"@extends",
14+
"@external",
15+
"@key",
16+
"@inaccessible",
17+
"@override",
18+
"@provides",
19+
"@requires",
20+
"@shareable",
21+
"@tag"
22+
]
23+
)
24+
25+
type Product
26+
@key(fields: "id")
27+
@key(fields: "sku package")
28+
@key(fields: "sku variation { id }") {
29+
id: ID!
30+
sku: String
31+
package: String
32+
variation: ProductVariation
33+
dimensions: ProductDimension
34+
createdBy: User @provides(fields: "totalProductsCreated")
35+
notes: String @tag(name: "internal")
36+
research: [ProductResearch!]!
37+
}
38+
39+
type DeprecatedProduct @key(fields: "sku package") {
40+
sku: String!
41+
package: String!
42+
reason: String
43+
createdBy: User
44+
}
45+
46+
type ProductVariation {
47+
id: ID!
48+
}
49+
50+
type ProductResearch @key(fields: "study { caseNumber }") {
51+
study: CaseStudy!
52+
outcome: String
53+
}
54+
55+
type CaseStudy {
56+
caseNumber: ID!
57+
description: String
58+
}
59+
60+
type ProductDimension @shareable {
61+
size: String
62+
weight: Float
63+
unit: String @inaccessible
64+
}
65+
66+
extend type Query {
67+
product(id: ID!): Product
68+
deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead")
69+
}
70+
71+
extend type User @key(fields: "email") {
72+
averageProductsCreatedPerYear: Int @requires(fields: "totalProductsCreated yearsOfEmployment")
73+
email: ID! @external
74+
name: String @override(from: "users")
75+
totalProductsCreated: Int @external
76+
yearsOfEmployment: Int! @external
77+
}
78+
"""
79+
80+
let schemaExtensionDefinition =
81+
SchemaExtensionDefinition(definition: SchemaDefinition(directives: [
82+
Directive(name: nameNode("link"), arguments: [
83+
Argument(
84+
name: nameNode("url"),
85+
value: StringValue(
86+
value: "https://specs.apollo.dev/federation/v2.0",
87+
block: false
88+
)
89+
),
90+
Argument(
91+
name: nameNode("import"),
92+
value: ListValue(values: [
93+
StringValue(value: "@extends", block: false),
94+
StringValue(value: "@external", block: false),
95+
StringValue(value: "@key", block: false),
96+
StringValue(value: "@inaccessible", block: false),
97+
StringValue(value: "@override", block: false),
98+
StringValue(value: "@provides", block: false),
99+
StringValue(value: "@requires", block: false),
100+
StringValue(value: "@shareable", block: false),
101+
StringValue(value: "@tag", block: false),
102+
])
103+
),
104+
]),
105+
], operationTypes: []))
106+
107+
let productObjectTypeDefinition = ObjectTypeDefinition(
108+
name: nameNode("Product"),
109+
directives: [
110+
Directive(name: nameNode("key"), arguments: [
111+
Argument(
112+
name: nameNode("fields"),
113+
value: StringValue(value: "id", block: false)
114+
),
115+
]),
116+
Directive(name: nameNode("key"), arguments: [
117+
Argument(
118+
name: nameNode("fields"),
119+
value: StringValue(value: "sku package", block: false)
120+
),
121+
]),
122+
Directive(name: nameNode("key"), arguments: [
123+
Argument(
124+
name: nameNode("fields"),
125+
value: StringValue(value: "sku variation { id }", block: false)
126+
),
127+
]),
128+
],
129+
fields: [
130+
FieldDefinition(name: nameNode("id"), type: NonNullType(type: typeNode("ID"))),
131+
FieldDefinition(name: nameNode("sku"), type: typeNode("String")),
132+
FieldDefinition(name: nameNode("package"), type: typeNode("String")),
133+
FieldDefinition(name: nameNode("variation"), type: typeNode("ProductVariation")),
134+
FieldDefinition(name: nameNode("dimensions"), type: typeNode("ProductDimension")),
135+
FieldDefinition(name: nameNode("createdBy"), type: typeNode("User"), directives: [
136+
Directive(name: nameNode("provides"), arguments: [
137+
Argument(
138+
name: nameNode("fields"),
139+
value: StringValue(value: "totalProductsCreated", block: false)
140+
),
141+
]),
142+
]),
143+
FieldDefinition(name: nameNode("notes"), type: typeNode("String"), directives: [
144+
Directive(name: nameNode("tag"), arguments: [
145+
Argument(
146+
name: nameNode("name"),
147+
value: StringValue(value: "internal", block: false)
148+
),
149+
]),
150+
]),
151+
FieldDefinition(
152+
name: nameNode("research"),
153+
type: NonNullType(
154+
type: ListType(
155+
type: NonNullType(type: NamedType(name: nameNode("ProductResearch")))
156+
)
157+
)
158+
),
159+
]
160+
)
161+
162+
let deprecatedProductObjectTypeDefinition = ObjectTypeDefinition(
163+
name: nameNode("DeprecatedProduct"),
164+
directives: [
165+
Directive(name: nameNode("key"), arguments: [
166+
Argument(
167+
name: nameNode("fields"),
168+
value: StringValue(value: "sku package", block: false)
169+
),
170+
]),
171+
],
172+
fields: [
173+
FieldDefinition(name: nameNode("sku"), type: NonNullType(type: typeNode("String"))),
174+
FieldDefinition(
175+
name: nameNode("package"),
176+
type: NonNullType(type: typeNode("String"))
177+
),
178+
FieldDefinition(name: nameNode("reason"), type: typeNode("String")),
179+
FieldDefinition(name: nameNode("createdBy"), type: typeNode("User")),
180+
]
181+
)
182+
183+
let productVariationObjectTypeDefinition = ObjectTypeDefinition(
184+
name: nameNode("ProductVariation"),
185+
fields: [
186+
FieldDefinition(name: nameNode("id"), type: NonNullType(type: typeNode("ID"))),
187+
]
188+
)
189+
190+
let productResearchObjectTypeDefinition = ObjectTypeDefinition(
191+
name: nameNode("ProductResearch"),
192+
directives: [
193+
Directive(name: nameNode("key"), arguments: [
194+
Argument(
195+
name: nameNode("fields"),
196+
value: StringValue(value: "study { caseNumber }", block: false)
197+
),
198+
]),
199+
],
200+
fields: [
201+
FieldDefinition(
202+
name: nameNode("study"),
203+
type: NonNullType(type: typeNode("CaseStudy"))
204+
),
205+
FieldDefinition(name: nameNode("outcome"), type: typeNode("String")),
206+
]
207+
)
208+
209+
let caseStudyObjectTypeDefinition = ObjectTypeDefinition(
210+
name: nameNode("CaseStudy"),
211+
fields: [
212+
FieldDefinition(
213+
name: nameNode("caseNumber"),
214+
type: NonNullType(type: typeNode("ID"))
215+
),
216+
FieldDefinition(name: nameNode("description"), type: typeNode("String")),
217+
]
218+
)
219+
220+
let productDimensionObjectTypeDefinition = ObjectTypeDefinition(
221+
name: nameNode("ProductDimension"),
222+
directives: [
223+
Directive(name: nameNode("shareable")),
224+
],
225+
fields: [
226+
FieldDefinition(name: nameNode("size"), type: typeNode("String")),
227+
FieldDefinition(name: nameNode("weight"), type: typeNode("Float")),
228+
FieldDefinition(name: nameNode("unit"), type: typeNode("String"), directives: [
229+
Directive(name: nameNode("inaccessible")),
230+
]),
231+
]
232+
)
233+
234+
let queryExtensionObjectTypeDefinition =
235+
TypeExtensionDefinition(definition: ObjectTypeDefinition(
236+
name: nameNode("Query"),
237+
fields: [
238+
FieldDefinition(name: nameNode("product"), arguments: [
239+
InputValueDefinition(
240+
name: nameNode("id"),
241+
type: NonNullType(type: NamedType(name: nameNode("ID")))
242+
),
243+
], type: typeNode("Product")),
244+
FieldDefinition(name: nameNode("deprecatedProduct"), arguments: [
245+
InputValueDefinition(
246+
name: nameNode("sku"),
247+
type: NonNullType(type: NamedType(name: nameNode("String")))
248+
),
249+
InputValueDefinition(
250+
name: nameNode("package"),
251+
type: NonNullType(type: NamedType(name: nameNode("String")))
252+
),
253+
], type: typeNode("DeprecatedProduct"), directives: [
254+
Directive(name: nameNode("deprecated"), arguments: [
255+
Argument(
256+
name: nameNode("reason"),
257+
value: StringValue(value: "Use product query instead", block: false)
258+
),
259+
]),
260+
]),
261+
]
262+
))
263+
264+
let userExtensionObjectTypeDefinition =
265+
TypeExtensionDefinition(definition: ObjectTypeDefinition(
266+
name: nameNode("User"),
267+
directives: [
268+
Directive(name: nameNode("key"), arguments: [
269+
Argument(
270+
name: nameNode("fields"),
271+
value: StringValue(value: "email", block: false)
272+
),
273+
]),
274+
],
275+
fields: [
276+
FieldDefinition(
277+
name: nameNode("averageProductsCreatedPerYear"),
278+
type: typeNode("Int"),
279+
directives: [
280+
Directive(name: nameNode("requires"), arguments: [
281+
Argument(
282+
name: nameNode("fields"),
283+
value: StringValue(
284+
value: "totalProductsCreated yearsOfEmployment",
285+
block: false
286+
)
287+
),
288+
]),
289+
]
290+
),
291+
FieldDefinition(
292+
name: nameNode("email"),
293+
type: NonNullType(type: NamedType(name: nameNode("ID"))),
294+
directives: [
295+
Directive(name: nameNode("external")),
296+
]
297+
),
298+
FieldDefinition(name: nameNode("name"), type: typeNode("String"), directives: [
299+
Directive(name: nameNode("override"), arguments: [
300+
Argument(
301+
name: nameNode("from"),
302+
value: StringValue(value: "users", block: false)
303+
),
304+
]),
305+
]),
306+
FieldDefinition(
307+
name: nameNode("totalProductsCreated"),
308+
type: typeNode("Int"),
309+
directives: [
310+
Directive(name: nameNode("external")),
311+
]
312+
),
313+
FieldDefinition(
314+
name: nameNode("yearsOfEmployment"),
315+
type: NonNullType(type: typeNode("Int")),
316+
directives: [
317+
Directive(name: nameNode("external")),
318+
]
319+
),
320+
]
321+
))
322+
323+
let expected = Document(definitions: [
324+
schemaExtensionDefinition,
325+
productObjectTypeDefinition,
326+
deprecatedProductObjectTypeDefinition,
327+
productVariationObjectTypeDefinition,
328+
productResearchObjectTypeDefinition,
329+
caseStudyObjectTypeDefinition,
330+
productDimensionObjectTypeDefinition,
331+
queryExtensionObjectTypeDefinition,
332+
userExtensionObjectTypeDefinition,
333+
])
334+
335+
let result = try parse(source: source)
336+
XCTAssert(result == expected)
337+
}
338+
}

0 commit comments

Comments
 (0)