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