11import  {  faker  }  from  "@faker-js/faker/locale/en" 
22import  {  factories ,  urls ,  makeRequest  }  from  "api/test-utils" 
3- import  type  { 
4-   LearningPathResource , 
5-   PaginatedLearningResourceTopicList , 
3+ import  { 
4+   PrivacyLevelEnum , 
5+   type  LearningPathResource , 
6+   type  PaginatedLearningResourceTopicList , 
7+   type  UserList , 
68}  from  "api" 
79import  {  allowConsoleErrors ,  getDescriptionFor  }  from  "ol-test-utilities" 
8- import  {  manageLearningPathDialogs  }  from  "./ManageListDialogs" 
10+ import  {  manageListDialogs  }  from  "./ManageListDialogs" 
911import  { 
1012  screen , 
1113  renderWithProviders , 
@@ -39,6 +41,11 @@ const inputs = {
3941    const  element  =  screen . getByLabelText ( value  ? "Public"  : "Private" ) 
4042    return  element  as  HTMLInputElement 
4143  } , 
44+   privacy_level : ( value ?: string )  =>  { 
45+     invariant ( value  !==  undefined ) 
46+     const  element  =  screen . getByDisplayValue ( value ) 
47+     return  element  as  HTMLInputElement 
48+   } , 
4249  title : ( )  =>  screen . getByLabelText ( "Title" ,  {  exact : false  } ) , 
4350  description : ( )  =>  screen . getByLabelText ( "Description" ,  {  exact : false  } ) , 
4451  topics : ( )  =>  screen . getByLabelText ( "Subjects" ,  {  exact : false  } ) , 
@@ -47,7 +54,7 @@ const inputs = {
4754  delete : ( )  =>  screen . getByRole ( "button" ,  {  name : "Yes, delete"  } ) , 
4855} 
4956
50- describe ( "manageListDialogs.upsert " ,  ( )  =>  { 
57+ describe ( "manageListDialogs.upsertLearningPath " ,  ( )  =>  { 
5158  const  setup  =  ( { 
5259    resource, 
5360    topics =  factories . learningResources . topics ( {  count : 10  } ) , 
@@ -70,7 +77,7 @@ describe("manageListDialogs.upsert", () => {
7077    renderWithProviders ( null ,  opts ) 
7178
7279    act ( ( )  =>  { 
73-       manageLearningPathDialogs . upsert ( resource ) 
80+       manageListDialogs . upsertLearningPath ( resource ) 
7481    } ) 
7582
7683    return  {  topics } 
@@ -211,12 +218,145 @@ describe("manageListDialogs.upsert", () => {
211218  } ) 
212219} ) 
213220
214- describe ( "manageListDialogs.destroy" ,  ( )  =>  { 
221+ describe ( "manageListDialogs.upsertUserList" ,  ( )  =>  { 
222+   const  setup  =  ( { 
223+     userList, 
224+     opts =  { 
225+       user : {  is_authenticated : true  } , 
226+     } , 
227+   } : { 
228+     userList ?: UserList 
229+     opts ?: Partial < TestAppOptions > 
230+   }  =  { } )  =>  { 
231+     renderWithProviders ( null ,  opts ) 
232+ 
233+     act ( ( )  =>  { 
234+       manageListDialogs . upsertUserList ( userList ) 
235+     } ) 
236+   } 
237+ 
238+   test . each ( [ 
239+     { 
240+       userList : undefined , 
241+       expectedTitle : "Create User List" , 
242+     } , 
243+     { 
244+       userList : factories . userLists . userList ( ) , 
245+       expectedTitle : "Edit User List" , 
246+     } , 
247+   ] ) ( 
248+     "Dialog title is $expectedTitle when userList=$userList" , 
249+     async  ( {  userList,  expectedTitle } )  =>  { 
250+       setup ( {  userList } ) 
251+       const  dialog  =  screen . getByRole ( "heading" ,  {  name : expectedTitle  } ) 
252+       expect ( dialog ) . toBeVisible ( ) 
253+     } , 
254+   ) 
255+ 
256+   test ( "'Cancel' closes dialog (and does not make request)" ,  async  ( )  =>  { 
257+     // behavior does not depend on stafflist / userlist, so just pick one 
258+     setup ( { 
259+       userList : factories . userLists . userList ( ) , 
260+     } ) 
261+     const  dialog  =  screen . getByRole ( "dialog" ) 
262+     await  user . click ( inputs . cancel ( ) ) 
263+     expect ( makeRequest ) . not . toHaveBeenCalledWith ( 
264+       "patch" , 
265+       expect . anything ( ) , 
266+       expect . anything ( ) , 
267+     ) 
268+     await  waitForElementToBeRemoved ( dialog ) 
269+   } ) 
270+ 
271+   test ( "Validates required fields" ,  async  ( )  =>  { 
272+     setup ( ) 
273+     await  user . click ( inputs . submit ( ) ) 
274+ 
275+     const  titleInput  =  inputs . title ( ) 
276+     const  titleFeedback  =  getDescriptionFor ( titleInput ) 
277+     expect ( titleInput ) . toBeInvalid ( ) 
278+     expect ( titleFeedback ) . toHaveTextContent ( "Title is required." ) 
279+ 
280+     const  descriptionInput  =  inputs . description ( ) 
281+     const  descriptionFeedback  =  getDescriptionFor ( descriptionInput ) 
282+     expect ( descriptionInput ) . toBeInvalid ( ) 
283+     expect ( descriptionFeedback ) . toHaveTextContent ( "Description is required." ) 
284+   } ) 
285+ 
286+   test ( "Form defaults are set" ,  ( )  =>  { 
287+     setup ( ) 
288+     expect ( inputs . title ( ) ) . toHaveValue ( "" ) 
289+     expect ( inputs . description ( ) ) . toHaveValue ( "" ) 
290+     expect ( inputs . privacy_level ( PrivacyLevelEnum . Private ) . checked ) . toBe ( true ) 
291+     expect ( inputs . privacy_level ( PrivacyLevelEnum . Unlisted ) . checked ) . toBe ( false ) 
292+   } ) 
293+ 
294+   test ( "Editing form values" ,  async  ( )  =>  { 
295+     const  userList  =  factories . userLists . userList ( ) 
296+     setup ( {  userList : userList  } ) 
297+     const  patch  =  { 
298+       title : faker . lorem . words ( ) , 
299+       description : faker . lorem . paragraph ( ) , 
300+       privacy_level : PrivacyLevelEnum . Unlisted , 
301+     } 
302+ 
303+     // Title 
304+     expect ( inputs . title ( ) ) . toHaveValue ( userList . title ) 
305+     await  user . click ( inputs . title ( ) ) 
306+     await  user . clear ( inputs . title ( ) ) 
307+     await  user . paste ( patch . title ) 
308+ 
309+     // Description 
310+     expect ( inputs . description ( ) ) . toHaveValue ( userList . description ) 
311+     await  user . click ( inputs . description ( ) ) 
312+     await  user . clear ( inputs . description ( ) ) 
313+     await  user . paste ( patch . description ) 
314+ 
315+     // Privacy Level 
316+     expect ( inputs . privacy_level ( PrivacyLevelEnum . Private ) . checked ) . toBe ( true ) 
317+     expect ( inputs . privacy_level ( PrivacyLevelEnum . Unlisted ) . checked ) . toBe ( false ) 
318+     await  user . click ( inputs . privacy_level ( patch . privacy_level ) ) 
319+ 
320+     // Submit 
321+     const  patchUrl  =  urls . userLists . details ( {  id : userList . id  } ) 
322+     setMockResponse . patch ( patchUrl ,  {  ...userList ,  ...patch  } ) 
323+     await  user . click ( inputs . submit ( ) ) 
324+ 
325+     expect ( makeRequest ) . toHaveBeenCalledWith ( 
326+       "patch" , 
327+       patchUrl , 
328+       expect . objectContaining ( {  ...patch  } ) , 
329+     ) 
330+   } ) 
331+ 
332+   test ( "Displays overall error if form validates but API call fails" ,  async  ( )  =>  { 
333+     allowConsoleErrors ( ) 
334+     const  userList  =  factories . userLists . userList ( ) 
335+     await  setup ( {  userList : userList  } ) 
336+ 
337+     const  patchUrl  =  urls . userLists . details ( {  id : userList . id  } ) 
338+     setMockResponse . patch ( patchUrl ,  { } ,  {  code : 408  } ) 
339+     await  user . click ( inputs . submit ( ) ) 
340+ 
341+     expect ( makeRequest ) . toHaveBeenCalledWith ( 
342+       "patch" , 
343+       patchUrl , 
344+       expect . anything ( ) , 
345+     ) 
346+     const  alertMessage  =  await  screen . findByRole ( "alert" ) 
347+ 
348+     expect ( alertMessage ) . toHaveTextContent ( 
349+       "There was a problem saving your list." , 
350+     ) 
351+   } ) 
352+ } ) 
353+ 
354+ describe ( "manageListDialogs.destroyLearningPath" ,  ( )  =>  { 
215355  const  setup  =  ( )  =>  { 
216356    const  resource  =  factories . learningResources . learningPath ( ) 
217357    renderWithProviders ( null ) 
218358    act ( ( )  =>  { 
219-       manageLearningPathDialogs . destroy ( resource ) 
359+       manageListDialogs . destroyLearningPath ( resource ) 
220360    } ) 
221361    return  {  resource } 
222362  } 
@@ -249,3 +389,42 @@ describe("manageListDialogs.destroy", () => {
249389    await  waitForElementToBeRemoved ( dialog ) 
250390  } ) 
251391} ) 
392+ 
393+ describe ( "manageListDialogs.destroyUserList" ,  ( )  =>  { 
394+   const  setup  =  ( )  =>  { 
395+     const  userList  =  factories . userLists . userList ( ) 
396+     renderWithProviders ( null ) 
397+     act ( ( )  =>  { 
398+       manageListDialogs . destroyUserList ( userList ) 
399+     } ) 
400+     return  {  userList : userList  } 
401+   } 
402+ 
403+   test ( "Dialog title is 'Delete list'" ,  async  ( )  =>  { 
404+     setup ( ) 
405+     const  dialog  =  screen . getByRole ( "heading" ,  {  name : "Delete User List"  } ) 
406+     expect ( dialog ) . toBeVisible ( ) 
407+   } ) 
408+ 
409+   test ( "Deleting a $label calls correct API" ,  async  ( )  =>  { 
410+     const  {  userList }  =  setup ( ) 
411+ 
412+     const  dialog  =  screen . getByRole ( "dialog" ) 
413+     const  url  =  urls . userLists . details ( {  id : userList . id  } ) 
414+     setMockResponse . delete ( url ,  undefined ) 
415+     await  user . click ( inputs . delete ( ) ) 
416+ 
417+     expect ( makeRequest ) . toHaveBeenCalledWith ( "delete" ,  url ,  undefined ) 
418+     await  waitForElementToBeRemoved ( dialog ) 
419+   } ) 
420+ 
421+   test ( "Clicking cancel does not delete list" ,  async  ( )  =>  { 
422+     setup ( ) 
423+ 
424+     const  dialog  =  screen . getByRole ( "dialog" ) 
425+     await  user . click ( inputs . cancel ( ) ) 
426+ 
427+     expect ( makeRequest ) . not . toHaveBeenCalled ( ) 
428+     await  waitForElementToBeRemoved ( dialog ) 
429+   } ) 
430+ } ) 
0 commit comments