From 61e7a4ce6451642889c61674cfd8c8b73d8fd964 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 10 Jul 2026 23:02:52 +0200 Subject: [PATCH 01/10] Apollo Federation V1 & V2 Compliance --- .../FederationSchemaTransformer.cs | 1 + .../ApolloFederation/RemoveEmptyQueryRoot.cs | 20 + .../SourceSchemaPreprocessor.cs | 6 + .../Completion/CompositeSchemaContext.cs | 14 +- .../Clients/HttpSourceSchemaClient.cs | 2 +- .../EmptyFederationQueryRootTests.cs | 188 + .../SchemaComposerTests.cs | 311 +- .../ComplexEntityCallSupplementalTests.cs | 58 + ...olvableInterfaceObjectSupplementalTests.cs | 33 + .../PartialUnionComplexSupplementalTests.cs | 53 + ...s.ApolloFederation.Compliance.Tests.csproj | 2 +- .../Infrastructure/AuditFixture.cs | 158 + .../Infrastructure/AuditTestCase.cs | 12 + .../Infrastructure/ComplianceTestBase.cs | 67 + .../Infrastructure/FusionGatewayBuilder.cs | 75 +- .../OfficialV2ComplianceTestBase.cs | 92 + .../OfficialV2SuiteAttribute.cs | 14 + .../SubgraphEndpointExtensions.cs | 9 +- .../OfficialAudit/OfficialAuditParityTests.cs | 121 + .../OfficialAudit/generate-v2-manifest.mjs | 194 + .../official-audit-deterministic-runtime.mjs | 1 + .../OfficialAudit/v2-manifest.json | 5128 +++++++++++++++++ .../AbstractTypes/AbstractTypesTests.cs | 1 + .../Suites/ChildTypeMismatch/A/User.cs | 5 +- .../Suites/ChildTypeMismatch/A/UserType.cs | 2 +- .../Suites/ChildTypeMismatch/B/Admin.cs | 4 +- .../Suites/ChildTypeMismatch/B/AdminType.cs | 2 +- .../ChildTypeMismatchTests.cs | 425 +- .../CircularReferenceInterface/A/BookType.cs | 6 +- .../CircularReferenceInterfaceTests.cs | 86 +- .../ComplexEntityCallTests.cs | 130 +- .../ComplexEntityCall/Products/ProductType.cs | 7 +- .../CorruptedSupergraphNodeId/B/Account.cs | 2 + .../B/AccountType.cs | 4 +- .../CorruptedSupergraphNodeId/B/QueryType.cs | 4 +- .../B/SubgraphBData.cs | 16 +- .../CorruptedSupergraphNodeIdTests.cs | 243 +- .../EnumIntersection/EnumIntersectionTests.cs | 114 +- .../Fed1ExternalExtendsTests.cs | 1 + .../Fed1ExternalExtendsResolvableTests.cs | 1 + .../Fed1ExternalExtensionTests.cs | 1 + .../Fed2ExternalExtendsTests.cs | 132 +- .../Fed2ExternalExtensionTests.cs | 132 +- .../Suites/IncludeSkip/B/ProductType.cs | 3 +- .../Suites/IncludeSkip/C/ProductType.cs | 3 +- .../Suites/IncludeSkip/IncludeSkipTests.cs | 101 +- .../InputObjectIntersectionTests.cs | 64 +- .../A/MediaInterfaceType.cs | 10 +- .../B/VideoType.cs | 11 +- .../InterfaceObjectIndirectExtensionTests.cs | 72 +- .../B/NodeWithNameType.cs | 21 +- .../InterfaceObjectWithRequiresTests.cs | 219 +- .../Suites/KeysMashup/KeysMashupTests.cs | 51 +- .../Suites/Mutations/A/ProductType.cs | 1 - .../Suites/Mutations/MutationsTests.cs | 123 +- .../Suites/Mutations/Shared/MutationsState.cs | 6 +- .../MysteriousExternalTests.cs | 67 +- .../MysteriousExternal/Price/ProductType.cs | 9 +- .../NestedProvides/AllProducts/ProductType.cs | 5 +- .../Category/CategoryEntityType.cs | 3 +- .../NestedProvides/Category/ProductType.cs | 3 +- .../NestedProvides/NestedProvidesTests.cs | 122 +- .../Subcategories/CategoryEntityType.cs | 12 +- .../Subcategories/ProductType.cs | 6 +- .../Subcategories/SubcategoriesData.cs | 25 +- .../Suites/Node/NodeTests.cs | 49 +- .../A/NodeImplType.cs | 7 +- .../NonResolvableInterfaceObjectTests.cs | 157 +- .../Suites/NullKeys/A/BookType.cs | 4 +- .../Suites/NullKeys/B/BookType.cs | 2 +- .../Suites/NullKeys/C/BookType.cs | 4 +- .../Suites/NullKeys/NullKeysTests.cs | 49 +- .../OverrideTypeInterfaceTests.cs | 120 +- .../Suites/OverrideWithRequires/A/UserType.cs | 19 +- .../Suites/OverrideWithRequires/C/UserType.cs | 19 +- .../OverrideWithRequiresTests.cs | 121 +- .../ParentEntityCall/ParentEntityCallTests.cs | 73 +- .../ParentEntityCallComplexTests.cs | 59 +- .../Suites/PartialUnion/PartialUnionTests.cs | 119 +- .../PartialUnionComplexTests.cs | 251 +- .../ProvidesOnInterfaceTests.cs | 77 +- .../ProvidesOnInterface/SubgraphA/BookType.cs | 23 +- .../ProvidesOnInterface/SubgraphA/CatType.cs | 8 +- .../ProvidesOnInterface/SubgraphA/Dog.cs | 2 + .../ProvidesOnInterface/SubgraphA/DogType.cs | 9 +- .../SubgraphA/QueryType.cs | 26 +- .../SubgraphA/SubgraphASubgraph.cs | 2 +- .../ProvidesOnInterface/SubgraphB/BookType.cs | 2 +- .../ProvidesOnInterface/SubgraphB/CatType.cs | 4 +- .../ProvidesOnInterface/SubgraphB/DogType.cs | 4 +- .../SubgraphB/QueryType.cs | 8 +- .../SubgraphB/SubgraphBSubgraph.cs | 2 +- .../ProvidesOnInterface/SubgraphC/DogType.cs | 2 +- .../SubgraphC/SubgraphCSubgraph.cs | 2 +- .../ProvidesOnUnion/ProvidesOnUnionTests.cs | 75 +- .../SubgraphA/SubgraphASubgraph.cs | 2 +- .../ProvidesOnUnion/SubgraphB/BookType.cs | 8 +- .../ProvidesOnUnion/SubgraphB/MovieType.cs | 5 +- .../ProvidesOnUnion/SubgraphB/QueryType.cs | 9 +- .../SubgraphB/SubgraphBSubgraph.cs | 2 +- .../SubgraphC/SubgraphCSubgraph.cs | 2 +- .../RequiresCircular/RequiresCircularTests.cs | 64 +- .../RequiresInterfaceTests.cs | 99 +- .../RequiresRequires/RequiresRequiresTests.cs | 129 +- .../RequiresWithArgument/A/ProductType.cs | 4 +- .../Suites/RequiresWithArgument/D/PostType.cs | 40 +- .../RequiresWithArgumentTests.cs | 203 +- .../A/ProductType.cs | 4 +- .../RequiresWithArgumentConflictTests.cs | 44 +- .../Suites/RequiresWithFragments/B/Entity.cs | 5 + .../RequiresWithFragments/B/EntityType.cs | 15 +- .../RequiresWithFragmentsTests.cs | 129 +- .../Suites/SharedRoot/SharedRootTests.cs | 79 +- .../SimpleEntityCall/SimpleEntityCallTests.cs | 30 +- .../SimpleInaccessibleTests.cs | 121 +- .../SimpleInterfaceObject/B/AccountType.cs | 5 +- .../B/NodeWithNameType.cs | 5 +- .../SimpleInterfaceObject/C/AccountType.cs | 3 +- .../SimpleInterfaceObjectTests.cs | 390 +- .../SimpleOverride/SimpleOverrideTests.cs | 71 +- .../Reviews/UserType.cs | 3 +- .../SimpleRequiresProvidesTests.cs | 374 +- .../Suites/Typename/TypenameTests.cs | 142 +- .../UnavailableOverrideTests.cs | 71 +- .../UnionInterfaceDistributedTests.cs | 227 +- .../UnionIntersectionTests.cs | 417 +- .../ApolloEntityBatchWireFormatTests.cs | 2 + .../WireFormat/LeftSubgraph.cs | 2 +- .../WireFormat/RightSubgraph.cs | 2 +- .../FusionSchemaDefinitionSourceTypeTests.cs | 203 + 130 files changed, 7271 insertions(+), 5753 deletions(-) create mode 100644 src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/RemoveEmptyQueryRoot.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Composition.ApolloFederation.Tests/EmptyFederationQueryRootTests.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/ComplexEntityCallSupplementalTests.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/NonResolvableInterfaceObjectSupplementalTests.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/PartialUnionComplexSupplementalTests.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2ComplianceTestBase.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2SuiteAttribute.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/OfficialAuditParityTests.cs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/generate-v2-manifest.mjs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/official-audit-deterministic-runtime.mjs create mode 100644 src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/v2-manifest.json create mode 100644 src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Types/FusionSchemaDefinitionSourceTypeTests.cs diff --git a/src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/FederationSchemaTransformer.cs b/src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/FederationSchemaTransformer.cs index 3b94a13a894..9fac12cbbc2 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/FederationSchemaTransformer.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/FederationSchemaTransformer.cs @@ -100,6 +100,7 @@ public static CompositionResult Transform(string federationSdl) RemoveExternalFields.Apply(schema); GenerateNodeLookup.Apply(schema); SourceExternalFieldMetadata.WriteMarker(schema); + RemoveEmptyQueryRoot.Apply(schema); return SchemaFormatter.FormatAsString(schema); } diff --git a/src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/RemoveEmptyQueryRoot.cs b/src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/RemoveEmptyQueryRoot.cs new file mode 100644 index 00000000000..27ed3e13fc6 --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Composition/ApolloFederation/RemoveEmptyQueryRoot.cs @@ -0,0 +1,20 @@ +using HotChocolate.Types.Mutable; + +namespace HotChocolate.Fusion.ApolloFederation; + +/// +/// Removes an empty query root from a mutable source schema. +/// +internal static class RemoveEmptyQueryRoot +{ + public static void Apply(MutableSchemaDefinition schema) + { + if (schema.QueryType is not { Fields.Count: 0 } emptyQueryRoot) + { + return; + } + + schema.Types.Remove(emptyQueryRoot); + schema.QueryType = null; + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Composition/SourceSchemaPreprocessor.cs b/src/HotChocolate/Fusion/src/Fusion.Composition/SourceSchemaPreprocessor.cs index 92412554275..f0db6082bcb 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Composition/SourceSchemaPreprocessor.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Composition/SourceSchemaPreprocessor.cs @@ -80,6 +80,11 @@ public CompositionResult Preprocess() ApplyShareableDirectives(); } + if (isFederationSchema) + { + RemoveEmptyQueryRoot.Apply(schema); + } + // Additional schema validation will catch issues introduced during preprocessing. It runs // while @external fields are still present so that the validator sees the source schema as // authored (modulo the earlier transforms); the external fields are stripped afterwards and @@ -97,6 +102,7 @@ public CompositionResult Preprocess() if (isFederationSchema) { RemoveExternalFields.Apply(schema); + RemoveEmptyQueryRoot.Apply(schema); } return log.HasErrors diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/CompositeSchemaContext.cs b/src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/CompositeSchemaContext.cs index 1177cdbe8d4..3136677b03d 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/CompositeSchemaContext.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/CompositeSchemaContext.cs @@ -14,7 +14,9 @@ internal sealed class CompositeSchemaBuilderContext : ICompositeSchemaBuilderCon #pragma warning disable IDE0052 // WIP private readonly DocumentNode _document; #pragma warning restore IDE0052 - private readonly Dictionary _compositeTypes = new(SyntaxComparer.BySyntax); + // A source type structure can be resolved against a differently named composite type. + // Both values are therefore part of the cache identity. + private readonly Dictionary> _compositeTypes = [with(StringComparer.Ordinal)]; private readonly Dictionary _typeDefinitionLookup; private ImmutableDictionary _typeDefinitionNodeLookup; private readonly Dictionary _directiveDefinitionLookup; @@ -138,10 +140,16 @@ public IType GetType(ITypeNode typeStructure, string? typeName = null) { typeName ??= typeStructure.NamedType().Name.Value; - if (!_compositeTypes.TryGetValue(typeStructure, out var type)) + if (!_compositeTypes.TryGetValue(typeName, out var typeLookup)) + { + typeLookup = [with(SyntaxComparer.BySyntax)]; + _compositeTypes.Add(typeName, typeLookup); + } + + if (!typeLookup.TryGetValue(typeStructure, out var type)) { type = CreateType(typeStructure, typeName); - _compositeTypes[typeStructure] = type; + typeLookup.Add(typeStructure, type); } return type; diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs index 9839830cc65..4d1b74a3307 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs @@ -37,7 +37,7 @@ public sealed class HttpSourceSchemaClient : ISourceSchemaClient /// The transport configuration for this source schema. /// /// Whether the GraphQL operation kind is annotated onto outgoing subgraph HTTP requests via - /// , so that delegating handlers (such as the + /// , so that delegating handlers (such as the /// RequestDeduplicationHandler) can consume it. false by default because materializing the /// request options bag allocates per request. /// diff --git a/src/HotChocolate/Fusion/test/Fusion.Composition.ApolloFederation.Tests/EmptyFederationQueryRootTests.cs b/src/HotChocolate/Fusion/test/Fusion.Composition.ApolloFederation.Tests/EmptyFederationQueryRootTests.cs new file mode 100644 index 00000000000..ba648db1631 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Composition.ApolloFederation.Tests/EmptyFederationQueryRootTests.cs @@ -0,0 +1,188 @@ +using HotChocolate.Serialization; +using HotChocolate.Types.Mutable; +using HotChocolate.Types.Mutable.Serialization; + +namespace HotChocolate.Fusion.ApolloFederation; + +public sealed class EmptyFederationQueryRootTests +{ + [Fact] + public void Transform_Should_RemoveSyntheticQuery_When_MutationOnlySchemaHasNoKey() + { + TransformAndDescribe( + """ + schema @link(url: "https://specs.apollo.dev/federation/v2.3") { + query: Query + mutation: Mutation + } + + type Query { + _service: _Service! + } + + type Mutation { + ping: Boolean + } + + type _Service { + sdl: String + } + + directive @link(url: String!) repeatable on SCHEMA + """).MatchInlineSnapshot( + """ + Query root: + Query fields: + Query description: + Query directives: + Mutation root: Mutation + Has Value type: False + Has Query type: False + Query field is lookup: False + """); + } + + [Fact] + public void Transform_Should_RemoveSyntheticQuery_When_ValueOnlySchemaHasNoKey() + { + TransformAndDescribe( + """ + schema @link(url: "https://specs.apollo.dev/federation/v2.3") { + query: Query + } + + type Query { + _service: _Service! + } + + type Value { + name: String + } + + type _Service { + sdl: String + } + + directive @link(url: String!) repeatable on SCHEMA + """).MatchInlineSnapshot( + """ + Query root: + Query fields: + Query description: + Query directives: + Mutation root: + Has Value type: True + Has Query type: False + Query field is lookup: False + """); + } + + [Fact] + public void Transform_Should_GenerateLookupQuery_When_TransportQueryHasResolvableKey() + { + TransformAndDescribe( + """" + schema @link(url: "https://specs.apollo.dev/federation/v2.3") { + query: Query + } + + """Transport query""" + type Query @audit { + _entities(representations: [_Any!]!): [_Entity]! + _service: _Service! + } + + type Product @key(fields: "id") { + id: ID! + } + + type _Service { + sdl: String + } + + union _Entity = Product + + scalar _Any + scalar FieldSet + + directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE + directive @audit on OBJECT + directive @link(url: String!) repeatable on SCHEMA + """").MatchInlineSnapshot( + """ + Query root: Query + Query fields: fusion__lookup_productById + Query description: Transport query + Query directives: audit + Mutation root: + Has Value type: False + Has Query type: True + Query field is lookup: True + """); + } + + [Fact] + public void Transform_Should_RetainQuery_When_QueryHasRealField() + { + TransformAndDescribe( + """ + schema @link(url: "https://specs.apollo.dev/federation/v2.3") { + query: Query + } + + type Query { + ping: Boolean + _service: _Service! + } + + type _Service { + sdl: String + } + + directive @link(url: String!) repeatable on SCHEMA + """).MatchInlineSnapshot( + """ + Query root: Query + Query fields: ping + Query description: + Query directives: + Mutation root: + Has Value type: False + Has Query type: True + Query field is lookup: False + """); + } + + private static string TransformAndDescribe(string sourceSchema) + { + var result = FederationSchemaTransformer.Transform(sourceSchema); + Assert.True(result.IsSuccess); + + var schema = SchemaParser.Parse(result.Value); + return Describe(schema); + } + + private static string Describe(MutableSchemaDefinition schema) + { + var queryType = schema.QueryType; + var queryFields = queryType is null + ? "" + : string.Join(", ", queryType.Fields.AsEnumerable().Select(field => field.Name)); + var queryDirectives = queryType is null || queryType.Directives.Count == 0 + ? "" + : string.Join(", ", queryType.Directives.AsEnumerable().Select(directive => directive.Name)); + var queryFieldIsLookup = queryType?.Fields.Count == 1 + && queryType.Fields[0].Directives.ContainsName("lookup"); + + return $""" + Query root: {queryType?.Name ?? ""} + Query fields: {queryFields} + Query description: {queryType?.Description ?? ""} + Query directives: {queryDirectives} + Mutation root: {schema.MutationType?.Name ?? ""} + Has Value type: {schema.Types.ContainsName("Value")} + Has Query type: {schema.Types.ContainsName("Query")} + Query field is lookup: {queryFieldIsLookup} + """; + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/SchemaComposerTests.cs b/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/SchemaComposerTests.cs index 7989fcf1d0c..a153e600449 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/SchemaComposerTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Composition.Tests/SchemaComposerTests.cs @@ -6,46 +6,30 @@ namespace HotChocolate.Fusion; public sealed class SchemaComposerTests { - [Theory] - [InlineData(NodeResolution.Gateway)] - [InlineData(NodeResolution.SourceSchema)] - public void Compose_Should_EmitExecutionMetadata(NodeResolution nodeResolution) + [Fact] + public void Compose_Should_EmitExecutionMetadataDefinitions() { - var options = new SchemaComposerOptions - { - Merger = - { - EnableGlobalObjectIdentification = nodeResolution is NodeResolution.SourceSchema, - NodeResolution = nodeResolution - } - }; + // arrange var composer = new SchemaComposer( [new SourceSchemaText("A", "type Query { ping: String }")], - options, + new SchemaComposerOptions(), new CompositionLog()); + // act var result = composer.Compose(); + // assert Assert.True(result.IsSuccess); var document = result.Value.ToSyntaxNode(); var executionMetadataDefinitions = new DocumentNode( - [ - document.Definitions.Single( - definition => definition is EnumTypeDefinitionNode - { - Name.Value: "fusion__NodeResolution" - }), - document.Definitions.Single( - definition => definition is EnumTypeDefinitionNode - { - Name.Value: "fusion__ShareableFieldRuntimeTypeRouting" - }), - document.Definitions.Single( - definition => definition is DirectiveDefinitionNode - { - Name.Value: "fusion__execution" - }) - ]); + document.Definitions + .Where(definition => definition is EnumTypeDefinitionNode + { + Name.Value: "fusion__NodeResolution" + or "fusion__ShareableFieldRuntimeTypeRouting" + } + or DirectiveDefinitionNode { Name.Value: "fusion__execution" }) + .ToArray()); executionMetadataDefinitions.ToString().MatchInlineSnapshot( """ @@ -64,7 +48,33 @@ directive @fusion__execution( shareableFieldRuntimeTypeRouting: fusion__ShareableFieldRuntimeTypeRouting! = SOURCE_LOCAL ) on SCHEMA """); + } + + [Theory] + [InlineData(NodeResolution.Gateway)] + [InlineData(NodeResolution.SourceSchema)] + public void Compose_Should_EmitNodeResolution(NodeResolution nodeResolution) + { + // arrange + var options = new SchemaComposerOptions + { + Merger = + { + EnableGlobalObjectIdentification = nodeResolution is NodeResolution.SourceSchema, + NodeResolution = nodeResolution + } + }; + var composer = new SchemaComposer( + [new SourceSchemaText("A", "type Query { ping: String }")], + options, + new CompositionLog()); + + // act + var result = composer.Compose(); + // assert + Assert.True(result.IsSuccess); + var document = result.Value.ToSyntaxNode(); var schemaDefinition = document.Definitions .OfType() .Single(); @@ -88,12 +98,12 @@ nodeResolution is NodeResolution.Gateway } [Theory] - [InlineData(ShareableFieldRuntimeTypeRouting.SourceLocal, "SOURCE_LOCAL")] - [InlineData(ShareableFieldRuntimeTypeRouting.CommonRuntimeTypes, "COMMON_RUNTIME_TYPES")] + [InlineData(ShareableFieldRuntimeTypeRouting.SourceLocal)] + [InlineData(ShareableFieldRuntimeTypeRouting.CommonRuntimeTypes)] public void Compose_Should_EmitShareableFieldRuntimeTypeRouting( - ShareableFieldRuntimeTypeRouting routing, - string expectedValue) + ShareableFieldRuntimeTypeRouting routing) { + // arrange var options = new SchemaComposerOptions { ApolloFederationCompatibility = { ShareableFieldRuntimeTypeRouting = routing } @@ -103,27 +113,38 @@ [new SourceSchemaText("A", "type Query { ping: String }")], options, new CompositionLog()); + // act var result = composer.Compose(); + // assert Assert.True(result.IsSuccess); var document = result.Value.ToSyntaxNode(); - var enumType = Assert.Single( - document.Definitions.OfType(), - definition => definition.Name.Value == "fusion__ShareableFieldRuntimeTypeRouting"); - Assert.Equal( - ["SOURCE_LOCAL", "COMMON_RUNTIME_TYPES"], - enumType.Values.Select(value => value.Name.Value)); - var schemaDefinition = Assert.Single(document.Definitions.OfType()); - var directive = Assert.Single( - schemaDefinition.Directives, - application => application.Name.Value == "fusion__execution"); - Assert.Equal(expectedValue, Assert.IsType( - directive.Arguments[1].Value).Value); + var schemaDefinition = document.Definitions + .OfType() + .Single(); + var executionApplication = schemaDefinition.Directives.Single( + directive => directive.Name.Value == "fusion__execution"); + + executionApplication.ToString().MatchInlineSnapshot( + routing is ShareableFieldRuntimeTypeRouting.SourceLocal + ? """ + @fusion__execution( + nodeResolution: GATEWAY + shareableFieldRuntimeTypeRouting: SOURCE_LOCAL + ) + """ + : """ + @fusion__execution( + nodeResolution: GATEWAY + shareableFieldRuntimeTypeRouting: COMMON_RUNTIME_TYPES + ) + """); } [Fact] - public void Compose_Should_Fail_When_SourceSchemaNodeResolutionIsDisabled() + public void Compose_Should_Fail_When_GlobalObjectIdentificationIsDisabledForSourceSchemaNodeResolution() { + // arrange var log = new CompositionLog(); var options = new SchemaComposerOptions { @@ -134,20 +155,28 @@ [new SourceSchemaText("A", "type Query { ping: String }")], options, log); + // act var result = composer.Compose(); + // assert Assert.True(result.IsFailure); - var entry = Assert.Single(log); - Assert.Equal(LogEntryCodes.InvalidNodeResolution, entry.Code); - Assert.Equal(LogSeverity.Error, entry.Severity); - Assert.Equal( - "Source-schema node resolution requires global object identification to be enabled.", - entry.Message); + log.Select(e => e.ToString()).MatchInlineSnapshots( + [ + """ + { + "message": "Source-schema node resolution requires global object identification to be enabled.", + "code": "INVALID_NODE_RESOLUTION", + "severity": "Error", + "extensions": {} + } + """ + ]); } [Fact] public void Compose_Should_Fail_When_NodeResolutionIsInvalid() { + // arrange var log = new CompositionLog(); var options = new SchemaComposerOptions { @@ -158,17 +187,28 @@ [new SourceSchemaText("A", "type Query { ping: String }")], options, log); + // act var result = composer.Compose(); + // assert Assert.True(result.IsFailure); - var entry = Assert.Single(log); - Assert.Equal(LogEntryCodes.InvalidNodeResolution, entry.Code); - Assert.Equal("The node resolution mode '42' is invalid.", entry.Message); + log.Select(e => e.ToString()).MatchInlineSnapshots( + [ + """ + { + "message": "The node resolution mode '42' is invalid.", + "code": "INVALID_NODE_RESOLUTION", + "severity": "Error", + "extensions": {} + } + """ + ]); } [Fact] public void Compose_Should_Fail_When_ShareableFieldRuntimeTypeRoutingIsInvalid() { + // arrange var log = new CompositionLog(); var options = new SchemaComposerOptions { @@ -182,14 +222,22 @@ [new SourceSchemaText("A", "type Query { ping: String }")], options, log); + // act var result = composer.Compose(); + // assert Assert.True(result.IsFailure); - var entry = Assert.Single(log); - Assert.Equal(LogEntryCodes.InvalidShareableFieldRuntimeTypeRouting, entry.Code); - Assert.Equal( - "The shareable field runtime type routing mode '42' is invalid.", - entry.Message); + log.Select(e => e.ToString()).MatchInlineSnapshots( + [ + """ + { + "message": "The shareable field runtime type routing mode '42' is invalid.", + "code": "INVALID_SHAREABLE_FIELD_RUNTIME_TYPE_ROUTING", + "severity": "Error", + "extensions": {} + } + """ + ]); } [Fact] @@ -290,8 +338,42 @@ type Query { var result = schemaComposer.Compose(); // assert + // The schema validator reports the same HCV0011 warning once per validation pass, so the + // log carries two identical entries. Assert.True(result.IsSuccess); - Assert.Contains(log, e => e.Code == "HCV0011" && e.Severity == LogSeverity.Warning); + log.Select(e => e.ToString()).MatchInlineSnapshots( + [ + """ + { + "message": "The field 'User.name' must not be deprecated without the corresponding field in the interface 'Node' being deprecated. (Schema: 'A')", + "code": "HCV0011", + "severity": "Warning", + "coordinate": "User.name", + "member": "name", + "schema": "A", + "extensions": { + "field": "name", + "implementedField": "name", + "specifiedBy": "https://spec.graphql.org/September2025/#sec-Objects.Type-Validation" + } + } + """, + """ + { + "message": "The field 'User.name' must not be deprecated without the corresponding field in the interface 'Node' being deprecated. (Schema: 'A')", + "code": "HCV0011", + "severity": "Warning", + "coordinate": "User.name", + "member": "name", + "schema": "A", + "extensions": { + "field": "name", + "implementedField": "name", + "specifiedBy": "https://spec.graphql.org/September2025/#sec-Objects.Type-Validation" + } + } + """ + ]); } [Fact] @@ -339,7 +421,24 @@ type Query { // assert Assert.True(result.IsFailure); - Assert.Contains(log, e => e.Code == "HCV0011" && e.Severity == LogSeverity.Error); + log.Select(e => e.ToString()).MatchInlineSnapshots( + [ + """ + { + "message": "The field 'User.name' must not be deprecated without the corresponding field in the interface 'Node' being deprecated. (Schema: 'A')", + "code": "HCV0011", + "severity": "Error", + "coordinate": "User.name", + "member": "name", + "schema": "A", + "extensions": { + "field": "name", + "implementedField": "name", + "specifiedBy": "https://spec.graphql.org/September2025/#sec-Objects.Type-Validation" + } + } + """ + ]); } [Fact] @@ -394,11 +493,27 @@ type User { // assert Assert.True(result.IsFailure); - Assert.Contains(log, e => e.Code == LogEntryCodes.UnsatisfiableQueryPath); + // Two distinct unsatisfiable paths are reported; order them so the snapshot is stable + // regardless of the order the validator emits them in. + log.Select(e => e.Message) + .Order(StringComparer.Ordinal) + .MatchInlineSnapshots( + [ + """ + Unable to access the field 'User.membershipStatus'. + Unable to transition between schemas 'A' and 'B' for access to field 'B:User.membershipStatus'. + No lookups found for type 'User' in schema 'B'. + """, + """ + Unable to access the field 'User.name'. + Unable to transition between schemas 'B' and 'A' for access to field 'A:User.name'. + No lookups found for type 'User' in schema 'A'. + """ + ]); } [Fact] - public void Compose_LookupFieldWithoutArguments_FailsWithLookupMustHaveArgumentsError() + public void Compose_Should_FailWithLookupMustHaveArgumentsError_When_LookupFieldHasNoArguments() { // arrange var log = new CompositionLog(); @@ -425,16 +540,24 @@ type Product { // assert Assert.True(result.IsFailure); - var entry = Assert.Single(log); - Assert.Equal(LogEntryCodes.LookupMustHaveArguments, entry.Code); - Assert.Equal(LogSeverity.Error, entry.Severity); - Assert.Equal( - "The lookup field 'Query.product' in schema 'A' must declare at least one argument.", - entry.Message); + log.Select(e => e.ToString()).MatchInlineSnapshots( + [ + """ + { + "message": "The lookup field 'Query.product' in schema 'A' must declare at least one argument.", + "code": "LOOKUP_MUST_HAVE_ARGUMENTS", + "severity": "Error", + "coordinate": "Query.product", + "member": "product", + "schema": "A", + "extensions": {} + } + """ + ]); } [Fact] - public void Compose_OrphanedTypeAfterTagExclusion_DoesNotProduceShareableError() + public void Compose_Should_NotProduceShareableError_When_TagExclusionOrphansType() { // arrange // Schema A's Product is only reachable via Mutation. When Mutation is removed by @@ -499,12 +622,50 @@ type Product { // assert Assert.True(result.IsSuccess); - Assert.False(result.Value.Types.ContainsName("Mutation")); - Assert.True(result.Value.Types.ContainsName("Product")); + result.Value.MatchInlineSnapshot( + """ + schema { + query: Query + } + + type Query @fusion__type(schema: A) @fusion__type(schema: B) { + book(id: ID! @fusion__inputField(schema: A)): Book @fusion__field(schema: A) + productById(id: ID! @fusion__inputField(schema: B)): Product + @fusion__field(schema: B) + } + + type Book + @fusion__type(schema: A) + @fusion__lookup( + schema: A + key: "id" + field: "book(id: ID!): Book" + map: ["id"] + path: null + internal: false + ) { + id: ID! @fusion__field(schema: A) + title: String! @fusion__field(schema: A) + } + + type Product + @fusion__type(schema: B) + @fusion__lookup( + schema: B + key: "id" + field: "productById(id: ID!): Product" + map: ["id"] + path: null + internal: false + ) { + id: ID! @fusion__field(schema: B) + name: String! @fusion__field(schema: B) + } + """); } [Fact] - public void Compose_WithExtensions_AppliesExtensions() + public void Compose_Should_ApplyExtensions_When_ExtensionsAreProvided() { // arrange var schemaComposer = new SchemaComposer( diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/ComplexEntityCallSupplementalTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/ComplexEntityCallSupplementalTests.cs new file mode 100644 index 00000000000..0ed54842727 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/ComplexEntityCallSupplementalTests.cs @@ -0,0 +1,58 @@ +using HotChocolate.Fusion.Suites.ComplexEntityCall.Link; +using HotChocolate.Fusion.Suites.ComplexEntityCall.List; +using HotChocolate.Fusion.Suites.ComplexEntityCall.Price; +using HotChocolate.Fusion.Suites.ComplexEntityCall.Products; + +namespace HotChocolate.Fusion.AdditionalCoverage; + +public sealed class ComplexEntityCallSupplementalTests : ComplianceTestBase +{ + protected override Task BuildGatewayAsync() + => FusionGatewayBuilder.ComposeAsync( + (LinkSubgraph.Name, LinkSubgraph.BuildAsync), + (ListSubgraph.Name, ListSubgraph.BuildAsync), + (PriceSubgraph.Name, PriceSubgraph.BuildAsync), + (ProductsSubgraph.Name, ProductsSubgraph.BuildAsync)); + + [Fact] + [Trait("Category", "Supplemental")] + public Task TopProducts_Should_ResolveNestedCategoryKey_When_Queried() => RunAsync( + query: """ + query { + topProducts { + products { + id + category { + mainProduct { id } + id + tag + } + } + } + } + """, + expectedData: """ + { + "topProducts": { + "products": [ + { + "id": "1", + "category": { + "mainProduct": { "id": "1" }, + "id": "c1", + "tag": "t1" + } + }, + { + "id": "2", + "category": { + "mainProduct": { "id": "2" }, + "id": "c2", + "tag": "t2" + } + } + ] + } + } + """); +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/NonResolvableInterfaceObjectSupplementalTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/NonResolvableInterfaceObjectSupplementalTests.cs new file mode 100644 index 00000000000..f31f5c7e183 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/NonResolvableInterfaceObjectSupplementalTests.cs @@ -0,0 +1,33 @@ +using HotChocolate.Execution; +using HotChocolate.Fusion.Execution; +using HotChocolate.Fusion.Suites.NonResolvableInterfaceObject.A; +using HotChocolate.Fusion.Suites.NonResolvableInterfaceObject.B; + +namespace HotChocolate.Fusion.AdditionalCoverage; + +public sealed class NonResolvableInterfaceObjectSupplementalTests +{ + [Fact] + [Trait("Category", "Supplemental")] + public async Task Gateway_Should_NotCallSource_When_InterfaceObjectIsNotResolvable() + { + var testCase = AuditFixture.GetOfficialV2Case("non-resolvable-interface-object/001"); + var capture = new SubgraphRequestCapture(); + await using var gateway = await FusionGatewayBuilder.ComposeAsync( + capture, + sourceSchemaSettings: null, + NodeResolution.Gateway, + allowNonResolvableInterfaceObjects: true, + ShareableFieldRuntimeTypeRouting.SourceLocal, + (ASubgraph.Name, ASubgraph.BuildAsync), + (BSubgraph.Name, BSubgraph.BuildAsync)); + + var result = await gateway.Executor.ExecuteAsync( + testCase.Query, + TestContext.Current.CancellationToken); + var json = result.ToJson(withIndentations: false); + + AuditAssertions.Assert(json, expectedDataJson: "null", expectsErrors: true); + Assert.Empty(capture.Requests); + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/PartialUnionComplexSupplementalTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/PartialUnionComplexSupplementalTests.cs new file mode 100644 index 00000000000..bef385ac106 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/AdditionalCoverage/PartialUnionComplexSupplementalTests.cs @@ -0,0 +1,53 @@ +using HotChocolate.Fusion.Options; +using HotChocolate.Fusion.Suites.PartialUnionComplex.A; +using HotChocolate.Fusion.Suites.PartialUnionComplex.B; + +namespace HotChocolate.Fusion.AdditionalCoverage; + +public sealed class PartialUnionComplexSupplementalTests : ComplianceTestBase +{ + protected override Task BuildGatewayAsync() + => FusionGatewayBuilder.ComposeAsync( + new ApolloFederationCompatibilityOptions + { + ShareableFieldRuntimeTypeRouting = + ShareableFieldRuntimeTypeRouting.CommonRuntimeTypes + }, + (ASubgraph.Name, ASubgraph.BuildAsync), + (BSubgraph.Name, BSubgraph.BuildAsync)); + + [Fact] + [Trait("Category", "Supplemental")] + public Task SharedActions_Should_UseCommonRuntimeTypes_When_RootHasMultipleProviders() + => RunAsync( + query: """ + query { + sharedActions { + __typename + ... on Common { + label + } + ... on OnlyA { + a + } + ... on OnlyB { + b + } + } + } + """, + expectedData: """ + { + "sharedActions": [ + { + "__typename": "Common", + "label": "common label" + }, + { + "__typename": "OnlyA", + "a": null + } + ] + } + """); +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/HotChocolate.Fusion.Connectors.ApolloFederation.Compliance.Tests.csproj b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/HotChocolate.Fusion.Connectors.ApolloFederation.Compliance.Tests.csproj index d36830934e9..ce7d3ed8b6c 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/HotChocolate.Fusion.Connectors.ApolloFederation.Compliance.Tests.csproj +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/HotChocolate.Fusion.Connectors.ApolloFederation.Compliance.Tests.csproj @@ -20,7 +20,7 @@ - + diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditFixture.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditFixture.cs index fb3de84235f..0d62675e369 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditFixture.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditFixture.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Text.Json; namespace HotChocolate.Fusion; @@ -13,8 +14,53 @@ internal static class AuditFixture { private const string SuitesPath = "Suites"; private const string ReferencePath = "Reference"; + private const string OfficialV2ManifestResource = + "HotChocolate.Fusion.OfficialAudit.v2-manifest.json"; private static readonly Assembly s_assembly = typeof(AuditFixture).Assembly; private static readonly string s_assemblyName = s_assembly.GetName().Name!; + private static readonly Lazy s_officialV2Manifest = + new(LoadOfficialV2Manifest); + + public static TheoryData GetOfficialV2CaseIds() + { + var suite = GetOfficialV2Suite(); + var cases = new TheoryData(); + + foreach (var testCase in suite.Cases) + { + cases.Add(testCase.Id); + } + + return cases; + } + + public static AuditTestCase GetOfficialV2Case(string caseId) + { + ArgumentException.ThrowIfNullOrEmpty(caseId); + + return GetOfficialV2Suite().Cases.Single(testCase => testCase.Id == caseId); + } + + public static AuditTestCase GetOfficialV2Case(string caseId) + { + ArgumentException.ThrowIfNullOrEmpty(caseId); + + return s_officialV2Manifest.Value.Suites + .SelectMany(suite => suite.Cases) + .Single(testCase => testCase.Id == caseId); + } + + public static IReadOnlyList GetOfficialV2SourceSchemas() + => GetOfficialV2Suite().Sources; + + public static OfficialV2Manifest GetOfficialV2Manifest() + => s_officialV2Manifest.Value; + + public static OfficialV2SuiteAttribute GetOfficialV2SuiteAttribute() + => typeof(TSuite) + .GetCustomAttribute() + ?? throw new InvalidOperationException( + $"Test class '{typeof(TSuite).FullName}' has no OfficialV2SuiteAttribute."); /// /// Reads an embedded reference text file for the specified audit suite. @@ -55,4 +101,116 @@ private static string BuildResourceName(string suiteName, string relativePath) var normalized = relativePath.Replace('/', '.').Replace('\\', '.'); return $"{s_assemblyName}.{SuitesPath}.{suiteName}.{ReferencePath}.{normalized}"; } + + private static OfficialV2Suite GetOfficialV2Suite() + { + var suiteId = GetOfficialV2SuiteAttribute().Id; + + return s_officialV2Manifest.Value.Suites.Single(suite => suite.Id == suiteId); + } + + private static OfficialV2Manifest LoadOfficialV2Manifest() + { + using var stream = s_assembly.GetManifestResourceStream(OfficialV2ManifestResource) + ?? throw new FileNotFoundException( + $"Embedded official audit manifest '{OfficialV2ManifestResource}' was not found.", + OfficialV2ManifestResource); + using var document = JsonDocument.Parse(stream); + var root = document.RootElement; + var suites = new List(); + var excludedV1DependentSuites = new List(); + + foreach (var excludedElement in root + .GetProperty("excludedV1DependentSuites") + .EnumerateArray()) + { + excludedV1DependentSuites.Add(new OfficialV1DependentSuite( + excludedElement.GetProperty("id").GetString()!, + excludedElement.GetProperty("caseCount").GetInt32(), + excludedElement + .GetProperty("v1Sources") + .EnumerateArray() + .Select(source => source.GetString()!) + .ToArray())); + } + + foreach (var suiteElement in root.GetProperty("suites").EnumerateArray()) + { + var suiteId = suiteElement.GetProperty("id").GetString()!; + var cases = new List(); + var sources = new List(); + var fixtureModules = new List(); + + foreach (var caseElement in suiteElement.GetProperty("cases").EnumerateArray()) + { + var variables = caseElement.GetProperty("variables"); + var expectedData = caseElement.GetProperty("expectedData"); + var expectsErrors = caseElement.GetProperty("expectsErrors"); + + cases.Add(new AuditTestCase( + caseElement.GetProperty("id").GetString()!, + caseElement.GetProperty("query").GetString()!, + variables.ValueKind is JsonValueKind.Null + ? null + : variables.GetRawText(), + caseElement.GetProperty("hasExpectedData").GetBoolean(), + expectedData.ValueKind is JsonValueKind.Null + ? null + : expectedData.GetRawText(), + caseElement.GetProperty("hasExpectedErrors").GetBoolean(), + expectsErrors.ValueKind is JsonValueKind.Null + ? null + : expectsErrors.GetBoolean())); + } + + foreach (var sourceElement in suiteElement.GetProperty("sources").EnumerateArray()) + { + sources.Add(new OfficialV2SourceSchema( + sourceElement.GetProperty("name").GetString()!, + sourceElement.GetProperty("rawSdl").GetString()!, + sourceElement.GetProperty("serviceSdl").GetString()!)); + } + + foreach (var moduleElement in suiteElement + .GetProperty("fixtureModules") + .EnumerateArray()) + { + fixtureModules.Add(new OfficialFixtureModule( + moduleElement.GetProperty("path").GetString()!, + moduleElement.GetProperty("sha256").GetString()!, + moduleElement.GetProperty("source").GetString()!)); + } + + suites.Add(new OfficialV2Suite(suiteId, cases, sources, fixtureModules)); + } + + return new OfficialV2Manifest( + root.GetProperty("revision").GetString()!, + root.GetProperty("suiteCount").GetInt32(), + root.GetProperty("caseCount").GetInt32(), + suites, + excludedV1DependentSuites); + } } + +internal sealed record OfficialV2Manifest( + string Revision, + int SuiteCount, + int CaseCount, + IReadOnlyList Suites, + IReadOnlyList ExcludedV1DependentSuites); + +internal sealed record OfficialV2Suite( + string Id, + IReadOnlyList Cases, + IReadOnlyList Sources, + IReadOnlyList FixtureModules); + +internal sealed record OfficialV2SourceSchema(string Name, string RawSdl, string ServiceSdl); + +internal sealed record OfficialFixtureModule(string Path, string Sha256, string Source); + +internal sealed record OfficialV1DependentSuite( + string Id, + int CaseCount, + IReadOnlyList V1Sources); diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditTestCase.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditTestCase.cs index a2c06db9cba..b8594d5aa88 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditTestCase.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/AuditTestCase.cs @@ -4,16 +4,28 @@ namespace HotChocolate.Fusion; /// Describes a single federation-gateway-audit test case: /// a GraphQL query and its expected response (data and/or errors). /// +/// The stable official suite and ordered case identifier. /// The GraphQL operation to execute against the gateway. +/// The optional JSON object containing operation variables. +/// +/// Indicates whether the upstream test explicitly declares a data member. +/// /// /// The expected JSON payload of the data field, or if the /// assertion should not compare the data payload. /// +/// +/// Indicates whether the upstream test explicitly declares an errors member. +/// /// /// If not , the test asserts whether an errors array is /// present on the response. /// public sealed record AuditTestCase( + string Id, string Query, + string? Variables, + bool HasExpectedData, string? ExpectedData, + bool HasExpectedErrors, bool? ExpectsErrors); diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/ComplianceTestBase.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/ComplianceTestBase.cs index fbb91d67bc3..00efeae3d61 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/ComplianceTestBase.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/ComplianceTestBase.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using HotChocolate.Execution; namespace HotChocolate.Fusion; @@ -46,6 +47,43 @@ protected async Task RunAsync( AuditAssertions.Assert(json, expectedData, expectsErrors); } + protected async Task RunAsync(AuditTestCase testCase) + { + ArgumentNullException.ThrowIfNull(testCase); + + _gateway ??= await BuildGatewayAsync(); + await ExecuteAndAssertAsync( + _gateway, + testCase, + TestContext.Current.CancellationToken); + } + + internal static async Task ExecuteAndAssertAsync( + FusionGateway gateway, + AuditTestCase testCase, + CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(gateway); + ArgumentNullException.ThrowIfNull(testCase); + + var request = OperationRequestBuilder.New().SetDocument(testCase.Query); + + if (testCase.Variables is not null) + { + request.SetVariableValues(ParseVariables(testCase.Variables)); + } + + var result = await gateway.Executor.ExecuteAsync( + request.Build(), + cancellationToken); + var json = result.ToJson(withIndentations: false); + + AuditAssertions.Assert( + json, + testCase.HasExpectedData ? testCase.ExpectedData : null, + testCase.HasExpectedErrors ? testCase.ExpectsErrors : null); + } + /// public ValueTask InitializeAsync() => ValueTask.CompletedTask; @@ -58,4 +96,33 @@ public async ValueTask DisposeAsync() _gateway = null; } } + + private static IReadOnlyDictionary ParseVariables(string json) + { + using var document = JsonDocument.Parse(json); + + if (document.RootElement.ValueKind is not JsonValueKind.Object) + { + throw new InvalidOperationException("Official audit variables must be a JSON object."); + } + + return (IReadOnlyDictionary)ParseValue(document.RootElement)!; + } + + private static object? ParseValue(JsonElement element) + => element.ValueKind switch + { + JsonValueKind.Object => element + .EnumerateObject() + .ToDictionary(property => property.Name, property => ParseValue(property.Value)), + JsonValueKind.Array => element.EnumerateArray().Select(ParseValue).ToArray(), + JsonValueKind.String => element.GetString(), + JsonValueKind.Number when element.TryGetInt64(out var value) => value, + JsonValueKind.Number => element.GetDouble(), + JsonValueKind.True => true, + JsonValueKind.False => false, + JsonValueKind.Null => null, + _ => throw new InvalidOperationException( + $"Unsupported official audit variable value kind '{element.ValueKind}'.") + }; } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/FusionGatewayBuilder.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/FusionGatewayBuilder.cs index d8a033e00c2..6faf2ded086 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/FusionGatewayBuilder.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/FusionGatewayBuilder.cs @@ -145,7 +145,39 @@ public static Task ComposeAsync( /// Determines how the gateway resolves the Query.node field. /// /// Named subgraph factories. - public static async Task ComposeAsync( + public static Task ComposeAsync( + SubgraphRequestCapture? capture, + IReadOnlyDictionary? sourceSchemaSettings, + NodeResolution nodeResolution, + bool allowNonResolvableInterfaceObjects, + ShareableFieldRuntimeTypeRouting shareableFieldRuntimeTypeRouting, + params (string Name, Func> Factory)[] subgraphs) + => ComposeAsync( + officialSourceSchemas: null, + capture, + sourceSchemaSettings, + nodeResolution, + allowNonResolvableInterfaceObjects, + shareableFieldRuntimeTypeRouting, + subgraphs); + + public static Task ComposeOfficialV2Async( + params (string Name, Func> Factory)[] subgraphs) + { + var suite = AuditFixture.GetOfficialV2SuiteAttribute(); + + return ComposeAsync( + AuditFixture.GetOfficialV2SourceSchemas(), + capture: null, + sourceSchemaSettings: null, + suite.NodeResolution, + suite.AllowNonResolvableInterfaceObjects, + suite.ShareableFieldRuntimeTypeRouting, + subgraphs); + } + + private static async Task ComposeAsync( + IReadOnlyList? officialSourceSchemas, SubgraphRequestCapture? capture, IReadOnlyDictionary? sourceSchemaSettings, NodeResolution nodeResolution, @@ -162,14 +194,27 @@ public static async Task ComposeAsync( nameof(subgraphs)); } + if (officialSourceSchemas is not null) + { + var officialSourceNames = officialSourceSchemas.Select(source => source.Name); + var localSourceNames = subgraphs.Select(subgraph => subgraph.Name); + + if (!officialSourceNames.SequenceEqual(localSourceNames, StringComparer.Ordinal)) + { + throw new InvalidOperationException( + "Local subgraph names and order must exactly match the official audit manifest."); + } + } + var hosts = new List(subgraphs.Length); var sourceSchemaTexts = new List(subgraphs.Length); var subgraphInfos = new List(subgraphs.Length); try { - foreach (var (name, factory) in subgraphs) + for (var i = 0; i < subgraphs.Length; i++) { + var (name, factory) = subgraphs[i]; var host = await factory().ConfigureAwait(false); if (!string.Equals(host.Name, name, StringComparison.Ordinal)) @@ -180,7 +225,12 @@ public static async Task ComposeAsync( hosts.Add(host); - var info = await BuildSubgraphInfoAsync(host).ConfigureAwait(false); + var info = officialSourceSchemas is null + ? await BuildSubgraphInfoAsync(host).ConfigureAwait(false) + : new SubgraphInfo( + name, + officialSourceSchemas[i].ServiceSdl, + SubgraphAddress(name)); sourceSchemaTexts.Add(new SourceSchemaText(name, info.SourceSchemaSdl)); subgraphInfos.Add(info); @@ -192,7 +242,10 @@ public static async Task ComposeAsync( nodeResolution, allowNonResolvableInterfaceObjects, shareableFieldRuntimeTypeRouting); - var settings = BuildGatewaySettings(subgraphInfos, sourceSchemaSettings); + var settings = BuildGatewaySettings( + subgraphInfos, + sourceSchemaSettings, + disableBatching: officialSourceSchemas is not null); var gatewayServices = new ServiceCollection(); gatewayServices.AddSingleton( @@ -360,7 +413,8 @@ private static DocumentNode ComposeSchema( private static JsonDocumentOwner BuildGatewaySettings( IReadOnlyList subgraphs, - IReadOnlyDictionary? sourceSchemaSettings) + IReadOnlyDictionary? sourceSchemaSettings, + bool disableBatching) { var buffer = new ArrayBufferWriter(); @@ -376,6 +430,17 @@ private static JsonDocumentOwner BuildGatewaySettings( writer.WriteStartObject("transports"); writer.WriteStartObject("http"); writer.WriteString("url", subgraph.BaseAddress.ToString()); + + if (disableBatching) + { + writer.WriteStartObject("capabilities"); + writer.WriteStartObject("batching"); + writer.WriteBoolean("variableBatching", false); + writer.WriteBoolean("requestBatching", false); + writer.WriteEndObject(); + writer.WriteEndObject(); + } + writer.WriteEndObject(); writer.WriteEndObject(); diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2ComplianceTestBase.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2ComplianceTestBase.cs new file mode 100644 index 00000000000..a62a8a5930f --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2ComplianceTestBase.cs @@ -0,0 +1,92 @@ +using System.Runtime.ExceptionServices; + +namespace HotChocolate.Fusion; + +public abstract class OfficialV2ComplianceTestBase : ComplianceTestBase + where TSuite : OfficialV2ComplianceTestBase +{ + public static TheoryData Cases => AuditFixture.GetOfficialV2CaseIds(); + + protected Task RunOfficialV2CaseAsync(string caseId) + => OfficialV2SuiteRun.AssertCaseAsync(caseId, BuildGatewayAsync); + + protected Task ComposeOfficialV2Async( + params (string Name, Func> Factory)[] subgraphs) + => FusionGatewayBuilder.ComposeOfficialV2Async(subgraphs); +} + +internal static class OfficialV2SuiteRun +{ + private static readonly object s_sync = new(); + private static Lazy>>? s_run; + + public static async Task AssertCaseAsync( + string caseId, + Func> buildGatewayAsync) + { + var run = Volatile.Read(ref s_run); + + if (run is null) + { + lock (s_sync) + { + run = s_run ??= new Lazy>>( + () => ExecuteSuiteAsync(buildGatewayAsync), + LazyThreadSafetyMode.ExecutionAndPublication); + } + } + + var outcomes = await run.Value.ConfigureAwait(false); + + if (outcomes[caseId] is { } error) + { + error.Throw(); + } + } + + private static async Task> ExecuteSuiteAsync( + Func> buildGatewayAsync) + { + var suite = AuditFixture.GetOfficialV2Manifest().Suites.Single( + candidate => candidate.Id == AuditFixture.GetOfficialV2SuiteAttribute().Id); + var outcomes = new Dictionary(StringComparer.Ordinal); + FusionGateway gateway; + + try + { + gateway = await buildGatewayAsync().ConfigureAwait(false); + } + catch (Exception exception) + { + var error = ExceptionDispatchInfo.Capture(exception); + + foreach (var testCase in suite.Cases) + { + outcomes.Add(testCase.Id, error); + } + + return outcomes; + } + + await using (gateway.ConfigureAwait(false)) + { + foreach (var testCase in suite.Cases) + { + try + { + await ComplianceTestBase.ExecuteAndAssertAsync( + gateway, + testCase, + CancellationToken.None).ConfigureAwait(false); + outcomes.Add(testCase.Id, null); + } + catch (Exception exception) + { + outcomes.Add(testCase.Id, ExceptionDispatchInfo.Capture(exception)); + } + } + } + + return outcomes; + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2SuiteAttribute.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2SuiteAttribute.cs new file mode 100644 index 00000000000..3b462aad6f2 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/OfficialV2SuiteAttribute.cs @@ -0,0 +1,14 @@ +namespace HotChocolate.Fusion; + +[AttributeUsage(AttributeTargets.Class, Inherited = false)] +public sealed class OfficialV2SuiteAttribute(string id) : Attribute +{ + public string Id { get; } = id; + + public NodeResolution NodeResolution { get; set; } = NodeResolution.Gateway; + + public bool AllowNonResolvableInterfaceObjects { get; set; } + + public ShareableFieldRuntimeTypeRouting ShareableFieldRuntimeTypeRouting { get; set; } = + ShareableFieldRuntimeTypeRouting.SourceLocal; +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/SubgraphEndpointExtensions.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/SubgraphEndpointExtensions.cs index a4eb755b74b..b24d1c643f1 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/SubgraphEndpointExtensions.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Infrastructure/SubgraphEndpointExtensions.cs @@ -17,10 +17,15 @@ internal static class SubgraphEndpointExtensions /// required. /// /// The subgraph web application. - public static void MapSubgraph(this WebApplication app) + public static void MapSubgraph(this WebApplication app, bool enableBatching = false) { ArgumentNullException.ThrowIfNull(app); - app.MapGraphQL().WithOptions(o => o.Batching = AllowedBatching.All); + var endpoint = app.MapGraphQL(); + + if (enableBatching) + { + endpoint.WithOptions(o => o.Batching = AllowedBatching.All); + } } } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/OfficialAuditParityTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/OfficialAuditParityTests.cs new file mode 100644 index 00000000000..faf38f1a4da --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/OfficialAuditParityTests.cs @@ -0,0 +1,121 @@ +using System.Reflection; +using System.Security.Cryptography; +using System.Text; + +namespace HotChocolate.Fusion; + +public sealed class OfficialAuditParityTests +{ + [Fact] + [Trait("Category", "OfficialV2Parity")] + public void Manifest_Should_DefineExactInventory_When_Loaded() + { + using var manifestStream = typeof(OfficialAuditParityTests).Assembly.GetManifestResourceStream( + "HotChocolate.Fusion.OfficialAudit.v2-manifest.json") + ?? throw new InvalidOperationException("The official V2 manifest resource was not found."); + Assert.Equal( + "146ef9f96f2f78ec35b613b67376b2b1741d41946e5f32efd4d0dc9062e3ae29", + Convert.ToHexString(SHA256.HashData(manifestStream)).ToLowerInvariant()); + + var manifest = AuditFixture.GetOfficialV2Manifest(); + var caseIds = manifest.Suites.SelectMany(suite => suite.Cases).Select(c => c.Id).ToArray(); + + Assert.Equal("f59c05e3f48f4a4f8e8a731d67a1b71a9788a96f", manifest.Revision); + Assert.Equal(42, manifest.SuiteCount); + Assert.Equal(172, manifest.CaseCount); + Assert.Equal(manifest.SuiteCount, manifest.Suites.Count); + Assert.Equal(manifest.CaseCount, caseIds.Length); + Assert.Equal(caseIds.Length, caseIds.Distinct(StringComparer.Ordinal).Count()); + + foreach (var suite in manifest.Suites) + { + Assert.Equal( + Enumerable.Range(0, suite.Cases.Count) + .Select(index => $"{suite.Id}/{index:000}"), + suite.Cases.Select(testCase => testCase.Id)); + Assert.Equal( + suite.Sources.Count, + suite.Sources.Select(source => source.Name).Distinct(StringComparer.Ordinal).Count()); + + foreach (var source in suite.Sources) + { + Assert.False(string.IsNullOrWhiteSpace(source.RawSdl)); + Assert.False(string.IsNullOrWhiteSpace(source.ServiceSdl)); + } + + foreach (var testCase in suite.Cases) + { + if (!testCase.HasExpectedData) + { + Assert.Null(testCase.ExpectedData); + } + + Assert.Equal(testCase.HasExpectedErrors, testCase.ExpectsErrors is not null); + } + + foreach (var module in suite.FixtureModules) + { + var hash = Convert.ToHexString( + SHA256.HashData(Encoding.UTF8.GetBytes(module.Source))) + .ToLowerInvariant(); + + Assert.Equal(module.Sha256, hash); + } + } + + Assert.Collection( + manifest.ExcludedV1DependentSuites, + suite => AssertV1Suite(suite, "abstract-types", 18, "users"), + suite => AssertV1Suite(suite, "fed1-external-extends", 4, "a", "b"), + suite => AssertV1Suite(suite, "fed1-external-extends-resolvable", 1, "a", "b"), + suite => AssertV1Suite(suite, "fed1-external-extension", 4, "a", "b")); + Assert.Equal(27, manifest.ExcludedV1DependentSuites.Sum(suite => suite.CaseCount)); + } + + [Fact] + [Trait("Category", "OfficialV2Parity")] + public void Port_Should_CoverEverySuiteExactlyOnce_When_Discovered() + { + var manifest = AuditFixture.GetOfficialV2Manifest(); + var suiteIds = typeof(OfficialAuditParityTests) + .Assembly + .GetTypes() + .Select(type => new + { + Type = type, + Suite = type.GetCustomAttribute() + }) + .Where(item => item.Suite is not null) + .ToArray(); + + Assert.Equal(suiteIds.Length, suiteIds.Select(item => item.Suite!.Id).Distinct().Count()); + Assert.Equal( + manifest.Suites.Select(suite => suite.Id).Order(StringComparer.Ordinal), + suiteIds.Select(item => item.Suite!.Id).Order(StringComparer.Ordinal)); + + foreach (var item in suiteIds) + { + var officialTestMethods = item.Type + .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .Where(method => method.GetCustomAttributes(inherit: false) + .Any(attribute => attribute is FactAttribute)) + .ToArray(); + + var testMethod = Assert.Single(officialTestMethods); + Assert.IsType( + testMethod.GetCustomAttributes(inherit: false) + .Single(attribute => attribute is FactAttribute)); + } + } + + private static void AssertV1Suite( + OfficialV1DependentSuite suite, + string id, + int caseCount, + params string[] sources) + { + Assert.Equal(id, suite.Id); + Assert.Equal(caseCount, suite.CaseCount); + Assert.Equal(sources, suite.V1Sources); + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/generate-v2-manifest.mjs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/generate-v2-manifest.mjs new file mode 100644 index 00000000000..b5582ee43be --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/generate-v2-manifest.mjs @@ -0,0 +1,194 @@ +import { execFileSync, spawn } from "node:child_process"; +import { createHash } from "node:crypto"; +import { readFileSync, readdirSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +const expectedRevision = "f59c05e3f48f4a4f8e8a731d67a1b71a9788a96f"; +const scriptDirectory = dirname(fileURLToPath(import.meta.url)); +const auditDirectory = process.argv[2] + ? resolve(process.argv[2]) + : resolve(scriptDirectory, "../../../../../../../../federation-gateway-audit"); +const outputPath = resolve(scriptDirectory, "v2-manifest.json"); +const deterministicRuntime = pathToFileURL( + join(scriptDirectory, "official-audit-deterministic-runtime.mjs"), +).href; +const port = Number(process.argv[3] ?? 4217); + +const revision = execFileSync("git", ["rev-parse", "HEAD"], { + cwd: auditDirectory, + encoding: "utf8", +}).trim(); + +if (revision !== expectedRevision) { + throw new Error( + `Expected federation-gateway-audit revision ${expectedRevision}, but found ${revision}.`, + ); +} + +const server = spawn( + join(auditDirectory, "node_modules", ".bin", "tsx"), + [join(auditDirectory, "src", "cli.ts"), "serve", "--port", String(port)], + { + cwd: auditDirectory, + env: { + ...process.env, + NODE_OPTIONS: [ + process.env.NODE_OPTIONS, + `--import=${deterministicRuntime}`, + ] + .filter(Boolean) + .join(" "), + }, + stdio: ["ignore", "pipe", "inherit"], + }, +); + +try { + await waitForServer(server, `http://localhost:${port}/_health`); + + const ids = await fetchJson(`http://localhost:${port}/ids`); + const suites = []; + const excludedV1DependentSuites = []; + + for (const id of ids) { + const [tests, subgraphs] = await Promise.all([ + fetchJson(`http://localhost:${port}/${id}/tests`), + fetchJson(`http://localhost:${port}/${id}/subgraphs`), + ]); + const v1Sources = subgraphs + .filter(({ sdl }) => isFederationV1Source(sdl)) + .map(({ name }) => name); + + if (v1Sources.length > 0) { + excludedV1DependentSuites.push({ id, caseCount: tests.length, v1Sources }); + continue; + } + + const suiteDirectory = join(auditDirectory, "src", "test-suites", id); + const sources = await Promise.all( + subgraphs.map(async ({ name, sdl, url }) => ({ + name, + rawSdl: sdl, + serviceSdl: await fetchServiceSdl(url), + })), + ); + const fixtureModules = readdirSync(suiteDirectory) + .filter((file) => file === "data.ts" || file.endsWith(".subgraph.ts")) + .sort() + .map((file) => { + const source = readFileSync(join(suiteDirectory, file), "utf8"); + + return { + path: file, + sha256: createHash("sha256").update(source).digest("hex"), + source, + }; + }); + + suites.push({ + id, + cases: tests.map((test, index) => ({ + id: `${id}/${String(index).padStart(3, "0")}`, + query: test.query, + variables: test.variables ?? null, + hasExpectedData: Object.hasOwn(test.expected, "data"), + expectedData: Object.hasOwn(test.expected, "data") + ? test.expected.data + : null, + hasExpectedErrors: Object.hasOwn(test.expected, "errors"), + expectsErrors: Object.hasOwn(test.expected, "errors") + ? test.expected.errors + : null, + })), + sources, + fixtureModules, + }); + } + + const manifest = { + source: "graphql-hive/federation-gateway-audit", + revision, + federationVersion: 2, + selection: + "Suites whose sources do not rely on linkless Federation directives.", + excludedV1DependentSuites, + suiteCount: suites.length, + caseCount: suites.reduce((sum, suite) => sum + suite.cases.length, 0), + suites, + }; + + writeFileSync(outputPath, `${JSON.stringify(manifest, null, 2)}\n`); + process.stdout.write( + `Wrote ${manifest.suiteCount} suites and ${manifest.caseCount} cases to ${outputPath}\n`, + ); +} finally { + server.kill("SIGTERM"); +} + +async function fetchJson(url) { + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`GET ${url} failed with ${response.status} ${response.statusText}.`); + } + + return response.json(); +} + +async function fetchServiceSdl(url) { + const response = await fetch(url, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query: "query AuditServiceSdl { _service { sdl } }" }), + }); + + if (!response.ok) { + throw new Error(`POST ${url} failed with ${response.status} ${response.statusText}.`); + } + + const result = await response.json(); + const sdl = result.data?._service?.sdl; + + if (typeof sdl !== "string" || sdl.length === 0) { + throw new Error(`POST ${url} returned no _service.sdl.`); + } + + return sdl; +} + +async function waitForServer(process, url) { + let failure; + + process.once("exit", (code) => { + failure = new Error(`Audit server exited before startup with code ${code}.`); + }); + + for (let attempt = 0; attempt < 100; attempt++) { + if (failure) { + throw failure; + } + + try { + const response = await fetch(url); + + if (response.ok) { + return; + } + } catch { + // The server has not started accepting connections yet. + } + + await new Promise((resolve) => setTimeout(resolve, 50)); + } + + throw new Error(`Audit server did not become healthy at ${url}.`); +} + +function isFederationV1Source(sdl) { + const linksFederation = sdl.includes("specs.apollo.dev/federation/"); + const usesFederationDirective = + /@(key|external|requires|provides|extends)\b|\bextend\s+type\b/.test(sdl); + + return !linksFederation && usesFederationDirective; +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/official-audit-deterministic-runtime.mjs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/official-audit-deterministic-runtime.mjs new file mode 100644 index 00000000000..2793b17f6db --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/official-audit-deterministic-runtime.mjs @@ -0,0 +1 @@ +Math.random = () => 0.625; diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/v2-manifest.json b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/v2-manifest.json new file mode 100644 index 00000000000..c192d45a5c2 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/OfficialAudit/v2-manifest.json @@ -0,0 +1,5128 @@ +{ + "source": "graphql-hive/federation-gateway-audit", + "revision": "f59c05e3f48f4a4f8e8a731d67a1b71a9788a96f", + "federationVersion": 2, + "selection": "Suites whose sources do not rely on linkless Federation directives.", + "excludedV1DependentSuites": [ + { + "id": "abstract-types", + "caseCount": 18, + "v1Sources": [ + "users" + ] + }, + { + "id": "fed1-external-extends", + "caseCount": 4, + "v1Sources": [ + "a", + "b" + ] + }, + { + "id": "fed1-external-extends-resolvable", + "caseCount": 1, + "v1Sources": [ + "a", + "b" + ] + }, + { + "id": "fed1-external-extension", + "caseCount": 4, + "v1Sources": [ + "a", + "b" + ] + } + ], + "suiteCount": 42, + "caseCount": 172, + "suites": [ + { + "id": "child-type-mismatch", + "cases": [ + { + "id": "child-type-mismatch/000", + "query": "\n {\n users {\n id\n name\n }\n accounts {\n ... on User {\n id\n name\n }\n ... on Admin {\n id\n name\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1", + "name": "u1-name" + } + ], + "accounts": [ + { + "id": "u1", + "name": "u1-name" + }, + { + "id": "a1", + "name": "a1-name" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "child-type-mismatch/001", + "query": "\n query NestedInternalAlias {\n users {\n id\n name\n }\n accounts {\n ... on User {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n }\n ... on Admin {\n id\n name\n }\n }\n }\n ... on Admin {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n }\n ... on Admin {\n id\n name\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1", + "name": "u1-name" + } + ], + "accounts": [ + { + "id": "u1", + "name": "u1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name" + }, + { + "id": "a1", + "name": "a1-name" + } + ] + }, + { + "id": "a1", + "name": "a1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name" + }, + { + "id": "a1", + "name": "a1-name" + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "child-type-mismatch/002", + "query": "\n query DeeplyNestedInternalAlias {\n users {\n id\n name\n }\n accounts {\n ... on User {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n }\n ... on Admin {\n id\n name\n }\n }\n }\n ... on Admin {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n }\n ... on Admin {\n id\n name\n }\n }\n }\n }\n }\n ... on Admin {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n }\n ... on Admin {\n id\n name\n }\n }\n }\n ... on Admin {\n id\n name\n similarAccounts {\n ... on User {\n id\n name\n }\n ... on Admin {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1", + "name": "u1-name" + } + ], + "accounts": [ + { + "id": "u1", + "name": "u1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name" + }, + { + "id": "a1", + "name": "a1-name" + } + ] + }, + { + "id": "a1", + "name": "a1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name" + }, + { + "id": "a1", + "name": "a1-name" + } + ] + } + ] + }, + { + "id": "a1", + "name": "a1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name" + }, + { + "id": "a1", + "name": "a1-name" + } + ] + }, + { + "id": "a1", + "name": "a1-name", + "similarAccounts": [ + { + "id": "u1", + "name": "u1-name" + }, + { + "id": "a1", + "name": "a1-name" + } + ] + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "child-type-mismatch/003", + "query": "\n query DeeplyNested {\n accounts {\n ... on User {\n name\n similarAccounts {\n ... on User {\n name\n similarAccounts {\n ... on User {\n name\n }\n ... on Admin {\n name\n }\n }\n }\n ... on Admin {\n name\n similarAccounts {\n ... on User {\n name\n }\n ... on Admin {\n name\n }\n }\n }\n }\n }\n ... on Admin {\n name\n similarAccounts {\n ... on User {\n name\n similarAccounts {\n ... on User {\n name\n }\n ... on Admin {\n name\n }\n }\n }\n ... on Admin {\n name\n similarAccounts {\n ... on User {\n name\n }\n ... on Admin {\n name\n }\n }\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "accounts": [ + { + "name": "u1-name", + "similarAccounts": [ + { + "name": "u1-name", + "similarAccounts": [ + { + "name": "u1-name" + }, + { + "name": "a1-name" + } + ] + }, + { + "name": "a1-name", + "similarAccounts": [ + { + "name": "u1-name" + }, + { + "name": "a1-name" + } + ] + } + ] + }, + { + "name": "a1-name", + "similarAccounts": [ + { + "name": "u1-name", + "similarAccounts": [ + { + "name": "u1-name" + }, + { + "name": "a1-name" + } + ] + }, + { + "name": "a1-name", + "similarAccounts": [ + { + "name": "u1-name" + }, + { + "name": "a1-name" + } + ] + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\"]\n )\n\n type User {\n id: ID @shareable\n }\n\n type Query {\n users: [User!]!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @federation__key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype User {\n id: ID @shareable\n}\n\ntype Query {\n users: [User!]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n union Account = User | Admin\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String\n similarAccounts: [Account!]!\n }\n\n type Admin {\n id: ID\n name: String @shareable\n similarAccounts: [Account!]!\n }\n\n type Query {\n accounts: [Account!]!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@shareable\", \"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\nunion Account = User | Admin\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n similarAccounts: [Account!]!\n}\n\ntype Admin {\n id: ID\n name: String @shareable\n similarAccounts: [Account!]!\n}\n\ntype Query {\n accounts: [Account!]!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "5e18e31e1c0607fa2e00f6cec64e8bea628493400169090d1c0b20328fa002e2", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\"]\n )\n\n type User {\n id: ID @shareable\n }\n\n type Query {\n users: [User!]!\n }\n `,\n resolvers: {\n Query: {\n users() {\n return users.map((u) => ({ __typename: \"User\", id: u.id }));\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "6c26aa25c6370397160fb65a9a9cc8da28d67687c8bf6c928d34ebc3538f73ad", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nfunction accounts() {\n return [\n ...users.map((user) => ({ __typename: \"User\", ...user })),\n { __typename: \"Admin\", id: \"a1\", name: \"a1-name\" },\n ];\n}\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n union Account = User | Admin\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String\n similarAccounts: [Account!]!\n }\n\n type Admin {\n id: ID\n name: String @shareable\n similarAccounts: [Account!]!\n }\n\n type Query {\n accounts: [Account!]!\n }\n `,\n resolvers: {\n Query: {\n accounts,\n },\n User: {\n __resolveReference(key: { id: string }) {\n return users.find((user) => user.id === key.id);\n },\n similarAccounts: accounts,\n },\n Admin: {\n similarAccounts: accounts,\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "1efdb15aebabb7872646ea496e36015dc0cf680158d1e2a88f7f710b7e8857a6", + "source": "export const users = [\n {\n id: \"u1\",\n name: \"u1-name\",\n },\n];\n" + } + ] + }, + { + "id": "circular-reference-interface", + "cases": [ + { + "id": "circular-reference-interface/000", + "query": "\n query {\n product {\n samePriceProduct {\n ... on Product {\n samePriceProduct {\n __typename\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "samePriceProduct": { + "samePriceProduct": { + "__typename": "Book" + } + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "circular-reference-interface/001", + "query": "\n query {\n product {\n __typename\n samePriceProduct {\n __typename\n ... on Book {\n id\n }\n samePriceProduct {\n __typename\n ... on Book {\n id\n }\n }\n }\n ... on Book {\n __typename\n id\n price\n samePriceProduct {\n id\n price\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "__typename": "Book", + "samePriceProduct": { + "__typename": "Book", + "id": "3", + "samePriceProduct": { + "__typename": "Book", + "id": "1" + }, + "price": 10.99 + }, + "id": "1", + "price": 10.99 + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@provides\"]\n )\n\n type Query {\n product: Product\n }\n\n interface Product {\n samePriceProduct: Product\n }\n\n type Book implements Product @key(fields: \"id\") {\n id: ID!\n samePriceProduct: Book @provides(fields: \"price\")\n price: Float @external\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@provides\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n product: Product\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Product {\n samePriceProduct: Product\n}\n\ntype Book implements Product\n @key(fields: \"id\")\n{\n id: ID!\n samePriceProduct: Book @provides(fields: \"price\")\n price: Float @external\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Book @key(fields: \"id\") {\n id: ID!\n price: Float @shareable\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Book\n @key(fields: \"id\")\n{\n id: ID!\n price: Float @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "fc18403e9c7fd029fa000a840ca88cbb5b5232065e33b7300659cff00708da71", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { books } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@provides\"]\n )\n\n type Query {\n product: Product\n }\n\n interface Product {\n samePriceProduct: Product\n }\n\n type Book implements Product @key(fields: \"id\") {\n id: ID!\n samePriceProduct: Book @provides(fields: \"price\")\n price: Float @external\n }\n `,\n resolvers: {\n Query: {\n product() {\n const book = books[0];\n return {\n __typename: book.__typename,\n id: book.id,\n price: book.price,\n };\n },\n },\n Book: {\n samePriceProduct(book: { id: string; price: number }) {\n const samePriceBook = books.find(\n (b) => b.price === book.price && b.id !== book.id,\n );\n\n if (!samePriceBook) {\n return null;\n }\n\n return {\n __typename: samePriceBook.__typename,\n id: samePriceBook.id,\n price: samePriceBook.price,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "55013ef8306d2b7af76849971ca8bfb88f2d5c77f40cd78c8408390485fa481e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { books } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Book @key(fields: \"id\") {\n id: ID!\n price: Float @shareable\n }\n `,\n\n resolvers: {\n Book: {\n __resolveReference(key: { id: string }) {\n const book = books.find((b) => b.id === key.id);\n\n if (!book) {\n return null;\n }\n\n return {\n __typename: book.__typename,\n id: book.id,\n price: book.price,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "7e0bab060baf3192278996886cf0c6d6c63c9000131af231ad1fac47a55cf391", + "source": "export const books = [\n {\n __typename: \"Book\",\n id: \"1\",\n price: 10.99,\n },\n {\n __typename: \"Book\",\n id: \"2\",\n price: 5.99,\n },\n {\n __typename: \"Book\",\n id: \"3\",\n price: 10.99,\n },\n];\n" + } + ] + }, + { + "id": "complex-entity-call", + "cases": [ + { + "id": "complex-entity-call/000", + "query": "\n query {\n topProducts {\n products {\n id\n pid\n price {\n price\n }\n category {\n mainProduct {\n id\n }\n id\n tag\n }\n }\n selected {\n id\n }\n first {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "topProducts": { + "products": [ + { + "id": "1", + "pid": "p1", + "price": { + "price": 100 + }, + "category": { + "mainProduct": { + "id": "1" + }, + "id": "c1", + "tag": "t1" + } + }, + { + "id": "2", + "pid": "p2", + "price": { + "price": 200 + }, + "category": { + "mainProduct": { + "id": "2" + }, + "id": "c2", + "tag": "t2" + } + } + ], + "selected": { + "id": "2" + }, + "first": { + "id": "1" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "link", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\"])\n\n type Product @key(fields: \"id\") @key(fields: \"id pid\") {\n id: String!\n pid: String!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype Product\n @key(fields: \"id\")\n @key(fields: \"id pid\")\n{\n id: String!\n pid: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "list", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type ProductList @key(fields: \"products{id pid}\") {\n products: [Product!]!\n first: Product @shareable\n selected: Product @shareable\n }\n\n type Product @key(fields: \"id pid\") {\n id: String!\n pid: String\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype ProductList\n @key(fields: \"products{id pid}\")\n{\n products: [Product!]!\n first: Product @shareable\n selected: Product @shareable\n}\n\ntype Product\n @key(fields: \"id pid\")\n{\n id: String!\n pid: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product | ProductList\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "price", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type ProductList\n @key(fields: \"products{id pid category{id tag}} selected{id}\") {\n products: [Product!]!\n first: Product @shareable\n selected: Product @shareable\n }\n\n type Product @key(fields: \"id pid category{id tag}\") {\n id: String!\n price: Price\n pid: String\n category: Category\n }\n\n type Category @key(fields: \"id tag\") {\n id: String!\n tag: String\n }\n\n type Price {\n price: Float!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype ProductList\n @key(fields: \"products{id pid category{id tag}} selected{id}\")\n{\n products: [Product!]!\n first: Product @shareable\n selected: Product @shareable\n}\n\ntype Product\n @key(fields: \"id pid category{id tag}\")\n{\n id: String!\n price: Price\n pid: String\n category: Category\n}\n\ntype Category\n @key(fields: \"id tag\")\n{\n id: String!\n tag: String\n}\n\ntype Price {\n price: Float!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product | ProductList\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "products", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@external\", \"@extends\", \"@shareable\"]\n )\n\n type Query {\n topProducts: ProductList!\n }\n\n type ProductList @key(fields: \"products{id}\") {\n products: [Product!]!\n }\n\n type Product @extends @key(fields: \"id\") {\n id: String! @external\n category: Category @shareable\n }\n\n type Category @key(fields: \"id\") {\n mainProduct: Product! @shareable\n id: String!\n tag: String @shareable\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\", \"@external\", \"@extends\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @extends on OBJECT | INTERFACE\n\ndirective @shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype Query {\n topProducts: ProductList!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype ProductList\n @key(fields: \"products{id}\")\n{\n products: [Product!]!\n}\n\ntype Product\n @extends\n @key(fields: \"id\")\n{\n id: String! @external\n category: Category @shareable\n}\n\ntype Category\n @key(fields: \"id\")\n{\n mainProduct: Product! @shareable\n id: String!\n tag: String @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product | ProductList" + } + ], + "fixtureModules": [ + { + "path": "data.ts", + "sha256": "aa2a9ee7d4d1a0a0a5566838c0b2a707c508e105086bc1696ce0203c4accb1f2", + "source": "export const products = [\n {\n id: \"1\",\n pid: \"p1\",\n categoryId: \"c1\",\n price: 100,\n },\n {\n id: \"2\",\n pid: \"p2\",\n categoryId: \"c2\",\n price: 200,\n },\n];\n\nexport const categories = [\n {\n id: \"c1\",\n tag: \"t1\",\n mainProduct: \"1\",\n },\n {\n id: \"c2\",\n tag: \"t2\",\n mainProduct: \"2\",\n },\n];\n" + }, + { + "path": "link.subgraph.ts", + "sha256": "ac06289b58fab861846cbab7bd7c101cd57b3d15a1ef49bb471ddaf6854a8800", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"link\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\"])\n\n type Product @key(fields: \"id\") @key(fields: \"id pid\") {\n id: String!\n pid: String!\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(\n key:\n | {\n id: string;\n pid: string;\n }\n | {\n id: string;\n },\n ) {\n if (\"pid\" in key) {\n return products.find(\n (product) => product.id === key.id && product.pid === key.pid,\n );\n }\n\n return products.find((product) => product.id === key.id);\n },\n },\n },\n});\n" + }, + { + "path": "list.subgraph.ts", + "sha256": "1000979115b483c97ec2679dec834f1d8df9f3f4f9127521abc6eedb39cb3645", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"list\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type ProductList @key(fields: \"products{id pid}\") {\n products: [Product!]!\n first: Product @shareable\n selected: Product @shareable\n }\n\n type Product @key(fields: \"id pid\") {\n id: String!\n pid: String\n }\n `,\n resolvers: {\n ProductList: {\n __resolveReference(key: { products: { id: string; pid: string }[] }) {\n const prods = products.filter((p) =>\n key.products.some((k) => k.id === p.id && k.pid === p.pid),\n );\n return {\n products: prods,\n first: prods[0],\n selected: prods[1],\n };\n },\n },\n Product: {\n __resolveReference(key: { id: string; pid: string }) {\n return products.find(\n (product) => product.id === key.id && product.pid === key.pid,\n );\n },\n },\n },\n});\n" + }, + { + "path": "price.subgraph.ts", + "sha256": "9b7e36a8d943366fb6a91b342bc506c982900b1d96b69f32ea9ae0ed112fdd91", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"price\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type ProductList\n @key(fields: \"products{id pid category{id tag}} selected{id}\") {\n products: [Product!]!\n first: Product @shareable\n selected: Product @shareable\n }\n\n type Product @key(fields: \"id pid category{id tag}\") {\n id: String!\n price: Price\n pid: String\n category: Category\n }\n\n type Category @key(fields: \"id tag\") {\n id: String!\n tag: String\n }\n\n type Price {\n price: Float!\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: {\n id: string;\n pid: string;\n category: { id: string; tag: string };\n }) {\n return products.find((p) => {\n if (p.id === key.id && p.pid === key.pid) {\n const cat = categories.find((c) => c.id === p.categoryId);\n\n if (\n cat &&\n cat.id === key.category.id &&\n cat.tag === key.category.tag\n ) {\n return true;\n }\n }\n\n return false;\n });\n },\n price(product: (typeof products)[number]) {\n return {\n price: product.price,\n };\n },\n category(product: (typeof products)[number]) {\n return categories.find((c) => c.id === product.categoryId);\n },\n },\n Category: {\n __resolveReference(key: { id: string; tag: string }) {\n return categories.find((c) => c.id === key.id);\n },\n },\n ProductList: {\n __resolveReference(key: {\n products: {\n id: string;\n pid: string;\n category: { id: string; tag: string };\n }[];\n selected: { id: string };\n }) {\n const prods = products.filter((p) =>\n key.products.some((k) => {\n if (p.id === k.id && p.pid === k.pid) {\n const cat = categories.find((c) => c.id === p.categoryId);\n\n if (\n cat &&\n cat.id === k.category.id &&\n cat.tag === k.category.tag\n ) {\n return true;\n }\n }\n\n return false;\n }),\n );\n\n return {\n products: prods,\n first: prods[0],\n selected: products.find((p) => p.id === key.selected.id),\n };\n },\n },\n },\n});\n" + }, + { + "path": "products.subgraph.ts", + "sha256": "630e3b9d64b586e6f956f9d750faf28cf9dd92cbb499038e6789bfda0301f8af", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"products\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@external\", \"@extends\", \"@shareable\"]\n )\n\n type Query {\n topProducts: ProductList!\n }\n\n type ProductList @key(fields: \"products{id}\") {\n products: [Product!]!\n }\n\n type Product @extends @key(fields: \"id\") {\n id: String! @external\n category: Category @shareable\n }\n\n type Category @key(fields: \"id\") {\n mainProduct: Product! @shareable\n id: String!\n tag: String @shareable\n }\n `,\n resolvers: {\n Query: {\n topProducts() {\n return {\n products,\n };\n },\n },\n ProductList: {\n __resolveReference(key: { products: { id: string }[] }) {\n return {\n products: products.filter((p) =>\n key.products.some((k) => k.id === p.id),\n ),\n };\n },\n },\n Product: {\n __resolveReference(key: { id: string }) {\n return products.find((product) => product.id === key.id);\n },\n category(product: (typeof products)[number]) {\n return categories.find((c) => c.id === product.categoryId);\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n return categories.find((c) => c.id === key.id);\n },\n mainProduct(category: (typeof categories)[number]) {\n return products.find((p) => p.id === category.mainProduct);\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "corrupted-supergraph-node-id", + "cases": [ + { + "id": "corrupted-supergraph-node-id/000", + "query": "\n query {\n node(id: \"a1\") {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "corrupted-supergraph-node-id/001", + "query": "\n query {\n account: node(id: \"a1\") {\n __typename\n }\n chat: node(id: \"c1\") {\n __typename\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "account": { + "__typename": "Account" + }, + "chat": { + "__typename": "Chat" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "corrupted-supergraph-node-id/002", + "query": "\n query {\n account: node(id: \"a1\") {\n ... on Account {\n id\n username\n }\n }\n chat: node(id: \"c1\") {\n ... on Chat {\n id\n text\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "account": { + "id": "a1", + "username": "a1-username" + }, + "chat": { + "id": "c1", + "text": "c1-text" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "corrupted-supergraph-node-id/003", + "query": "\n query {\n account: node(id: \"a1\") {\n ... on Chat {\n id\n }\n }\n chat: node(id: \"c1\") {\n ... on Account {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "account": {}, + "chat": {} + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "corrupted-supergraph-node-id/004", + "query": "\n query {\n account: node(id: \"a1\") {\n __typename\n ... on Chat {\n id\n }\n }\n chat: node(id: \"c1\") {\n __typename\n ... on Account {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "account": { + "__typename": "Account" + }, + "chat": { + "__typename": "Chat" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "corrupted-supergraph-node-id/005", + "query": "\n query {\n account: node(id: \"a1\") {\n id\n ... on Chat {\n id\n }\n }\n chat: node(id: \"c1\") {\n __typename\n ... on Account {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "corrupted-supergraph-node-id/006", + "query": "\n query {\n chat(id: \"c1\") {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "chat": { + "id": "c1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "corrupted-supergraph-node-id/007", + "query": "\n query {\n account(id: \"a1\") {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "account": { + "id": "a1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "corrupted-supergraph-node-id/008", + "query": "\n query {\n chat(id: \"c1\") {\n id\n text\n account {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "chat": { + "id": "c1", + "text": "c1-text", + "account": { + "id": "a1" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "corrupted-supergraph-node-id/009", + "query": "\n query {\n account(id: \"a1\") {\n id\n username\n chats {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "account": { + "id": "a1", + "username": "a1-username", + "chats": [ + { + "id": "c1" + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\"]\n )\n\n type Query {\n node(id: ID!): Node @shareable\n account(id: String!): Account\n }\n\n interface Node {\n id: ID!\n }\n\n type Account implements Node @key(fields: \"id\") {\n id: ID!\n username: String!\n }\n\n type Chat implements Node @key(fields: \"id\") {\n id: ID! @external\n account: Account!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n node(id: ID!): Node @shareable\n account(id: String!): Account\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Node {\n id: ID!\n}\n\ntype Account implements Node\n @key(fields: \"id\")\n{\n id: ID!\n username: String!\n}\n\ntype Chat implements Node\n @key(fields: \"id\")\n{\n id: ID! @external\n account: Account!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Account | Chat" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\"]\n )\n type Query {\n node(id: ID!): Node @shareable\n chat(id: String!): Chat\n }\n\n interface Node {\n id: ID!\n }\n\n type Account implements Node @key(fields: \"id\") {\n id: ID! @external\n chats: [Chat!]!\n }\n\n type Chat implements Node @key(fields: \"id\") {\n id: ID!\n text: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n node(id: ID!): Node @shareable\n chat(id: String!): Chat\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Node {\n id: ID!\n}\n\ntype Account implements Node\n @key(fields: \"id\")\n{\n id: ID! @external\n chats: [Chat!]!\n}\n\ntype Chat implements Node\n @key(fields: \"id\")\n{\n id: ID!\n text: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Account | Chat" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "d6659cadb2d1e06b01056a07046db5353ddd370babcbbb33fb22357e924f8406", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { accounts, chats } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\"]\n )\n\n type Query {\n node(id: ID!): Node @shareable\n account(id: String!): Account\n }\n\n interface Node {\n id: ID!\n }\n\n type Account implements Node @key(fields: \"id\") {\n id: ID!\n username: String!\n }\n\n type Chat implements Node @key(fields: \"id\") {\n id: ID! @external\n account: Account!\n }\n `,\n resolvers: {\n Query: {\n node(_: {}, { id }: { id: string }) {\n const account = accounts.find((a) => a.id === id);\n\n if (account) {\n return {\n __typename: \"Account\",\n id: account.id,\n username: account.username,\n };\n }\n\n const chat = chats.find((c) => c.id === id);\n\n if (chat) {\n return {\n __typename: \"Chat\",\n id: \"never\",\n accountId: chat.accountId,\n };\n }\n },\n account(_: {}, { id }: { id: string }) {\n const account = accounts.find((a) => a.id === id);\n\n if (account) {\n return {\n __typename: \"Account\",\n id: account.id,\n username: account.username,\n };\n }\n\n return null;\n },\n },\n Account: {\n __resolveReference(key: { id: string }) {\n const account = accounts.find((a) => a.id === key.id);\n\n if (account) {\n return {\n __typename: \"Account\",\n id: account.id,\n username: account.username,\n };\n }\n\n return null;\n },\n },\n Chat: {\n __resolveReference(key: { id: string }) {\n const chat = chats.find((c) => c.id === key.id);\n\n if (chat) {\n return {\n __typename: \"Chat\",\n id: chat.id,\n accountId: chat.accountId,\n };\n }\n\n return null;\n },\n account(chat: { accountId: string }) {\n const account = accounts.find((a) => a.id === chat.accountId);\n\n if (account) {\n return {\n __typename: \"Account\",\n id: account.id,\n username: account.username,\n };\n }\n\n return null;\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "ea0e1210ab79bad6a3d65c119233951a45fa1131bef2618d66022db0cfd13780", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { accounts, chats } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\"]\n )\n type Query {\n node(id: ID!): Node @shareable\n chat(id: String!): Chat\n }\n\n interface Node {\n id: ID!\n }\n\n type Account implements Node @key(fields: \"id\") {\n id: ID! @external\n chats: [Chat!]!\n }\n\n type Chat implements Node @key(fields: \"id\") {\n id: ID!\n text: String!\n }\n `,\n resolvers: {\n Query: {\n node(_: {}, { id }: { id: string }) {\n const account = accounts.find((a) => a.id === id);\n\n if (account) {\n return {\n __typename: \"Account\",\n id: \"never\",\n chatIds: chats\n .filter((c) => c.accountId === account.id)\n .map((c) => c.id),\n };\n }\n\n const chat = chats.find((c) => c.id === id);\n\n if (chat) {\n return {\n __typename: \"Chat\",\n id: chat.id,\n text: chat.text,\n };\n }\n\n return null;\n },\n chat(_: {}, { id }: { id: string }) {\n const chat = chats.find((c) => c.id === id);\n\n if (chat) {\n return {\n __typename: \"Chat\",\n id: chat.id,\n text: chat.text,\n };\n }\n\n return null;\n },\n },\n Account: {\n __resolveReference(key: { id: string }) {\n const account = accounts.find((a) => a.id === key.id);\n\n if (account) {\n return {\n __typename: \"Account\",\n id: account.id,\n chatIds: chats\n .filter((c) => c.accountId === account.id)\n .map((c) => c.id),\n };\n }\n\n return null;\n },\n chats(account: { chatIds: string[] }) {\n return chats\n .filter((c) => account.chatIds.includes(c.id))\n .map((chat) => ({\n __typename: \"Chat\",\n id: chat.id,\n text: chat.text,\n }));\n },\n },\n Chat: {\n __resolveReference(key: { id: string }) {\n const chat = chats.find((c) => c.id === key.id);\n\n if (chat) {\n return {\n __typename: \"Chat\",\n id: chat.id,\n text: chat.text,\n };\n }\n\n return null;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "5283123509e2beab1ced714a2132bdcfcf754a42e6f5410c0c1b7d1c9bd96890", + "source": "export const accounts = [\n {\n __typename: \"Account\",\n id: \"a1\",\n username: \"a1-username\",\n },\n];\n\nexport const chats = [\n {\n __typename: \"Chat\",\n id: \"c1\",\n accountId: \"a1\",\n text: \"c1-text\",\n },\n];\n" + } + ] + }, + { + "id": "enum-intersection", + "cases": [ + { + "id": "enum-intersection/000", + "query": "\n query {\n users {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1" + }, + { + "id": "u2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "enum-intersection/001", + "query": "\n query {\n users {\n id\n type\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1", + "type": "REGULAR" + }, + { + "id": "u2", + "type": null + } + ] + }, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "enum-intersection/002", + "query": "\n query {\n usersB {\n id\n type\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "usersB": [ + { + "id": "u1", + "type": "REGULAR" + }, + { + "id": "u2", + "type": null + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "enum-intersection/003", + "query": "\n query {\n usersByType(type: REGULAR) {\n id\n type\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "usersByType": [ + { + "id": "u1", + "type": "REGULAR" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "enum-intersection/004", + "query": "\n query {\n usersByType(type: ANONYMOUS) {\n id\n type\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n users: [User]\n }\n\n type User @key(fields: \"id\") {\n id: ID\n type: UserType @shareable\n }\n\n enum UserType {\n REGULAR\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n users: [User]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID\n type: UserType @shareable\n}\n\nenum UserType {\n REGULAR\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\", \"@shareable\"]\n )\n\n type Query {\n usersByType(type: UserType!): [User!]\n usersB: [User!]\n }\n\n extend type User @key(fields: \"id\") {\n id: ID\n type: UserType @shareable\n }\n\n enum UserType {\n ANONYMOUS @inaccessible\n REGULAR\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@inaccessible\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n usersByType(type: UserType!): [User!]\n usersB: [User!]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nextend type User\n @key(fields: \"id\")\n{\n id: ID\n type: UserType @shareable\n}\n\nenum UserType {\n ANONYMOUS @inaccessible\n REGULAR\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "80ac0e22b80690654c8b015db4ad5418f7f3a404e77671e5ca658b6882c96e83", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n users: [User]\n }\n\n type User @key(fields: \"id\") {\n id: ID\n type: UserType @shareable\n }\n\n enum UserType {\n REGULAR\n }\n `,\n resolvers: {\n Query: {\n users() {\n return users;\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n type: user.type,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "8686dd4bc964896b47b485a1c445e1a063a10d561889bbce66cd06961614dc68", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\", \"@shareable\"]\n )\n\n type Query {\n usersByType(type: UserType!): [User!]\n usersB: [User!]\n }\n\n extend type User @key(fields: \"id\") {\n id: ID\n type: UserType @shareable\n }\n\n enum UserType {\n ANONYMOUS @inaccessible\n REGULAR\n }\n `,\n resolvers: {\n Query: {\n usersByType(_: {}, { type }: { type: string }) {\n return users.filter((u) => u.type === type);\n },\n usersB() {\n return users;\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n type: user.type,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "4cc4e4972b666b242c1a0b829e954498500c3dc2e565ccd0843a5a31364ddd1f", + "source": "export const users = [\n {\n id: \"u1\",\n type: \"REGULAR\",\n },\n {\n id: \"u2\",\n type: \"ANONYMOUS\",\n },\n];\n" + } + ] + }, + { + "id": "fed2-external-extends", + "cases": [ + { + "id": "fed2-external-extends/000", + "query": "\n query {\n randomUser {\n id\n name\n }\n userById(id: \"u2\") {\n id\n name\n nickname\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "randomUser": { + "id": "u1", + "name": "u1-name" + }, + "userById": { + "id": "u2", + "name": "u2-name", + "nickname": "u2-nickname" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "fed2-external-extends/001", + "query": "\n query {\n randomUser {\n id\n rid\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "randomUser": { + "id": "u1", + "rid": "u1-rid" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "fed2-external-extends/002", + "query": "\n query {\n randomUser {\n id\n rid\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "randomUser": { + "id": "u1", + "rid": "u1-rid", + "name": "u1-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "fed2-external-extends/003", + "query": "\n query {\n providedRandomUser {\n id\n rid\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "providedRandomUser": { + "id": "u1", + "rid": "u1-rid", + "name": "u1-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@extends\", \"@provides\"]\n )\n\n type Query {\n randomUser: User\n providedRandomUser: User @provides(fields: \"name\")\n }\n\n type User @key(fields: \"id\") @extends {\n id: ID! @external\n name: String! @external\n rid: ID\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@extends\", \"@provides\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n randomUser: User\n providedRandomUser: User @provides(fields: \"name\")\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n @extends\n{\n id: ID! @external\n name: String! @external\n rid: ID\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n userById(id: ID): User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n nickname: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n userById(id: ID): User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n nickname: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "c5bbb29afbd678e0efeecf78bd777478db41584dfde796e177ccfb84a0ba3c7e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@extends\", \"@provides\"]\n )\n\n type Query {\n randomUser: User\n providedRandomUser: User @provides(fields: \"name\")\n }\n\n type User @key(fields: \"id\") @extends {\n id: ID! @external\n name: String! @external\n rid: ID\n }\n `,\n resolvers: {\n Query: {\n randomUser() {\n return {\n id: users[0].id,\n rid: users[0].rid,\n };\n },\n providedRandomUser() {\n return {\n id: users[0].id,\n rid: users[0].rid,\n name: users[0].name,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n rid: user.rid,\n };\n },\n name(user: { name: string | undefined }) {\n return user.name ?? \"never\";\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "eefcccdd7f77e5015ee80dced38b2b51db225995584e33341e038ea8eb65c4c6", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n userById(id: ID): User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n nickname: String\n }\n `,\n resolvers: {\n Query: {\n userById: (_: {}, { id }: { id: string }) => {\n const user = users.find((u) => u.id === id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n nickname: user.nickname,\n };\n },\n },\n User: {\n __resolveReference: (key: { id: string }) => {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n nickname: user.nickname,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "6d37b20b771a31f2219f84d9d6172394d6b52dac271d6dd6dbc9d86359f3445c", + "source": "export const users = [\n {\n id: \"u1\",\n rid: \"u1-rid\",\n name: \"u1-name\",\n nickname: \"u1-nickname\",\n },\n {\n id: \"u2\",\n rid: \"u2-rid\",\n name: \"u2-name\",\n nickname: \"u2-nickname\",\n },\n];\n" + } + ] + }, + { + "id": "fed2-external-extension", + "cases": [ + { + "id": "fed2-external-extension/000", + "query": "\n query {\n randomUser {\n id\n name\n }\n userById(id: \"u2\") {\n id\n name\n nickname\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "randomUser": { + "id": "u1", + "name": "u1-name" + }, + "userById": { + "id": "u2", + "name": "u2-name", + "nickname": "u2-nickname" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "fed2-external-extension/001", + "query": "\n query {\n randomUser {\n id\n rid\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "randomUser": { + "id": "u1", + "rid": "u1-rid" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "fed2-external-extension/002", + "query": "\n query {\n randomUser {\n id\n rid\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "randomUser": { + "id": "u1", + "rid": "u1-rid", + "name": "u1-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "fed2-external-extension/003", + "query": "\n query {\n providedRandomUser {\n id\n rid\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "providedRandomUser": { + "id": "u1", + "rid": "u1-rid", + "name": "u1-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@provides\"]\n )\n\n type Query {\n randomUser: User\n providedRandomUser: User @provides(fields: \"name\")\n }\n\n extend type User @key(fields: \"id\") {\n id: ID! @external\n name: String! @external\n rid: ID\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@provides\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n randomUser: User\n providedRandomUser: User @provides(fields: \"name\")\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nextend type User\n @key(fields: \"id\")\n{\n id: ID! @external\n name: String! @external\n rid: ID\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n userById(id: ID): User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n nickname: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n userById(id: ID): User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n nickname: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "f754190d3cd761f8d024e6bee5522a1f19427037e23bed4d85dec7f32a381654", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@provides\"]\n )\n\n type Query {\n randomUser: User\n providedRandomUser: User @provides(fields: \"name\")\n }\n\n extend type User @key(fields: \"id\") {\n id: ID! @external\n name: String! @external\n rid: ID\n }\n `,\n resolvers: {\n Query: {\n randomUser() {\n return {\n id: users[0].id,\n rid: users[0].rid,\n };\n },\n providedRandomUser() {\n return {\n id: users[0].id,\n rid: users[0].rid,\n name: users[0].name,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n rid: user.rid,\n };\n },\n name(user: { name: string | undefined }) {\n return user.name ?? \"never\";\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "eefcccdd7f77e5015ee80dced38b2b51db225995584e33341e038ea8eb65c4c6", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n userById(id: ID): User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n nickname: String\n }\n `,\n resolvers: {\n Query: {\n userById: (_: {}, { id }: { id: string }) => {\n const user = users.find((u) => u.id === id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n nickname: user.nickname,\n };\n },\n },\n User: {\n __resolveReference: (key: { id: string }) => {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n nickname: user.nickname,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "6d37b20b771a31f2219f84d9d6172394d6b52dac271d6dd6dbc9d86359f3445c", + "source": "export const users = [\n {\n id: \"u1\",\n rid: \"u1-rid\",\n name: \"u1-name\",\n nickname: \"u1-nickname\",\n },\n {\n id: \"u2\",\n rid: \"u2-rid\",\n name: \"u2-name\",\n nickname: \"u2-nickname\",\n },\n];\n" + } + ] + }, + { + "id": "include-skip", + "cases": [ + { + "id": "include-skip/000", + "query": "\n query ($bool: Boolean = false) {\n product {\n price\n neverCalledInclude @include(if: $bool)\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "price": 699.99 + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "include-skip/001", + "query": "\n query ($bool: Boolean = true) {\n product {\n price\n neverCalledSkip @skip(if: $bool)\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "price": 699.99 + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "include-skip/002", + "query": "\n query ($bool: Boolean = true) {\n product {\n price\n include @include(if: $bool)\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "price": 699.99, + "include": true + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "include-skip/003", + "query": "\n query ($bool: Boolean = false) {\n product {\n price\n skip @skip(if: $bool)\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "price": 699.99, + "skip": true + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n product: Product\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n product: Product\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n price: Float!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n isExpensive: Boolean! @external\n include: Boolean! @requires(fields: \"isExpensive\")\n skip: Boolean! @requires(fields: \"isExpensive\")\n neverCalledInclude: Boolean! @requires(fields: \"isExpensive\")\n neverCalledSkip: Boolean! @requires(fields: \"isExpensive\")\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n isExpensive: Boolean! @external\n include: Boolean! @requires(fields: \"isExpensive\")\n skip: Boolean! @requires(fields: \"isExpensive\")\n neverCalledInclude: Boolean! @requires(fields: \"isExpensive\")\n neverCalledSkip: Boolean! @requires(fields: \"isExpensive\")\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "b7c3493b221278419a3bace3dd8e6f38f82ecfb66f28d65ce5a577125d312e1b", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n product: Product\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float!\n }\n `,\n resolvers: {\n Query: {\n product() {\n return {\n id: products[0].id,\n price: products[0].price,\n };\n },\n },\n Product: {\n __resolveReference(key: { id: string }) {\n const product = products.find((product) => product.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n price: product.price,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "91b7e1c184081e400fa368336003d4949b196e9d144b5dec3e822c05ea394be4", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string } | { id: string; price: number }) {\n const product = products.find((product) => product.id === key.id);\n\n if (!product) {\n return null;\n }\n\n if (\"price\" in key) {\n return {\n id: product.id,\n price: key.price,\n };\n }\n\n return {\n id: product.id,\n };\n },\n isExpensive(product: { price?: number }) {\n if (!product.price) {\n throw new Error(\"Price is missing\");\n }\n\n return product.price > 500;\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "6bd3dd39ea04431e9d59e57f99d4a22d25394d1cfa190cd53af251886468044e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n isExpensive: Boolean! @external\n include: Boolean! @requires(fields: \"isExpensive\")\n skip: Boolean! @requires(fields: \"isExpensive\")\n neverCalledInclude: Boolean! @requires(fields: \"isExpensive\")\n neverCalledSkip: Boolean! @requires(fields: \"isExpensive\")\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(\n key: { id: string } | { id: string; isExpensive: boolean },\n ) {\n const product = products.find((product) => product.id === key.id);\n\n if (!product) {\n return null;\n }\n\n if (\"isExpensive\" in key) {\n return {\n id: product.id,\n isExpensive: key.isExpensive,\n };\n }\n\n return {\n id: product.id,\n };\n },\n include(product: { isExpensive?: number }) {\n if (typeof product.isExpensive !== \"boolean\") {\n throw new Error(\"isExpensive is missing\");\n }\n\n return true;\n },\n neverCalledInclude() {\n throw new Error(\"neverCalledInclude should not be called\");\n },\n skip(product: { isExpensive?: number }) {\n if (typeof product.isExpensive !== \"boolean\") {\n throw new Error(\"isExpensive is missing\");\n }\n\n return true;\n },\n neverCalledSkip() {\n throw new Error(\"neverCalledSkip should not be called\");\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "647dc2229973ade355c519506df8246128080cac617d3fd4bea89c3bf22a0ec2", + "source": "export const products = [\n {\n id: \"p1\",\n price: 699.99,\n },\n];\n" + } + ] + }, + { + "id": "input-object-intersection", + "cases": [ + { + "id": "input-object-intersection/000", + "query": "\n query {\n usersInA(filter: { first: 1 }) {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "usersInA": [ + { + "id": "u1" + }, + { + "id": "u2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "input-object-intersection/001", + "query": "\n query {\n usersInA(filter: { first: 1, offset: 2 }) {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": false, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "input-object-intersection/002", + "query": "\n query {\n usersInB(filter: { first: 1, offset: 2 }) {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": false, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n input UsersFilter {\n first: Int!\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n\n type Query {\n usersInA(filter: UsersFilter!): [User!]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninput UsersFilter {\n first: Int!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n}\n\ntype Query {\n usersInA(filter: UsersFilter!): [User!]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n input UsersFilter {\n offset: Int\n first: Int!\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n\n type Query {\n usersInB(filter: UsersFilter!): [User!]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninput UsersFilter {\n offset: Int\n first: Int!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n}\n\ntype Query {\n usersInB(filter: UsersFilter!): [User!]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "f647af2c7645fa8c1cb68f047370f72e874a03290417c3e8698e5bfffa618752", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n input UsersFilter {\n first: Int!\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n\n type Query {\n usersInA(filter: UsersFilter!): [User!]\n }\n `,\n resolvers: {\n Query: {\n usersInA(_: {}, { filter }: { filter: { first: number } }) {\n if (\"offset\" in filter) {\n return [];\n }\n\n return users;\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((user) => user.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return user;\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "e25aed07c98f8dd0e458b84f714edf71b2e0d4c0866f8863d3714cc643a6906a", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n input UsersFilter {\n offset: Int\n first: Int!\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n\n type Query {\n usersInB(filter: UsersFilter!): [User!]\n }\n `,\n resolvers: {\n Query: {\n usersInB(\n _: {},\n { filter }: { filter: { offset?: number; first: number } },\n ) {\n if (\"offset\" in filter) {\n return [];\n }\n\n return users;\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((user) => user.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return user;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "6efaef2c1a7ee31e629402d1d61ce2b143130ce9805f5c7b2df580328af4ee25", + "source": "export const users = [\n {\n id: \"u1\",\n name: \"u1-name\",\n },\n {\n id: \"u2\",\n name: \"u2-name\",\n },\n];\n" + } + ] + }, + { + "id": "interface-object-indirect-extension", + "cases": [ + { + "id": "interface-object-indirect-extension/000", + "query": "\n query {\n media {\n id\n title\n ... on Video {\n duration\n authorName\n }\n ... on Article {\n wordCount\n }\n }\n author {\n id\n name\n }\n playlist {\n id\n name\n media {\n id\n ... on Video {\n duration\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": { + "id": "1", + "title": "title for 1", + "duration": 100, + "authorName": "John Doe" + }, + "author": { + "id": "1", + "name": "name for 1" + }, + "playlist": { + "id": "1", + "name": "name for 1", + "media": { + "id": "1", + "duration": 100 + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "b", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n author: Author\n }\n\n type Author @key(fields: \"id\") {\n id: ID!\n name: String\n }\n\n extend type Video @key(fields: \"id\") {\n id: ID!\n authorName: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n author: Author\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Author\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n}\n\nextend type Video\n @key(fields: \"id\")\n{\n id: ID!\n authorName: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Author | Video" + }, + { + "name": "a", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n media: Media\n }\n\n interface Media @key(fields: \"id\") {\n id: ID!\n title: String\n }\n\n type Video implements Media @key(fields: \"id\") {\n id: ID!\n title: String\n duration: Int\n }\n\n type Article implements Media @key(fields: \"id\") {\n id: ID!\n title: String\n wordCount: Int\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n media: Media\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Media\n @key(fields: \"id\")\n{\n id: ID!\n title: String\n}\n\ntype Video implements Media\n @key(fields: \"id\")\n{\n id: ID!\n title: String\n duration: Int\n}\n\ntype Article implements Media\n @key(fields: \"id\")\n{\n id: ID!\n title: String\n wordCount: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Article | Video" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n type Query {\n playlist: Playlist\n }\n\n type Playlist @key(fields: \"id\") {\n id: ID!\n name: String\n media: Media\n }\n\n type Media @key(fields: \"id\") @interfaceObject {\n id: ID!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @interfaceObject on OBJECT\n\ntype Query {\n playlist: Playlist\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Playlist\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n media: Media\n}\n\ntype Media\n @key(fields: \"id\")\n @interfaceObject\n{\n id: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Media | Playlist" + } + ], + "fixtureModules": [ + { + "path": "author.subgraph.ts", + "sha256": "d656f9f98940baae9621e017f7e83df9dc61a31b7255cad58fa3cabe5cdcf226", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n author: Author\n }\n\n type Author @key(fields: \"id\") {\n id: ID!\n name: String\n }\n\n extend type Video @key(fields: \"id\") {\n id: ID!\n authorName: String\n }\n `,\n resolvers: {\n Query: {\n author() {\n return { id: \"1\", name: `name for 1` };\n },\n },\n Author: {\n __resolveReference(ref: { id: string }) {\n return { id: ref.id, name: `name for ${ref.id}` };\n },\n },\n Video: {\n authorName() {\n return \"John Doe\";\n },\n },\n },\n});\n" + }, + { + "path": "media.subgraph.ts", + "sha256": "6afe129a81f1bb185d3f4af97e625bd500ab1ea959268c4639d71e3c093a4a58", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n media: Media\n }\n\n interface Media @key(fields: \"id\") {\n id: ID!\n title: String\n }\n\n type Video implements Media @key(fields: \"id\") {\n id: ID!\n title: String\n duration: Int\n }\n\n type Article implements Media @key(fields: \"id\") {\n id: ID!\n title: String\n wordCount: Int\n }\n `,\n resolvers: {\n Query: {\n media() {\n return {\n id: \"1\",\n title: \"title for 1\",\n duration: 100,\n };\n },\n },\n Media: {\n __resolveType() {\n return \"Video\";\n },\n },\n Video: {\n __resolveReference(ref: { id: string }) {\n return {\n id: ref.id,\n title: `title for ${ref.id}`,\n duration: 100 * Number(ref.id),\n };\n },\n },\n Article: {\n __resolveReference(ref: { id: string }) {\n return {\n id: ref.id,\n title: `title for ${ref.id}`,\n wordCount: 900 * Number(ref.id),\n };\n },\n },\n },\n});\n" + }, + { + "path": "playlist.subgraph.ts", + "sha256": "40ab322dfddae6d94c6f7897ac6ccd43e712bb7ee201a35ac8ea8f5464174e77", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n type Query {\n playlist: Playlist\n }\n\n type Playlist @key(fields: \"id\") {\n id: ID!\n name: String\n media: Media\n }\n\n type Media @key(fields: \"id\") @interfaceObject {\n id: ID!\n }\n `,\n resolvers: {\n Query: {\n playlist() {\n return { id: \"1\", name: \"name for 1\", media: { id: \"1\" } };\n },\n },\n Playlist: {\n __resolveReference(ref: { id: string }) {\n return {\n id: ref.id,\n name: `name for ${ref.id}`,\n media: { id: ref.id },\n };\n },\n },\n Media: {\n __resolveReference(ref: { id: string }) {\n return {\n id: ref.id,\n };\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "interface-object-with-requires", + "cases": [ + { + "id": "interface-object-with-requires/000", + "query": "\n query {\n anotherUsers {\n id\n name\n username\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherUsers": [ + { + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "interface-object-with-requires/001", + "query": "\n query {\n users {\n id\n name\n username\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "interface-object-with-requires/002", + "query": "\n query {\n anotherUsers {\n ... on User {\n age\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherUsers": [ + { + "age": 11 + }, + { + "age": 22 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "interface-object-with-requires/003", + "query": "\n query {\n users {\n ... on User {\n age\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "age": 11 + }, + { + "age": 22 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "interface-object-with-requires/004", + "query": "\n query {\n anotherUsers {\n ... on User {\n age\n id\n name\n username\n }\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherUsers": [ + { + "age": 11, + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "age": 22, + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "interface-object-with-requires/005", + "query": "\n query {\n users {\n ... on User {\n age\n id\n name\n username\n }\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "age": 11, + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "age": 22, + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "interface-object-with-requires/006", + "query": "\n query {\n users {\n ... on User {\n age\n id\n name\n username\n }\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "age": 11, + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "age": 22, + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n users: [NodeWithName!]!\n }\n\n interface NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n }\n\n type User implements NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n age: Int\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n users: [NodeWithName!]!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface NodeWithName\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n}\n\ntype User implements NodeWithName\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n age: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\", \"@external\", \"@requires\"]\n )\n\n type Query {\n anotherUsers: [NodeWithName]\n }\n\n type NodeWithName @key(fields: \"id\") @interfaceObject {\n id: ID!\n name: String @external\n username: String @requires(fields: \"name\")\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @interfaceObject on OBJECT\n\ntype Query {\n anotherUsers: [NodeWithName]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype NodeWithName\n @key(fields: \"id\")\n @interfaceObject\n{\n id: ID!\n name: String @external\n username: String @requires(fields: \"name\")\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = NodeWithName" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "33463f5f364dbe8f06e7d0ba3ae3db8b805db357bf0c56a8b04ad688ec4d60b3", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n users: [NodeWithName!]!\n }\n\n interface NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n }\n\n type User implements NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n age: Int\n }\n `,\n resolvers: {\n NodeWithName: {\n __resolveReference(key: { id: string }) {\n const node = users.find((u) => u.id === key.id);\n\n if (!node) {\n return null;\n }\n\n return {\n __typename: \"User\",\n id: node.id,\n name: node.name,\n age: node.age,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n __typename: \"User\",\n id: user.id,\n name: user.name,\n age: user.age,\n };\n },\n },\n Query: {\n users() {\n return users.map((u) => ({\n __typename: \"User\",\n id: u.id,\n name: u.name,\n age: u.age,\n }));\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "a41c9e2c5162f16ca7deb1e520291f87f6efebac6a8997f09f776981ab0d7368", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\", \"@external\", \"@requires\"]\n )\n\n type Query {\n anotherUsers: [NodeWithName]\n }\n\n type NodeWithName @key(fields: \"id\") @interfaceObject {\n id: ID!\n name: String @external\n username: String @requires(fields: \"name\")\n }\n `,\n resolvers: {\n NodeWithName: {\n __resolveReference(key: { id: string } | { id: string; name: string }) {\n const node = users.find((u) => u.id === key.id);\n\n if (!node) {\n return null;\n }\n\n return {\n __typename: \"User\",\n id: node.id,\n name: \"name\" in key ? key.name : undefined,\n };\n },\n username(node: { id: string; name: string }) {\n const user = users.find((u) => u.id === node.id);\n\n if (!user) {\n return null;\n }\n\n if (!node.name) {\n throw new Error(\"Requires field 'name' not provided\");\n }\n\n return user.username;\n },\n },\n Query: {\n anotherUsers() {\n return users.map((u) => ({\n __typename: \"User\",\n id: u.id,\n username: u.username,\n }));\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "6a5cebe4bde40491373d1afebc3fbfeb4d6adf5ecbc1f96e60f44291007ac457", + "source": "export const users = [\n {\n id: \"u1\",\n name: \"u1-name\",\n username: \"u1-username\",\n age: 11,\n },\n {\n id: \"u2\",\n name: \"u2-name\",\n username: \"u2-username\",\n age: 22,\n },\n];\n" + } + ] + }, + { + "id": "keys-mashup", + "cases": [ + { + "id": "keys-mashup/000", + "query": "\n query {\n b {\n id\n a {\n id\n name\n nameInB\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "b": { + "id": "100", + "a": [ + { + "id": "1", + "name": "a.1", + "nameInB": "b.a.nameInB a.1" + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.5\", import: [\"@key\"])\n\n type A\n @key(fields: \"id\", resolvable: true)\n @key(fields: \"pId\", resolvable: false)\n @key(fields: \"compositeId { one two }\", resolvable: false)\n @key(fields: \"id compositeId { two three }\", resolvable: false) {\n id: ID!\n pId: ID!\n compositeId: CompositeID!\n name: String!\n }\n\n type CompositeID {\n one: ID!\n two: ID!\n three: ID!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.5\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ndirective @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ndirective @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ntype A\n @key(fields: \"id\", resolvable: true)\n @key(fields: \"pId\", resolvable: false)\n @key(fields: \"compositeId { one two }\", resolvable: false)\n @key(fields: \"id compositeId { two three }\", resolvable: false)\n{\n id: ID!\n pId: ID!\n compositeId: CompositeID!\n name: String!\n}\n\ntype CompositeID {\n one: ID!\n two: ID!\n three: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar federation__Scope\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = A\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.5\"\n import: [\"@key\", \"@requires\", \"@external\"]\n )\n\n type Query {\n b: B\n }\n\n type B @key(fields: \"id\") {\n id: ID!\n a: [A!]!\n }\n\n type A\n @key(fields: \"compositeId { one two }\", resolvable: false)\n @key(fields: \"id compositeId { two three }\", resolvable: true)\n @key(fields: \"pId\", resolvable: false)\n @key(fields: \"id\", resolvable: false) {\n id: ID!\n pId: ID!\n compositeId: CompositeID!\n name: String! @external\n nameInB: String! @requires(fields: \"name\")\n }\n\n type CompositeID {\n one: ID!\n two: ID!\n three: ID!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.5\", import: [\"@key\", \"@requires\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ndirective @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ndirective @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ntype Query {\n b: B\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype B\n @key(fields: \"id\")\n{\n id: ID!\n a: [A!]!\n}\n\ntype A\n @key(fields: \"compositeId { one two }\", resolvable: false)\n @key(fields: \"id compositeId { two three }\", resolvable: true)\n @key(fields: \"pId\", resolvable: false)\n @key(fields: \"id\", resolvable: false)\n{\n id: ID!\n pId: ID!\n compositeId: CompositeID!\n name: String! @external\n nameInB: String! @requires(fields: \"name\")\n}\n\ntype CompositeID {\n one: ID!\n two: ID!\n three: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar federation__Scope\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = A | B" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "202b06759a5e6e0706a4e4d1d510ddcfb1a48d125048d3889c6ca6764712d010", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { data } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.5\", import: [\"@key\"])\n\n type A\n @key(fields: \"id\", resolvable: true)\n @key(fields: \"pId\", resolvable: false)\n @key(fields: \"compositeId { one two }\", resolvable: false)\n @key(fields: \"id compositeId { two three }\", resolvable: false) {\n id: ID!\n pId: ID!\n compositeId: CompositeID!\n name: String!\n }\n\n type CompositeID {\n one: ID!\n two: ID!\n three: ID!\n }\n `,\n resolvers: {\n A: {\n __resolveReference: (reference: { id: string }) => {\n // The only key that is resolvable is \"id\"\n const obj = data.a[reference.id];\n\n if (!obj) {\n return null;\n }\n\n return {\n __typename: \"A\",\n id: obj.id,\n pId: obj.pId,\n compositeId: obj.compositeId,\n name: obj.name,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "bc91e9c0d8827fc8e4c050bcd64a2b808c0a999afba16bb314fbcf18b15eedf0", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { data } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.5\"\n import: [\"@key\", \"@requires\", \"@external\"]\n )\n\n type Query {\n b: B\n }\n\n type B @key(fields: \"id\") {\n id: ID!\n a: [A!]!\n }\n\n type A\n @key(fields: \"compositeId { one two }\", resolvable: false)\n @key(fields: \"id compositeId { two three }\", resolvable: true)\n @key(fields: \"pId\", resolvable: false)\n @key(fields: \"id\", resolvable: false) {\n id: ID!\n pId: ID!\n compositeId: CompositeID!\n name: String! @external\n nameInB: String! @requires(fields: \"name\")\n }\n\n type CompositeID {\n one: ID!\n two: ID!\n three: ID!\n }\n `,\n resolvers: {\n Query: {\n b: () => {\n return {\n __typename: \"B\",\n id: data.b[\"100\"].id,\n a: data.b[\"100\"].a,\n };\n },\n },\n B: {\n __resolveReference: (reference: { id: string }) => {\n const obj = data.b[reference.id];\n\n if (!obj) {\n return null;\n }\n\n return {\n __typename: \"B\",\n id: obj.id,\n a: obj.a,\n };\n },\n a: ({ a }: { a: string[] }) => {\n return a.map((id) => {\n const obj = data.a[id];\n\n if (!obj) {\n return null;\n }\n\n return {\n __typename: \"A\",\n id: obj.id,\n pId: obj.pId,\n compositeId: obj.compositeId,\n };\n });\n },\n },\n A: {\n __resolveReference: (reference: {\n id: string;\n compositeId: { two: string; three: string };\n name?: string;\n }) => {\n const obj = data.a[reference.id];\n\n if (!obj) {\n return null;\n }\n\n if (reference.name) {\n return {\n __typename: \"A\",\n id: obj.id,\n pId: obj.pId,\n compositeId: obj.compositeId,\n name: reference.name,\n };\n }\n\n return {\n __typename: \"A\",\n id: obj.id,\n pId: obj.pId,\n compositeId: obj.compositeId,\n };\n },\n nameInB: ({ name }: { name?: string }) => {\n if (!name) {\n throw new Error(\"A.name was not provided\");\n }\n\n return `b.a.nameInB ${name}`;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "13652e843c7ae6740a2462e79a3b0b73b9c50c1f8778a7ea8aae747d0a65838d", + "source": "export const data: {\n a: Record<\n string,\n {\n id: string;\n pId: string;\n name: string;\n compositeId: {\n one: string;\n two: string;\n three: string;\n };\n }\n >;\n b: Record;\n} = {\n a: {\n \"1\": {\n id: \"1\",\n pId: \"a.1.pId\",\n name: \"a.1\",\n compositeId: {\n one: \"a.1.compositeId.one\",\n two: \"a.1.compositeId.two\",\n three: \"a.1.compositeId.three\",\n },\n },\n \"2\": {\n id: \"2\",\n pId: \"a.2.pId\",\n name: \"a.2\",\n compositeId: {\n one: \"a.2.compositeId.one\",\n two: \"a.2.compositeId.two\",\n three: \"a.2.compositeId.three\",\n },\n },\n },\n b: {\n \"100\": { id: \"100\", a: [\"1\"] },\n \"200\": { id: \"200\", a: [\"1\", \"2\"] },\n },\n};\n" + } + ] + }, + { + "id": "mutations", + "cases": [ + { + "id": "mutations/000", + "query": "\n mutation {\n addProduct(input: { name: \"new\", price: 599.99 }) {\n name\n price\n isExpensive\n isAvailable\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "addProduct": { + "name": "new", + "price": 599.99, + "isExpensive": true, + "isAvailable": true + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "mutations/001", + "query": "\n query {\n product(id: \"p1\") {\n id\n name\n price\n isExpensive\n isAvailable\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "id": "p1", + "name": "p1-name", + "price": 9.99, + "isExpensive": false, + "isAvailable": true + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "mutations/002", + "query": "\n mutation {\n five: add(num: 5, requestId: \"a\")\n ten: multiply(by: 2, requestId: \"a\")\n twelve: add(num: 2, requestId: \"a\")\n final: delete(requestId: \"a\")\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "five": 5, + "ten": 10, + "twelve": 12, + "final": 12 + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "mutations/003", + "query": "\n mutation {\n addCategory(name: \"new\", requestId: \"a\") {\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "addCategory": { + "id": "c-added-a", + "name": "new" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Mutation {\n addProduct(input: AddProductInput!): Product!\n addCategory(name: String!, requestId: String!): Category! @shareable\n multiply(by: Int!, requestId: String!): Int!\n }\n\n type Query {\n product(id: ID!): Product!\n products: [Product!]!\n }\n\n input AddProductInput {\n name: String!\n price: Float!\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n name: String!\n price: Float!\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n mutation: Mutation\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Mutation {\n addProduct(input: AddProductInput!): Product!\n addCategory(name: String!, requestId: String!): Category! @shareable\n multiply(by: Int!, requestId: String!): Int!\n}\n\ntype Query {\n product(id: ID!): Product!\n products: [Product!]!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninput AddProductInput {\n name: String!\n price: Float!\n}\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n name: String!\n price: Float!\n}\n\ntype Category\n @key(fields: \"id\")\n{\n id: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n isAvailable: Boolean!\n }\n\n type Mutation {\n delete(requestId: String!): Int!\n addCategory(name: String!, requestId: String!): Category! @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n mutation: Mutation\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n isAvailable: Boolean!\n}\n\ntype Mutation {\n delete(requestId: String!): Int!\n addCategory(name: String!, requestId: String!): Category! @shareable\n}\n\ntype Category\n @key(fields: \"id\")\n{\n id: ID!\n name: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Mutation {\n add(num: Int!, requestId: String!): Int!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n mutation: Mutation\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Mutation {\n add(num: Int!, requestId: String!): Int!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\ntype Query {\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "05097bd14896f0d66ad34504fac1be5134fcfc192f39194b5294da4308601aeb", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport {\n addCategory,\n addProduct,\n deleteProduct,\n getCategories,\n getProducts,\n initProducts,\n multiplyNumber,\n} from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Mutation {\n addProduct(input: AddProductInput!): Product!\n addCategory(name: String!, requestId: String!): Category! @shareable\n multiply(by: Int!, requestId: String!): Int!\n }\n\n type Query {\n product(id: ID!): Product!\n products: [Product!]!\n }\n\n input AddProductInput {\n name: String!\n price: Float!\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n name: String!\n price: Float!\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n }\n `,\n resolvers: {\n Query: {\n async product(_: {}, { id }: { id: string }) {\n initProducts();\n const product = (await getProducts()).find((p) => p.id === id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n name: product.name,\n price: product.price,\n };\n },\n async products() {\n initProducts();\n return getProducts();\n },\n },\n Mutation: {\n async multiply(\n _: {},\n args: {\n by: number;\n requestId: string;\n },\n ) {\n return multiplyNumber(args.by, args.requestId);\n },\n async addProduct(\n _: {},\n {\n input,\n }: {\n input: {\n name: string;\n price: number;\n };\n },\n ) {\n return addProduct(input.name, input.price);\n },\n async addCategory(\n _: {},\n {\n name,\n requestId,\n }: {\n name: string;\n requestId: string;\n },\n ) {\n return addCategory(name, requestId);\n },\n },\n Product: {\n async __resolveReference(key: { id: string }) {\n const products = await getProducts();\n const product = products.find((p) => p.id === key.id);\n\n if (!product) {\n return null;\n }\n\n await deleteProduct(product.id);\n\n return {\n id: product.id,\n name: product.name,\n price: product.price,\n };\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n const categories = getCategories();\n const category = categories.find((p) => p.id === key.id);\n\n if (!category) {\n return null;\n }\n\n return {\n id: category.id,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "3ecc406643b32dd602d7b80b8b7b37f1df8b8247565a3d4455350b7e38a023f8", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport {\n addCategory,\n deleteNumber,\n deleteProduct,\n getCategories,\n getProducts,\n} from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n isAvailable: Boolean!\n }\n\n type Mutation {\n delete(requestId: String!): Int!\n addCategory(name: String!, requestId: String!): Category! @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n `,\n resolvers: {\n Mutation: {\n delete(\n _: {},\n args: {\n requestId: string;\n },\n ) {\n return deleteNumber(args.requestId);\n },\n async addCategory(\n _: {},\n {\n name,\n requestId,\n }: {\n name: string;\n requestId: string;\n },\n ) {\n return addCategory(name, requestId);\n },\n },\n Product: {\n async __resolveReference(key: { id: string; price?: number }) {\n const product = (await getProducts()).find(\n (product) => product.id === key.id,\n );\n\n if (!product) {\n return null;\n }\n\n await deleteProduct(product.id);\n\n if (typeof product.price === \"number\") {\n return {\n id: product.id,\n isAvailable: true,\n price: product.price,\n };\n }\n\n return {\n id: product.id,\n isAvailable: false,\n };\n },\n isExpensive(product: { price?: number }) {\n if (typeof product.price !== \"number\") {\n throw new Error(\"Price is not available\");\n }\n\n return product.price > 100;\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n const categories = getCategories();\n const category = categories.find((p) => p.id === key.id);\n\n if (!category) {\n return null;\n }\n\n return {\n id: category.id,\n name: category.name,\n };\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "45f9c52e827c480ac1094cff80f97cde7974895403976b7ecd628dac228254d4", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { addNumber } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Mutation {\n add(num: Int!, requestId: String!): Int!\n }\n `,\n resolvers: {\n Mutation: {\n add(\n _: {},\n args: {\n num: number;\n requestId: string;\n },\n ) {\n return addNumber(args.num, args.requestId);\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "d342b6d4ec6c633e08942ca811dc3dead0fff8d640edd10eebc234517b0c23ba", + "source": "interface Product {\n id: string;\n name: string;\n price: number;\n}\n\ninterface Category {\n id: string;\n name: string;\n}\n\nlet products: Product[] = [];\nlet categories: Category[] = [];\nconst numbers: Record = {};\n\nexport async function getProducts(): Promise {\n return products;\n}\n\nexport function getCategories(): Category[] {\n return categories;\n}\n\nexport async function addProduct(name: string, price: number) {\n const newProduct = {\n id: \"p-added-\" + products.length,\n name: name,\n price: price,\n };\n products.push(newProduct);\n return newProduct;\n}\n\nexport async function addCategory(name: string, requestId: string) {\n if (categories.some((c) => c.id === \"c-added-\" + requestId)) {\n throw new Error(\"Category with this requestId was already added\");\n }\n\n const newCategory = {\n id: \"c-added-\" + requestId,\n name: name,\n };\n categories.push(newCategory);\n return newCategory;\n}\n\nexport async function deleteProduct(id: string) {\n const after = products.filter((p) => p.id !== id);\n products = after;\n}\n\nexport function initProducts() {\n const product = {\n id: \"p1\",\n name: \"p1-name\",\n price: 9.99,\n };\n\n if (products.some((p) => p.id === product.id)) {\n return;\n }\n\n products.push(product);\n}\n\nfunction getNumber(requestId: string) {\n const num = numbers[requestId];\n return num ?? 0;\n}\n\nexport function addNumber(num: number, requestId: string) {\n const existingNumber = getNumber(requestId);\n const sum = existingNumber + num;\n numbers[requestId] = sum;\n return sum;\n}\n\nexport function multiplyNumber(by: number, requestId: string) {\n const existingNumber = getNumber(requestId);\n const result = existingNumber * by;\n numbers[requestId] = result;\n return result;\n}\n\nexport function deleteNumber(requestId: string) {\n const num = getNumber(requestId);\n if (typeof numbers[requestId] === \"number\") {\n delete numbers[requestId];\n }\n return num;\n}\n" + } + ] + }, + { + "id": "mysterious-external", + "cases": [ + { + "id": "mysterious-external/000", + "query": "\n query {\n cheapestProduct {\n id\n price\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "cheapestProduct": { + "id": "1", + "price": 100, + "name": "name-1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "mysterious-external/001", + "query": "\n query {\n products {\n name\n price\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "name": "name-1", + "price": 100, + "id": "1" + }, + { + "name": "name-2", + "price": 200, + "id": "2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "price", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\"]\n )\n\n # Composition will fail if it's not an extension (I have no idea why this is the case)\n extend type Product @key(fields: \"id\") {\n id: ID! @external\n price: Float\n }\n\n type Query {\n cheapestProduct: Product\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\nextend type Product\n @key(fields: \"id\")\n{\n id: ID! @external\n price: Float\n}\n\ntype Query {\n cheapestProduct: Product\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + }, + { + "name": "product", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n\n type Query {\n products: [Product!]!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n name: String!\n}\n\ntype Query {\n products: [Product!]!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + } + ], + "fixtureModules": [ + { + "path": "data.ts", + "sha256": "7a72bbbcf26eaaec331d950360129ad92445715224249bd1f802a55794508819", + "source": "export const products = [\n {\n id: \"1\",\n name: \"name-1\",\n price: 100,\n },\n {\n id: \"2\",\n name: \"name-2\",\n price: 200,\n },\n];\n" + }, + { + "path": "price.subgraph.ts", + "sha256": "5a599d53ffca8b44d53d71d7e8261b0c43d2531e99713f994e958fbe77f7566d", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"price\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\"]\n )\n\n # Composition will fail if it's not an extension (I have no idea why this is the case)\n extend type Product @key(fields: \"id\") {\n id: ID! @external\n price: Float\n }\n\n type Query {\n cheapestProduct: Product\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string }) {\n const product = products.find((product) => product.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n price: product.price,\n };\n },\n },\n Query: {\n cheapestProduct() {\n let cheapest: (typeof products)[number] | null = null;\n\n for (const product of products) {\n if (cheapest) {\n if (product.price < cheapest.price) {\n cheapest = product;\n }\n } else {\n cheapest = product;\n }\n }\n\n return cheapest;\n },\n },\n },\n});\n" + }, + { + "path": "product.subgraph.ts", + "sha256": "4c06e6db4b427e9fe0e5143e4a1c4091bea45fd6727ea1755bef072e0609f937", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"product\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n\n type Query {\n products: [Product!]!\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string }) {\n const product = products.find((product) => product.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n name: product.name,\n };\n },\n },\n Query: {\n products() {\n return products.map((p) => ({\n id: p.id,\n name: p.name,\n }));\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "nested-provides", + "cases": [ + { + "id": "nested-provides/000", + "query": "\n query {\n products {\n id\n categories {\n id\n name\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "id": "p1", + "categories": [ + { + "id": "c1", + "name": "Category 1" + }, + { + "id": "c2", + "name": "Category 2" + } + ] + }, + { + "id": "p2", + "categories": [ + { + "id": "c3", + "name": "Category 3" + }, + { + "id": "c2", + "name": "Category 2" + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "nested-provides/001", + "query": "\n query {\n products {\n id\n categories {\n id\n name\n subCategories {\n id\n name\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "id": "p1", + "categories": [ + { + "id": "c1", + "name": "Category 1", + "subCategories": [ + { + "id": "c2", + "name": "Category 2" + } + ] + }, + { + "id": "c2", + "name": "Category 2", + "subCategories": [ + { + "id": "c3", + "name": "Category 3" + } + ] + } + ] + }, + { + "id": "p2", + "categories": [ + { + "id": "c3", + "name": "Category 3", + "subCategories": [ + { + "id": "c1", + "name": "Category 1" + } + ] + }, + { + "id": "c2", + "name": "Category 2", + "subCategories": [ + { + "id": "c3", + "name": "Category 3" + } + ] + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "all-products", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "category", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\", \"@provides\"]\n )\n\n type Query {\n products: [Product]\n @shareable\n @provides(fields: \"categories { id name subCategories { id name } }\")\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n categories: [Category] @external\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n \"\"\"\n This field is provided by Query.products\n and we deliberately don't resolve it.\n The test suite is about checking if @provides is used correctly.\n \"\"\"\n name: String\n subCategories: [Category] @external\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@external\", \"@provides\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n products: [Product] @shareable @provides(fields: \"categories { id name subCategories { id name } }\")\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n categories: [Category] @external\n}\n\ntype Category\n @key(fields: \"id\")\n{\n id: ID!\n\n \"\"\"\n This field is provided by Query.products\n and we deliberately don't resolve it.\n The test suite is about checking if @provides is used correctly.\n \"\"\"\n name: String\n subCategories: [Category] @external\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product" + }, + { + "name": "subcategories", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n categories: [Category] @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n subCategories: [Category] @shareable\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n categories: [Category] @shareable\n}\n\ntype Category\n @key(fields: \"id\")\n{\n id: ID!\n subCategories: [Category] @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "all-products.subgraph.ts", + "sha256": "cec25d29798e33e34226593d90c1e42f7035d0402f4924453a68325bb0c4cfdb", + "source": "import { shouldPunishForPoorPlans } from \"../../env.js\";\nimport { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\n// I deliberately name it all-products to make sure it's first in the list of subgraphs (in case the order matters)\nexport default createSubgraph(\"all-products\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string }) {\n if (shouldPunishForPoorPlans()) {\n throw new Error(\"You should be using the categories subgraph!\");\n }\n\n const product = products.find((p) => p.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n };\n },\n },\n },\n});\n" + }, + { + "path": "category.subgraph.ts", + "sha256": "4883312a3361dae693493f3f416270434dcca38517854affed9887398b8cbec8", + "source": "import { shouldPunishForPoorPlans } from \"../../env.js\";\nimport { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"category\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\", \"@provides\"]\n )\n\n type Query {\n products: [Product]\n @shareable\n @provides(fields: \"categories { id name subCategories { id name } }\")\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n categories: [Category] @external\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n \"\"\"\n This field is provided by Query.products\n and we deliberately don't resolve it.\n The test suite is about checking if @provides is used correctly.\n \"\"\"\n name: String\n subCategories: [Category] @external\n }\n `,\n resolvers: {\n Query: {\n products() {\n return products.map((p) => ({\n id: p.id,\n categories: p.categories.map((catId) => {\n const cat = categories.find((c) => c.id === catId);\n\n if (!cat) {\n return null;\n }\n\n return {\n id: cat.id,\n name: cat.name,\n subCategories: cat.subCategories.map((subCatId) => {\n const subCat = categories.find((c) => c.id === subCatId);\n\n if (!subCat) {\n return null;\n }\n\n return {\n id: subCat.id,\n name: subCat.name,\n };\n }),\n };\n }),\n }));\n },\n },\n Product: {\n __resolveReference(key: { id: string }, context: any) {\n if (shouldPunishForPoorPlans()) {\n throw new Error(\"You should be using the categories subgraph!\");\n }\n\n const product = products.find((p) => p.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n };\n },\n },\n Category: {\n __resolveReference(key: { id: string }, context: any) {\n if (shouldPunishForPoorPlans()) {\n throw new Error(\"You should be using the categories subgraph!\");\n }\n\n const cat = categories.find((c) => c.id === key.id);\n\n if (!cat) {\n return null;\n }\n\n return {\n id: cat.id,\n // We explicitly don't resolve `name` here\n // name: cat.name,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "d5bb60afb87e46d83cb045a96d795a3de69ea06bb64616bc6bf74694a6fcfa3e", + "source": "export const products = [\n {\n id: \"p1\",\n categories: [\"c1\", \"c2\"],\n },\n {\n id: \"p2\",\n categories: [\"c3\", \"c2\"],\n },\n];\n\nexport const categories = [\n {\n id: \"c1\",\n name: \"Category 1\",\n subCategories: [\"c2\"],\n },\n {\n id: \"c2\",\n name: \"Category 2\",\n subCategories: [\"c3\"],\n },\n {\n id: \"c3\",\n name: \"Category 3\",\n subCategories: [\"c1\"],\n },\n];\n" + }, + { + "path": "subcategories.subgraph.ts", + "sha256": "e7f747376171278a687e3edb516a60478697628882e2ccd240f61a1d3a65cb0d", + "source": "import { shouldPunishForPoorPlans } from \"../../env.js\";\nimport { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"subcategories\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n categories: [Category] @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n subCategories: [Category] @shareable\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string }, context: any) {\n if (shouldPunishForPoorPlans()) {\n throw new Error(\"You should be using the categories subgraph!\");\n }\n\n const product = products.find((p) => p.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n categories: product.categories,\n };\n },\n categories(product: { categories: string[] }, _a: unknown, context: any) {\n if (shouldPunishForPoorPlans()) {\n throw new Error(\"You should be using the categories subgraph!\");\n }\n\n return product.categories.map((catId) => {\n const cat = categories.find((c) => c.id === catId);\n\n if (!cat) {\n return null;\n }\n\n return {\n id: cat.id,\n subCategories: cat.subCategories,\n };\n });\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n const cat = categories.find((c) => c.id === key.id);\n\n if (!cat) {\n return null;\n }\n\n return {\n id: cat.id,\n subCategories: cat.subCategories,\n };\n },\n subCategories(category: { subCategories: string[] }) {\n return category.subCategories.map((catId) => {\n const cat = categories.find((c) => c.id === catId);\n\n if (!cat) {\n return null;\n }\n\n return {\n id: cat.id,\n subCategories: cat.subCategories,\n };\n });\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "node", + "cases": [ + { + "id": "node/000", + "query": "\n {\n productNode {\n ... on Product {\n id\n name\n __typename\n price\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "productNode": { + "id": "p-1", + "name": "Product 1", + "__typename": "Product", + "price": 10 + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "node", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n productNode: Node\n categoryNode: Node\n }\n\n interface Node {\n id: ID!\n }\n\n type Product implements Node @key(fields: \"id\") {\n id: ID!\n }\n\n type Category implements Node @key(fields: \"id\") {\n id: ID!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n productNode: Node\n categoryNode: Node\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Node {\n id: ID!\n}\n\ntype Product implements Node\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Category implements Node\n @key(fields: \"id\")\n{\n id: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product" + }, + { + "name": "node-two", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n interface Node {\n id: ID!\n }\n\n type Product implements Node @key(fields: \"id\") {\n id: ID!\n }\n\n type Category implements Node @key(fields: \"id\") {\n id: ID!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninterface Node {\n id: ID!\n}\n\ntype Product implements Node\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Category implements Node\n @key(fields: \"id\")\n{\n id: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "types", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n interface Node {\n id: ID!\n }\n\n type Product implements Node @key(fields: \"id\") @shareable {\n id: ID!\n name: String!\n price: Float!\n }\n\n type Category implements Node @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninterface Node {\n id: ID!\n}\n\ntype Product implements Node\n @key(fields: \"id\")\n @shareable\n{\n id: ID!\n name: String!\n price: Float!\n}\n\ntype Category implements Node\n @key(fields: \"id\")\n{\n id: ID!\n name: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "data.ts", + "sha256": "dd3ba1e1231367cb8131321aa6c28694ca4e61d6c8cb22d701870e94dd7ea388", + "source": "export const products = [\n {\n id: \"p-1\",\n name: \"Product 1\",\n price: 10.0,\n },\n {\n id: \"p-2\",\n name: \"Product 2\",\n price: 20.0,\n },\n];\n\nexport const categories = [\n {\n id: \"pc-1\",\n name: \"Category 1\",\n },\n {\n id: \"c-2\",\n name: \"Category 2\",\n },\n];\n" + }, + { + "path": "node.subgraph.ts", + "sha256": "fa680a47506c1aa32c5921e6caf0f6b34f3ea4c47abebdf41618e3007a52e417", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"node\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n productNode: Node\n categoryNode: Node\n }\n\n interface Node {\n id: ID!\n }\n\n type Product implements Node @key(fields: \"id\") {\n id: ID!\n }\n\n type Category implements Node @key(fields: \"id\") {\n id: ID!\n }\n `,\n resolvers: {\n Query: {\n productNode() {\n return {\n __typename: \"Product\",\n id: products[0].id,\n };\n },\n categoryNode() {\n return {\n __typename: \"Category\",\n id: categories[0].id,\n };\n },\n },\n Product: {\n __resolveReference(key: { id: string }) {\n const product = products.find((p) => p.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n };\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n const cat = categories.find((c) => c.id === key.id);\n\n if (!cat) {\n return null;\n }\n\n return {\n id: cat.id,\n };\n },\n },\n },\n});\n" + }, + { + "path": "types.subgraph.ts", + "sha256": "1d0c73d29456d9232b451dfc25be667cd4e1d88d179bb44a678052f8962f54a3", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"types\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n interface Node {\n id: ID!\n }\n\n type Product implements Node @key(fields: \"id\") @shareable {\n id: ID!\n name: String!\n price: Float!\n }\n\n type Category implements Node @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string }) {\n const product = products.find((p) => p.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n name: product.name,\n price: product.price,\n };\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n const cat = categories.find((c) => c.id === key.id);\n\n if (!cat) {\n return null;\n }\n\n return {\n id: cat.id,\n name: cat.name,\n };\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "non-resolvable-interface-object", + "cases": [ + { + "id": "non-resolvable-interface-object/000", + "query": "\n query {\n b {\n id\n field\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "b": { + "id": "n1", + "field": "foo" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "non-resolvable-interface-object/001", + "query": "\n query {\n a {\n field\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "non-resolvable-interface-object/002", + "query": "\n query {\n b {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "b": { + "id": "n1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "non-resolvable-interface-object/003", + "query": "\n query {\n a {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "a": null + }, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "non-resolvable-interface-object/004", + "query": "\n query {\n product {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "id": "p1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "non-resolvable-interface-object/005", + "query": "\n query {\n product {\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": false, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "non-resolvable-interface-object/006", + "query": "\n query {\n product {\n ... on Bread {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "id": "p1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n interface Node @key(fields: \"id\") {\n id: ID!\n }\n\n type Product @key(fields: \"id\", resolvable: false) @interfaceObject {\n id: ID!\n }\n\n type Query {\n a: Node\n product: Product!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @interfaceObject on OBJECT\n\ninterface Node\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Product\n @key(fields: \"id\", resolvable: false)\n @interfaceObject\n{\n id: ID!\n}\n\ntype Query {\n a: Node\n product: Product!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n type Node @key(fields: \"id\", resolvable: false) @interfaceObject {\n id: ID!\n field: String\n }\n\n interface Product @key(fields: \"id\") {\n id: ID!\n }\n\n type Bread implements Product @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n\n type Query {\n b: Node\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @interfaceObject on OBJECT\n\ntype Node\n @key(fields: \"id\", resolvable: false)\n @interfaceObject\n{\n id: ID!\n field: String\n}\n\ninterface Product\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Bread implements Product\n @key(fields: \"id\")\n{\n id: ID!\n name: String!\n}\n\ntype Query {\n b: Node\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Bread | Node" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "709c07b785e551a04a2b635aba2c5e09286a20025c6e55be13f223df8268439f", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n interface Node @key(fields: \"id\") {\n id: ID!\n }\n\n type Product @key(fields: \"id\", resolvable: false) @interfaceObject {\n id: ID!\n }\n\n type Query {\n a: Node\n product: Product!\n }\n `,\n resolvers: {\n Query: {\n a() {\n return { __typename: \"Node\", id: \"n1\" };\n },\n product() {\n return { __typename: \"Product\", id: products[0].id };\n },\n },\n Node: {\n __resolveReference() {\n throw new Error(\"Not resolvable as it is an interface object\");\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "93aedb3600add39a2f8b97feded5c0a098d55e652602b780db0cdc6761d290e1", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n type Node @key(fields: \"id\", resolvable: false) @interfaceObject {\n id: ID!\n field: String\n }\n\n interface Product @key(fields: \"id\") {\n id: ID!\n }\n\n type Bread implements Product @key(fields: \"id\") {\n id: ID!\n name: String!\n }\n\n type Query {\n b: Node\n }\n `,\n resolvers: {\n Query: {\n b() {\n return { __typename: \"Node\", id: \"n1\" };\n },\n },\n Node: {\n __resolveReference() {\n throw new Error(\"Not resolvable\");\n },\n field() {\n return \"foo\";\n },\n },\n Product: {\n __resolveReference(key: { id: string }) {\n return products.find((p) => p.id === key.id);\n },\n },\n Bread: {\n __resolveReference(key: { id: string }) {\n return products.find((p) => p.id === key.id);\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "bc44295e53b2e7864a9fdfb8262764c3c01e749611ef079c85b12140b405a783", + "source": "export const products = [\n {\n __typename: \"Bread\",\n id: \"p1\",\n name: \"Bread\",\n },\n];\n" + } + ] + }, + { + "id": "null-keys", + "cases": [ + { + "id": "null-keys/000", + "query": "\n query {\n bookContainers {\n book {\n upc\n author {\n name\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "bookContainers": [ + { + "book": { + "upc": "b1", + "author": { + "name": "Alice" + } + } + }, + { + "book": { + "upc": "b2", + "author": { + "name": "Bob" + } + } + }, + { + "book": { + "upc": "b3", + "author": null + } + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n bookContainers: [BookContainer]\n }\n type BookContainer {\n book: Book\n }\n type Book @key(fields: \"upc\") {\n upc: ID!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n bookContainers: [BookContainer]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype BookContainer {\n book: Book\n}\n\ntype Book\n @key(fields: \"upc\")\n{\n upc: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Book @key(fields: \"id\") @key(fields: \"upc\") {\n id: ID!\n upc: ID!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Book\n @key(fields: \"id\")\n @key(fields: \"upc\")\n{\n id: ID!\n upc: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Book @key(fields: \"id\") {\n id: ID!\n author: Author\n }\n\n type Author {\n id: ID!\n name: String\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Book\n @key(fields: \"id\")\n{\n id: ID!\n author: Author\n}\n\ntype Author {\n id: ID!\n name: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "0f8ed17169e398e96ce3f24321cf8ba6dce3059da6ecf905c05b11964ed95a11", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { books } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n bookContainers: [BookContainer]\n }\n type BookContainer {\n book: Book\n }\n type Book @key(fields: \"upc\") {\n upc: ID!\n }\n `,\n resolvers: {\n Query: {\n bookContainers() {\n return books.map((book) => ({ book: { upc: book.upc } }));\n },\n },\n Book: {\n __resolveReference(reference: { upc: String }) {\n if (reference != null) {\n let book = books.find((book) => book.upc === reference.upc);\n if (book != null && book.upc !== null) {\n return {\n __typename: \"Book\",\n upc: book.upc,\n };\n }\n }\n throw new Error(\"Invalid reference\");\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "c0a6e1a23d54e7084bec901b3f9232a0f52842be1d22c4f46f42e0451c7813b9", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { books } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Book @key(fields: \"id\") @key(fields: \"upc\") {\n id: ID!\n upc: ID!\n }\n `,\n resolvers: {\n Book: {\n __resolveReference(reference: { id: String } | { upc: String }) {\n if (reference != null) {\n let book: { id: string; upc: string } | undefined;\n if (\"id\" in reference) {\n book = books.find((book) => book.id === reference.id);\n }\n if (\"upc\" in reference) {\n book = books.find((book) => book.upc === reference.upc);\n }\n if (book != null) {\n // `a` has `Book` entities with upc: `b1, b2, b3`, but `b` has `Book` entities with only `b1` and `b2`.\n // `b3` is not available and this subgraph is the only possible step to get to the other subgraph (need of `id` field) to resolve the author.\n if (book.id === \"3\") {\n return null;\n }\n return {\n __typename: \"Book\",\n id: book.id,\n upc: book.upc,\n };\n }\n }\n throw new Error(\"Invalid reference\");\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "840968711d127c92d393acf115a1d05f40e63e41db5ca7d11bfbb24e2f6c659e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { books } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Book @key(fields: \"id\") {\n id: ID!\n author: Author\n }\n\n type Author {\n id: ID!\n name: String\n }\n `,\n resolvers: {\n Book: {\n __resolveReference(reference: { id: String } | { upc: String }) {\n if (reference != null) {\n let book:\n | { id: string; author: { id: string; name: string } }\n | undefined;\n if (\"id\" in reference && reference.id !== null) {\n book = books.find((book) => book.id === reference.id);\n }\n if (\"upc\" in reference && reference.upc !== null) {\n book = books.find((book) => book.upc === reference.upc);\n }\n if (book != null) {\n return {\n __typename: \"Book\",\n id: book.id,\n author: {\n __typename: \"Author\",\n id: book.author.id,\n name: book.author.name,\n },\n };\n }\n }\n throw new Error(\"Invalid reference\");\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "3480c4fa2734cc7b2935a3df95ee8feebacb614fb55d3c7075dae741fe1e29f9", + "source": "export const books = [\n {\n __typename: \"Book\",\n id: \"1\",\n upc: \"b1\",\n author: {\n __typename: \"Author\",\n id: \"a1\",\n name: \"Alice\",\n },\n },\n {\n __typename: \"Book\",\n id: \"2\",\n upc: \"b2\",\n author: {\n __typename: \"Author\",\n id: \"a2\",\n name: \"Bob\",\n },\n },\n {\n __typename: \"Book\",\n id: \"3\",\n upc: \"b3\",\n author: {\n __typename: \"Author\",\n id: \"a3\",\n name: \"Jack\",\n },\n },\n];\n" + } + ] + }, + { + "id": "override-type-interface", + "cases": [ + { + "id": "override-type-interface/000", + "query": "\n query {\n feed {\n id\n createdAt\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "id": "i1", + "createdAt": "i1-createdAt" + }, + { + "id": "i2", + "createdAt": "i2-createdAt" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "override-type-interface/001", + "query": "\n query {\n feed {\n ... on TextPost {\n id\n body\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + {}, + {} + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "override-type-interface/002", + "query": "\n query {\n anotherFeed {\n createdAt\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherFeed": [ + { + "createdAt": "i1-createdAt" + }, + { + "createdAt": "i2-createdAt" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "override-type-interface/003", + "query": "\n {\n anotherFeed {\n createdAt\n id\n ... on ImagePost {\n createdAt\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherFeed": [ + { + "createdAt": "i1-createdAt", + "id": "i1" + }, + { + "createdAt": "i2-createdAt", + "id": "i2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n interface Post {\n id: ID!\n createdAt: String!\n }\n\n type ImagePost implements Post @key(fields: \"id\") {\n id: ID!\n createdAt: String!\n }\n\n type Query {\n feed: [Post]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninterface Post {\n id: ID!\n createdAt: String!\n}\n\ntype ImagePost implements Post\n @key(fields: \"id\")\n{\n id: ID!\n createdAt: String!\n}\n\ntype Query {\n feed: [Post]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = ImagePost" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@override\"]\n )\n\n interface Post {\n id: ID!\n createdAt: String!\n }\n\n type TextPost implements Post @key(fields: \"id\") {\n id: ID!\n createdAt: String!\n body: String!\n }\n\n interface AnotherPost {\n id: ID!\n createdAt: String!\n }\n\n type ImagePost implements AnotherPost @key(fields: \"id\") {\n id: ID!\n createdAt: String! @override(from: \"a\")\n }\n\n type Query {\n anotherFeed: [AnotherPost]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@override\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninterface Post {\n id: ID!\n createdAt: String!\n}\n\ntype TextPost implements Post\n @key(fields: \"id\")\n{\n id: ID!\n createdAt: String!\n body: String!\n}\n\ninterface AnotherPost {\n id: ID!\n createdAt: String!\n}\n\ntype ImagePost implements AnotherPost\n @key(fields: \"id\")\n{\n id: ID!\n createdAt: String! @override(from: \"a\")\n}\n\ntype Query {\n anotherFeed: [AnotherPost]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = ImagePost | TextPost" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "db3a1ba13c8827c244dc1eb234d977b577271d639147562c6a97aee1a996d82f", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { imagePosts } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n interface Post {\n id: ID!\n createdAt: String!\n }\n\n type ImagePost implements Post @key(fields: \"id\") {\n id: ID!\n createdAt: String!\n }\n\n type Query {\n feed: [Post]\n }\n `,\n resolvers: {\n Query: {\n feed() {\n return imagePosts;\n },\n },\n ImagePost: {\n __resolveReference(key: { id: string }) {\n const post = imagePosts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n createdAt: post.createdAt,\n };\n },\n createdAt() {\n return \"NEVER\";\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "c3971c48e04b0e58158e31b8cf8d07c84f8f93cc4f9d49b9cfae0927ff3bba17", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { imagePosts, textPosts } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@override\"]\n )\n\n interface Post {\n id: ID!\n createdAt: String!\n }\n\n type TextPost implements Post @key(fields: \"id\") {\n id: ID!\n createdAt: String!\n body: String!\n }\n\n interface AnotherPost {\n id: ID!\n createdAt: String!\n }\n\n type ImagePost implements AnotherPost @key(fields: \"id\") {\n id: ID!\n createdAt: String! @override(from: \"a\")\n }\n\n type Query {\n anotherFeed: [AnotherPost]\n }\n `,\n resolvers: {\n Query: {\n anotherFeed() {\n return imagePosts;\n },\n },\n TextPost: {\n __resolveReference(key: { id: string }) {\n const post = textPosts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n createdAt: post.createdAt,\n body: post.body,\n };\n },\n },\n ImagePost: {\n __resolveReference(key: { id: string }) {\n const post = imagePosts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n createdAt: post.createdAt,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "ed3194df120ff7a37cf428a7586592071fa2dbb553f3f59a6528aff7ad529233", + "source": "export const imagePosts = [\n {\n __typename: \"ImagePost\",\n id: \"i1\",\n createdAt: \"i1-createdAt\",\n },\n {\n __typename: \"ImagePost\",\n id: \"i2\",\n createdAt: \"i2-createdAt\",\n },\n];\n\nexport const textPosts = [\n {\n __typename: \"TextPost\",\n id: \"t1\",\n createdAt: \"t1-createdAt\",\n body: \"t1-body\",\n },\n {\n __typename: \"TextPost\",\n id: \"t2\",\n createdAt: \"t2-createdAt\",\n body: \"t2-body\",\n },\n];\n" + } + ] + }, + { + "id": "override-with-requires", + "cases": [ + { + "id": "override-with-requires/000", + "query": "\n {\n userInA {\n id\n name\n aName\n cName\n }\n userInB {\n id\n name\n aName\n cName\n }\n userInC {\n id\n name\n aName\n cName\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "userInA": { + "id": "u1", + "name": "u1-name", + "aName": "a__u1-name", + "cName": "c__u1-name" + }, + "userInB": { + "id": "u2", + "name": "u2-name", + "aName": "a__u2-name", + "cName": "c__u2-name" + }, + "userInC": { + "id": "u3", + "name": "u3-name", + "aName": "a__u3-name", + "cName": "c__u3-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "override-with-requires/001", + "query": "\n query {\n userInC {\n cName\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "userInC": { + "cName": "c__u3-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "override-with-requires/002", + "query": "\n query {\n userInA {\n cName\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "userInA": { + "cName": "c__u1-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "override-with-requires/003", + "query": "\n query {\n userInA {\n aName\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "userInA": { + "aName": "a__u1-name" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@requires\", \"@external\"]\n )\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @external\n aName: String! @requires(fields: \"name\")\n }\n\n type Query {\n userInA: User\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@requires\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @external\n aName: String! @requires(fields: \"name\")\n}\n\ntype Query {\n userInA: User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@override\"]\n )\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @override(from: \"c\")\n }\n\n type Query {\n userInB: User\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@override\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @override(from: \"c\")\n}\n\ntype Query {\n userInB: User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@requires\", \"@external\"]\n )\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @external\n cName: String! @requires(fields: \"name\")\n }\n\n type Query {\n userInC: User\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@requires\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @external\n cName: String! @requires(fields: \"name\")\n}\n\ntype Query {\n userInC: User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "652ee31ad5bc168acdd3bc86f5bed414385fc29c9b81570e50b0cce3c09afeca", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@requires\", \"@external\"]\n )\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @external\n aName: String! @requires(fields: \"name\")\n }\n\n type Query {\n userInA: User\n }\n `,\n resolvers: {\n Query: {\n userInA() {\n return users[0];\n },\n },\n User: {\n __resolveReference(key: { id: string } | { id: string; name: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n if (\"name\" in key) {\n return {\n id: user.id,\n name: user.name,\n };\n }\n\n return {\n id: user.id,\n };\n },\n aName(user: { name: string }) {\n return `a__${user.name}`;\n },\n name() {\n return \"NEVER\";\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "6428449ae318be2c03d446143011c80d198b60371d9f6544e1290713000aa1ad", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@override\"]\n )\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @override(from: \"c\")\n }\n\n type Query {\n userInB: User\n }\n `,\n resolvers: {\n Query: {\n userInB() {\n return users[1];\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n };\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "0c4c88054dce079e001824b642fedfb329a045ac48b4ad3c66990a06dcdb0bff", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@requires\", \"@external\"]\n )\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @external\n cName: String! @requires(fields: \"name\")\n }\n\n type Query {\n userInC: User\n }\n `,\n resolvers: {\n Query: {\n userInC() {\n return users[2];\n },\n },\n User: {\n __resolveReference(key: { id: string } | { id: string; name: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n if (\"name\" in key) {\n return {\n id: user.id,\n name: user.name,\n };\n }\n\n return {\n id: user.id,\n };\n },\n name() {\n return \"NEVER\";\n },\n cName(user: { name: string }) {\n return `c__${user.name}`;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "25229fa9da466caebaeb30e3c69f26822b7a688babde0136b82baba1f66a2863", + "source": "export const users = [\n {\n id: \"u1\",\n name: \"u1-name\",\n },\n {\n id: \"u2\",\n name: \"u2-name\",\n },\n {\n id: \"u3\",\n name: \"u3-name\",\n },\n];\n" + } + ] + }, + { + "id": "parent-entity-call", + "cases": [ + { + "id": "parent-entity-call/000", + "query": "\n query {\n products {\n id\n category {\n id\n details {\n products\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "id": "p1", + "category": { + "id": "c1", + "details": { + "products": 2 + } + } + }, + { + "id": "p2", + "category": { + "id": "c2", + "details": { + "products": 1 + } + } + }, + { + "id": "p3", + "category": { + "id": "c1", + "details": { + "products": 2 + } + } + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@shareable\"]\n )\n\n type Query {\n products: [Product!]!\n }\n\n type Product @key(fields: \"id\") @key(fields: \"id pid\") {\n id: ID!\n pid: ID!\n category: Category @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n products: [Product!]!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"id\")\n @key(fields: \"id pid\")\n{\n id: ID!\n pid: ID!\n category: Category @shareable\n}\n\ntype Category\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id pid\") {\n id: ID!\n pid: ID!\n category: Category @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id pid\")\n{\n id: ID!\n pid: ID!\n category: Category @shareable\n}\n\ntype Category\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category | Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Category {\n details: CategoryDetails\n }\n\n type Product @key(fields: \"id pid\") {\n id: ID!\n pid: ID!\n category: Category @shareable\n }\n\n type CategoryDetails {\n products: Int\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Category {\n details: CategoryDetails\n}\n\ntype Product\n @key(fields: \"id pid\")\n{\n id: ID!\n pid: ID!\n category: Category @shareable\n}\n\ntype CategoryDetails {\n products: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "4357f0445b2210c07fee719f9059ef64870be1b4e4572ffb6d5a7887ae2b6580", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products, categories } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@shareable\"]\n )\n\n type Query {\n products: [Product!]!\n }\n\n type Product @key(fields: \"id\") @key(fields: \"id pid\") {\n id: ID!\n pid: ID!\n category: Category @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n `,\n resolvers: {\n Query: {\n products() {\n return products.map((p) => ({\n id: p.id,\n pid: p.pid,\n categoryId: p.categoryId,\n }));\n },\n },\n Product: {\n __resolveReference(\n key:\n | {\n id: string;\n }\n | {\n id: string;\n pid: string;\n },\n ) {\n const product = products.find(\n (p) => p.id === key.id && (\"pid\" in key ? p.pid === key.pid : true),\n );\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n pid: product.pid,\n categoryId: product.categoryId,\n };\n },\n category(product: { categoryId: string }) {\n const category = categories.find((c) => c.id === product.categoryId);\n\n if (!category) {\n return null;\n }\n\n return {\n id: category.id,\n name: category.name,\n };\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n const category = categories.find((c) => c.id === key.id);\n\n if (!category) {\n return null;\n }\n\n return {\n id: category.id,\n name: category.name,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "59d5bd3434cd33ad79529b433e4bf2bc5c5a4c95030de22c9d11f2d184a49c57", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id pid\") {\n id: ID!\n pid: ID!\n category: Category @shareable\n }\n\n type Category @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string; pid: string }) {\n const product = products.find(\n (p) => p.id === key.id && p.pid === key.pid,\n );\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n pid: product.pid,\n categoryId: product.categoryId,\n };\n },\n category(product: { categoryId: string }) {\n const category = categories.find((c) => c.id === product.categoryId);\n\n if (!category) {\n return null;\n }\n\n return {\n id: category.id,\n name: category.name,\n };\n },\n },\n Category: {\n __resolveReference(key: { id: string }) {\n const category = categories.find((c) => c.id === key.id);\n\n if (!category) {\n return null;\n }\n\n return {\n id: category.id,\n name: category.name,\n };\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "7542c1817c9086f6501599b69188840739ba79be69fb3af9f09b90dcf4feef7e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { categories, products } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Category {\n details: CategoryDetails\n }\n\n type Product @key(fields: \"id pid\") {\n id: ID!\n pid: ID!\n category: Category @shareable\n }\n\n type CategoryDetails {\n products: Int\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string; pid: string }) {\n const product = products.find(\n (p) => p.id === key.id && p.pid === key.pid,\n );\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n pid: product.pid,\n categoryId: product.categoryId,\n };\n },\n category(product: { categoryId: string }) {\n const category = categories.find((c) => c.id === product.categoryId);\n\n if (!category) {\n return null;\n }\n\n return {\n details: category.details,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "8fa6803380bc857d4b52b43ac347c5fab340235247592e949d6b486ba56a67a3", + "source": "export const products = [\n {\n id: \"p1\",\n pid: \"p1-pid\",\n categoryId: \"c1\",\n },\n {\n id: \"p2\",\n pid: \"p2-pid\",\n categoryId: \"c2\",\n },\n {\n id: \"p3\",\n pid: \"p3-pid\",\n categoryId: \"c1\",\n },\n];\n\nexport const categories = [\n {\n id: \"c1\",\n name: \"c1-name\",\n details: {\n products: products.filter((p) => p.categoryId === \"c1\").length,\n },\n },\n {\n id: \"c2\",\n name: \"c2-name\",\n details: {\n products: products.filter((p) => p.categoryId === \"c2\").length,\n },\n },\n];\n" + } + ] + }, + { + "id": "parent-entity-call-complex", + "cases": [ + { + "id": "parent-entity-call-complex/000", + "query": "\n query {\n productFromD(id: \"1\") {\n id\n name\n category {\n id\n name\n details\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "productFromD": { + "id": "1", + "name": "Product#1", + "category": { + "id": "3", + "name": "Category#3", + "details": "Details for Product#1" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID @external\n category: Category @shareable\n }\n type Category {\n details: String\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID @external\n category: Category @shareable\n}\n\ntype Category {\n details: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID @external\n category: Category @shareable\n }\n\n type Category {\n id: ID @shareable\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID @external\n category: Category @shareable\n}\n\ntype Category {\n id: ID @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n type Category @key(fields: \"id\") {\n id: ID\n name: String\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Category\n @key(fields: \"id\")\n{\n id: ID\n name: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Category\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "d", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n productFromD(id: ID!): Product\n }\n\n type Product @key(fields: \"id\") {\n id: ID\n name: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n productFromD(id: ID!): Product\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID\n name: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "1fc10286493572a01c82fab750d91c3f3347cfed8c26ac5f0cefb345f3e6f998", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID @external\n category: Category @shareable\n }\n type Category {\n details: String\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(product: { id: string }) {\n return {\n id: product.id,\n category: { details: `Details for Product#${product.id}` },\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "ab6ceb93887b6dbffd3a4391098ac830f9b0111dab4102f1708bb3fb2c954372", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@shareable\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID @external\n category: Category @shareable\n }\n\n type Category {\n id: ID @shareable\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(product: { id: string }) {\n return {\n id: product.id,\n category: {\n id: 3,\n },\n };\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "eb4bdbc23d0b0dc802a02b28aeb0f56318e255b15207bb5acd5d32c0ef0f36ab", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n type Category @key(fields: \"id\") {\n id: ID\n name: String\n }\n `,\n resolvers: {\n Category: {\n __resolveReference(category: { id: string }) {\n return {\n id: category.id,\n name: `Category#${category.id}`,\n };\n },\n },\n },\n});\n" + }, + { + "path": "d.subgraph.ts", + "sha256": "86a790e24e7dc416d295d2c5d3fe6bb0c599bc8397ba79f1142d793845dbb4d7", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\nexport default createSubgraph(\"d\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n productFromD(id: ID!): Product\n }\n\n type Product @key(fields: \"id\") {\n id: ID\n name: String\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(product: { id: string }) {\n return {\n id: product.id,\n name: `Product#${product.id}`,\n };\n },\n },\n Query: {\n productFromD(_: never, { id }: { id: string }) {\n return {\n id,\n name: `Product#${id}`,\n };\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "partial-union", + "cases": [ + { + "id": "partial-union/000", + "query": "\n query {\n getResponse {\n message\n actions {\n __typename\n ... on Alpha {\n id\n value\n }\n ... on Beta {\n id\n name\n details\n }\n ... on Gamma {\n id\n label\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "getResponse": { + "message": "Hello, Federation!", + "actions": [ + { + "__typename": "Alpha", + "id": "alpha-1", + "value": "alpha value" + }, + { + "__typename": "Beta", + "id": "beta-1", + "name": "beta name", + "details": "beta details" + }, + { + "__typename": "Gamma", + "id": "gamma-1", + "label": "gamma label" + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "partial-union/001", + "query": "\n query {\n getResponse {\n actions {\n __typename\n ... on Beta {\n name\n }\n ... on Gamma {\n label\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "getResponse": { + "actions": [ + { + "__typename": "Alpha" + }, + { + "__typename": "Beta", + "name": "beta name" + }, + { + "__typename": "Gamma", + "label": "gamma label" + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n getResponse: Response\n }\n\n type Response @shareable {\n actions: [Action!]!\n message: String\n }\n\n union Action = Alpha | Beta | Gamma\n\n type Alpha @shareable {\n id: ID!\n value: String\n }\n\n type Beta {\n id: ID!\n name: String\n details: String\n }\n\n type Gamma {\n id: ID!\n label: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype Query {\n getResponse: Response\n _service: _Service!\n}\n\ntype Response\n @shareable\n{\n actions: [Action!]!\n message: String\n}\n\nunion Action = Alpha | Beta | Gamma\n\ntype Alpha\n @shareable\n{\n id: ID!\n value: String\n}\n\ntype Beta {\n id: ID!\n name: String\n details: String\n}\n\ntype Gamma {\n id: ID!\n label: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Response @shareable {\n actions: [Action!]!\n message: String\n }\n\n union Action = Alpha\n\n type Alpha @shareable {\n id: ID!\n value: String\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype Response\n @shareable\n{\n actions: [Action!]!\n message: String\n}\n\nunion Action = Alpha\n\ntype Alpha\n @shareable\n{\n id: ID!\n value: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\ntype Query {\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "8aa2302e476e13edb402dc217aa50aafe10b455edf19b5dfa438cd2422f81528", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { actions, message } from \"./data.js\";\n\n// \"primary\" subgraph: declares the full union `Alpha | Beta | Gamma` and is the\n// only subgraph that defines `getResponse`. `Beta` and `Gamma` have no `@key`,\n// so they can only ever be resolved here.\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n getResponse: Response\n }\n\n type Response @shareable {\n actions: [Action!]!\n message: String\n }\n\n union Action = Alpha | Beta | Gamma\n\n type Alpha @shareable {\n id: ID!\n value: String\n }\n\n type Beta {\n id: ID!\n name: String\n details: String\n }\n\n type Gamma {\n id: ID!\n label: String\n }\n `,\n resolvers: {\n Query: {\n getResponse: () => ({ message, actions }),\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "55d851cd90ab9de2b8c0cc2688576e9feedee0bd1389040de451646287d66a97", + "source": "import { createSubgraph } from \"../../subgraph.js\";\n\n// \"secondary\" subgraph: contributes only a partial union (`Alpha` only) and the\n// shared `@shareable Response` type. It does NOT define `getResponse`, so the\n// planner must resolve the whole field from the primary subgraph. Its only role\n// is to make `Action` a partial union across the supergraph: a buggy planner\n// sees that `Response`/`Alpha` are shareable here and wrongly assumes `Beta`\n// and `Gamma` can be fetched via entity resolution, stripping their fragments.\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Response @shareable {\n actions: [Action!]!\n message: String\n }\n\n union Action = Alpha\n\n type Alpha @shareable {\n id: ID!\n value: String\n }\n `,\n resolvers: {},\n});\n" + }, + { + "path": "data.ts", + "sha256": "2d4fc0b3e805dbb9a7f55f2716796a9119c55286bd02346dc2901e72944ee265", + "source": "export const message = \"Hello, Federation!\";\n\nexport const alpha = {\n __typename: \"Alpha\",\n id: \"alpha-1\",\n value: \"alpha value\",\n};\n\nexport const beta = {\n __typename: \"Beta\",\n id: \"beta-1\",\n name: \"beta name\",\n details: \"beta details\",\n};\n\nexport const gamma = {\n __typename: \"Gamma\",\n id: \"gamma-1\",\n label: \"gamma label\",\n};\n\n// The primary subgraph can resolve all three union members.\nexport const actions = [alpha, beta, gamma];\n" + } + ] + }, + { + "id": "partial-union-complex", + "cases": [ + { + "id": "partial-union-complex/000", + "query": "\n query {\n rootA {\n wrapper {\n actions {\n __typename\n ... on Common {\n label\n }\n ... on OnlyA {\n a\n }\n ... on OnlyB {\n b\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "rootA": { + "wrapper": { + "actions": [ + { + "__typename": "Common", + "label": "common label" + }, + { + "__typename": "OnlyA", + "a": null + } + ] + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "partial-union-complex/001", + "query": "\n query {\n rootB {\n wrapper {\n actions {\n __typename\n ... on Common {\n label\n }\n ... on OnlyA {\n a\n }\n ... on OnlyB {\n b\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "rootB": { + "wrapper": { + "actions": [ + { + "__typename": "Common", + "label": "common label" + }, + { + "__typename": "OnlyB", + "b": null + } + ] + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "partial-union-complex/002", + "query": "\n query {\n rootA {\n wrapper {\n actions {\n __typename\n ... on OnlyB {\n b\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "rootA": { + "wrapper": { + "actions": [ + { + "__typename": "Common" + }, + { + "__typename": "OnlyA" + } + ] + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "partial-union-complex/003", + "query": "\n query {\n shared {\n wrapper {\n actions {\n __typename\n ... on Common {\n label\n }\n ... on OnlyA {\n a\n }\n ... on OnlyB {\n b\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "shared": { + "wrapper": { + "actions": [ + { + "__typename": "Common", + "label": "common label" + } + ] + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "partial-union-complex/004", + "query": "\n query {\n rootA {\n bWrapper {\n actions {\n __typename\n ... on Common {\n label\n }\n ... on OnlyA {\n a\n }\n ... on OnlyB {\n b\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "rootA": { + "bWrapper": { + "actions": [ + { + "__typename": "Common", + "label": "common label" + }, + { + "__typename": "OnlyB", + "b": "only b" + } + ] + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n rootA: Container\n shared: Container @shareable\n }\n\n type Container @key(fields: \"id\") {\n id: ID!\n wrapper: Wrapper @shareable\n }\n\n type Wrapper @shareable {\n actions: [Action!]! @shareable\n }\n\n union Action = Common | OnlyA\n\n type Common @shareable {\n label: String\n }\n\n type OnlyA {\n a: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n rootA: Container\n shared: Container @shareable\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Container\n @key(fields: \"id\")\n{\n id: ID!\n wrapper: Wrapper @shareable\n}\n\ntype Wrapper\n @shareable\n{\n actions: [Action!]! @shareable\n}\n\nunion Action = Common | OnlyA\n\ntype Common\n @shareable\n{\n label: String\n}\n\ntype OnlyA {\n a: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Container" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n rootB: Container\n shared: Container @shareable\n }\n\n type Container @key(fields: \"id\") {\n id: ID!\n wrapper: Wrapper @shareable\n bWrapper: Wrapper\n }\n\n type Wrapper @shareable {\n actions: [Action!]! @shareable\n }\n\n union Action = Common | OnlyB\n\n type Common @shareable {\n label: String\n }\n\n type OnlyB {\n b: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n rootB: Container\n shared: Container @shareable\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Container\n @key(fields: \"id\")\n{\n id: ID!\n wrapper: Wrapper @shareable\n bWrapper: Wrapper\n}\n\ntype Wrapper\n @shareable\n{\n actions: [Action!]! @shareable\n}\n\nunion Action = Common | OnlyB\n\ntype Common\n @shareable\n{\n label: String\n}\n\ntype OnlyB {\n b: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Container" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "67f0d9cd83b7147c12a3d78bd2b9b245922d6ea64e03dac45e8fe2aeceeb266e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { aActions, container, sharedActions } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n rootA: Container\n shared: Container @shareable\n }\n\n type Container @key(fields: \"id\") {\n id: ID!\n wrapper: Wrapper @shareable\n }\n\n type Wrapper @shareable {\n actions: [Action!]! @shareable\n }\n\n union Action = Common | OnlyA\n\n type Common @shareable {\n label: String\n }\n\n type OnlyA {\n a: String\n }\n `,\n resolvers: {\n Query: {\n rootA: () => ({ ...container, actions: aActions }),\n shared: () => ({ ...container, actions: sharedActions }),\n },\n Container: {\n __resolveReference(key: { id: string }) {\n if (key.id !== container.id) {\n return null;\n }\n\n return { ...container, actions: aActions };\n },\n wrapper(parent: { actions?: typeof aActions }) {\n return { actions: parent.actions ?? aActions };\n },\n },\n Action: {\n __resolveType(value: { __typename: string }) {\n return value.__typename;\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "e8c15ef431b611892bdd14ff0e21402fe496d76ece8d98f2af94e38696f97350", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { bActions, container, sharedActions } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n rootB: Container\n shared: Container @shareable\n }\n\n type Container @key(fields: \"id\") {\n id: ID!\n wrapper: Wrapper @shareable\n bWrapper: Wrapper\n }\n\n type Wrapper @shareable {\n actions: [Action!]! @shareable\n }\n\n union Action = Common | OnlyB\n\n type Common @shareable {\n label: String\n }\n\n type OnlyB {\n b: String\n }\n `,\n resolvers: {\n Query: {\n rootB: () => ({ ...container, actions: bActions }),\n shared: () => ({ ...container, actions: sharedActions }),\n },\n Container: {\n __resolveReference(key: { id: string }) {\n if (key.id !== container.id) {\n return null;\n }\n\n return { ...container, actions: bActions };\n },\n wrapper(parent: { actions?: typeof bActions }) {\n return { actions: parent.actions ?? bActions };\n },\n bWrapper() {\n return { actions: bActions };\n },\n },\n Action: {\n __resolveType(value: { __typename: string }) {\n return value.__typename;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "7b499fd23457447dc260a716e7e8c7c8350ff4e5849984e726fcfcd32e532eb8", + "source": "export const common = {\n __typename: \"Common\",\n label: \"common label\",\n};\n\nexport const onlyA = {\n __typename: \"OnlyA\",\n a: \"only a\",\n};\n\nexport const onlyB = {\n __typename: \"OnlyB\",\n b: \"only b\",\n};\n\nexport const container = {\n id: \"container-1\",\n};\n\nexport const aActions = [common, onlyA];\nexport const bActions = [common, onlyB];\nexport const sharedActions = [common];\n" + } + ] + }, + { + "id": "provides-on-interface", + "cases": [ + { + "id": "provides-on-interface/000", + "query": "\n query {\n media {\n id\n animals {\n id\n name\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": { + "id": "m1", + "animals": [ + { + "id": "a1", + "name": "Fido" + }, + { + "id": "a2", + "name": "Whiskers" + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "provides-on-interface/001", + "query": "\n query {\n media {\n id\n animals {\n id\n name\n ... on Cat {\n age\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": { + "id": "m1", + "animals": [ + { + "id": "a1", + "name": "Fido" + }, + { + "id": "a2", + "name": "Whiskers", + "age": 6 + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\", \"@provides\"]\n )\n\n type Query {\n media: Media @shareable\n book: Book @provides(fields: \"animals { ... on Dog { name } }\")\n }\n\n interface Media {\n id: ID!\n }\n\n interface Animal {\n id: ID!\n }\n\n type Book implements Media @key(fields: \"id\") {\n id: ID!\n animals: [Animal] @shareable\n }\n\n type Dog implements Animal @key(fields: \"id\") {\n id: ID! @external\n name: String @external\n }\n\n type Cat implements Animal @key(fields: \"id\") {\n id: ID! @external\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@external\", \"@provides\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n media: Media @shareable\n book: Book @provides(fields: \"animals { ... on Dog { name } }\")\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Media {\n id: ID!\n}\n\ninterface Animal {\n id: ID!\n}\n\ntype Book implements Media\n @key(fields: \"id\")\n{\n id: ID!\n animals: [Animal] @shareable\n}\n\ntype Dog implements Animal\n @key(fields: \"id\")\n{\n id: ID! @external\n name: String @external\n}\n\ntype Cat implements Animal\n @key(fields: \"id\")\n{\n id: ID! @external\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book | Cat | Dog" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@provides\", \"@external\"]\n )\n\n type Query {\n media: Media @shareable @provides(fields: \"animals { id name }\")\n }\n\n interface Media {\n id: ID!\n animals: [Animal]\n }\n\n interface Animal {\n id: ID!\n name: String\n }\n\n type Book implements Media {\n id: ID! @shareable\n animals: [Animal] @external\n }\n\n type Dog implements Animal {\n id: ID! @external\n name: String @external\n }\n\n type Cat implements Animal {\n id: ID! @external\n name: String @external\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@provides\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n media: Media @shareable @provides(fields: \"animals { id name }\")\n _service: _Service!\n}\n\ninterface Media {\n id: ID!\n animals: [Animal]\n}\n\ninterface Animal {\n id: ID!\n name: String\n}\n\ntype Book implements Media {\n id: ID! @shareable\n animals: [Animal] @external\n}\n\ntype Dog implements Animal {\n id: ID! @external\n name: String @external\n}\n\ntype Cat implements Animal {\n id: ID! @external\n name: String @external\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n interface Media {\n id: ID!\n animals: [Animal]\n }\n\n interface Animal {\n id: ID!\n name: String\n }\n\n type Book implements Media @key(fields: \"id\") {\n id: ID!\n animals: [Animal] @shareable\n }\n\n type Dog implements Animal @key(fields: \"id\") {\n id: ID!\n name: String @shareable\n age: Int\n }\n\n type Cat implements Animal @key(fields: \"id\") {\n id: ID!\n name: String @shareable\n age: Int\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninterface Media {\n id: ID!\n animals: [Animal]\n}\n\ninterface Animal {\n id: ID!\n name: String\n}\n\ntype Book implements Media\n @key(fields: \"id\")\n{\n id: ID!\n animals: [Animal] @shareable\n}\n\ntype Dog implements Animal\n @key(fields: \"id\")\n{\n id: ID!\n name: String @shareable\n age: Int\n}\n\ntype Cat implements Animal\n @key(fields: \"id\")\n{\n id: ID!\n name: String @shareable\n age: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book | Cat | Dog\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "8313969199182e1fa7148b4e44e09f98eeb10214e0ef8981e420b958a401cea3", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { animals, medias, pubishPoorPlans } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\", \"@provides\"]\n )\n\n type Query {\n media: Media @shareable\n book: Book @provides(fields: \"animals { ... on Dog { name } }\")\n }\n\n interface Media {\n id: ID!\n }\n\n interface Animal {\n id: ID!\n }\n\n type Book implements Media @key(fields: \"id\") {\n id: ID!\n animals: [Animal] @shareable\n }\n\n type Dog implements Animal @key(fields: \"id\") {\n id: ID! @external\n name: String @external\n }\n\n type Cat implements Animal @key(fields: \"id\") {\n id: ID! @external\n }\n `,\n resolvers: {\n Query: {\n media() {\n if (pubishPoorPlans) {\n throw new Error(\"You should be using the 'a' subgraph!\");\n }\n\n const media = medias[0];\n\n return {\n __typename: media.__typename,\n id: media.id,\n animals: media.animals.map((animalId) => {\n const animal = animals.find((a) => a.id === animalId);\n\n if (!animal) {\n return null;\n }\n\n return {\n __typename: animal.__typename,\n id: animal.id,\n };\n }),\n };\n },\n book() {\n const book = medias[0];\n\n return {\n __typename: \"Book\",\n id: book.id,\n animals: book.animals.map((animalId) => {\n const animal = animals.find((a) => a.id === animalId);\n\n if (!animal) {\n return null;\n }\n\n if (animal.__typename === \"Dog\") {\n return {\n __typename: \"Dog\",\n id: animal.id,\n name: animal.name,\n };\n }\n\n return {\n __typename: animal.__typename,\n id: animal.id,\n };\n }),\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "4d2da3e467803c4de15b0a49b40c7067da3006a500bcb8afea0df3575f19e423", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { animals, medias } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@provides\", \"@external\"]\n )\n\n type Query {\n media: Media @shareable @provides(fields: \"animals { id name }\")\n }\n\n interface Media {\n id: ID!\n animals: [Animal]\n }\n\n interface Animal {\n id: ID!\n name: String\n }\n\n type Book implements Media {\n id: ID! @shareable\n animals: [Animal] @external\n }\n\n type Dog implements Animal {\n id: ID! @external\n name: String @external\n }\n\n type Cat implements Animal {\n id: ID! @external\n name: String @external\n }\n `,\n resolvers: {\n Query: {\n media() {\n const media = medias[0];\n return {\n __typename: media.__typename,\n id: media.id,\n animals: media.animals.map((animalId) => {\n const animal = animals.find((a) => a.id === animalId);\n\n if (!animal) {\n return null;\n }\n\n return {\n __typename: animal.__typename,\n id: animal.id,\n name: animal.name,\n };\n }),\n };\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "c5861e2cbf5fb77c76c55a3d52ba6a757457578aca669302c91385f06f490cf0", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { animals, medias, pubishPoorPlans } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n interface Media {\n id: ID!\n animals: [Animal]\n }\n\n interface Animal {\n id: ID!\n name: String\n }\n\n type Book implements Media @key(fields: \"id\") {\n id: ID!\n animals: [Animal] @shareable\n }\n\n type Dog implements Animal @key(fields: \"id\") {\n id: ID!\n name: String @shareable\n age: Int\n }\n\n type Cat implements Animal @key(fields: \"id\") {\n id: ID!\n name: String @shareable\n age: Int\n }\n `,\n resolvers: {\n Query: {\n media() {\n if (pubishPoorPlans) {\n throw new Error(\"You should be using the 'a' subgraph!\");\n }\n\n return medias[0];\n },\n },\n Book: {\n __resolveReference(key: { id: string }) {\n const media = medias.find((media) => media.id === key.id);\n\n return media\n ? {\n __typename: \"Book\",\n id: media.id,\n animals: media.animals,\n }\n : null;\n },\n animals(book: { animals: string[] }) {\n return book.animals.map((animalId) => {\n const animal = animals.find((a) => a.id === animalId);\n\n return animal\n ? {\n __typename: animal.__typename,\n id: animal.id,\n name: animal.name,\n }\n : null;\n });\n },\n },\n Cat: {\n __resolveReference(key: { id: string }) {\n const animal = animals.find((animal) => animal.id === key.id);\n\n return animal\n ? {\n __typename: \"Cat\",\n id: animal.id,\n name: animal.name,\n age: animal.age,\n }\n : null;\n },\n age(cat: { id: string }) {\n const animal = animals.find((a) => a.id === cat.id);\n\n return animal ? animal.age : null;\n },\n },\n Dog: {\n __resolveReference(key: { id: string }) {\n if (pubishPoorPlans) {\n // Nothing in tests should be calling this resolver\n throw new Error(\"You should be using the 'c' subgraph!\");\n }\n\n const animal = animals.find((animal) => animal.id === key.id);\n\n return animal\n ? {\n __typename: \"Dog\",\n id: animal.id,\n name: animal.name,\n age: animal.age,\n }\n : null;\n },\n age(dog: { id: string }) {\n const animal = animals.find((a) => a.id === dog.id);\n\n return animal ? animal.age : null;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "56f2f0eb1e0858f524a59cecc6bfcd77bd6ad34ede30bf5553e47d3b1774e7a8", + "source": "export const pubishPoorPlans = true;\n\nexport const medias = [\n {\n __typename: \"Book\",\n id: \"m1\",\n animals: [\"a1\", \"a2\"],\n },\n];\n\nexport const animals = [\n {\n __typename: \"Dog\",\n id: \"a1\",\n name: \"Fido\",\n age: 3,\n },\n {\n __typename: \"Cat\",\n id: \"a2\",\n name: \"Whiskers\",\n age: 6,\n },\n];\n" + } + ] + }, + { + "id": "provides-on-union", + "cases": [ + { + "id": "provides-on-union/000", + "query": "\n query {\n media {\n ... on Book {\n id\n title\n }\n ... on Movie {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": [ + { + "id": "m1", + "title": "Book 1" + }, + { + "id": "m2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "provides-on-union/001", + "query": "\n query {\n media {\n ... on Book {\n id\n title\n }\n ... on Movie {\n id\n title\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": [ + { + "id": "m1", + "title": "Book 1" + }, + { + "id": "m2", + "title": "Movie 1" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\"]\n )\n\n type Query {\n media: [Media] @shareable\n }\n\n union Media = Book | Movie\n\n type Book @key(fields: \"id\") {\n id: ID!\n }\n\n type Movie @key(fields: \"id\") {\n id: ID!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n media: [Media] @shareable\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nunion Media = Book | Movie\n\ntype Book\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Movie\n @key(fields: \"id\")\n{\n id: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book | Movie" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@provides\", \"@external\"]\n )\n\n type Query {\n media: [Media] @shareable @provides(fields: \"... on Book { title }\")\n }\n\n union Media = Book | Movie\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String @external\n }\n\n type Movie @key(fields: \"id\") {\n id: ID!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\", \"@provides\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n media: [Media] @shareable @provides(fields: \"... on Book { title }\")\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nunion Media = Book | Movie\n\ntype Book\n @key(fields: \"id\")\n{\n id: ID!\n title: String @external\n}\n\ntype Movie\n @key(fields: \"id\")\n{\n id: ID!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book | Movie" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String @shareable\n }\n\n type Movie @key(fields: \"id\") {\n id: ID!\n title: String @shareable\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Book\n @key(fields: \"id\")\n{\n id: ID!\n title: String @shareable\n}\n\ntype Movie\n @key(fields: \"id\")\n{\n id: ID!\n title: String @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book | Movie\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "1a6b9b5d7fd7fffbd43bed75970bdea1a0d5c9f52afe3abb55d33339d491b7fd", + "source": "import { shouldPunishForPoorPlans } from \"../../env.js\";\nimport { createSubgraph } from \"../../subgraph.js\";\nimport { medias } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@external\"]\n )\n\n type Query {\n media: [Media] @shareable\n }\n\n union Media = Book | Movie\n\n type Book @key(fields: \"id\") {\n id: ID!\n }\n\n type Movie @key(fields: \"id\") {\n id: ID!\n }\n `,\n resolvers: {\n Query: {\n media(_p: unknown, _a: unknown, context: any) {\n if (shouldPunishForPoorPlans()) {\n throw new Error(\"You should not be using the 'a' subgraph!\");\n }\n\n return medias.map((media) => ({\n __typename: media.__typename,\n id: media.id,\n }));\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "21f466bfd1df9437e8e59908572f4e37803014d47931f53354ad704898af3ce6", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { medias } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\", \"@provides\", \"@external\"]\n )\n\n type Query {\n media: [Media] @shareable @provides(fields: \"... on Book { title }\")\n }\n\n union Media = Book | Movie\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String @external\n }\n\n type Movie @key(fields: \"id\") {\n id: ID!\n }\n `,\n resolvers: {\n Query: {\n media() {\n return medias.map((media) => {\n if (media.__typename === \"Book\") {\n return {\n __typename: media.__typename,\n id: media.id,\n title: media.title,\n };\n }\n\n return {\n __typename: media.__typename,\n id: media.id,\n };\n });\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "df009cd9e99a2011f2b218cf88581b2dbee7af9365589565eb9514b8e9eeb6a1", + "source": "import { shouldPunishForPoorPlans } from \"../../env.js\";\nimport { createSubgraph } from \"../../subgraph.js\";\nimport { medias } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String @shareable\n }\n\n type Movie @key(fields: \"id\") {\n id: ID!\n title: String @shareable\n }\n `,\n resolvers: {\n Book: {\n __resolveReference(key: { id: string }, context: any) {\n if (shouldPunishForPoorPlans()) {\n throw new Error(\"You should be using the 'b' subgraph!\");\n }\n\n const media = medias.find((media) => media.id === key.id);\n\n if (!media) {\n return null;\n }\n\n return {\n __typename: media.__typename,\n id: media.id,\n title: media.title,\n };\n },\n },\n Movie: {\n __resolveReference(key: { id: string }) {\n const media = medias.find((media) => media.id === key.id);\n\n if (!media) {\n return null;\n }\n\n return {\n __typename: media.__typename,\n id: media.id,\n title: media.title,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "984d622714ab05c160491275f011f9f5a41a3bf36eafe897b75aa4b82056cdd0", + "source": "export const medias = [\n {\n __typename: \"Book\",\n id: \"m1\",\n title: \"Book 1\",\n },\n {\n __typename: \"Movie\",\n id: \"m2\",\n title: \"Movie 1\",\n },\n];\n" + } + ] + }, + { + "id": "requires-circular", + "cases": [ + { + "id": "requires-circular/000", + "query": "\n {\n feed {\n byNovice\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "byNovice": true + }, + { + "byNovice": false + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-circular/001", + "query": "\n {\n feed {\n byExpert\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "byExpert": false + }, + { + "byExpert": true + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Query {\n feed: [Post]\n }\n\n type Post @key(fields: \"id\") {\n id: ID!\n byNovice: Boolean! @external\n byExpert: Boolean! @requires(fields: \"byNovice\")\n }\n\n type Author @key(fields: \"id\") {\n id: ID!\n name: String!\n yearsOfExperience: Int!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n feed: [Post]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n byNovice: Boolean! @external\n byExpert: Boolean! @requires(fields: \"byNovice\")\n}\n\ntype Author\n @key(fields: \"id\")\n{\n id: ID!\n name: String!\n yearsOfExperience: Int!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Author | Post" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n author: Author!\n byNovice: Boolean! @requires(fields: \"author { yearsOfExperience }\")\n }\n\n type Author @key(fields: \"id\") {\n id: ID!\n yearsOfExperience: Int! @external\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n author: Author!\n byNovice: Boolean! @requires(fields: \"author { yearsOfExperience }\")\n}\n\ntype Author\n @key(fields: \"id\")\n{\n id: ID!\n yearsOfExperience: Int! @external\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Author | Post\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "5d2305ded6f140ab0cd6913e2b4ef9e1102c01e768cea8baa497807571f7e984", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { authors, posts } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Query {\n feed: [Post]\n }\n\n type Post @key(fields: \"id\") {\n id: ID!\n byNovice: Boolean! @external\n byExpert: Boolean! @requires(fields: \"byNovice\")\n }\n\n type Author @key(fields: \"id\") {\n id: ID!\n name: String!\n yearsOfExperience: Int!\n }\n `,\n resolvers: {\n Query: {\n feed() {\n return posts.map((post) => ({ id: post.id }));\n },\n },\n Post: {\n __resolveReference(ref: { id: string; byNovice?: boolean }) {\n const post = posts.find((post) => post.id === ref.id);\n if (!post) {\n return null;\n }\n if (ref.byNovice == null) {\n return {\n id: post.id,\n };\n }\n return {\n id: post.id,\n byNovice: ref.byNovice,\n };\n },\n byExpert(post: { byNovice: boolean }) {\n if (post.byNovice == null) {\n // ensuring requires is not skipped\n return null;\n }\n return !post.byNovice;\n },\n },\n Author: {\n __resolveReference(ref: { id: string }) {\n const author = authors.find((author) => author.id === ref.id);\n if (!author) {\n return null;\n }\n return {\n id: author.id,\n name: author.name,\n yearsOfExperience: author.yearsOfExperience,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "8ea2d5356ddb1811ade3cd01de01d526c5afc15effe8f07c7ece25677b4a0dc0", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { posts } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n author: Author!\n byNovice: Boolean! @requires(fields: \"author { yearsOfExperience }\")\n }\n\n type Author @key(fields: \"id\") {\n id: ID!\n yearsOfExperience: Int! @external\n }\n `,\n resolvers: {\n Post: {\n __resolveReference(ref: {\n id: string;\n author?: { yearsOfExperience: number };\n }) {\n const post = posts.find((post) => post.id === ref.id);\n if (!post) {\n return null;\n }\n return {\n id: post.id,\n author: {\n id: post.author.id,\n ...ref.author,\n },\n };\n },\n byNovice(post: { author: { yearsOfExperience: number } }) {\n return post.author.yearsOfExperience < 10;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "6dc14e350e85a77b47e5fbab1b1664a9c26887ad9fe6a7f0c5e787fb27164642", + "source": "export const authors = [\n {\n id: \"a1\",\n name: \"John\",\n yearsOfExperience: 5,\n },\n {\n id: \"a2\",\n name: \"Jane\",\n yearsOfExperience: 20,\n },\n];\n\nexport const posts = [\n {\n id: \"p1\",\n body: \"p1-body\",\n author: authors[0],\n },\n {\n id: \"p2\",\n body: \"p2-body\",\n author: authors[1],\n },\n];\n" + } + ] + }, + { + "id": "requires-interface", + "cases": [ + { + "id": "requires-interface/000", + "query": "\n query {\n a {\n city\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "a": { + "city": "a1-city" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-interface/001", + "query": "\n query {\n b {\n city\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "b": { + "city": "a2-city" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-interface/002", + "query": "\n query {\n a {\n country\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "a": { + "country": null + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-interface/003", + "query": "\n query {\n a {\n address {\n __typename\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "a": { + "address": { + "__typename": "HomeAddress", + "id": "a1" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-interface/004", + "query": "\n query {\n b {\n address {\n __typename\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "b": { + "address": { + "__typename": "WorkAddress", + "id": "a2" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@requires\", \"@external\", \"@shareable\"]\n )\n\n type Query {\n a: User\n }\n\n interface Address {\n id: ID!\n }\n\n type HomeAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type WorkAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n address: Address @external\n city: String @requires(fields: \"address { id }\")\n country: String @requires(fields: \"address { ... on WorkAddress { id } }\")\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@requires\", \"@external\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n a: User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Address {\n id: ID!\n}\n\ntype HomeAddress implements Address\n @key(fields: \"id\")\n{\n id: ID!\n city: String @shareable\n}\n\ntype WorkAddress implements Address\n @key(fields: \"id\")\n{\n id: ID!\n city: String @shareable\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n address: Address @external\n city: String @requires(fields: \"address { id }\")\n country: String @requires(fields: \"address { ... on WorkAddress { id } }\")\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = HomeAddress | User | WorkAddress" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n b: User\n }\n\n interface Address {\n id: ID!\n }\n\n type HomeAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type WorkAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type SecondAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n address: Address @shareable\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n b: User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface Address {\n id: ID!\n}\n\ntype HomeAddress implements Address\n @key(fields: \"id\")\n{\n id: ID!\n city: String @shareable\n}\n\ntype WorkAddress implements Address\n @key(fields: \"id\")\n{\n id: ID!\n city: String @shareable\n}\n\ntype SecondAddress implements Address\n @key(fields: \"id\")\n{\n id: ID!\n city: String @shareable\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String! @shareable\n address: Address @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = HomeAddress | SecondAddress | User | WorkAddress" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "1ed84ff6365f87d817e93ca0cca6e87531534e98d3c781f2a582b03e72f2a382", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { addresses, users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@requires\", \"@external\", \"@shareable\"]\n )\n\n type Query {\n a: User\n }\n\n interface Address {\n id: ID!\n }\n\n type HomeAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type WorkAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n address: Address @external\n city: String @requires(fields: \"address { id }\")\n country: String @requires(fields: \"address { ... on WorkAddress { id } }\")\n }\n `,\n resolvers: {\n Query: {\n a() {\n const user = users[0];\n\n return {\n id: user.id,\n name: user.name,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string; address?: { id?: string } }) {\n const user = users.find((user) => user.id === key.id);\n\n if (!user) {\n return null;\n }\n\n if (key.address?.id) {\n return {\n id: user.id,\n name: user.name,\n address: {\n id: user.address,\n },\n };\n }\n\n return {\n id: user.id,\n name: user.name,\n };\n },\n city(user: { address: { id: string } }) {\n return addresses.find((address) => address.id === user.address.id)\n ?.city;\n },\n country(user: { address?: { id?: string } }) {\n return addresses.find((address) => address.id === user?.address?.id)\n ?.country;\n },\n },\n HomeAddress: {\n __resolveReference(key: { id: string }) {\n return addresses.find((address) => address.id === key.id);\n },\n },\n WorkAddress: {\n __resolveReference(key: { id: string }) {\n return addresses.find((address) => address.id === key.id);\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "2e51236cfb6f014a66c22694778c6a923579f53d8f56bcea74cf32f66491a190", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { addresses, users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n b: User\n }\n\n interface Address {\n id: ID!\n }\n\n type HomeAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type WorkAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type SecondAddress implements Address @key(fields: \"id\") {\n id: ID!\n city: String @shareable\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String! @shareable\n address: Address @shareable\n }\n `,\n resolvers: {\n Query: {\n b() {\n const user = users[1];\n\n return {\n id: user.id,\n name: user.name,\n address: user.address,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((user) => user.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n address: user.address,\n };\n },\n address(user: { id: string; address: string }) {\n return addresses.find((address) => address.id === user.address);\n },\n },\n HomeAddress: {\n __resolveReference(key: { id: string }) {\n return addresses.find((address) => address.id === key.id);\n },\n },\n WorkAddress: {\n __resolveReference(key: { id: string }) {\n return addresses.find((address) => address.id === key.id);\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "f049a629bf36d483858a2484dc4fbe1e4eade084cefca1d9c8560e22038c91e1", + "source": "export const users = [\n {\n id: \"u1\",\n name: \"u1-name\",\n address: \"a1\",\n },\n {\n id: \"u2\",\n name: \"u2-name\",\n address: \"a2\",\n },\n];\n\nexport const addresses = [\n {\n __typename: \"HomeAddress\",\n id: \"a1\",\n city: \"a1-city\",\n country: \"a1-country\",\n },\n {\n __typename: \"WorkAddress\",\n id: \"a2\",\n city: \"a2-city\",\n country: \"a2-country\",\n },\n];\n" + } + ] + }, + { + "id": "requires-requires", + "cases": [ + { + "id": "requires-requires/000", + "query": "\n query {\n product {\n canAfford\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "canAfford": false + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-requires/001", + "query": "\n query {\n product {\n isExpensive\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "isExpensive": true + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-requires/002", + "query": "\n query {\n product {\n isExpensive\n canAfford\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "isExpensive": true, + "canAfford": false + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-requires/003", + "query": "\n query {\n product {\n canAffordWithDiscount\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "canAffordWithDiscount": true + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-requires/004", + "query": "\n query {\n product {\n canAfford\n canAffordWithDiscount\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "canAfford": false, + "canAffordWithDiscount": true + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @inaccessible\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@inaccessible\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n price: Float! @inaccessible\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n product: Product\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n hasDiscount: Boolean!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n product: Product\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n hasDiscount: Boolean!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n hasDiscount: Boolean! @external\n isExpensiveWithDiscount: Boolean! @requires(fields: \"hasDiscount\")\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n hasDiscount: Boolean! @external\n isExpensiveWithDiscount: Boolean! @requires(fields: \"hasDiscount\")\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "d", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n isExpensive: Boolean! @external\n canAfford: Boolean! @requires(fields: \"isExpensive\")\n isExpensiveWithDiscount: Boolean! @external\n canAffordWithDiscount: Boolean!\n @requires(fields: \"isExpensiveWithDiscount\")\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"id\")\n{\n id: ID!\n isExpensive: Boolean! @external\n canAfford: Boolean! @requires(fields: \"isExpensive\")\n isExpensiveWithDiscount: Boolean! @external\n canAffordWithDiscount: Boolean! @requires(fields: \"isExpensiveWithDiscount\")\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "ccb36125e4936e126bce681758ad02a0617d217a030caad4d2eb1b4162a9aa43", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @inaccessible\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: { id: string }) {\n const product = products.find((product) => product.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n price: product.price,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "14378328290695d6d920d0efe7f477b25d866cbc9bc498b39409f3386687f5a9", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n product: Product\n }\n\n type Product @key(fields: \"id\") {\n id: ID!\n hasDiscount: Boolean!\n }\n `,\n resolvers: {\n Query: {\n product() {\n return {\n id: products[0].id,\n hasDiscount: products[0].hasDiscount,\n };\n },\n },\n Product: {\n __resolveReference(key: { id: string }) {\n const product = products.find((product) => product.id === key.id);\n\n if (!product) {\n return null;\n }\n\n return {\n id: product.id,\n hasDiscount: product.hasDiscount,\n };\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "20c086a62291d26f7aff18411ce699c560ff7dfcc49faa845da244e1a4e6e76a", + "source": "import { GraphQLError } from \"graphql\";\nimport { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n price: Float! @external\n isExpensive: Boolean! @requires(fields: \"price\")\n hasDiscount: Boolean! @external\n isExpensiveWithDiscount: Boolean! @requires(fields: \"hasDiscount\")\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: {\n id: string;\n price?: number;\n hasDiscount?: boolean;\n }) {\n if (!products.find((product) => product.id === key.id)) {\n return null;\n }\n\n const product: {\n __typename: \"Product\";\n id: string;\n price?: number;\n isExpensive?: boolean;\n hasDiscount?: boolean;\n isExpensiveWithDiscount?: boolean;\n } = {\n __typename: \"Product\",\n id: key.id,\n };\n\n if (typeof key.price === \"number\") {\n product.price = key.price;\n product.isExpensive = key.price > 500;\n } else if (\"price\" in key && typeof key.price !== \"undefined\") {\n return new GraphQLError(\"Product.price must be a number\");\n }\n\n if (typeof key.hasDiscount === \"boolean\") {\n product.hasDiscount = key.hasDiscount;\n product.isExpensiveWithDiscount = !key.hasDiscount;\n } else if (\n \"hasDiscount\" in key &&\n typeof key.hasDiscount !== \"undefined\"\n ) {\n return new GraphQLError(\"Product.hasDiscount must be a number\");\n }\n\n return product;\n },\n },\n },\n});\n" + }, + { + "path": "d.subgraph.ts", + "sha256": "779ce633ce5422adaff872b17517b12f574746ed2e4146b47b02f28524b24cd0", + "source": "import { GraphQLError } from \"graphql\";\nimport { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"d\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"id\") {\n id: ID!\n isExpensive: Boolean! @external\n canAfford: Boolean! @requires(fields: \"isExpensive\")\n isExpensiveWithDiscount: Boolean! @external\n canAffordWithDiscount: Boolean!\n @requires(fields: \"isExpensiveWithDiscount\")\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(key: {\n id: string;\n isExpensive?: boolean;\n isExpensiveWithDiscount?: boolean;\n }) {\n if (!products.find((product) => product.id === key.id)) {\n return null;\n }\n\n const product: {\n __typename: \"Product\";\n id: string;\n isExpensive?: boolean;\n canAfford?: boolean;\n isExpensiveWithDiscount?: boolean;\n canAffordWithDiscount?: boolean;\n } = {\n __typename: \"Product\",\n id: key.id,\n };\n\n if (typeof key.isExpensive === \"boolean\") {\n product.isExpensive = key.isExpensive;\n product.canAfford = !key.isExpensive;\n } else if (\n \"isExpensive\" in key &&\n typeof key.isExpensive !== \"undefined\"\n ) {\n return new GraphQLError(\"Product.isExpensive must be a boolean\");\n }\n\n if (typeof key.isExpensiveWithDiscount === \"boolean\") {\n product.isExpensiveWithDiscount = key.isExpensiveWithDiscount;\n product.canAffordWithDiscount = !key.isExpensiveWithDiscount;\n } else if (\n \"isExpensiveWithDiscount\" in key &&\n typeof key.isExpensiveWithDiscount !== \"undefined\"\n ) {\n return new GraphQLError(\n \"Product.isExpensiveWithDiscount must be a boolean\",\n );\n }\n\n return product;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "fad1708b13eddd9ee1de40420c76ffb3813009b0869bd62bca516067d8119e31", + "source": "export const products = [\n {\n id: \"p1\",\n price: 699.99,\n hasDiscount: true,\n },\n];\n" + } + ] + }, + { + "id": "requires-with-argument", + "cases": [ + { + "id": "requires-with-argument/000", + "query": "\n query {\n products {\n upc\n name\n shippingEstimate\n isExpensiveCategory\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "upc": "p1", + "name": "p-name-1", + "shippingEstimate": 110, + "isExpensiveCategory": false + }, + { + "upc": "p2", + "name": "p-name-2", + "shippingEstimate": 440, + "isExpensiveCategory": true + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-argument/001", + "query": "\n {\n feed {\n author {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "author": { + "id": "a2" + } + }, + { + "author": { + "id": "a1" + } + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-argument/002", + "query": "\n query {\n feed {\n author {\n id\n }\n comments(limit: 1) {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "author": { + "id": "a2" + }, + "comments": [ + { + "id": "c1" + } + ] + }, + { + "author": { + "id": "a1" + }, + "comments": [ + { + "id": "c4" + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-argument/003", + "query": "\n query ($limit: Int = 1) {\n feed {\n author {\n id\n }\n comments(limit: $limit) {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "author": { + "id": "a2" + }, + "comments": [ + { + "id": "c1" + } + ] + }, + { + "author": { + "id": "a1" + }, + "comments": [ + { + "id": "c4" + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-argument/004", + "query": "\n query ($limit: Int = 1) {\n feed {\n author {\n id\n }\n ...Foo\n ...Bar\n }\n }\n\n fragment Foo on Post {\n comments(limit: $limit) {\n id\n }\n }\n\n fragment Bar on Post {\n comments(limit: $limit) {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "author": { + "id": "a2" + }, + "comments": [ + { + "id": "c1" + } + ] + }, + { + "author": { + "id": "a1" + }, + "comments": [ + { + "id": "c4" + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"upc\") {\n upc: String!\n weight: Int @external\n price(currency: String!): Int @external\n shippingEstimate: Int\n @requires(\n fields: \"\"\"\n price(currency: \"USD\") weight\n \"\"\"\n )\n category: Category @external\n isExpensiveCategory: Boolean\n @requires(\n fields: \"\"\"\n category { averagePrice(currency: \"USD\") }\n \"\"\"\n )\n }\n\n type Category @external {\n averagePrice(currency: String!): Int\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"upc\")\n{\n upc: String!\n weight: Int @external\n price(currency: String!): Int @external\n shippingEstimate: Int @requires(fields: \"price(currency: \\\"USD\\\") weight\")\n category: Category @external\n isExpensiveCategory: Boolean @requires(fields: \"category { averagePrice(currency: \\\"USD\\\") }\")\n}\n\ntype Category\n @external\n{\n averagePrice(currency: String!): Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n products: [Product]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n name: String\n price(currency: String!): Int\n weight: Int\n category: Category\n }\n\n type Category {\n averagePrice(currency: String!): Int\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n products: [Product]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"upc\")\n{\n upc: String!\n name: String\n price(currency: String!): Int\n weight: Int\n category: Category\n}\n\ntype Category {\n averagePrice(currency: String!): Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Query {\n feed: [Post]\n }\n\n type Post @key(fields: \"id\") {\n id: ID!\n }\n\n type Comment @key(fields: \"id\") {\n id: ID!\n authorId: ID\n body: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n feed: [Post]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Comment\n @key(fields: \"id\")\n{\n id: ID!\n authorId: ID\n body: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Comment | Post" + }, + { + "name": "d", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n author: Author @requires(fields: \"comments(limit: 3) { authorId }\")\n comments(limit: Int!): [Comment]\n }\n\n type Comment @key(fields: \"id\") {\n id: ID!\n date: String\n authorId: ID @external\n }\n\n type Author {\n id: ID!\n name: String\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n author: Author @requires(fields: \"comments(limit: 3) { authorId }\")\n comments(limit: Int!): [Comment]\n}\n\ntype Comment\n @key(fields: \"id\")\n{\n id: ID!\n date: String\n authorId: ID @external\n}\n\ntype Author {\n id: ID!\n name: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Comment | Post\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "b21bb2621016a7031d417511337be7684cbd981e1f0c295690bd3dd073e87b6b", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"upc\") {\n upc: String!\n weight: Int @external\n price(currency: String!): Int @external\n shippingEstimate: Int\n @requires(\n fields: \"\"\"\n price(currency: \"USD\") weight\n \"\"\"\n )\n category: Category @external\n isExpensiveCategory: Boolean\n @requires(\n fields: \"\"\"\n category { averagePrice(currency: \"USD\") }\n \"\"\"\n )\n }\n\n type Category @external {\n averagePrice(currency: String!): Int\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(\n key: { upc: string; price: number; weight: number } | { upc: string },\n ) {\n const product = products.find((p) => p.upc === key.upc);\n\n if (!product) {\n return null;\n }\n\n if (\"weight\" in key && \"price\" in key) {\n return {\n upc: product.upc,\n weight: key.weight,\n price: key.price,\n category: product.category,\n };\n }\n\n return {\n upc: product.upc,\n category: product.category,\n };\n },\n shippingEstimate(product: { price: number; weight: number }) {\n return product.price * product.weight * 10;\n },\n isExpensiveCategory(product: { category: { averagePrice: number } }) {\n return product.category.averagePrice > 11;\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "530b6b9e029ff279700a4cfb1b24d65733475f4061c335196bdd9c40d1bdb84e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n products: [Product]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n name: String\n price(currency: String!): Int\n weight: Int\n category: Category\n }\n\n type Category {\n averagePrice(currency: String!): Int\n }\n `,\n resolvers: {\n Query: {\n products() {\n return products.map((p) => ({\n upc: p.upc,\n name: p.name,\n price: p.price,\n weight: p.weight,\n category: p.category,\n }));\n },\n },\n Product: {\n __resolveReference(key: { upc: string }) {\n const product = products.find((p) => p.upc === key.upc);\n\n if (!product) {\n return null;\n }\n\n return {\n upc: product.upc,\n name: product.name,\n price: product.price,\n weight: product.weight,\n category: product.category,\n };\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "82b233ebc27ac5372dc27051e1d94c9f9a7f1fbf17f87a44375a7e3725f846d0", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { comments, posts } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Query {\n feed: [Post]\n }\n\n type Post @key(fields: \"id\") {\n id: ID!\n }\n\n type Comment @key(fields: \"id\") {\n id: ID!\n authorId: ID\n body: String!\n }\n `,\n resolvers: {\n Query: {\n feed() {\n return posts.map((post) => ({ id: post.id }));\n },\n },\n Post: {\n __resolveReference(key: { id: string }) {\n const post = posts.find((post) => post.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n };\n },\n comments(post: { id: string }, { limit }: { limit: number }) {\n return comments\n .filter((comment) => comment.postId === post.id)\n .slice(0, limit)\n .map((c) => ({\n id: c.id,\n authorId: c.authorId,\n body: c.body,\n }));\n },\n },\n Comment: {\n __resolveReference(key: { id: string }) {\n const comment = comments.find((c) => c.id === key.id);\n\n if (!comment) {\n return null;\n }\n\n return {\n id: comment.id,\n authorId: comment.authorId,\n body: comment.body,\n };\n },\n },\n },\n});\n" + }, + { + "path": "d.subgraph.ts", + "sha256": "aeaf1986ab924a037e4703c75ea3ddc6a082157f5bdf5be549c430ffa086380f", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { authors, comments, posts } from \"./data.js\";\n\nexport default createSubgraph(\"d\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n author: Author @requires(fields: \"comments(limit: 3) { authorId }\")\n comments(limit: Int!): [Comment]\n }\n\n type Comment @key(fields: \"id\") {\n id: ID!\n date: String\n authorId: ID @external\n }\n\n type Author {\n id: ID!\n name: String\n }\n `,\n resolvers: {\n Post: {\n __resolveReference(key: {\n id: string;\n comments?: Array<{ authorId: string }>;\n }) {\n const post = posts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n if (key.comments) {\n if (key.comments.length !== 3) {\n throw new Error(\"Expected 3 comments\");\n }\n\n return {\n id: post.id,\n authorId: key.comments?.[2].authorId,\n };\n }\n\n return {\n id: post.id,\n };\n },\n author(post: { authorId?: string }) {\n if (!post.authorId) {\n return null;\n }\n\n const author = authors.find((a) => a.id === post.authorId);\n\n if (!author) {\n return null;\n }\n\n return {\n id: author.id,\n name: author.name,\n };\n },\n comments(post: { id: string }, { limit }: { limit: number }) {\n const coms = comments\n .filter((comment) => comment.postId === post.id)\n .slice(0, limit)\n .map((c) => ({\n id: c.id,\n }));\n\n return coms;\n },\n },\n Comment: {\n __resolveReference(key: { id: string }) {\n const comment = comments.find((c) => c.id === key.id);\n\n if (!comment) {\n return null;\n }\n\n return {\n id: comment.id,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "e61676fe28d111c468ecff2664577e3e7955e437a9419ee384e574a290a17884", + "source": "export const products = [\n {\n upc: \"p1\",\n name: \"p-name-1\",\n price: 11,\n weight: 1,\n category: {\n averagePrice: 11,\n },\n },\n {\n upc: \"p2\",\n name: \"p-name-2\",\n price: 22,\n weight: 2,\n category: {\n averagePrice: 22,\n },\n },\n];\n\nexport const posts = [\n {\n id: \"p1\",\n body: \"p1-body\",\n },\n {\n id: \"p2\",\n body: \"p2-body\",\n },\n];\n\nexport const comments = [\n {\n id: \"c1\",\n postId: \"p1\",\n authorId: \"a2\",\n body: \"c1-body\",\n },\n {\n id: \"c2\",\n postId: \"p1\",\n authorId: \"a2\",\n body: \"c2-body\",\n },\n {\n id: \"c3\",\n postId: \"p1\",\n authorId: \"a2\",\n body: \"c3-body\",\n },\n {\n id: \"c4\",\n postId: \"p2\",\n authorId: \"a1\",\n body: \"c4-body\",\n },\n {\n id: \"c5\",\n postId: \"p2\",\n authorId: \"a1\",\n body: \"c5-body\",\n },\n {\n id: \"c6\",\n postId: \"p2\",\n authorId: \"a1\",\n body: \"c6-body\",\n },\n];\n\nexport const authors = [\n {\n id: \"a1\",\n name: \"a1-name\",\n },\n {\n id: \"a2\",\n name: \"a2-name\",\n },\n];\n" + } + ] + }, + { + "id": "requires-with-argument-conflict", + "cases": [ + { + "id": "requires-with-argument-conflict/000", + "query": "\n query {\n products {\n upc\n name\n shippingEstimate\n shippingEstimateEUR\n isExpensiveCategory\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "upc": "p1", + "name": "p-name-1", + "shippingEstimate": 110, + "shippingEstimateEUR": 220, + "isExpensiveCategory": false + }, + { + "upc": "p2", + "name": "p-name-2", + "shippingEstimate": 440, + "shippingEstimateEUR": 880, + "isExpensiveCategory": true + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"upc\") {\n upc: String!\n weight: Int @external\n price(currency: String!): Int @external\n shippingEstimate: Int\n @requires(\n fields: \"\"\"\n price(currency: \"USD\") weight\n \"\"\"\n )\n shippingEstimateEUR: Int\n @requires(\n fields: \"\"\"\n price(currency: \"EUR\") weight\n \"\"\"\n )\n category: Category @external\n isExpensiveCategory: Boolean\n @requires(\n fields: \"\"\"\n category { averagePrice(currency: \"USD\") }\n \"\"\"\n )\n }\n\n type Category @external {\n averagePrice(currency: String!): Int\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"upc\")\n{\n upc: String!\n weight: Int @external\n price(currency: String!): Int @external\n shippingEstimate: Int @requires(fields: \"price(currency: \\\"USD\\\") weight\")\n shippingEstimateEUR: Int @requires(fields: \"price(currency: \\\"EUR\\\") weight\")\n category: Category @external\n isExpensiveCategory: Boolean @requires(fields: \"category { averagePrice(currency: \\\"USD\\\") }\")\n}\n\ntype Category\n @external\n{\n averagePrice(currency: String!): Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n products: [Product]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n name: String\n price(currency: String!): Int\n weight: Int\n category: Category\n }\n\n type Category {\n averagePrice(currency: String!): Int\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n products: [Product]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"upc\")\n{\n upc: String!\n name: String\n price(currency: String!): Int\n weight: Int\n category: Category\n}\n\ntype Category {\n averagePrice(currency: String!): Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "c0f21ba286ac9c8cfce77969888a0016facce47e8aef1bface231e692babd359", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"upc\") {\n upc: String!\n weight: Int @external\n price(currency: String!): Int @external\n shippingEstimate: Int\n @requires(\n fields: \"\"\"\n price(currency: \"USD\") weight\n \"\"\"\n )\n shippingEstimateEUR: Int\n @requires(\n fields: \"\"\"\n price(currency: \"EUR\") weight\n \"\"\"\n )\n category: Category @external\n isExpensiveCategory: Boolean\n @requires(\n fields: \"\"\"\n category { averagePrice(currency: \"USD\") }\n \"\"\"\n )\n }\n\n type Category @external {\n averagePrice(currency: String!): Int\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(\n key: { upc: string; price: number; weight: number } | { upc: string },\n ) {\n const product = products.find((p) => p.upc === key.upc);\n\n if (!product) {\n return null;\n }\n\n if (\"weight\" in key && \"price\" in key) {\n return {\n upc: product.upc,\n weight: key.weight,\n price: key.price,\n category: product.category,\n };\n }\n\n return {\n upc: product.upc,\n category: product.category,\n };\n },\n shippingEstimate(product: { price: number; weight: number }) {\n const value = product.price * product.weight * 10;\n return value;\n },\n shippingEstimateEUR(product: { price: number; weight: number }) {\n const value = product.price * product.weight * 10;\n return value;\n },\n isExpensiveCategory(product: { category: { averagePrice: number } }) {\n return product.category.averagePrice > 11;\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "7f0ea9450502beb3195c72aa441e908769ac6555cdd138da7e5715f5610df220", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n products: [Product]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n name: String\n price(currency: String!): Int\n weight: Int\n category: Category\n }\n\n type Category {\n averagePrice(currency: String!): Int\n }\n `,\n resolvers: {\n Query: {\n products() {\n return products.map((p) => ({\n upc: p.upc,\n name: p.name,\n price: p.price,\n weight: p.weight,\n category: p.category,\n }));\n },\n },\n Product: {\n __resolveReference(key: { upc: string }) {\n const product = products.find((p) => p.upc === key.upc);\n\n if (!product) {\n return null;\n }\n\n return {\n upc: product.upc,\n name: product.name,\n price: product.price,\n weight: product.weight,\n category: product.category,\n };\n },\n price(parent: { price: number }, args: { currency: string }) {\n if (args.currency === \"EUR\") return parent.price * 2;\n if (args.currency === \"USD\") return parent.price;\n throw new Error(\"Unsupported currency \" + args.currency);\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "f009bdf06569182594816ccb2caf4db70a45db08b445d90425d240ad45ffdeba", + "source": "export const products = [\n {\n upc: \"p1\",\n name: \"p-name-1\",\n price: 11,\n weight: 1,\n category: {\n averagePrice: 11,\n },\n },\n {\n upc: \"p2\",\n name: \"p-name-2\",\n price: 22,\n weight: 2,\n category: {\n averagePrice: 22,\n },\n },\n];\n" + } + ] + }, + { + "id": "requires-with-fragments", + "cases": [ + { + "id": "requires-with-fragments/000", + "query": "\n query {\n b {\n id\n data {\n __typename\n }\n }\n bb {\n id\n data {\n __typename\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "b": { + "id": "e1", + "data": null + }, + "bb": { + "id": "e2", + "data": { + "__typename": "Qux" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-fragments/001", + "query": "\n query {\n a {\n requirer\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "a": { + "requirer": "q1-foo_requirer" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-fragments/002", + "query": "\n query {\n a {\n data {\n __typename\n }\n requirer\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "a": { + "data": { + "__typename": "Qux" + }, + "requirer": "q1-foo_requirer" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-fragments/003", + "query": "\n query {\n bb {\n data {\n __typename\n }\n requirer\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "bb": { + "data": { + "__typename": "Qux" + }, + "requirer": "q1-foo_requirer" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-fragments/004", + "query": "\n query {\n b {\n data {\n __typename\n }\n requirer\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "b": { + "data": null, + "requirer": "b1-foo_requirer" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "requires-with-fragments/005", + "query": "\n query {\n bb {\n data {\n __typename\n }\n requirer2\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "bb": { + "data": { + "__typename": "Qux" + }, + "requirer2": "q1-foo_requirer2" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.5\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query @shareable {\n a: Entity\n }\n\n type Entity @key(fields: \"id\") {\n id: ID!\n data: Foo\n }\n\n interface Foo {\n foo: String!\n }\n\n interface Bar implements Foo {\n foo: String!\n bar: String!\n }\n\n type Baz implements Foo & Bar @shareable {\n foo: String!\n bar: String!\n baz: String!\n }\n\n type Qux implements Foo & Bar @shareable {\n foo: String!\n bar: String!\n qux: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.5\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ndirective @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ndirective @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ntype Query\n @shareable\n{\n a: Entity\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Entity\n @key(fields: \"id\")\n{\n id: ID!\n data: Foo\n}\n\ninterface Foo {\n foo: String!\n}\n\ninterface Bar implements Foo {\n foo: String!\n bar: String!\n}\n\ntype Baz implements Foo & Bar\n @shareable\n{\n foo: String!\n bar: String!\n baz: String!\n}\n\ntype Qux implements Foo & Bar\n @shareable\n{\n foo: String!\n bar: String!\n qux: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar federation__Scope\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Entity" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.5\"\n import: [\n \"@key\"\n \"@shareable\"\n \"@inaccessible\"\n \"@external\"\n \"@requires\"\n ]\n )\n\n type Query @shareable {\n b: Entity\n bb: Entity\n }\n\n type Entity @key(fields: \"id\") {\n id: ID!\n data: Foo @external\n requirer: String!\n @requires(\n fields: \"\"\"\n data {\n foo\n ... on Bar {\n bar\n ... on Baz {\n baz\n }\n ... on Qux {\n qux\n }\n }\n }\n \"\"\"\n )\n requirer2: String!\n @requires(\n fields: \"\"\"\n data {\n ... on Foo {\n foo\n }\n }\n \"\"\"\n )\n }\n\n interface Foo {\n foo: String!\n }\n\n interface Bar implements Foo {\n foo: String!\n bar: String!\n }\n\n type Baz implements Foo & Bar @shareable @inaccessible {\n foo: String!\n bar: String!\n baz: String!\n }\n\n type Qux implements Foo & Bar @shareable {\n foo: String!\n bar: String!\n qux: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.5\", import: [\"@key\", \"@shareable\", \"@inaccessible\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ndirective @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ndirective @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM\n\ntype Query\n @shareable\n{\n b: Entity\n bb: Entity\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Entity\n @key(fields: \"id\")\n{\n id: ID!\n data: Foo @external\n requirer: String! @requires(fields: \"data {\\n foo\\n ... on Bar {\\n bar\\n ... on Baz {\\n baz\\n }\\n ... on Qux {\\n qux\\n }\\n }\\n}\")\n requirer2: String! @requires(fields: \"data {\\n ... on Foo {\\n foo\\n }\\n}\")\n}\n\ninterface Foo {\n foo: String!\n}\n\ninterface Bar implements Foo {\n foo: String!\n bar: String!\n}\n\ntype Baz implements Foo & Bar\n @shareable\n @inaccessible\n{\n foo: String!\n bar: String!\n baz: String!\n}\n\ntype Qux implements Foo & Bar\n @shareable\n{\n foo: String!\n bar: String!\n qux: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar federation__Scope\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Entity" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "eeb5690054ce0f62a494e497a032487ac4a430d8109b78b6a596fdf6cfa38a73", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { bazs, entities, quxs } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.5\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query @shareable {\n a: Entity\n }\n\n type Entity @key(fields: \"id\") {\n id: ID!\n data: Foo\n }\n\n interface Foo {\n foo: String!\n }\n\n interface Bar implements Foo {\n foo: String!\n bar: String!\n }\n\n type Baz implements Foo & Bar @shareable {\n foo: String!\n bar: String!\n baz: String!\n }\n\n type Qux implements Foo & Bar @shareable {\n foo: String!\n bar: String!\n qux: String!\n }\n `,\n resolvers: {\n Query: {\n a() {\n return entities[1];\n },\n },\n Entity: {\n __resolveReference(key: { id: string }) {\n const entity = entities.find((e) => e.id === key.id);\n\n if (!entity) {\n return null;\n }\n\n return entity;\n },\n data(entity: { id: string; data: string }) {\n const data = entities.find((e) => e.id === entity.id)?.data;\n\n if (!data) {\n return null;\n }\n\n const baz = bazs.find((b) => b.id === data);\n\n if (baz) {\n return baz;\n }\n\n const qux = quxs.find((q) => q.id === data);\n\n if (qux) {\n return qux;\n }\n\n throw new Error(\"Invalid data\");\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "a9211eea91108f0c527a657b659dfd5e72847c75d82ce902b9a21d24be5c3982", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { entities, bazs, quxs } from \"./data.js\";\n\ntype WithData = T & {\n data: {\n foo: string;\n } & ({ bar: string; baz: string } | { bar: string; qux: string });\n};\ntype WithFoo = T & {\n data: {\n foo: string;\n };\n};\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.5\"\n import: [\n \"@key\"\n \"@shareable\"\n \"@inaccessible\"\n \"@external\"\n \"@requires\"\n ]\n )\n\n type Query @shareable {\n b: Entity\n bb: Entity\n }\n\n type Entity @key(fields: \"id\") {\n id: ID!\n data: Foo @external\n requirer: String!\n @requires(\n fields: \"\"\"\n data {\n foo\n ... on Bar {\n bar\n ... on Baz {\n baz\n }\n ... on Qux {\n qux\n }\n }\n }\n \"\"\"\n )\n requirer2: String!\n @requires(\n fields: \"\"\"\n data {\n ... on Foo {\n foo\n }\n }\n \"\"\"\n )\n }\n\n interface Foo {\n foo: String!\n }\n\n interface Bar implements Foo {\n foo: String!\n bar: String!\n }\n\n type Baz implements Foo & Bar @shareable @inaccessible {\n foo: String!\n bar: String!\n baz: String!\n }\n\n type Qux implements Foo & Bar @shareable {\n foo: String!\n bar: String!\n qux: String!\n }\n `,\n resolvers: {\n Query: {\n b() {\n return entities[0];\n },\n bb() {\n return entities[1];\n },\n },\n Entity: {\n __resolveReference(\n key:\n | { id: string }\n | WithData<{ id: string }>\n | WithFoo<{ id: string }>,\n ) {\n const entity = entities.find((e) => e.id === key.id);\n\n if (!entity) {\n return null;\n }\n\n return {\n ...entity,\n ...key,\n };\n },\n data(entity: { id: string }) {\n const data = entities.find((e) => e.id === entity.id)?.data;\n\n if (!data) {\n return null;\n }\n\n const baz = bazs.find((b) => b.id === data);\n\n if (baz) {\n return baz;\n }\n\n const qux = quxs.find((q) => q.id === data);\n\n if (qux) {\n return qux;\n }\n\n throw new Error(\"Invalid data\");\n },\n requirer(entity: WithData<{ id: string }>) {\n if (!(\"data\" in entity)) {\n throw new Error(\"Expected entity to have a data field\");\n }\n\n return entity.data.foo + \"_requirer\";\n },\n requirer2(entity: WithFoo<{ id: string }>) {\n if (!(\"data\" in entity)) {\n throw new Error(\"Expected entity to have a data field\");\n }\n\n return entity.data.foo + \"_requirer2\";\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "94028a4d3b1c95160f14519d3330182dac162a29127aacc480a9f3547a8c22fc", + "source": "export const entities = [\n {\n id: \"e1\",\n data: \"b1\",\n },\n {\n id: \"e2\",\n data: \"q1\",\n },\n];\n\nexport const bazs = [\n {\n __typename: \"Baz\",\n id: \"b1\",\n foo: \"b1-foo\",\n bar: \"b1-bar\",\n baz: \"b1-baz\",\n },\n];\n\nexport const quxs = [\n {\n __typename: \"Qux\",\n id: \"q1\",\n foo: \"q1-foo\",\n bar: \"q1-bar\",\n qux: \"q1-qux\",\n },\n];\n" + } + ] + }, + { + "id": "shared-root", + "cases": [ + { + "id": "shared-root/000", + "query": "\n query {\n product {\n id\n name {\n id\n brand\n model\n }\n category {\n id\n name\n }\n price {\n id\n amount\n currency\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "product": { + "id": "1", + "name": { + "id": "1", + "brand": "Brand 1", + "model": "Model 1" + }, + "price": { + "id": "1", + "amount": 1000, + "currency": "USD" + }, + "category": { + "id": "1", + "name": "Category 1" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "shared-root/001", + "query": "\n query {\n products {\n id\n name {\n id\n brand\n model\n }\n category {\n id\n name\n }\n price {\n id\n amount\n currency\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "id": "1", + "name": { + "id": "1", + "brand": "Brand 1", + "model": "Model 1" + }, + "price": { + "id": "1", + "amount": 1000, + "currency": "USD" + }, + "category": { + "id": "1", + "name": "Category 1" + } + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "name", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n }\n\n type Product {\n id: ID! @shareable\n name: Name!\n }\n\n type Name {\n id: ID!\n brand: String!\n model: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n _service: _Service!\n}\n\ntype Product {\n id: ID! @shareable\n name: Name!\n}\n\ntype Name {\n id: ID!\n brand: String!\n model: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}" + }, + { + "name": "price", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n }\n\n type Product {\n id: ID! @shareable\n price: Price!\n }\n\n type Price {\n id: ID!\n amount: Int!\n currency: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n _service: _Service!\n}\n\ntype Product {\n id: ID! @shareable\n price: Price!\n}\n\ntype Price {\n id: ID!\n amount: Int!\n currency: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}" + }, + { + "name": "category", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n }\n\n type Product {\n id: ID! @shareable\n category: Category!\n }\n\n type Category {\n id: ID!\n name: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n _service: _Service!\n}\n\ntype Product {\n id: ID! @shareable\n category: Category!\n}\n\ntype Category {\n id: ID!\n name: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}" + } + ], + "fixtureModules": [ + { + "path": "category.subgraph.ts", + "sha256": "2984b39e201c07f4aff70c7f139e8354e5c24f07cbbec54e25eb7ad5003c2272", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { product } from \"./data.js\";\n\nexport default createSubgraph(\"category\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n }\n\n type Product {\n id: ID! @shareable\n category: Category!\n }\n\n type Category {\n id: ID!\n name: String!\n }\n `,\n resolvers: {\n Query: {\n product() {\n return {\n id: product.id,\n category: product.category,\n };\n },\n products() {\n return [\n {\n id: product.id,\n category: product.category,\n },\n ];\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "ab1cf17ba1077a7bf0ceccd8b46beadbfa752c7fe99739c90e9a9598359e3fcf", + "source": "export const product = {\n id: \"1\",\n name: {\n id: \"1\",\n brand: \"Brand 1\",\n model: \"Model 1\",\n },\n category: {\n id: \"1\",\n name: \"Category 1\",\n },\n price: {\n id: \"1\",\n amount: 1000,\n currency: \"USD\",\n },\n address: {\n id: \"1\",\n street: \"123 Main St\",\n city: \"Springfield\",\n },\n};\n" + }, + { + "path": "name.subgraph.ts", + "sha256": "136118f77ca6423cc946cf1618d7a36d561a52aa277ba08ebab9df8666cee80b", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { product } from \"./data.js\";\n\nexport default createSubgraph(\"name\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n }\n\n type Product {\n id: ID! @shareable\n name: Name!\n }\n\n type Name {\n id: ID!\n brand: String!\n model: String!\n }\n `,\n resolvers: {\n Query: {\n product() {\n return {\n id: product.id,\n name: product.name,\n };\n },\n products() {\n return [\n {\n id: product.id,\n name: product.name,\n },\n ];\n },\n },\n },\n});\n" + }, + { + "path": "price.subgraph.ts", + "sha256": "a1a8f5335b0d3b8841d54d315276f65f3cda78c3a80071b4b70f87464e0a16c8", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { product } from \"./data.js\";\n\nexport default createSubgraph(\"price\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n product: Product! @shareable\n products: [Product!]! @shareable\n }\n\n type Product {\n id: ID! @shareable\n price: Price!\n }\n\n type Price {\n id: ID!\n amount: Int!\n currency: String!\n }\n `,\n resolvers: {\n Query: {\n product() {\n return {\n id: product.id,\n price: product.price,\n };\n },\n products() {\n return [\n {\n id: product.id,\n price: product.price,\n },\n ];\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "simple-entity-call", + "cases": [ + { + "id": "simple-entity-call/000", + "query": "\n query {\n user {\n id\n nickname\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "user": { + "id": "1", + "nickname": "user1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "email", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\"])\n\n type Query {\n user: User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n email: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype Query {\n user: User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n email: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "nickname", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@external\"]\n )\n\n type User @key(fields: \"email\") {\n email: String! @external\n nickname: String!\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\", \"@external\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ntype User\n @key(fields: \"email\")\n{\n email: String! @external\n nickname: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "data.ts", + "sha256": "4cef6e66af03abfeedf86177ea4cb2870fe34921467c41912c55cf1863f2a301", + "source": "export const users = [\n {\n id: \"1\",\n email: \"user1@gmail.com\",\n nickname: \"user1\",\n },\n {\n id: \"2\",\n email: \"user2@gmail.com\",\n nickname: \"user2\",\n },\n];\n" + }, + { + "path": "email.subgraph.ts", + "sha256": "5bd33e72e74e19e19b1e8f684b64163d0d4c8cde2233ab86718320ea66acdd78", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"email\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.0\", import: [\"@key\"])\n\n type Query {\n user: User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n email: String!\n }\n `,\n resolvers: {\n Query: {\n user() {\n return {\n id: users[0].id,\n email: users[0].email,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n email: user.email,\n };\n },\n },\n },\n});\n" + }, + { + "path": "nickname.subgraph.ts", + "sha256": "d95aba3323f6b0c2b3914dbb3413542e5a63eb7431f378fe27fe63eb94330e7d", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"nickname\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.0\"\n import: [\"@key\", \"@external\"]\n )\n\n type User @key(fields: \"email\") {\n email: String! @external\n nickname: String!\n }\n `,\n resolvers: {\n User: {\n __resolveReference(key: { email: string }) {\n const user = users.find((u) => u.email === key.email);\n\n if (!user) {\n return null;\n }\n\n return {\n nickname: user.nickname,\n };\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "simple-inaccessible", + "cases": [ + { + "id": "simple-inaccessible/000", + "query": "\n query {\n usersInAge {\n id\n friends {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "usersInAge": [ + { + "id": "u1", + "friends": [ + { + "id": "u2" + } + ] + }, + { + "id": "u2", + "friends": [ + { + "id": "u1" + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-inaccessible/001", + "query": "\n query {\n usersInFriends {\n id\n friends {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "usersInFriends": [ + { + "id": "u1", + "friends": [ + { + "id": "u2" + } + ] + }, + { + "id": "u2", + "friends": [ + { + "id": "u1" + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-inaccessible/002", + "query": "\n query {\n usersInFriends {\n id\n friends(type: FRIEND) {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": false, + "expectedData": null, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "simple-inaccessible/003", + "query": "\n query {\n usersInFriends {\n id\n friends {\n id\n type\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "usersInFriends": [ + { + "id": "u1", + "friends": [ + { + "id": "u2", + "type": null + } + ] + }, + { + "id": "u2", + "friends": [ + { + "id": "u1", + "type": null + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "friends", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\", \"@shareable\"]\n )\n\n type Query {\n usersInFriends: [User!]!\n }\n\n type User @key(fields: \"id\") {\n id: ID\n friends(type: FriendType = FAMILY @inaccessible): [User!]!\n type: FriendType\n }\n\n enum FriendType {\n FAMILY @inaccessible\n FRIEND\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@inaccessible\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n usersInFriends: [User!]!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID\n friends(type: FriendType = FAMILY @inaccessible): [User!]!\n type: FriendType\n}\n\nenum FriendType {\n FAMILY @inaccessible\n FRIEND\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "age", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\", \"@shareable\"]\n )\n\n type Query {\n usersInAge: [User!]! @shareable\n }\n\n type User @key(fields: \"id\") {\n id: ID\n age: Int\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@inaccessible\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n usersInAge: [User!]! @shareable\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID\n age: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "age.subgraph.ts", + "sha256": "cfe7c042907e89bb0377625e75d557d117169890d47c6429e689a236d346d391", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"age\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\", \"@shareable\"]\n )\n\n type Query {\n usersInAge: [User!]! @shareable\n }\n\n type User @key(fields: \"id\") {\n id: ID\n age: Int\n }\n `,\n resolvers: {\n Query: {\n usersInAge() {\n return users.map((u) => ({\n id: u.id,\n age: u.age,\n }));\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n age: user.age,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "d62e20375091662647df462d75906cbae360ad31f82061bb290502be7acd97e1", + "source": "export const users = [\n {\n id: \"u1\",\n age: 11,\n friends: [\"u2\"],\n },\n {\n id: \"u2\",\n age: 22,\n friends: [\"u1\"],\n },\n];\n" + }, + { + "path": "friends.subgraph.ts", + "sha256": "da76a1be63dec5a179c17042fa7438c7babde8473867dacad245a4f526676e7d", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"friends\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@inaccessible\", \"@shareable\"]\n )\n\n type Query {\n usersInFriends: [User!]!\n }\n\n type User @key(fields: \"id\") {\n id: ID\n friends(type: FriendType = FAMILY @inaccessible): [User!]!\n type: FriendType\n }\n\n enum FriendType {\n FAMILY @inaccessible\n FRIEND\n }\n `,\n resolvers: {\n Query: {\n usersInFriends() {\n return users.map((u) => ({\n id: u.id,\n friends: u.friends,\n }));\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n friends: user.friends,\n };\n },\n friends(user: { id: string; friends: string[] }) {\n return user.friends.map((id) => {\n const friend = users.find((u) => u.id === id);\n\n if (!friend) {\n return null;\n }\n\n return {\n id: friend.id,\n friends: friend.friends,\n };\n });\n },\n type() {\n return \"FAMILY\";\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "simple-interface-object", + "cases": [ + { + "id": "simple-interface-object/000", + "query": "\n query {\n anotherUsers {\n id\n name\n username\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherUsers": [ + { + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/001", + "query": "\n query {\n users {\n id\n name\n username\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/002", + "query": "\n query {\n anotherUsers {\n ... on User {\n age\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherUsers": [ + { + "age": 11 + }, + { + "age": 22 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/003", + "query": "\n query {\n users {\n ... on User {\n age\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "age": 11 + }, + { + "age": 22 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/004", + "query": "\n query {\n anotherUsers {\n ... on User {\n age\n id\n name\n username\n }\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "anotherUsers": [ + { + "age": 11, + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "age": 22, + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/005", + "query": "\n query {\n users {\n ... on User {\n age\n id\n name\n username\n }\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "age": 11, + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "age": 22, + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/006", + "query": "\n query {\n users {\n ... on User {\n age\n id\n name\n username\n }\n id\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "age": 11, + "id": "u1", + "name": "u1-name", + "username": "u1-username" + }, + { + "age": 22, + "id": "u2", + "name": "u2-name", + "username": "u2-username" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/007", + "query": "\n query {\n accounts {\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "accounts": [ + { + "name": "Alice" + }, + { + "name": "Bob" + }, + { + "name": "Charlie" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/008", + "query": "\n query {\n accounts {\n ... on Admin {\n name\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "accounts": [ + { + "name": "Alice" + }, + { + "name": "Bob" + }, + {} + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/009", + "query": "\n query {\n accounts {\n name\n # NOTE\n # __typename is not available in the interfaceObject, needs to be resolved indirectly\n __typename\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "accounts": [ + { + "name": "Alice", + "__typename": "Admin" + }, + { + "name": "Bob", + "__typename": "Admin" + }, + { + "name": "Charlie", + "__typename": "Regular" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/010", + "query": "\n query {\n accounts {\n ... on Admin {\n __typename\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "accounts": [ + { + "__typename": "Admin" + }, + { + "__typename": "Admin" + }, + {} + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/011", + "query": "\n query {\n accounts {\n id\n isActive\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "accounts": [ + { + "id": "u1", + "isActive": false + }, + { + "id": "u2", + "isActive": false + }, + { + "id": "u3", + "isActive": false + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-interface-object/012", + "query": "\n query {\n accounts {\n # NOTE\n # id is available in the interfaceObject and can be resolved as there's no type condition involved\n id\n ... on Admin {\n isActive\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "accounts": [ + { + "id": "u1", + "isActive": true + }, + { + "id": "u2", + "isActive": true + }, + { + "id": "u3" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n users: [NodeWithName!]!\n }\n\n interface NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n }\n\n type User implements NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n age: Int\n }\n\n interface Account @key(fields: \"id\") {\n id: ID!\n }\n\n type Admin implements Account @key(fields: \"id\") {\n id: ID!\n isMain: Boolean!\n isActive: Boolean! @shareable\n }\n\n type Regular implements Account @key(fields: \"id\") {\n id: ID!\n isMain: Boolean!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n users: [NodeWithName!]!\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ninterface NodeWithName\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n}\n\ntype User implements NodeWithName\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n age: Int\n}\n\ninterface Account\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Admin implements Account\n @key(fields: \"id\")\n{\n id: ID!\n isMain: Boolean!\n isActive: Boolean! @shareable\n}\n\ntype Regular implements Account\n @key(fields: \"id\")\n{\n id: ID!\n isMain: Boolean!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Admin | Regular | User" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\", \"@shareable\"]\n )\n\n type Query {\n anotherUsers: [NodeWithName]\n accounts: [Account] @shareable\n }\n\n type Account @key(fields: \"id\") @interfaceObject {\n id: ID!\n name: String!\n }\n\n type NodeWithName @key(fields: \"id\") @interfaceObject {\n id: ID!\n username: String\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @interfaceObject on OBJECT\n\ntype Query {\n anotherUsers: [NodeWithName]\n accounts: [Account] @shareable\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Account\n @key(fields: \"id\")\n @interfaceObject\n{\n id: ID!\n name: String!\n}\n\ntype NodeWithName\n @key(fields: \"id\")\n @interfaceObject\n{\n id: ID!\n username: String\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Account | NodeWithName" + }, + { + "name": "c", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\", \"@shareable\"]\n )\n\n type Account @key(fields: \"id\") @interfaceObject {\n id: ID!\n isActive: Boolean! @shareable\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @interfaceObject on OBJECT\n\ntype Account\n @key(fields: \"id\")\n @interfaceObject\n{\n id: ID!\n isActive: Boolean! @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Account\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "d1b9d9aea619d20c39fa5f37cfb1d9ea373abb2cb88a3060535f34d9fad3e8fe", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users, accounts } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n users: [NodeWithName!]!\n }\n\n interface NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n }\n\n type User implements NodeWithName @key(fields: \"id\") {\n id: ID!\n name: String\n age: Int\n }\n\n interface Account @key(fields: \"id\") {\n id: ID!\n }\n\n type Admin implements Account @key(fields: \"id\") {\n id: ID!\n isMain: Boolean!\n isActive: Boolean! @shareable\n }\n\n type Regular implements Account @key(fields: \"id\") {\n id: ID!\n isMain: Boolean!\n }\n `,\n resolvers: {\n NodeWithName: {\n __resolveReference(key: { id: string }) {\n const node = users.find((u) => u.id === key.id);\n\n if (!node) {\n return null;\n }\n\n return {\n __typename: \"User\",\n id: node.id,\n name: node.name,\n age: node.age,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n __typename: \"User\",\n id: user.id,\n name: user.name,\n age: user.age,\n };\n },\n },\n Account: {\n __resolveReference(key: { id: string }) {\n const account = accounts.find((account) => account.id === key.id);\n\n if (!account) {\n return null;\n }\n\n return {\n __typename: account.__typename,\n id: account.id,\n isActive: account.isActive,\n };\n },\n },\n Admin: {\n __resolveReference(key: { id: string }) {\n const admin = accounts.find((account) => account.id === key.id);\n\n if (!admin) {\n return null;\n }\n\n if (admin.__typename !== \"Admin\") {\n return null;\n }\n\n return {\n __typename: admin.__typename,\n id: admin.id,\n isMain: admin.isMain,\n isActive: admin.isActive,\n };\n },\n isMain(admin: { id: string; isMain?: boolean }) {\n if (typeof admin.isMain === \"boolean\") {\n return admin.isMain;\n }\n\n const account = accounts.find((a) => a.id === admin.id);\n\n if (!account) {\n return null;\n }\n\n return account.isMain;\n },\n },\n Regular: {\n __resolveReference(key: { id: string }) {\n const admin = accounts.find((account) => account.id === key.id);\n\n if (!admin) {\n return null;\n }\n\n return {\n __typename: admin.__typename,\n id: admin.id,\n isMain: admin.isMain,\n isActive: admin.isActive,\n };\n },\n isMain(admin: { id: string; isMain?: boolean }) {\n if (typeof admin.isMain === \"boolean\") {\n return admin.isMain;\n }\n\n const account = accounts.find((a) => a.id === admin.id);\n\n if (!account) {\n return null;\n }\n\n return account.isMain;\n },\n },\n Query: {\n users() {\n return users.map((u) => ({\n __typename: \"User\",\n id: u.id,\n name: u.name,\n age: u.age,\n }));\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "9bdf09f3031bd333015d74c0c883e6ff3306e69ba45031dfb8faaed30957b513", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users, accounts } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\", \"@shareable\"]\n )\n\n type Query {\n anotherUsers: [NodeWithName]\n accounts: [Account] @shareable\n }\n\n type Account @key(fields: \"id\") @interfaceObject {\n id: ID!\n name: String!\n }\n\n type NodeWithName @key(fields: \"id\") @interfaceObject {\n id: ID!\n username: String\n }\n `,\n resolvers: {\n NodeWithName: {\n __resolveReference(key: { id: string }) {\n const node = users.find((u) => u.id === key.id);\n\n if (!node) {\n return null;\n }\n\n return {\n __typename: \"User\",\n id: node.id,\n username: node.username,\n };\n },\n username(node: { id: string }) {\n const user = users.find((u) => u.id === node.id);\n\n if (!user) {\n return null;\n }\n\n return user.username;\n },\n },\n Account: {\n __resolveReference(key: { __typename: string; id: string }) {\n const account = accounts.find((account) => account.id === key.id);\n\n if (!account) {\n return null;\n }\n\n return {\n // I deliberately return a wrong __typename here to make sure it's not used by the gateway\n __typename: \"Never\",\n id: account.id,\n };\n },\n name(account: { id: string }) {\n return accounts.find((u) => u.id === account.id)?.name;\n },\n },\n Query: {\n anotherUsers() {\n return users.map((u) => ({\n __typename: \"User\",\n id: u.id,\n username: u.username,\n }));\n },\n accounts() {\n return accounts.map((user) => {\n return {\n // I deliberately return a wrong __typename here to make sure it's not used by the gateway\n __typename: \"Never\",\n id: user.id,\n };\n });\n },\n },\n },\n});\n" + }, + { + "path": "c.subgraph.ts", + "sha256": "0e346f56a92fe1966b91f9d75b89e6738f70b2b7b7556ad134afbd2ebfac86dc", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { accounts } from \"./data.js\";\n\nexport default createSubgraph(\"c\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\", \"@shareable\"]\n )\n\n type Account @key(fields: \"id\") @interfaceObject {\n id: ID!\n isActive: Boolean! @shareable\n }\n `,\n resolvers: {\n Account: {\n __resolveReference(key: { __typename: string; id: string }) {\n const account = accounts.find((account) => account.id === key.id);\n\n if (!account) {\n return null;\n }\n\n return {\n // I deliberately return a wrong __typename here to make sure it's not used by the gateway\n __typename: \"Never\",\n id: account.id,\n };\n },\n isActive(account: { id: string }) {\n return false;\n },\n },\n Query: {\n accounts() {\n return accounts.map((user) => {\n return {\n // I deliberately return a wrong __typename here to make sure it's not used by the gateway\n __typename: \"Never\",\n id: user.id,\n };\n });\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "2012d77b635d1dff8e478687ee770b58a794f462ae4f390497f8c07ccc544d5a", + "source": "export const users = [\n {\n id: \"u1\",\n name: \"u1-name\",\n username: \"u1-username\",\n age: 11,\n },\n {\n id: \"u2\",\n name: \"u2-name\",\n username: \"u2-username\",\n age: 22,\n },\n];\n\nexport const accounts = [\n {\n __typename: \"Admin\",\n id: \"u1\",\n name: \"Alice\",\n isMain: false,\n isActive: true,\n },\n {\n __typename: \"Admin\",\n id: \"u2\",\n name: \"Bob\",\n isMain: true,\n isActive: true,\n },\n {\n __typename: \"Regular\",\n id: \"u3\",\n name: \"Charlie\",\n isMain: false,\n isActive: true,\n },\n];\n" + } + ] + }, + { + "id": "simple-override", + "cases": [ + { + "id": "simple-override/000", + "query": "\n query {\n feed {\n createdAt\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "createdAt": "p1-createdAt" + }, + { + "createdAt": "p2-createdAt" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-override/001", + "query": "\n query {\n aFeed {\n createdAt\n }\n bFeed {\n createdAt\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "aFeed": [ + { + "createdAt": "p2-createdAt" + } + ], + "bFeed": [ + { + "createdAt": "p1-createdAt" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n aFeed: [Post]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n createdAt: String! @shareable\n}\n\ntype Query {\n feed: [Post] @shareable\n aFeed: [Post]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Post" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@override\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @override(from: \"a\") @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n bFeed: [Post]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@override\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n createdAt: String! @override(from: \"a\") @shareable\n}\n\ntype Query {\n feed: [Post] @shareable\n bFeed: [Post]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Post" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "dce46798836f6f6b62c299791fee51ce3e0ba0e7e94141d26f02d17209482bf3", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { posts } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n aFeed: [Post]\n }\n `,\n resolvers: {\n Query: {\n feed() {\n return posts;\n },\n aFeed() {\n return [posts[1]];\n },\n },\n Post: {\n __resolveReference(key: { id: string }) {\n const post = posts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n createdAt: post.createdAt,\n };\n },\n createdAt() {\n return \"NEVER\";\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "7e1aba5e5ce6f7ddd6f19296eb660696f10f50b505359584582f1ca52213b87e", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { posts } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@override\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @override(from: \"a\") @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n bFeed: [Post]\n }\n `,\n resolvers: {\n Query: {\n feed() {\n return posts;\n },\n bFeed() {\n return [posts[0]];\n },\n },\n Post: {\n __resolveReference(key: { id: string }) {\n const post = posts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n createdAt: post.createdAt,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "029b5a3d869e8cafda598325ac43ef79d3ce0b74295c8ccbea98a3831f144328", + "source": "export const posts = [\n {\n id: \"p1\",\n createdAt: \"p1-createdAt\",\n },\n {\n id: \"p2\",\n createdAt: \"p2-createdAt\",\n },\n];\n" + } + ] + }, + { + "id": "simple-requires-provides", + "cases": [ + { + "id": "simple-requires-provides/000", + "query": "\n query {\n me {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "me": { + "id": "u1" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/001", + "query": "\n query {\n me {\n id\n reviews {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "me": { + "id": "u1", + "reviews": [ + { + "id": "r1" + }, + { + "id": "r2" + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/002", + "query": "\n query {\n me {\n reviews {\n id\n author {\n id\n username\n }\n product {\n inStock\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "me": { + "reviews": [ + { + "id": "r1", + "author": { + "id": "u1", + "username": "u-username-1" + }, + "product": { + "inStock": true + } + }, + { + "id": "r2", + "author": { + "id": "u1", + "username": "u-username-1" + }, + "product": { + "inStock": false + } + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/003", + "query": "\n query {\n products {\n name\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "name": "p-name-1" + }, + { + "name": "p-name-2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/004", + "query": "\n query {\n products {\n price\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "price": 11 + }, + { + "price": 22 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/005", + "query": "\n query {\n products {\n shippingEstimate\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "shippingEstimate": 110 + }, + { + "shippingEstimate": 440 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/006", + "query": "\n query {\n products {\n shippingEstimate\n weight\n price\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "shippingEstimate": 110, + "weight": 1, + "price": 11 + }, + { + "shippingEstimate": 440, + "weight": 2, + "price": 22 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/007", + "query": "\n {\n products {\n reviews {\n id\n author {\n username\n }\n product {\n name\n shippingEstimate\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "reviews": [ + { + "id": "r1", + "author": { + "username": "u-username-1" + }, + "product": { + "name": "p-name-1", + "shippingEstimate": 110 + } + } + ] + }, + { + "reviews": [ + { + "id": "r2", + "author": { + "username": "u-username-1" + }, + "product": { + "name": "p-name-2", + "shippingEstimate": 440 + } + } + ] + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/008", + "query": "\n {\n me {\n reviews {\n product {\n reviews {\n id\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "me": { + "reviews": [ + { + "product": { + "reviews": [ + { + "id": "r1" + } + ] + } + }, + { + "product": { + "reviews": [ + { + "id": "r2" + } + ] + } + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/009", + "query": "\n query {\n me {\n reviews {\n product {\n inStock\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "me": { + "reviews": [ + { + "product": { + "inStock": true + } + }, + { + "product": { + "inStock": false + } + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/010", + "query": "\n query {\n me {\n reviews {\n product {\n shippingEstimate\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "me": { + "reviews": [ + { + "product": { + "shippingEstimate": 110 + } + }, + { + "product": { + "shippingEstimate": 440 + } + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "simple-requires-provides/011", + "query": "\n query {\n me {\n reviews {\n product {\n shippingEstimate\n shippingEstimateTag\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "me": { + "reviews": [ + { + "product": { + "shippingEstimate": 110, + "shippingEstimateTag": "#p1#110#" + } + }, + { + "product": { + "shippingEstimate": 440, + "shippingEstimateTag": "#p2#440#" + } + } + ] + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "accounts", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n me: User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String\n username: String @shareable\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n me: User\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n name: String\n username: String @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + }, + { + "name": "inventory", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"upc\") {\n upc: String!\n weight: Int @external\n price: Int @external\n inStock: Boolean\n shippingEstimate: Int @requires(fields: \"price weight\")\n shippingEstimateTag: String @requires(fields: \"price weight\")\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Product\n @key(fields: \"upc\")\n{\n upc: String!\n weight: Int @external\n price: Int @external\n inStock: Boolean\n shippingEstimate: Int @requires(fields: \"price weight\")\n shippingEstimateTag: String @requires(fields: \"price weight\")\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + }, + { + "name": "products", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n products: [Product]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n name: String\n price: Int\n weight: Int\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n products: [Product]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Product\n @key(fields: \"upc\")\n{\n upc: String!\n name: String\n price: Int\n weight: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product" + }, + { + "name": "reviews", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@provides\"]\n )\n\n type Review @key(fields: \"id\") {\n id: ID!\n body: String\n author: User @provides(fields: \"username\")\n product: Product\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n username: String @external\n reviews: [Review]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n reviews: [Review]\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@provides\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Review\n @key(fields: \"id\")\n{\n id: ID!\n body: String\n author: User @provides(fields: \"username\")\n product: Product\n}\n\ntype User\n @key(fields: \"id\")\n{\n id: ID!\n username: String @external\n reviews: [Review]\n}\n\ntype Product\n @key(fields: \"upc\")\n{\n upc: String!\n reviews: [Review]\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Product | Review | User\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "accounts.subgraph.ts", + "sha256": "d93af41df8620d6555b2d85033080553ed0e375983c68831e41ef8c532ddcfb3", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"accounts\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Query {\n me: User\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n name: String\n username: String @shareable\n }\n `,\n resolvers: {\n Query: {\n me() {\n return {\n id: users[0].id,\n name: users[0].name,\n username: users[0].username,\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n name: user.name,\n username: user.username,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "ffc8298df5d1c147b543f6c72cf89b844117f19fbfdb70212c30a18bb768f8b5", + "source": "export const users = [\n {\n id: \"u1\",\n username: \"u-username-1\",\n name: \"u-name-1\",\n },\n {\n id: \"u2\",\n username: \"u-username-2\",\n name: \"u-name-2\",\n },\n];\n\nexport const products = [\n {\n upc: \"p1\",\n name: \"p-name-1\",\n price: 11,\n weight: 1,\n },\n {\n upc: \"p2\",\n name: \"p-name-2\",\n price: 22,\n weight: 2,\n },\n];\n\nexport const inStock = [products[0].upc];\n\nexport const reviews = [\n {\n id: \"r1\",\n body: \"r-body-1\",\n authorId: users[0].id,\n productUpc: products[0].upc,\n },\n {\n id: \"r2\",\n body: \"r-body-2\",\n authorId: users[0].id,\n productUpc: products[1].upc,\n },\n];\n" + }, + { + "path": "inventory.subgraph.ts", + "sha256": "41561f9a5ead3df41ab5b46de2b5e269b9f23265c25e8a580ce77ef81d8d68b3", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { inStock, products } from \"./data.js\";\n\nexport default createSubgraph(\"inventory\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@requires\"]\n )\n\n type Product @key(fields: \"upc\") {\n upc: String!\n weight: Int @external\n price: Int @external\n inStock: Boolean\n shippingEstimate: Int @requires(fields: \"price weight\")\n shippingEstimateTag: String @requires(fields: \"price weight\")\n }\n `,\n resolvers: {\n Product: {\n __resolveReference(\n key: { upc: string; price: number; weight: number } | { upc: string },\n ) {\n const product = products.find((p) => p.upc === key.upc);\n\n if (!product) {\n return null;\n }\n\n if (\"weight\" in key && \"price\" in key) {\n return {\n upc: product.upc,\n weight: key.weight,\n price: key.price,\n };\n }\n\n return {\n upc: product.upc,\n };\n },\n shippingEstimate(product: { price: number; weight: number }) {\n return product.price * product.weight * 10;\n },\n shippingEstimateTag(product: {\n upc: string;\n price: number;\n weight: number;\n }) {\n return `#${product.upc}#${product.price * product.weight * 10}#`;\n },\n inStock(product: { upc: string }) {\n return inStock.includes(product.upc);\n },\n },\n },\n});\n" + }, + { + "path": "products.subgraph.ts", + "sha256": "80cfccf5093edc3d62bb746a5e3a01eeb954c9ecb389fe204ff438390cfdf42d", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"products\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n products: [Product]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n name: String\n price: Int\n weight: Int\n }\n `,\n resolvers: {\n Query: {\n products() {\n return products.map((p) => ({\n upc: p.upc,\n name: p.name,\n price: p.price,\n weight: p.weight,\n }));\n },\n },\n Product: {\n __resolveReference(key: { upc: string }) {\n const product = products.find((p) => p.upc === key.upc);\n\n if (!product) {\n return null;\n }\n\n return {\n upc: product.upc,\n name: product.name,\n price: product.price,\n weight: product.weight,\n };\n },\n },\n },\n});\n" + }, + { + "path": "reviews.subgraph.ts", + "sha256": "03691acbfa5255af6998edc802eb71f23734ba35a47a5ef8c8ccfbe555699c56", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products, reviews, users } from \"./data.js\";\n\nexport default createSubgraph(\"reviews\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@external\", \"@provides\"]\n )\n\n type Review @key(fields: \"id\") {\n id: ID!\n body: String\n author: User @provides(fields: \"username\")\n product: Product\n }\n\n type User @key(fields: \"id\") {\n id: ID!\n username: String @external\n reviews: [Review]\n }\n\n type Product @key(fields: \"upc\") {\n upc: String!\n reviews: [Review]\n }\n `,\n resolvers: {\n Review: {\n __resolveReference(key: { id: string }) {\n const review = reviews.find((r) => r.id === key.id);\n\n if (!review) {\n return null;\n }\n\n return {\n id: review.id,\n body: review.body,\n authorId: review.authorId,\n productUpc: review.productUpc,\n };\n },\n author(review: { id: string; authorId: string }) {\n const user = users.find((u) => u.id === review.authorId);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n username: user.username,\n };\n },\n product(review: { productUpc: string }) {\n const product = products.find((p) => p.upc === review.productUpc);\n\n if (!product) {\n return null;\n }\n\n return {\n upc: product.upc,\n reviews: reviews\n .filter((r) => r.productUpc === product.upc)\n .map((r) => ({\n id: r.id,\n body: r.body,\n authorId: r.authorId,\n productUpc: r.productUpc,\n })),\n };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((u) => u.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n id: user.id,\n username: user.username,\n };\n },\n reviews(user: { id: string }) {\n return reviews.filter((r) => r.authorId === user.id);\n },\n },\n Product: {\n __resolveReference(key: { upc: string }) {\n return {\n upc: key.upc,\n };\n },\n reviews(product: { upc: string }) {\n return reviews.filter((r) => r.productUpc === product.upc);\n },\n },\n },\n});\n" + } + ] + }, + { + "id": "typename", + "cases": [ + { + "id": "typename/000", + "query": "\n query {\n union {\n __typename\n typename: __typename\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "union": { + "__typename": "Oven", + "typename": "Oven" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "typename/001", + "query": "\n query {\n interface {\n id\n __typename\n typename: __typename\n t: __typename\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "interface": { + "id": "2", + "__typename": "Toaster", + "typename": "Toaster", + "t": "Toaster" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "typename/002", + "query": "\n query {\n union {\n __typename\n ... on Oven {\n typename: __typename\n }\n ... on Toaster {\n typename: __typename\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "union": { + "__typename": "Oven", + "typename": "Oven" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "typename/003", + "query": "\n query {\n interface {\n __typename\n ... on Oven {\n typename: __typename\n }\n ... on Toaster {\n typename: __typename\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "interface": { + "__typename": "Toaster", + "typename": "Toaster" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "typename/004", + "query": "\n query {\n users {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "id": "u1" + }, + { + "id": "u2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "typename/005", + "query": "\n query {\n users {\n __typename\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "users": [ + { + "__typename": "Admin" + }, + { + "__typename": "Admin" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n union: Product\n interface: Node\n }\n\n union Product = Oven | Toaster\n\n interface Node {\n id: ID!\n }\n\n type Oven implements Node {\n id: ID!\n }\n\n type Toaster implements Node {\n id: ID!\n }\n\n interface User @key(fields: \"id\") {\n id: ID!\n }\n\n type Admin implements User @key(fields: \"id\") {\n id: ID!\n isMain: Boolean!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n union: Product\n interface: Node\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nunion Product = Oven | Toaster\n\ninterface Node {\n id: ID!\n}\n\ntype Oven implements Node {\n id: ID!\n}\n\ntype Toaster implements Node {\n id: ID!\n}\n\ninterface User\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Admin implements User\n @key(fields: \"id\")\n{\n id: ID!\n isMain: Boolean!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Admin" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n type Query {\n users: [User]\n }\n\n type User @key(fields: \"id\") @interfaceObject {\n id: ID!\n name: String!\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@interfaceObject\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @interfaceObject on OBJECT\n\ntype Query {\n users: [User]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype User\n @key(fields: \"id\")\n @interfaceObject\n{\n id: ID!\n name: String!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = User" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "83b216689cb7ed0141ec9cb37176450eb75b2c60f21670a1af30cc7f495e5725", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n type Query {\n union: Product\n interface: Node\n }\n\n union Product = Oven | Toaster\n\n interface Node {\n id: ID!\n }\n\n type Oven implements Node {\n id: ID!\n }\n\n type Toaster implements Node {\n id: ID!\n }\n\n interface User @key(fields: \"id\") {\n id: ID!\n }\n\n type Admin implements User @key(fields: \"id\") {\n id: ID!\n isMain: Boolean!\n }\n `,\n resolvers: {\n Query: {\n union() {\n return { id: \"1\", __typename: \"Oven\" };\n },\n interface() {\n return { id: \"2\", __typename: \"Toaster\" };\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((user) => user.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n __typename: user.__typename,\n id: user.id,\n };\n },\n },\n Admin: {\n __resolveReference(key: { id: string }) {\n const user = users.find((user) => user.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n __typename: user.__typename,\n id: user.id,\n isMain: user.isMain,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "5b7e8287c80a3f37dbed6726ab2c98f34f00c182c3aa66b9cdf1ba3efc5757bb", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { users } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@interfaceObject\"]\n )\n\n type Query {\n users: [User]\n }\n\n type User @key(fields: \"id\") @interfaceObject {\n id: ID!\n name: String!\n }\n `,\n resolvers: {\n Query: {\n users() {\n return users.map((user) => {\n return {\n // I deliberately return no __typename as it should not be resolved by the @interfaceObject\n id: user.id,\n };\n });\n },\n },\n User: {\n __resolveReference(key: { id: string }) {\n const user = users.find((user) => user.id === key.id);\n\n if (!user) {\n return null;\n }\n\n return {\n // I deliberately return no __typename as it should not be resolved by the @interfaceObject\n id: user.id,\n };\n },\n name(user: { id: string }) {\n return users.find((u) => u.id === user.id)?.name;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "d8e61c2cbb69de1c6add220c78078f20c4965b613d3fb21b84fafa327e7383c5", + "source": "export const users = [\n {\n __typename: \"Admin\",\n id: \"u1\",\n name: \"Alice\",\n isMain: false,\n },\n {\n __typename: \"Admin\",\n id: \"u2\",\n name: \"Bob\",\n isMain: true,\n },\n];\n" + } + ] + }, + { + "id": "unavailable-override", + "cases": [ + { + "id": "unavailable-override/000", + "query": "\n query {\n feed {\n createdAt\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "feed": [ + { + "createdAt": "p1-createdAt" + }, + { + "createdAt": "p2-createdAt" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "unavailable-override/001", + "query": "\n query {\n aFeed {\n createdAt\n }\n bFeed {\n createdAt\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "aFeed": [ + { + "createdAt": "p2-createdAt" + } + ], + "bFeed": [ + { + "createdAt": "p1-createdAt" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n aFeed: [Post]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n createdAt: String! @shareable\n}\n\ntype Query {\n feed: [Post] @shareable\n aFeed: [Post]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Post" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@override\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @override(from: \"non-existing\") @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n bFeed: [Post]\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@override\", \"@shareable\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Post\n @key(fields: \"id\")\n{\n id: ID!\n createdAt: String! @override(from: \"non-existing\") @shareable\n}\n\ntype Query {\n feed: [Post] @shareable\n bFeed: [Post]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Post" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "dc538b91d4fd8913e5f984dfb10e3360b96be0361a9fa366f68e96b2a09d07e0", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { posts } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n aFeed: [Post]\n }\n `,\n resolvers: {\n Query: {\n feed() {\n return posts;\n },\n aFeed() {\n return [posts[1]];\n },\n },\n Post: {\n __resolveReference(key: { id: string }) {\n const post = posts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n createdAt: post.createdAt,\n };\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "029d5a7ac19dd1e1f21f3f3e870886df4b82afd7aac4822ca346c5d6587a1f2c", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { posts } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@key\", \"@override\", \"@shareable\"]\n )\n\n type Post @key(fields: \"id\") {\n id: ID!\n createdAt: String! @override(from: \"non-existing\") @shareable\n }\n\n type Query {\n feed: [Post] @shareable\n bFeed: [Post]\n }\n `,\n resolvers: {\n Query: {\n feed() {\n return posts;\n },\n bFeed() {\n return [posts[0]];\n },\n },\n Post: {\n __resolveReference(key: { id: string }) {\n const post = posts.find((p) => p.id === key.id);\n\n if (!post) {\n return null;\n }\n\n return {\n id: post.id,\n createdAt: post.createdAt,\n };\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "029b5a3d869e8cafda598325ac43ef79d3ce0b74295c8ccbea98a3831f144328", + "source": "export const posts = [\n {\n id: \"p1\",\n createdAt: \"p1-createdAt\",\n },\n {\n id: \"p2\",\n createdAt: \"p2-createdAt\",\n },\n];\n" + } + ] + }, + { + "id": "union-interface-distributed", + "cases": [ + { + "id": "union-interface-distributed/000", + "query": "\n query {\n products {\n ... on Node {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "products": [ + { + "id": "oven1" + }, + { + "id": "oven2" + }, + { + "id": "toaster1" + }, + { + "id": "toaster2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-interface-distributed/001", + "query": "\n query {\n nodes {\n ... on Toaster {\n warranty\n }\n ... on Oven {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "nodes": [ + { + "warranty": 3 + }, + { + "warranty": 4 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-interface-distributed/002", + "query": "\n query {\n nodes {\n id\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "nodes": [ + { + "id": "toaster1" + }, + { + "id": "toaster2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-interface-distributed/003", + "query": "\n query {\n nodes {\n ... on Node {\n id\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "nodes": [ + { + "id": "toaster1" + }, + { + "id": "toaster2" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-interface-distributed/004", + "query": "\n query {\n nodes {\n ... on Node {\n ... on WithWarranty {\n warranty\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "nodes": [ + { + "warranty": 3 + }, + { + "warranty": 4 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-interface-distributed/005", + "query": "\n query {\n nodes {\n ... on Node {\n id\n ... on Node {\n id\n ... on WithWarranty {\n warranty\n }\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "nodes": [ + { + "id": "toaster1", + "warranty": 3 + }, + { + "id": "toaster2", + "warranty": 4 + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-interface-distributed/006", + "query": "\n {\n toasters {\n ...ToasterFragment\n ...NodeFragment\n }\n }\n\n fragment ToasterFragment on Toaster {\n id\n }\n\n fragment NodeFragment on Node {\n id\n __typename\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "toasters": [ + { + "id": "toaster1", + "__typename": "Toaster" + }, + { + "id": "toaster2", + "__typename": "Toaster" + } + ] + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-interface-distributed/007", + "query": "\n query {\n node(id: \"oven1\") {\n ... on Oven {\n warranty\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "node": null + }, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "union-interface-distributed/008", + "query": "\n query {\n node(id: \"oven1\") {\n ... on Toaster {\n warranty\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "node": null + }, + "hasExpectedErrors": true, + "expectsErrors": true + }, + { + "id": "union-interface-distributed/009", + "query": "\n query {\n node(id: \"toaster1\") {\n ... on Toaster {\n warranty\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "node": { + "warranty": 3 + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n type Query {\n products: [Product]\n node(id: ID!): Node\n nodes: [Node]\n toasters: [Toaster]\n }\n\n union Product = Oven | Toaster\n\n interface Node {\n id: ID!\n }\n\n interface WithWarranty {\n warranty: Int\n }\n\n type Oven @key(fields: \"id\") {\n id: ID!\n }\n\n type Toaster implements Node & WithWarranty @key(fields: \"id\") {\n id: ID!\n warranty: Int\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@shareable\", \"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n products: [Product]\n node(id: ID!): Node\n nodes: [Node]\n toasters: [Toaster]\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nunion Product = Oven | Toaster\n\ninterface Node {\n id: ID!\n}\n\ninterface WithWarranty {\n warranty: Int\n}\n\ntype Oven\n @key(fields: \"id\")\n{\n id: ID!\n}\n\ntype Toaster implements Node & WithWarranty\n @key(fields: \"id\")\n{\n id: ID!\n warranty: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Oven | Toaster" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n interface Node {\n id: ID!\n }\n\n interface WithWarranty {\n warranty: Int\n }\n\n type Oven implements Node & WithWarranty @key(fields: \"id\") {\n id: ID!\n warranty: Int\n }\n ", + "serviceSdl": "extend schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @federation__shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ninterface Node {\n id: ID!\n}\n\ninterface WithWarranty {\n warranty: Int\n}\n\ntype Oven implements Node & WithWarranty\n @key(fields: \"id\")\n{\n id: ID!\n warranty: Int\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Oven\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "3a83aacad3180addc2eb46313b276a5917bb078436cf1ef22552ed8aa8b995a5", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n type Query {\n products: [Product]\n node(id: ID!): Node\n nodes: [Node]\n toasters: [Toaster]\n }\n\n union Product = Oven | Toaster\n\n interface Node {\n id: ID!\n }\n\n interface WithWarranty {\n warranty: Int\n }\n\n type Oven @key(fields: \"id\") {\n id: ID!\n }\n\n type Toaster implements Node & WithWarranty @key(fields: \"id\") {\n id: ID!\n warranty: Int\n }\n `,\n resolvers: {\n Query: {\n products() {\n return products.map((product) => {\n if (product.__typename === \"Oven\") {\n return {\n __typename: \"Oven\",\n id: product.id,\n };\n } else {\n return {\n __typename: \"Toaster\",\n id: product.id,\n warranty: product.warranty,\n };\n }\n });\n },\n node(_: {}, { id }: { id: string }) {\n const product = products.find((p) => p.id === id);\n\n if (product?.__typename === \"Oven\") {\n return {\n __typename: \"Oven\",\n id: product.id,\n };\n } else if (product?.__typename === \"Toaster\") {\n return {\n __typename: \"Toaster\",\n id: product.id,\n warranty: product.warranty,\n };\n }\n\n return null;\n },\n toasters() {\n return products\n .filter((product) => product.__typename === \"Toaster\")\n .map((toaster) => ({\n __typename: \"Toaster\",\n id: toaster.id,\n warranty: toaster.warranty,\n }));\n },\n nodes() {\n return products\n .filter((product) => product.__typename === \"Toaster\")\n .map((toaster) => ({\n __typename: \"Toaster\",\n id: toaster.id,\n warranty: toaster.warranty,\n }));\n },\n },\n Oven: {\n __resolveReference(key: { id: string }) {\n const oven = products.find((p) => p.id === key.id);\n\n if (oven?.__typename === \"Oven\") {\n return {\n __typename: \"Oven\",\n id: oven.id,\n };\n }\n\n return null;\n },\n warranty() {\n throw new Error(\"Never\");\n },\n },\n Toaster: {\n __resolveReference(key: { id: string }) {\n const toaster = products.find((p) => p.id === key.id);\n\n if (toaster?.__typename === \"Toaster\") {\n return {\n __typename: \"Toaster\",\n id: toaster.id,\n warranty: toaster.warranty,\n };\n }\n\n return null;\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "70d8694a65aa0951e0031c86b1c95de4c2ba698f51251e07d405b5f573114fd2", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { products } from \"./data.js\";\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\"])\n\n interface Node {\n id: ID!\n }\n\n interface WithWarranty {\n warranty: Int\n }\n\n type Oven implements Node & WithWarranty @key(fields: \"id\") {\n id: ID!\n warranty: Int\n }\n `,\n resolvers: {\n Oven: {\n __resolveReference(key: { id: string }) {\n const oven = products.find((p) => p.id === key.id);\n\n if (oven?.__typename === \"Oven\") {\n return {\n __typename: \"Oven\",\n id: oven.id,\n warranty: 1,\n };\n }\n\n return null;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "e23b6d8607d893f131ed7fbadeec3ad8ce8f0c3ea7d1b536952c07d289d8edfd", + "source": "export const ovens = [\n {\n __typename: \"Oven\",\n id: \"oven1\",\n warranty: 1,\n },\n {\n __typename: \"Oven\",\n id: \"oven2\",\n warranty: 2,\n },\n];\nexport const toasters = [\n {\n __typename: \"Toaster\",\n id: \"toaster1\",\n warranty: 3,\n },\n {\n __typename: \"Toaster\",\n id: \"toaster2\",\n warranty: 4,\n },\n];\n\nexport const products = [...ovens, ...toasters];\n" + } + ] + }, + { + "id": "union-intersection", + "cases": [ + { + "id": "union-intersection/000", + "query": "\n query {\n media {\n ... on Movie {\n title\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": {} + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/001", + "query": "\n query {\n media {\n ... on Book {\n title\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": { + "title": "The Lord of the Rings" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/002", + "query": "\n query {\n media {\n ... on Book {\n title\n }\n ... on Movie {\n title\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "media": { + "title": "The Lord of the Rings" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/003", + "query": "\n query {\n viewer {\n media {\n __typename\n ... on Song {\n title\n }\n ... on Movie {\n title\n }\n ... on Book {\n title\n }\n }\n book {\n __typename\n ... on Song {\n title\n }\n ... on Movie {\n title\n }\n ... on Book {\n title\n }\n }\n song {\n __typename\n ... on Song {\n title\n }\n ... on Movie {\n title\n }\n ... on Book {\n title\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "viewer": { + "media": { + "__typename": "Book", + "title": "The Lord of the Rings" + }, + "book": { + "__typename": "Book", + "title": "The Lord of the Rings" + }, + "song": { + "__typename": "Song", + "title": "Song Title" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/004", + "query": "\n query {\n viewer {\n media {\n ... on Movie {\n title\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "viewer": { + "media": {} + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/005", + "query": "\n query {\n viewer {\n media {\n ... on Book {\n title\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "viewer": { + "media": { + "title": "The Lord of the Rings" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/006", + "query": "\n query {\n viewer {\n media {\n ... on Book {\n title\n }\n ... on Movie {\n title\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "viewer": { + "media": { + "title": "The Lord of the Rings" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/007", + "query": "\n query {\n viewer {\n media {\n __typename\n ... on Song {\n title\n }\n ... on Movie {\n title\n }\n ... on Book {\n title\n }\n }\n book {\n __typename\n ... on Song {\n title\n }\n ... on Movie {\n title\n }\n ... on Book {\n title\n }\n }\n song {\n __typename\n ... on Song {\n title\n }\n ... on Movie {\n title\n }\n ... on Book {\n title\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "viewer": { + "media": { + "__typename": "Book", + "title": "The Lord of the Rings" + }, + "book": { + "__typename": "Book", + "title": "The Lord of the Rings" + }, + "song": { + "__typename": "Song", + "title": "Song Title" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/008", + "query": "\n query {\n aMedia {\n ... on Movie {\n title\n bTitle\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "aMedia": {} + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/009", + "query": "\n query {\n aMedia {\n ... on Book {\n title\n aTitle\n bTitle\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "aMedia": { + "title": "The Lord of the Rings", + "aTitle": "A: The Lord of the Rings", + "bTitle": "B: The Lord of the Rings" + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/010", + "query": "\n query {\n viewer {\n media {\n __typename\n ... on Song {\n title\n aTitle\n }\n ... on Movie {\n title\n bTitle\n }\n ... on Book {\n title\n aTitle\n bTitle\n }\n }\n book {\n __typename\n ... on Song {\n title\n aTitle\n }\n ... on Movie {\n title\n bTitle\n }\n ... on Book {\n title\n aTitle\n bTitle\n }\n }\n song {\n __typename\n ... on Song {\n title\n aTitle\n }\n ... on Movie {\n title\n bTitle\n }\n ... on Book {\n title\n aTitle\n bTitle\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "viewer": { + "media": { + "__typename": "Book", + "title": "The Lord of the Rings", + "aTitle": "A: The Lord of the Rings", + "bTitle": "B: The Lord of the Rings" + }, + "book": { + "__typename": "Book", + "title": "The Lord of the Rings", + "aTitle": "A: The Lord of the Rings", + "bTitle": "B: The Lord of the Rings" + }, + "song": { + "__typename": "Song", + "title": "Song Title", + "aTitle": "A: Song Title" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + }, + { + "id": "union-intersection/011", + "query": "\n query {\n viewer {\n aMedia {\n ... on Movie {\n title\n bTitle\n }\n }\n bMedia {\n ... on Movie {\n title\n bTitle\n }\n }\n }\n }\n ", + "variables": null, + "hasExpectedData": true, + "expectedData": { + "viewer": { + "aMedia": {}, + "bMedia": { + "title": "A Movie Title", + "bTitle": "B Movie Title" + } + } + }, + "hasExpectedErrors": false, + "expectsErrors": null + } + ], + "sources": [ + { + "name": "a", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n union Media = Book | Song\n union ViewerMedia = Book | Song\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n aTitle: String!\n }\n\n type Song @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n aTitle: String!\n }\n\n type Query {\n media: Media @shareable\n aMedia: Media @shareable\n book: Book @shareable\n song: Media @shareable\n viewer: Viewer @shareable\n }\n\n type Viewer {\n media: ViewerMedia @shareable\n aMedia: ViewerMedia\n book: Book @shareable\n song: ViewerMedia @shareable\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@shareable\", \"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\nunion Media = Book | Song\n\nunion ViewerMedia = Book | Song\n\ntype Book\n @key(fields: \"id\")\n{\n id: ID!\n title: String! @shareable\n aTitle: String!\n}\n\ntype Song\n @key(fields: \"id\")\n{\n id: ID!\n title: String! @shareable\n aTitle: String!\n}\n\ntype Query {\n media: Media @shareable\n aMedia: Media @shareable\n book: Book @shareable\n song: Media @shareable\n viewer: Viewer @shareable\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\ntype Viewer {\n media: ViewerMedia @shareable\n aMedia: ViewerMedia\n book: Book @shareable\n song: ViewerMedia @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book | Song" + }, + { + "name": "b", + "rawSdl": "\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n type Query {\n media: Media @shareable\n bMedia: Media @shareable\n book: Media @shareable\n viewer: Viewer @shareable\n }\n\n union Media = Book | Movie\n union ViewerMedia = Book | Movie\n\n type Movie @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n bTitle: String!\n }\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n bTitle: String!\n }\n\n type Viewer {\n media: ViewerMedia @shareable\n bMedia: ViewerMedia\n book: ViewerMedia @shareable\n }\n ", + "serviceSdl": "schema\n @link(url: \"https://specs.apollo.dev/link/v1.0\")\n{\n query: Query\n}\n\nextend schema\n @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@shareable\", \"@key\"])\n\ndirective @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA\n\ndirective @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE\n\ndirective @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION\n\ndirective @federation__external(reason: String) on OBJECT | FIELD_DEFINITION\n\ndirective @federation__tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA\n\ndirective @federation__extends on OBJECT | INTERFACE\n\ndirective @shareable repeatable on OBJECT | FIELD_DEFINITION\n\ndirective @federation__inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION\n\ndirective @federation__override(from: String!) on FIELD_DEFINITION\n\ndirective @federation__composeDirective(name: String) repeatable on SCHEMA\n\ndirective @federation__interfaceObject on OBJECT\n\ntype Query {\n media: Media @shareable\n bMedia: Media @shareable\n book: Media @shareable\n viewer: Viewer @shareable\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n}\n\nunion Media = Book | Movie\n\nunion ViewerMedia = Book | Movie\n\ntype Movie\n @key(fields: \"id\")\n{\n id: ID!\n title: String! @shareable\n bTitle: String!\n}\n\ntype Book\n @key(fields: \"id\")\n{\n id: ID!\n title: String! @shareable\n bTitle: String!\n}\n\ntype Viewer {\n media: ViewerMedia @shareable\n bMedia: ViewerMedia\n book: ViewerMedia @shareable\n}\n\nenum link__Purpose {\n \"\"\"\n `SECURITY` features provide metadata necessary to securely resolve fields.\n \"\"\"\n SECURITY\n\n \"\"\"\n `EXECUTION` features provide metadata necessary for operation execution.\n \"\"\"\n EXECUTION\n}\n\nscalar link__Import\n\nscalar federation__FieldSet\n\nscalar _Any\n\ntype _Service {\n sdl: String\n}\n\nunion _Entity = Book | Movie" + } + ], + "fixtureModules": [ + { + "path": "a.subgraph.ts", + "sha256": "234e8c35f15b72a93a9443a4d1b07e2eeb69a079e74cfe68ca31de2d0f206481", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { media } from \"./data.js\";\n\nconst song = {\n __typename: \"Song\",\n id: \"s2\",\n title: \"Song Title\",\n aTitle: \"A: Song Title\",\n};\n\nexport default createSubgraph(\"a\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n union Media = Book | Song\n union ViewerMedia = Book | Song\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n aTitle: String!\n }\n\n type Song @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n aTitle: String!\n }\n\n type Query {\n media: Media @shareable\n aMedia: Media @shareable\n book: Book @shareable\n song: Media @shareable\n viewer: Viewer @shareable\n }\n\n type Viewer {\n media: ViewerMedia @shareable\n aMedia: ViewerMedia\n book: Book @shareable\n song: ViewerMedia @shareable\n }\n `,\n resolvers: {\n Query: {\n media: () => media,\n aMedia: () => media,\n book: () => media,\n song: () => song,\n viewer: () => {\n return {\n media: media,\n aMedia: media,\n book: media,\n song: song,\n };\n },\n },\n Book: {\n __resolveReference(key: { id: string }) {\n if (key.id !== media.id) {\n return null;\n }\n\n return media;\n },\n },\n Song: {\n __resolveReference(key: { id: string }) {\n if (key.id !== song.id) {\n return null;\n }\n\n return song;\n },\n },\n },\n});\n" + }, + { + "path": "b.subgraph.ts", + "sha256": "8a94a5f9763b22d2ae4710b2fb9e0af8e7906722ef4925781ddb45b5a9027975", + "source": "import { createSubgraph } from \"../../subgraph.js\";\nimport { media } from \"./data.js\";\n\nconst movie = {\n __typename: \"Movie\",\n id: \"m3\",\n title: \"A Movie Title\",\n bTitle: \"B Movie Title\",\n};\n\nexport default createSubgraph(\"b\", {\n typeDefs: /* GraphQL */ `\n extend schema\n @link(\n url: \"https://specs.apollo.dev/federation/v2.3\"\n import: [\"@shareable\", \"@key\"]\n )\n\n type Query {\n media: Media @shareable\n bMedia: Media @shareable\n book: Media @shareable\n viewer: Viewer @shareable\n }\n\n union Media = Book | Movie\n union ViewerMedia = Book | Movie\n\n type Movie @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n bTitle: String!\n }\n\n type Book @key(fields: \"id\") {\n id: ID!\n title: String! @shareable\n bTitle: String!\n }\n\n type Viewer {\n media: ViewerMedia @shareable\n bMedia: ViewerMedia\n book: ViewerMedia @shareable\n }\n `,\n resolvers: {\n Query: {\n media: () => media,\n bMedia: () => media,\n book: () => media,\n viewer: () => {\n return {\n media,\n bMedia: movie,\n book: media,\n };\n },\n },\n Book: {\n __resolveReference(key: { id: string }) {\n if (key.id !== media.id) {\n return null;\n }\n\n return media;\n },\n },\n Movie: {\n __resolveReference(key: { id: string }) {\n if (key.id !== movie.id) {\n return null;\n }\n\n return movie;\n },\n },\n },\n});\n" + }, + { + "path": "data.ts", + "sha256": "0798fa26e09168e84b90db0648dab15af607e1e3c948b870f4dcef25889c0b68", + "source": "export const media = {\n __typename: \"Book\",\n id: \"b1\",\n title: \"The Lord of the Rings\",\n aTitle: \"A: The Lord of the Rings\",\n bTitle: \"B: The Lord of the Rings\",\n};\n" + } + ] + } + ] +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/AbstractTypes/AbstractTypesTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/AbstractTypes/AbstractTypesTests.cs index 35cfd2506b4..e2e759e9583 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/AbstractTypes/AbstractTypesTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/AbstractTypes/AbstractTypesTests.cs @@ -8,6 +8,7 @@ namespace HotChocolate.Fusion.Suites; +[Trait("Category", "OfficialV1")] public sealed class AbstractTypesTests : ComplianceTestBase { protected override Task BuildGatewayAsync() diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/User.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/User.cs index bb87a53d896..0f11673cdf1 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/User.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/User.cs @@ -3,10 +3,7 @@ namespace HotChocolate.Fusion.Suites.ChildTypeMismatch.A; /// /// The User type as projected by the a subgraph. /// This subgraph does not declare @key on User; it only -/// contributes a shareable id field. The original SDL uses -/// nullable id: ID, but HotChocolate's field selection merging -/// requires matching nullability across union members, so id -/// is declared ID! here to match subgraph B's User entity. +/// contributes the nullable shareable id: ID field from the official fixture. /// public sealed class User { diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/UserType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/UserType.cs index 0a067f83674..9030c46c416 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/UserType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/A/UserType.cs @@ -12,6 +12,6 @@ public sealed class UserType : ObjectType { protected override void Configure(IObjectTypeDescriptor descriptor) { - descriptor.Field(u => u.Id).Shareable().Type>(); + descriptor.Field(u => u.Id).Shareable().Type(); } } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/Admin.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/Admin.cs index 4be17c39947..293918e588c 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/Admin.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/Admin.cs @@ -2,9 +2,7 @@ namespace HotChocolate.Fusion.Suites.ChildTypeMismatch.B; /// /// The Admin type in the b subgraph. Not an entity (no @key). -/// name is @shareable. The original SDL uses nullable id: ID, -/// but HotChocolate requires matching nullability across union members for -/// field selection merging, so id is declared ID! here. +/// name is @shareable, and id: ID is nullable. /// public sealed class Admin { diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/AdminType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/AdminType.cs index 7f5a8525ed5..10328f124c6 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/AdminType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/B/AdminType.cs @@ -12,7 +12,7 @@ public sealed class AdminType : ObjectType { protected override void Configure(IObjectTypeDescriptor descriptor) { - descriptor.Field(a => a.Id).Type>(); + descriptor.Field(a => a.Id).Type(); descriptor.Field(a => a.Name).Shareable().Type(); descriptor diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/ChildTypeMismatchTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/ChildTypeMismatchTests.cs index 232dc593c2f..893cb10d83f 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/ChildTypeMismatchTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ChildTypeMismatch/ChildTypeMismatchTests.cs @@ -3,425 +3,18 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the child-type-mismatch suite from -/// graphql-hive/federation-gateway-audit. The gateway composes -/// subgraph a (which exposes User { id @shareable } without -/// a key) and subgraph b (which owns User @key(fields: "id"), -/// Admin, and the union Account = User | Admin). Tests verify -/// that union types and nested similarAccounts resolve correctly -/// across subgraphs. -/// -public sealed class ChildTypeMismatchTests : ComplianceTestBase +[OfficialV2Suite("child-type-mismatch")] +public sealed class ChildTypeMismatchTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (ASubgraph.Name, ASubgraph.BuildAsync), (BSubgraph.Name, BSubgraph.BuildAsync)); - [Fact] - public Task Users_And_Accounts_Resolve_Across_Subgraphs() => RunAsync( - query: """ - { - users { - id - name - } - accounts { - ... on User { - id - name - } - ... on Admin { - id - name - } - } - } - """, - expectedData: """ - { - "users": [ - { - "id": "u1", - "name": "u1-name" - } - ], - "accounts": [ - { - "id": "u1", - "name": "u1-name" - }, - { - "id": "a1", - "name": "a1-name" - } - ] - } - """); - - [Fact] - public Task NestedInternalAlias_SimilarAccounts_Resolve() => RunAsync( - query: """ - query NestedInternalAlias { - users { - id - name - } - accounts { - ... on User { - id - name - similarAccounts { - ... on User { - id - name - } - ... on Admin { - id - name - } - } - } - ... on Admin { - id - name - similarAccounts { - ... on User { - id - name - } - ... on Admin { - id - name - } - } - } - } - } - """, - expectedData: """ - { - "users": [ - { - "id": "u1", - "name": "u1-name" - } - ], - "accounts": [ - { - "id": "u1", - "name": "u1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name" - }, - { - "id": "a1", - "name": "a1-name" - } - ] - }, - { - "id": "a1", - "name": "a1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name" - }, - { - "id": "a1", - "name": "a1-name" - } - ] - } - ] - } - """); - - [Fact] - public Task DeeplyNestedInternalAlias_ThreeLevels_Resolve() => RunAsync( - query: """ - query DeeplyNestedInternalAlias { - users { - id - name - } - accounts { - ... on User { - id - name - similarAccounts { - ... on User { - id - name - similarAccounts { - ... on User { - id - name - } - ... on Admin { - id - name - } - } - } - ... on Admin { - id - name - similarAccounts { - ... on User { - id - name - } - ... on Admin { - id - name - } - } - } - } - } - ... on Admin { - id - name - similarAccounts { - ... on User { - id - name - similarAccounts { - ... on User { - id - name - } - ... on Admin { - id - name - } - } - } - ... on Admin { - id - name - similarAccounts { - ... on User { - id - name - } - ... on Admin { - id - name - } - } - } - } - } - } - } - """, - expectedData: """ - { - "users": [ - { - "id": "u1", - "name": "u1-name" - } - ], - "accounts": [ - { - "id": "u1", - "name": "u1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name" - }, - { - "id": "a1", - "name": "a1-name" - } - ] - }, - { - "id": "a1", - "name": "a1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name" - }, - { - "id": "a1", - "name": "a1-name" - } - ] - } - ] - }, - { - "id": "a1", - "name": "a1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name" - }, - { - "id": "a1", - "name": "a1-name" - } - ] - }, - { - "id": "a1", - "name": "a1-name", - "similarAccounts": [ - { - "id": "u1", - "name": "u1-name" - }, - { - "id": "a1", - "name": "a1-name" - } - ] - } - ] - } - ] - } - """); - - [Fact] - public Task DeeplyNested_NamesOnly_ThreeLevels_Resolve() => RunAsync( - query: """ - query DeeplyNested { - accounts { - ... on User { - name - similarAccounts { - ... on User { - name - similarAccounts { - ... on User { - name - } - ... on Admin { - name - } - } - } - ... on Admin { - name - similarAccounts { - ... on User { - name - } - ... on Admin { - name - } - } - } - } - } - ... on Admin { - name - similarAccounts { - ... on User { - name - similarAccounts { - ... on User { - name - } - ... on Admin { - name - } - } - } - ... on Admin { - name - similarAccounts { - ... on User { - name - } - ... on Admin { - name - } - } - } - } - } - } - } - """, - expectedData: """ - { - "accounts": [ - { - "name": "u1-name", - "similarAccounts": [ - { - "name": "u1-name", - "similarAccounts": [ - { - "name": "u1-name" - }, - { - "name": "a1-name" - } - ] - }, - { - "name": "a1-name", - "similarAccounts": [ - { - "name": "u1-name" - }, - { - "name": "a1-name" - } - ] - } - ] - }, - { - "name": "a1-name", - "similarAccounts": [ - { - "name": "u1-name", - "similarAccounts": [ - { - "name": "u1-name" - }, - { - "name": "a1-name" - } - ] - }, - { - "name": "a1-name", - "similarAccounts": [ - { - "name": "u1-name" - }, - { - "name": "a1-name" - } - ] - } - ] - } - ] - } - """); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/A/BookType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/A/BookType.cs index 27686965ad1..c15893af5e6 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/A/BookType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/A/BookType.cs @@ -9,8 +9,7 @@ protected override void Configure(IObjectTypeDescriptor descriptor) { descriptor .Implements() - .Key("id") - .ResolveReferenceWith(_ => ResolveById(default!)); + .Key("id"); descriptor.Field(b => b.Id).Type>(); descriptor.Field(b => b.Price).External().Type(); @@ -28,7 +27,4 @@ protected override void Configure(IObjectTypeDescriptor descriptor) && !string.Equals(b.Id, book.Id, StringComparison.Ordinal)); }); } - - private static Book? ResolveById(string id) - => AData.BooksById.TryGetValue(id, out var book) ? book : null; } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/CircularReferenceInterfaceTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/CircularReferenceInterfaceTests.cs index 0c3f69ee04f..7384f988c96 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/CircularReferenceInterfaceTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CircularReferenceInterface/CircularReferenceInterfaceTests.cs @@ -3,86 +3,18 @@ namespace HotChocolate.Fusion.Suites; -public sealed class CircularReferenceInterfaceTests : ComplianceTestBase +[OfficialV2Suite("circular-reference-interface")] +public sealed class CircularReferenceInterfaceTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (ASubgraph.Name, ASubgraph.BuildAsync), (BSubgraph.Name, BSubgraph.BuildAsync)); - [Fact] - public Task Product_Should_ReturnNestedTypename_When_CircularSamePriceProduct() => RunAsync( - query: """ - query { - product { - samePriceProduct { - ... on Product { - samePriceProduct { - __typename - } - } - } - } - } - """, - expectedData: """ - { - "product": { - "samePriceProduct": { - "samePriceProduct": { - "__typename": "Book" - } - } - } - } - """); - - [Fact] - public Task Product_Should_ReturnFullNested_When_CircularWithIdAndPrice() => RunAsync( - query: """ - query { - product { - __typename - samePriceProduct { - __typename - ... on Book { - id - } - samePriceProduct { - __typename - ... on Book { - id - } - } - } - ... on Book { - __typename - id - price - samePriceProduct { - id - price - } - } - } - } - """, - expectedData: """ - { - "product": { - "__typename": "Book", - "samePriceProduct": { - "__typename": "Book", - "id": "3", - "samePriceProduct": { - "__typename": "Book", - "id": "1" - }, - "price": 10.99 - }, - "id": "1", - "price": 10.99 - } - } - """); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/ComplexEntityCallTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/ComplexEntityCallTests.cs index 3c471db003e..fd493c28a0c 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/ComplexEntityCallTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/ComplexEntityCallTests.cs @@ -5,132 +5,20 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the complex-entity-call suite from -/// graphql-hive/federation-gateway-audit. The gateway composes four -/// Apollo Federation subgraphs (link, list, price, -/// products) that share the Product / ProductList / -/// Category entities via several nested-path @key directives, -/// including the list-typed products { id pid } and the deeply nested -/// products { id pid category { id tag } } selected { id }. -/// -public sealed class ComplexEntityCallTests : ComplianceTestBase +[OfficialV2Suite("complex-entity-call")] +public sealed class ComplexEntityCallTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (LinkSubgraph.Name, LinkSubgraph.BuildAsync), (ListSubgraph.Name, ListSubgraph.BuildAsync), (PriceSubgraph.Name, PriceSubgraph.BuildAsync), (ProductsSubgraph.Name, ProductsSubgraph.BuildAsync)); - /// - /// Verifies the four-subgraph composition accepts the nested and nested-list - /// @key directives from the audit fixtures and that a query - /// traversing the nested-object Category @key("id tag") pattern and - /// the mainProduct cycle back through Product resolves - /// correctly. - /// - [Fact] - public Task TopProducts_ResolvesNestedCategoryKey() => RunAsync( - query: """ - query { - topProducts { - products { - id - category { - mainProduct { id } - id - tag - } - } - } - } - """, - expectedData: """ - { - "topProducts": { - "products": [ - { - "id": "1", - "category": { - "mainProduct": { "id": "1" }, - "id": "c1", - "tag": "t1" - } - }, - { - "id": "2", - "category": { - "mainProduct": { "id": "2" }, - "id": "c2", - "tag": "t2" - } - } - ] - } - } - """); - - /// - /// The full audit query. Exercises the nested-list - /// ProductList @key("products { id pid }") and deeply nested - /// ProductList @key("products { id pid category { id tag } } selected { id }") - /// routing through the Fusion planner to populate first, - /// selected, pid, and price in a single query. - /// - /// - /// Pins that the planner wires each nested-list @key lookup onto the hop - /// that produces its buried key leaf (pid inside products), so - /// selected, first, pid, and price all resolve. - /// - [Fact] - public Task TopProducts_Projects_Across_All_Subgraphs() => RunAsync( - query: """ - query { - topProducts { - products { - id - pid - price { price } - category { - mainProduct { id } - id - tag - } - } - selected { id } - first { id } - } - } - """, - expectedData: """ - { - "topProducts": { - "products": [ - { - "id": "1", - "pid": "p1", - "price": { "price": 100 }, - "category": { - "mainProduct": { "id": "1" }, - "id": "c1", - "tag": "t1" - } - }, - { - "id": "2", - "pid": "p2", - "price": { "price": 200 }, - "category": { - "mainProduct": { "id": "2" }, - "id": "c2", - "tag": "t2" - } - } - ], - "selected": { "id": "2" }, - "first": { "id": "1" } - } - } - """); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/Products/ProductType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/Products/ProductType.cs index 742fe6a94d8..23fef0d5643 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/Products/ProductType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/ComplexEntityCall/Products/ProductType.cs @@ -18,13 +18,8 @@ protected override void Configure(IObjectTypeDescriptor descriptor) .Key("id") .ResolveReferenceWith(_ => ResolveById(default!)); - // Apollo Federation would mark this as '@external' (the field is - // owned by the link/list/price subgraphs). In the Fusion composite - // schema we model the same intent with '@shareable': the field - // travels with Product instances returned from this subgraph's root - // queries so the planner can use it as the entity-routing key. descriptor.Field(p => p.Id) - .Shareable() + .External() .Type>(); descriptor.Field("category") diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/Account.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/Account.cs index 02d3021d0b6..aa1017b64a9 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/Account.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/Account.cs @@ -8,4 +8,6 @@ namespace HotChocolate.Fusion.Suites.CorruptedSupergraphNodeId.B; public sealed class Account : INode { public string Id { get; init; } = default!; + + public IReadOnlyList ChatIds { get; init; } = []; } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/AccountType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/AccountType.cs index 85c24737643..7bc15e10b09 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/AccountType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/AccountType.cs @@ -26,9 +26,11 @@ protected override void Configure(IObjectTypeDescriptor descriptor) { var account = ctx.Parent(); return SubgraphBData.Chats - .Where(c => c.AccountId == account.Id) + .Where(c => account.ChatIds.Contains(c.Id)) .ToList(); }); + + descriptor.Field(a => a.ChatIds).Ignore(); } private static Account? ResolveById(string id) diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/QueryType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/QueryType.cs index 3b7b0607a44..499c1761a2a 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/QueryType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/QueryType.cs @@ -23,11 +23,11 @@ protected override void Configure(IObjectTypeDescriptor descriptor) { var id = ctx.ArgumentValue("id"); - if (SubgraphBData.AccountsById.TryGetValue(id, out _)) + if (SubgraphBData.AccountsById.TryGetValue(id, out var account)) { // Intentionally corrupted: Account.id is @external in // this subgraph, so we return "never" as the id. - return (INode)new Account { Id = "never" }; + return (INode)new Account { Id = "never", ChatIds = account.ChatIds }; } if (SubgraphBData.ChatsById.TryGetValue(id, out var chat)) diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/SubgraphBData.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/SubgraphBData.cs index 770a96585c6..75b4dca12b2 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/SubgraphBData.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/B/SubgraphBData.cs @@ -5,14 +5,6 @@ namespace HotChocolate.Fusion.Suites.CorruptedSupergraphNodeId.B; /// internal static class SubgraphBData { - public static readonly IReadOnlyList Accounts = - [ - new Account { Id = "a1" } - ]; - - public static readonly IReadOnlyDictionary AccountsById = - Accounts.ToDictionary(static a => a.Id, StringComparer.Ordinal); - public static readonly IReadOnlyList Chats = [ new Chat { Id = "c1", AccountId = "a1", Text = "c1-text" } @@ -20,4 +12,12 @@ internal static class SubgraphBData public static readonly IReadOnlyDictionary ChatsById = Chats.ToDictionary(static c => c.Id, StringComparer.Ordinal); + + public static readonly IReadOnlyList Accounts = + [ + new Account { Id = "a1", ChatIds = ["c1"] } + ]; + + public static readonly IReadOnlyDictionary AccountsById = + Accounts.ToDictionary(static a => a.Id, StringComparer.Ordinal); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/CorruptedSupergraphNodeIdTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/CorruptedSupergraphNodeIdTests.cs index 258b6177860..86ee4d347c5 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/CorruptedSupergraphNodeIdTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/CorruptedSupergraphNodeId/CorruptedSupergraphNodeIdTests.cs @@ -4,243 +4,18 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the corrupted-supergraph-node-id suite from -/// graphql-hive/federation-gateway-audit. Two subgraphs (a, b) -/// each expose node(id: ID!): Node @shareable but intentionally return -/// corrupted (wrong) IDs for the entity types they do not own. The tests verify -/// that the gateway handles these corrupted IDs correctly. -/// -public sealed class CorruptedSupergraphNodeIdTests : ComplianceTestBase +[OfficialV2Suite("corrupted-supergraph-node-id", NodeResolution = NodeResolution.SourceSchema)] +public sealed class CorruptedSupergraphNodeIdTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( - NodeResolution.SourceSchema, + => ComposeOfficialV2Async( (SubgraphASubgraph.Name, SubgraphASubgraph.BuildAsync), (SubgraphBSubgraph.Name, SubgraphBSubgraph.BuildAsync)); - [Fact] - public Task Node_Account_Id_Only() => RunAsync( - query: """ - { - node(id: "a1") { - id - } - } - """, - expectedData: "null", - expectsErrors: true); - - [Fact] - public Task Node_Account_And_Chat_Typename() => RunAsync( - query: """ - { - account: node(id: "a1") { - __typename - } - chat: node(id: "c1") { - __typename - } - } - """, - expectedData: """ - { - "account": { - "__typename": "Account" - }, - "chat": { - "__typename": "Chat" - } - } - """); - - [Fact] - public Task Node_Account_And_Chat_Full_Fragments() => RunAsync( - query: """ - { - account: node(id: "a1") { - ... on Account { - id - username - } - } - chat: node(id: "c1") { - ... on Chat { - id - text - } - } - } - """, - expectedData: """ - { - "account": { - "id": "a1", - "username": "a1-username" - }, - "chat": { - "id": "c1", - "text": "c1-text" - } - } - """); - - [Fact] - public Task Node_Account_As_Chat_And_Chat_As_Account() => RunAsync( - query: """ - { - account: node(id: "a1") { - ... on Chat { - id - } - } - chat: node(id: "c1") { - ... on Account { - id - } - } - } - """, - expectedData: """ - { - "account": {}, - "chat": {} - } - """); - - [Fact] - public Task Node_Mismatched_Fragments_With_Typename() => RunAsync( - query: """ - { - account: node(id: "a1") { - __typename - ... on Chat { - id - } - } - chat: node(id: "c1") { - __typename - ... on Account { - id - } - } - } - """, - expectedData: """ - { - "account": { - "__typename": "Account" - }, - "chat": { - "__typename": "Chat" - } - } - """); - - [Fact] - public Task Node_Account_Id_With_Mismatched_Chat_Fragment() => RunAsync( - query: """ - { - account: node(id: "a1") { - id - ... on Chat { - id - } - } - chat: node(id: "c1") { - __typename - ... on Account { - id - } - } - } - """, - expectedData: "null", - expectsErrors: true); - - [Fact] - public Task Chat_By_Id() => RunAsync( - query: """ - { - chat(id: "c1") { - id - } - } - """, - expectedData: """ - { - "chat": { - "id": "c1" - } - } - """); - - [Fact] - public Task Account_By_Id() => RunAsync( - query: """ - { - account(id: "a1") { - id - } - } - """, - expectedData: """ - { - "account": { - "id": "a1" - } - } - """); - - [Fact] - public Task Chat_With_Account() => RunAsync( - query: """ - { - chat(id: "c1") { - id - text - account { - id - } - } - } - """, - expectedData: """ - { - "chat": { - "id": "c1", - "text": "c1-text", - "account": { - "id": "a1" - } - } - } - """); - - [Fact] - public Task Account_With_Chats() => RunAsync( - query: """ - { - account(id: "a1") { - id - username - chats { - id - } - } - } - """, - expectedData: """ - { - "account": { - "id": "a1", - "username": "a1-username", - "chats": [ - { - "id": "c1" - } - ] - } - } - """); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/EnumIntersection/EnumIntersectionTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/EnumIntersection/EnumIntersectionTests.cs index a7e5dbd20a7..2f5c48fc63c 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/EnumIntersection/EnumIntersectionTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/EnumIntersection/EnumIntersectionTests.cs @@ -3,114 +3,18 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the enum-intersection suite from -/// graphql-hive/federation-gateway-audit. Two Apollo Federation -/// subgraphs declare overlapping enum values: subgraph a only -/// declares REGULAR; subgraph b declares both -/// ANONYMOUS @inaccessible and REGULAR. The supergraph -/// must intersect to REGULAR only. -/// -public sealed class EnumIntersectionTests : ComplianceTestBase +[OfficialV2Suite("enum-intersection")] +public sealed class EnumIntersectionTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (ASubgraph.Name, ASubgraph.BuildAsync), (BSubgraph.Name, BSubgraph.BuildAsync)); - /// - /// Plain id selection. The planner picks one subgraph and returns - /// both users. - /// - [Fact] - public Task Users_Returns_Ids_Only() => RunAsync( - query: """ - query { - users { id } - } - """, - expectedData: """ - { - "users": [ - { "id": "u1" }, - { "id": "u2" } - ] - } - """); - - /// - /// Walking type from subgraph a's Query.users - /// surfaces null for u2 because subgraph a - /// cannot project the ANONYMOUS value. - /// - [Fact] - public Task Users_Type_Returns_Null_For_Subgraph_A_Side() => RunAsync( - query: """ - query { - users { id type } - } - """, - expectedData: """ - { - "users": [ - { "id": "u1", "type": "REGULAR" }, - { "id": "u2", "type": null } - ] - } - """, - expectsErrors: true); - - /// - /// Walking type from subgraph b's Query.usersB - /// surfaces null for u2 because ANONYMOUS is - /// inaccessible in the supergraph. - /// - [Fact] - public Task UsersB_Type_Returns_Null_For_Inaccessible_Value() => RunAsync( - query: """ - query { - usersB { id type } - } - """, - expectedData: """ - { - "usersB": [ - { "id": "u1", "type": "REGULAR" }, - { "id": "u2", "type": null } - ] - } - """); - - /// - /// Filtering by the public REGULAR value works. - /// - [Fact] - public Task UsersByType_Regular_Returns_Single_User() => RunAsync( - query: """ - query { - usersByType(type: REGULAR) { id type } - } - """, - expectedData: """ - { - "usersByType": [ - { "id": "u1", "type": "REGULAR" } - ] - } - """); - - /// - /// Filtering by the inaccessible ANONYMOUS value must be - /// rejected by validation. The data payload is null and the - /// response carries errors. - /// - [Fact] - public Task UsersByType_Anonymous_Is_Rejected() => RunAsync( - query: """ - query { - usersByType(type: ANONYMOUS) { id type } - } - """, - expectedData: "null", - expectsErrors: true); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtends/Fed1ExternalExtendsTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtends/Fed1ExternalExtendsTests.cs index 21b653eff95..de201f80969 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtends/Fed1ExternalExtendsTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtends/Fed1ExternalExtendsTests.cs @@ -15,6 +15,7 @@ namespace HotChocolate.Fusion.Suites; /// @provides(fields: "name") ship name alongside the /// reference so no entity call to b is needed. /// +[Trait("Category", "OfficialV1")] public sealed class Fed1ExternalExtendsTests : ComplianceTestBase { protected override Task BuildGatewayAsync() diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtendsResolvable/Fed1ExternalExtendsResolvableTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtendsResolvable/Fed1ExternalExtendsResolvableTests.cs index f4824e9ce16..ed5fcf56212 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtendsResolvable/Fed1ExternalExtendsResolvableTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtendsResolvable/Fed1ExternalExtendsResolvableTests.cs @@ -11,6 +11,7 @@ namespace HotChocolate.Fusion.Suites; /// extends it (@extends) with a resolvable price field keyed by /// the external id name and upc routing fields. /// +[Trait("Category", "OfficialV1")] public sealed class Fed1ExternalExtendsResolvableTests : ComplianceTestBase { protected override Task BuildGatewayAsync() diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtension/Fed1ExternalExtensionTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtension/Fed1ExternalExtensionTests.cs index 10c60b995d3..3c342fdd878 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtension/Fed1ExternalExtensionTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed1ExternalExtension/Fed1ExternalExtensionTests.cs @@ -15,6 +15,7 @@ namespace HotChocolate.Fusion.Suites; /// @provides(fields: "name") ship name alongside the /// reference so no entity call to b is needed. /// +[Trait("Category", "OfficialV1")] public sealed class Fed1ExternalExtensionTests : ComplianceTestBase { protected override Task BuildGatewayAsync() diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtends/Fed2ExternalExtendsTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtends/Fed2ExternalExtendsTests.cs index 28b19e8571a..9cb912c73d1 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtends/Fed2ExternalExtendsTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtends/Fed2ExternalExtendsTests.cs @@ -3,132 +3,18 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the fed2-external-extends suite from -/// graphql-hive/federation-gateway-audit. Two Apollo Federation -/// subgraphs share the User entity. Subgraph a uses the -/// Federation v1 style @extends directive together with -/// @external markers to project only its own field rid; -/// subgraph b owns the rest of the entity. The audit verifies that -/// the gateway can route the external name field to b, and -/// that subgraph a's providedRandomUser field lets -/// @provides(fields: "name") ship name alongside the -/// reference so no entity call to b is needed. -/// -public sealed class Fed2ExternalExtendsTests : ComplianceTestBase +[OfficialV2Suite("fed2-external-extends")] +public sealed class Fed2ExternalExtendsTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (ASubgraph.Name, ASubgraph.BuildAsync), (BSubgraph.Name, BSubgraph.BuildAsync)); - /// - /// Combined query: randomUser from subgraph a needs the - /// external name from b via the entity lookup; - /// userById resolves entirely in b. - /// - [Fact] - public Task RandomUser_And_UserById_Resolve_Across_Subgraphs() => RunAsync( - query: """ - query { - randomUser { - id - name - } - userById(id: "u2") { - id - name - nickname - } - } - """, - expectedData: """ - { - "randomUser": { - "id": "u1", - "name": "u1-name" - }, - "userById": { - "id": "u2", - "name": "u2-name", - "nickname": "u2-nickname" - } - } - """); - - /// - /// randomUser with id and rid only stays inside - /// subgraph a. - /// - [Fact] - public Task RandomUser_Returns_Local_Rid_Without_Entity_Call() => RunAsync( - query: """ - query { - randomUser { - id - rid - } - } - """, - expectedData: """ - { - "randomUser": { - "id": "u1", - "rid": "u1-rid" - } - } - """); - - /// - /// randomUser with the external name selection forces - /// the gateway to issue an entity call to subgraph b for - /// name, then merge with rid from subgraph a. - /// - [Fact] - public Task RandomUser_Resolves_External_Name_Via_Entity_Call() => RunAsync( - query: """ - query { - randomUser { - id - rid - name - } - } - """, - expectedData: """ - { - "randomUser": { - "id": "u1", - "rid": "u1-rid", - "name": "u1-name" - } - } - """); - - /// - /// providedRandomUser uses - /// @provides(fields: "name") so the gateway should accept the - /// name shipped from subgraph a and skip the entity - /// call to subgraph b. - /// - [Fact] - public Task ProvidedRandomUser_Uses_Local_Name_Via_Provides() => RunAsync( - query: """ - query { - providedRandomUser { - id - rid - name - } - } - """, - expectedData: """ - { - "providedRandomUser": { - "id": "u1", - "rid": "u1-rid", - "name": "u1-name" - } - } - """); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtension/Fed2ExternalExtensionTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtension/Fed2ExternalExtensionTests.cs index 796a1e2e7df..66a002af1ad 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtension/Fed2ExternalExtensionTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/Fed2ExternalExtension/Fed2ExternalExtensionTests.cs @@ -3,132 +3,18 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the fed2-external-extension suite from -/// graphql-hive/federation-gateway-audit. Two Apollo Federation -/// subgraphs share the User entity. Subgraph a uses the -/// Federation v2 extend type User @key(...) form together with -/// @external markers to project only its own field rid; -/// subgraph b owns the rest of the entity. The audit verifies that -/// the gateway can route the external name field to b, and -/// that subgraph a's providedRandomUser field lets -/// @provides(fields: "name") ship name alongside the -/// reference so no entity call to b is needed. -/// -public sealed class Fed2ExternalExtensionTests : ComplianceTestBase +[OfficialV2Suite("fed2-external-extension")] +public sealed class Fed2ExternalExtensionTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (ASubgraph.Name, ASubgraph.BuildAsync), (BSubgraph.Name, BSubgraph.BuildAsync)); - /// - /// Combined query: randomUser from subgraph a needs the - /// external name from b via the entity lookup; - /// userById resolves entirely in b. - /// - [Fact] - public Task RandomUser_And_UserById_Resolve_Across_Subgraphs() => RunAsync( - query: """ - query { - randomUser { - id - name - } - userById(id: "u2") { - id - name - nickname - } - } - """, - expectedData: """ - { - "randomUser": { - "id": "u1", - "name": "u1-name" - }, - "userById": { - "id": "u2", - "name": "u2-name", - "nickname": "u2-nickname" - } - } - """); - - /// - /// randomUser with id and rid only stays inside - /// subgraph a. - /// - [Fact] - public Task RandomUser_Returns_Local_Rid_Without_Entity_Call() => RunAsync( - query: """ - query { - randomUser { - id - rid - } - } - """, - expectedData: """ - { - "randomUser": { - "id": "u1", - "rid": "u1-rid" - } - } - """); - - /// - /// randomUser with the external name selection forces - /// the gateway to issue an entity call to subgraph b for - /// name, then merge with rid from subgraph a. - /// - [Fact] - public Task RandomUser_Resolves_External_Name_Via_Entity_Call() => RunAsync( - query: """ - query { - randomUser { - id - rid - name - } - } - """, - expectedData: """ - { - "randomUser": { - "id": "u1", - "rid": "u1-rid", - "name": "u1-name" - } - } - """); - - /// - /// providedRandomUser uses - /// @provides(fields: "name") so the gateway should accept the - /// name shipped from subgraph a and skip the entity - /// call to subgraph b. - /// - [Fact] - public Task ProvidedRandomUser_Uses_Local_Name_Via_Provides() => RunAsync( - query: """ - query { - providedRandomUser { - id - rid - name - } - } - """, - expectedData: """ - { - "providedRandomUser": { - "id": "u1", - "rid": "u1-rid", - "name": "u1-name" - } - } - """); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/B/ProductType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/B/ProductType.cs index 99c53a02b8d..996598ac47c 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/B/ProductType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/B/ProductType.cs @@ -34,5 +34,6 @@ protected override void Configure(IObjectTypeDescriptor descriptor) }); } - private static Product ResolveById(string id) => new() { Id = id }; + private static Product? ResolveById(string id) + => A.AData.ById.ContainsKey(id) ? new Product { Id = id } : null; } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/C/ProductType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/C/ProductType.cs index 0528ecfa292..b41d5205489 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/C/ProductType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/C/ProductType.cs @@ -63,5 +63,6 @@ protected override void Configure(IObjectTypeDescriptor descriptor) "neverCalledSkip should not be called.")); } - private static Product ResolveById(string id) => new() { Id = id }; + private static Product? ResolveById(string id) + => A.AData.ById.ContainsKey(id) ? new Product { Id = id } : null; } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/IncludeSkipTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/IncludeSkipTests.cs index 34ae229f399..e3219db52dc 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/IncludeSkipTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/IncludeSkip/IncludeSkipTests.cs @@ -4,102 +4,19 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the include-skip suite from -/// graphql-hive/federation-gateway-audit. Three Apollo Federation -/// subgraphs share the Product entity. The audit verifies that -/// @include and @skip short-circuit downstream resolvers -/// (the neverCalledInclude and neverCalledSkip resolvers -/// throw if invoked) and that toggled fields still receive their -/// @requires dependencies. -/// -public sealed class IncludeSkipTests : ComplianceTestBase +[OfficialV2Suite("include-skip")] +public sealed class IncludeSkipTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (ASubgraph.Name, ASubgraph.BuildAsync), (BSubgraph.Name, BSubgraph.BuildAsync), (CSubgraph.Name, CSubgraph.BuildAsync)); - /// - /// @include(if: false) should keep the planner from invoking - /// the neverCalledInclude resolver. - /// - [Fact] - public Task NeverCalledInclude_Is_Skipped_When_Include_False() => RunAsync( - query: """ - query ($bool: Boolean = false) { - product { - price - neverCalledInclude @include(if: $bool) - } - } - """, - expectedData: """ - { - "product": { "price": 699.99 } - } - """); - - /// - /// @skip(if: true) should keep the planner from invoking - /// the neverCalledSkip resolver. - /// - [Fact] - public Task NeverCalledSkip_Is_Skipped_When_Skip_True() => RunAsync( - query: """ - query ($bool: Boolean = true) { - product { - price - neverCalledSkip @skip(if: $bool) - } - } - """, - expectedData: """ - { - "product": { "price": 699.99 } - } - """); - - /// - /// @include(if: true) keeps the field active. The chained - /// @requires path must still deliver isExpensive to - /// c's include resolver. - /// - [Fact] - public Task Include_Resolves_Through_Requires_Chain() => RunAsync( - query: """ - query ($bool: Boolean = true) { - product { - price - include @include(if: $bool) - } - } - """, - expectedData: """ - { - "product": { "price": 699.99, "include": true } - } - """); - - /// - /// @skip(if: false) keeps the field active. The chained - /// @requires path must still deliver isExpensive to - /// c's skip resolver. - /// - [Fact] - public Task Skip_Resolves_Through_Requires_Chain() => RunAsync( - query: """ - query ($bool: Boolean = false) { - product { - price - skip @skip(if: $bool) - } - } - """, - expectedData: """ - { - "product": { "price": 699.99, "skip": true } - } - """); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InputObjectIntersection/InputObjectIntersectionTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InputObjectIntersection/InputObjectIntersectionTests.cs index 072702bfcd2..bc3b8527da7 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InputObjectIntersection/InputObjectIntersectionTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InputObjectIntersection/InputObjectIntersectionTests.cs @@ -3,64 +3,18 @@ namespace HotChocolate.Fusion.Suites; -/// -/// Port of the input-object-intersection suite from -/// graphql-hive/federation-gateway-audit. Two Apollo Federation -/// subgraphs each declare a UsersFilter input object with a -/// different field set; the supergraph must expose only the -/// intersection (first only). -/// -public sealed class InputObjectIntersectionTests : ComplianceTestBase +[OfficialV2Suite("input-object-intersection")] +public sealed class InputObjectIntersectionTests + : OfficialV2ComplianceTestBase { protected override Task BuildGatewayAsync() - => FusionGatewayBuilder.ComposeAsync( + => ComposeOfficialV2Async( (ASubgraph.Name, ASubgraph.BuildAsync), (BSubgraph.Name, BSubgraph.BuildAsync)); - /// - /// The first field is in the intersection so the query - /// succeeds. - /// - [Fact] - public Task UsersInA_With_First_Returns_All_Users() => RunAsync( - query: """ - query { - usersInA(filter: { first: 1 }) { id } - } - """, - expectedData: """ - { - "usersInA": [ - { "id": "u1" }, - { "id": "u2" } - ] - } - """); - - /// - /// offset is only declared by subgraph b and therefore - /// not part of the supergraph's intersection. Validation must - /// reject the query. - /// - [Fact] - public Task UsersInA_With_Offset_Is_Rejected() => RunAsync( - query: """ - query { - usersInA(filter: { first: 1, offset: 2 }) { id } - } - """, - expectsErrors: true); - - /// - /// Even on subgraph b's own root field, the supergraph - /// intersection forbids offset. - /// - [Fact] - public Task UsersInB_With_Offset_Is_Rejected() => RunAsync( - query: """ - query { - usersInB(filter: { first: 1, offset: 2 }) { id } - } - """, - expectsErrors: true); + [Theory] + [MemberData(nameof(Cases))] + [Trait("Category", "OfficialV2")] + public Task OfficialCase_Should_MatchExpectedResult_When_Executed(string caseId) + => RunOfficialV2CaseAsync(caseId); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/A/MediaInterfaceType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/A/MediaInterfaceType.cs index 13bfc5f8f69..f935c258c6e 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/A/MediaInterfaceType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/A/MediaInterfaceType.cs @@ -5,10 +5,7 @@ namespace HotChocolate.Fusion.Suites.InterfaceObjectIndirectExtension.A; /// /// Descriptor for the Media interface in the a subgraph -/// (interface Media @key(fields: "id")). The reference resolver dispatches -/// to the concrete Video implementer so the gateway can recover the -/// concrete __typename for the Media @interfaceObject declared in -/// subgraph c. +/// (interface Media @key(fields: "id")). /// public sealed class MediaInterfaceType : InterfaceType { @@ -16,12 +13,9 @@ protected override void Configure(IInterfaceTypeDescriptor descriptor) { descriptor.Name("Media"); descriptor - .Key("id") - .ResolveReferenceWith(_ => ResolveById(default!)); + .Key("id"); descriptor.Field(m => m.Id).Type>(); descriptor.Field(m => m.Title).Type(); } - - private static IMedia ResolveById(string id) => AData.VideoById(id); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/B/VideoType.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/B/VideoType.cs index 8ac481fa0c4..0efe2476731 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/B/VideoType.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/Suites/InterfaceObjectIndirectExtension/B/VideoType.cs @@ -15,20 +15,13 @@ protected override void Configure(IObjectTypeDescriptor