Skip to content

Commit

Permalink
Ensure watchFragment used with variables does not crash when the ca…
Browse files Browse the repository at this point in the history
…che updates #12284 (#12287)

Co-authored-by: Jerel Miller <[email protected]>
  • Loading branch information
phryneas and jerelmiller authored Jan 22, 2025
1 parent 3abd944 commit bf313a3
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/ten-rules-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": patch
---

Fixes an issue where `client.watchFragment`/`useFragment` with `@includes` crashes when a separate cache update writes to the conditionally included fields.
4 changes: 2 additions & 2 deletions .size-limits.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dist/apollo-client.min.cjs": 41639,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 34382
"dist/apollo-client.min.cjs": 41642,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 34384
}
69 changes: 69 additions & 0 deletions src/__tests__/ApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2465,6 +2465,75 @@ describe("ApolloClient", () => {
}
});

it("supports the @includes directive with `variables` - parallel cache modification", async () => {
const cache = new InMemoryCache();
const client = new ApolloClient({ cache });

const FullFragment = gql`
fragment ItemFragment on Item {
id
text
}
`;

const ItemFragment = gql`
fragment ItemFragment on Item {
id
...IncludedFragment @include(if: $withText)
}
fragment IncludedFragment on Item {
id
text
}
`;

cache.writeFragment({
fragment: FullFragment,
data: {
__typename: "Item",
id: 5,
text: "Item #5",
},
});

const observable = client.watchFragment({
fragment: ItemFragment,
from: { __typename: "Item", id: 5 },
variables: { withText: true },
fragmentName: "ItemFragment",
});

const stream = new ObservableStream(observable);

await expect(stream).toEmitValueStrict({
data: {
__typename: "Item",
id: 5,
text: "Item #5",
},
complete: true,
});

client.writeFragment({
fragment: FullFragment,
data: {
__typename: "Item",
id: 5,
text: "changed Item #5",
},
});

await expect(stream).toEmitValueStrict({
data: {
__typename: "Item",
id: 5,
text: "changed Item #5",
},
complete: true,
});
});

it("works with nested fragments", async () => {
const cache = new InMemoryCache();
const client = new ApolloClient({
Expand Down
9 changes: 8 additions & 1 deletion src/cache/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,14 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {
if (
// Always ensure we deliver the first result
latestDiff &&
equalByQuery(query, { data: latestDiff?.result }, { data })
equalByQuery(
query,
{ data: latestDiff.result },
{ data },
// TODO: Fix the type on WatchFragmentOptions so that TVars
// extends OperationVariables
options.variables as OperationVariables
)
) {
return;
}
Expand Down

0 comments on commit bf313a3

Please sign in to comment.