Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/apollo-mock-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"devDependencies": {
"@apollo/client": ">= 3.3.0 < 3.7.0",
"@graphitation/apollo-forest-run": "^0.21.1",
"@graphitation/graphql-js-tag": "^0.11.0",
"@graphitation/graphql-js-operation-payload-generator": "^0.13.1",
"@types/invariant": "^2.2.34",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { buildSchema, DocumentNode } from "graphql";
import * as ReactTestRenderer from "react-test-renderer";
import {
ApolloProvider,
InMemoryCache,
useMutation,
useQuery,
useSubscription,
Expand Down Expand Up @@ -633,3 +634,101 @@ describe("ReactRelayTestMocker with Containers", () => {
});
});
});

describe("createMockClient with cacheFactory", () => {
it("should use the default InMemoryCache when no cacheFactory is provided", () => {
const client = createMockClient(schema);
expect(client.cache).toBeInstanceOf(InMemoryCache);
});

it("should use the cache returned by cacheFactory when provided", () => {
const cacheFactory = jest.fn(
(possibleTypes: Record<string, string[]>) =>
new InMemoryCache({ possibleTypes }),
);
const client = createMockClient(schema, { cacheFactory });
expect(cacheFactory).toHaveBeenCalledTimes(1);
expect(cacheFactory).toHaveBeenCalledWith(
expect.objectContaining({}),
);
expect(client.cache).toBeInstanceOf(InMemoryCache);
});

it("should pass possibleTypes derived from the schema to cacheFactory", () => {
const cacheFactory = jest.fn(
(possibleTypes: Record<string, string[]>) =>
new InMemoryCache({ possibleTypes }),
);
createMockClient(schema, { cacheFactory });
const possibleTypes = cacheFactory.mock.calls[0][0];
expect(typeof possibleTypes).toBe("object");
// The test schema has abstract types (e.g. Node interface), so possibleTypes should not be empty
expect(Object.keys(possibleTypes).length).toBeGreaterThan(0);
});
});

describe("createMockClient with ForestRun cache", () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { ForestRun } = require("@graphitation/apollo-forest-run");

it("should work with ForestRun cache via cacheFactory", () => {
const client = createMockClient(schema, {
cacheFactory: (possibleTypes) =>
new ForestRun({ possibleTypes }),
});
expect(client.cache).toBeInstanceOf(ForestRun);
});

it("should resolve a query when using ForestRun cache", async () => {
const TestQuery = graphql`
query ForestRunCacheTestQuery($id: ID = "<default>") {
user: node(id: $id) {
id
name
}
}
`;

const client = createMockClient(schema, {
cacheFactory: (possibleTypes) =>
new ForestRun({ possibleTypes }),
});

const TestComponent: React.FC = () => {
const { data: props, error } = useQuery<{
user: { id: string; name: string };
}>(TestQuery as any);
if (props) {
return (
`My id ${props.user.id} and name is ${props.user.name}` as any
);
} else if (error) {
return <div id="error">{error.message}</div>;
}
return <div id="loading">Loading...</div>;
};

let testComponentTree!: ReactTestRenderer.ReactTestRenderer;
ReactTestRenderer.act(() => {
testComponentTree = ReactTestRenderer.create(
<ApolloProvider client={client}>
<TestComponent />
</ApolloProvider>,
);
});

// Should render loading state
expect(() => {
testComponentTree.root.find((node) => node.props.id === "loading");
}).not.toThrow();

await ReactTestRenderer.act(() =>
client.mock.resolveMostRecentOperation((operation) =>
MockPayloadGenerator.generate(operation),
),
);

// Should render data from resolved operation
expect(testComponentTree).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,5 @@ exports[`ReactRelayTestMocker with Containers resolve/reject next with component
&lt;mock-value-for-field-"name"&gt;
</div>
`;

exports[`createMockClient with ForestRun cache should resolve a query when using ForestRun cache 1`] = `"My id <mock-id-1> and name is <mock-value-for-field-"name">"`;
22 changes: 16 additions & 6 deletions packages/apollo-mock-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
InMemoryCache,
} from "@apollo/client";
import type {
ApolloCache,
Operation,
FetchResult,
NormalizedCacheObject,
Expand Down Expand Up @@ -318,7 +319,12 @@ class Mock implements MockFunctions {

export function createMockClient(
schema: GraphQLSchema,
options?: { cache?: InMemoryCacheConfig },
options?: {
cache?: InMemoryCacheConfig;
cacheFactory?: (
possibleTypes: Record<string, string[]>,
) => ApolloCache<NormalizedCacheObject>;
},
): ApolloMockClient {
// Build a list of abstract types and their possible types.
// TODO: Cache this on the schema?
Expand All @@ -335,16 +341,20 @@ export function createMockClient(

const link = new MockLink(schema);

const cache = options?.cacheFactory
? options.cacheFactory(possibleTypes)
: new InMemoryCache({
addTypename: true,
...options?.cache,
possibleTypes,
});

return Object.assign<
ApolloClient<NormalizedCacheObject>,
ApolloClientExtension
>(
new ApolloClient({
cache: new InMemoryCache({
addTypename: true,
...options?.cache,
possibleTypes,
}),
cache,
link,
}),
{
Expand Down
1 change: 1 addition & 0 deletions packages/apollo-mock-client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
"include": ["src"],
"references": [
{ "path": "../apollo-forest-run" },
{ "path": "../graphql-js-tag" },
{ "path": "../graphql-js-operation-payload-generator" }
]
Expand Down
Loading