From 78d40f1abcb0cd7d5964d3bc4a6ae7f94b32648b Mon Sep 17 00:00:00 2001 From: Kat Huang Date: Mon, 8 Jan 2024 15:57:12 -0700 Subject: [PATCH] Create with query wrapper --- component/with-query-handling.tsx | 42 +++++++++++++ test/component/with-query-handling.test.tsx | 65 +++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 component/with-query-handling.tsx create mode 100644 test/component/with-query-handling.test.tsx diff --git a/component/with-query-handling.tsx b/component/with-query-handling.tsx new file mode 100644 index 0000000..9771452 --- /dev/null +++ b/component/with-query-handling.tsx @@ -0,0 +1,42 @@ +import React from "react"; +import { useQuery, DocumentNode, OperationVariables } from "@apollo/client"; +import { Text } from "react-native"; +/** + * A higher-order component that provides loading and error handling for GraphQL queries. + * @param {React.ComponentType} WrappedComponent - The component to wrap. + * @param {DocumentNode} query - The GraphQL query to execute. + * @param {string} dataKey - The key in the data object to pass to the wrapped component. + * @param {Object} queryOptions - Optional. Additional options for the Apollo query. + * @returns {React.ComponentType} A component that renders the WrappedComponent with loading and error handling. + */ +/* eslint-disable react/display-name */ +type WithQueryHandlingProps = { + WrappedComponent: React.ComponentType; + query: DocumentNode; + dataKey: string; + queryOptions?: OperationVariables; +}; + +function withQueryHandling({ + WrappedComponent, + query, + dataKey, + queryOptions = {}, +}: WithQueryHandlingProps) { + return function (props: any) { + // You can replace 'any' with specific props type if known + const { loading, error, data } = useQuery(query, queryOptions); + + if (loading) { + return Loading...; + } + if (error) { + return Error: {error.message}; + } + + const specificData = data[dataKey]; + return ; + }; +} + +export default withQueryHandling; diff --git a/test/component/with-query-handling.test.tsx b/test/component/with-query-handling.test.tsx new file mode 100644 index 0000000..970994d --- /dev/null +++ b/test/component/with-query-handling.test.tsx @@ -0,0 +1,65 @@ +import React from "react"; +import { render, cleanup, waitFor } from "@testing-library/react-native"; +import "@testing-library/jest-native/extend-expect"; +import { gql, useQuery } from "@apollo/client"; +import withQueryHandling from "../../component/with-query-handling"; +import { Text } from "react-native"; + +jest.mock("@apollo/client", () => ({ + ...jest.requireActual("@apollo/client"), + useQuery: jest.fn(), +})); + +const MockComponent: React.FC<{ data?: string }> = ({ data }) => ( + {data ? data : "No Data"} +); + +const MOCK_QUERY = gql` + query GetMockData { + mockData { + id + name + description + } + } +`; + +describe("withQueryHandling HOC Tests", () => { + afterEach(() => { + jest.clearAllMocks(); + cleanup(); + }); + + it("should render loading state initially", async () => { + (useQuery as jest.Mock).mockReturnValue({ + loading: true, + error: undefined, + data: undefined, + }); + const WrappedComponent = withQueryHandling({ + WrappedComponent: MockComponent, + query: MOCK_QUERY, + dataKey: "mockDataKey", + }); + const { getByText } = render(); + await waitFor(() => { + expect(getByText("Loading...")).toBeTruthy(); + }); + }); + + it("should render the wrapped component with data", () => { + const mockData = { getShots: "shots" }; + (useQuery as jest.Mock).mockReturnValue({ + loading: false, + error: undefined, + data: mockData, + }); + const WrappedComponent = withQueryHandling({ + WrappedComponent: MockComponent, + query: MOCK_QUERY, + dataKey: "getShots", + }); + const { getByText } = render(); + expect(getByText("shots")).toBeTruthy(); + }); +});