|
1 | | -import { screen, waitFor } from '@testing-library/react'; |
| 1 | +import type { ComponentProps } from 'react'; |
| 2 | +import { screen } from '@testing-library/react'; |
2 | 3 | import userEvent from '@testing-library/user-event'; |
3 | | -import { Formik } from 'formik'; |
4 | | -import type { ObjectSchema } from 'yup'; |
5 | | -import * as yup from 'yup'; |
6 | | -import { limitsValidationSchema } from '@console/dev-console/src/components/import/validation-schema'; |
7 | | -import type { K8sResourceKind } from '@console/internal/module/k8s'; |
| 4 | +import type { FormikProps, FormikValues } from 'formik'; |
| 5 | +import { formikFormProps } from '@console/shared/src/test-utils/formik-props-utils'; |
8 | 6 | import { renderWithProviders } from '@console/shared/src/test-utils/unit-test-utils'; |
9 | | -import { getLimitsDataFromResource } from '@console/shared/src/utils/resource-utils'; |
10 | | -import { t } from '../../../../../../../__mocks__/i18next'; |
11 | 7 | import ResourceLimitsModal from '../ResourceLimitsModal'; |
12 | 8 |
|
13 | | -jest.mock('@patternfly/react-topology', () => ({})); |
| 9 | +jest.mock('@console/dev-console/src/components/import/advanced/ResourceLimitSection', () => ({ |
| 10 | + default: () => null, |
| 11 | +})); |
14 | 12 |
|
15 | | -const emptyLimits = { |
16 | | - cpu: { |
17 | | - request: '', |
18 | | - requestUnit: '', |
19 | | - defaultRequestUnit: '', |
20 | | - limit: '', |
21 | | - limitUnit: '', |
22 | | - defaultLimitUnit: '', |
23 | | - }, |
24 | | - memory: { |
25 | | - request: '', |
26 | | - requestUnit: 'Mi', |
27 | | - defaultRequestUnit: 'Mi', |
28 | | - limit: '', |
29 | | - limitUnit: 'Mi', |
30 | | - defaultLimitUnit: 'Mi', |
31 | | - }, |
32 | | -}; |
| 13 | +type ResourceLimitsModalProps = ComponentProps<typeof ResourceLimitsModal>; |
33 | 14 |
|
34 | | -const resourceLimitsSchema = yup.object().shape({ |
35 | | - limits: limitsValidationSchema(t), |
36 | | -}); |
| 15 | +describe('ResourceLimitsModal Form', () => { |
| 16 | + let formProps: ResourceLimitsModalProps; |
37 | 17 |
|
38 | | -const limitsFormValues = { |
39 | | - limits: emptyLimits, |
40 | | - container: 'hello-openshift', |
41 | | -}; |
| 18 | + type Props = FormikProps<FormikValues> & ResourceLimitsModalProps; |
42 | 19 |
|
43 | | -const baseDeployment = (): K8sResourceKind => |
44 | | - ({ |
45 | | - apiVersion: 'apps/v1', |
46 | | - kind: 'Deployment', |
47 | | - metadata: { |
48 | | - name: 'xyz-deployment', |
49 | | - }, |
50 | | - spec: { |
51 | | - selector: { |
52 | | - matchLabels: { |
53 | | - app: 'hello-openshift', |
54 | | - }, |
55 | | - }, |
56 | | - replicas: 1, |
57 | | - template: { |
| 20 | + beforeEach(() => { |
| 21 | + jest.clearAllMocks(); |
| 22 | + formProps = { |
| 23 | + ...formikFormProps, |
| 24 | + isSubmitting: false, |
| 25 | + cancel: jest.fn(), |
| 26 | + resource: { |
| 27 | + apiVersion: 'apps/v1', |
| 28 | + kind: 'Deployment', |
58 | 29 | metadata: { |
59 | | - labels: { |
60 | | - app: 'hello-openshift', |
61 | | - }, |
| 30 | + name: 'xyz-deployment', |
62 | 31 | }, |
63 | 32 | spec: { |
64 | | - containers: [ |
65 | | - { |
66 | | - name: 'hello-openshift', |
67 | | - image: 'openshift/hello-openshift', |
68 | | - ports: [ |
| 33 | + selector: { |
| 34 | + matchLabels: { |
| 35 | + app: 'hello-openshift', |
| 36 | + }, |
| 37 | + }, |
| 38 | + replicas: 1, |
| 39 | + template: { |
| 40 | + metadata: { |
| 41 | + labels: { |
| 42 | + app: 'hello-openshift', |
| 43 | + }, |
| 44 | + }, |
| 45 | + spec: { |
| 46 | + containers: [ |
69 | 47 | { |
70 | | - containerPort: 8080, |
| 48 | + name: 'hello-openshift', |
| 49 | + image: 'openshift/hello-openshift', |
| 50 | + ports: [ |
| 51 | + { |
| 52 | + containerPort: 8080, |
| 53 | + }, |
| 54 | + ], |
71 | 55 | }, |
72 | 56 | ], |
73 | 57 | }, |
74 | | - ], |
| 58 | + }, |
75 | 59 | }, |
76 | 60 | }, |
77 | | - }, |
78 | | - } as K8sResourceKind); |
79 | | - |
80 | | -type RenderResourceLimitsModalOptions = { |
81 | | - resource?: K8sResourceKind; |
82 | | - validationSchema?: ObjectSchema<unknown>; |
83 | | - onSubmit?: jest.Mock; |
84 | | - cancel?: jest.Mock; |
85 | | -}; |
86 | | - |
87 | | -const renderResourceLimitsModal = ({ |
88 | | - resource, |
89 | | - validationSchema, |
90 | | - onSubmit: onSubmitOption, |
91 | | - cancel: cancelOption, |
92 | | -}: RenderResourceLimitsModalOptions = {}) => { |
93 | | - const onSubmit = onSubmitOption ?? jest.fn(); |
94 | | - const cancel = cancelOption ?? jest.fn(); |
95 | | - const initialValues = resource |
96 | | - ? { |
97 | | - limits: getLimitsDataFromResource(resource), |
98 | | - container: resource.spec.template.spec.containers[0].name, |
99 | | - } |
100 | | - : limitsFormValues; |
101 | | - |
102 | | - return { |
103 | | - onSubmit, |
104 | | - cancel, |
105 | | - ...renderWithProviders( |
106 | | - <Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={onSubmit}> |
107 | | - {(formikProps) => ( |
108 | | - <ResourceLimitsModal {...formikProps} cancel={cancel} isSubmitting={false} /> |
109 | | - )} |
110 | | - </Formik>, |
111 | | - ), |
112 | | - }; |
113 | | -}; |
114 | | - |
115 | | -describe('ResourceLimitsModal Form', () => { |
116 | | - beforeEach(() => { |
117 | | - jest.clearAllMocks(); |
| 61 | + } as Props; |
118 | 62 | }); |
119 | 63 |
|
120 | | - it('renders the modal title', () => { |
121 | | - renderResourceLimitsModal(); |
| 64 | + it('renders the modal with the correct title and initial elements', () => { |
| 65 | + renderWithProviders(<ResourceLimitsModal {...formProps} />); |
122 | 66 |
|
123 | 67 | expect(screen.getByText('Edit resource limits')).toBeVisible(); |
124 | | - }); |
125 | | - |
126 | | - it('renders the form with Cancel and Save actions', () => { |
127 | | - renderResourceLimitsModal(); |
128 | | - |
129 | 68 | expect(screen.getByRole('form')).toBeVisible(); |
130 | 69 | expect(screen.getByRole('button', { name: 'Cancel' })).toBeVisible(); |
131 | 70 | expect(screen.getByRole('button', { name: 'Save' })).toBeVisible(); |
132 | 71 | }); |
133 | 72 |
|
134 | 73 | it('calls the cancel function when the Cancel button is clicked', async () => { |
135 | 74 | const user = userEvent.setup(); |
136 | | - const cancel = jest.fn(); |
137 | | - renderResourceLimitsModal({ cancel }); |
| 75 | + renderWithProviders(<ResourceLimitsModal {...formProps} />); |
138 | 76 |
|
139 | 77 | await user.click(screen.getByRole('button', { name: 'Cancel' })); |
140 | | - expect(cancel).toHaveBeenCalledTimes(1); |
| 78 | + expect(formProps.cancel).toHaveBeenCalledTimes(1); |
141 | 79 | }); |
142 | 80 |
|
143 | | - it('submits the form when Save is clicked', async () => { |
| 81 | + it('calls the handleSubmit function when the form is submitted', async () => { |
144 | 82 | const user = userEvent.setup(); |
145 | | - const onSubmit = jest.fn(); |
146 | | - renderResourceLimitsModal({ onSubmit }); |
| 83 | + renderWithProviders(<ResourceLimitsModal {...formProps} />); |
147 | 84 |
|
148 | 85 | await user.click(screen.getByRole('button', { name: 'Save' })); |
149 | | - expect(onSubmit).toHaveBeenCalledTimes(1); |
150 | | - }); |
151 | | -}); |
152 | | - |
153 | | -describe('ResourceLimitsModal with validation (resource limits schema)', () => { |
154 | | - beforeEach(() => { |
155 | | - jest.clearAllMocks(); |
156 | | - }); |
157 | | - |
158 | | - it('populates CPU and Memory request/limit fields from the workload resource', () => { |
159 | | - const resource = baseDeployment(); |
160 | | - resource.spec.template.spec.containers[0].resources = { |
161 | | - requests: { cpu: '100m', memory: '128Mi' }, |
162 | | - limits: { cpu: '500m', memory: '256Mi' }, |
163 | | - }; |
164 | | - |
165 | | - renderResourceLimitsModal({ resource, validationSchema: resourceLimitsSchema }); |
166 | | - |
167 | | - expect(screen.getByDisplayValue('100')).toBeVisible(); |
168 | | - expect(screen.getByDisplayValue('500')).toBeVisible(); |
169 | | - expect(screen.getByDisplayValue('128')).toBeVisible(); |
170 | | - expect(screen.getByDisplayValue('256')).toBeVisible(); |
171 | | - }); |
172 | | - |
173 | | - it('disables Save when CPU request is greater than CPU limit', async () => { |
174 | | - const user = userEvent.setup(); |
175 | | - const resource = baseDeployment(); |
176 | | - resource.spec.template.spec.containers[0].resources = { |
177 | | - requests: { cpu: '100m', memory: '128Mi' }, |
178 | | - limits: { cpu: '200m', memory: '256Mi' }, |
179 | | - }; |
180 | | - |
181 | | - renderResourceLimitsModal({ resource, validationSchema: resourceLimitsSchema }); |
182 | | - |
183 | | - const save = screen.getByRole('button', { name: 'Save' }); |
184 | | - expect(save).not.toBeDisabled(); |
185 | | - |
186 | | - const cpuRequest = screen.getByRole('spinbutton', { name: 'CPU request' }); |
187 | | - await user.click(cpuRequest); |
188 | | - await user.keyboard('{Control>}a{/Control}'); |
189 | | - await user.keyboard('300'); |
190 | | - |
191 | | - await waitFor(() => expect(save).toBeDisabled()); |
192 | | - expect( |
193 | | - await screen.findByText('CPU request must be less than or equal to limit.'), |
194 | | - ).toBeVisible(); |
195 | | - }); |
196 | | - |
197 | | - it('disables Save when Memory request is greater than Memory limit', async () => { |
198 | | - const user = userEvent.setup(); |
199 | | - const resource = baseDeployment(); |
200 | | - resource.spec.template.spec.containers[0].resources = { |
201 | | - requests: { cpu: '100m', memory: '128Mi' }, |
202 | | - limits: { cpu: '500m', memory: '256Mi' }, |
203 | | - }; |
204 | | - |
205 | | - renderResourceLimitsModal({ resource, validationSchema: resourceLimitsSchema }); |
206 | | - |
207 | | - const save = screen.getByRole('button', { name: 'Save' }); |
208 | | - const memoryRequest = screen.getByRole('spinbutton', { name: 'Memory request' }); |
209 | | - |
210 | | - await user.click(memoryRequest); |
211 | | - await user.keyboard('{Control>}a{/Control}'); |
212 | | - await user.keyboard('512'); |
213 | | - |
214 | | - await waitFor(() => expect(save).toBeDisabled()); |
215 | | - expect( |
216 | | - await screen.findByText('Memory request must be less than or equal to limit.'), |
217 | | - ).toBeVisible(); |
| 86 | + expect(formProps.handleSubmit).toHaveBeenCalledTimes(1); |
218 | 87 | }); |
219 | 88 | }); |
0 commit comments