Merge pull request 'Create higher order component that wraps display components' (#12) from create-query-hoc into master
Reviewed-on: billnerds/rn-playground#12
This commit is contained in:
		
							
								
								
									
										42
									
								
								component/with-query-handling.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								component/with-query-handling.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -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<any>;
 | 
			
		||||
	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 <Text>Loading...</Text>;
 | 
			
		||||
		}
 | 
			
		||||
		if (error) {
 | 
			
		||||
			return <Text>Error: {error.message}</Text>;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const specificData = data[dataKey];
 | 
			
		||||
		return <WrappedComponent {...props} data={specificData} />;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default withQueryHandling;
 | 
			
		||||
@@ -39,6 +39,8 @@
 | 
			
		||||
    },
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@babel/core": "^7.20.0",
 | 
			
		||||
        "@testing-library/jest-native": "^5.4.3",
 | 
			
		||||
        "@testing-library/react-native": "^12.4.3",
 | 
			
		||||
        "@types/jest": "^29.5.11",
 | 
			
		||||
        "eslint-config-prettier": "^9.1.0"
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										65
									
								
								test/component/with-query-handling.test.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								test/component/with-query-handling.test.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -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 }) => (
 | 
			
		||||
	<Text>{data ? data : "No Data"}</Text>
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
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(<WrappedComponent />);
 | 
			
		||||
		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(<WrappedComponent />);
 | 
			
		||||
		expect(getByText("shots")).toBeTruthy();
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										46
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -2238,6 +2238,26 @@
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@sinonjs/commons" "^3.0.0"
 | 
			
		||||
 | 
			
		||||
"@testing-library/jest-native@^5.4.3":
 | 
			
		||||
  version "5.4.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@testing-library/jest-native/-/jest-native-5.4.3.tgz#9334c68eaf45db9eb20d0876728cc5d7fc2c3ea2"
 | 
			
		||||
  integrity sha512-/sSDGaOuE+PJ1Z9Kp4u7PQScSVVXGud59I/qsBFFJvIbcn4P6yYw6cBnBmbPF+X9aRIsTJRDl6gzw5ZkJNm66w==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    chalk "^4.1.2"
 | 
			
		||||
    jest-diff "^29.0.1"
 | 
			
		||||
    jest-matcher-utils "^29.0.1"
 | 
			
		||||
    pretty-format "^29.0.3"
 | 
			
		||||
    redent "^3.0.0"
 | 
			
		||||
 | 
			
		||||
"@testing-library/react-native@^12.4.3":
 | 
			
		||||
  version "12.4.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@testing-library/react-native/-/react-native-12.4.3.tgz#57cd6a88b289f19144558b5e97336b57101af3ec"
 | 
			
		||||
  integrity sha512-WLE7VbbR5jZJQl3vfNK7Wt+IHnzhOxyu95Mr56EHmzH3XhC8DkrPVAnUq9asq/QWj4aGnymbinFx6zZys/WZmA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    jest-matcher-utils "^29.7.0"
 | 
			
		||||
    pretty-format "^29.7.0"
 | 
			
		||||
    redent "^3.0.0"
 | 
			
		||||
 | 
			
		||||
"@tootallnate/once@2":
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
 | 
			
		||||
@@ -5503,7 +5523,7 @@ jest-config@^29.7.0:
 | 
			
		||||
    slash "^3.0.0"
 | 
			
		||||
    strip-json-comments "^3.1.1"
 | 
			
		||||
 | 
			
		||||
jest-diff@^29.7.0:
 | 
			
		||||
jest-diff@^29.0.1, jest-diff@^29.7.0:
 | 
			
		||||
  version "29.7.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a"
 | 
			
		||||
  integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
 | 
			
		||||
@@ -5605,7 +5625,7 @@ jest-leak-detector@^29.7.0:
 | 
			
		||||
    jest-get-type "^29.6.3"
 | 
			
		||||
    pretty-format "^29.7.0"
 | 
			
		||||
 | 
			
		||||
jest-matcher-utils@^29.7.0:
 | 
			
		||||
jest-matcher-utils@^29.0.1, jest-matcher-utils@^29.7.0:
 | 
			
		||||
  version "29.7.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12"
 | 
			
		||||
  integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==
 | 
			
		||||
@@ -6613,6 +6633,11 @@ mimic-fn@^2.1.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
 | 
			
		||||
  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
 | 
			
		||||
 | 
			
		||||
min-indent@^1.0.0:
 | 
			
		||||
  version "1.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
 | 
			
		||||
  integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
 | 
			
		||||
 | 
			
		||||
"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
 | 
			
		||||
  version "3.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
 | 
			
		||||
@@ -7279,7 +7304,7 @@ pretty-format@^26.5.2, pretty-format@^26.6.2:
 | 
			
		||||
    ansi-styles "^4.0.0"
 | 
			
		||||
    react-is "^17.0.1"
 | 
			
		||||
 | 
			
		||||
pretty-format@^29.0.0, pretty-format@^29.7.0:
 | 
			
		||||
pretty-format@^29.0.0, pretty-format@^29.0.3, pretty-format@^29.7.0:
 | 
			
		||||
  version "29.7.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
 | 
			
		||||
  integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
 | 
			
		||||
@@ -7549,6 +7574,14 @@ recast@^0.21.0:
 | 
			
		||||
    source-map "~0.6.1"
 | 
			
		||||
    tslib "^2.0.1"
 | 
			
		||||
 | 
			
		||||
redent@^3.0.0:
 | 
			
		||||
  version "3.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
 | 
			
		||||
  integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    indent-string "^4.0.0"
 | 
			
		||||
    strip-indent "^3.0.0"
 | 
			
		||||
 | 
			
		||||
reflect.getprototypeof@^1.0.4:
 | 
			
		||||
  version "1.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3"
 | 
			
		||||
@@ -8247,6 +8280,13 @@ strip-final-newline@^2.0.0:
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
 | 
			
		||||
  integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
 | 
			
		||||
 | 
			
		||||
strip-indent@^3.0.0:
 | 
			
		||||
  version "3.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
 | 
			
		||||
  integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    min-indent "^1.0.0"
 | 
			
		||||
 | 
			
		||||
strip-json-comments@^3.1.1:
 | 
			
		||||
  version "3.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user