mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
fork refine
This commit is contained in:
313
packages/antd/src/hooks/fields/useSelect/index.spec.ts
Normal file
313
packages/antd/src/hooks/fields/useSelect/index.spec.ts
Normal file
@@ -0,0 +1,313 @@
|
||||
import { renderHook, waitFor } from "@testing-library/react";
|
||||
|
||||
import { MockJSONServer, TestWrapper } from "@test";
|
||||
|
||||
import { useSelect } from "./";
|
||||
|
||||
describe("useSelect Hook", () => {
|
||||
it("default", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label: "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("defaultValue", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
defaultValue: ["1", "2", "3", "4"],
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label: "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("defaultValue is not an array", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
defaultValue: "1",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label: "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should success data with resource with optionLabel and optionValue", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
optionLabel: "slug",
|
||||
optionValue: "id",
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{ label: "ut-ad-et", value: "1" },
|
||||
{ label: "consequatur-molestiae-rerum", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("should success data with resource with filters", async () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect<{ id: string; slug: string }>({
|
||||
resource: "posts",
|
||||
filters: [
|
||||
{
|
||||
field: "slug",
|
||||
operator: "ncontains",
|
||||
value: "test",
|
||||
},
|
||||
],
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label: "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("onSearch debounce with default value (300ms)", async () => {
|
||||
const getListMock = jest.fn(() =>
|
||||
Promise.resolve({ data: [], total: 0 }),
|
||||
);
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
debounce: 300,
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: {
|
||||
...MockJSONServer,
|
||||
getList: getListMock,
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(1));
|
||||
|
||||
const { selectProps } = result.current;
|
||||
|
||||
selectProps?.onSearch?.("1");
|
||||
selectProps?.onSearch?.("12");
|
||||
selectProps?.onSearch?.("123");
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(2));
|
||||
});
|
||||
|
||||
it("onSearch disabled debounce (0ms)", async () => {
|
||||
const getListMock = jest.fn(() => {
|
||||
return Promise.resolve({ data: [], total: 0 });
|
||||
});
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
debounce: 0,
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: {
|
||||
...MockJSONServer,
|
||||
getList: getListMock,
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(!result.current.queryResult.isFetching).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(1));
|
||||
|
||||
const { selectProps } = result.current;
|
||||
|
||||
selectProps?.onSearch?.("1");
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(2));
|
||||
|
||||
selectProps?.onSearch?.("2");
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(3));
|
||||
|
||||
selectProps?.onSearch?.("3");
|
||||
await waitFor(() => expect(getListMock).toBeCalledTimes(4));
|
||||
});
|
||||
|
||||
it("should invoke queryOptions methods successfully", async () => {
|
||||
const mockFunc = jest.fn();
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
queryOptions: {
|
||||
onSuccess: (data) => {
|
||||
mockFunc();
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label: "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
|
||||
expect(mockFunc).toBeCalled();
|
||||
});
|
||||
|
||||
it("should invoke queryOptions methods for default value successfully", async () => {
|
||||
const mockFunc = jest.fn();
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useSelect({
|
||||
resource: "posts",
|
||||
defaultValue: ["1", "2", "3", "4"],
|
||||
defaultValueQueryOptions: {
|
||||
onSuccess: (data) => {
|
||||
mockFunc();
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
wrapper: TestWrapper({}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queryResult.isSuccess).toBeTruthy();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toHaveLength(2),
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(result.current.selectProps.options).toEqual([
|
||||
{
|
||||
label: "Necessitatibus necessitatibus id et cupiditate provident est qui amet.",
|
||||
value: "1",
|
||||
},
|
||||
{ label: "Recusandae consectetur aut atque est.", value: "2" },
|
||||
]),
|
||||
);
|
||||
expect(mockFunc).toBeCalled();
|
||||
});
|
||||
});
|
||||
56
packages/antd/src/hooks/fields/useSelect/index.ts
Normal file
56
packages/antd/src/hooks/fields/useSelect/index.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { SelectProps } from "antd/lib/select";
|
||||
import { QueryObserverResult } from "@tanstack/react-query";
|
||||
|
||||
import {
|
||||
useSelect as useSelectCore,
|
||||
BaseRecord,
|
||||
GetManyResponse,
|
||||
GetListResponse,
|
||||
HttpError,
|
||||
UseSelectProps,
|
||||
BaseOption,
|
||||
} from "@refinedev/core";
|
||||
|
||||
export type UseSelectReturnType<
|
||||
TData extends BaseRecord = BaseRecord,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
> = {
|
||||
selectProps: SelectProps<TOption>;
|
||||
queryResult: QueryObserverResult<GetListResponse<TData>>;
|
||||
defaultValueQueryResult: QueryObserverResult<GetManyResponse<TData>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* `useSelect` hook allows you to manage an Ant Design {@link https://ant.design/components/select/ Select} component when records in a resource needs to be used as select options.
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/api-reference/antd/hooks/field/useSelect/} for more details.
|
||||
*
|
||||
* @typeParam TQueryFnData - Result data returned by the query function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}
|
||||
* @typeParam TError - Custom error object that extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#httperror `HttpError`}
|
||||
* @typeParam TData - Result data returned by the `select` function. Extends {@link https://refine.dev/docs/api-reference/core/interfaceReferences#baserecord `BaseRecord`}. Defaults to `TQueryFnData`
|
||||
*
|
||||
*/
|
||||
|
||||
export const useSelect = <
|
||||
TQueryFnData extends BaseRecord = BaseRecord,
|
||||
TError extends HttpError = HttpError,
|
||||
TData extends BaseRecord = TQueryFnData,
|
||||
TOption extends BaseOption = BaseOption,
|
||||
>(
|
||||
props: UseSelectProps<TQueryFnData, TError, TData>,
|
||||
): UseSelectReturnType<TData, TOption> => {
|
||||
const { queryResult, defaultValueQueryResult, onSearch, options } =
|
||||
useSelectCore<TQueryFnData, TError, TData, TOption>(props);
|
||||
|
||||
return {
|
||||
selectProps: {
|
||||
options,
|
||||
onSearch,
|
||||
loading: defaultValueQueryResult.isFetching,
|
||||
showSearch: true,
|
||||
filterOption: false,
|
||||
},
|
||||
queryResult,
|
||||
defaultValueQueryResult,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user