Skip to content

Commit f772407

Browse files
Add unit tests and make some more changes
Signed-off-by: Adhitya Mamallan <[email protected]>
1 parent 50fe13a commit f772407

File tree

5 files changed

+393
-25
lines changed

5 files changed

+393
-25
lines changed
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
import { render, screen, userEvent } from '@/test-utils/rtl';
2+
3+
import {
4+
completedActivityTaskEvents,
5+
scheduleActivityTaskEvent,
6+
} from '@/views/workflow-history/__fixtures__/workflow-history-activity-events';
7+
import {
8+
mockActivityEventGroup,
9+
mockDecisionEventGroup,
10+
} from '@/views/workflow-history/__fixtures__/workflow-history-event-groups';
11+
import type WorkflowHistoryEventStatusBadge from '@/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge';
12+
import type WorkflowHistoryGroupLabel from '@/views/workflow-history/workflow-history-group-label/workflow-history-group-label';
13+
import type WorkflowHistoryTimelineResetButton from '@/views/workflow-history/workflow-history-timeline-reset-button/workflow-history-timeline-reset-button';
14+
import { type HistoryEventsGroup } from '@/views/workflow-history/workflow-history.types';
15+
16+
import WorkflowHistoryEventGroup from '../workflow-history-event-group';
17+
import type { Props } from '../workflow-history-event-group.types';
18+
19+
jest.mock('@/utils/data-formatters/format-date', () =>
20+
jest.fn((timeMs: number) => `Formatted: ${timeMs}`)
21+
);
22+
23+
jest.mock<typeof WorkflowHistoryEventStatusBadge>(
24+
'@/views/workflow-history/workflow-history-event-status-badge/workflow-history-event-status-badge',
25+
() =>
26+
jest.fn((props) => (
27+
<div data-testid="status-badge">
28+
{props.statusReady ? props.status : 'Loading'}
29+
</div>
30+
))
31+
);
32+
33+
jest.mock<typeof WorkflowHistoryGroupLabel>(
34+
'@/views/workflow-history/workflow-history-group-label/workflow-history-group-label',
35+
() => jest.fn((props) => <>{props.label}</>)
36+
);
37+
38+
jest.mock<typeof WorkflowHistoryTimelineResetButton>(
39+
'@/views/workflow-history/workflow-history-timeline-reset-button/workflow-history-timeline-reset-button',
40+
() =>
41+
jest.fn((props) => (
42+
<button onClick={props.onReset} data-testid="reset-button">
43+
Reset Button
44+
</button>
45+
))
46+
);
47+
48+
jest.mock('../../hooks/use-event-group-duration', () =>
49+
jest.fn(() => '1m 30s')
50+
);
51+
52+
jest.mock('../helpers/get-event-group-filtering-type', () =>
53+
jest.fn(() => 'ACTIVITY')
54+
);
55+
56+
jest.mock(
57+
'../../config/workflow-history-event-filtering-type-colors.config',
58+
() => ({
59+
__esModule: true,
60+
default: {
61+
ACTIVITY: {
62+
content: '#FF5733',
63+
background: '#FFE5E0',
64+
backgroundHighlighted: '#FFD4CC',
65+
},
66+
},
67+
})
68+
);
69+
70+
const mockActivityEventGroupWithMetadata: HistoryEventsGroup = {
71+
...mockActivityEventGroup,
72+
eventsMetadata: [
73+
{
74+
label: 'Scheduled',
75+
status: 'COMPLETED',
76+
timeMs: 1725747370599,
77+
timeLabel: 'Scheduled at 07 Sep, 22:16:10 UTC',
78+
},
79+
{
80+
label: 'Completed',
81+
status: 'COMPLETED',
82+
timeMs: 1725747370632,
83+
timeLabel: 'Completed at 07 Sep, 22:16:10 UTC',
84+
},
85+
],
86+
};
87+
88+
const mockDecisionEventGroupWithMetadata: HistoryEventsGroup = {
89+
...mockDecisionEventGroup,
90+
eventsMetadata: [
91+
{
92+
label: 'Scheduled',
93+
status: 'COMPLETED',
94+
timeMs: 1725747370599,
95+
timeLabel: 'Scheduled at 07 Sep, 22:16:10 UTC',
96+
},
97+
{
98+
label: 'Started',
99+
status: 'COMPLETED',
100+
timeMs: 1725747370575,
101+
timeLabel: 'Started at 07 Sep, 22:16:10 UTC',
102+
},
103+
{
104+
label: 'Completed',
105+
status: 'COMPLETED',
106+
timeMs: 1725747370632,
107+
timeLabel: 'Completed at 07 Sep, 22:16:10 UTC',
108+
},
109+
],
110+
};
111+
112+
describe(WorkflowHistoryEventGroup.name, () => {
113+
it('renders group correctly', () => {
114+
setup({ eventGroup: mockActivityEventGroupWithMetadata });
115+
116+
expect(screen.getByText('Mock event')).toBeInTheDocument();
117+
expect(screen.getByText('1m 30s')).toBeInTheDocument();
118+
119+
expect(screen.getByTestId('status-badge')).toBeInTheDocument();
120+
expect(screen.getByText('COMPLETED')).toBeInTheDocument();
121+
122+
expect(screen.getByText('Completed')).toBeInTheDocument();
123+
124+
expect(screen.getByText('Formatted: 1725747370632')).toBeInTheDocument();
125+
});
126+
127+
it('renders reset button when resetToDecisionEventId is provided', () => {
128+
const eventGroup: HistoryEventsGroup = {
129+
...mockDecisionEventGroupWithMetadata,
130+
resetToDecisionEventId: 'decision-event-id',
131+
};
132+
133+
setup({ eventGroup });
134+
135+
expect(screen.getByTestId('reset-button')).toBeInTheDocument();
136+
});
137+
138+
it('calls onReset when reset button is clicked', async () => {
139+
const eventGroup: HistoryEventsGroup = {
140+
...mockDecisionEventGroupWithMetadata,
141+
resetToDecisionEventId: 'decision-event-id',
142+
};
143+
144+
const { mockOnReset, user } = setup({ eventGroup });
145+
146+
const resetButton = screen.getByTestId('reset-button');
147+
await user.click(resetButton);
148+
149+
expect(mockOnReset).toHaveBeenCalledTimes(1);
150+
});
151+
152+
it('expands panel when any event is expanded', () => {
153+
const eventGroup: HistoryEventsGroup = {
154+
...mockActivityEventGroupWithMetadata,
155+
events: completedActivityTaskEvents,
156+
};
157+
158+
const getIsEventExpanded = jest.fn(
159+
(eventId: string) => eventId === completedActivityTaskEvents[1].eventId
160+
);
161+
162+
setup({ eventGroup, getIsEventExpanded });
163+
164+
// Panel should be expanded if any event is expanded, showing content
165+
expect(screen.getByText('TODO: Full event details')).toBeInTheDocument();
166+
});
167+
168+
it('calls toggleIsEventExpanded when panel is toggled', async () => {
169+
const eventGroup: HistoryEventsGroup = {
170+
...mockActivityEventGroupWithMetadata,
171+
events: [scheduleActivityTaskEvent],
172+
};
173+
174+
const toggleIsEventExpanded = jest.fn();
175+
const { user } = setup({ eventGroup, toggleIsEventExpanded });
176+
177+
// Click on the header content to toggle the panel
178+
const headerLabel = screen.getByText('Mock event');
179+
await user.click(headerLabel);
180+
181+
expect(toggleIsEventExpanded).toHaveBeenCalledWith(
182+
scheduleActivityTaskEvent.eventId
183+
);
184+
});
185+
186+
it('handles missing event group time gracefully', () => {
187+
const eventGroup: HistoryEventsGroup = {
188+
...mockActivityEventGroupWithMetadata,
189+
timeMs: null,
190+
};
191+
192+
setup({ eventGroup });
193+
194+
// Should not crash, and should render null for date
195+
expect(screen.queryByText(/Formatted:/)).not.toBeInTheDocument();
196+
});
197+
198+
it('shows status when statusReady is true (showLoadingMoreEvents is false)', () => {
199+
setup({
200+
eventGroup: mockActivityEventGroupWithMetadata,
201+
showLoadingMoreEvents: false,
202+
});
203+
204+
expect(screen.getByTestId('status-badge')).toBeInTheDocument();
205+
expect(screen.getByText('COMPLETED')).toBeInTheDocument();
206+
expect(screen.queryByText('Loading')).not.toBeInTheDocument();
207+
});
208+
209+
it('shows Loading when statusReady is false (showLoadingMoreEvents is true)', () => {
210+
setup({
211+
eventGroup: mockActivityEventGroupWithMetadata,
212+
showLoadingMoreEvents: true,
213+
});
214+
215+
expect(screen.getByTestId('status-badge')).toBeInTheDocument();
216+
expect(screen.getByText('Loading')).toBeInTheDocument();
217+
expect(screen.queryByText('COMPLETED')).not.toBeInTheDocument();
218+
});
219+
});
220+
221+
function setup({
222+
eventGroup = mockActivityEventGroupWithMetadata,
223+
selected = false,
224+
workflowCloseTimeMs = null,
225+
workflowCloseStatus = null,
226+
workflowIsArchived = false,
227+
showLoadingMoreEvents = false,
228+
decodedPageUrlParams = {
229+
domain: 'test-domain',
230+
cluster: 'test-cluster',
231+
workflowId: 'test-workflow-id',
232+
runId: 'test-run-id',
233+
workflowTab: 'history',
234+
},
235+
onReset = jest.fn(),
236+
getIsEventExpanded = jest.fn(() => false),
237+
toggleIsEventExpanded = jest.fn(),
238+
}: Partial<Props> = {}) {
239+
const mockOnReset = onReset || jest.fn();
240+
const user = userEvent.setup();
241+
242+
render(
243+
<WorkflowHistoryEventGroup
244+
eventGroup={eventGroup}
245+
selected={selected}
246+
workflowCloseTimeMs={workflowCloseTimeMs}
247+
workflowCloseStatus={workflowCloseStatus}
248+
workflowIsArchived={workflowIsArchived}
249+
showLoadingMoreEvents={showLoadingMoreEvents}
250+
decodedPageUrlParams={decodedPageUrlParams}
251+
onReset={mockOnReset}
252+
getIsEventExpanded={getIsEventExpanded}
253+
toggleIsEventExpanded={toggleIsEventExpanded}
254+
/>
255+
);
256+
257+
return {
258+
mockOnReset,
259+
user,
260+
toggleIsEventExpanded,
261+
getIsEventExpanded,
262+
};
263+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import {
2+
mockActivityEventGroup,
3+
mockDecisionEventGroup,
4+
mockTimerEventGroup,
5+
mockChildWorkflowEventGroup,
6+
mockSignalExternalWorkflowEventGroup,
7+
mockRequestCancelExternalWorkflowEventGroup,
8+
mockSingleEventGroup,
9+
} from '@/views/workflow-history/__fixtures__/workflow-history-event-groups';
10+
import { signalWorkflowExecutionEvent } from '@/views/workflow-history/__fixtures__/workflow-history-single-events';
11+
12+
import getEventGroupFilteringType from '../get-event-group-filtering-type';
13+
14+
jest.mock(
15+
'@/views/workflow-history/config/workflow-history-filters-type.config',
16+
() => ({
17+
ACTIVITY: 'Activity',
18+
CHILDWORKFLOW: 'ChildWorkflowExecution',
19+
DECISION: 'Decision',
20+
TIMER: 'Timer',
21+
SIGNAL: jest.fn(
22+
(g) =>
23+
g.groupType === 'SignalExternalWorkflowExecution' ||
24+
g.events[0].attributes === 'workflowExecutionSignaledEventAttributes'
25+
),
26+
WORKFLOW: jest.fn(
27+
(g) =>
28+
g.groupType === 'RequestCancelExternalWorkflowExecution' ||
29+
(g.groupType === 'Event' &&
30+
g.events[0].attributes !== 'workflowExecutionSignaledEventAttributes')
31+
),
32+
})
33+
);
34+
35+
describe(getEventGroupFilteringType.name, () => {
36+
beforeEach(() => {
37+
jest.clearAllMocks();
38+
});
39+
40+
it('should return ACTIVITY for Activity group type', () => {
41+
expect(getEventGroupFilteringType(mockActivityEventGroup)).toBe('ACTIVITY');
42+
});
43+
44+
it('should return DECISION for Decision group type', () => {
45+
expect(getEventGroupFilteringType(mockDecisionEventGroup)).toBe('DECISION');
46+
});
47+
48+
it('should return TIMER for Timer group type', () => {
49+
expect(getEventGroupFilteringType(mockTimerEventGroup)).toBe('TIMER');
50+
});
51+
52+
it('should return CHILDWORKFLOW for ChildWorkflowExecution group type', () => {
53+
expect(getEventGroupFilteringType(mockChildWorkflowEventGroup)).toBe(
54+
'CHILDWORKFLOW'
55+
);
56+
});
57+
58+
it('should return SIGNAL for SignalExternalWorkflowExecution group type', () => {
59+
expect(
60+
getEventGroupFilteringType(mockSignalExternalWorkflowEventGroup)
61+
).toBe('SIGNAL');
62+
});
63+
64+
it('should return SIGNAL for Event group type with workflowExecutionSignaledEventAttributes', () => {
65+
const group = {
66+
...mockSingleEventGroup,
67+
events: [signalWorkflowExecutionEvent],
68+
firstEventId: signalWorkflowExecutionEvent.eventId,
69+
};
70+
71+
expect(getEventGroupFilteringType(group)).toBe('SIGNAL');
72+
});
73+
74+
it('should return WORKFLOW for RequestCancelExternalWorkflowExecution group type', () => {
75+
expect(
76+
getEventGroupFilteringType(mockRequestCancelExternalWorkflowEventGroup)
77+
).toBe('WORKFLOW');
78+
});
79+
80+
it('should return WORKFLOW for Event group type with non-signal attributes', () => {
81+
expect(getEventGroupFilteringType(mockSingleEventGroup)).toBe('WORKFLOW');
82+
});
83+
});

src/views/workflow-history-v2/workflow-history-event-group/workflow-history-event-group.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ export default function WorkflowHistoryEventGroup({
6565
workflowCloseTime: workflowCloseTimeMs,
6666
});
6767

68-
const lastEventTimeMs = eventsMetadata[eventsMetadata.length - 1].timeMs;
69-
7068
return (
7169
<Panel
7270
title={
@@ -88,7 +86,7 @@ export default function WorkflowHistoryEventGroup({
8886
/>
8987
{eventsMetadata[eventsMetadata.length - 1].label}
9088
</styled.StatusContainer>
91-
<div>{lastEventTimeMs ? formatDate(lastEventTimeMs) : null}</div>
89+
<div>{eventGroup.timeMs ? formatDate(eventGroup.timeMs) : null}</div>
9290
<div>{eventGroupDuration}</div>
9391
{/* TODO: add as event details:
9492
- Existing event details

0 commit comments

Comments
 (0)