import { execute } from '../execution-utils'; import { astSerializer, queryPlanSerializer } from '../../snapshotSerializers'; import { accounts, reviews } from 'apollo-federation-integration-testsuite'; expect.addSnapshotSerializer(astSerializer); expect.addSnapshotSerializer(queryPlanSerializer); function spyOnResolver(resolverMap: any, resolverName: T) { return jest.spyOn(resolverMap, resolverName).mockName(resolverName); } it('supports mutations', async () => { const query = `#graphql mutation Login($username: String!, $password: String!) { login(username: $username, password: $password) { reviews { product { upc } } } } `; const variables = { username: '@complete', password: 'css_completes_me' }; const { data, queryPlan } = await execute({ query, variables, }); expect(data).toEqual({ login: { reviews: [ { product: { upc: '3' } }, { product: { upc: '1' } }, { product: { upc: '0262510871' } }, { product: { upc: '0136291554' } }, ], }, }); expect(queryPlan).toCallService('accounts'); expect(queryPlan).toCallService('reviews'); expect(queryPlan).toCallService('product'); }); it('returning across service boundaries', async () => { const query = `#graphql mutation Review($upc: String!, $body: String!) { reviewProduct(upc: $upc, body: $body) { ... on Furniture { name } } } `; const variables = { upc: '1', body: 'A great table' }; const { data, queryPlan } = await execute({ query, variables, }); expect(data).toEqual({ reviewProduct: { name: 'Table', }, }); expect(queryPlan).toCallService('reviews'); expect(queryPlan).toCallService('product'); }); it('multiple root mutations', async () => { const login = spyOnResolver(accounts.resolvers.Mutation, 'login'); const reviewProduct = spyOnResolver( reviews.resolvers.Mutation, 'reviewProduct', ); const query = `#graphql mutation LoginAndReview( $username: String! $password: String! $upc: String! $body: String! ) { login(username: $username, password: $password) { reviews { product { upc } } } reviewProduct(upc: $upc, body: $body) { ... on Furniture { name } } } `; const variables = { username: '@complete', password: 'css_completes_me', upc: '1', body: 'A great table.', }; const { data, queryPlan } = await execute({ query, variables, }); expect(data).toEqual({ login: { reviews: [ { product: { upc: '3' } }, { product: { upc: '1' } }, { product: { upc: '0262510871' } }, { product: { upc: '0136291554' } }, ], }, reviewProduct: { name: 'Table', }, }); expect(queryPlan).toCallService('accounts'); expect(queryPlan).toCallService('reviews'); expect(queryPlan).toCallService('product'); expect(login).toHaveBeenCalledBefore(reviewProduct); }); it('multiple root mutations with correct service order', async () => { const reviewsMutations = reviews.resolvers.Mutation; const reviewProduct = spyOnResolver(reviewsMutations, 'reviewProduct'); const login = spyOnResolver(accounts.resolvers.Mutation, 'login'); const updateReview = spyOnResolver(reviewsMutations, 'updateReview'); const deleteReview = spyOnResolver(reviewsMutations, 'deleteReview'); const query = `#graphql mutation LoginAndReview( $upc: String! $body: String! $updatedReview: UpdateReviewInput! $username: String! $password: String! $reviewId: ID! ) { reviewProduct(upc: $upc, body: $body) { ... on Furniture { upc } } updateReview(review: $updatedReview) { id body } login(username: $username, password: $password) { reviews { product { upc } } } deleteReview(id: $reviewId) } `; const variables = { upc: '1', body: 'A great table.', updatedReview: { id: '1', body: 'An excellent table.', }, username: '@complete', password: 'css_completes_me', reviewId: '6', }; const { data, queryPlan } = await execute({ query, variables, }); expect(data).toEqual({ deleteReview: true, login: { reviews: [ { product: { upc: '3' } }, { product: { upc: '1' } }, { product: { upc: '0262510871' } }, { product: { upc: '0136291554' } }, ], }, reviewProduct: { upc: '1', }, updateReview: { body: 'An excellent table.', id: '1', }, }); expect(queryPlan).toMatchInlineSnapshot(` QueryPlan { Sequence { Fetch(service: "reviews") { { reviewProduct(upc: $upc, body: $body) { __typename ... on Furniture { upc } } updateReview(review: $updatedReview) { id body } } }, Fetch(service: "accounts") { { login(username: $username, password: $password) { __typename id } } }, Flatten(path: "login") { Fetch(service: "reviews") { { ... on User { __typename id } } => { ... on User { reviews { product { __typename ... on Book { __typename isbn } ... on Furniture { upc } } } } } }, }, Flatten(path: "login.reviews.@.product") { Fetch(service: "product") { { ... on Book { __typename isbn } } => { ... on Book { upc } } }, }, Fetch(service: "reviews") { { deleteReview(id: $reviewId) } }, }, } `); expect(reviewProduct).toHaveBeenCalledBefore(updateReview); expect(updateReview).toHaveBeenCalledBefore(login); expect(login).toHaveBeenCalledBefore(deleteReview); });