Skip to content

Commit d864fde

Browse files
jeremylenzclaude
andcommitted
Refs #38901 - Update tests for UX review changes
- Update SyncStatusPage test for new toolbar buttons - Update SyncStatusTable test for new props and column headers - Update SyncStatusToolbar test for TreeSelectAllCheckbox - Add TreeSelectAllCheckbox test file - Update SyncResultCell tests for simplified output - Fix Switch component rendering multiple labels in tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 4ec2ac3 commit d864fde

File tree

6 files changed

+147
-53
lines changed

6 files changed

+147
-53
lines changed

webpack/scenes/SyncStatus/SyncStatusConstants.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ export const SYNC_STATE_CANCELED = 'canceled';
1313
export const SYNC_STATE_PAUSED = 'paused';
1414

1515
export const SYNC_STATE_LABELS = {
16-
[SYNC_STATE_STOPPED]: __('Syncing Complete'),
17-
[SYNC_STATE_ERROR]: __('Sync Incomplete'),
18-
[SYNC_STATE_NEVER_SYNCED]: __('Never Synced'),
16+
[SYNC_STATE_STOPPED]: __('Syncing complete'),
17+
[SYNC_STATE_ERROR]: __('Sync incomplete'),
18+
[SYNC_STATE_NEVER_SYNCED]: __('Never synced'),
1919
[SYNC_STATE_RUNNING]: __('Running'),
2020
[SYNC_STATE_CANCELED]: __('Canceled'),
2121
[SYNC_STATE_PAUSED]: __('Paused'),

webpack/scenes/SyncStatus/__tests__/SyncStatusPage.test.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,12 @@ test('Displays toolbar with action buttons', async () => {
6060
.query(true)
6161
.reply(200, mockSyncStatusData);
6262

63-
const { queryByText } = renderWithRedux(<SyncStatusPage />, renderOptions);
63+
const { getAllByText, queryByText } = renderWithRedux(<SyncStatusPage />, renderOptions);
6464

6565
await patientlyWaitFor(() => {
66-
expect(queryByText('Expand All')).toBeInTheDocument();
67-
expect(queryByText('Collapse All')).toBeInTheDocument();
68-
expect(queryByText('Select All')).toBeInTheDocument();
69-
expect(queryByText('Select None')).toBeInTheDocument();
70-
expect(queryByText('Synchronize Now')).toBeInTheDocument();
66+
// Switch renders label twice (on/off states), so use getAllByText
67+
expect(getAllByText('Show syncing only').length).toBeGreaterThan(0);
68+
expect(queryByText('Synchronize')).toBeInTheDocument();
7169
});
7270

7371
assertNockRequest(scope);

webpack/scenes/SyncStatus/components/__tests__/SyncResultCell.test.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,39 +11,39 @@ describe('SyncResultCell', () => {
1111
it('renders completed state correctly', () => {
1212
const repo = {
1313
raw_state: SYNC_STATE_STOPPED,
14-
state: 'Syncing Complete',
15-
start_time: '2 hours ago',
14+
state: 'Syncing complete',
1615
};
1716
render(<SyncResultCell repo={repo} />);
18-
expect(screen.getByText(/Syncing Complete/)).toBeInTheDocument();
17+
expect(screen.getByText(/Syncing complete/i)).toBeInTheDocument();
1918
});
2019

2120
it('renders error state correctly', () => {
2221
const repo = {
2322
raw_state: SYNC_STATE_ERROR,
24-
state: 'Sync Incomplete',
23+
state: 'Sync incomplete',
2524
error_details: ['Connection timeout'],
2625
};
2726
render(<SyncResultCell repo={repo} />);
28-
expect(screen.getByText(/Sync Incomplete/)).toBeInTheDocument();
27+
expect(screen.getByText(/Sync incomplete/i)).toBeInTheDocument();
2928
});
3029

3130
it('renders never synced state correctly', () => {
3231
const repo = {
3332
raw_state: SYNC_STATE_NEVER_SYNCED,
34-
state: 'Never Synced',
33+
state: 'Never synced',
3534
};
3635
render(<SyncResultCell repo={repo} />);
37-
expect(screen.getByText(/Never Synced/)).toBeInTheDocument();
36+
expect(screen.getByText(/Never synced/i)).toBeInTheDocument();
3837
});
3938

40-
it('includes start time in the label', () => {
39+
it('renders task link when sync_id is present', () => {
4140
const repo = {
4241
raw_state: SYNC_STATE_STOPPED,
43-
state: 'Syncing Complete',
44-
start_time: '3 hours ago',
42+
state: 'Syncing complete',
43+
sync_id: '12345',
4544
};
4645
render(<SyncResultCell repo={repo} />);
47-
expect(screen.getByText(/3 hours ago/)).toBeInTheDocument();
46+
const link = screen.getByRole('link');
47+
expect(link).toHaveAttribute('href', expect.stringContaining('12345'));
4848
});
4949
});

webpack/scenes/SyncStatus/components/__tests__/SyncStatusTable.test.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,16 @@ describe('SyncStatusTable', () => {
3939
const mockProps = {
4040
products: mockProducts,
4141
repoStatuses: mockRepoStatuses,
42-
selectedRepoIds: [],
4342
onSelectRepo: jest.fn(),
43+
onSelectProduct: jest.fn(),
44+
onSyncRepo: jest.fn(),
4445
onCancelSync: jest.fn(),
4546
expandedNodeIds: [],
4647
setExpandedNodeIds: jest.fn(),
4748
showActiveOnly: false,
49+
isSelected: jest.fn(() => false),
50+
onExpandAll: jest.fn(),
51+
onCollapseAll: jest.fn(),
4852
};
4953

5054
beforeEach(() => {
@@ -54,9 +58,8 @@ describe('SyncStatusTable', () => {
5458
it('renders table with column headers', () => {
5559
render(<SyncStatusTable {...mockProps} />);
5660

57-
expect(screen.getByText('Product / Repository')).toBeInTheDocument();
58-
expect(screen.getByText('Start Time')).toBeInTheDocument();
59-
expect(screen.getByText('Duration')).toBeInTheDocument();
61+
expect(screen.getByText('Product | Repository')).toBeInTheDocument();
62+
expect(screen.getByText('Started at')).toBeInTheDocument();
6063
expect(screen.getByText('Details')).toBeInTheDocument();
6164
expect(screen.getByText('Progress / Result')).toBeInTheDocument();
6265
});
@@ -88,11 +91,11 @@ describe('SyncStatusTable', () => {
8891
const checkboxes = screen.getAllByRole('checkbox');
8992
// eslint-disable-next-line promise/prefer-await-to-callbacks
9093
const repoCheckbox = checkboxes.find(cb =>
91-
cb.getAttribute('aria-label')?.includes('Test Repository'));
94+
cb.getAttribute('aria-label')?.includes('Select repository'));
9295

9396
if (repoCheckbox) {
9497
fireEvent.click(repoCheckbox);
95-
expect(mockProps.onSelectRepo).toHaveBeenCalledWith(1);
98+
expect(mockProps.onSelectRepo).toHaveBeenCalled();
9699
}
97100
});
98101

webpack/scenes/SyncStatus/components/__tests__/SyncStatusToolbar.test.js

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,59 @@ describe('SyncStatusToolbar', () => {
66
const mockProps = {
77
selectedRepoIds: [1, 2],
88
onSyncNow: jest.fn(),
9-
onExpandAll: jest.fn(),
10-
onCollapseAll: jest.fn(),
11-
onSelectAll: jest.fn(),
12-
onSelectNone: jest.fn(),
139
showActiveOnly: false,
1410
onToggleActiveOnly: jest.fn(),
11+
selectAllCheckboxProps: {
12+
selectNone: jest.fn(),
13+
selectAll: jest.fn(),
14+
selectedCount: 2,
15+
totalCount: 10,
16+
areAllRowsSelected: false,
17+
},
1518
};
1619

1720
beforeEach(() => {
1821
jest.clearAllMocks();
1922
});
2023

21-
it('renders all action buttons', () => {
24+
it('renders toolbar with selection checkbox and sync button', () => {
2225
render(<SyncStatusToolbar {...mockProps} />);
2326

24-
expect(screen.getByText('Expand All')).toBeInTheDocument();
25-
expect(screen.getByText('Collapse All')).toBeInTheDocument();
26-
expect(screen.getByText('Select All')).toBeInTheDocument();
27-
expect(screen.getByText('Select None')).toBeInTheDocument();
28-
expect(screen.getByText('Synchronize Now')).toBeInTheDocument();
27+
expect(screen.getByText('2 selected')).toBeInTheDocument();
28+
expect(screen.getByText('Synchronize')).toBeInTheDocument();
29+
// Switch renders label twice (on/off states), so use getAllByText
30+
expect(screen.getAllByText('Show syncing only').length).toBeGreaterThan(0);
2931
});
3032

31-
it('calls onSyncNow when Synchronize Now is clicked', () => {
33+
it('calls onSyncNow when Synchronize is clicked', () => {
3234
render(<SyncStatusToolbar {...mockProps} />);
3335

34-
const syncButton = screen.getByText('Synchronize Now');
36+
const syncButton = screen.getByText('Synchronize');
3537
fireEvent.click(syncButton);
3638

3739
expect(mockProps.onSyncNow).toHaveBeenCalled();
3840
});
3941

40-
it('disables Synchronize Now when no repos selected', () => {
41-
const props = { ...mockProps, selectedRepoIds: [] };
42+
it('disables Synchronize when no repos selected', () => {
43+
const props = {
44+
...mockProps,
45+
selectedRepoIds: [],
46+
selectAllCheckboxProps: {
47+
...mockProps.selectAllCheckboxProps,
48+
selectedCount: 0,
49+
},
50+
};
4251
render(<SyncStatusToolbar {...props} />);
4352

44-
const syncButton = screen.getByText('Synchronize Now');
53+
const syncButton = screen.getByText('Synchronize');
4554
expect(syncButton).toBeDisabled();
4655
});
4756

48-
it('calls onExpandAll when Expand All is clicked', () => {
57+
it('toggles show syncing only switch', () => {
4958
render(<SyncStatusToolbar {...mockProps} />);
5059

51-
const expandButton = screen.getByText('Expand All');
52-
fireEvent.click(expandButton);
53-
54-
expect(mockProps.onExpandAll).toHaveBeenCalled();
55-
});
56-
57-
it('toggles active only switch', () => {
58-
render(<SyncStatusToolbar {...mockProps} />);
59-
60-
const activeOnlySwitch = screen.getByLabelText('Active Only');
61-
fireEvent.click(activeOnlySwitch);
60+
const showSyncingSwitch = screen.getByLabelText('Show syncing only');
61+
fireEvent.click(showSyncingSwitch);
6262

6363
expect(mockProps.onToggleActiveOnly).toHaveBeenCalled();
6464
});
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent } from '@testing-library/react';
3+
import TreeSelectAllCheckbox from '../TreeSelectAllCheckbox';
4+
5+
describe('TreeSelectAllCheckbox', () => {
6+
const mockProps = {
7+
selectNone: jest.fn(),
8+
selectAll: jest.fn(),
9+
selectedCount: 2,
10+
totalCount: 10,
11+
areAllRowsSelected: false,
12+
};
13+
14+
beforeEach(() => {
15+
jest.clearAllMocks();
16+
});
17+
18+
it('renders with selected count', () => {
19+
render(<TreeSelectAllCheckbox {...mockProps} />);
20+
21+
expect(screen.getByText('2 selected')).toBeInTheDocument();
22+
});
23+
24+
it('calls selectAll when select all is clicked', () => {
25+
render(<TreeSelectAllCheckbox {...mockProps} />);
26+
27+
// Click the dropdown toggle (aria-label is "Select")
28+
const dropdownToggle = screen.getByRole('button', { name: 'Select' });
29+
fireEvent.click(dropdownToggle);
30+
31+
// Click select all option
32+
const selectAllOption = screen.getByText('Select all (10)');
33+
fireEvent.click(selectAllOption);
34+
35+
expect(mockProps.selectAll).toHaveBeenCalled();
36+
});
37+
38+
it('calls selectNone when select none is clicked', () => {
39+
render(<TreeSelectAllCheckbox {...mockProps} />);
40+
41+
// Click the dropdown toggle (aria-label is "Select")
42+
const dropdownToggle = screen.getByRole('button', { name: 'Select' });
43+
fireEvent.click(dropdownToggle);
44+
45+
// Click select none option
46+
const selectNoneOption = screen.getByText('Select none (0)');
47+
fireEvent.click(selectNoneOption);
48+
49+
expect(mockProps.selectNone).toHaveBeenCalled();
50+
});
51+
52+
it('shows indeterminate state when some items selected', () => {
53+
render(<TreeSelectAllCheckbox {...mockProps} />);
54+
55+
const checkbox = screen.getByRole('checkbox');
56+
expect(checkbox).toBeInTheDocument();
57+
});
58+
59+
it('disables select all when all rows are selected', () => {
60+
const propsAllSelected = {
61+
...mockProps,
62+
selectedCount: 10,
63+
areAllRowsSelected: true,
64+
};
65+
66+
render(<TreeSelectAllCheckbox {...propsAllSelected} />);
67+
68+
// Click the dropdown toggle
69+
const dropdownToggle = screen.getByRole('button', { name: 'Select' });
70+
fireEvent.click(dropdownToggle);
71+
72+
// Check that select all has aria-disabled
73+
const selectAllOption = screen.getByText('Select all (10)');
74+
expect(selectAllOption.closest('button')).toHaveAttribute('aria-disabled', 'true');
75+
});
76+
77+
it('disables select none when no items are selected', () => {
78+
const propsNoneSelected = {
79+
...mockProps,
80+
selectedCount: 0,
81+
};
82+
83+
render(<TreeSelectAllCheckbox {...propsNoneSelected} />);
84+
85+
// Click the dropdown toggle
86+
const dropdownToggle = screen.getByRole('button', { name: 'Select' });
87+
fireEvent.click(dropdownToggle);
88+
89+
// Check that select none has aria-disabled
90+
const selectNoneOption = screen.getByText('Select none (0)');
91+
expect(selectNoneOption.closest('button')).toHaveAttribute('aria-disabled', 'true');
92+
});
93+
});

0 commit comments

Comments
 (0)