Skip to content

Commit

Permalink
[EuiTablePagination] Allow page size props to be configured via `EuiP…
Browse files Browse the repository at this point in the history
…rovider.componentProps` (elastic#6951)

Co-authored-by: Tomasz Kajtoch <tomasz.kajtoch@elastic.co>
  • Loading branch information
cee-chen and tkajtoch committed Jul 25, 2023
1 parent 5e5ae65 commit e76c8da
Show file tree
Hide file tree
Showing 10 changed files with 597 additions and 550 deletions.
Original file line number Diff line number Diff line change
@@ -1,72 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`PaginationBar render - custom page size options 1`] = `
<div>
<EuiSpacer
size="m"
/>
<EuiTablePagination
activePage={0}
itemsPerPage={5}
itemsPerPageOptions={
Array [
1,
2,
3,
]
}
onChangeItemsPerPage={[Function]}
onChangePage={[Function]}
pageCount={0}
/>
</div>
`;

exports[`PaginationBar render - hiding per page options 1`] = `
<div>
<EuiSpacer
size="m"
/>
<EuiTablePagination
activePage={0}
itemsPerPage={5}
itemsPerPageOptions={
Array [
10,
25,
50,
]
}
onChangeItemsPerPage={[Function]}
onChangePage={[Function]}
pageCount={0}
showPerPageOptions={false}
/>
</div>
`;

exports[`PaginationBar render - show all pageSize 1`] = `
<div>
<EuiSpacer
size="m"
/>
<EuiTablePagination
activePage={0}
itemsPerPage={0}
itemsPerPageOptions={
Array [
1,
5,
0,
]
}
onChangeItemsPerPage={[Function]}
onChangePage={[Function]}
pageCount={1}
/>
</div>
`;

