import gql from 'graphql-tag'; import { execute } from '../execution-utils'; import { astSerializer, queryPlanSerializer } from '../../snapshotSerializers'; expect.addSnapshotSerializer(astSerializer); expect.addSnapshotSerializer(queryPlanSerializer); describe('value types', () => { it('resolves value types within their respective services', async () => { const query = `#graphql fragment Metadata on MetadataOrError { ... on KeyValue { key value } ... on Error { code message } } query ProducsWithMetadata { topProducts(first: 10) { upc ... on Book { metadata { ...Metadata } } ... on Furniture { metadata { ...Metadata } } reviews { metadata { ...Metadata } } } } `; const { data, errors, queryPlan } = await execute({ query, }); expect(errors).toBeUndefined(); expect(queryPlan).toMatchInlineSnapshot(` QueryPlan { Sequence { Fetch(service: "product") { { topProducts(first: 10) { __typename ... on Book { upc __typename isbn } ... on Furniture { upc metadata { __typename ... on KeyValue { key value } ... on Error { code message } } __typename } } } }, Parallel { Flatten(path: "topProducts.@") { Fetch(service: "books") { { ... on Book { __typename isbn } } => { ... on Book { metadata { __typename ... on KeyValue { key value } ... on Error { code message } } } } }, }, Flatten(path: "topProducts.@") { Fetch(service: "reviews") { { ... on Book { __typename isbn } ... on Furniture { __typename upc } } => { ... on Book { reviews { metadata { __typename ... on KeyValue { key value } ... on Error { code message } } } } ... on Furniture { reviews { metadata { __typename ... on KeyValue { key value } ... on Error { code message } } } } } }, }, }, }, } `); const [furniture, , , , book] = data!.topProducts; // Sanity check, referenceable ID expect(furniture.upc).toEqual('1'); // Value type resolves from the correct service expect(furniture.metadata[0]).toEqual({ key: 'Condition', value: 'excellent', }); // Value type from a different service (reviews) also resolves correctly expect(furniture.reviews[0].metadata[0]).toEqual({ code: 418, message: "I'm a teapot", }); // Sanity check, referenceable ID expect(book.upc).toEqual('0136291554'); // Value type as a union resolves correctly expect(book.metadata).toEqual([ { key: 'Condition', value: 'used', }, { code: 401, message: 'Unauthorized', }, ]); expect(queryPlan).toCallService('product'); expect(queryPlan).toCallService('books'); expect(queryPlan).toCallService('reviews'); }); it('resolves @provides fields on value types correctly via contrived example', async () => { const firstService = { name: 'firstService', typeDefs: gql` extend type Query { valueType: ValueType } type ValueType { id: ID! user: User! @provides(fields: "id name") } extend type User @key(fields: "id") { id: ID! @external name: String! @external } `, resolvers: { Query: { valueType() { return { id: '123', user: { id: '1', name: 'trevor' } }; }, }, }, }; const secondService = { name: 'secondService', typeDefs: gql` extend type Query { otherValueType: ValueType } type ValueType { id: ID! user: User! @provides(fields: "id name") } extend type User @key(fields: "id") { id: ID! @external name: String! @external } `, resolvers: { Query: { otherValueType() { return { id: '456', user: { id: '2', name: 'james' } }; }, }, }, }; const userService = { name: 'userService', typeDefs: gql` type User @key(fields: "id") { id: ID! name: String! address: String! } `, resolvers: { User: { __resolveReference(user: any) { return user.id === '1' ? { id: '1', name: 'trevor', address: '123 Abc St' } : { id: '2', name: 'james', address: '456 Hello St.' }; }, }, }, }; const query = `#graphql query Hello { valueType { id user { id name address } } otherValueType { id user { id name address } } } `; const { data, errors, queryPlan } = await execute( { query, }, [firstService, secondService, userService], ); expect(errors).toBeUndefined(); expect(queryPlan).toCallService('firstService'); expect(queryPlan).toCallService('secondService'); expect(queryPlan).toCallService('userService'); expect(data).toMatchInlineSnapshot(` Object { "otherValueType": Object { "id": "456", "user": Object { "address": "456 Hello St.", "id": "2", "name": "james", }, }, "valueType": Object { "id": "123", "user": Object { "address": "123 Abc St", "id": "1", "name": "trevor", }, }, } `); expect(queryPlan).toMatchInlineSnapshot(` QueryPlan { Parallel { Sequence { Fetch(service: "firstService") { { valueType { id user { id name __typename } } } }, Flatten(path: "valueType.user") { Fetch(service: "userService") { { ... on User { __typename id } } => { ... on User { address } } }, }, }, Sequence { Fetch(service: "secondService") { { otherValueType { id user { id name __typename } } } }, Flatten(path: "otherValueType.user") { Fetch(service: "userService") { { ... on User { __typename id } } => { ... on User { address } } }, }, }, }, } `); }); });