From 66553dbbe9774a1bd0624c416c379ee8ac98787c Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 27 Apr 2021 17:42:39 -0400 Subject: [PATCH 1/2] Regression test for issue #8057. --- src/cache/inmemory/__tests__/writeToStore.ts | 134 +++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/src/cache/inmemory/__tests__/writeToStore.ts b/src/cache/inmemory/__tests__/writeToStore.ts index 407daa25d64..3923e915c88 100644 --- a/src/cache/inmemory/__tests__/writeToStore.ts +++ b/src/cache/inmemory/__tests__/writeToStore.ts @@ -1812,6 +1812,140 @@ describe('writing to the store', () => { todos: null, }); }); + + it("handles multiple overlaping fragments (issue #8057)", () => { + const cache = new InMemoryCache({ + typePolicies: { + Amount: { + keyFields: false + }, + }, + possibleTypes: { + AmountInterface: ["VatAmount", "Amount", "CoinsAmount"], + }, + }); + + const AmountFragment = gql` + fragment AmountFragment on AmountInterface { + amount + currency + } + `; + + const OrderItemsList_OrderFragment = gql` + ## BUG: This fragment is defined on type which has identity ("id" field). + ## When spreaded to the "ApplicationDetailFragment", it overwrites its + ## selection for "rewards" + fragment OrderItemsList_OrderFragment on Order { + items { + rewards { + # coins # TODO: uncomment will pass the test + isPurchased + discount { + ...AmountFragment + } + relatedObjects { + serviceId + } + type + } + } + } + `; + + const ApplicationDetailFragment = gql` + fragment ApplicationDetailFragment on Application { + order { + ## The "OrderItemsList_OrderFragment" is nested here, when spreaded + ## directly to the "ApplicationDetailQuery", the test will pass + ...OrderItemsList_OrderFragment + items { + id + rewards { + coins { + ...AmountFragment + } + discount { + ...AmountFragment + } + isPurchased + relatedObjects { + serviceId + } + type + } + } + } + } + `; + + const ApplicationDetailQuery = gql` + query ApplicationDetailQuery($id: String!) { + myContractApplication(id: $id) { + ...ApplicationDetailFragment + } + } + ${ApplicationDetailFragment} + ${OrderItemsList_OrderFragment} + ${AmountFragment} + `; + + const result = { + myContractApplication: { + __typename: "Application", + order: { + __typename: "Order", + items: [ + { + __typename: "OrderItem", + id: "JUTVV93M8G1Rw4kGJsmtBW", + rewards: [ + { + coins: { + currency: "XXX", + amount: 500, + __typename: "CoinsAmount" + }, + discount: { + currency: "CZK", + amount: 10000, + __typename: "Amount" + }, + type: "FREE_DELIVERY", + isPurchased: false, + relatedObjects: null, + __typename: "Reward" + } + ] + }, + { + __typename: "OrderItem", + id: "Rz4rsMMEtGzzrrCfa8En55", + rewards: [] + } + ] + } + } + }; + + cache.writeQuery({ + query: ApplicationDetailQuery, + data: result, + variables: { + id: "QMvzmo6pZmV24UxFjbgKeQ", + }, + }); + + const orderId = cache.identify({ + __typename: "OrderItem", + id: "JUTVV93M8G1Rw4kGJsmtBW", + })!; + + expect(cache.extract()[orderId]).toEqual( + result.myContractApplication.order.items[0] + ); + }); + it('should not warn if a field is defered', () => { let originalWarn = console.warn; console.warn = jest.fn((...args) => {}); From c9c2687a05b20d2b53eb199f73d28b6b71334b3c Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 27 Apr 2021 18:37:47 -0400 Subject: [PATCH 2/2] Fix test by configuring OrderItem.rewards array merge function. --- src/cache/inmemory/__tests__/writeToStore.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/cache/inmemory/__tests__/writeToStore.ts b/src/cache/inmemory/__tests__/writeToStore.ts index 3923e915c88..f50da3f55e1 100644 --- a/src/cache/inmemory/__tests__/writeToStore.ts +++ b/src/cache/inmemory/__tests__/writeToStore.ts @@ -1819,6 +1819,20 @@ describe('writing to the store', () => { Amount: { keyFields: false }, + OrderItem: { + fields: { + rewards: { + merge(existing: any[] | undefined, incoming: any[], { mergeObjects }) { + if (existing) { + const merged = existing.map((e, i) => mergeObjects(e, incoming[i])); + const additional = incoming.slice(existing.length); + return [ ...merged, ...additional ]; + } + return incoming; + } + } + } + }, }, possibleTypes: { AmountInterface: ["VatAmount", "Amount", "CoinsAmount"],