fork refine

This commit is contained in:
Stefan Pejcic
2024-02-05 10:23:04 +01:00
parent 3fffde9a8f
commit 8496a83edb
3634 changed files with 715528 additions and 2 deletions

View 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();
});
});

View 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,
};
};