mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-05 17:53:12 +02:00
Feat/scheduled cr UI tests (#5296)
Ui tests scheduled change requests Closes # [1-1598](https://linear.app/unleash/issue/1-1598/e2e-ui-tests) --------- Signed-off-by: andreas-unleash <andreas@getunleash.ai> Co-authored-by: Thomas Heartman <thomas@getunleash.io>
This commit is contained in:
parent
24f9fa3058
commit
3e9d88f789
@ -0,0 +1,289 @@
|
|||||||
|
import { fireEvent, screen, waitFor, within } from '@testing-library/react';
|
||||||
|
import { testServerRoute, testServerSetup } from 'utils/testServer';
|
||||||
|
import { ChangeRequestState, IChangeRequest } from '../changeRequest.types';
|
||||||
|
import { render } from 'utils/testRenderer';
|
||||||
|
import { ChangeRequestOverview } from './ChangeRequestOverview';
|
||||||
|
import {
|
||||||
|
ADMIN,
|
||||||
|
APPLY_CHANGE_REQUEST,
|
||||||
|
} from 'component/providers/AccessProvider/permissions';
|
||||||
|
import { Route, Routes } from 'react-router-dom';
|
||||||
|
|
||||||
|
const server = testServerSetup();
|
||||||
|
const mockChangeRequest = (
|
||||||
|
featureName: string,
|
||||||
|
state: ChangeRequestState,
|
||||||
|
): IChangeRequest => {
|
||||||
|
const result: IChangeRequest = {
|
||||||
|
id: 1,
|
||||||
|
environment: 'production',
|
||||||
|
state: state,
|
||||||
|
minApprovals: 1,
|
||||||
|
project: 'default',
|
||||||
|
createdBy: {
|
||||||
|
id: 1,
|
||||||
|
username: 'admin',
|
||||||
|
imageUrl:
|
||||||
|
'https://gravatar.com/avatar/21232f297a57a5a743894a0e4a801fc3?size=42&default=retro',
|
||||||
|
},
|
||||||
|
createdAt: new Date('2022-12-02T09:19:12.242Z'),
|
||||||
|
segments: [],
|
||||||
|
title: '',
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
name: featureName,
|
||||||
|
changes: [
|
||||||
|
{
|
||||||
|
id: 292,
|
||||||
|
action: 'addStrategy',
|
||||||
|
payload: {
|
||||||
|
name: 'default',
|
||||||
|
segments: [],
|
||||||
|
parameters: {},
|
||||||
|
constraints: [],
|
||||||
|
},
|
||||||
|
createdAt: new Date('2022-12-02T09:19:12.245Z'),
|
||||||
|
createdBy: {
|
||||||
|
id: 1,
|
||||||
|
username: 'admin',
|
||||||
|
imageUrl:
|
||||||
|
'https://gravatar.com/avatar/21232f297a57a5a743894a0e4a801fc3?size=42&default=retro',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
approvals: [],
|
||||||
|
rejections: [],
|
||||||
|
comments: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (state === 'Scheduled') {
|
||||||
|
result.schedule = {
|
||||||
|
scheduledAt: '2022-12-02T09:19:12.242Z',
|
||||||
|
status: 'pending',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
const pendingChangeRequest = (changeRequest: IChangeRequest) =>
|
||||||
|
testServerRoute(
|
||||||
|
server,
|
||||||
|
'/api/admin/projects/default/change-requests/pending',
|
||||||
|
[changeRequest],
|
||||||
|
);
|
||||||
|
|
||||||
|
const changeRequest = (changeRequest: IChangeRequest) =>
|
||||||
|
testServerRoute(
|
||||||
|
server,
|
||||||
|
'/api/admin/projects/default/change-requests/1',
|
||||||
|
changeRequest,
|
||||||
|
'get',
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateChangeRequestState = () =>
|
||||||
|
testServerRoute(
|
||||||
|
server,
|
||||||
|
'/api/admin/projects/default/change-requests/1/state',
|
||||||
|
{},
|
||||||
|
'post',
|
||||||
|
);
|
||||||
|
const changeRequestConfig = () =>
|
||||||
|
testServerRoute(
|
||||||
|
server,
|
||||||
|
'/api/admin/projects/default/change-requests/config',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
environment: 'development',
|
||||||
|
type: 'development',
|
||||||
|
changeRequestEnabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
environment: 'production',
|
||||||
|
type: 'production',
|
||||||
|
changeRequestEnabled: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'get',
|
||||||
|
);
|
||||||
|
|
||||||
|
const setupChangeRequest = (featureName: string, state: ChangeRequestState) => {
|
||||||
|
pendingChangeRequest(mockChangeRequest(featureName, state));
|
||||||
|
changeRequest(mockChangeRequest(featureName, state));
|
||||||
|
};
|
||||||
|
|
||||||
|
const uiConfig = () => {
|
||||||
|
testServerRoute(server, '/api/admin/ui-config', {
|
||||||
|
versionInfo: {
|
||||||
|
current: { oss: 'version', enterprise: 'version' },
|
||||||
|
},
|
||||||
|
flags: {
|
||||||
|
scheduledConfigurationChanges: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const user = () => {
|
||||||
|
testServerRoute(server, '/api/admin/user', {
|
||||||
|
user: {
|
||||||
|
isAPI: false,
|
||||||
|
id: 17,
|
||||||
|
name: 'Some User',
|
||||||
|
email: 'user@example.com',
|
||||||
|
imageUrl:
|
||||||
|
'https://gravatar.com/avatar/8aa1132e102345f8c79322340e15340?size=42&default=retro',
|
||||||
|
seenAt: '2022-11-28T14:55:18.982Z',
|
||||||
|
loginAttempts: 0,
|
||||||
|
createdAt: '2022-11-23T13:31:17.061Z',
|
||||||
|
},
|
||||||
|
permissions: [{ permission: ADMIN }],
|
||||||
|
feedback: [],
|
||||||
|
splash: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupHttpRoutes = () => {
|
||||||
|
uiConfig();
|
||||||
|
changeRequestConfig();
|
||||||
|
user();
|
||||||
|
updateChangeRequestState();
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
setupHttpRoutes();
|
||||||
|
});
|
||||||
|
|
||||||
|
const Component = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Routes>
|
||||||
|
<Route
|
||||||
|
path={'/projects/:projectId/change-requests/:id'}
|
||||||
|
element={<ChangeRequestOverview />}
|
||||||
|
/>
|
||||||
|
</Routes>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const featureName = 'feature1';
|
||||||
|
|
||||||
|
test('should allow scheduling of approved change request and show the schedule dialog', async () => {
|
||||||
|
setupChangeRequest(featureName, 'Approved');
|
||||||
|
|
||||||
|
render(<Component />, {
|
||||||
|
route: '/projects/default/change-requests/1',
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
permission: APPLY_CHANGE_REQUEST,
|
||||||
|
project: 'default',
|
||||||
|
environment: 'production',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const applyOrScheduleButton = await screen.findByText(
|
||||||
|
'Apply or schedule changes',
|
||||||
|
);
|
||||||
|
await waitFor(() => expect(applyOrScheduleButton).toBeEnabled(), {
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(applyOrScheduleButton);
|
||||||
|
|
||||||
|
const scheduleChangesButton = await screen.findByRole('menuitem', {
|
||||||
|
name: 'Schedule changes',
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(scheduleChangesButton);
|
||||||
|
|
||||||
|
await screen.findByRole('dialog', { name: 'Schedule changes' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show a reschedule dialog when change request is scheduled and update schedule is selected', async () => {
|
||||||
|
setupChangeRequest(featureName, 'Scheduled');
|
||||||
|
render(<Component />, {
|
||||||
|
route: '/projects/default/change-requests/1',
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
permission: APPLY_CHANGE_REQUEST,
|
||||||
|
project: 'default',
|
||||||
|
environment: 'production',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const applyOrScheduleButton = await screen.findByText(
|
||||||
|
'Apply or schedule changes',
|
||||||
|
);
|
||||||
|
await waitFor(() => expect(applyOrScheduleButton).toBeEnabled(), {
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
|
fireEvent.click(applyOrScheduleButton);
|
||||||
|
|
||||||
|
const scheduleChangesButton = await screen.findByRole('menuitem', {
|
||||||
|
name: 'Update schedule',
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.click(scheduleChangesButton);
|
||||||
|
|
||||||
|
await screen.findByRole('dialog', { name: 'Update schedule' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show an apply dialog when change request is scheduled and apply is selected', async () => {
|
||||||
|
setupChangeRequest(featureName, 'Scheduled');
|
||||||
|
|
||||||
|
render(<Component />, {
|
||||||
|
route: '/projects/default/change-requests/1',
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
permission: APPLY_CHANGE_REQUEST,
|
||||||
|
project: 'default',
|
||||||
|
environment: 'production',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const applyOrScheduleButton = await screen.findByText(
|
||||||
|
'Apply or schedule changes',
|
||||||
|
);
|
||||||
|
await waitFor(() => expect(applyOrScheduleButton).toBeEnabled(), {
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
|
fireEvent.click(applyOrScheduleButton);
|
||||||
|
|
||||||
|
const applyChangesButton = await screen.findByRole('menuitem', {
|
||||||
|
name: 'Apply changes',
|
||||||
|
});
|
||||||
|
fireEvent.click(applyChangesButton);
|
||||||
|
|
||||||
|
await screen.findByRole('dialog', { name: 'Apply changes' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show a reject dialog when change request is scheduled and Reject Changes button is clicked', async () => {
|
||||||
|
setupChangeRequest(featureName, 'Scheduled');
|
||||||
|
|
||||||
|
render(<Component />, {
|
||||||
|
route: '/projects/default/change-requests/1',
|
||||||
|
permissions: [{ permission: ADMIN }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const applyOrScheduleButton = await screen.findByText(
|
||||||
|
'Apply or schedule changes',
|
||||||
|
);
|
||||||
|
await waitFor(() => expect(applyOrScheduleButton).toBeEnabled(), {
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const buttons = await screen.findAllByRole('button');
|
||||||
|
const rejectChangesButton = buttons[buttons.length - 1];
|
||||||
|
expect(
|
||||||
|
within(rejectChangesButton).getByText('Reject changes'),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
fireEvent.click(rejectChangesButton);
|
||||||
|
|
||||||
|
await screen.findByRole('dialog', {
|
||||||
|
name: 'Reject changes',
|
||||||
|
});
|
||||||
|
});
|
@ -186,13 +186,13 @@ export const ChangeRequestOverview: FC = () => {
|
|||||||
comment,
|
comment,
|
||||||
});
|
});
|
||||||
setShowRejectDialog(false);
|
setShowRejectDialog(false);
|
||||||
refetchChangeRequest();
|
|
||||||
refetchChangeRequestOpen();
|
|
||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
text: 'Changes rejected',
|
text: 'Changes rejected',
|
||||||
});
|
});
|
||||||
|
refetchChangeRequest();
|
||||||
|
refetchChangeRequestOpen();
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
setToastApiError(formatUnknownError(error));
|
setToastApiError(formatUnknownError(error));
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,10 @@ export const MultiActionButton: FC<{
|
|||||||
>
|
>
|
||||||
{actions.map(
|
{actions.map(
|
||||||
({ label, onSelect, icon }) => (
|
({ label, onSelect, icon }) => (
|
||||||
<MenuItem onClick={onSelect}>
|
<MenuItem
|
||||||
|
onClick={onSelect}
|
||||||
|
key={`MenuItem-${label}`}
|
||||||
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
{icon}
|
{icon}
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
@ -6,7 +6,7 @@ export const UpdateCount: FC<{
|
|||||||
featuresCount: number;
|
featuresCount: number;
|
||||||
segmentsCount: number;
|
segmentsCount: number;
|
||||||
}> = ({ featuresCount, segmentsCount }) => (
|
}> = ({ featuresCount, segmentsCount }) => (
|
||||||
<Box sx={{ display: 'inline', pl: 0.5 }}>
|
<Box component={'span'} sx={{ display: 'inline', pl: 0.5 }}>
|
||||||
<Typography
|
<Typography
|
||||||
component='span'
|
component='span'
|
||||||
variant='body2'
|
variant='body2'
|
||||||
|
@ -14,7 +14,6 @@ export const useChangeRequestConfig = (projectId: string) => {
|
|||||||
formatApiPath(`api/admin/projects/${projectId}/change-requests/config`),
|
formatApiPath(`api/admin/projects/${projectId}/change-requests/config`),
|
||||||
fetcher,
|
fetcher,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: data || [],
|
data: data || [],
|
||||||
loading: !error && !data,
|
loading: !error && !data,
|
||||||
|
Loading…
Reference in New Issue
Block a user