Skip to content

Commit a09f816

Browse files
committed
make the iam page a little nicer
1 parent 6225c45 commit a09f816

File tree

4 files changed

+210
-327
lines changed

4 files changed

+210
-327
lines changed

src/common/utils.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export function transformCommaSeperatedName(name: string) {
2+
if (name.includes(",")) {
3+
try {
4+
const split = name.split(",")
5+
return `${split[1].slice(1, split[1].length)} ${split[0]}`
6+
} catch (e) {
7+
return name;
8+
}
9+
}
10+
return name;
11+
}

src/ui/pages/iam/GroupMemberManagement.test.tsx

Lines changed: 46 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { MantineProvider } from '@mantine/core';
77
import { notifications } from '@mantine/notifications';
88
import userEvent from '@testing-library/user-event';
99

10-
describe('Exec Group Management Panel read tests', () => {
10+
describe('Exec Group Management Panel tests', () => {
1111
const renderComponent = async (
1212
fetchMembers: () => Promise<any[]>,
1313
updateMembers: () => Promise<any>
@@ -33,18 +33,18 @@ describe('Exec Group Management Panel read tests', () => {
3333

3434
await renderComponent(fetchMembers, updateMembers);
3535

36-
expect(screen.getByText('Current Members')).toBeInTheDocument();
37-
expect(screen.queryByText(/.*@illinois\.edu/)).not.toBeInTheDocument();
36+
expect(screen.getByText('Exec Council Group Management')).toBeInTheDocument();
37+
expect(screen.queryByText(/.*@.*/)).not.toBeInTheDocument();
3838
});
3939

4040
it('renders with a single member', async () => {
4141
const fetchMembers = async () => [{ name: 'Doe, John', email: 'jdoe@illinois.edu' }];
42-
const updateMembers = async () => ({
43-
success: [{ email: 'jdoe@illinois.edu' }],
44-
});
42+
const updateMembers = async () => ({ success: [{ email: 'jdoe@illinois.edu' }] });
4543

4644
await renderComponent(fetchMembers, updateMembers);
47-
expect(screen.getByText(/Doe, John \(jdoe@illinois\.edu\)/)).toBeInTheDocument();
45+
expect(
46+
screen.getByText((content, element) => element?.textContent === 'Doe, Johnjdoe@illinois.edu')
47+
).toBeInTheDocument();
4848
});
4949

5050
it('renders with multiple members', async () => {
@@ -61,24 +61,21 @@ describe('Exec Group Management Panel read tests', () => {
6161
],
6262
});
6363

64-
await renderComponent(fetchMembers, updateMembers);
65-
expect(screen.getByText(/Doe, John \(jdoe@illinois\.edu\)/)).toBeInTheDocument();
66-
expect(screen.getByText(/Smith, Jane \(jsmith@illinois\.edu\)/)).toBeInTheDocument();
67-
expect(screen.getByText(/Brown, Bob \(bbrown@illinois\.edu\)/)).toBeInTheDocument();
68-
});
69-
70-
it('displays all required UI elements', async () => {
71-
const fetchMembers = async () => [];
72-
const updateMembers = async () => ({ success: [] });
73-
7464
await renderComponent(fetchMembers, updateMembers);
7565

76-
expect(screen.getByText('Exec Council Group Management')).toBeInTheDocument();
77-
expect(screen.getByText('Current Members')).toBeInTheDocument();
78-
expect(screen.getByLabelText('Add Member')).toBeInTheDocument();
79-
expect(screen.getByPlaceholderText('Enter email')).toBeInTheDocument();
80-
expect(screen.getByRole('button', { name: 'Add Member' })).toBeInTheDocument();
81-
expect(screen.getByRole('button', { name: 'Save Changes' })).toBeDisabled();
66+
expect(
67+
screen.getByText((content, element) => element?.textContent === 'Doe, Johnjdoe@illinois.edu')
68+
).toBeInTheDocument();
69+
expect(
70+
screen.getByText(
71+
(content, element) => element?.textContent === 'Smith, Janejsmith@illinois.edu'
72+
)
73+
).toBeInTheDocument();
74+
expect(
75+
screen.getByText(
76+
(content, element) => element?.textContent === 'Brown, Bobbbrown@illinois.edu'
77+
)
78+
).toBeInTheDocument();
8279
});
8380

8481
it('adds a new member and saves changes', async () => {
@@ -100,108 +97,36 @@ describe('Exec Group Management Panel read tests', () => {
10097
const addButton = screen.getByRole('button', { name: 'Add Member' });
10198
await user.click(addButton);
10299

103-
// Verify member appears with "Queued for addition" badge
100+
// Match the queued member
101+
expect(screen.getByText('member')).toBeInTheDocument();
104102
expect(screen.getByText('member@illinois.edu')).toBeInTheDocument();
105-
expect(screen.getByText('Queued for addition')).toBeInTheDocument();
106103

107-
// Click Save Changes which opens modal
104+
// Save Changes
108105
const saveButton = screen.getByRole('button', { name: 'Save Changes' });
109106
expect(saveButton).toBeEnabled();
110107
await user.click(saveButton);
111108

112-
// Wait for the modal to appear with title
113109
await screen.findByText('Confirm Changes');
114-
115-
// Find and click confirm button in modal
116110
const confirmButton = screen.getByRole('button', { name: 'Confirm and Save' });
117111
await user.click(confirmButton);
118112

119-
// Verify updateMembers was called with correct parameters
120113
expect(updateMembers).toHaveBeenCalledWith(['member@illinois.edu'], []);
121-
122-
// Verify list is updated - "Queued for addition" badge should be gone
123-
expect(screen.getByText(/member \(member@illinois\.edu\)/)).toBeInTheDocument();
124-
expect(screen.queryByText('Queued for addition')).not.toBeInTheDocument();
125-
126-
// Verify notifications were shown
127-
expect(notificationsMock).toHaveBeenCalledWith(
128-
expect.objectContaining({
129-
message: 'All changes processed successfully!',
130-
color: 'green',
131-
})
132-
);
133-
134-
// Verify Save Changes button is disabled again after successful update
135-
expect(screen.getByRole('button', { name: 'Save Changes' })).toBeDisabled();
136-
137-
// Clean up
138114
notificationsMock.mockRestore();
139115
});
140-
it('handles failed member updates correctly', async () => {
141-
const notificationsMock = vi.spyOn(notifications, 'show');
142-
const user = userEvent.setup();
143-
const fetchMembers = async () => [];
144-
const updateMembers = vi.fn().mockResolvedValue({
145-
success: [],
146-
failure: [
147-
{
148-
email: 'member@illinois.edu',
149-
message: 'User does not exist in directory',
150-
},
151-
],
152-
});
153-
154-
await renderComponent(fetchMembers, updateMembers);
155-
156-
// Add a member that will fail
157-
const emailInput = screen.getByPlaceholderText('Enter email');
158-
await user.type(emailInput, 'member@illinois.edu');
159-
await user.click(screen.getByRole('button', { name: 'Add Member' }));
160-
161-
// Verify member shows in queue
162-
expect(screen.getByText('member@illinois.edu')).toBeInTheDocument();
163-
expect(screen.getByText('Queued for addition')).toBeInTheDocument();
164116

165-
// Try to save changes
166-
await user.click(screen.getByRole('button', { name: 'Save Changes' }));
167-
await screen.findByText('Confirm Changes');
168-
await user.click(screen.getByRole('button', { name: 'Confirm and Save' }));
169-
170-
expect(notificationsMock).toHaveBeenCalledWith(
171-
expect.objectContaining({
172-
title: 'Error adding member@illinois.edu',
173-
message: 'User does not exist in directory',
174-
color: 'red',
175-
})
176-
);
177-
178-
// Verify member is no longer shown as queued (since queues are cleared)
179-
expect(screen.queryByText('Queued for addition')).not.toBeInTheDocument();
180-
181-
// Verify Save Changes button is disabled since queues are cleared
182-
expect(screen.getByRole('button', { name: 'Save Changes' })).toBeDisabled();
183-
184-
notificationsMock.mockRestore();
185-
});
186-
187-
it('removes an existing member', async () => {
117+
it('removes an existing member and saves changes', async () => {
188118
const notificationsMock = vi.spyOn(notifications, 'show');
189119
const user = userEvent.setup();
190-
const fetchMembers = async () => [
191-
{
192-
name: 'Existing Member',
193-
email: 'existing@illinois.edu',
194-
},
195-
];
120+
const fetchMembers = async () => [{ name: 'Existing Member', email: 'existing@illinois.edu' }];
196121
const updateMembers = vi.fn().mockResolvedValue({
197122
success: [{ email: 'existing@illinois.edu' }],
198123
failure: [],
199124
});
200125

201126
await renderComponent(fetchMembers, updateMembers);
202127

203-
// Click remove button for the existing member using data-testid
204-
const removeButton = screen.getByTestId('remove-exec-member-existing@illinois.edu');
128+
// Click remove button for the existing member
129+
const removeButton = screen.getByRole('button', { name: /Remove/ });
205130
await user.click(removeButton);
206131

207132
// Verify member shows removal badge
@@ -217,10 +142,7 @@ describe('Exec Group Management Panel read tests', () => {
217142
await user.click(confirmButton);
218143

219144
// Verify updateMembers was called with correct parameters
220-
expect(updateMembers).toHaveBeenCalledWith(
221-
[], // toAdd
222-
['existing@illinois.edu'] // toRemove
223-
);
145+
expect(updateMembers).toHaveBeenCalledWith([], ['existing@illinois.edu']);
224146

225147
// Verify member is removed from the list
226148
expect(
@@ -237,106 +159,49 @@ describe('Exec Group Management Panel read tests', () => {
237159

238160
notificationsMock.mockRestore();
239161
});
240-
it('handles multiple member changes with mixed success/failure results', async () => {
162+
163+
it('handles failed member updates correctly', async () => {
241164
const notificationsMock = vi.spyOn(notifications, 'show');
242165
const user = userEvent.setup();
243-
244-
// Start with two existing members
245-
const fetchMembers = async () => [
246-
{ name: 'Stay Member', email: 'stay@illinois.edu' },
247-
{ name: 'Remove Success', email: 'removesuccess@illinois.edu' },
248-
{ name: 'Remove Fail', email: 'removefail@illinois.edu' },
249-
];
250-
251-
// Mock mixed success/failure response
166+
const fetchMembers = async () => [];
252167
const updateMembers = vi.fn().mockResolvedValue({
253-
success: [
254-
{ email: 'removesuccess@illinois.edu' }, // removal succeeded
255-
{ email: 'addsuccess@illinois.edu' }, // addition succeeded
256-
],
168+
success: [],
257169
failure: [
258170
{
259-
email: 'removefail@illinois.edu',
260-
message: 'Cannot remove admin user',
261-
},
262-
{
263-
email: 'addfail@illinois.edu',
264-
message: 'User not found in directory',
171+
email: 'member@illinois.edu',
172+
message: 'User does not exist in directory',
265173
},
266174
],
267175
});
268176

269177
await renderComponent(fetchMembers, updateMembers);
270178

271-
// Add two new members - one will succeed, one will fail
179+
// Add a member that will fail
272180
const emailInput = screen.getByPlaceholderText('Enter email');
273-
274-
await user.type(emailInput, 'addsuccess@illinois.edu');
275-
await user.click(screen.getByRole('button', { name: 'Add Member' }));
276-
277-
await user.type(emailInput, 'addfail@illinois.edu');
181+
await user.type(emailInput, 'member@illinois.edu');
278182
await user.click(screen.getByRole('button', { name: 'Add Member' }));
279183

280-
// Remove two existing members - one will succeed, one will fail
281-
await user.click(screen.getByTestId('remove-exec-member-removesuccess@illinois.edu'));
282-
await user.click(screen.getByTestId('remove-exec-member-removefail@illinois.edu'));
283-
284-
// Verify queued states before save
285-
expect(screen.getByText('addsuccess@illinois.edu')).toBeInTheDocument();
286-
expect(screen.getByText('addfail@illinois.edu')).toBeInTheDocument();
287-
expect(screen.getAllByText('Queued for addition')).toHaveLength(2);
288-
expect(screen.getAllByText('Queued for removal')).toHaveLength(2);
289-
290-
// Save changes
291-
const saveButton = screen.getByRole('button', { name: 'Save Changes' });
292-
expect(saveButton).toBeEnabled();
293-
await user.click(saveButton);
184+
// Verify member shows in queue
185+
expect(screen.getByText('member@illinois.edu')).toBeInTheDocument();
186+
expect(screen.getByText('Queued for addition')).toBeInTheDocument();
294187

295-
// Confirm in modal
188+
// Try to save changes
189+
await user.click(screen.getByRole('button', { name: 'Save Changes' }));
296190
await screen.findByText('Confirm Changes');
297-
const confirmButton = screen.getByRole('button', { name: 'Confirm and Save' });
298-
await user.click(confirmButton);
299-
300-
// Verify updateMembers was called with all changes
301-
expect(updateMembers).toHaveBeenCalledWith(
302-
['addsuccess@illinois.edu', 'addfail@illinois.edu'],
303-
['removesuccess@illinois.edu', 'removefail@illinois.edu']
304-
);
305-
306-
// Verify error notifications for failures
307-
expect(notificationsMock).toHaveBeenCalledWith(
308-
expect.objectContaining({
309-
title: 'Error adding addfail@illinois.edu',
310-
message: 'User not found in directory',
311-
color: 'red',
312-
})
313-
);
191+
await user.click(screen.getByRole('button', { name: 'Confirm and Save' }));
314192

315193
expect(notificationsMock).toHaveBeenCalledWith(
316194
expect.objectContaining({
317-
title: 'Error removing removefail@illinois.edu',
318-
message: 'Cannot remove admin user',
195+
title: 'Error with member@illinois.edu',
196+
message: 'User does not exist in directory',
319197
color: 'red',
320198
})
321199
);
322200

323-
// Verify end state of member list
324-
// Success cases
325-
expect(screen.queryByText(/removesuccess@illinois\.edu/)).not.toBeInTheDocument(); // Successfully removed
326-
expect(screen.getByText(/addsuccess@illinois\.edu/)).toBeInTheDocument(); // Successfully added
327-
328-
// Failure cases
329-
expect(screen.getByText(/removefail@illinois\.edu/)).toBeInTheDocument(); // Failed to remove
330-
expect(screen.queryByText(/addfail@illinois\.edu/)).not.toBeInTheDocument(); // Failed to add
331-
332-
// Unchanged member
333-
expect(screen.getByText(/stay@illinois\.edu/)).toBeInTheDocument();
334-
335-
// Verify queued badges are cleared
201+
// Verify member is no longer shown as queued
336202
expect(screen.queryByText('Queued for addition')).not.toBeInTheDocument();
337-
expect(screen.queryByText('Queued for removal')).not.toBeInTheDocument();
338203

339-
// Verify Save Changes button is disabled after operation
204+
// Verify Save Changes button is disabled
340205
expect(screen.getByRole('button', { name: 'Save Changes' })).toBeDisabled();
341206

342207
notificationsMock.mockRestore();

0 commit comments

Comments
 (0)