Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to react-query@5 #179

Merged
merged 9 commits into from
Oct 23, 2023
Merged
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
2 changes: 1 addition & 1 deletion examples/react/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@connectrpc/connect-web": "^1.1.2",
"@connectrpc/protoc-gen-connect-es": "^1.1.2",
"@connectrpc/protoc-gen-connect-query": "^0.5.1",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-query": "^5.0.0",
"@tanstack/react-query-devtools": "^4.36.1",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/react": "^14.0.0",
Expand Down
14 changes: 4 additions & 10 deletions examples/react/basic/src/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,15 @@ import { Page } from "./page";
* This example demonstrates a basic usage of Connect-Query with `useQuery`
*/
export const Example: FC = () => {
const {
status,
fetchStatus,
error,
//^? const error: ConnectError | null
data,
//^? const data: SayResponse | undefined
} = useQuery(say.useQuery({}));
// ^? const say: UnaryHooks<SayRequest, SayResponse>
const { status, fetchStatus, error, data } = useQuery({
...say.useQuery({}),
});

return (
<Page>
Status: {status}
<Indicators label="queryStatus">
<Indicator label="loading" parent={status} />
<Indicator label="pending" parent={status} />
<Indicator label="success" parent={status} />
<Indicator label="error" parent={status} />
</Indicators>
Expand Down
4 changes: 2 additions & 2 deletions packages/connect-query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"@connectrpc/connect": "^1.1.2",
"@connectrpc/connect-web": "^1.1.2",
"@connectrpc/protoc-gen-connect-es": "^1.1.2",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-query": "^5.0.0",
"@testing-library/react": "^14.0.0",
"@types/react": "^18.2.30",
"@types/react-dom": "^18.2.14",
Expand All @@ -52,7 +52,7 @@
"peerDependencies": {
"@bufbuild/protobuf": "^1.3.3",
"@connectrpc/connect": "^1.1.2",
"@tanstack/react-query": "4.x",
"@tanstack/react-query": "^5.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
196 changes: 39 additions & 157 deletions packages/connect-query/src/create-unary-functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,17 @@ import type {
PartialMessage,
} from "@bufbuild/protobuf";
import { MethodKind } from "@bufbuild/protobuf";
import type { CallOptions, ConnectError, Transport } from "@connectrpc/connect";
import {
afterAll,
beforeEach,
describe,
expect,
it,
jest,
} from "@jest/globals";
import type { CallOptions, Transport } from "@connectrpc/connect";
import { Code, ConnectError } from "@connectrpc/connect";
import { describe, expect, it, jest } from "@jest/globals";
import type {
GetNextPageParamFunction,
QueryFunction,
QueryFunctionContext,
UseMutationResult,
} from "@tanstack/react-query";
import { useInfiniteQuery, useMutation, useQuery } from "@tanstack/react-query";
import { renderHook, waitFor } from "@testing-library/react";
import { spyOn } from "jest-mock";

import type {
ConnectPartialQueryKey,
Expand Down Expand Up @@ -62,8 +56,6 @@ import {
import type { DisableQuery } from "./utils";
import { disableQuery } from "./utils";

const consoleErrorSpy = spyOn(console, "error").mockImplementation(() => {});

const genCount = createUnaryFunctions({
methodInfo: BigIntService.methods.count,
typeName: BigIntService.typeName,
Expand Down Expand Up @@ -175,7 +167,7 @@ describe("createUnaryFunctions", () => {

describe("setQueriesData", () => {
it("returns the correct queryKey", () => {
const [queryKey] = genCount.setQueriesData(partialUpdater);
const [{ queryKey }] = genCount.setQueriesData(partialUpdater);
type ExpectType_QueryKey = Expect<
Equal<typeof queryKey, ConnectPartialQueryKey>
>;
Expand Down Expand Up @@ -302,7 +294,12 @@ describe("createUnaryFunctions", () => {
>;

type ExpectType_UseInfiniteQueryParams0 = Expect<
Equal<params[0], DisableQuery | PartialMessage<CountRequest>>
Equal<
params[0],
| DisableQuery
| (PartialMessage<CountRequest> &
Required<Pick<PartialMessage<CountRequest>, "add">>)
>
>;

type returnType = ReturnType<
Expand All @@ -312,7 +309,12 @@ describe("createUnaryFunctions", () => {
type ExpectType_UseInfiniteQueryReturnKeys = Expect<
Equal<
keyof returnType,
"enabled" | "getNextPageParam" | "onError" | "queryFn" | "queryKey"
| "enabled"
| "getNextPageParam"
| "initialPageParam"
| "queryFn"
| "queryKey"
| "throwOnError"
>
>;

Expand All @@ -322,14 +324,17 @@ describe("createUnaryFunctions", () => {
{
enabled: boolean;
queryKey: ConnectQueryKey<CountRequest>;
queryFn: (
context: QueryFunctionContext<
ConnectQueryKey<CountRequest>,
bigint | undefined
>,
) => Promise<CountResponse>;
getNextPageParam: GetNextPageParamFunction<CountResponse>;
onError?: (error: ConnectError) => void;
queryFn: QueryFunction<
CountResponse,
ConnectQueryKey<CountRequest>,
bigint | undefined
>;
getNextPageParam: GetNextPageParamFunction<
bigint | undefined,
CountResponse
>;
throwOnError?: (error: ConnectError) => boolean;
initialPageParam: bigint | undefined;
}
>
>;
Expand Down Expand Up @@ -377,7 +382,9 @@ describe("createUnaryFunctions", () => {
it("requires a transport", () => {
expect(() => {
genCount.createUseInfiniteQueryOptions(
{},
{
add: 0n,
},
{
getNextPageParam: (lastPage) => lastPage.count + 1n,
pageParamKey: "add",
Expand All @@ -404,14 +411,10 @@ describe("createUnaryFunctions", () => {
wrapper({ defaultOptions }),
);

expect(result.current.data).toStrictEqual(undefined);

await waitFor(() => {
expect(result.current.isSuccess).toBeTruthy();
});

expect(result.current.data?.pageParams).toStrictEqual([undefined]);

expect(result.current.data?.pages).toHaveLength(1);
expect(result.current.data?.pages[0].page).toStrictEqual(1n);
expect(result.current.data?.pages[0].items).toStrictEqual([
Expand All @@ -424,8 +427,6 @@ describe("createUnaryFunctions", () => {
await result.current.fetchNextPage();
rerender();

expect(result.current.data?.pageParams).toStrictEqual([undefined, 2n]);

expect(result.current.data?.pages).toHaveLength(2);
expect(result.current.data?.pages[1].page).toStrictEqual(2n);
expect(result.current.data?.pages[1].items).toStrictEqual([
Expand Down Expand Up @@ -489,70 +490,13 @@ describe("createUnaryFunctions", () => {
pageParam: 1n,
queryKey: genCount.getQueryKey(input),
meta: {},
direction: "forward",
signal: new AbortController().signal,
});

expect(count).toStrictEqual(1n);
});

describe("onError", () => {
beforeEach(() => {
consoleErrorSpy.mockReset();
});

it("doesn't use onError if it isn't passed", () => {
const { result } = renderHook(
() =>
genCount.createUseInfiniteQueryOptions(
{},
{
pageParamKey: "add",
getNextPageParam: (lastPage) => lastPage.count,
transport: mockEliza(),
},
),
wrapper(),
);
expect(result.current.onError).toBeUndefined();
expect(consoleErrorSpy).not.toHaveBeenCalled();
});

it("allows for a passthrough onError", async () => {
const onError = jest.fn();
const { result, rerender } = renderHook(
() =>
useQuery({
...genCount.createUseInfiniteQueryOptions(
// @ts-expect-error(2345) intentionally invalid input
{ nope: "nope nope" },
{ onError, pageParamKey: "add", transport: mockEliza() },
),
queryFn: async () => Promise.reject("error"),
retry: false,
}),
wrapper(undefined, mockBigInt()),
);
rerender();

expect(result.current.error).toStrictEqual(null);
expect(result.current.isError).toStrictEqual(false);
expect(onError).toHaveBeenCalledTimes(0);
expect(consoleErrorSpy).not.toHaveBeenCalled();

await waitFor(
() => {
expect(result.current.error).toStrictEqual("error");
},
{
timeout: 300,
},
);

expect(result.current.isError).toStrictEqual(true);
expect(onError).toHaveBeenCalledTimes(1);
expect(consoleErrorSpy).toHaveBeenCalledWith("error");
});
});

it("passes through callOptions", () => {
const transport = mockBigInt();
const transportSpy = jest.spyOn(transport, "unary");
Expand Down Expand Up @@ -844,8 +788,9 @@ describe("createUnaryFunctions", () => {
onError,
transport: mockBigInt(),
}),
mutationFn: async () => Promise.reject("error"),
mutationKey: genCount.getQueryKey(),
mutationFn: () => {
throw new ConnectError("error", Code.Aborted);
},
}),
wrapper({ defaultOptions }),
);
Expand All @@ -855,7 +800,6 @@ describe("createUnaryFunctions", () => {
expect(result.current.error).toStrictEqual(null);
expect(result.current.isError).toStrictEqual(false);
expect(onError).toHaveBeenCalledTimes(0);
expect(consoleErrorSpy).toHaveBeenCalled();

type ExpectType_Error = Expect<
Equal<typeof result.current.error, ConnectError | null>
Expand All @@ -865,10 +809,9 @@ describe("createUnaryFunctions", () => {

await sleep(10);

expect(result.current.error).toStrictEqual("error");
expect(result.current.error?.code).toStrictEqual(Code.Aborted);
expect(result.current.isError).toStrictEqual(true);
expect(onError).toHaveBeenCalledTimes(1);
expect(consoleErrorSpy).toHaveBeenCalledWith("error");
});

it("makes a mutation", async () => {
Expand Down Expand Up @@ -986,7 +929,6 @@ describe("createUnaryFunctions", () => {
getPlaceholderData?: (
enabled: boolean,
) => PartialMessage<SayResponse> | undefined;
onError?: (error: ConnectError) => void;
transport?: Transport | undefined;
callOptions?: CallOptions | undefined;
}
Expand All @@ -1008,26 +950,19 @@ describe("createUnaryFunctions", () => {
context?: QueryFunctionContext<ConnectQueryKey<SayRequest>>,
) => Promise<SayResponse>;
placeholderData?: () => SayResponse | undefined;
onError?: (error: ConnectError) => void;
throwOnError?: (error: ConnectError) => boolean;
}
>
>;

const result = genSay.createUseQueryOptions(undefined, {
onError: jest.fn(),
getPlaceholderData: jest.fn(() => new SayResponse()),
transport: mockEliza(),
});

expect(
Object.keys(result).sort((a, b) => a.localeCompare(b)),
).toStrictEqual([
"enabled",
"onError",
"placeholderData",
"queryFn",
"queryKey",
]);
).toStrictEqual(["enabled", "placeholderData", "queryFn", "queryKey"]);
});

describe("enabled", () => {
Expand Down Expand Up @@ -1160,59 +1095,6 @@ describe("createUnaryFunctions", () => {
});
});

describe("onError", () => {
beforeEach(() => {
consoleErrorSpy.mockReset();
});
afterAll(() => {
consoleErrorSpy.mockReset();
});

it("doesn't use onError if it isn't passed", () => {
const result = genSay.createUseQueryOptions(undefined, {
transport: mockEliza(),
});
expect(result.onError).toBeUndefined();
});

it("allows for a passthrough onError", async () => {
const onError = jest.fn();
const { result, rerender } = renderHook(
() =>
useQuery({
...genSay.createUseQueryOptions(
// @ts-expect-error(2345) intentionally invalid input
{ nope: "nope nope" },
{ onError, transport: mockEliza() },
),
queryFn: async () => Promise.reject("error"),
retry: false,
}),
wrapper(),
);
rerender();

expect(result.current.error).toStrictEqual(null);
expect(result.current.isError).toStrictEqual(false);
expect(onError).toHaveBeenCalledTimes(0);
expect(consoleErrorSpy).not.toHaveBeenCalled();

await waitFor(
() => {
expect(result.current.error).toStrictEqual("error");
},
{
timeout: 300,
},
);

expect(result.current.error).toStrictEqual("error");
expect(result.current.isError).toStrictEqual(true);
expect(onError).toHaveBeenCalledTimes(1);
expect(consoleErrorSpy).toHaveBeenCalledWith("error");
});
});

describe("queryFn", () => {
const input: PartialMessage<SayRequest> = { sentence: "ziltoid" };

Expand Down
Loading