11// spec: e2e/.agent-output/test-plan-admin-model-card.md
22// section: 5. Delete Model Card
33import { AdminModelCardPage } from '../utils/classes/AdminModelCardPage' ;
4- import { loginAsAdmin , webuiEndpoint } from '../utils/test-util' ;
4+ import {
5+ deleteForeverAndVerifyFromTrash ,
6+ loginAsAdmin ,
7+ moveToTrashAndVerify ,
8+ webuiEndpoint ,
9+ } from '../utils/test-util' ;
510import { test , expect } from '@playwright/test' ;
611
712test . describe (
@@ -18,13 +23,19 @@ test.describe(
1823 test ( 'Superadmin can delete a model card via the trash icon with confirmation' , async ( {
1924 page,
2025 } ) => {
26+ test . setTimeout ( 90000 ) ;
2127 const adminModelCardPage = new AdminModelCardPage ( page ) ;
22- const cardName = `e2e-test-delete-single-${ Date . now ( ) } ` ;
28+ const timestamp = Date . now ( ) ;
29+ const folderName = `e2e-test-delete-single-folder-${ timestamp } ` ;
30+ const cardName = `e2e-test-delete-single-${ timestamp } ` ;
2331
24- // Setup: create a model card to delete
32+ // Setup: create a dedicated folder and model card
2533 await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
2634 await adminModelCardPage . waitForTableLoad ( ) ;
27- await adminModelCardPage . createModelCard ( { name : cardName } ) ;
35+ await adminModelCardPage . createModelCard ( {
36+ name : cardName ,
37+ createNewFolderName : folderName ,
38+ } ) ;
2839
2940 // Navigate back and find the row
3041 await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
@@ -51,31 +62,46 @@ test.describe(
5162 await expect ( adminModelCardPage . getDeleteConfirmButton ( ) ) . toBeVisible ( ) ;
5263 await expect ( adminModelCardPage . getDeleteCancelButton ( ) ) . toBeVisible ( ) ;
5364
54- // Click Delete to confirm
65+ // The "Also delete folder" checkbox should be visible (card has an associated folder)
66+ await expect (
67+ adminModelCardPage . getAlsoDeleteFolderCheckbox ( ) ,
68+ ) . toBeVisible ( ) ;
69+
70+ // Click Delete to confirm (leave folder checkbox unchecked — folder cleanup handled separately)
5571 await adminModelCardPage . getDeleteConfirmButton ( ) . click ( ) ;
5672
5773 // Verify success message
58- await expect ( page . getByText ( ' Model card has been deleted.' ) ) . toBeVisible ( {
74+ await expect ( page . getByText ( / M o d e l c a r d h a s b e e n d e l e t e d / ) ) . toBeVisible ( {
5975 timeout : 15000 ,
6076 } ) ;
6177
6278 // Verify the row is no longer in the table
6379 await expect ( adminModelCardPage . getPaginationInfo ( ) ) . toContainText (
6480 '0 items' ,
6581 ) ;
82+
83+ // Cleanup: move folder to trash then permanently delete
84+ await moveToTrashAndVerify ( page , folderName , 'admin-data' ) ;
85+ await deleteForeverAndVerifyFromTrash ( page , folderName , 'admin-data' ) ;
6686 } ) ;
6787
6888 // 5.2 Superadmin can cancel a single-delete confirmation without deleting
6989 test ( 'Superadmin can cancel a single-delete confirmation without deleting' , async ( {
7090 page,
7191 } ) => {
92+ test . setTimeout ( 90000 ) ;
7293 const adminModelCardPage = new AdminModelCardPage ( page ) ;
73- const cardName = `e2e-test-no-delete-${ Date . now ( ) } ` ;
94+ const timestamp = Date . now ( ) ;
95+ const folderName = `e2e-test-no-delete-folder-${ timestamp } ` ;
96+ const cardName = `e2e-test-no-delete-${ timestamp } ` ;
7497
75- // Setup: create a model card to keep
98+ // Setup: create a dedicated folder and model card
7699 await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
77100 await adminModelCardPage . waitForTableLoad ( ) ;
78- await adminModelCardPage . createModelCard ( { name : cardName } ) ;
101+ await adminModelCardPage . createModelCard ( {
102+ name : cardName ,
103+ createNewFolderName : folderName ,
104+ } ) ;
79105
80106 // Navigate back and filter
81107 await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
@@ -94,34 +120,48 @@ test.describe(
94120 // Verify the model card is still in the table
95121 await expect ( adminModelCardPage . getRowByName ( cardName ) ) . toBeVisible ( ) ;
96122
97- // Cleanup: delete the test model card
123+ // Cleanup: delete card only, then move folder to trash and permanently delete
98124 await adminModelCardPage . deleteModelCardByName ( cardName ) ;
125+ await moveToTrashAndVerify ( page , folderName , 'admin-data' ) ;
126+ await deleteForeverAndVerifyFromTrash ( page , folderName , 'admin-data' ) ;
99127 } ) ;
100128
101129 // 5.3 Superadmin can select multiple model cards and delete them in bulk
102130 test ( 'Superadmin can select multiple model cards and delete them in bulk' , async ( {
103131 page,
104132 } ) => {
105- test . setTimeout ( 90000 ) ;
133+ test . setTimeout ( 120000 ) ;
106134 const adminModelCardPage = new AdminModelCardPage ( page ) ;
107135 const timestamp = Date . now ( ) ;
136+ const folderName = `e2e-test-bulk-delete-folder-${ timestamp } ` ;
108137 const filterPrefix = `e2e-test-bulk-delete-${ timestamp } ` ;
109138 const cardNames = [
110139 `${ filterPrefix } -1` ,
111140 `${ filterPrefix } -2` ,
112141 `${ filterPrefix } -3` ,
113142 ] ;
114143
115- // Setup: create three model cards
144+ // Setup: create a shared folder via the "+" button for the first card,
145+ // then reuse it for the remaining cards
116146 await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
117147 await adminModelCardPage . waitForTableLoad ( ) ;
118- for ( const name of cardNames ) {
119- await adminModelCardPage . createModelCard ( { name } ) ;
148+ await adminModelCardPage . createModelCard ( {
149+ name : cardNames [ 0 ] ,
150+ createNewFolderName : folderName ,
151+ } ) ;
152+
153+ for ( const name of cardNames . slice ( 1 ) ) {
120154 await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
121155 await adminModelCardPage . waitForTableLoad ( ) ;
156+ await adminModelCardPage . createModelCard ( {
157+ name,
158+ vfolderTitle : folderName ,
159+ } ) ;
122160 }
123161
124162 // Filter to show only this run's test cards (timestamp ensures uniqueness)
163+ await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
164+ await adminModelCardPage . waitForTableLoad ( ) ;
125165 await adminModelCardPage . applyNameFilter ( filterPrefix ) ;
126166 await expect ( adminModelCardPage . getDataRows ( ) . first ( ) ) . toBeVisible ( {
127167 timeout : 10000 ,
@@ -161,26 +201,41 @@ test.describe(
161201
162202 // Verify the selection label disappears
163203 await expect ( adminModelCardPage . getSelectionLabel ( ) ) . toBeHidden ( ) ;
204+
205+ // Cleanup: model cards were deleted but the shared folder remains;
206+ // move it to trash and permanently delete
207+ await moveToTrashAndVerify ( page , folderName , 'admin-data' ) ;
208+ await deleteForeverAndVerifyFromTrash ( page , folderName , 'admin-data' ) ;
164209 } ) ;
165210
166211 // 5.4 Superadmin can cancel bulk deletion
167212 test ( 'Superadmin can cancel bulk deletion' , async ( { page } ) => {
168- test . setTimeout ( 90000 ) ;
213+ test . setTimeout ( 120000 ) ;
169214 const adminModelCardPage = new AdminModelCardPage ( page ) ;
170215 const timestamp = Date . now ( ) ;
216+ const folderName = `e2e-test-bulk-cancel-folder-${ timestamp } ` ;
171217 const filterPrefix = `e2e-test-bulk-cancel-${ timestamp } ` ;
172218 const cardNames = [ `${ filterPrefix } -1` , `${ filterPrefix } -2` ] ;
173219
174- // Setup: create two model cards
220+ // Setup: create a shared folder via the "+" button for the first card,
221+ // then reuse it for the second card
175222 await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
176223 await adminModelCardPage . waitForTableLoad ( ) ;
177- for ( const name of cardNames ) {
178- await adminModelCardPage . createModelCard ( { name } ) ;
179- await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
180- await adminModelCardPage . waitForTableLoad ( ) ;
181- }
224+ await adminModelCardPage . createModelCard ( {
225+ name : cardNames [ 0 ] ,
226+ createNewFolderName : folderName ,
227+ } ) ;
228+
229+ await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
230+ await adminModelCardPage . waitForTableLoad ( ) ;
231+ await adminModelCardPage . createModelCard ( {
232+ name : cardNames [ 1 ] ,
233+ vfolderTitle : folderName ,
234+ } ) ;
182235
183236 // Filter to show only this run's test cards (timestamp ensures uniqueness)
237+ await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
238+ await adminModelCardPage . waitForTableLoad ( ) ;
184239 await adminModelCardPage . applyNameFilter ( filterPrefix ) ;
185240 await expect ( adminModelCardPage . getDataRows ( ) . first ( ) ) . toBeVisible ( {
186241 timeout : 10000 ,
@@ -210,10 +265,12 @@ test.describe(
210265 await expect ( adminModelCardPage . getRowByName ( name ) ) . toBeVisible ( ) ;
211266 }
212267
213- // Cleanup: delete the test model cards
268+ // Cleanup: delete each model card (card only), then clean up the shared folder
214269 for ( const name of cardNames ) {
215270 await adminModelCardPage . deleteModelCardByName ( name ) ;
216271 }
272+ await moveToTrashAndVerify ( page , folderName , 'admin-data' ) ;
273+ await deleteForeverAndVerifyFromTrash ( page , folderName , 'admin-data' ) ;
217274 } ) ;
218275
219276 // 5.5 Superadmin can clear selection using the BAISelectionLabel clear button
@@ -266,5 +323,133 @@ test.describe(
266323 `${ rowCount } selected` ,
267324 ) ;
268325 } ) ;
326+
327+ // 5.7 Superadmin can delete a model card and its associated folder together
328+ test ( 'Superadmin can delete a model card and its associated folder, and navigate to trash with folder filter' , async ( {
329+ page,
330+ } ) => {
331+ test . setTimeout ( 90000 ) ;
332+ const adminModelCardPage = new AdminModelCardPage ( page ) ;
333+ const timestamp = Date . now ( ) ;
334+ const folderName = `e2e-test-delete-folder-${ timestamp } ` ;
335+ const cardName = `e2e-test-delete-with-folder-${ timestamp } ` ;
336+
337+ // Create a model card with a new dedicated folder via the "+" button
338+ await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
339+ await adminModelCardPage . waitForTableLoad ( ) ;
340+ await adminModelCardPage . createModelCard ( {
341+ name : cardName ,
342+ createNewFolderName : folderName ,
343+ } ) ;
344+
345+ // Navigate back and filter for the created card
346+ await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
347+ await adminModelCardPage . waitForTableLoad ( ) ;
348+ await adminModelCardPage . applyNameFilter ( cardName ) ;
349+
350+ // Open the delete confirmation dialog
351+ await adminModelCardPage . clickDeleteForRow ( cardName ) ;
352+
353+ // Verify the "Also delete the associated model folder" checkbox is visible
354+ await expect (
355+ adminModelCardPage . getAlsoDeleteFolderCheckbox ( ) ,
356+ ) . toBeVisible ( ) ;
357+
358+ // Verify the folder link shows the expected folder name
359+ const folderLink = adminModelCardPage . getFolderNameLinkInDeleteDialog ( ) ;
360+ await expect ( folderLink ) . toBeVisible ( ) ;
361+ await expect ( folderLink ) . toHaveText ( folderName ) ;
362+
363+ // Check the "Also delete the associated model folder" checkbox
364+ await adminModelCardPage . getAlsoDeleteFolderCheckbox ( ) . check ( ) ;
365+ await expect (
366+ adminModelCardPage . getAlsoDeleteFolderCheckbox ( ) ,
367+ ) . toBeChecked ( ) ;
368+
369+ // Confirm deletion
370+ await adminModelCardPage . getDeleteConfirmButton ( ) . click ( ) ;
371+
372+ // Verify the success notification for card + folder deletion
373+ await expect (
374+ page . getByText ( 'Model card and folder have been moved to trash.' ) ,
375+ ) . toBeVisible ( { timeout : 15000 } ) ;
376+
377+ // Verify "Go to Data > Trash" link is visible in the notification
378+ const goToTrashLink = page . getByText ( 'Go to Data > Trash' ) ;
379+ await expect ( goToTrashLink ) . toBeVisible ( ) ;
380+
381+ // Click "Go to Data > Trash" and verify URL includes folder filter
382+ await goToTrashLink . click ( ) ;
383+ await page . waitForURL (
384+ ( url ) =>
385+ url . pathname === '/data' &&
386+ url . searchParams . get ( 'statusCategory' ) === 'deleted' &&
387+ url . searchParams . get ( 'filter' ) === `name == "${ folderName } "` ,
388+ { timeout : 10000 } ,
389+ ) ;
390+
391+ // Verify the folder row is visible in the trash list and permanently delete it
392+ await deleteForeverAndVerifyFromTrash ( page , folderName , 'admin-data' ) ;
393+ } ) ;
394+
395+ // 5.8 Superadmin deletes card only: notification shows correct message and Go to Trash navigates correctly
396+ test ( 'Superadmin can delete a model card only and navigate to trash without folder filter' , async ( {
397+ page,
398+ } ) => {
399+ test . setTimeout ( 90000 ) ;
400+ const adminModelCardPage = new AdminModelCardPage ( page ) ;
401+ const timestamp = Date . now ( ) ;
402+ const folderName = `e2e-test-keep-folder-${ timestamp } ` ;
403+ const cardName = `e2e-test-delete-card-only-${ timestamp } ` ;
404+
405+ // Create a model card with a new dedicated folder via the "+" button
406+ await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
407+ await adminModelCardPage . waitForTableLoad ( ) ;
408+ await adminModelCardPage . createModelCard ( {
409+ name : cardName ,
410+ createNewFolderName : folderName ,
411+ } ) ;
412+
413+ // Navigate back and filter
414+ await page . goto ( `${ webuiEndpoint } /admin-serving?tab=model-store` ) ;
415+ await adminModelCardPage . waitForTableLoad ( ) ;
416+ await adminModelCardPage . applyNameFilter ( cardName ) ;
417+
418+ // Open delete dialog
419+ await adminModelCardPage . clickDeleteForRow ( cardName ) ;
420+
421+ // Leave "Also delete folder" checkbox unchecked (default)
422+ await expect (
423+ adminModelCardPage . getAlsoDeleteFolderCheckbox ( ) ,
424+ ) . not . toBeChecked ( ) ;
425+
426+ // Confirm deletion
427+ await adminModelCardPage . getDeleteConfirmButton ( ) . click ( ) ;
428+
429+ // Verify the notification message for card-only deletion
430+ await expect (
431+ page . getByText (
432+ 'Model card has been deleted. The model folder was not deleted.' ,
433+ ) ,
434+ ) . toBeVisible ( { timeout : 15000 } ) ;
435+
436+ // Verify "Go to Data > Trash" link is visible
437+ const goToTrashLink = page . getByText ( 'Go to Data > Trash' ) ;
438+ await expect ( goToTrashLink ) . toBeVisible ( ) ;
439+
440+ // Click "Go to Data > Trash" and verify URL (no folder filter)
441+ await goToTrashLink . click ( ) ;
442+ await page . waitForURL (
443+ ( url ) =>
444+ url . pathname === '/data' &&
445+ url . searchParams . get ( 'statusCategory' ) === 'deleted' &&
446+ ! url . searchParams . has ( 'filter' ) ,
447+ { timeout : 10000 } ,
448+ ) ;
449+
450+ // Cleanup: move the kept test folder to trash then permanently delete it
451+ await moveToTrashAndVerify ( page , folderName , 'admin-data' ) ;
452+ await deleteForeverAndVerifyFromTrash ( page , folderName , 'admin-data' ) ;
453+ } ) ;
269454 } ,
270455) ;
0 commit comments