exports[`PaginationBar renders 1`] = `
<div>
<div
Expand Down
88 changes: 27 additions & 61 deletions src/components/basic_table/pagination_bar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,78 +7,44 @@
*/

import React from 'react';
import { shallow } from 'enzyme';
import { fireEvent } from '@testing-library/react';
import { render } from '../../test/rtl';
import { requiredProps } from '../../test';

import { PaginationBar } from './pagination_bar';

describe('PaginationBar', () => {
it('renders', () => {
const props = {
...requiredProps,
pagination: {
pageIndex: 0,
pageSize: 5,
totalItemCount: 0,
},
onPageSizeChange: () => {},
onPageChange: () => {},
};
const props = {
...requiredProps,
pagination: {
pageIndex: 0,
pageSize: 5,
totalItemCount: 0,
},
onPageSizeChange: () => {},
onPageChange: () => {},
};

it('renders', () => {
const { container } = render(<PaginationBar {...props} />);

expect(container.firstChild).toMatchSnapshot();
});

test('render - custom page size options', () => {
const props = {
pagination: {
pageIndex: 0,
pageSize: 5,
totalItemCount: 0,
pageSizeOptions: [1, 2, 3],
},
onPageSizeChange: () => {},
onPageChange: () => {},
};

const component = shallow(<PaginationBar {...props} />);

expect(component).toMatchSnapshot();
});

test('render - hiding per page options', () => {
const props = {
pagination: {
pageIndex: 0,
pageSize: 5,
totalItemCount: 0,
showPerPageOptions: false,
},
onPageSizeChange: () => {},
onPageChange: () => {},
};

const component = shallow(<PaginationBar {...props} />);

expect(component).toMatchSnapshot();
});

test('render - show all pageSize', () => {
const props = {
pagination: {
pageIndex: 0,
pageSize: 0,
pageSizeOptions: [1, 5, 0],
totalItemCount: 5,
},
onPageSizeChange: () => {},
onPageChange: () => {},
};

const component = shallow(<PaginationBar {...props} />);

expect(component).toMatchSnapshot();
it('calls onPageChange with the correct off-by-one offset', () => {
const onPageChange = jest.fn();
const { getByLabelText } = render(
<PaginationBar
{...props}
pagination={{
...props.pagination,
totalItemCount: 10,
}}
onPageChange={onPageChange}
/>
);

fireEvent.click(getByLabelText('Page 2 of 2'));
expect(onPageChange).toHaveBeenCalledWith(1);
});
});
16 changes: 6 additions & 10 deletions src/components/focus_trap/focus_trap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { RemoveScrollBar } from 'react-remove-scroll-bar';

import { CommonProps } from '../common';
import { findElementBySelectorOrRef, ElementTarget } from '../../services';
import { useEuiComponentDefaults } from '../provider/component_defaults';
import { usePropsWithComponentDefaults } from '../provider/component_defaults';

export type FocusTarget = ElementTarget;

Expand Down Expand Up @@ -82,16 +82,12 @@ export type EuiFocusTrapProps = Omit<
returnFocus?: ReactFocusOnProps['returnFocus'];
};

export const EuiFocusTrap: FunctionComponent<EuiFocusTrapProps> = ({
children,
...props
}) => {
const { EuiFocusTrap: defaults } = useEuiComponentDefaults();
return (
<EuiFocusTrapClass {...defaults} {...props}>
{children}
</EuiFocusTrapClass>
export const EuiFocusTrap: FunctionComponent<EuiFocusTrapProps> = (props) => {
const propsWithDefaults = usePropsWithComponentDefaults(
'EuiFocusTrap',
props
);
return <EuiFocusTrapClass {...propsWithDefaults} />;
};

interface State {
Expand Down
15 changes: 4 additions & 11 deletions src/components/portal/portal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import React, { Component, FunctionComponent, ReactNode } from 'react';
import { createPortal } from 'react-dom';

import { EuiNestedThemeContext } from '../../services';
import { useEuiComponentDefaults } from '../provider/component_defaults';
import { usePropsWithComponentDefaults } from '../provider/component_defaults';

const INSERT_POSITIONS = ['after', 'before'] as const;
type EuiPortalInsertPosition = (typeof INSERT_POSITIONS)[number];
Expand All @@ -40,16 +40,9 @@ export interface EuiPortalProps {
portalRef?: (ref: HTMLDivElement | null) => void;
}

export const EuiPortal: FunctionComponent<EuiPortalProps> = ({
children,
...props
}) => {
const { EuiPortal: defaults } = useEuiComponentDefaults();
return (
<EuiPortalClass {...defaults} {...props}>
{children}
</EuiPortalClass>
);
export const EuiPortal: FunctionComponent<EuiPortalProps> = (props) => {
const propsWithDefaults = usePropsWithComponentDefaults('EuiPortal', props);
return <EuiPortalClass {...propsWithDefaults} />;
};

export class EuiPortalClass extends Component<EuiPortalProps> {
Expand Down
141 changes: 119 additions & 22 deletions src/components/provider/component_defaults/component_defaults.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,138 @@ import { renderHook } from '@testing-library/react-hooks';

import {
EuiComponentDefaultsProvider,
useEuiComponentDefaults,
useComponentDefaults,
usePropsWithComponentDefaults,
} from './component_defaults';

describe('EuiComponentDefaultsProvider', () => {
it('sets up context that allows accessing the passed `componentDefaults` from anywhere', () => {
describe('useComponentDefaults', () => {
it('allows accessing provided `componentDefaults` from anywhere', () => {
const wrapper = ({ children }: PropsWithChildren<{}>) => (
<EuiComponentDefaultsProvider
componentDefaults={{
EuiPortal: {
insert: {
sibling: document.createElement('div'),
position: 'before',
},
},
}}
>
{children}
</EuiComponentDefaultsProvider>
);
const { result } = renderHook(useComponentDefaults, { wrapper });

expect(result.current).toMatchInlineSnapshot(`
Object {
"EuiPortal": Object {
"insert": Object {
"position": "before",
"sibling": <div />,
},
},
}
`);
});
});

describe('usePropsWithComponentDefaults', () => {
const wrapper = ({ children }: PropsWithChildren<{}>) => (
<EuiComponentDefaultsProvider
componentDefaults={{
EuiPortal: {
insert: {
sibling: document.createElement('div'),
position: 'before',
},
EuiTablePagination: {
itemsPerPage: 20,
itemsPerPageOptions: [20, 40, 80, 0],
},
}}
>
{children}
</EuiComponentDefaultsProvider>
);
const { result } = renderHook(useEuiComponentDefaults, { wrapper });

expect(result.current).toMatchInlineSnapshot(`
Object {
"EuiPortal": Object {
"insert": Object {
"position": "before",
"sibling": <div />,
},
},
}
`);

it("returns a specific component's provided default props", () => {
const { result } = renderHook(
() => usePropsWithComponentDefaults('EuiTablePagination', {}),
{ wrapper }
);

expect(result.current).toEqual({
itemsPerPage: 20,
itemsPerPageOptions: [20, 40, 80, 0],
});
});

it('correctly overrides defaults with actual props passed', () => {
const { result } = renderHook(
() =>
usePropsWithComponentDefaults('EuiTablePagination', {
itemsPerPageOptions: [5, 10, 20],
}),
{ wrapper }
);

expect(result.current).toEqual({
itemsPerPage: 20,
itemsPerPageOptions: [5, 10, 20],
});
});

it('correctly handles props without a default defined', () => {
const { result } = renderHook(
() =>
usePropsWithComponentDefaults('EuiTablePagination', {
showPerPageOptions: false,
}),
{ wrapper }
);

expect(result.current).toEqual({
itemsPerPage: 20,
itemsPerPageOptions: [20, 40, 80, 0],
showPerPageOptions: false,
});
});

it('correctly handles components with no defaults defined', () => {
const { result } = renderHook(
() =>
usePropsWithComponentDefaults('EuiFocusTrap', {
children: 'test',
crossFrame: true,
}),
{ wrapper }
);

expect(result.current).toEqual({
children: 'test',
crossFrame: true,
});
});

it('correctly handles no component defaults defined at all', () => {
const wrapper = ({ children }: PropsWithChildren<{}>) => (
<EuiComponentDefaultsProvider>{children}</EuiComponentDefaultsProvider>
);
const { result } = renderHook(
() =>
usePropsWithComponentDefaults('EuiFocusTrap', {
children: 'test',
gapMode: 'margin',
}),
{ wrapper }
);

expect(result.current).toEqual({
children: 'test',
gapMode: 'margin',
});
});
});

// NOTE: Components are in charge of their own testing to ensure that the props
// coming from `useEuiComponentDefaults()` were properly applied. This file
// is simply a very light wrapper that carries prop data.
// @see `src/components/portal/portal.spec.tsx` as an example
// coming from the `componentDefaults` configuration were properly applied.
// Examples:
// @see src/components/portal/portal.spec.tsx
// @see src/components/table/table_pagination/table_pagination.test.tsx
});
Loading

0 comments on commit e76c8da

Please sign in to comment.