From 636d2ce3f9efdb007ab7dd422b867b9a19adec9a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:38:36 -0700 Subject: [PATCH 01/21] Copy over links test to ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 414 ++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 src/core/__tests__/ApolloClient/links.test.ts diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts new file mode 100644 index 00000000000..de43efdf8b9 --- /dev/null +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -0,0 +1,414 @@ +// externals +import gql from "graphql-tag"; +import { print } from "graphql"; + +import { + Observable, + ObservableSubscription, +} from "../../../utilities/observables/Observable"; +import { ApolloLink } from "../../../link/core"; +import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; + +// mocks +import { MockSubscriptionLink } from "../../../testing/core"; + +// core +import { QueryManager } from "../../QueryManager"; +import { NextLink, Operation, Reference } from "../../../core"; +import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; + +describe("Link interactions", () => { + it("includes the cache on the context for eviction links", (done) => { + const query = gql` + query CachedLuke { + people_one(id: 1) { + name + friends { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: [{ name: "Leia Skywalker" }], + }, + }; + + const evictionLink = (operation: Operation, forward: NextLink) => { + const { cache } = operation.getContext(); + expect(cache).toBeDefined(); + return forward(operation).map((result) => { + setTimeout(() => { + const cacheResult = cache.read({ query }); + expect(cacheResult).toEqual(initialData); + expect(cacheResult).toEqual(result.data); + if (count === 1) { + done(); + } + }, 10); + return result; + }); + }; + + const mockLink = new MockSubscriptionLink(); + const link = ApolloLink.from([evictionLink, mockLink]); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + }); + + let count = 0; + observable.subscribe({ + next: (result) => { + count++; + }, + error: (e) => { + console.error(e); + }, + }); + + // fire off first result + mockLink.simulateResult({ result: { data: initialData } }); + }); + + it("cleans up all links on the final unsubscribe from watchQuery", (done) => { + const query = gql` + query WatchedLuke { + people_one(id: 1) { + name + friends { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: [{ name: "Leia Skywalker" }], + }, + }; + + const link = new MockSubscriptionLink(); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + }); + + let count = 0; + let four: ObservableSubscription; + // first watch + const one = observable.subscribe((result) => count++); + // second watch + const two = observable.subscribe((result) => count++); + // third watch (to be unsubscribed) + const three = observable.subscribe((result) => { + count++; + three.unsubscribe(); + // fourth watch + four = observable.subscribe((x) => count++); + }); + + // fire off first result + link.simulateResult({ result: { data: initialData } }); + setTimeout(() => { + one.unsubscribe(); + + link.simulateResult({ + result: { + data: { + people_one: { + name: "Luke Skywalker", + friends: [{ name: "R2D2" }], + }, + }, + }, + }); + setTimeout(() => { + four.unsubscribe(); + // final unsubscribe should be called now + two.unsubscribe(); + }, 10); + }, 10); + + link.onUnsubscribe(() => { + expect(count).toEqual(6); + done(); + }); + }); + + it("cleans up all links on the final unsubscribe from watchQuery [error]", (done) => { + const query = gql` + query WatchedLuke { + people_one(id: 1) { + name + friends { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: [{ name: "Leia Skywalker" }], + }, + }; + + const link = new MockSubscriptionLink(); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + }); + + let count = 0; + let four: ObservableSubscription; + // first watch + const one = observable.subscribe((result) => count++); + // second watch + observable.subscribe({ + next: () => count++, + error: () => { + count = 0; + }, + }); + // third watch (to be unsubscribed) + const three = observable.subscribe((result) => { + count++; + three.unsubscribe(); + // fourth watch + four = observable.subscribe((x) => count++); + }); + + // fire off first result + link.simulateResult({ result: { data: initialData } }); + setTimeout(() => { + one.unsubscribe(); + four.unsubscribe(); + + // final unsubscribe should be called now + // since errors clean up subscriptions + link.simulateResult({ error: new Error("dang") }); + + setTimeout(() => { + expect(count).toEqual(0); + done(); + }, 10); + }, 10); + + link.onUnsubscribe(() => { + expect(count).toEqual(4); + }); + }); + + it("includes the cache on the context for mutations", (done) => { + const mutation = gql` + mutation UpdateLuke { + people_one(id: 1) { + name + friends { + name + } + } + } + `; + + const evictionLink = (operation: Operation, forward: NextLink) => { + const { cache } = operation.getContext(); + expect(cache).toBeDefined(); + done(); + return forward(operation); + }; + + const mockLink = new MockSubscriptionLink(); + const link = ApolloLink.from([evictionLink, mockLink]); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + void queryManager.mutate({ mutation }); + }); + + it("includes passed context in the context for mutations", (done) => { + const mutation = gql` + mutation UpdateLuke { + people_one(id: 1) { + name + friends { + name + } + } + } + `; + + const evictionLink = (operation: Operation, forward: NextLink) => { + const { planet } = operation.getContext(); + expect(planet).toBe("Tatooine"); + done(); + return forward(operation); + }; + + const mockLink = new MockSubscriptionLink(); + const link = ApolloLink.from([evictionLink, mockLink]); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + void queryManager.mutate({ mutation, context: { planet: "Tatooine" } }); + }); + + it("includes getCacheKey function on the context for cache resolvers", async () => { + const query = gql` + { + books { + id + title + } + } + `; + + const shouldHitCacheResolver = gql` + { + book(id: 1) { + title + } + } + `; + + const bookData = { + books: [ + { id: 1, title: "Woo", __typename: "Book" }, + { id: 2, title: "Foo", __typename: "Book" }, + ], + }; + + const link = new ApolloLink((operation, forward) => { + const { getCacheKey } = operation.getContext(); + expect(getCacheKey).toBeDefined(); + expect(getCacheKey({ id: 1, __typename: "Book" })).toEqual("Book:1"); + return Observable.of({ data: bookData }); + }); + + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + link, + cache: new InMemoryCache({ + typePolicies: { + Query: { + fields: { + book(_, { args, toReference, readField }) { + if (!args) { + throw new Error("arg must never be null"); + } + + const ref = toReference({ __typename: "Book", id: args.id }); + if (!ref) { + throw new Error("ref must never be null"); + } + + expect(ref).toEqual({ __ref: `Book:${args.id}` }); + const found = readField("books")!.find( + (book) => book.__ref === ref.__ref + ); + expect(found).toBeTruthy(); + return found; + }, + }, + }, + }, + }), + }) + ); + + await queryManager.query({ query }); + + return queryManager + .query({ query: shouldHitCacheResolver }) + .then(({ data }) => { + expect(data).toMatchObject({ + book: { title: "Woo", __typename: "Book" }, + }); + }); + }); + + it("removes @client fields from the query before it reaches the link", async () => { + const result: { current: Operation | undefined } = { + current: undefined, + }; + + const query = gql` + query { + books { + id + title + isRead @client + } + } + `; + + const expectedQuery = gql` + query { + books { + id + title + } + } + `; + + const link = new ApolloLink((operation) => { + result.current = operation; + + return Observable.of({ + data: { + books: [ + { id: 1, title: "Woo", __typename: "Book" }, + { id: 2, title: "Foo", __typename: "Book" }, + ], + }, + }); + }); + + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + link, + cache: new InMemoryCache({ addTypename: false }), + }) + ); + + await queryManager.query({ query }); + + expect(print(result.current!.query)).toEqual(print(expectedQuery)); + }); +}); From 4b092107ccd35c81e884605a7f277e3dc29852b2 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:38:48 -0700 Subject: [PATCH 02/21] Remove unneeded comments --- src/core/__tests__/ApolloClient/links.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index de43efdf8b9..b37c322052f 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -1,4 +1,3 @@ -// externals import gql from "graphql-tag"; import { print } from "graphql"; @@ -9,10 +8,8 @@ import { import { ApolloLink } from "../../../link/core"; import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; -// mocks import { MockSubscriptionLink } from "../../../testing/core"; -// core import { QueryManager } from "../../QueryManager"; import { NextLink, Operation, Reference } from "../../../core"; import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; From e2832c6294dadd1303187bf3975870031e31d3e7 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:39:16 -0700 Subject: [PATCH 03/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index b37c322052f..e7d1e9708de 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -11,7 +11,7 @@ import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; import { MockSubscriptionLink } from "../../../testing/core"; import { QueryManager } from "../../QueryManager"; -import { NextLink, Operation, Reference } from "../../../core"; +import { ApolloClient, NextLink, Operation, Reference } from "../../../core"; import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; describe("Link interactions", () => { @@ -52,14 +52,12 @@ describe("Link interactions", () => { const mockLink = new MockSubscriptionLink(); const link = ApolloLink.from([evictionLink, mockLink]); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, }); From e45798c2e01b1b491aab2efa7c446d5d6d64e56c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:39:28 -0700 Subject: [PATCH 04/21] Include number of assertions in test --- src/core/__tests__/ApolloClient/links.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index e7d1e9708de..66796a35905 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -16,6 +16,7 @@ import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/moc describe("Link interactions", () => { it("includes the cache on the context for eviction links", (done) => { + expect.assertions(3); const query = gql` query CachedLuke { people_one(id: 1) { From 2035f7d836726b27dbaad34104cf92378243d7e6 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:40:59 -0700 Subject: [PATCH 05/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index 66796a35905..d7e08c9f1f0 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -97,14 +97,12 @@ describe("Link interactions", () => { }; const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, }); From 3e9dbbbfd1ffeec638a54316b24ea6062c4e1e80 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:41:43 -0700 Subject: [PATCH 06/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index d7e08c9f1f0..e46c4443be4 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -169,14 +169,12 @@ describe("Link interactions", () => { }; const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, }); From 05066f1ddec631f5730ae0c17cc617a987803a91 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:42:15 -0700 Subject: [PATCH 07/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index e46c4443be4..581e8f9fee7 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -240,14 +240,12 @@ describe("Link interactions", () => { const mockLink = new MockSubscriptionLink(); const link = ApolloLink.from([evictionLink, mockLink]); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - void queryManager.mutate({ mutation }); + void client.mutate({ mutation }); }); it("includes passed context in the context for mutations", (done) => { From 3d98afcd9c0ebe7b1b2db220a70ef606eb70bf78 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:42:44 -0700 Subject: [PATCH 08/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index 581e8f9fee7..a8fcf6b8bc5 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -269,14 +269,12 @@ describe("Link interactions", () => { const mockLink = new MockSubscriptionLink(); const link = ApolloLink.from([evictionLink, mockLink]); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - void queryManager.mutate({ mutation, context: { planet: "Tatooine" } }); + void client.mutate({ mutation, context: { planet: "Tatooine" } }); }); it("includes getCacheKey function on the context for cache resolvers", async () => { From 1e35270b82c81be58b729739d49b4f6051565da7 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:43:15 -0700 Subject: [PATCH 09/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 64 +++++++++---------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index a8fcf6b8bc5..aa7344ce758 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -309,46 +309,42 @@ describe("Link interactions", () => { return Observable.of({ data: bookData }); }); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - link, - cache: new InMemoryCache({ - typePolicies: { - Query: { - fields: { - book(_, { args, toReference, readField }) { - if (!args) { - throw new Error("arg must never be null"); - } - - const ref = toReference({ __typename: "Book", id: args.id }); - if (!ref) { - throw new Error("ref must never be null"); - } - - expect(ref).toEqual({ __ref: `Book:${args.id}` }); - const found = readField("books")!.find( - (book) => book.__ref === ref.__ref - ); - expect(found).toBeTruthy(); - return found; - }, + const client = new ApolloClient({ + link, + cache: new InMemoryCache({ + typePolicies: { + Query: { + fields: { + book(_, { args, toReference, readField }) { + if (!args) { + throw new Error("arg must never be null"); + } + + const ref = toReference({ __typename: "Book", id: args.id }); + if (!ref) { + throw new Error("ref must never be null"); + } + + expect(ref).toEqual({ __ref: `Book:${args.id}` }); + const found = readField("books")!.find( + (book) => book.__ref === ref.__ref + ); + expect(found).toBeTruthy(); + return found; }, }, }, - }), - }) - ); + }, + }), + }); - await queryManager.query({ query }); + await client.query({ query }); - return queryManager - .query({ query: shouldHitCacheResolver }) - .then(({ data }) => { - expect(data).toMatchObject({ - book: { title: "Woo", __typename: "Book" }, - }); + return client.query({ query: shouldHitCacheResolver }).then(({ data }) => { + expect(data).toMatchObject({ + book: { title: "Woo", __typename: "Book" }, }); + }); }); it("removes @client fields from the query before it reaches the link", async () => { From 3107284f367b1d544b39bb7df2e9c7dba908d0ff Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:43:40 -0700 Subject: [PATCH 10/21] Flatten test with await --- src/core/__tests__/ApolloClient/links.test.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index aa7344ce758..bce21ed7c0e 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -340,10 +340,9 @@ describe("Link interactions", () => { await client.query({ query }); - return client.query({ query: shouldHitCacheResolver }).then(({ data }) => { - expect(data).toMatchObject({ - book: { title: "Woo", __typename: "Book" }, - }); + const { data } = await client.query({ query: shouldHitCacheResolver }); + expect(data).toMatchObject({ + book: { title: "Woo", __typename: "Book" }, }); }); From bc81ea5f479416268348e5aec7403fbe68ef33c4 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:44:09 -0700 Subject: [PATCH 11/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- src/core/__tests__/ApolloClient/links.test.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index bce21ed7c0e..848171b5fcb 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -383,14 +383,12 @@ describe("Link interactions", () => { }); }); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - link, - cache: new InMemoryCache({ addTypename: false }), - }) - ); - - await queryManager.query({ query }); + const client = new ApolloClient({ + link, + cache: new InMemoryCache({ addTypename: false }), + }); + + await client.query({ query }); expect(print(result.current!.query)).toEqual(print(expectedQuery)); }); From 7ce773e0e3c42f44dcad32bd7d758d2ab2d5c2c1 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:44:23 -0700 Subject: [PATCH 12/21] Remove unused imports --- src/core/__tests__/ApolloClient/links.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/__tests__/ApolloClient/links.test.ts b/src/core/__tests__/ApolloClient/links.test.ts index 848171b5fcb..6aef5ca37e3 100644 --- a/src/core/__tests__/ApolloClient/links.test.ts +++ b/src/core/__tests__/ApolloClient/links.test.ts @@ -1,18 +1,13 @@ import gql from "graphql-tag"; import { print } from "graphql"; - import { Observable, ObservableSubscription, } from "../../../utilities/observables/Observable"; import { ApolloLink } from "../../../link/core"; import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; - import { MockSubscriptionLink } from "../../../testing/core"; - -import { QueryManager } from "../../QueryManager"; import { ApolloClient, NextLink, Operation, Reference } from "../../../core"; -import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; describe("Link interactions", () => { it("includes the cache on the context for eviction links", (done) => { From 595f1cd341207c54aa18d9b4468a4ff169fdab27 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:45:00 -0700 Subject: [PATCH 13/21] Remove old QueryManager/links test --- src/core/__tests__/QueryManager/links.ts | 414 ----------------------- 1 file changed, 414 deletions(-) delete mode 100644 src/core/__tests__/QueryManager/links.ts diff --git a/src/core/__tests__/QueryManager/links.ts b/src/core/__tests__/QueryManager/links.ts deleted file mode 100644 index de43efdf8b9..00000000000 --- a/src/core/__tests__/QueryManager/links.ts +++ /dev/null @@ -1,414 +0,0 @@ -// externals -import gql from "graphql-tag"; -import { print } from "graphql"; - -import { - Observable, - ObservableSubscription, -} from "../../../utilities/observables/Observable"; -import { ApolloLink } from "../../../link/core"; -import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; - -// mocks -import { MockSubscriptionLink } from "../../../testing/core"; - -// core -import { QueryManager } from "../../QueryManager"; -import { NextLink, Operation, Reference } from "../../../core"; -import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; - -describe("Link interactions", () => { - it("includes the cache on the context for eviction links", (done) => { - const query = gql` - query CachedLuke { - people_one(id: 1) { - name - friends { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: [{ name: "Leia Skywalker" }], - }, - }; - - const evictionLink = (operation: Operation, forward: NextLink) => { - const { cache } = operation.getContext(); - expect(cache).toBeDefined(); - return forward(operation).map((result) => { - setTimeout(() => { - const cacheResult = cache.read({ query }); - expect(cacheResult).toEqual(initialData); - expect(cacheResult).toEqual(result.data); - if (count === 1) { - done(); - } - }, 10); - return result; - }); - }; - - const mockLink = new MockSubscriptionLink(); - const link = ApolloLink.from([evictionLink, mockLink]); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - }); - - let count = 0; - observable.subscribe({ - next: (result) => { - count++; - }, - error: (e) => { - console.error(e); - }, - }); - - // fire off first result - mockLink.simulateResult({ result: { data: initialData } }); - }); - - it("cleans up all links on the final unsubscribe from watchQuery", (done) => { - const query = gql` - query WatchedLuke { - people_one(id: 1) { - name - friends { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: [{ name: "Leia Skywalker" }], - }, - }; - - const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - }); - - let count = 0; - let four: ObservableSubscription; - // first watch - const one = observable.subscribe((result) => count++); - // second watch - const two = observable.subscribe((result) => count++); - // third watch (to be unsubscribed) - const three = observable.subscribe((result) => { - count++; - three.unsubscribe(); - // fourth watch - four = observable.subscribe((x) => count++); - }); - - // fire off first result - link.simulateResult({ result: { data: initialData } }); - setTimeout(() => { - one.unsubscribe(); - - link.simulateResult({ - result: { - data: { - people_one: { - name: "Luke Skywalker", - friends: [{ name: "R2D2" }], - }, - }, - }, - }); - setTimeout(() => { - four.unsubscribe(); - // final unsubscribe should be called now - two.unsubscribe(); - }, 10); - }, 10); - - link.onUnsubscribe(() => { - expect(count).toEqual(6); - done(); - }); - }); - - it("cleans up all links on the final unsubscribe from watchQuery [error]", (done) => { - const query = gql` - query WatchedLuke { - people_one(id: 1) { - name - friends { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: [{ name: "Leia Skywalker" }], - }, - }; - - const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - }); - - let count = 0; - let four: ObservableSubscription; - // first watch - const one = observable.subscribe((result) => count++); - // second watch - observable.subscribe({ - next: () => count++, - error: () => { - count = 0; - }, - }); - // third watch (to be unsubscribed) - const three = observable.subscribe((result) => { - count++; - three.unsubscribe(); - // fourth watch - four = observable.subscribe((x) => count++); - }); - - // fire off first result - link.simulateResult({ result: { data: initialData } }); - setTimeout(() => { - one.unsubscribe(); - four.unsubscribe(); - - // final unsubscribe should be called now - // since errors clean up subscriptions - link.simulateResult({ error: new Error("dang") }); - - setTimeout(() => { - expect(count).toEqual(0); - done(); - }, 10); - }, 10); - - link.onUnsubscribe(() => { - expect(count).toEqual(4); - }); - }); - - it("includes the cache on the context for mutations", (done) => { - const mutation = gql` - mutation UpdateLuke { - people_one(id: 1) { - name - friends { - name - } - } - } - `; - - const evictionLink = (operation: Operation, forward: NextLink) => { - const { cache } = operation.getContext(); - expect(cache).toBeDefined(); - done(); - return forward(operation); - }; - - const mockLink = new MockSubscriptionLink(); - const link = ApolloLink.from([evictionLink, mockLink]); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - void queryManager.mutate({ mutation }); - }); - - it("includes passed context in the context for mutations", (done) => { - const mutation = gql` - mutation UpdateLuke { - people_one(id: 1) { - name - friends { - name - } - } - } - `; - - const evictionLink = (operation: Operation, forward: NextLink) => { - const { planet } = operation.getContext(); - expect(planet).toBe("Tatooine"); - done(); - return forward(operation); - }; - - const mockLink = new MockSubscriptionLink(); - const link = ApolloLink.from([evictionLink, mockLink]); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - void queryManager.mutate({ mutation, context: { planet: "Tatooine" } }); - }); - - it("includes getCacheKey function on the context for cache resolvers", async () => { - const query = gql` - { - books { - id - title - } - } - `; - - const shouldHitCacheResolver = gql` - { - book(id: 1) { - title - } - } - `; - - const bookData = { - books: [ - { id: 1, title: "Woo", __typename: "Book" }, - { id: 2, title: "Foo", __typename: "Book" }, - ], - }; - - const link = new ApolloLink((operation, forward) => { - const { getCacheKey } = operation.getContext(); - expect(getCacheKey).toBeDefined(); - expect(getCacheKey({ id: 1, __typename: "Book" })).toEqual("Book:1"); - return Observable.of({ data: bookData }); - }); - - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - link, - cache: new InMemoryCache({ - typePolicies: { - Query: { - fields: { - book(_, { args, toReference, readField }) { - if (!args) { - throw new Error("arg must never be null"); - } - - const ref = toReference({ __typename: "Book", id: args.id }); - if (!ref) { - throw new Error("ref must never be null"); - } - - expect(ref).toEqual({ __ref: `Book:${args.id}` }); - const found = readField("books")!.find( - (book) => book.__ref === ref.__ref - ); - expect(found).toBeTruthy(); - return found; - }, - }, - }, - }, - }), - }) - ); - - await queryManager.query({ query }); - - return queryManager - .query({ query: shouldHitCacheResolver }) - .then(({ data }) => { - expect(data).toMatchObject({ - book: { title: "Woo", __typename: "Book" }, - }); - }); - }); - - it("removes @client fields from the query before it reaches the link", async () => { - const result: { current: Operation | undefined } = { - current: undefined, - }; - - const query = gql` - query { - books { - id - title - isRead @client - } - } - `; - - const expectedQuery = gql` - query { - books { - id - title - } - } - `; - - const link = new ApolloLink((operation) => { - result.current = operation; - - return Observable.of({ - data: { - books: [ - { id: 1, title: "Woo", __typename: "Book" }, - { id: 2, title: "Foo", __typename: "Book" }, - ], - }, - }); - }); - - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - link, - cache: new InMemoryCache({ addTypename: false }), - }) - ); - - await queryManager.query({ query }); - - expect(print(result.current!.query)).toEqual(print(expectedQuery)); - }); -}); From 4bf2db4e45282701ecaa0dc0f08849fd85c37b6d Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:45:07 -0700 Subject: [PATCH 14/21] Copy multiple-results to ApolloClient tests --- .../ApolloClient/multiple-results.test.ts | 347 ++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 src/core/__tests__/ApolloClient/multiple-results.test.ts diff --git a/src/core/__tests__/ApolloClient/multiple-results.test.ts b/src/core/__tests__/ApolloClient/multiple-results.test.ts new file mode 100644 index 00000000000..a8458d0ff13 --- /dev/null +++ b/src/core/__tests__/ApolloClient/multiple-results.test.ts @@ -0,0 +1,347 @@ +// externals +import gql from "graphql-tag"; +import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; + +// mocks +import { MockSubscriptionLink, wait } from "../../../testing/core"; + +// core +import { QueryManager } from "../../QueryManager"; +import { GraphQLError } from "graphql"; +import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; +import { ObservableStream } from "../../../testing/internal"; +import { ApolloError } from "../../../errors"; + +describe("mutiple results", () => { + it("allows multiple query results from link", async () => { + const query = gql` + query LazyLoadLuke { + people_one(id: 1) { + name + friends @defer { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: null, + }, + }; + + const laterData = { + people_one: { + // XXX true defer's wouldn't send this + name: "Luke Skywalker", + friends: [{ name: "Leia Skywalker" }], + }, + }; + const link = new MockSubscriptionLink(); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + }); + const stream = new ObservableStream(observable); + + // fire off first result + link.simulateResult({ result: { data: initialData } }); + + await expect(stream).toEmitValue({ + data: initialData, + loading: false, + networkStatus: 7, + }); + + link.simulateResult({ result: { data: laterData } }); + + await expect(stream).toEmitValue({ + data: laterData, + loading: false, + networkStatus: 7, + }); + }); + + it("allows multiple query results from link with ignored errors", async () => { + const query = gql` + query LazyLoadLuke { + people_one(id: 1) { + name + friends @defer { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: null, + }, + }; + + const laterData = { + people_one: { + // XXX true defer's wouldn't send this + name: "Luke Skywalker", + friends: [{ name: "Leia Skywalker" }], + }, + }; + const link = new MockSubscriptionLink(); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + errorPolicy: "ignore", + }); + const stream = new ObservableStream(observable); + + // fire off first result + link.simulateResult({ result: { data: initialData } }); + + await expect(stream).toEmitValue({ + data: initialData, + loading: false, + networkStatus: 7, + }); + + link.simulateResult({ + result: { errors: [new GraphQLError("defer failed")] }, + }); + + await expect(stream).toEmitValueStrict({ + data: undefined, + loading: false, + networkStatus: 7, + }); + + await wait(20); + link.simulateResult({ result: { data: laterData } }); + + await expect(stream).toEmitValue({ + data: laterData, + loading: false, + networkStatus: 7, + }); + }); + + it("strips errors from a result if ignored", async () => { + const query = gql` + query LazyLoadLuke { + people_one(id: 1) { + name + friends @defer { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: null, + }, + }; + + const laterData = { + people_one: { + // XXX true defer's wouldn't send this + name: "Luke Skywalker", + friends: [{ name: "Leia Skywalker" }], + }, + }; + const link = new MockSubscriptionLink(); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + errorPolicy: "ignore", + }); + const stream = new ObservableStream(observable); + + // fire off first result + link.simulateResult({ result: { data: initialData } }); + + await expect(stream).toEmitValue({ + data: initialData, + loading: false, + networkStatus: 7, + }); + + // this should fire the `next` event without this error + link.simulateResult({ + result: { + errors: [new GraphQLError("defer failed")], + data: laterData, + }, + }); + + await expect(stream).toEmitValueStrict({ + data: laterData, + loading: false, + networkStatus: 7, + }); + }); + + it.skip("allows multiple query results from link with all errors", async () => { + const query = gql` + query LazyLoadLuke { + people_one(id: 1) { + name + friends @defer { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: null, + }, + }; + + const laterData = { + people_one: { + // XXX true defer's wouldn't send this + name: "Luke Skywalker", + friends: [{ name: "Leia Skywalker" }], + }, + }; + const link = new MockSubscriptionLink(); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + errorPolicy: "all", + }); + const stream = new ObservableStream(observable); + + // fire off first result + link.simulateResult({ result: { data: initialData } }); + + await expect(stream).toEmitValue({ + data: initialData, + loading: false, + networkStatus: 7, + }); + + // this should fire the next event again + link.simulateResult({ + error: new Error("defer failed"), + }); + + await expect(stream).toEmitValue({ + data: initialData, + loading: false, + networkStatus: 7, + errors: [new Error("defer failed")], + }); + + link.simulateResult({ result: { data: laterData } }); + + await expect(stream).toEmitValueStrict({ + data: laterData, + loading: false, + networkStatus: 7, + }); + }); + + it("closes the observable if an error is set with the none policy", async () => { + const query = gql` + query LazyLoadLuke { + people_one(id: 1) { + name + friends @defer { + name + } + } + } + `; + + const initialData = { + people_one: { + name: "Luke Skywalker", + friends: null, + }, + }; + + const link = new MockSubscriptionLink(); + const queryManager = new QueryManager( + getDefaultOptionsForQueryManagerTests({ + cache: new InMemoryCache({ addTypename: false }), + link, + }) + ); + + const observable = queryManager.watchQuery({ + query, + variables: {}, + // errorPolicy: 'none', // this is the default + }); + const stream = new ObservableStream(observable); + + let count = 0; + observable.subscribe({ + next: (result) => { + // errors should never be passed since they are ignored + count++; + if (count === 1) { + expect(result.errors).toBeUndefined(); + } + if (count === 2) { + console.log(new Error("result came after an error")); + } + }, + error: (e) => { + expect(e).toBeDefined(); + expect(e.graphQLErrors).toBeDefined(); + }, + }); + + // fire off first result + link.simulateResult({ result: { data: initialData } }); + + await expect(stream).toEmitValue({ + data: initialData, + loading: false, + networkStatus: 7, + }); + + link.simulateResult({ error: new Error("defer failed") }); + + await expect(stream).toEmitError( + new ApolloError({ networkError: new Error("defer failed") }) + ); + }); +}); From c695f05887341d6eb6c1f599c955fe6a890ceb56 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:46:20 -0700 Subject: [PATCH 15/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- .../ApolloClient/multiple-results.test.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/core/__tests__/ApolloClient/multiple-results.test.ts b/src/core/__tests__/ApolloClient/multiple-results.test.ts index a8458d0ff13..9c9df0d5dab 100644 --- a/src/core/__tests__/ApolloClient/multiple-results.test.ts +++ b/src/core/__tests__/ApolloClient/multiple-results.test.ts @@ -11,6 +11,7 @@ import { GraphQLError } from "graphql"; import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; import { ObservableStream } from "../../../testing/internal"; import { ApolloError } from "../../../errors"; +import { ApolloClient } from "../../ApolloClient"; describe("mutiple results", () => { it("allows multiple query results from link", async () => { @@ -40,14 +41,12 @@ describe("mutiple results", () => { }, }; const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, }); @@ -56,7 +55,7 @@ describe("mutiple results", () => { // fire off first result link.simulateResult({ result: { data: initialData } }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: initialData, loading: false, networkStatus: 7, @@ -64,7 +63,7 @@ describe("mutiple results", () => { link.simulateResult({ result: { data: laterData } }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: laterData, loading: false, networkStatus: 7, From 5c55c99ff1f1db0b5ebce893fab508d5dfc5fa13 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:47:09 -0700 Subject: [PATCH 16/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- .../ApolloClient/multiple-results.test.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/core/__tests__/ApolloClient/multiple-results.test.ts b/src/core/__tests__/ApolloClient/multiple-results.test.ts index 9c9df0d5dab..f35a7135ffb 100644 --- a/src/core/__tests__/ApolloClient/multiple-results.test.ts +++ b/src/core/__tests__/ApolloClient/multiple-results.test.ts @@ -97,14 +97,12 @@ describe("mutiple results", () => { }, }; const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, errorPolicy: "ignore", @@ -114,7 +112,7 @@ describe("mutiple results", () => { // fire off first result link.simulateResult({ result: { data: initialData } }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: initialData, loading: false, networkStatus: 7, @@ -124,7 +122,7 @@ describe("mutiple results", () => { result: { errors: [new GraphQLError("defer failed")] }, }); - await expect(stream).toEmitValueStrict({ + await expect(stream).toEmitApolloQueryResult({ data: undefined, loading: false, networkStatus: 7, @@ -133,7 +131,7 @@ describe("mutiple results", () => { await wait(20); link.simulateResult({ result: { data: laterData } }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: laterData, loading: false, networkStatus: 7, From aff9e3fd768ff9cbdac34ffa6c607308e21df76f Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:47:40 -0700 Subject: [PATCH 17/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- .../ApolloClient/multiple-results.test.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/core/__tests__/ApolloClient/multiple-results.test.ts b/src/core/__tests__/ApolloClient/multiple-results.test.ts index f35a7135ffb..3c908e69d9e 100644 --- a/src/core/__tests__/ApolloClient/multiple-results.test.ts +++ b/src/core/__tests__/ApolloClient/multiple-results.test.ts @@ -165,14 +165,12 @@ describe("mutiple results", () => { }, }; const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, errorPolicy: "ignore", @@ -182,7 +180,7 @@ describe("mutiple results", () => { // fire off first result link.simulateResult({ result: { data: initialData } }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: initialData, loading: false, networkStatus: 7, @@ -196,7 +194,7 @@ describe("mutiple results", () => { }, }); - await expect(stream).toEmitValueStrict({ + await expect(stream).toEmitApolloQueryResult({ data: laterData, loading: false, networkStatus: 7, From 2267e7ca4edd7e2affc9b3a268d395fc20c18785 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:48:51 -0700 Subject: [PATCH 18/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- .../ApolloClient/multiple-results.test.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/core/__tests__/ApolloClient/multiple-results.test.ts b/src/core/__tests__/ApolloClient/multiple-results.test.ts index 3c908e69d9e..5acdfbd39e6 100644 --- a/src/core/__tests__/ApolloClient/multiple-results.test.ts +++ b/src/core/__tests__/ApolloClient/multiple-results.test.ts @@ -228,14 +228,12 @@ describe("mutiple results", () => { }, }; const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, errorPolicy: "all", @@ -245,7 +243,7 @@ describe("mutiple results", () => { // fire off first result link.simulateResult({ result: { data: initialData } }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: initialData, loading: false, networkStatus: 7, @@ -256,7 +254,7 @@ describe("mutiple results", () => { error: new Error("defer failed"), }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: initialData, loading: false, networkStatus: 7, @@ -265,7 +263,7 @@ describe("mutiple results", () => { link.simulateResult({ result: { data: laterData } }); - await expect(stream).toEmitValueStrict({ + await expect(stream).toEmitApolloQueryResult({ data: laterData, loading: false, networkStatus: 7, From 5b92f5f173d3fc82e85341f4dce00ae9056b9ea7 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:49:22 -0700 Subject: [PATCH 19/21] Replace instantiation of QueryManager with instantiation of ApolloClient --- .../ApolloClient/multiple-results.test.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/__tests__/ApolloClient/multiple-results.test.ts b/src/core/__tests__/ApolloClient/multiple-results.test.ts index 5acdfbd39e6..cacf9cb695d 100644 --- a/src/core/__tests__/ApolloClient/multiple-results.test.ts +++ b/src/core/__tests__/ApolloClient/multiple-results.test.ts @@ -290,14 +290,12 @@ describe("mutiple results", () => { }; const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); + const client = new ApolloClient({ + cache: new InMemoryCache({ addTypename: false }), + link, + }); - const observable = queryManager.watchQuery({ + const observable = client.watchQuery({ query, variables: {}, // errorPolicy: 'none', // this is the default @@ -325,7 +323,7 @@ describe("mutiple results", () => { // fire off first result link.simulateResult({ result: { data: initialData } }); - await expect(stream).toEmitValue({ + await expect(stream).toEmitApolloQueryResult({ data: initialData, loading: false, networkStatus: 7, From 444b57128e0b2afb50e6f1a7dbc017f8c9673997 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:49:37 -0700 Subject: [PATCH 20/21] Remove unused imports --- src/core/__tests__/ApolloClient/multiple-results.test.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/core/__tests__/ApolloClient/multiple-results.test.ts b/src/core/__tests__/ApolloClient/multiple-results.test.ts index cacf9cb695d..6122807d97d 100644 --- a/src/core/__tests__/ApolloClient/multiple-results.test.ts +++ b/src/core/__tests__/ApolloClient/multiple-results.test.ts @@ -1,14 +1,7 @@ -// externals import gql from "graphql-tag"; import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; - -// mocks import { MockSubscriptionLink, wait } from "../../../testing/core"; - -// core -import { QueryManager } from "../../QueryManager"; import { GraphQLError } from "graphql"; -import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; import { ObservableStream } from "../../../testing/internal"; import { ApolloError } from "../../../errors"; import { ApolloClient } from "../../ApolloClient"; From 2f5139f72560f1b11f0b61cb124dc3de22088813 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 30 Jan 2025 15:52:05 -0700 Subject: [PATCH 21/21] Remove old multiple-results tests --- .../QueryManager/multiple-results.ts | 347 ------------------ 1 file changed, 347 deletions(-) delete mode 100644 src/core/__tests__/QueryManager/multiple-results.ts diff --git a/src/core/__tests__/QueryManager/multiple-results.ts b/src/core/__tests__/QueryManager/multiple-results.ts deleted file mode 100644 index a8458d0ff13..00000000000 --- a/src/core/__tests__/QueryManager/multiple-results.ts +++ /dev/null @@ -1,347 +0,0 @@ -// externals -import gql from "graphql-tag"; -import { InMemoryCache } from "../../../cache/inmemory/inMemoryCache"; - -// mocks -import { MockSubscriptionLink, wait } from "../../../testing/core"; - -// core -import { QueryManager } from "../../QueryManager"; -import { GraphQLError } from "graphql"; -import { getDefaultOptionsForQueryManagerTests } from "../../../testing/core/mocking/mockQueryManager"; -import { ObservableStream } from "../../../testing/internal"; -import { ApolloError } from "../../../errors"; - -describe("mutiple results", () => { - it("allows multiple query results from link", async () => { - const query = gql` - query LazyLoadLuke { - people_one(id: 1) { - name - friends @defer { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: null, - }, - }; - - const laterData = { - people_one: { - // XXX true defer's wouldn't send this - name: "Luke Skywalker", - friends: [{ name: "Leia Skywalker" }], - }, - }; - const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - }); - const stream = new ObservableStream(observable); - - // fire off first result - link.simulateResult({ result: { data: initialData } }); - - await expect(stream).toEmitValue({ - data: initialData, - loading: false, - networkStatus: 7, - }); - - link.simulateResult({ result: { data: laterData } }); - - await expect(stream).toEmitValue({ - data: laterData, - loading: false, - networkStatus: 7, - }); - }); - - it("allows multiple query results from link with ignored errors", async () => { - const query = gql` - query LazyLoadLuke { - people_one(id: 1) { - name - friends @defer { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: null, - }, - }; - - const laterData = { - people_one: { - // XXX true defer's wouldn't send this - name: "Luke Skywalker", - friends: [{ name: "Leia Skywalker" }], - }, - }; - const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - errorPolicy: "ignore", - }); - const stream = new ObservableStream(observable); - - // fire off first result - link.simulateResult({ result: { data: initialData } }); - - await expect(stream).toEmitValue({ - data: initialData, - loading: false, - networkStatus: 7, - }); - - link.simulateResult({ - result: { errors: [new GraphQLError("defer failed")] }, - }); - - await expect(stream).toEmitValueStrict({ - data: undefined, - loading: false, - networkStatus: 7, - }); - - await wait(20); - link.simulateResult({ result: { data: laterData } }); - - await expect(stream).toEmitValue({ - data: laterData, - loading: false, - networkStatus: 7, - }); - }); - - it("strips errors from a result if ignored", async () => { - const query = gql` - query LazyLoadLuke { - people_one(id: 1) { - name - friends @defer { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: null, - }, - }; - - const laterData = { - people_one: { - // XXX true defer's wouldn't send this - name: "Luke Skywalker", - friends: [{ name: "Leia Skywalker" }], - }, - }; - const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - errorPolicy: "ignore", - }); - const stream = new ObservableStream(observable); - - // fire off first result - link.simulateResult({ result: { data: initialData } }); - - await expect(stream).toEmitValue({ - data: initialData, - loading: false, - networkStatus: 7, - }); - - // this should fire the `next` event without this error - link.simulateResult({ - result: { - errors: [new GraphQLError("defer failed")], - data: laterData, - }, - }); - - await expect(stream).toEmitValueStrict({ - data: laterData, - loading: false, - networkStatus: 7, - }); - }); - - it.skip("allows multiple query results from link with all errors", async () => { - const query = gql` - query LazyLoadLuke { - people_one(id: 1) { - name - friends @defer { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: null, - }, - }; - - const laterData = { - people_one: { - // XXX true defer's wouldn't send this - name: "Luke Skywalker", - friends: [{ name: "Leia Skywalker" }], - }, - }; - const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - errorPolicy: "all", - }); - const stream = new ObservableStream(observable); - - // fire off first result - link.simulateResult({ result: { data: initialData } }); - - await expect(stream).toEmitValue({ - data: initialData, - loading: false, - networkStatus: 7, - }); - - // this should fire the next event again - link.simulateResult({ - error: new Error("defer failed"), - }); - - await expect(stream).toEmitValue({ - data: initialData, - loading: false, - networkStatus: 7, - errors: [new Error("defer failed")], - }); - - link.simulateResult({ result: { data: laterData } }); - - await expect(stream).toEmitValueStrict({ - data: laterData, - loading: false, - networkStatus: 7, - }); - }); - - it("closes the observable if an error is set with the none policy", async () => { - const query = gql` - query LazyLoadLuke { - people_one(id: 1) { - name - friends @defer { - name - } - } - } - `; - - const initialData = { - people_one: { - name: "Luke Skywalker", - friends: null, - }, - }; - - const link = new MockSubscriptionLink(); - const queryManager = new QueryManager( - getDefaultOptionsForQueryManagerTests({ - cache: new InMemoryCache({ addTypename: false }), - link, - }) - ); - - const observable = queryManager.watchQuery({ - query, - variables: {}, - // errorPolicy: 'none', // this is the default - }); - const stream = new ObservableStream(observable); - - let count = 0; - observable.subscribe({ - next: (result) => { - // errors should never be passed since they are ignored - count++; - if (count === 1) { - expect(result.errors).toBeUndefined(); - } - if (count === 2) { - console.log(new Error("result came after an error")); - } - }, - error: (e) => { - expect(e).toBeDefined(); - expect(e.graphQLErrors).toBeDefined(); - }, - }); - - // fire off first result - link.simulateResult({ result: { data: initialData } }); - - await expect(stream).toEmitValue({ - data: initialData, - loading: false, - networkStatus: 7, - }); - - link.simulateResult({ error: new Error("defer failed") }); - - await expect(stream).toEmitError( - new ApolloError({ networkError: new Error("defer failed") }) - ); - }); -});