From: Wouter Admiraal Date: Fri, 12 May 2023 10:11:16 +0000 (+0200) Subject: SONAR-19249 Introduce new variant for the ListFooter X-Git-Tag: 10.1.0.73491~242 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=50dba7534f62a4f22cb0d085a8abc2a9200c0d95;p=sonarqube.git SONAR-19249 Introduce new variant for the ListFooter --- diff --git a/server/sonar-web/src/main/js/components/controls/ListFooter.tsx b/server/sonar-web/src/main/js/components/controls/ListFooter.tsx index fbbcb2af464..cd0f7f985d6 100644 --- a/server/sonar-web/src/main/js/components/controls/ListFooter.tsx +++ b/server/sonar-web/src/main/js/components/controls/ListFooter.tsx @@ -17,10 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import styled from '@emotion/styled'; import classNames from 'classnames'; +import { ButtonSecondary, themeColor, withTheme } from 'design-system'; import * as React from 'react'; import { translate, translateWithParameters } from '../../helpers/l10n'; import { formatMeasure } from '../../helpers/measures'; +import { MetricType } from '../../types/metrics'; import DeferredSpinner from '../ui/DeferredSpinner'; import { Button } from './buttons'; @@ -35,6 +38,7 @@ export interface ListFooterProps { reload?: () => void; ready?: boolean; total?: number; + useMIUIButtons?: boolean; } export default function ListFooter(props: ListFooterProps) { @@ -48,6 +52,7 @@ export default function ListFooter(props: ListFooterProps) { total, pageSize, ready = true, + useMIUIButtons = false, } = props; const rootNode = React.useRef(null); @@ -71,32 +76,38 @@ export default function ListFooter(props: ListFooterProps) { let button; if (needReload && props.reload) { - button = ( - + button = React.createElement( + useMIUIButtons ? ButtonSecondary : Button, + { + 'data-test': 'reload', + className: classNames('sw-ml-2', { 'sw-body-sm': useMIUIButtons }), + disabled: loading, + onClick: props.reload, + } as Button['props'], + translate('reload') ); } else if (hasMore && props.loadMore) { - button = ( - + button = React.createElement( + useMIUIButtons ? ButtonSecondary : Button, + { + 'aria-label': loadMoreAriaLabel, + 'data-test': 'show-more', + className: classNames('sw-ml-2', { 'sw-body-sm': useMIUIButtons }), + disabled: loading, + onClick: onLoadMore, + } as Button['props'], + translate('show_more') ); } return ( -
@@ -104,13 +115,17 @@ export default function ListFooter(props: ListFooterProps) { {total !== undefined ? translateWithParameters( 'x_of_y_shown', - formatMeasure(count, 'INT', null), - formatMeasure(total, 'INT', null) + formatMeasure(count, MetricType.Integer, null), + formatMeasure(total, MetricType.Integer, null) ) - : translateWithParameters('x_show', formatMeasure(count, 'INT', null))} + : translateWithParameters('x_show', formatMeasure(count, MetricType.Integer, null))} {button} - {} -
+ {} + ); } + +const StyledDiv = withTheme(styled.div` + color: ${themeColor('pageContentLight')}; +`); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx index 0986463f7ab..08e3d387107 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx @@ -17,58 +17,127 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { shallow } from 'enzyme'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import * as React from 'react'; -import { click } from '../../../helpers/testUtils'; -import { Button } from '../buttons'; +import { renderComponent } from '../../../helpers/testReactTestingUtils'; import ListFooter, { ListFooterProps } from '../ListFooter'; -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ loading: true })).toMatchSnapshot('loading'); - expect(shallowRender({ needReload: true, reload: jest.fn() })).toMatchSnapshot('reload'); - expect(shallowRender({ loading: true, needReload: true, reload: jest.fn() })).toMatchSnapshot( - 'reload, loading' - ); - expect(shallowRender({ loadMore: undefined })).toMatchSnapshot( - 'empty if no loadMore nor reload props' - ); - expect(shallowRender({ count: 5 })).toMatchSnapshot('empty if everything is loaded'); - expect(shallowRender({ total: undefined })).toMatchSnapshot('total undefined'); - expect(shallowRender({ total: undefined, count: 60, pageSize: 30 })).toMatchSnapshot( - 'force show load more button if count % pageSize is 0, and total is undefined' - ); -}); +describe('ListFooter', () => { + describe('rendering', () => { + it('should render correctly when loading', async () => { + renderListFooter({ loading: true }); + expect(await screen.findByText('loading')).toBeInTheDocument(); + }); -it.each([ - [undefined, 60, 30, true], - [undefined, 45, 30, false], - [undefined, 60, undefined, false], - [60, 60, 30, false], -])( - 'handle showing load more button based on total, count and pageSize', - (total, count, pageSize, expected) => { - const wrapper = shallowRender({ total, count, pageSize }); - expect(wrapper.find(Button).exists()).toBe(expected); - } -); + it('should not render if there are neither loadmore nor reload props', () => { + renderListFooter({ loadMore: undefined, reload: undefined }); + expect(screen.queryByRole('button')).not.toBeInTheDocument(); + }); -it('should properly call loadMore', () => { - const loadMore = jest.fn(); - const wrapper = shallowRender({ loadMore }); - click(wrapper.find(Button)); - expect(loadMore).toHaveBeenCalled(); -}); + it.each([ + [undefined, 60, 30, true], + [undefined, 45, 30, false], + [undefined, 60, undefined, false], + [60, 60, 30, false], + ])( + 'should handle showing load more button based on total, count and pageSize', + (total, count, pageSize, expected) => { + renderListFooter({ total, count, pageSize }); + + /* eslint-disable jest/no-conditional-in-test */ + /* eslint-disable jest/no-conditional-expect */ + if (expected) { + expect(screen.getByRole('button')).toBeInTheDocument(); + } else { + expect(screen.queryByRole('button')).not.toBeInTheDocument(); + } + /* eslint-enable jest/no-conditional-in-test */ + /* eslint-enable jest/no-conditional-expect */ + } + ); + }); + + it('should properly call load more callback', async () => { + const user = userEvent.setup(); + const loadMore = jest.fn(); + renderListFooter({ loadMore }); -it('should properly call reload', () => { - const reload = jest.fn(); - const wrapper = shallowRender({ needReload: true, reload }); - click(wrapper.find(Button)); - expect(reload).toHaveBeenCalled(); + await user.click(screen.getByRole('button')); + expect(loadMore).toHaveBeenCalled(); + }); + + it('should properly call reload callback', async () => { + const user = userEvent.setup(); + const reload = jest.fn(); + renderListFooter({ needReload: true, reload }); + + await user.click(screen.getByRole('button')); + expect(reload).toHaveBeenCalled(); + }); + + function renderListFooter(props: Partial = {}) { + return renderComponent(); + } }); -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} +// Once the MIUI buttons become the norm, we can use only the above test "suite" and drop this one. +describe('ListFooter using MIUI buttons', () => { + describe('rendering', () => { + it('should render correctly when loading', async () => { + renderListFooter({ loading: true }); + expect(await screen.findByText('loading')).toBeInTheDocument(); + }); + + it('should not render if there are neither loadmore nor reload props', () => { + renderListFooter({ loadMore: undefined, reload: undefined }); + expect(screen.queryByRole('button')).not.toBeInTheDocument(); + }); + + it.each([ + [undefined, 60, 30, true], + [undefined, 45, 30, false], + [undefined, 60, undefined, false], + [60, 60, 30, false], + ])( + 'should handle showing load more button based on total, count and pageSize', + (total, count, pageSize, expected) => { + renderListFooter({ total, count, pageSize }); + + /* eslint-disable jest/no-conditional-in-test */ + /* eslint-disable jest/no-conditional-expect */ + if (expected) { + expect(screen.getByRole('button')).toBeInTheDocument(); + } else { + expect(screen.queryByRole('button')).not.toBeInTheDocument(); + } + /* eslint-enable jest/no-conditional-in-test */ + /* eslint-enable jest/no-conditional-expect */ + } + ); + }); + + it('should properly call load more callback', async () => { + const user = userEvent.setup(); + const loadMore = jest.fn(); + renderListFooter({ loadMore }); + + await user.click(screen.getByRole('button')); + expect(loadMore).toHaveBeenCalled(); + }); + + it('should properly call reload callback', async () => { + const user = userEvent.setup(); + const reload = jest.fn(); + renderListFooter({ needReload: true, reload }); + + await user.click(screen.getByRole('button')); + expect(reload).toHaveBeenCalled(); + }); + + function renderListFooter(props: Partial = {}) { + return renderComponent( + + ); + } +}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ListFooter-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ListFooter-test.tsx.snap deleted file mode 100644 index c565c087a57..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ListFooter-test.tsx.snap +++ /dev/null @@ -1,185 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -
- - x_of_y_shown.3.5 - - - -
-`; - -exports[`should render correctly: empty if everything is loaded 1`] = ` -
- - x_of_y_shown.5.5 - - -
-`; - -exports[`should render correctly: empty if no loadMore nor reload props 1`] = ` -
- - x_of_y_shown.3.5 - - -
-`; - -exports[`should render correctly: force show load more button if count % pageSize is 0, and total is undefined 1`] = ` -
- - x_show.60 - - - -
-`; - -exports[`should render correctly: loading 1`] = ` -
- - x_of_y_shown.3.5 - - - -
-`; - -exports[`should render correctly: reload 1`] = ` -
- - x_of_y_shown.3.5 - - - -
-`; - -exports[`should render correctly: reload, loading 1`] = ` -
- - x_of_y_shown.3.5 - - - -
-`; - -exports[`should render correctly: total undefined 1`] = ` -
- - x_show.3 - - -
-`;