Skip to content

Commit e9b219f

Browse files
authored
chore(storage-browser): Add control hooks for consistency (#6209)
1 parent 4279e9f commit e9b219f

17 files changed

+193
-129
lines changed

packages/react-storage/src/components/StorageBrowser/controls/PaginationControl.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import React from 'react';
22

33
import { Pagination } from '../composables/Pagination';
44
import { useResolvedComposable } from './hooks/useResolvedComposable';
5-
import { useControlsContext } from './context';
5+
import { usePagination } from './hooks/usePagination';
66

77
export const PaginationControl = (): React.JSX.Element => {
8-
const { data } = useControlsContext();
8+
const props = usePagination();
99

1010
const Resolved = useResolvedComposable(Pagination, 'Pagination');
1111

12-
return <Resolved {...data.paginationData} />;
12+
return <Resolved {...props} />;
1313
};

packages/react-storage/src/components/StorageBrowser/controls/SearchControl.tsx

-30
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
3+
import { SearchField } from '../composables/SearchField';
4+
5+
import { useResolvedComposable } from './hooks/useResolvedComposable';
6+
import { useSearchField } from './hooks/useSearchField';
7+
8+
export const SearchFieldControl = (): React.JSX.Element => {
9+
const props = useSearchField();
10+
const Resolved = useResolvedComposable(SearchField, 'SearchField');
11+
12+
return <Resolved {...props} />;
13+
};
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,34 @@
11
import React from 'react';
22
import { render, screen } from '@testing-library/react';
33
import { PaginationControl } from '../PaginationControl';
4-
import { useControlsContext } from '../context';
4+
import { usePagination } from '../hooks/usePagination';
55
import { useResolvedComposable } from '../hooks/useResolvedComposable';
66

7-
jest.mock('../context');
7+
jest.mock('../hooks/usePagination');
88
jest.mock('../hooks/useResolvedComposable');
9+
jest.mock('../../composables/Pagination', () => ({
10+
Pagination: () => <div data-testid="pagination" />,
11+
}));
912

1013
describe('PaginationControl', () => {
11-
// assert mocks
12-
const mockUseControlsContext = useControlsContext as jest.Mock;
13-
const mockUseResolvedComposable = useResolvedComposable as jest.Mock;
14+
const mockUsePagination = jest.mocked(usePagination);
15+
const mockUseResolvedComposable = jest.mocked(useResolvedComposable);
1416

1517
beforeAll(() => {
1618
mockUseResolvedComposable.mockImplementation(
17-
(component: React.JSX.Element) => component
19+
(component) => component as () => React.JSX.Element
1820
);
1921
});
2022

2123
afterEach(() => {
22-
mockUseControlsContext.mockReset();
23-
mockUseResolvedComposable.mockReset();
24+
mockUsePagination.mockClear();
2425
});
2526

26-
it('renders the PaginationControl', async () => {
27-
mockUseControlsContext.mockReturnValue({
28-
data: {
29-
paginationData: {
30-
hasNextPage: true,
31-
highestPageVisited: 1,
32-
onPaginate: jest.fn(),
33-
page: 1,
34-
},
35-
},
36-
});
37-
27+
it('renders', () => {
3828
render(<PaginationControl />);
3929

40-
const nav = screen.getByRole('navigation');
41-
const list = screen.getByRole('list');
42-
const listItems = await screen.findAllByRole('listitem');
43-
const nextButton = screen.getByRole('button', { name: 'Go to next page' });
44-
const prevButton = screen.getByRole('button', {
45-
name: 'Go to previous page',
46-
});
47-
const nextIcon = nextButton.querySelector('svg');
48-
const prevIcon = nextButton.querySelector('svg');
30+
const pagination = screen.getByTestId('pagination');
4931

50-
expect(nextButton).toBeInTheDocument();
51-
expect(prevButton).toBeInTheDocument();
52-
expect(nextIcon).toBeInTheDocument();
53-
expect(prevIcon).toBeInTheDocument();
54-
expect(nextIcon).toHaveAttribute('aria-hidden', 'true');
55-
expect(prevIcon).toHaveAttribute('aria-hidden', 'true');
56-
expect(nav).toBeInTheDocument();
57-
expect(list).toBeInTheDocument();
58-
expect(listItems).toHaveLength(3);
32+
expect(pagination).toBeInTheDocument();
5933
});
6034
});

packages/react-storage/src/components/StorageBrowser/controls/__tests__/SearchControl.spec.tsx

-40
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import { SearchFieldControl } from '../SearchFieldControl';
4+
import { useSearchField } from '../hooks/useSearchField';
5+
import { useResolvedComposable } from '../hooks/useResolvedComposable';
6+
7+
jest.mock('../hooks/useSearchField');
8+
jest.mock('../hooks/useResolvedComposable');
9+
jest.mock('../../composables/SearchField', () => ({
10+
SearchField: () => <div data-testid="search-field" />,
11+
}));
12+
13+
describe('SearchFieldControl', () => {
14+
const mockUseSearchField = jest.mocked(useSearchField);
15+
const mockUseResolvedComposable = jest.mocked(useResolvedComposable);
16+
17+
beforeAll(() => {
18+
mockUseResolvedComposable.mockImplementation(
19+
(component) => component as () => React.JSX.Element
20+
);
21+
});
22+
23+
afterEach(() => {
24+
mockUseSearchField.mockClear();
25+
});
26+
27+
it('renders', () => {
28+
render(<SearchFieldControl />);
29+
30+
const searchField = screen.getByTestId('search-field');
31+
32+
expect(searchField).toBeInTheDocument();
33+
});
34+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { renderHook } from '@testing-library/react';
2+
import { PaginationProps } from '../../../composables/Pagination';
3+
import { useControlsContext } from '../../../controls/context';
4+
import { usePagination } from '../usePagination';
5+
6+
jest.mock('../../../controls/context');
7+
8+
describe('usePagination', () => {
9+
const data = {
10+
paginationData: { hasNextPage: true, highestPageVisited: 1, page: 1 },
11+
};
12+
13+
const mockUseControlsContext = jest.mocked(useControlsContext);
14+
15+
beforeEach(() => {
16+
mockUseControlsContext.mockReturnValue({ data, onPaginate: jest.fn() });
17+
});
18+
19+
afterEach(() => {
20+
mockUseControlsContext.mockReset();
21+
});
22+
23+
it('returns Pagination props', () => {
24+
const { result } = renderHook(() => usePagination());
25+
26+
const expected: PaginationProps = {
27+
hasNextPage: data.paginationData.hasNextPage,
28+
highestPageVisited: data.paginationData.highestPageVisited,
29+
page: data.paginationData.page,
30+
onPaginate: expect.any(Function),
31+
};
32+
33+
expect(result.current).toStrictEqual(expected);
34+
});
35+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { renderHook } from '@testing-library/react';
2+
import { SearchFieldProps } from '../../../composables/SearchField';
3+
import { useControlsContext } from '../../../controls/context';
4+
import { useSearchField } from '../useSearchField';
5+
6+
jest.mock('../../../controls/context');
7+
8+
describe('useSearchField', () => {
9+
const data = {
10+
searchClearLabel: 'search-clear-label',
11+
searchPlaceholder: 'search-placeholder',
12+
searchSubmitLabel: 'search-submit-label',
13+
searchQuery: 'search-query',
14+
};
15+
16+
const mockUseControlsContext = jest.mocked(useControlsContext);
17+
18+
beforeEach(() => {
19+
mockUseControlsContext.mockReturnValue({
20+
data,
21+
onSearch: jest.fn(),
22+
onSearchClear: jest.fn(),
23+
onSearchQueryChange: jest.fn(),
24+
});
25+
});
26+
27+
afterEach(() => {
28+
mockUseControlsContext.mockReset();
29+
});
30+
31+
it('returns useSearchField data', () => {
32+
const { result } = renderHook(() => useSearchField());
33+
34+
const expected: SearchFieldProps = {
35+
clearLabel: data.searchClearLabel,
36+
placeholder: data.searchPlaceholder,
37+
query: data.searchQuery,
38+
submitLabel: data.searchSubmitLabel,
39+
onClear: expect.any(Function),
40+
onQueryChange: expect.any(Function),
41+
onSearch: expect.any(Function),
42+
};
43+
44+
expect(result.current).toStrictEqual(expected);
45+
});
46+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { PaginationProps } from '../../composables/Pagination';
2+
import { useControlsContext } from '../../controls/context';
3+
4+
export const usePagination = (): PaginationProps => {
5+
const { data, onPaginate } = useControlsContext();
6+
const { paginationData } = data;
7+
8+
return { ...paginationData, onPaginate };
9+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { SearchFieldProps } from '../../composables/SearchField';
2+
import { useControlsContext } from '../../controls/context';
3+
4+
export const useSearchField = (): SearchFieldProps => {
5+
const { data, onSearch, onSearchClear, onSearchQueryChange } =
6+
useControlsContext();
7+
const {
8+
searchPlaceholder,
9+
searchClearLabel,
10+
searchQuery,
11+
searchSubmitLabel,
12+
} = data;
13+
14+
return {
15+
clearLabel: searchClearLabel,
16+
placeholder: searchPlaceholder,
17+
query: searchQuery,
18+
submitLabel: searchSubmitLabel,
19+
onClear: onSearchClear,
20+
onQueryChange: onSearchQueryChange,
21+
onSearch,
22+
};
23+
};

packages/react-storage/src/components/StorageBrowser/controls/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ interface TableData {
3131
interface PaginationData {
3232
hasNextPage: boolean;
3333
highestPageVisited: number;
34-
onPaginate: (page: number) => void;
3534
page: number;
3635
}
3736

@@ -90,6 +89,7 @@ export interface ControlsContext {
9089
onFolderNameChange?: (value: string) => void;
9190
onNavigate?: (location: LocationData, path?: string) => void;
9291
onNavigateHome?: () => void;
92+
onPaginate?: (page: number) => void;
9393
onRefresh?: () => void;
9494
onSearch?: () => void;
9595
onSearchClear?: () => void;

packages/react-storage/src/components/StorageBrowser/views/LocationActionView/CopyView/CopyView.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { ActionStartControl } from '../../../controls/ActionStartControl';
1010
import { DataTableControl } from '../../../controls/DataTableControl';
1111
import { LoadingIndicatorControl } from '../../../controls/LoadingIndicatorControl';
1212
import { MessageControl } from '../../../controls/MessageControl';
13-
import { SearchControl } from '../../../controls/SearchControl';
13+
import { SearchFieldControl } from '../../../controls/SearchFieldControl';
1414
import { StatusDisplayControl } from '../../../controls/StatusDisplayControl';
1515
import { TitleControl } from '../../../controls/TitleControl';
1616

@@ -40,7 +40,7 @@ export const CopyView: CopyViewType = ({ className, ...props }) => {
4040
<>
4141
<ViewElement className={`${STORAGE_BROWSER_BLOCK}__controls`}>
4242
<ViewElement className={`${STORAGE_BROWSER_BLOCK}__search`}>
43-
<SearchControl />
43+
<SearchFieldControl />
4444
</ViewElement>
4545
<FoldersPaginationControl />
4646
</ViewElement>
@@ -77,7 +77,7 @@ CopyView.Exit = ActionExitControl;
7777
CopyView.FoldersLoadingIndicator = LoadingIndicatorControl;
7878
CopyView.FoldersMessage = FoldersMessageControl;
7979
CopyView.FoldersPagination = FoldersPaginationControl;
80-
CopyView.FoldersSearch = SearchControl;
80+
CopyView.FoldersSearch = SearchFieldControl;
8181
CopyView.FoldersTable = FoldersTableControl;
8282
CopyView.Message = MessageControl;
8383
CopyView.Start = ActionStartControl;

0 commit comments

Comments
 (0)