foreman-tasks 0.16.0 → 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.babelrc +4 -1
  3. data/.eslintrc +4 -13
  4. data/app/assets/stylesheets/foreman_tasks/application.css.scss +0 -37
  5. data/app/controllers/foreman_tasks/api/tasks_controller.rb +9 -5
  6. data/app/controllers/foreman_tasks/tasks_controller.rb +23 -19
  7. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +28 -29
  8. data/app/lib/actions/bulk_action.rb +1 -1
  9. data/app/models/foreman_tasks/task.rb +1 -1
  10. data/app/models/foreman_tasks/task/dynflow_task.rb +30 -0
  11. data/app/services/foreman_tasks/troubleshooting_help_generator.rb +4 -0
  12. data/app/views/foreman_tasks/api/tasks/details.json.rabl +18 -0
  13. data/app/views/foreman_tasks/layouts/react.html.erb +1 -1
  14. data/app/views/foreman_tasks/tasks/index.html.erb +3 -0
  15. data/app/views/foreman_tasks/tasks/show.html.erb +10 -134
  16. data/config/routes.rb +3 -0
  17. data/lib/foreman_tasks/engine.rb +1 -1
  18. data/lib/foreman_tasks/tasks/export_tasks.rake +1 -2
  19. data/lib/foreman_tasks/version.rb +1 -1
  20. data/package.json +6 -20
  21. data/test/controllers/tasks_controller_test.rb +11 -0
  22. data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +39 -0
  23. data/test/unit/actions/bulk_action_test.rb +2 -0
  24. data/test/unit/task_test.rb +4 -0
  25. data/webpack/ForemanTasks/Components/TaskDetails/Components/Errors.js +60 -0
  26. data/webpack/ForemanTasks/Components/TaskDetails/Components/Locks.js +46 -0
  27. data/webpack/ForemanTasks/Components/TaskDetails/Components/Raw.js +73 -0
  28. data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +55 -0
  29. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +202 -0
  30. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskHelper.js +38 -0
  31. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +238 -0
  32. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Errors.test.js +36 -0
  33. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Locks.test.js +28 -0
  34. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Raw.test.js +27 -0
  35. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +29 -0
  36. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +18 -0
  37. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskHelper.test.js +77 -0
  38. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +60 -0
  39. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Errors.test.js.snap +77 -0
  40. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Locks.test.js.snap +108 -0
  41. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Raw.test.js.snap +174 -0
  42. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +62 -0
  43. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +282 -0
  44. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskHelper.test.js.snap +37 -0
  45. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +568 -0
  46. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +87 -0
  47. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +63 -0
  48. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.stories.js +5 -0
  49. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +109 -0
  50. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +18 -0
  51. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +44 -0
  52. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +83 -0
  53. data/webpack/ForemanTasks/Components/TaskDetails/TasksDetailsHelper.js +1 -0
  54. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +12 -0
  55. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +20 -0
  56. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +33 -0
  57. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +97 -0
  58. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +43 -0
  59. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsReducer.test.js.snap +26 -0
  60. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/integration.test.js.snap +122 -0
  61. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +63 -0
  62. data/webpack/ForemanTasks/Components/TaskDetails/index.js +77 -0
  63. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.js +6 -1
  64. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap +2 -0
  65. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.js +6 -1
  66. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap +2 -0
  67. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js +3 -6
  68. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +0 -3
  69. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap +3 -0
  70. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +2 -0
  71. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +0 -4
  72. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardHelper.js +3 -3
  73. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +495 -54
  74. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js +1 -0
  75. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +6 -0
  76. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.scss +0 -3
  77. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.scss +1 -1
  78. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboard.scss +2 -2
  79. data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +83 -0
  80. data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -0
  81. data/webpack/__mocks__/foremanReact/common/I18n.js +2 -0
  82. data/webpack/__mocks__/foremanReact/components/Layout/LayoutActions.js +2 -0
  83. data/webpack/index.js +5 -0
  84. metadata +46 -9
  85. data/app/views/foreman_tasks/tasks/_details.html.erb +0 -195
  86. data/app/views/foreman_tasks/tasks/_errors.html.erb +0 -42
  87. data/app/views/foreman_tasks/tasks/_locks.html.erb +0 -19
  88. data/app/views/foreman_tasks/tasks/_raw.html.erb +0 -28
  89. data/app/views/foreman_tasks/tasks/_running_steps.html.erb +0 -40
