foreman-tasks 12.1.1 → 12.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
- data/foreman-tasks.gemspec +1 -3
- data/lib/foreman_tasks/version.rb +1 -1
- data/test/controllers/api/tasks_controller_test.rb +2 -2
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Errors.js +25 -5
- data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +12 -4
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +217 -201
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +30 -34
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Dependencies.test.js +30 -30
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Errors.test.js +50 -27
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Raw.test.js +44 -22
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +56 -24
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +42 -22
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +45 -54
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +65 -25
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +37 -13
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +53 -8
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.test.js +53 -7
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.test.js +53 -7
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js +5 -4
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.test.js +44 -14
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +6 -5
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js +5 -4
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +3 -8
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.test.js +75 -34
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.test.js +57 -34
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartHelper.test.js +23 -9
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.fixtures.js +14 -11
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.js +19 -21
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.test.js +63 -14
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.js +9 -17
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.test.js +49 -13
- metadata +2 -45
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Errors.test.js.snap +0 -77
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Raw.test.js.snap +0 -174
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +0 -62
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +0 -127
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +0 -580
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +0 -172
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +0 -52
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap +0 -38
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap +0 -38
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap +0 -97
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/__snapshots__/TasksDonutCard.test.js.snap +0 -183
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChart.test.js.snap +0 -302
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChartHelper.test.js.snap +0 -21
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +0 -210
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/__snapshots__/TimeDropDown.test.js.snap +0 -85
|
@@ -1,24 +1,48 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
|
|
3
5
|
import TaskDetails from '../TaskDetails';
|
|
4
6
|
import { minProps } from './TaskDetails.fixtures';
|
|
5
7
|
|
|
6
|
-
const fixtures = {
|
|
7
|
-
'render with loading Props': { ...minProps, isLoading: true },
|
|
8
|
-
'render with error Props': {
|
|
9
|
-
...minProps,
|
|
10
|
-
status: 'ERROR',
|
|
11
|
-
APIerror: { message: 'some-error' },
|
|
12
|
-
},
|
|
13
|
-
'render with min Props': minProps,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
8
|
delete window.location;
|
|
17
9
|
window.location = new URL(
|
|
18
10
|
'https://foreman.com/foreman_tasks/tasks/a15dd820-32f1-4ced-9ab7-c0fab8234c47/'
|
|
19
11
|
);
|
|
20
12
|
|
|
21
13
|
describe('TaskDetails', () => {
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
it('shows error message when status is ERROR', () => {
|
|
15
|
+
render(
|
|
16
|
+
<TaskDetails
|
|
17
|
+
{...minProps}
|
|
18
|
+
status="ERROR"
|
|
19
|
+
APIerror={{ message: 'some-error' }}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
expect(
|
|
23
|
+
screen.getByText(/could not receive data: some-error/i)
|
|
24
|
+
).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('shows skeleton while loading on the Task tab', () => {
|
|
28
|
+
const { container } = render(<TaskDetails {...minProps} isLoading />);
|
|
29
|
+
expect(
|
|
30
|
+
container.querySelector('.react-loading-skeleton')
|
|
31
|
+
).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('renders six tabs with expected labels', () => {
|
|
35
|
+
render(<TaskDetails {...minProps} />);
|
|
36
|
+
expect(document.getElementById('task-details-tabs')).toBeInTheDocument();
|
|
37
|
+
expect(screen.getByRole('tab', { name: /^task$/i })).toBeInTheDocument();
|
|
38
|
+
expect(
|
|
39
|
+
screen.getByRole('tab', { name: /running steps/i })
|
|
40
|
+
).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByRole('tab', { name: /errors/i })).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByRole('tab', { name: /locks/i })).toBeInTheDocument();
|
|
43
|
+
expect(
|
|
44
|
+
screen.getByRole('tab', { name: /dependencies/i })
|
|
45
|
+
).toBeInTheDocument();
|
|
46
|
+
expect(screen.getByRole('tab', { name: /raw/i })).toBeInTheDocument();
|
|
47
|
+
});
|
|
24
48
|
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { testActionSnapshotWithFixtures } from '@theforeman/test';
|
|
2
1
|
import {
|
|
3
2
|
taskReloadStop,
|
|
4
3
|
taskReloadStart,
|
|
5
4
|
cancelStep,
|
|
6
5
|
} from '../TaskDetailsActions';
|
|
6
|
+
import {
|
|
7
|
+
FOREMAN_TASK_DETAILS,
|
|
8
|
+
TASK_STEP_CANCEL,
|
|
9
|
+
} from '../TaskDetailsConstants';
|
|
7
10
|
|
|
8
11
|
jest.mock('foremanReact/components/ToastsList', () => ({
|
|
9
12
|
addToast: toast => ({
|
|
@@ -14,11 +17,53 @@ jest.mock('foremanReact/components/ToastsList', () => ({
|
|
|
14
17
|
}),
|
|
15
18
|
}));
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
'should
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
describe('TaskDetails - Actions', () => {
|
|
21
|
+
it('should stop reload', () => {
|
|
22
|
+
expect(taskReloadStop()).toEqual({
|
|
23
|
+
type: 'STOP_INTERVAL',
|
|
24
|
+
key: FOREMAN_TASK_DETAILS,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should start reload', () => {
|
|
29
|
+
const dispatch = jest.fn();
|
|
30
|
+
taskReloadStart(1)(dispatch);
|
|
31
|
+
|
|
32
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
33
|
+
const [action] = dispatch.mock.calls[0];
|
|
34
|
+
expect(action.type).toBe('API_GET');
|
|
35
|
+
expect(action.interval).toBe(5000);
|
|
36
|
+
expect(action.payload.key).toBe(FOREMAN_TASK_DETAILS);
|
|
37
|
+
expect(action.payload.url).toBe(
|
|
38
|
+
'/foreman_tasks/api/tasks/1/details?include_permissions'
|
|
39
|
+
);
|
|
40
|
+
expect(action.payload.handleSuccess).toEqual(expect.any(Function));
|
|
41
|
+
expect(action.payload.handleError).toEqual(expect.any(Function));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should cancelStep', async () => {
|
|
45
|
+
const dispatch = jest.fn();
|
|
46
|
+
await cancelStep('task-id', 'step-id')(dispatch);
|
|
47
|
+
|
|
48
|
+
expect(dispatch).toHaveBeenCalledTimes(2);
|
|
49
|
+
|
|
50
|
+
expect(dispatch.mock.calls[0][0]).toEqual({
|
|
51
|
+
type: 'TOASTS_ADD',
|
|
52
|
+
payload: {
|
|
53
|
+
message: {
|
|
54
|
+
message: 'Trying to cancel step step-id',
|
|
55
|
+
type: 'info',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
22
59
|
|
|
23
|
-
|
|
24
|
-
|
|
60
|
+
const postAction = dispatch.mock.calls[1][0];
|
|
61
|
+
expect(postAction.type).toBe('API_POST');
|
|
62
|
+
expect(postAction.payload.key).toBe(TASK_STEP_CANCEL);
|
|
63
|
+
expect(postAction.payload.url).toBe(
|
|
64
|
+
'/foreman_tasks/tasks/task-id/cancel_step?step_id=step-id'
|
|
65
|
+
);
|
|
66
|
+
expect(postAction.payload.handleSuccess).toEqual(expect.any(Function));
|
|
67
|
+
expect(postAction.payload.handleError).toEqual(expect.any(Function));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,11 +1,57 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import { TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS } from '../TasksDonutChart/TasksDonutChartConstants';
|
|
2
6
|
|
|
3
7
|
import PausedTasksCard from './PausedTasksCard';
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
jest.mock('../TasksDonutChart/TasksDonutChart', () => {
|
|
10
|
+
const React = require('react');
|
|
11
|
+
const Stub = props => (
|
|
12
|
+
<div
|
|
13
|
+
data-testid="tasks-donut-chart-stub"
|
|
14
|
+
data-last={props.last}
|
|
15
|
+
data-older={props.older}
|
|
16
|
+
data-focused-on={props.focusedOn}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
Stub.displayName = 'TasksDonutChart';
|
|
20
|
+
return Stub;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('PausedTasksCard', () => {
|
|
24
|
+
it('renders Paused title, card id, and chart area', () => {
|
|
25
|
+
render(<PausedTasksCard />);
|
|
26
|
+
expect(screen.getByText('Paused')).toBeInTheDocument();
|
|
27
|
+
expect(document.getElementById('paused-tasks-card')).toBeInTheDocument();
|
|
28
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
29
|
+
expect(chart).toHaveAttribute('data-last', '0');
|
|
30
|
+
expect(chart).toHaveAttribute('data-older', '0');
|
|
31
|
+
expect(chart).toHaveAttribute(
|
|
32
|
+
'data-focused-on',
|
|
33
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.NORMAL
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('forwards extra props to the underlying donut card', () => {
|
|
38
|
+
const updateQuery = jest.fn();
|
|
39
|
+
render(
|
|
40
|
+
<PausedTasksCard
|
|
41
|
+
updateQuery={updateQuery}
|
|
42
|
+
data={{ last: 1, older: 2 }}
|
|
43
|
+
query={{ state: 'paused' }}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
47
|
+
expect(chart).toHaveAttribute('data-last', '1');
|
|
48
|
+
expect(chart).toHaveAttribute('data-older', '2');
|
|
49
|
+
expect(chart).toHaveAttribute(
|
|
50
|
+
'data-focused-on',
|
|
51
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.TOTAL
|
|
52
|
+
);
|
|
9
53
|
|
|
10
|
-
|
|
11
|
-
|
|
54
|
+
fireEvent.click(screen.getByText('Paused'));
|
|
55
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: 'paused' });
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -1,11 +1,57 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import { TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS } from '../TasksDonutChart/TasksDonutChartConstants';
|
|
2
6
|
|
|
3
7
|
import RunningTasksCard from './RunningTasksCard';
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
jest.mock('../TasksDonutChart/TasksDonutChart', () => {
|
|
10
|
+
const React = require('react');
|
|
11
|
+
const Stub = props => (
|
|
12
|
+
<div
|
|
13
|
+
data-testid="tasks-donut-chart-stub"
|
|
14
|
+
data-last={props.last}
|
|
15
|
+
data-older={props.older}
|
|
16
|
+
data-focused-on={props.focusedOn}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
Stub.displayName = 'TasksDonutChart';
|
|
20
|
+
return Stub;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('RunningTasksCard', () => {
|
|
24
|
+
it('renders Running title, card id, and chart area', () => {
|
|
25
|
+
render(<RunningTasksCard />);
|
|
26
|
+
expect(screen.getByText('Running')).toBeInTheDocument();
|
|
27
|
+
expect(document.getElementById('running-tasks-card')).toBeInTheDocument();
|
|
28
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
29
|
+
expect(chart).toHaveAttribute('data-last', '0');
|
|
30
|
+
expect(chart).toHaveAttribute('data-older', '0');
|
|
31
|
+
expect(chart).toHaveAttribute(
|
|
32
|
+
'data-focused-on',
|
|
33
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.NORMAL
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('forwards extra props to the underlying donut card', () => {
|
|
38
|
+
const updateQuery = jest.fn();
|
|
39
|
+
render(
|
|
40
|
+
<RunningTasksCard
|
|
41
|
+
updateQuery={updateQuery}
|
|
42
|
+
data={{ last: 2, older: 4 }}
|
|
43
|
+
query={{ state: 'running' }}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
47
|
+
expect(chart).toHaveAttribute('data-last', '2');
|
|
48
|
+
expect(chart).toHaveAttribute('data-older', '4');
|
|
49
|
+
expect(chart).toHaveAttribute(
|
|
50
|
+
'data-focused-on',
|
|
51
|
+
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.TOTAL
|
|
52
|
+
);
|
|
9
53
|
|
|
10
|
-
|
|
11
|
-
|
|
54
|
+
fireEvent.click(screen.getByText('Running'));
|
|
55
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: 'running' });
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Card } from 'patternfly-
|
|
3
|
+
import { Card, CardTitle, CardBody } from '@patternfly/react-core';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import { noop } from 'foremanReact/common/helpers';
|
|
6
6
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
@@ -32,14 +32,15 @@ const ScheduledTasksCard = ({
|
|
|
32
32
|
)}
|
|
33
33
|
{...props}
|
|
34
34
|
id="scheduled-tasks-card"
|
|
35
|
+
ouiaId="scheduled-tasks-card"
|
|
35
36
|
>
|
|
36
|
-
<
|
|
37
|
-
<
|
|
37
|
+
<CardTitle onClick={onClick}>{__('Scheduled')}</CardTitle>
|
|
38
|
+
<CardBody>
|
|
38
39
|
<div className="scheduled-data" onClick={onClick}>
|
|
39
40
|
{data}
|
|
40
41
|
<p>{__('Total')}</p>
|
|
41
42
|
</div>
|
|
42
|
-
</
|
|
43
|
+
</CardBody>
|
|
43
44
|
</Card>
|
|
44
45
|
);
|
|
45
46
|
};
|
|
@@ -1,18 +1,48 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
|
|
3
5
|
import { TASKS_DASHBOARD_AVAILABLE_QUERY_STATES } from '../../../../TasksDashboardConstants';
|
|
4
6
|
import ScheduledTasksCard from './ScheduledTasksCard';
|
|
5
7
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
const { SCHEDULED } = TASKS_DASHBOARD_AVAILABLE_QUERY_STATES;
|
|
9
|
+
|
|
10
|
+
describe('ScheduledTasksCard', () => {
|
|
11
|
+
it('renders scheduled count, labels, and card structure', () => {
|
|
12
|
+
render(<ScheduledTasksCard data={3} />);
|
|
13
|
+
expect(screen.getByText('Scheduled')).toBeInTheDocument();
|
|
14
|
+
expect(screen.getByText('Total')).toBeInTheDocument();
|
|
15
|
+
expect(document.getElementById('scheduled-tasks-card')).toBeInTheDocument();
|
|
16
|
+
expect(document.querySelector('.scheduled-data')?.textContent).toContain(
|
|
17
|
+
'3'
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('merges optional className onto the card', () => {
|
|
22
|
+
const { container } = render(
|
|
23
|
+
<ScheduledTasksCard className="extra-scheduled-class" />
|
|
24
|
+
);
|
|
25
|
+
expect(container.querySelector('.extra-scheduled-class')).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('marks the card selected when query state is scheduled', () => {
|
|
29
|
+
const { container } = render(
|
|
30
|
+
<ScheduledTasksCard query={{ state: SCHEDULED }} />
|
|
31
|
+
);
|
|
32
|
+
expect(container.querySelector('#scheduled-tasks-card')).toHaveClass(
|
|
33
|
+
'selected-tasks-card'
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('calls updateQuery with scheduled state when title or data area is clicked', () => {
|
|
38
|
+
const updateQuery = jest.fn();
|
|
39
|
+
render(<ScheduledTasksCard updateQuery={updateQuery} />);
|
|
40
|
+
|
|
41
|
+
fireEvent.click(screen.getByText('Scheduled'));
|
|
42
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: SCHEDULED });
|
|
43
|
+
|
|
44
|
+
updateQuery.mockClear();
|
|
45
|
+
fireEvent.click(document.querySelector('.scheduled-data'));
|
|
46
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: SCHEDULED });
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Card } from 'patternfly-
|
|
3
|
+
import { Card, CardTitle, CardBody } from '@patternfly/react-core';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import { noop } from 'foremanReact/common/helpers';
|
|
6
6
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
@@ -38,11 +38,12 @@ const StoppedTasksCard = ({
|
|
|
38
38
|
)}
|
|
39
39
|
{...props}
|
|
40
40
|
id="stopped-tasks-card"
|
|
41
|
+
ouiaId="stopped-tasks-card"
|
|
41
42
|
>
|
|
42
|
-
<
|
|
43
|
+
<CardTitle onClick={() => updateQuery({ state: STOPPED })}>
|
|
43
44
|
{__('Stopped')}
|
|
44
|
-
</
|
|
45
|
-
<
|
|
45
|
+
</CardTitle>
|
|
46
|
+
<CardBody>
|
|
46
47
|
<React.Fragment>
|
|
47
48
|
<StoppedTable
|
|
48
49
|
data={data.results}
|
|
@@ -56,7 +57,7 @@ const StoppedTasksCard = ({
|
|
|
56
57
|
query={query}
|
|
57
58
|
/>
|
|
58
59
|
</React.Fragment>
|
|
59
|
-
</
|
|
60
|
+
</CardBody>
|
|
60
61
|
</Card>
|
|
61
62
|
);
|
|
62
63
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
-
import { Card } from 'patternfly-
|
|
4
|
+
import { Card, CardTitle, CardBody } from '@patternfly/react-core';
|
|
5
5
|
import { noop } from 'foremanReact/common/helpers';
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -42,9 +42,10 @@ const TasksDonutCard = ({
|
|
|
42
42
|
'not-focused': focusedOn === TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS.NONE,
|
|
43
43
|
})}
|
|
44
44
|
{...props}
|
|
45
|
+
ouiaId="tasks-donut-card"
|
|
45
46
|
>
|
|
46
|
-
<
|
|
47
|
-
<
|
|
47
|
+
<CardTitle onClick={onTotalClick}>{title}</CardTitle>
|
|
48
|
+
<CardBody className="card-pf-body">
|
|
48
49
|
<TasksDonutChart
|
|
49
50
|
last={data.last}
|
|
50
51
|
older={data.older}
|
|
@@ -66,7 +67,7 @@ const TasksDonutCard = ({
|
|
|
66
67
|
})
|
|
67
68
|
}
|
|
68
69
|
/>
|
|
69
|
-
</
|
|
70
|
+
</CardBody>
|
|
70
71
|
</Card>
|
|
71
72
|
);
|
|
72
73
|
};
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
.tasks-donut-card {
|
|
2
2
|
&.not-focused {
|
|
3
|
-
.
|
|
3
|
+
.pf-v5-c-card__title-text,
|
|
4
4
|
.card-pf-body {
|
|
5
5
|
opacity: 0.6;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
-
.
|
|
8
|
+
.pf-v5-c-card__title-text {
|
|
9
9
|
text-align: center;
|
|
10
|
-
font-size: 180%;
|
|
11
10
|
cursor: pointer;
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
.card-pf-body {
|
|
15
|
-
padding-left: 15px;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
13
|
&.selected-tasks-card {
|
|
19
|
-
.
|
|
14
|
+
.pf-v5-c-card__title-text {
|
|
20
15
|
font-weight: bold;
|
|
21
16
|
}
|
|
22
17
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
|
|
3
5
|
import {
|
|
4
6
|
TASKS_DASHBOARD_AVAILABLE_TIMES,
|
|
@@ -6,38 +8,77 @@ import {
|
|
|
6
8
|
} from '../../../../TasksDashboardConstants';
|
|
7
9
|
import TasksDonutCard from './TasksDonutCard';
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
jest.mock('../TasksDonutChart/TasksDonutChart', () => {
|
|
12
|
+
const React = require('react');
|
|
13
|
+
const Stub = props => (
|
|
14
|
+
<div
|
|
15
|
+
data-testid="tasks-donut-chart-stub"
|
|
16
|
+
data-focused-on={props.focusedOn}
|
|
17
|
+
data-time={props.time}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
Stub.displayName = 'TasksDonutChart';
|
|
21
|
+
return Stub;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('TasksDonutCard', () => {
|
|
25
|
+
const baseProps = {
|
|
26
|
+
title: 'Card title',
|
|
27
|
+
wantedQueryState: 'running',
|
|
16
28
|
data: { last: 3, older: 5 },
|
|
17
|
-
},
|
|
18
|
-
'render with total selected': {
|
|
19
|
-
wantedQueryState: 'some-state',
|
|
20
|
-
query: { state: 'some-state' },
|
|
21
|
-
},
|
|
22
|
-
'render with last selected': {
|
|
23
|
-
wantedQueryState: 'some-state',
|
|
24
|
-
time: TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK,
|
|
25
|
-
query: {
|
|
26
|
-
state: 'some-state',
|
|
27
|
-
mode: TASKS_DASHBOARD_AVAILABLE_QUERY_MODES.LAST,
|
|
28
|
-
time: TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK,
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
'render with older selected': {
|
|
32
|
-
wantedQueryState: 'some-state',
|
|
33
29
|
time: TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
it('renders title and wires chart stub with time and focus from query', () => {
|
|
33
|
+
render(
|
|
34
|
+
<TasksDonutCard
|
|
35
|
+
{...baseProps}
|
|
36
|
+
query={{ state: 'running', mode: TASKS_DASHBOARD_AVAILABLE_QUERY_MODES.LAST, time: TASKS_DASHBOARD_AVAILABLE_TIMES.WEEK }}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
expect(screen.getByText('Card title')).toBeInTheDocument();
|
|
40
|
+
const chart = screen.getByTestId('tasks-donut-chart-stub');
|
|
41
|
+
expect(chart).toHaveAttribute('data-focused-on', 'last');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('clicking the title requests the wanted query state', () => {
|
|
45
|
+
const updateQuery = jest.fn();
|
|
46
|
+
render(<TasksDonutCard {...baseProps} updateQuery={updateQuery} />);
|
|
47
|
+
fireEvent.click(screen.getByText('Card title'));
|
|
48
|
+
expect(updateQuery).toHaveBeenCalledWith({ state: 'running' });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('applies selected styling when this card state matches the query (total focus)', () => {
|
|
52
|
+
const { container } = render(
|
|
53
|
+
<TasksDonutCard {...baseProps} query={{ state: 'running' }} />
|
|
54
|
+
);
|
|
55
|
+
expect(container.querySelector('.tasks-donut-card')).toHaveClass(
|
|
56
|
+
'selected-tasks-card'
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('applies not-focused when another dashboard state is active', () => {
|
|
61
|
+
const { container } = render(
|
|
62
|
+
<TasksDonutCard {...baseProps} query={{ state: 'paused' }} />
|
|
63
|
+
);
|
|
64
|
+
expect(container.querySelector('.tasks-donut-card')).toHaveClass(
|
|
65
|
+
'not-focused'
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('merges className onto the card', () => {
|
|
70
|
+
const { container } = render(
|
|
71
|
+
<TasksDonutCard {...baseProps} className="extra-donut" />
|
|
72
|
+
);
|
|
73
|
+
expect(container.querySelector('.tasks-donut-card')).toHaveClass(
|
|
74
|
+
'extra-donut'
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('does not mark the card selected or dimmed when the query is empty', () => {
|
|
79
|
+
const { container } = render(<TasksDonutCard {...baseProps} query={{}} />);
|
|
80
|
+
const card = container.querySelector('.tasks-donut-card');
|
|
81
|
+
expect(card).not.toHaveClass('selected-tasks-card');
|
|
82
|
+
expect(card).not.toHaveClass('not-focused');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -1,40 +1,63 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
2
4
|
|
|
3
|
-
import {
|
|
5
|
+
import { TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS } from './TasksDonutChartConstants';
|
|
4
6
|
import TasksDonutChart from './TasksDonutChart';
|
|
5
7
|
|
|
6
|
-
jest.mock('./TasksDonutChartHelper', () =>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
updateChartTitle: jest.fn(),
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
const createRequiredProps = () => ({ last: 3, older: 5 });
|
|
18
|
-
|
|
19
|
-
const fixtures = {
|
|
20
|
-
'render with minimal props': { ...createRequiredProps() },
|
|
21
|
-
'render with props': {
|
|
22
|
-
...createRequiredProps(),
|
|
23
|
-
className: 'some-class',
|
|
24
|
-
time: 'time-period',
|
|
25
|
-
colorsPattern: ['color1', 'color2'],
|
|
26
|
-
onTotalClick: jest.fn(),
|
|
27
|
-
onLastClick: jest.fn(),
|
|
28
|
-
onOlderClick: jest.fn(),
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS_ARRAY.forEach(mode => {
|
|
33
|
-
fixtures[`render with focused-on ${mode}`] = {
|
|
34
|
-
...createRequiredProps(),
|
|
35
|
-
focusedOn: mode,
|
|
8
|
+
jest.mock('./TasksDonutChartHelper', () => {
|
|
9
|
+
const actual = jest.requireActual('./TasksDonutChartHelper');
|
|
10
|
+
return {
|
|
11
|
+
...actual,
|
|
12
|
+
getBaseChartConfig: jest.fn(() => ({ mockBase: true })),
|
|
13
|
+
updateChartTitle: jest.fn(),
|
|
14
|
+
assignExtraChartEvents: jest.fn(),
|
|
15
|
+
clearExtraChartEvents: jest.fn(),
|
|
36
16
|
};
|
|
37
17
|
});
|
|
38
18
|
|
|
39
|
-
|
|
40
|
-
|
|
19
|
+
jest.mock('../../../../../../Components/Chart/Chart', () => {
|
|
20
|
+
const React = require('react');
|
|
21
|
+
return class MockChart extends React.Component {
|
|
22
|
+
componentDidMount() {
|
|
23
|
+
this.props.onChartCreate?.({
|
|
24
|
+
element: {},
|
|
25
|
+
focus: jest.fn(),
|
|
26
|
+
revert: jest.fn(),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
render() {
|
|
31
|
+
return <div data-testid="chart-root" className={this.props.className} />;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const { NORMAL, TOTAL } = TASKS_DONUT_CHART_FOCUSED_ON_OPTIONS;
|
|
37
|
+
|
|
38
|
+
describe('TasksDonutChart', () => {
|
|
39
|
+
const required = { last: 3, older: 5 };
|
|
40
|
+
|
|
41
|
+
it('renders a chart with donut classes', () => {
|
|
42
|
+
render(<TasksDonutChart {...required} />);
|
|
43
|
+
const root = screen.getByTestId('chart-root');
|
|
44
|
+
expect(root).toHaveClass('donut-chart-pf', 'tasks-donut-chart');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('adds selection class when focusedOn is not normal or none', () => {
|
|
48
|
+
render(<TasksDonutChart {...required} focusedOn={TOTAL} />);
|
|
49
|
+
expect(screen.getByTestId('chart-root')).toHaveClass('tasks-donut-selected');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('does not add selection class in normal focus', () => {
|
|
53
|
+
render(<TasksDonutChart {...required} focusedOn={NORMAL} />);
|
|
54
|
+
expect(screen.getByTestId('chart-root')).not.toHaveClass(
|
|
55
|
+
'tasks-donut-selected'
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('merges custom className', () => {
|
|
60
|
+
render(<TasksDonutChart {...required} className="custom-chart" />);
|
|
61
|
+
expect(screen.getByTestId('chart-root')).toHaveClass('custom-chart');
|
|
62
|
+
});
|
|
63
|
+
});
|