diff --git a/assets/js/common/Table/Pagination.jsx b/assets/js/common/Pagination/Pagination.jsx similarity index 100% rename from assets/js/common/Table/Pagination.jsx rename to assets/js/common/Pagination/Pagination.jsx diff --git a/assets/js/common/Pagination/Pagination.stories.jsx b/assets/js/common/Pagination/Pagination.stories.jsx new file mode 100644 index 0000000000..5d2ca513e8 --- /dev/null +++ b/assets/js/common/Pagination/Pagination.stories.jsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { action } from '@storybook/addon-actions'; + +import Pagination from '.'; + +export default { + title: 'Components/Pagination', + component: Pagination, + argTypes: { + pages: { + control: { + type: 'number', + }, + defaultValue: 5, + }, + currentPage: { + control: { + type: 'number', + }, + defaultValue: 1, + }, + currentItemsPerPage: { + control: { + type: 'number', + }, + defaultValue: 10, + }, + itemsPerPageOptions: { + control: { + type: 'array', + }, + defaultValue: [10], + }, + }, + render: (args) => ( + { + action('onSelect')(value); + }} + onChangeItemsPerPage={(value) => { + action('onChangeItemsPerPage')(value); + }} + /> + ), +}; + +export const Default = { + args: { + pages: 5, + currentPage: 1, + currentItemsPerPage: 10, + itemsPerPageOptions: [10, 20, 50], + }, +}; diff --git a/assets/js/common/Pagination/Pagination.test.jsx b/assets/js/common/Pagination/Pagination.test.jsx new file mode 100644 index 0000000000..847943aa5a --- /dev/null +++ b/assets/js/common/Pagination/Pagination.test.jsx @@ -0,0 +1,88 @@ +import React, { act } from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '@testing-library/jest-dom'; +import { noop } from 'lodash'; +import Pagination from '.'; + +describe('Pagination component', () => { + it('should render', () => { + render( + + ); + expect(screen.getByText('Results per page')).toBeInTheDocument(); + expect(screen.getByText('10')).toBeInTheDocument(); + + for (let i = 1; i <= 5; i += 1) { + expect(screen.getByText(`${i}`)).toBeInTheDocument(); + } + expect(screen.queryByText('6')).not.toBeInTheDocument(); + }); + + it('should select the correct page', async () => { + const user = userEvent.setup(); + + const onSelect = jest.fn(); + render( + + ); + + for (let i = 1; i <= 5; i += 1) { + // This includes the current page, too. Is it expected? + // eslint-disable-next-line no-await-in-loop + await act(() => user.click(screen.getByText(`${i}`))); + expect(onSelect).toHaveBeenCalledTimes(1); + expect(onSelect).toHaveBeenCalledWith(i); + onSelect.mockClear(); + } + }); + + it('should select items per page', async () => { + const user = userEvent.setup(); + + const onChangeItemsPerPage = jest.fn(); + const currentItemsPerPage = 10; + const itemsPerPageOptions = [10, 20, 50]; + render( + + ); + + for (let i = 0; i < itemsPerPageOptions.length; i += 1) { + // open dropdown + // eslint-disable-next-line no-await-in-loop + await act(() => user.click(screen.getByText(`${currentItemsPerPage}`))); + + // select item + const selection = itemsPerPageOptions[i]; + const [selectable] = screen.getAllByText(`${selection}`).reverse(); + // eslint-disable-next-line no-await-in-loop + await act(() => user.click(selectable)); + + // check if the correct item was selected + expect(onChangeItemsPerPage).toHaveBeenCalledTimes(1); + expect(onChangeItemsPerPage).toHaveBeenCalledWith(selection); + onChangeItemsPerPage.mockClear(); + } + }); +}); diff --git a/assets/js/common/Pagination/index.js b/assets/js/common/Pagination/index.js new file mode 100644 index 0000000000..9ed530b1f6 --- /dev/null +++ b/assets/js/common/Pagination/index.js @@ -0,0 +1,3 @@ +import Pagination from './Pagination'; + +export default Pagination; diff --git a/assets/js/common/Table/Table.jsx b/assets/js/common/Table/Table.jsx index 4654d2cf44..9f1f5a9930 100644 --- a/assets/js/common/Table/Table.jsx +++ b/assets/js/common/Table/Table.jsx @@ -3,12 +3,12 @@ import React, { useState, useEffect } from 'react'; import classNames from 'classnames'; import { page, pages } from '@lib/lists'; +import Pagination from '@common/Pagination'; import { TableFilters, createFilter } from './filters'; import { defaultRowKey } from './defaultRowKey'; import SortingIcon from './SortingIcon'; import EmptyState from './EmptyState'; import CollapsibleTableRow from './CollapsibleTableRow'; -import Pagination from './Pagination'; const defaultCellRender = (content) => (

{content}