Skip to content

Commit 4978b72

Browse files
test: added tests for mcp and workspace deletion (#356)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 1b5dbf0 commit 4978b72

10 files changed

+357
-32
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { SplitterProvider } from '../../Splitter/SplitterContext.tsx';
2+
import { ListControlPlanesType } from '../../../lib/api/types/crate/controlPlanes.ts';
3+
import { MemoryRouter } from 'react-router-dom';
4+
import '@ui5/webcomponents-cypress-commands';
5+
import { ControlPlaneCard } from './ControlPlaneCard.tsx';
6+
import { useDeleteManagedControlPlane } from '../../../hooks/useDeleteManagedControlPlane.ts';
7+
import { ListWorkspacesType } from '../../../lib/api/types/crate/listWorkspaces.ts';
8+
9+
describe('ControlPlaneCard', () => {
10+
let deleteManagedControlPlaneCalled = false;
11+
const fakeUseDeleteManagedControlPlane: typeof useDeleteManagedControlPlane = () => ({
12+
deleteManagedControlPlane: async (): Promise<void> => {
13+
deleteManagedControlPlaneCalled = true;
14+
},
15+
});
16+
17+
beforeEach(() => {
18+
deleteManagedControlPlaneCalled = false;
19+
});
20+
21+
it('deletes the workspace', () => {
22+
const managedControlPlane: ListControlPlanesType = {
23+
metadata: {
24+
name: 'mcp-name',
25+
},
26+
} as unknown as ListControlPlanesType;
27+
28+
const workspace: ListWorkspacesType = {
29+
metadata: {
30+
name: 'workspaceName',
31+
},
32+
} as unknown as ListWorkspacesType;
33+
34+
cy.mount(
35+
<MemoryRouter>
36+
<SplitterProvider>
37+
<ControlPlaneCard
38+
controlPlane={managedControlPlane}
39+
workspace={workspace}
40+
projectName="projectName"
41+
useDeleteManagedControlPlane={fakeUseDeleteManagedControlPlane}
42+
/>
43+
</SplitterProvider>
44+
</MemoryRouter>,
45+
);
46+
47+
cy.get("[data-testid='ControlPlaneCardMenu-opener']").click();
48+
cy.contains('Delete ManagedControlPlane').click({ force: true });
49+
cy.get('ui5-dialog[open]').find('ui5-input').typeIntoUi5Input('mcp-name');
50+
cy.then(() => cy.wrap(deleteManagedControlPlaneCalled).should('equal', false));
51+
cy.get('ui5-dialog[open]').find('ui5-button').contains('Delete').click();
52+
cy.then(() => cy.wrap(deleteManagedControlPlaneCalled).should('equal', true));
53+
});
54+
});

src/components/ControlPlanes/ControlPlaneCard/ControlPlaneCard.tsx

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,34 @@ import styles from './ControlPlaneCard.module.css';
1414
import { KubectlDeleteMcp } from '../../Dialogs/KubectlCommandInfo/Controllers/KubectlDeleteMcp.tsx';
1515
import { ListControlPlanesType, ReadyStatus } from '../../../lib/api/types/crate/controlPlanes.ts';
1616
import { ListWorkspacesType } from '../../../lib/api/types/crate/listWorkspaces.ts';
17-
import { useApiResourceMutation } from '../../../lib/api/useApiResource.ts';
18-
import {
19-
DeleteMCPResource,
20-
DeleteMCPType,
21-
PatchMCPResourceForDeletion,
22-
PatchMCPResourceForDeletionBody,
23-
} from '../../../lib/api/types/crate/deleteMCP.ts';
24-
2517
import { YamlViewButton } from '../../Yaml/YamlViewButton.tsx';
26-
import { useToast } from '../../../context/ToastContext.tsx';
2718
import { canConnectToMCP } from '../controlPlanes.ts';
2819

2920
import { Infobox } from '../../Ui/Infobox/Infobox.tsx';
3021

3122
import { ControlPlaneCardMenu } from './ControlPlaneCardMenu.tsx';
3223
import { EditManagedControlPlaneWizardDataLoader } from '../../Wizards/CreateManagedControlPlane/EditManagedControlPlaneWizardDataLoader.tsx';
3324
import { DISPLAY_NAME_ANNOTATION } from '../../../lib/api/types/shared/keyNames.ts';
25+
import { useDeleteManagedControlPlane as _useDeleteManagedControlPlane } from '../../../hooks/useDeleteManagedControlPlane.ts';
3426

3527
interface Props {
3628
controlPlane: ListControlPlanesType;
3729
workspace: ListWorkspacesType;
3830
projectName: string;
31+
useDeleteManagedControlPlane?: typeof _useDeleteManagedControlPlane;
3932
}
4033

4134
type MCPWizardState = {
4235
isOpen: boolean;
4336
mode?: 'edit' | 'duplicate';
4437
};
45-
export const ControlPlaneCard = ({ controlPlane, workspace, projectName }: Props) => {
38+
export const ControlPlaneCard = ({
39+
controlPlane,
40+
workspace,
41+
projectName,
42+
useDeleteManagedControlPlane = _useDeleteManagedControlPlane,
43+
}: Props) => {
4644
const [dialogDeleteMcpIsOpen, setDialogDeleteMcpIsOpen] = useState(false);
47-
const toast = useToast();
4845
const { t } = useTranslation();
4946
const [managedControlPlaneWizardState, setManagedControlPlaneWizardState] = useState<MCPWizardState>({
5047
isOpen: false,
@@ -54,11 +51,9 @@ export const ControlPlaneCard = ({ controlPlane, workspace, projectName }: Props
5451
const handleIsManagedControlPlaneWizardOpen = (isOpen: boolean, mode?: 'edit' | 'duplicate') => {
5552
setManagedControlPlaneWizardState({ isOpen, mode });
5653
};
57-
const { trigger: patchTrigger } = useApiResourceMutation<DeleteMCPType>(
58-
PatchMCPResourceForDeletion(controlPlane.metadata.namespace, controlPlane.metadata.name),
59-
);
60-
const { trigger: deleteTrigger } = useApiResourceMutation<DeleteMCPType>(
61-
DeleteMCPResource(controlPlane.metadata.namespace, controlPlane.metadata.name),
54+
const { deleteManagedControlPlane } = useDeleteManagedControlPlane(
55+
controlPlane.metadata.namespace,
56+
controlPlane.metadata.name,
6257
);
6358

6459
const name = controlPlane.metadata.name;
@@ -135,11 +130,7 @@ export const ControlPlaneCard = ({ controlPlane, workspace, projectName }: Props
135130
}
136131
isOpen={dialogDeleteMcpIsOpen}
137132
setIsOpen={setDialogDeleteMcpIsOpen}
138-
onDeletionConfirmed={async () => {
139-
await patchTrigger(PatchMCPResourceForDeletionBody);
140-
await deleteTrigger();
141-
toast.show(t('ControlPlaneCard.deleteConfirmationDialog'));
142-
}}
133+
onDeletionConfirmed={deleteManagedControlPlane}
143134
/>
144135
<EditManagedControlPlaneWizardDataLoader
145136
isOpen={managedControlPlaneWizardState.isOpen}

src/components/ControlPlanes/ControlPlaneCard/ControlPlaneCardMenu.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ export const ControlPlaneCardMenu: FC<ControlPlanesListMenuProps> = ({
2727

2828
return (
2929
<>
30-
<Button ref={buttonRef} icon="overflow" icon-end onClick={handleOpenerClick} />
30+
<Button
31+
ref={buttonRef}
32+
icon="overflow"
33+
icon-end
34+
data-testid="ControlPlaneCardMenu-opener"
35+
onClick={handleOpenerClick}
36+
/>
3137
<Menu
3238
open={menuIsOpen}
3339
opener={buttonRef.current}

src/components/ControlPlanes/ControlPlanesListMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const ControlPlanesListMenu: FC<ControlPlanesListMenuProps> = ({
3535

3636
return (
3737
<>
38-
<Button icon="overflow" icon-end onClick={handleOpenerClick} />
38+
<Button icon="overflow" icon-end data-testid="ControlPlanesListMenu-opener" onClick={handleOpenerClick} />
3939
<Menu
4040
ref={popoverRef}
4141
open={open}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { ControlPlaneListWorkspaceGridTile } from './ControlPlaneListWorkspaceGridTile.tsx';
2+
import { SplitterProvider } from '../../Splitter/SplitterContext.tsx';
3+
import { useManagedControlPlanesQuery } from '../../../hooks/useManagedControlPlanesQuery.ts';
4+
import { ControlPlaneType, ReadyStatus } from '../../../lib/api/types/crate/controlPlanes.ts';
5+
import { MemoryRouter } from 'react-router-dom';
6+
import { useDeleteWorkspace } from '../../../hooks/useDeleteWorkspace.ts';
7+
import '@ui5/webcomponents-cypress-commands';
8+
import { ListWorkspacesType } from '../../../lib/api/types/crate/listWorkspaces.ts';
9+
10+
describe('ControlPlaneListWorkspaceGridTile', () => {
11+
let deleteWorkspaceCalled = false;
12+
const fakeUseDeleteWorkspace: typeof useDeleteWorkspace = () => ({
13+
deleteWorkspace: async (): Promise<void> => {
14+
deleteWorkspaceCalled = true;
15+
},
16+
});
17+
18+
const fakeManagedControlPlanes: ControlPlaneType[] = [
19+
{
20+
metadata: {
21+
name: 'mcp-a',
22+
namespace: 'project-webapp-playground--ws-workspaceName',
23+
creationTimestamp: '2024-05-28T10:00:00Z',
24+
},
25+
spec: {
26+
authentication: {
27+
enableSystemIdentityProvider: true,
28+
},
29+
components: {
30+
crossplane: undefined,
31+
btpServiceOperator: undefined,
32+
externalSecretsOperator: undefined,
33+
kyverno: undefined,
34+
flux: undefined,
35+
landscaper: undefined,
36+
},
37+
},
38+
status: {
39+
status: ReadyStatus.Ready,
40+
conditions: [],
41+
access: undefined,
42+
},
43+
},
44+
{
45+
metadata: {
46+
annotations: {
47+
'openmcp.cloud/created-by': 'andreas.kienle@sap.com',
48+
'openmcp.cloud/display-name': '',
49+
},
50+
name: 'd056765-all',
51+
namespace: 'project-webapp-playground--ws-d056765',
52+
creationTimestamp: '2024-05-28T10:00:00Z',
53+
},
54+
spec: {
55+
authentication: {
56+
enableSystemIdentityProvider: true,
57+
},
58+
components: {
59+
crossplane: undefined,
60+
btpServiceOperator: undefined,
61+
externalSecretsOperator: undefined,
62+
kyverno: undefined,
63+
flux: undefined,
64+
landscaper: undefined,
65+
},
66+
},
67+
status: {
68+
status: ReadyStatus.Ready,
69+
conditions: [],
70+
access: undefined,
71+
},
72+
},
73+
{
74+
metadata: {
75+
annotations: {
76+
'openmcp.cloud/created-by': 'andreas.kienle@sap.com',
77+
'openmcp.cloud/display-name': '',
78+
},
79+
name: 'flux',
80+
namespace: 'project-webapp-playground--ws-d056765',
81+
creationTimestamp: '2024-05-28T10:00:00Z',
82+
},
83+
spec: {
84+
authentication: {
85+
enableSystemIdentityProvider: true,
86+
},
87+
components: {
88+
crossplane: undefined,
89+
btpServiceOperator: undefined,
90+
externalSecretsOperator: undefined,
91+
kyverno: undefined,
92+
flux: undefined,
93+
landscaper: undefined,
94+
},
95+
},
96+
status: {
97+
status: ReadyStatus.Ready,
98+
conditions: [],
99+
access: undefined,
100+
},
101+
},
102+
];
103+
104+
const fakeUseManagedControlPlanesQuery: typeof useManagedControlPlanesQuery = () => ({
105+
managedControlPlanes: fakeManagedControlPlanes,
106+
error: undefined,
107+
});
108+
109+
beforeEach(() => {
110+
deleteWorkspaceCalled = false;
111+
});
112+
113+
it('deletes the workspace', () => {
114+
const workspace: ListWorkspacesType = {
115+
metadata: {
116+
name: 'workspaceName',
117+
},
118+
spec: {
119+
members: [],
120+
},
121+
} as unknown as ListWorkspacesType;
122+
123+
cy.mount(
124+
<MemoryRouter>
125+
<SplitterProvider>
126+
<ControlPlaneListWorkspaceGridTile
127+
workspace={workspace}
128+
projectName="some-project"
129+
useManagedControlPlanesQuery={fakeUseManagedControlPlanesQuery}
130+
useDeleteWorkspace={fakeUseDeleteWorkspace}
131+
/>
132+
</SplitterProvider>
133+
</MemoryRouter>,
134+
);
135+
136+
cy.get("[data-testid='ControlPlanesListMenu-opener']").click();
137+
cy.contains('Delete workspace').click({ force: true });
138+
cy.get('ui5-dialog[open]').find('ui5-input').typeIntoUi5Input('workspaceName');
139+
cy.then(() => cy.wrap(deleteWorkspaceCalled).should('equal', false));
140+
cy.get('ui5-dialog[open]').find('ui5-button').contains('Delete').click();
141+
cy.then(() => cy.wrap(deleteWorkspaceCalled).should('equal', true));
142+
});
143+
});

src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ import { ControlPlaneCard } from '../ControlPlaneCard/ControlPlaneCard.tsx';
77
import { ListWorkspacesType, isWorkspaceReady } from '../../../lib/api/types/crate/listWorkspaces.ts';
88
import { useMemo, useState } from 'react';
99
import { MembersAvatarView } from './MembersAvatarView.tsx';
10-
import { useApiResource } from '../../../lib/api/useApiResource.ts';
1110
import { DISPLAY_NAME_ANNOTATION } from '../../../lib/api/types/shared/keyNames.ts';
1211
import { DeleteConfirmationDialog } from '../../Dialogs/DeleteConfirmationDialog.tsx';
1312
import { KubectlDeleteWorkspace } from '../../Dialogs/KubectlCommandInfo/Controllers/KubectlDeleteWorkspace.tsx';
14-
import { ListControlPlanes } from '../../../lib/api/types/crate/controlPlanes.ts';
1513
import IllustratedError from '../../Shared/IllustratedError.tsx';
1614
import { APIError } from '../../../lib/api/error.ts';
1715
import { useTranslation } from 'react-i18next';
@@ -23,16 +21,19 @@ import styles from './WorkspacesList.module.css';
2321
import { ControlPlanesListMenu } from '../ControlPlanesListMenu.tsx';
2422
import { CreateManagedControlPlaneWizardContainer } from '../../Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx';
2523
import { useDeleteWorkspace as _useDeleteWorkspace } from '../../../hooks/useDeleteWorkspace.ts';
24+
import { useManagedControlPlanesQuery as _useManagedControlPlanesQuery } from '../../../hooks/useManagedControlPlanesQuery.ts';
2625

2726
interface Props {
2827
projectName: string;
2928
workspace: ListWorkspacesType;
29+
useManagedControlPlanesQuery?: typeof _useManagedControlPlanesQuery;
3030
useDeleteWorkspace?: typeof _useDeleteWorkspace;
3131
}
3232

3333
export function ControlPlaneListWorkspaceGridTile({
3434
projectName,
3535
workspace,
36+
useManagedControlPlanesQuery = _useManagedControlPlanesQuery,
3637
useDeleteWorkspace = _useDeleteWorkspace,
3738
}: Props) {
3839
const [isCreateManagedControlPlaneWizardOpen, setIsCreateManagedControlPlaneWizardOpen] = useState(false);
@@ -46,7 +47,7 @@ export function ControlPlaneListWorkspaceGridTile({
4647

4748
const [dialogDeleteWsIsOpen, setDialogDeleteWsIsOpen] = useState(false);
4849

49-
const { data: controlplanes, error: cpsError } = useApiResource(ListControlPlanes(projectName, workspaceName));
50+
const { managedControlPlanes, error: cpsError } = useManagedControlPlanesQuery(projectName, workspaceName);
5051
const { deleteWorkspace } = useDeleteWorkspace(projectName, projectNamespace, workspaceName);
5152

5253
const { mcpCreationGuide } = useLink();
@@ -138,7 +139,7 @@ export function ControlPlaneListWorkspaceGridTile({
138139
>
139140
{errorView ? (
140141
errorView
141-
) : controlplanes?.length === 0 ? (
142+
) : managedControlPlanes?.length === 0 ? (
142143
<IllustratedBanner
143144
title={t('IllustratedBanner.titleMessage')}
144145
subtitle={t('IllustratedBanner.subtitleMessage')}
@@ -164,10 +165,10 @@ export function ControlPlaneListWorkspaceGridTile({
164165
) : (
165166
<div className={styles.wrapper}>
166167
<div className={styles.grid}>
167-
{controlplanes?.map((cp) => (
168+
{managedControlPlanes?.map((mcp) => (
168169
<ControlPlaneCard
169-
key={`${cp.metadata.name}--${cp.metadata.namespace}`}
170-
controlPlane={cp}
170+
key={`${mcp.metadata.name}--${mcp.metadata.namespace}`}
171+
controlPlane={mcp}
171172
projectName={projectName}
172173
workspace={workspace}
173174
/>

0 commit comments

Comments
 (0)