@@ -12,52 +12,57 @@ testVersions((api, version) => {
1212 {
1313 name : "billing" ,
1414 typeDefs : graphql `
15- extend schema
16- @link(
17- url: "https://specs.apollo.dev/federation/${ version } "
18- import: ["@override", "@external", "@provides"]
19- )
20- @link(url: "https://specs.apollo.dev", import: [{ name: "@key", as: "@renamed" }])
15+ extend schema
16+ @link(
17+ url: "https://specs.apollo.dev/federation/${ version } "
18+ import: ["@override", "@external", "@provides"]
19+ )
20+ @link(url: "https://specs.apollo.dev", import: [{ name: "@key", as: "@renamed" }])
2121
22- extend type Payment @key(fields: "id") {
23- id: ID!
24- amount: Int! @external
25- }
22+ extend type Payment @key(fields: "id") {
23+ id: ID!
24+ amount: Int! @external
25+ }
2626
27- type Invoice @key(fields: "id") {
28- id: ID!
29- amount: Int!
30- payment: Payment
31- }
32- ` ,
27+ type Invoice @key(fields: "id") {
28+ id: ID!
29+ amount: Int!
30+ payment: Payment
31+ }
32+ ` ,
3333 } ,
3434 {
3535 name : "payments" ,
3636 typeDefs : graphql `
37- extend schema
38- @link(
39- url: "https://specs.apollo.dev/federation/${ version } "
40- import: [{ name: "@key", as: "@renamed" }]
41- )
37+ extend schema
38+ @link(
39+ url: "https://specs.apollo.dev/federation/${ version } "
40+ import: [{ name: "@key", as: "@renamed" }]
41+ )
4242
43- type Query {
44- payments: [Payment]
45- }
43+ type Query {
44+ payments: [Payment]
45+ }
4646
47- type Payment @renamed(fields: "id") {
48- id: ID!
49- amount: Int!
50- }
51- ` ,
47+ type Payment @renamed(fields: "id") {
48+ id: ID!
49+ amount: Int!
50+ }
51+ ` ,
5252 } ,
5353 ] ) ,
5454 ) . toEqual (
5555 expect . objectContaining ( {
5656 errors : expect . arrayContaining ( [
5757 expect . objectContaining ( {
58- message : expect . stringMatching (
59- "Missing path in feature url 'https://specs.apollo.dev" ,
60- ) ,
58+ message :
59+ api . library === "guild"
60+ ? expect . stringContaining (
61+ "Invalid @link url 'https://specs.apollo.dev': expected '/<feature>/vX.Y' (for example '/federation/v2.9')" ,
62+ )
63+ : expect . stringContaining (
64+ "Missing path in feature url 'https://specs.apollo.dev/'" ,
65+ ) ,
6166 extensions : expect . objectContaining ( {
6267 code : "INVALID_LINK_IDENTIFIER" ,
6368 } ) ,
@@ -73,16 +78,14 @@ testVersions((api, version) => {
7378 typeDefs : graphql `
7479 extend schema
7580 @link(
76- url: "https://specs.apollo.dev/federation/not-a-version"
77- import: ["@override", "@external", "@provides"]
78- )
79- @link(
80- url: "https://specs.apollo.dev"
81- import: [{ name: "@key", as: "@renamed" }]
81+ url: "https://specs.apollo.dev/federation/${ version } "
82+ import: ["@override", "@external", "@provides", "@key", "@requires"]
8283 )
84+ @link(url: "https://specs.apollo.dev/federation/not-a-version", import: [{ name: "@key", as: "@renamed" }])
8385
8486 extend type Payment @key(fields: "id") {
8587 id: ID!
88+ tax: Int! @requires(fields: "amount")
8689 amount: Int! @external
8790 }
8891
@@ -98,7 +101,7 @@ testVersions((api, version) => {
98101 typeDefs : graphql `
99102 extend schema
100103 @link(
101- url: "https://specs.apollo.dev/federation/not-a- version"
104+ url: "https://specs.apollo.dev/federation/${ version } "
102105 import: [{ name: "@key", as: "@renamed" }]
103106 )
104107
@@ -118,15 +121,7 @@ testVersions((api, version) => {
118121 errors : expect . arrayContaining ( [
119122 expect . objectContaining ( {
120123 message : expect . stringContaining (
121- "[billing] Expected a version string (of the form v1.2), got not-a-version" ,
122- ) ,
123- extensions : expect . objectContaining ( {
124- code : "INVALID_LINK_IDENTIFIER" ,
125- } ) ,
126- } ) ,
127- expect . objectContaining ( {
128- message : expect . stringContaining (
129- "[payments] Expected a version string (of the form v1.2), got not-a-version" ,
124+ "Expected a version string (of the form v1.2), got" , // Hive correctly says "got null", apollo says "got not-a-version"
130125 ) ,
131126 extensions : expect . objectContaining ( {
132127 code : "INVALID_LINK_IDENTIFIER" ,
@@ -201,7 +196,7 @@ testVersions((api, version) => {
201196 ) ;
202197 } ) ;
203198
204- test ( " INVALID_LINK_DIRECTIVE_USAGE: unknown element" , ( ) => {
199+ test ( "INVALID_LINK_DIRECTIVE_USAGE: unknown element" , ( ) => {
205200 expect (
206201 api . composeServices ( [
207202 {
@@ -337,4 +332,84 @@ testVersions((api, version) => {
337332 ] ) ,
338333 ) ;
339334 } ) ;
335+
336+ /**
337+ * If url: is not a valid RFC 3986 url, then it MUST be treated as an opaque
338+ * identifier for the foreign schema. Such non‐URL inputs to url: SHOULD
339+ * NOT have name and version information extracted from them—both are null.
340+ * source: https://specs.apollo.dev/link/v1.0/#@link.url
341+ */
342+ api . runIf ( "guild" , ( ) => {
343+ test ( "Non-RFC 3986 url" , ( ) => {
344+ let result = api . composeServices ( [
345+ {
346+ name : "billing" ,
347+ typeDefs : graphql `
348+ extend schema
349+ @link(
350+ url: "https://specs.apollo.dev/federation/${ version } "
351+ import: ["@override", "@external", "@provides", "@key", "@requires", "@shareable"]
352+ )
353+ @link(url: "file:///foo/bar", import: ["Bar"])
354+
355+ scalar Bar
356+
357+ extend type Payment @key(fields: "id") {
358+ id: ID!
359+ tax: Int! @requires(fields: "amount")
360+ amount: Int! @external
361+ bar: Bar @shareable
362+ }
363+
364+ type Invoice @key(fields: "id") {
365+ id: ID!
366+ amount: Int!
367+ payment: Payment
368+ }
369+ ` ,
370+ } ,
371+ {
372+ name : "payments" ,
373+ typeDefs : graphql `
374+ extend schema
375+ @link(
376+ url: "https://specs.apollo.dev/federation/${ version } "
377+ import: [{ name: "@key", as: "@renamed" }, "@shareable"]
378+ )
379+ @link(url: "file:///foo/bar", import: ["Bar"])
380+
381+ scalar Bar
382+
383+ type Query {
384+ payments: [Payment]
385+ }
386+
387+ type Payment @renamed(fields: "id") {
388+ id: ID!
389+ amount: Int!
390+ bar: Bar @shareable
391+ }
392+ ` ,
393+ } ,
394+ ] ) ;
395+ assertCompositionSuccess ( result ) ;
396+
397+ expect ( result . supergraphSdl ) . toContainGraphQL ( /* GraphQL */ `
398+ scalar Bar @join__type(graph: BILLING) @join__type(graph: PAYMENTS)
399+ ` ) ;
400+
401+ expect ( result . supergraphSdl ) . toContainGraphQL ( /* GraphQL */ `
402+ type Payment
403+ @join__type(graph: BILLING, key: "id", extension: true)
404+ @join__type(graph: PAYMENTS, key: "id") {
405+ id: ID!
406+ tax: Int! @join__field(graph: BILLING, requires: "amount")
407+ amount: Int!
408+ @join__field(graph: BILLING, external: true)
409+ @join__field(graph: PAYMENTS)
410+ bar: Bar
411+ }
412+ ` ) ;
413+ } ) ;
414+ } ) ;
340415} ) ;
0 commit comments