From 09c103002d965cd4a152587105ebd633cec22266 Mon Sep 17 00:00:00 2001 From: hayes-mysten <135670682+hayes-mysten@users.noreply.github.com> Date: Tue, 24 Oct 2023 08:57:17 -0700 Subject: [PATCH] =?UTF-8?q?Add=20tests=20for=20query=20hooks=20and=20fix?= =?UTF-8?q?=20pagination=20in=20useSuiClientInfiniteQ=E2=80=A6=20(#14344)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …uery ## Description Describe the changes or additions included in this PR. ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes --- .changeset/selfish-readers-marry.md | 5 ++ .../src/hooks/useSuiClientInfiniteQuery.ts | 22 +++-- .../hooks/useSuiClientInfiniteQuery.test.tsx | 82 +++++++++++++++++++ .../test/hooks/useSuiClientMutation.test.tsx | 49 +++++++++++ .../test/hooks/useSuiClientQuery.test.tsx | 51 ++++++++++++ 5 files changed, 197 insertions(+), 12 deletions(-) create mode 100644 .changeset/selfish-readers-marry.md create mode 100644 sdk/dapp-kit/test/hooks/useSuiClientInfiniteQuery.test.tsx create mode 100644 sdk/dapp-kit/test/hooks/useSuiClientMutation.test.tsx create mode 100644 sdk/dapp-kit/test/hooks/useSuiClientQuery.test.tsx diff --git a/.changeset/selfish-readers-marry.md b/.changeset/selfish-readers-marry.md new file mode 100644 index 0000000000000..acd5b1107626c --- /dev/null +++ b/.changeset/selfish-readers-marry.md @@ -0,0 +1,5 @@ +--- +'@mysten/dapp-kit': patch +--- + +fix pagination in useSuiClientInfiniteQuery diff --git a/sdk/dapp-kit/src/hooks/useSuiClientInfiniteQuery.ts b/sdk/dapp-kit/src/hooks/useSuiClientInfiniteQuery.ts index d0b77dfae8592..9ce7807dc3a7b 100644 --- a/sdk/dapp-kit/src/hooks/useSuiClientInfiniteQuery.ts +++ b/sdk/dapp-kit/src/hooks/useSuiClientInfiniteQuery.ts @@ -17,19 +17,13 @@ export type SuiRpcPaginatedMethodName = { }[keyof SuiClient]; export type SuiRpcPaginatedMethods = { - [K in SuiRpcPaginatedMethodName]: SuiClient[K] extends (input: infer P) => Promise<{ - data?: infer R; - nextCursor?: infer Cursor | null; - hasNextPage: boolean; - }> + [K in SuiRpcPaginatedMethodName]: SuiClient[K] extends ( + input: infer Params, + ) => Promise ? { name: K; - result: { - data?: R; - nextCursor?: Cursor | null; - hasNextPage: boolean; - }; - params: P; + result: Result; + params: Params; cursor: Cursor; } : never; @@ -57,7 +51,11 @@ export function useSuiClientInfiniteQuery suiContext.client[method](params as never), + queryFn: ({ pageParam }) => + suiContext.client[method]({ + ...(params ?? {}), + cursor: pageParam, + } as never), getNextPageParam: (lastPage) => { return (lastPage as PaginatedResult).nextCursor ?? null; }, diff --git a/sdk/dapp-kit/test/hooks/useSuiClientInfiniteQuery.test.tsx b/sdk/dapp-kit/test/hooks/useSuiClientInfiniteQuery.test.tsx new file mode 100644 index 0000000000000..3a747153836b3 --- /dev/null +++ b/sdk/dapp-kit/test/hooks/useSuiClientInfiniteQuery.test.tsx @@ -0,0 +1,82 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; +import { act, renderHook, waitFor } from '@testing-library/react'; + +import { useSuiClientInfiniteQuery } from '../../src/hooks/useSuiClientInfiniteQuery.js'; +import { createWalletProviderContextWrapper } from '../test-utils.js'; + +describe('useSuiClientInfiniteQuery', () => { + it('should fetch data', async () => { + const suiClient = new SuiClient({ url: getFullnodeUrl('mainnet') }); + const wrapper = createWalletProviderContextWrapper({}, suiClient); + + const queryTransactionBlocks = vi.spyOn(suiClient, 'queryTransactionBlocks'); + + const pages = [ + { + data: [{ digest: '0x123' }], + hasNextPage: true, + nextCursor: 'page2', + }, + { + data: [{ digest: '0x456' }], + hasNextPage: false, + nextCursor: null, + }, + ]; + + queryTransactionBlocks.mockResolvedValueOnce(pages[0]); + + const { result } = renderHook( + () => + useSuiClientInfiniteQuery('queryTransactionBlocks', { + filter: { + FromAddress: '0x123', + }, + }), + { wrapper }, + ); + + expect(result.current.isLoading).toBe(true); + expect(result.current.isError).toBe(false); + expect(result.current.data).toBe(undefined); + expect(queryTransactionBlocks).toHaveBeenCalledWith({ + filter: { + FromAddress: '0x123', + }, + }); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + expect(result.current.isLoading).toBe(false); + expect(result.current.isError).toBe(false); + expect(result.current.data).toEqual({ + pageParams: [undefined], + pages: [pages[0]], + }); + + queryTransactionBlocks.mockResolvedValueOnce(pages[1]); + + await act(() => { + result.current.fetchNextPage(); + }); + + await waitFor(() => expect(result.current.isFetchingNextPage).toBe(false)); + + expect(result.current.isLoading).toBe(false); + expect(result.current.isError).toBe(false); + expect(result.current.data).toEqual({ + pageParams: [undefined, 'page2'], + pages: [pages[0], pages[1]], + }); + expect(result.current.data?.pages[0].data[0].digest).toBe('0x123'); + + expect(queryTransactionBlocks).toHaveBeenCalledWith({ + filter: { + FromAddress: '0x123', + }, + cursor: 'page2', + }); + }); +}); diff --git a/sdk/dapp-kit/test/hooks/useSuiClientMutation.test.tsx b/sdk/dapp-kit/test/hooks/useSuiClientMutation.test.tsx new file mode 100644 index 0000000000000..3d7b51d84deca --- /dev/null +++ b/sdk/dapp-kit/test/hooks/useSuiClientMutation.test.tsx @@ -0,0 +1,49 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; +import { act, renderHook, waitFor } from '@testing-library/react'; + +import { useSuiClientMutation } from '../../src/hooks/useSuiClientMutation.js'; +import { createWalletProviderContextWrapper } from '../test-utils.js'; + +describe('useSuiClientMutation', () => { + it('should fetch data', async () => { + const suiClient = new SuiClient({ url: getFullnodeUrl('mainnet') }); + const wrapper = createWalletProviderContextWrapper({}, suiClient); + + const queryTransactionBlocks = vi.spyOn(suiClient, 'queryTransactionBlocks'); + + queryTransactionBlocks.mockResolvedValueOnce({ + data: [{ digest: '0x123' }], + hasNextPage: true, + nextCursor: 'page2', + }); + + const { result } = renderHook(() => useSuiClientMutation('queryTransactionBlocks'), { + wrapper, + }); + + act(() => { + result.current.mutate({ + filter: { + FromAddress: '0x123', + }, + }); + }); + + await waitFor(() => expect(result.current.status).toBe('success')); + + expect(queryTransactionBlocks).toHaveBeenCalledWith({ + filter: { + FromAddress: '0x123', + }, + }); + expect(result.current.isLoading).toBe(false); + expect(result.current.isError).toBe(false); + expect(result.current.data).toEqual({ + data: [{ digest: '0x123' }], + hasNextPage: true, + nextCursor: 'page2', + }); + }); +}); diff --git a/sdk/dapp-kit/test/hooks/useSuiClientQuery.test.tsx b/sdk/dapp-kit/test/hooks/useSuiClientQuery.test.tsx new file mode 100644 index 0000000000000..7d87c057a9152 --- /dev/null +++ b/sdk/dapp-kit/test/hooks/useSuiClientQuery.test.tsx @@ -0,0 +1,51 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 +import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; +import { renderHook, waitFor } from '@testing-library/react'; + +import { useSuiClientQuery } from '../../src/hooks/useSuiClientQuery.js'; +import { createWalletProviderContextWrapper } from '../test-utils.js'; + +describe('useSuiClientQuery', () => { + it('should fetch data', async () => { + const suiClient = new SuiClient({ url: getFullnodeUrl('mainnet') }); + const wrapper = createWalletProviderContextWrapper({}, suiClient); + + const queryTransactionBlocks = vi.spyOn(suiClient, 'queryTransactionBlocks'); + + queryTransactionBlocks.mockResolvedValueOnce({ + data: [{ digest: '0x123' }], + hasNextPage: true, + nextCursor: 'page2', + }); + + const { result } = renderHook( + () => + useSuiClientQuery('queryTransactionBlocks', { + filter: { + FromAddress: '0x123', + }, + }), + { wrapper }, + ); + + expect(result.current.isLoading).toBe(true); + expect(result.current.isError).toBe(false); + expect(result.current.data).toBe(undefined); + expect(queryTransactionBlocks).toHaveBeenCalledWith({ + filter: { + FromAddress: '0x123', + }, + }); + + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + + expect(result.current.isLoading).toBe(false); + expect(result.current.isError).toBe(false); + expect(result.current.data).toEqual({ + data: [{ digest: '0x123' }], + hasNextPage: true, + nextCursor: 'page2', + }); + }); +});