@@ -10,7 +10,6 @@ import { faker } from '@faker-js/faker';
1010import { waitFor } from '@testing-library/react' ;
1111
1212import { NodeDetailsDescription } from './NodeDetailsDescription' ;
13- import { ICON_REGEXP } from '../../constants/test' ;
1413import { populateFile } from '../../mocks/mockUtils' ;
1514import { generateError , setup , screen } from '../../tests/utils' ;
1615import { Resolvers } from '../../types/graphql/resolvers-types' ;
@@ -19,7 +18,7 @@ import { canUpsertDescription } from '../../utils/ActionsFactory';
1918import { mockErrorResolver , mockUpdateNode } from '../../utils/resolverMocks' ;
2019
2120describe ( 'NodeDetailsDescription component' , ( ) => {
22- test ( 'Missing description show missing description label ', ( ) => {
21+ it ( 'should render description section ', ( ) => {
2322 const node = populateFile ( ) ;
2423 node . permissions . can_write_file = true ;
2524 node . description = '' ;
@@ -31,11 +30,12 @@ describe('NodeDetailsDescription component', () => {
3130 /> ,
3231 { mocks : { } }
3332 ) ;
34- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
35- expect ( screen . getByText ( 'Click the edit button to add a description' ) ) . toBeInTheDocument ( ) ;
33+
34+ expect ( screen . getAllByText ( 'Description' ) [ 0 ] ) . toBeVisible ( ) ;
35+ expect ( screen . getByRole ( 'textbox' , { name : 'Description' } ) ) . toBeVisible ( ) ;
3636 } ) ;
3737
38- test ( 'Missing description is not shown if description cannot be edited', ( ) => {
38+ it ( 'should render TextArea as readOnly when description cannot be edited', ( ) => {
3939 const node = populateFile ( ) ;
4040 node . permissions . can_write_file = false ;
4141 node . description = '' ;
@@ -47,15 +47,13 @@ describe('NodeDetailsDescription component', () => {
4747 /> ,
4848 { mocks : { } }
4949 ) ;
50- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
51- expect (
52- screen . queryByText ( 'Click the edit button to add a description' )
53- ) . not . toBeInTheDocument ( ) ;
50+
51+ expect ( screen . getByRole ( 'textbox' ) ) . toHaveAttribute ( 'readonly' ) ;
5452 } ) ;
5553
56- test ( 'Edit icon disabled if can_write_file is false ', ( ) => {
54+ it ( 'should render TextArea as editable when can_write_file is true ', ( ) => {
5755 const node = populateFile ( ) ;
58- node . permissions . can_write_file = false ;
56+ node . permissions . can_write_file = true ;
5957 setup (
6058 < NodeDetailsDescription
6159 id = { node . id }
@@ -64,35 +62,50 @@ describe('NodeDetailsDescription component', () => {
6462 /> ,
6563 { mocks : { } }
6664 ) ;
67- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
6865
69- const editIcon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
70- expect ( editIcon ) . toBeVisible ( ) ;
71- expect ( editIcon ) . toBeDisabled ( ) ;
66+ expect ( screen . getByRole ( 'textbox' ) ) . not . toHaveAttribute ( 'readonly' ) ;
7267 } ) ;
7368
74- test ( 'Edit icon not disabled if can_write_file is true' , ( ) => {
69+ it ( 'should show Cancel and Save buttons only when description changes and hide them when restored to original' , async ( ) => {
7570 const node = populateFile ( ) ;
7671 node . permissions . can_write_file = true ;
77- setup (
72+ const newDescription = 'newDescription' ;
73+
74+ const { user } = setup (
7875 < NodeDetailsDescription
7976 id = { node . id }
8077 description = { node . description }
8178 canUpsertDescription = { canUpsertDescription ( { nodes : [ node ] } ) }
8279 /> ,
8380 { mocks : { } }
8481 ) ;
85- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
8682
87- const editIcon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
88- expect ( editIcon ) . toBeVisible ( ) ;
89- expect ( editIcon ) . toBeEnabled ( ) ;
83+ expect ( screen . queryByRole ( 'button' , { name : / c a n c e l / i } ) ) . not . toBeInTheDocument ( ) ;
84+ expect ( screen . queryByRole ( 'button' , { name : / s a v e / i } ) ) . not . toBeInTheDocument ( ) ;
85+
86+ const inputField = screen . getByRole ( 'textbox' ) ;
87+ await user . clear ( inputField ) ;
88+ await user . type ( inputField , newDescription ) ;
89+
90+ const saveButton = screen . getByRole ( 'button' , { name : / s a v e / i } ) ;
91+ expect ( saveButton ) . toBeVisible ( ) ;
92+ expect ( saveButton ) . toBeEnabled ( ) ;
93+ expect ( screen . getByRole ( 'button' , { name : / c a n c e l / i } ) ) . toBeVisible ( ) ;
94+
95+ await user . clear ( inputField ) ;
96+ await user . type ( inputField , node . description ) ;
97+
98+ expect ( screen . queryByRole ( 'button' , { name : / s a v e / i } ) ) . not . toBeInTheDocument ( ) ;
99+ expect ( screen . queryByRole ( 'button' , { name : / c a n c e l / i } ) ) . not . toBeInTheDocument ( ) ;
90100 } ) ;
91101
92- test ( 'save button is disabled when description is the same ', async ( ) => {
102+ it ( 'should disable Save button when description has more than 1024 characters ', async ( ) => {
93103 const node = populateFile ( ) ;
94104 node . permissions . can_write_file = true ;
95105 const newDescription = 'newDescription' ;
106+ const moreThan1024Description = faker . string . sample ( 2000 ) ;
107+
108+ expect ( moreThan1024Description . length ) . toBeGreaterThan ( 1024 ) ;
96109
97110 const { user } = setup (
98111 < NodeDetailsDescription
@@ -102,37 +115,24 @@ describe('NodeDetailsDescription component', () => {
102115 /> ,
103116 { mocks : { } }
104117 ) ;
105- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
106- expect ( screen . getByText ( node . description ) ) . toBeInTheDocument ( ) ;
107-
108- const editIcon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
109- expect ( editIcon ) . toBeVisible ( ) ;
110- expect ( editIcon ) . toBeEnabled ( ) ;
111- await user . click ( editIcon ) ;
112-
113- const saveIcon = await screen . findByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . save } ) ;
114- expect ( saveIcon ) . toBeVisible ( ) ;
115- expect ( saveIcon ) . toBeDisabled ( ) ;
116118
117119 const inputField = screen . getByRole ( 'textbox' ) ;
118120 await user . clear ( inputField ) ;
119121 await user . type ( inputField , newDescription ) ;
120122
121- expect ( saveIcon ) . toBeEnabled ( ) ;
123+ const saveButton = screen . getByRole ( 'button' , { name : / s a v e / i } ) ;
124+ expect ( saveButton ) . toBeEnabled ( ) ;
122125
123126 await user . clear ( inputField ) ;
124- await user . type ( inputField , node . description ) ;
127+ await user . paste ( moreThan1024Description ) ;
125128
126- expect ( saveIcon ) . toBeDisabled ( ) ;
129+ expect ( saveButton ) . toBeDisabled ( ) ;
127130 } ) ;
128131
129- test ( 'save button is disabled when description has more than 4096 characters ', async ( ) => {
132+ it ( 'should render "Maximum length allowed is 1024 characters" text when textarea is focused ', async ( ) => {
130133 const node = populateFile ( ) ;
131134 node . permissions . can_write_file = true ;
132- const newDescription = 'newDescription' ;
133- const moreThan4096Description = faker . string . sample ( 5000 ) ;
134-
135- expect ( moreThan4096Description . length ) . toBeGreaterThan ( 4096 ) ;
135+ node . description = '' ;
136136
137137 const { user } = setup (
138138 < NodeDetailsDescription
@@ -142,31 +142,25 @@ describe('NodeDetailsDescription component', () => {
142142 /> ,
143143 { mocks : { } }
144144 ) ;
145- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
146- expect ( screen . getByText ( node . description ) ) . toBeInTheDocument ( ) ;
147145
148- const editIcon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
149- expect ( editIcon ) . toBeVisible ( ) ;
150- expect ( editIcon ) . toBeEnabled ( ) ;
151- await user . click ( editIcon ) ;
146+ const inputField = screen . getByRole ( 'textbox' , { name : 'Description' } ) ;
152147
153- const saveIcon = await screen . findByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . save } ) ;
154- expect ( saveIcon ) . toBeVisible ( ) ;
155- expect ( saveIcon ) . toBeDisabled ( ) ;
148+ expect (
149+ screen . queryByText ( / m a x i m u m l e n g t h a l l o w e d i s 1 0 2 4 c h a r a c t e r s / i )
150+ ) . not . toBeInTheDocument ( ) ;
156151
157- const inputField = screen . getByRole ( 'textbox' ) ;
158- await user . clear ( inputField ) ;
159- await user . type ( inputField , newDescription ) ;
152+ await user . click ( inputField ) ;
160153
161- expect ( saveIcon ) . toBeEnabled ( ) ;
154+ expect ( screen . getByText ( / m a x i m u m l e n g t h a l l o w e d i s 1 0 2 4 c h a r a c t e r s / i ) ) . toBeVisible ( ) ;
162155
163- await user . clear ( inputField ) ;
164- await user . paste ( moreThan4096Description ) ;
156+ await user . tab ( ) ;
165157
166- expect ( saveIcon ) . toBeDisabled ( ) ;
158+ expect (
159+ screen . queryByText ( / m a x i m u m l e n g t h a l l o w e d i s 1 0 2 4 c h a r a c t e r s / i)
160+ ) . not . toBeInTheDocument ( ) ;
167161 } ) ;
168162
169- test ( 'close button do not save changes ', async ( ) => {
163+ it ( 'should discard changes and restore original value when Cancel button is clicked ', async ( ) => {
170164 const node = populateFile ( ) ;
171165 node . permissions . can_write_file = true ;
172166 const newDescription = 'newDescription' ;
@@ -179,42 +173,25 @@ describe('NodeDetailsDescription component', () => {
179173 /> ,
180174 { mocks : { } }
181175 ) ;
182- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
183- expect ( screen . getByText ( node . description ) ) . toBeInTheDocument ( ) ;
184-
185- let editIcon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
186- expect ( editIcon ) . toBeVisible ( ) ;
187- expect ( editIcon ) . toBeEnabled ( ) ;
188- await user . click ( editIcon ) ;
189176
190- const saveIcon = await screen . findByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . save } ) ;
191- expect ( saveIcon ) . toBeVisible ( ) ;
192- expect ( saveIcon ) . toBeDisabled ( ) ;
177+ const inputField = screen . getByRole ( 'textbox' ) ;
178+ expect ( inputField ) . toHaveValue ( node . description ) ;
193179
194- let inputField = screen . getByRole ( 'textbox' ) ;
195180 await user . clear ( inputField ) ;
196181 await user . type ( inputField , newDescription ) ;
197182
198183 expect ( inputField ) . toHaveValue ( newDescription ) ;
199184
200- expect ( saveIcon ) . toBeEnabled ( ) ;
201-
202- const closeICon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . close } ) ;
203- expect ( closeICon ) . toBeVisible ( ) ;
204- await user . click ( closeICon ) ;
205-
206- editIcon = await screen . findByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
207- expect ( editIcon ) . toBeVisible ( ) ;
208- expect ( screen . getByText ( node . description ) ) . toBeInTheDocument ( ) ;
209-
210- await user . click ( editIcon ) ;
211-
212- inputField = screen . getByRole ( 'textbox' ) ;
185+ const cancelButton = screen . getByRole ( 'button' , { name : / c a n c e l / i } ) ;
186+ await user . click ( cancelButton ) ;
213187
188+ // Value restored, buttons gone
214189 expect ( inputField ) . toHaveValue ( node . description ) ;
190+ expect ( screen . queryByRole ( 'button' , { name : / c a n c e l / i } ) ) . not . toBeInTheDocument ( ) ;
191+ expect ( screen . queryByRole ( 'button' , { name : / s a v e / i } ) ) . not . toBeInTheDocument ( ) ;
215192 } ) ;
216193
217- test ( 'save button close editing mode and call mutation ', async ( ) => {
194+ it ( 'should call mutation when Save button is clicked ', async ( ) => {
218195 const node = populateFile ( ) ;
219196 node . permissions . can_write_file = true ;
220197 const newDescription = 'newDescription' ;
@@ -238,38 +215,23 @@ describe('NodeDetailsDescription component', () => {
238215 /> ,
239216 { mocks }
240217 ) ;
241- expect ( screen . getByText ( 'Description' ) ) . toBeInTheDocument ( ) ;
242- expect ( screen . getByText ( node . description ) ) . toBeInTheDocument ( ) ;
243-
244- let editIcon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
245- expect ( editIcon ) . toBeVisible ( ) ;
246- expect ( editIcon ) . toBeEnabled ( ) ;
247- await user . click ( editIcon ) ;
248-
249- const saveIcon = await screen . findByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . save } ) ;
250- expect ( saveIcon ) . toBeVisible ( ) ;
251- expect ( saveIcon ) . toBeDisabled ( ) ;
252218
253219 const inputField = screen . getByRole ( 'textbox' ) ;
254220 await user . clear ( inputField ) ;
255221 await user . type ( inputField , newDescription ) ;
256222
257223 expect ( inputField ) . toHaveValue ( newDescription ) ;
258224
259- expect ( saveIcon ) . toBeEnabled ( ) ;
225+ const saveButton = screen . getByRole ( 'button' , { name : / s a v e / i } ) ;
226+ expect ( saveButton ) . toBeEnabled ( ) ;
260227
261- await user . click ( saveIcon ) ;
262-
263- editIcon = await screen . findByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
264- expect ( editIcon ) . toBeVisible ( ) ;
265-
266- expect ( saveIcon ) . not . toBeVisible ( ) ;
228+ await user . click ( saveButton ) ;
267229
268230 await waitFor ( ( ) => expect ( mocks . Mutation . updateNode ) . toHaveBeenCalled ( ) ) ;
269231 expect ( mocks . Mutation . updateNode ) . toHaveBeenCalledTimes ( 1 ) ;
270232 } ) ;
271233
272- test ( 'if save operation throws an error, description input field is shown with last description typed ', async ( ) => {
234+ it ( 'should keep description textarea visible with last typed value if save operation throws an error ', async ( ) => {
273235 const node = populateFile ( ) ;
274236 node . permissions . can_write_file = true ;
275237 const newDescription = 'newDescription' ;
@@ -286,28 +248,19 @@ describe('NodeDetailsDescription component', () => {
286248 /> ,
287249 { mocks }
288250 ) ;
289- expect ( screen . getByText ( / d e s c r i p t i o n / i) ) . toBeVisible ( ) ;
290- expect ( screen . getByText ( node . description ) ) . toBeVisible ( ) ;
291-
292- const editIcon = screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } ) ;
293- expect ( editIcon ) . toBeVisible ( ) ;
294- await user . click ( editIcon ) ;
295- const saveIcon = await screen . findByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . save } ) ;
296- expect ( saveIcon ) . toBeVisible ( ) ;
297- const inputField = screen . getByRole ( 'textbox' , {
298- name : / m a x i m u m l e n g t h a l l o w e d i s 4 0 9 6 c h a r a c t e r s / i
299- } ) ;
251+ expect ( screen . getAllByText ( 'Description' ) [ 0 ] ) . toBeVisible ( ) ;
252+
253+ const inputField = screen . getByRole ( 'textbox' ) ;
300254 await user . clear ( inputField ) ;
301255 await user . type ( inputField , newDescription ) ;
302- await user . click ( saveIcon ) ;
256+
257+ const saveButton = screen . getByRole ( 'button' , { name : / s a v e / i } ) ;
258+ await user . click ( saveButton ) ;
259+
303260 await screen . findByText ( / u p d a t e d e s c r i p t i o n e r r o r / i) ;
304261
305- expect (
306- screen . getByRole ( 'textbox' , { name : / m a x i m u m l e n g t h a l l o w e d i s 4 0 9 6 c h a r a c t e r s / i } )
307- ) . toBeVisible ( ) ;
308- expect ( screen . getByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . save } ) ) . toBeVisible ( ) ;
309- expect (
310- screen . queryByRoleWithIcon ( 'button' , { icon : ICON_REGEXP . edit } )
311- ) . not . toBeInTheDocument ( ) ;
262+ // TextArea still visible with the typed value
263+ expect ( screen . getByRole ( 'textbox' ) ) . toBeVisible ( ) ;
264+ expect ( screen . getByRole ( 'textbox' ) ) . toHaveValue ( newDescription ) ;
312265 } ) ;
313266} ) ;
0 commit comments