@@ -0,0 +1,38 @@
1
+ import { translate as __, documentLocale } from 'foremanReact/common/I18n';
2
+ import React from 'react';
3
+ import { FormattedRelative } from 'react-intl';
4
+ import humanizeDuration from 'humanize-duration';
5
+
6
+ const formatDate = date => {
7
+ // Firefox doesnt format dd-mm-yyyy type strings to date
8
+ if (typeof date === 'string' || date instanceof String)
9
+ return new Date(date.replace(/-/, '/').replace(/-/, '/'));
10
+ return date;
11
+ };
12
+
13
+ export const timeInWords = time => {
14
+ if (!time) return __('N/A');
15
+ time = formatDate(time);
16
+ return <FormattedRelative value={time} />;
17
+ };
18
+
19
+ export const durationInWords = (
20
+ start,
21
+ finish,
22
+ selectedLocale = documentLocale()
23
+ ) => {
24
+ if (!start) return __('N/A');
25
+ start = formatDate(start).getTime();
26
+ finish = formatDate(finish).getTime();
27
+ return {
28
+ text: humanizeDuration(new Date(finish - start).getTime(), {
29
+ largest: 1,
30
+ language: selectedLocale,
31
+ fallbacks: ['en'],
32
+ }),
33
+ tooltip: `${numberWithDelimiter((finish - start) / 1000)} ${__('seconds')}`,
34
+ };
35
+ };
36
+
37
+ const numberWithDelimiter = x =>
38
+ x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
@@ -0,0 +1,238 @@
1
+ import React, { Component } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Grid, Row, Col, ProgressBar } from 'patternfly-react';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+ import EllipsisWithTooltip from 'react-ellipsis-with-tooltip';
6
+ import { timeInWords } from './TaskHelper';
7
+
8
+ class TaskInfo extends Component {
9
+ isDelayed = () => {
10
+ const startAt = new Date(this.props.startAt);
11
+ const startedAt = new Date(this.props.startedAt);
12
+ startAt.setMilliseconds(0);
13
+ startedAt.setMilliseconds(0);
14
+ return startAt.getTime() !== startedAt.getTime();
15
+ };
16
+ resultIcon = () => {
17
+ if (this.props.state !== 'stopped') return 'task-status pficon-help';
18
+ const { result } = this.props;
19
+ let icon;
20
+ switch (result) {
21
+ case 'success':
22
+ icon = 'pficon-ok';
23
+ break;
24
+ case 'error':
25
+ icon = 'pficon-error-circle-o';
26
+ break;
27
+ case 'warning':
28
+ icon = 'pficon-ok status-warn';
29
+ break;
30
+ default:
31
+ icon = 'pficon-help';
32
+ break;
33
+ }
34
+ return `task-status ${icon}`;
35
+ };
36
+
37
+ progressBarType = () => {
38
+ const { result } = this.props;
39
+ switch (result) {
40
+ case 'error':
41
+ return 'danger';
42
+ case 'success':
43
+ return 'success';
44
+ case 'warning':
45
+ return 'warning';
46
+ default:
47
+ return null;
48
+ }
49
+ };
50
+
51
+ render() {
52
+ const {
53
+ action,
54
+ endedAt,
55
+ result,
56
+ startAt,
57
+ startBefore,
58
+ startedAt,
59
+ state,
60
+ help,
61
+ output,
62
+ error,
63
+ progress,
64
+ username,
65
+ usernamePath,
66
+ } = this.props;
67
+
68
+ const details = [
69
+ [
70
+ {
71
+ title: 'Name',
72
+ value: (
73
+ <EllipsisWithTooltip>{action || __('N/A')}</EllipsisWithTooltip>
74
+ ),
75
+ },
76
+ { title: 'Start at', value: timeInWords(startAt) },
77
+ ],
78
+ [
79
+ {
80
+ title: 'Result',
81
+ value: (
82
+ <React.Fragment>
83
+ <i className={this.resultIcon()} />
84
+ <span> {result}</span>
85
+ </React.Fragment>
86
+ ),
87
+ },
88
+ { title: 'Started at', value: timeInWords(startedAt) },
89
+ ],
90
+ [
91
+ {
92
+ title: 'Triggered by',
93
+ value: (usernamePath || '').includes('href') ? (
94
+ <a href={usernamePath.split('"')[1]}>{username}</a>
95
+ ) : (
96
+ username || ''
97
+ ),
98
+ },
99
+ { title: 'Ended at', value: timeInWords(endedAt) },
100
+ ],
101
+ [
102
+ {
103
+ title: 'Execution type',
104
+ value: __(this.isDelayed() ? 'Delayed' : 'Immediate'),
105
+ },
106
+ {
107
+ title: 'Start before',
108
+ value: startBefore ? timeInWords(startBefore) : '-',
109
+ },
110
+ ],
111
+ ];
112
+ return (
113
+ <Grid>
114
+ <br />
115
+ {details.map((items, key) => (
116
+ <Row key={key}>
117
+ <Col md={2} sm={6}>
118
+ <span className="list-group-item-heading">
119
+ {__(items[0].title)}:
120
+ </span>
121
+ </Col>
122
+ <Col md={5} sm={6}>
123
+ <span>{items[0].value}</span>
124
+ </Col>
125
+ <Col md={2} sm={6}>
126
+ <span className="list-group-item-heading">
127
+ {__(items[1].title)}:
128
+ </span>
129
+ </Col>
130
+ <Col md={3} sm={6}>
131
+ {items[1].value}
132
+ </Col>
133
+ </Row>
134
+ ))}
135
+ <br />
136
+ <Row>
137
+ <Col xs={6}>
138
+ <div className="progress-description">
139
+ <span className="list-group-item-heading">{__('State')}: </span>
140
+ {state}
141
+ </div>
142
+ </Col>
143
+ <Col xs={3} xsOffset={3} className="progress-label-top-right">
144
+ <span>{`${progress}% ${__('Complete')}`}</span>
145
+ </Col>
146
+ <Col xs={12}>
147
+ <ProgressBar
148
+ now={progress}
149
+ bsStyle={this.progressBarType()}
150
+ striped
151
+ />
152
+ </Col>
153
+ </Row>
154
+ <br />
155
+ {help && (
156
+ <Row>
157
+ <Col xs={12}>
158
+ <p>
159
+ <span>
160
+ <b>{__('Troubleshooting')}</b>
161
+ </span>
162
+ </p>
163
+ <p>
164
+ {help.split('\n').map((item, i) => (
165
+ <React.Fragment key={i}>
166
+ {item}
167
+ <br />
168
+ </React.Fragment>
169
+ ))}
170
+ </p>
171
+ </Col>
172
+ </Row>
173
+ )}
174
+ {output && output.length > 0 && (
175
+ <Row>
176
+ <Col xs={12}>
177
+ <p>
178
+ <span>
179
+ <b>{__('Output:')}</b>
180
+ </span>
181
+ </p>
182
+ <pre>{output}</pre>
183
+ </Col>
184
+ </Row>
185
+ )}
186
+ {error && error.length > 0 && (
187
+ <Row>
188
+ <Col xs={12}>
189
+ <div>
190
+ <span>
191
+ <b>{__('Errors:')}</b>
192
+ </span>
193
+ </div>
194
+ <pre>{error}</pre>
195
+ </Col>
196
+ </Row>
197
+ )}
198
+ </Grid>
199
+ );
200
+ }
201
+ }
202
+
203
+ TaskInfo.propTypes = {
204
+ action: PropTypes.string,
205
+ endedAt: PropTypes.string,
206
+ result: PropTypes.string,
207
+ startAt: PropTypes.string,
208
+ startBefore: PropTypes.string,
209
+ startedAt: PropTypes.string,
210
+ state: PropTypes.string,
211
+ help: PropTypes.string,
212
+ error: PropTypes.array,
213
+ progress: PropTypes.number,
214
+ username: PropTypes.string,
215
+ usernamePath: PropTypes.string,
216
+ output: PropTypes.PropTypes.oneOfType([
217
+ PropTypes.string,
218
+ PropTypes.shape({}),
219
+ ]),
220
+ };
221
+
222
+ TaskInfo.defaultProps = {
223
+ action: '',
224
+ endedAt: '',
225
+ result: 'error',
226
+ startAt: '',
227
+ startBefore: '',
228
+ startedAt: '',
229
+ state: '',
230
+ help: '',
231
+ error: [],
232
+ progress: 0,
233
+ username: '',
234
+ usernamePath: '',
235
+ output: '',
236
+ };
237
+
238
+ export default TaskInfo;
@@ -0,0 +1,36 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import Errors from '../Errors';
4
+
5
+ const fixtures = {
6
+ 'render without Props': {},
7
+ 'render with Props': {
8
+ executionPlan: {
9
+ state: 'paused',
10
+ cancellable: false,
11
+ },
12
+ failedSteps: [
13
+ {
14
+ error: {
15
+ exception_class: 'RuntimeError',
16
+ message:
17
+ 'Action Actions::Katello::EventQueue::Monitor is already active',
18
+ backtrace: [
19
+ "/home/vagrant/.gem/ruby/gems/dynflow-1.2.3/lib/dynflow/action/singleton.rb:15:in `rescue in singleton_lock!'",
20
+ "/home/vagrant/.gem/ruby/gems/dynflow-1.2.3/lib/dynflow/action/singleton.rb:12:in `singleton_lock!'",
21
+ ],
22
+ },
23
+ action_class: 'Actions::Katello::EventQueue::Monitor',
24
+ state: 'error',
25
+ input:
26
+ '{"locale"=>"en",\n "current_request_id"=>nil,\n "current_user_id"=>4,\n "current_organization_id"=>nil,\n "current_location_id"=>nil}\n',
27
+ output: '{}\n',
28
+ },
29
+ ],
30
+ },
31
+ };
32
+
33
+ describe('Errors', () => {
34
+ describe('rendering', () =>
35
+ testComponentSnapshotsWithFixtures(Errors, fixtures));
36
+ });
@@ -0,0 +1,28 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import Locks from '../Locks';
4
+
5
+ const fixtures = {
6
+ 'render without Props': {},
7
+ 'render with Props': {
8
+ locks: [
9
+ {
10
+ name: 'task_owner',
11
+ exclusive: false,
12
+ resource_type: 'User',
13
+ resource_id: 4,
14
+ },
15
+ {
16
+ name: 'task_owner2',
17
+ exclusive: false,
18
+ resource_type: 'User',
19
+ resource_id: 2,
20
+ },
21
+ ],
22
+ },
23
+ };
24
+
25
+ describe('Locks', () => {
26
+ describe('rendering', () =>
27
+ testComponentSnapshotsWithFixtures(Locks, fixtures));
28
+ });
@@ -0,0 +1,27 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import Raw from '../Raw';
4
+
5
+ const fixtures = {
6
+ 'render without Props': {},
7
+ 'render with Props': {
8
+ startedAt: '2019-06-17 16:04:09 +0300',
9
+ endedAt: '2019-06-17 16:05:09 +0300',
10
+ id: '6b0d6db2-e9ab-40da-94e5-b6842ac50bd0',
11
+ label: 'Actions::Katello::EventQueue::Monitor',
12
+ input: {
13
+ locale: 'en',
14
+ current_request_id: 1,
15
+ current_user_id: 4,
16
+ current_organization_id: 2,
17
+ current_location_id: 3,
18
+ },
19
+ output: {},
20
+ externalId: 'test',
21
+ },
22
+ };
23
+
24
+ describe('Raw', () => {
25
+ describe('rendering', () =>
26
+ testComponentSnapshotsWithFixtures(Raw, fixtures));
27
+ });
@@ -0,0 +1,29 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import RunningSteps from '../RunningSteps';
4
+
5
+ const fixtures = {
6
+ 'render without Props': {},
7
+ 'render with Props': {
8
+ executionPlan: {
9
+ state: 'paused',
10
+ cancellable: false,
11
+ },
12
+ runningSteps: [
13
+ {
14
+ cancellable: false,
15
+ id: 1,
16
+ action_class: 'test',
17
+ state: 'paused',
18
+ input:
19
+ '{"locale"=>"en",\n "current_request_id"=>nil,\n "current_user_id"=>4,\n "current_organization_id"=>nil,\n "current_location_id"=>nil}\n',
20
+ output: '{}\n',
21
+ },
22
+ ],
23
+ },
24
+ };
25
+
26
+ describe('RunningSteps', () => {
27
+ describe('rendering', () =>
28
+ testComponentSnapshotsWithFixtures(RunningSteps, fixtures));
29
+ });
@@ -0,0 +1,18 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import Task from '../Task';
4
+
5
+ const fixtures = {
6
+ 'render without Props': { id: 'test' },
7
+ 'render with some Props': {
8
+ id: 'test',
9
+ state: 'paused',
10
+ hasSubTasks: true,
11
+ allowDangerousActions: true,
12
+ },
13
+ };
14
+
15
+ describe('Task', () => {
16
+ describe('rendering', () =>
17
+ testComponentSnapshotsWithFixtures(Task, fixtures));
18
+ });
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import { mount } from 'enzyme';
3
+ import toJson from 'enzyme-to-json';
4
+ import { IntlProvider } from 'react-intl';
5
+ import { timeInWords, durationInWords } from '../TaskHelper';
6
+
7
+ describe('timeInWords', () => {
8
+ it('should work for past minutes', () => {
9
+ const component = mount(
10
+ <IntlProvider locale="en">
11
+ {timeInWords(new Date().getTime() - 1000 * 60 * 5)}
12
+ </IntlProvider>
13
+ );
14
+ expect(toJson(component.render())).toMatchSnapshot();
15
+ });
16
+ it('should work for past hours', () => {
17
+ const component = mount(
18
+ <IntlProvider locale="en">
19
+ {timeInWords(new Date().getTime() - 1000 * 60 * 60 * 5)}
20
+ </IntlProvider>
21
+ );
22
+ expect(toJson(component.render())).toMatchSnapshot();
23
+ });
24
+ it('should work for past days', () => {
25
+ const component = mount(
26
+ <IntlProvider locale="en">
27
+ {timeInWords(new Date().getTime() - 1000 * 60 * 60 * 24 * 5)}
28
+ </IntlProvider>
29
+ );
30
+ expect(toJson(component.render())).toMatchSnapshot();
31
+ });
32
+ it('should work for future minutes', () => {
33
+ const component = mount(
34
+ <IntlProvider locale="en">
35
+ {timeInWords(new Date().getTime() + 1000 * 60 * 5)}
36
+ </IntlProvider>
37
+ );
38
+ expect(toJson(component.render())).toMatchSnapshot();
39
+ });
40
+ it('should work for future hours', () => {
41
+ const component = mount(
42
+ <IntlProvider locale="en">
43
+ {timeInWords(new Date().getTime() + 1000 * 60 * 60 * 5)}
44
+ </IntlProvider>
45
+ );
46
+ expect(toJson(component.render())).toMatchSnapshot();
47
+ });
48
+ it('should work for future days', () => {
49
+ const component = mount(
50
+ <IntlProvider locale="en">
51
+ {timeInWords(new Date().getTime() + 1000 * 60 * 60 * 24 * 5)}
52
+ </IntlProvider>
53
+ );
54
+ expect(toJson(component.render())).toMatchSnapshot();
55
+ });
56
+ });
57
+
58
+ describe('durationInWords', () => {
59
+ it('should work for seconds', () => {
60
+ expect(durationInWords('1/1/1 10:00:00', '1/1/1 10:00:01')).toEqual({
61
+ text: '1 second',
62
+ tooltip: '1 seconds',
63
+ });
64
+ });
65
+ it('should work for minutes', () => {
66
+ expect(durationInWords('1/1/1 10:00:00', '1/1/1 10:02:01')).toEqual({
67
+ text: '2 minutes',
68
+ tooltip: '121 seconds',
69
+ });
70
+ });
71
+ it('should work for hours', () => {
72
+ expect(durationInWords('1/1/1 10:00:00', '1/1/1 13:00:01')).toEqual({
73
+ text: '3 hours',
74
+ tooltip: '10,801 seconds',
75
+ });
76
+ });
77
+ });