From ac64b4fe18f42fdbc1d54c3409cee2a74e234051 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gr=C3=A9goire=20Aubert?= Date: Thu, 9 May 2019 08:42:22 +0200 Subject: [PATCH] SONAR-12040 Display pending time on system background task page --- .../src/main/js/app/styles/init/type.css | 5 - .../__tests__/BackgroundTasks-test.tsx | 95 ---------- .../background-tasks/background-tasks.css | 5 + .../components/BackgroundTasksApp.tsx | 74 ++++---- .../components/StatPendingCount.tsx | 69 +++++++ .../components/StatPendingTime.tsx | 49 +++++ .../components/StatStillFailing.tsx | 52 ++++++ .../background-tasks/components/Stats.tsx | 131 +++----------- .../__tests__/BackgroundTasksApp-test.tsx | 100 +++++++++++ .../__tests__/StatPendingCount-test.tsx | 62 +++++++ .../__tests__/StatPendingTime-test.tsx | 49 +++++ .../__tests__/StatStillFailing-test.tsx | 47 +++++ .../Stats-test.tsx} | 28 ++- .../BackgroundTasksApp-test.tsx.snap | 168 ++++++++++++++++++ .../StatPendingCount-test.tsx.snap | 26 +++ .../StatPendingTime-test.tsx.snap | 20 +++ .../StatStillFailing-test.tsx.snap | 40 +++++ .../__snapshots__/Stats-test.tsx.snap | 33 ++++ .../resources/org/sonar/l10n/core.properties | 2 + 19 files changed, 805 insertions(+), 250 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/StatPendingCount.tsx create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/StatPendingTime.tsx create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/StatStillFailing.tsx create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/BackgroundTasksApp-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingCount-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingTime-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatStillFailing-test.tsx rename server/sonar-web/src/main/js/apps/background-tasks/components/{StatsContainer.tsx => __tests__/Stats-test.tsx} (57%) create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/BackgroundTasksApp-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingCount-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingTime-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatStillFailing-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Stats-test.tsx.snap diff --git a/server/sonar-web/src/main/js/app/styles/init/type.css b/server/sonar-web/src/main/js/app/styles/init/type.css index 36046303c59..8e812a83275 100644 --- a/server/sonar-web/src/main/js/app/styles/init/type.css +++ b/server/sonar-web/src/main/js/app/styles/init/type.css @@ -146,11 +146,6 @@ mark { font-weight: bold; } -.emphasised-measure { - font-size: 24px; - font-weight: 300; -} - blockquote { border-left: 3px solid var(--barBorderColor); padding: 0 8px; diff --git a/server/sonar-web/src/main/js/apps/background-tasks/__tests__/BackgroundTasks-test.tsx b/server/sonar-web/src/main/js/apps/background-tasks/__tests__/BackgroundTasks-test.tsx index 7996c05b470..2d529a67187 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/__tests__/BackgroundTasks-test.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/__tests__/BackgroundTasks-test.tsx @@ -19,14 +19,11 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import Stats from '../components/Stats'; import Search from '../components/Search'; import { STATUSES, CURRENTS, DEBOUNCE_DELAY, DEFAULT_FILTERS } from '../constants'; import { formatDuration } from '../utils'; import { click } from '../../../helpers/testUtils'; -const stub = jest.fn(); - describe('Constants', () => { it('should have STATUSES', () => { expect(Object.keys(STATUSES).length).toBe(7); @@ -79,98 +76,6 @@ describe('Search', () => { }); }); -describe('Stats', () => { - describe('Pending', () => { - it('should show zero pending', () => { - const result = shallow( - - ); - expect(result.find('.js-pending-count').text()).toContain('0'); - }); - - it('should show 5 pending', () => { - const result = shallow( - - ); - expect(result.find('.js-pending-count').text()).toContain('5'); - }); - - it('should not show cancel pending button', () => { - const result = shallow( - - ); - expect(result.find('[data-test="cancel-pending"]').length).toBe(0); - }); - - it('should show cancel pending button', () => { - const result = shallow( - - ); - expect(result.find('[data-test="cancel-pending"]').length).toBe(1); - }); - - it('should trigger cancelling pending', () => { - const spy = jest.fn(); - const result = shallow( - - ); - expect(spy).not.toBeCalled(); - result.find('[data-test="cancel-pending"]').prop('onConfirm')(); - expect(spy).toBeCalled(); - }); - }); - - describe('Failures', () => { - it('should show zero failures', () => { - const result = shallow( - - ); - expect(result.find('.js-failures-count').text()).toContain('0'); - }); - - it('should show 5 failures', () => { - const result = shallow( - - ); - expect(result.find('.js-failures-count').text()).toContain('5'); - }); - - it('should not show link to failures', () => { - const result = shallow( - - ); - expect(result.find('.js-failures-count').is('a')).toBeFalsy(); - }); - - it('should show link to failures', () => { - const result = shallow( - - ); - expect(result.find('.js-failures-count').is('a')).toBeTruthy(); - }); - - it('should trigger filtering failures', () => { - const spy = jest.fn(); - const result = shallow( - - ); - expect(spy).not.toBeCalled(); - click(result.find('.js-failures-count')); - expect(spy).toBeCalled(); - }); - }); -}); - describe('Helpers', () => { describe('#formatDuration()', () => { it('should format 173ms', () => { diff --git a/server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css b/server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css index 1302b172d5d..edabbb5eb57 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css +++ b/server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css @@ -41,3 +41,8 @@ .bt-workers-warning-icon { margin-top: 5px; } + +.emphasised-measure { + font-size: var(--hugeFontSize); + font-weight: 300; +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.tsx index 411f5746a03..437d743ee07 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.tsx @@ -21,15 +21,14 @@ import * as React from 'react'; import Helmet from 'react-helmet'; import { debounce, uniq } from 'lodash'; import { connect } from 'react-redux'; -import { InjectedRouter } from 'react-router'; -import { Location } from 'history'; import Header from './Header'; import Footer from './Footer'; -import StatsContainer from './StatsContainer'; +import Stats from './Stats'; import Search from './Search'; import Tasks from './Tasks'; import { DEFAULT_FILTERS, DEBOUNCE_DELAY, STATUSES, CURRENTS } from '../constants'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; +import { Location, Router } from '../../../components/hoc/withRouter'; import { getTypes, getActivity, @@ -45,34 +44,28 @@ import { toShortNotSoISOString } from '../../../helpers/dates'; import '../background-tasks.css'; interface Props { - component?: { id: string }; + component?: Pick & { id: string }; // id should be removed when api/ce/activity accept a component key instead of an id fetchOrganizations: (keys: string[]) => void; location: Location; - router: Pick; + router: Pick; } interface State { + failingCount: number; loading: boolean; + pendingCount: number; + pendingTime?: number; tasks: T.Task[]; types?: string[]; - query: string; - pendingCount: number; - failingCount: number; } -class BackgroundTasksApp extends React.PureComponent { +export class BackgroundTasksApp extends React.PureComponent { loadTasksDebounced: () => void; mounted = false; constructor(props: Props) { super(props); - this.state = { - failingCount: 0, - loading: true, - pendingCount: 0, - query: '', - tasks: [] - }; + this.state = { failingCount: 0, loading: true, pendingCount: 0, tasks: [] }; this.loadTasksDebounced = debounce(this.loadTasks, DEBOUNCE_DELAY); } @@ -125,25 +118,23 @@ class BackgroundTasksApp extends React.PureComponent { parameters.componentId = this.props.component.id; } - Promise.all([getActivity(parameters), getStatus(parameters.componentId)]).then(responses => { - if (this.mounted) { - const [activity, status] = responses; - const { tasks } = activity; - - const pendingCount = status.pending; - const failingCount = status.failing; - - const organizations = uniq(tasks.map(task => task.organization).filter(o => o)); - this.props.fetchOrganizations(organizations); - - this.setState({ - tasks, - pendingCount, - failingCount, - loading: false - }); - } - }, this.stopLoading); + Promise.all([getActivity(parameters), getStatus(parameters.componentId)]).then( + ([{ tasks }, status]) => { + if (this.mounted) { + const organizations = uniq(tasks.map(task => task.organization).filter(o => o)); + this.props.fetchOrganizations(organizations); + + this.setState({ + failingCount: status.failing, + loading: false, + pendingCount: status.pending, + pendingTime: status.pendingTime, + tasks + }); + } + }, + this.stopLoading + ); }; handleFilterUpdate = (nextState: Partial) => { @@ -187,13 +178,13 @@ class BackgroundTasksApp extends React.PureComponent { this.handleFilterUpdate({ query: task.componentKey }); }; - handleShowFailing() { + handleShowFailing = () => { this.handleFilterUpdate({ ...DEFAULT_FILTERS, status: STATUSES.FAILED, currents: CURRENTS.ONLY_CURRENTS }); - } + }; handleCancelAllPending = () => { this.setState({ loading: true }); @@ -207,7 +198,7 @@ class BackgroundTasksApp extends React.PureComponent { render() { const { component } = this.props; - const { loading, types, tasks, pendingCount, failingCount } = this.state; + const { loading, types, tasks } = this.state; if (!types) { return ( @@ -230,12 +221,13 @@ class BackgroundTasksApp extends React.PureComponent {
- void; + pendingCount?: number; +} + +export function StatPendingCount({ isSystemAdmin, onCancelAllPending, pendingCount }: Props) { + if (pendingCount === undefined) { + return null; + } + + return ( + + {pendingCount} + + {translate('background_tasks.pending')} + {isSystemAdmin && pendingCount > 0 && ( + + {({ onClick }) => ( + + + + )} + + )} + + + ); +} + +const mapStateToProps = (state: Store) => ({ + isSystemAdmin: getAppState(state).canAdmin +}); + +export default connect(mapStateToProps)(StatPendingCount); diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/StatPendingTime.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/StatPendingTime.tsx new file mode 100644 index 00000000000..52d34f201a8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/StatPendingTime.tsx @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; +import { translate } from '../../../helpers/l10n'; +import { formatMeasure } from '../../../helpers/measures'; + +// Do not display the pending time for values smaller than this threshold (in ms) +const MIN_PENDING_TIME_THRESHOLD = 1000; + +export interface Props { + className?: string; + component?: Pick; + pendingCount?: number; + pendingTime?: number; +} + +export default function StatPendingTime({ className, pendingCount, pendingTime }: Props) { + if (!pendingTime || !pendingCount || pendingTime < MIN_PENDING_TIME_THRESHOLD) { + return null; + } + return ( + + {formatMeasure(pendingTime, 'MILLISEC')} + {translate('background_tasks.pending_time')} + + + ); +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/StatStillFailing.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/StatStillFailing.tsx new file mode 100644 index 00000000000..9bede3d54c5 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/StatStillFailing.tsx @@ -0,0 +1,52 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { ButtonLink } from '../../../components/ui/buttons'; +import { translate } from '../../../helpers/l10n'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; + +export interface Props { + className?: string; + failingCount?: number; + onShowFailing: () => void; +} + +export default function StatStillFailing({ className, failingCount, onShowFailing }: Props) { + if (failingCount === undefined) { + return null; + } + + return ( + + {failingCount > 0 ? ( + + {failingCount} + + ) : ( + {failingCount} + )} + {translate('background_tasks.failures')} + + + ); +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.tsx index 777c20c8cd3..a4ce66f43a4 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.tsx @@ -18,112 +18,37 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import Tooltip from '../../../components/controls/Tooltip'; -import { DeleteButton } from '../../../components/ui/buttons'; -import { translate } from '../../../helpers/l10n'; -import ConfirmButton from '../../../components/controls/ConfirmButton'; +import StatPendingCount from './StatPendingCount'; +import StatPendingTime from './StatPendingTime'; +import StatStillFailing from './StatStillFailing'; -interface Props { - component?: unknown; +export interface Props { + component?: Pick; failingCount?: number; - isSystemAdmin?: boolean; - pendingCount?: number; - onShowFailing: () => void; onCancelAllPending: () => void; + onShowFailing: () => void; + pendingCount?: number; + pendingTime?: number; } -export default class Stats extends React.PureComponent { - handleShowFailing = (event: React.MouseEvent) => { - event.preventDefault(); - event.currentTarget.blur(); - this.props.onShowFailing(); - }; - - renderPending() { - if (this.props.pendingCount === undefined) { - return null; - } - if (this.props.pendingCount > 0) { - return ( - - {this.props.pendingCount} - - {translate('background_tasks.pending')} - {this.props.isSystemAdmin && ( - - {({ onClick }) => ( - - - - )} - - )} - - - ); - } else { - return ( - - {this.props.pendingCount} -   - {translate('background_tasks.pending')} - - ); - } - } - - renderFailures() { - if (this.props.failingCount === undefined) { - return null; - } - - if (this.props.component) { - return null; - } - - if (this.props.failingCount > 0) { - return ( - - - - {this.props.failingCount} - - -   - {translate('background_tasks.failures')} - - ); - } else { - return ( - - - {this.props.failingCount} - - {translate('background_tasks.failures')} - - ); - } - } - - render() { - return ( -
- {this.renderPending()} - {this.renderFailures()} -
- ); - } +export default function Stats({ component, pendingCount, pendingTime, ...props }: Props) { + return ( +
+ + {!component && ( + + )} + {!component && ( + + )} +
+ ); } diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/BackgroundTasksApp-test.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/BackgroundTasksApp-test.tsx new file mode 100644 index 00000000000..0c52d27c0e5 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/BackgroundTasksApp-test.tsx @@ -0,0 +1,100 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import { BackgroundTasksApp } from '../BackgroundTasksApp'; +import { mockLocation, mockRouter } from '../../../../helpers/testMocks'; +import { waitAndUpdate } from '../../../../helpers/testUtils'; + +jest.mock('../../../../api/ce', () => ({ + getTypes: jest.fn().mockResolvedValue({ + taskTypes: ['REPORT', 'PROJECT_EXPORT', 'PROJECT_IMPORT', 'VIEW_REFRESH'] + }), + getActivity: jest.fn().mockResolvedValue({ + tasks: [ + { + id: 'AWkGcOThOiAPiP5AE-kM', + type: 'VIEW_REFRESH', + componentId: 'AWBLZYhGOUrjxRA-u6ex', + componentKey: 'sonar-csharp', + componentName: 'SonarC#', + componentQualifier: 'APP', + status: 'FAILED', + submittedAt: '2019-02-19T16:47:35+0100', + startedAt: '2019-02-19T16:47:36+0100', + executedAt: '2019-02-19T16:47:36+0100', + executionTimeMs: 16, + logs: false, + errorMessage: + 'Analyses suspended. Please set a valid license for the Edition you installed.', + hasScannerContext: false, + organization: 'default-organization', + errorType: 'LICENSING', + warningCount: 0, + warnings: [] + }, + { + id: 'AWkGcOThOiAPiP5AE-kL', + type: 'VIEW_REFRESH', + componentId: 'AV2ZaHs1Wa2znA6pDz1l', + componentKey: 'c-cpp-build-wrapper', + componentName: 'C/C++ Build Wrapper', + componentQualifier: 'APP', + status: 'SUCCESS', + submittedAt: '2019-02-19T16:47:35+0100', + startedAt: '2019-02-19T16:47:36+0100', + executedAt: '2019-02-19T16:47:36+0100', + executionTimeMs: 19, + logs: false, + hasScannerContext: false, + organization: 'default-organization', + warningCount: 0, + warnings: [] + } + ] + }), + getStatus: jest.fn().mockResolvedValue({ pending: 0, failing: 15, inProgress: 0 }), + cancelAllTasks: jest.fn().mockResolvedValue({}), + cancelTask: jest.fn().mockResolvedValue({}) +})); + +beforeEach(() => { + jest.clearAllMocks(); +}); + +it('should render correctly', async () => { + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot(); + + await waitAndUpdate(wrapper); + expect(wrapper).toMatchSnapshot(); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingCount-test.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingCount-test.tsx new file mode 100644 index 00000000000..82dff7aecf4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingCount-test.tsx @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import { StatPendingCount, Props } from '../StatPendingCount'; + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should not render', () => { + expect(shallowRender({ pendingCount: undefined }).type()).toBeNull(); +}); + +it('should not show cancel pending button', () => { + expect( + shallowRender({ pendingCount: 0 }) + .find('ConfirmButton') + .exists() + ).toBe(false); + expect( + shallowRender({ isSystemAdmin: false }) + .find('ConfirmButton') + .exists() + ).toBe(false); +}); + +it('should trigger cancelling pending', () => { + const onCancelAllPending = jest.fn(); + const result = shallowRender({ onCancelAllPending }); + expect(onCancelAllPending).not.toBeCalled(); + result.find('ConfirmButton').prop('onConfirm')(); + expect(onCancelAllPending).toBeCalled(); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingTime-test.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingTime-test.tsx new file mode 100644 index 00000000000..5aa625193fe --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatPendingTime-test.tsx @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import StatPendingTime, { Props } from '../StatPendingTime'; + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should not render', () => { + expect(shallowRender({ pendingCount: undefined }).type()).toBeNull(); + expect(shallowRender({ pendingCount: 0 }).type()).toBeNull(); + expect(shallowRender({ pendingTime: undefined }).type()).toBeNull(); +}); + +it('should not render when pending time is too small', () => { + expect( + shallowRender({ pendingTime: 0 }) + .find('.emphasised-measure') + .exists() + ).toBe(false); + expect( + shallowRender({ pendingTime: 900 }) + .find('.emphasised-measure') + .exists() + ).toBe(false); +}); + +function shallowRender(props: Partial = {}) { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatStillFailing-test.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatStillFailing-test.tsx new file mode 100644 index 00000000000..ffd9cf82d36 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/StatStillFailing-test.tsx @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import StatStillFailing, { Props } from '../StatStillFailing'; +import { click } from '../../../../helpers/testUtils'; + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should not render', () => { + expect(shallowRender({ failingCount: undefined }).type()).toBeNull(); +}); + +it('should render without the filter link', () => { + expect(shallowRender({ failingCount: 0 })).toMatchSnapshot(); +}); + +it('should trigger filtering failures', () => { + const onShowFailing = jest.fn(); + const result = shallowRender({ onShowFailing }); + expect(onShowFailing).not.toBeCalled(); + click(result.find('ButtonLink')); + expect(onShowFailing).toBeCalled(); +}); + +function shallowRender(props: Partial = {}) { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/StatsContainer.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/Stats-test.tsx similarity index 57% rename from server/sonar-web/src/main/js/apps/background-tasks/components/StatsContainer.tsx rename to server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/Stats-test.tsx index 382312b9953..c20b3f1ea02 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/StatsContainer.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/Stats-test.tsx @@ -17,12 +17,28 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { connect } from 'react-redux'; -import Stats from './Stats'; -import { getAppState, Store } from '../../../store/rootReducer'; +import * as React from 'react'; +import { shallow } from 'enzyme'; +import Stats, { Props } from '../Stats'; +import { mockComponent } from '../../../../helpers/testMocks'; -const mapStateToProps = (state: Store) => ({ - isSystemAdmin: !!getAppState(state).canAdmin +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); }); -export default connect(mapStateToProps)(Stats); +it('should render correctly for a component', () => { + expect(shallowRender({ component: mockComponent() })).toMatchSnapshot(); +}); + +function shallowRender(props: Partial = {}) { + return shallow( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/BackgroundTasksApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/BackgroundTasksApp-test.tsx.snap new file mode 100644 index 00000000000..72846dc1217 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/BackgroundTasksApp-test.tsx.snap @@ -0,0 +1,168 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+ +
+`; + +exports[`should render correctly 2`] = ` +
+ + +
+ + + +
+
+`; diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingCount-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingCount-test.tsx.snap new file mode 100644 index 00000000000..c68b3903d4a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingCount-test.tsx.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + 5 + + + background_tasks.pending + + + + + +`; diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingTime-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingTime-test.tsx.snap new file mode 100644 index 00000000000..85a355501c1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatPendingTime-test.tsx.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + 15s + + + background_tasks.pending_time + + + +`; diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatStillFailing-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatStillFailing-test.tsx.snap new file mode 100644 index 00000000000..98ba7bb6e06 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/StatStillFailing-test.tsx.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + 5 + + + background_tasks.failures + + + +`; + +exports[`should render without the filter link 1`] = ` + + + 0 + + + background_tasks.failures + + + +`; diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Stats-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Stats-test.tsx.snap new file mode 100644 index 00000000000..c352f81491e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Stats-test.tsx.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +
+ + + +
+`; + +exports[`should render correctly for a component 1`] = ` +
+ +
+`; diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index fe313a54f3a..040b965790d 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2356,6 +2356,8 @@ background_tasks.show_warnings=Show Warnings background_tasks.error_message=Error Message background_tasks.error_stacktrace=Error Details background_tasks.pending=pending +background_tasks.pending_time=pending time +background_tasks.pending_time.description=Pending time of the oldest background task waiting to be processed. background_tasks.failures=still failing background_tasks.number_of_workers=Number of Workers: -- 2.39.5