Skip to content

Commit b9c18ca

Browse files
committed
test(FR-2652): add E2E tests for admin model card deletion with folder option
- Add tests 5.7 and 5.8 to admin-model-card-delete.spec.ts - 5.7: delete model card + folder together, verify notification and Go to Trash URL with folder filter - 5.8: delete model card only, verify notification and Go to Trash URL without filter - Add getAlsoDeleteFolderCheckbox() and getFolderNameLinkInDeleteDialog() to AdminModelCardPage POM - Update E2E_COVERAGE_REPORT.md: Admin Model Store 22→26 features covered
1 parent 444c84b commit b9c18ca

3 files changed

Lines changed: 153 additions & 6 deletions

File tree

e2e/E2E_COVERAGE_REPORT.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# E2E Test Coverage Report
22

3-
> **Last Updated:** 2026-04-13
3+
> **Last Updated:** 2026-04-22
44
> **Router Source:** [`react/src/routes.tsx`](../react/src/routes.tsx)
55
> **E2E Root:** [`e2e/`](.)
66
>
@@ -12,7 +12,7 @@
1212

1313
**Scope:** Coverage metrics apply only to the routes listed below and do **not** include all entries from `react/src/routes.tsx`. Routes such as `/admin-dashboard` (not yet exposed in menu) and `/ai-agent` (experimental) are currently out of scope.
1414

15-
**Overall (in-scope routes): 261 / 408 features covered (64%)**
15+
**Overall (in-scope routes): 265 / 412 features covered (64%)**
1616

1717
| Page | Route | Features | Covered | Status |
1818
|------|-------|:--------:|:-------:|:------:|
@@ -27,7 +27,7 @@
2727
| Service Launcher | `/service/start` | 5 | 0 | ❌ 0% |
2828
| VFolder / Data | `/data` | 45 | 32 | 🔶 71% |
2929
| Model Store | `/model-store` | 6 | 6 | ✅ 100% |
30-
| Admin Model Store | `/admin-model-store` | 22 | 22 | ✅ 100% |
30+
| Admin Model Store | `/admin-model-store` | 26 | 26 | ✅ 100% |
3131
| Storage Host | `/storage-settings/:hostname` | 3 | 0 | ❌ 0% |
3232
| My Environment | `/my-environment` | 2 | 2 | ✅ 100% |
3333
| Environment | `/environment` | 27 | 21 | 🔶 78% |
@@ -47,7 +47,7 @@
4747
| Chat | `/chat/:id?` | 6 | 6 | ✅ 100% |
4848
| Plugin System | (config-based) | 12 | 12 | ✅ 100% |
4949
| RBAC Management | `/rbac` | 22 | 21 | 🔶 95% |
50-
| **Total** | | **408** | **261** | **64%** |
50+
| **Total** | | **412** | **265** | **64%** |
5151

5252
---
5353

@@ -420,14 +420,18 @@
420420
| Cancel edit modal || `admin-model-card-edit.spec.ts` |
421421
| Single delete with confirmation || `admin-model-card-delete.spec.ts` |
422422
| Cancel single delete || `admin-model-card-delete.spec.ts` |
423+
| Delete card + folder together (checkbox) || `admin-model-card-delete.spec.ts` |
424+
| Notification + Go to Trash with folder filter || `admin-model-card-delete.spec.ts` |
425+
| Delete card only, folder kept notification || `admin-model-card-delete.spec.ts` |
426+
| Go to Trash without folder filter || `admin-model-card-delete.spec.ts` |
423427
| Bulk select and delete || `admin-model-card-delete.spec.ts` |
424428
| Cancel bulk delete || `admin-model-card-delete.spec.ts` |
425429
| Clear selection || `admin-model-card-delete.spec.ts` |
426430
| Select all via header checkbox || `admin-model-card-delete.spec.ts` |
427431
| Non-admin access blocked || `admin-model-card-access-control.spec.ts` |
428432
| URL state persistence (filter/sort/pagination) || `admin-model-card-url-state.spec.ts` |
429433

430-
**Coverage: ✅ 22/22 features**
434+
**Coverage: ✅ 26/26 features**
431435

432436
---
433437

e2e/admin-model-card/admin-model-card-delete.spec.ts

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
// spec: e2e/.agent-output/test-plan-admin-model-card.md
22
// section: 5. Delete Model Card
33
import { AdminModelCardPage } from '../utils/classes/AdminModelCardPage';
4-
import { loginAsAdmin, webuiEndpoint } from '../utils/test-util';
4+
import {
5+
createVFolderAndVerify,
6+
loginAsAdmin,
7+
moveToTrashAndVerify,
8+
webuiEndpoint,
9+
} from '../utils/test-util';
510
import { test, expect } from '@playwright/test';
611

712
test.describe(
@@ -266,5 +271,135 @@ test.describe(
266271
`${rowCount} selected`,
267272
);
268273
});
274+
275+
// 5.7 Superadmin can delete a model card and its associated folder together
276+
test('Superadmin can delete a model card and its associated folder, and navigate to trash with folder filter', async ({
277+
page,
278+
}) => {
279+
test.setTimeout(90000);
280+
const adminModelCardPage = new AdminModelCardPage(page);
281+
const timestamp = Date.now();
282+
const folderName = `e2e-test-delete-folder-${timestamp}`;
283+
const cardName = `e2e-test-delete-with-folder-${timestamp}`;
284+
285+
// Setup: create a dedicated test VFolder to avoid affecting real folders
286+
await createVFolderAndVerify(page, folderName, 'model');
287+
288+
// Create a model card linked to the dedicated test folder
289+
await page.goto(`${webuiEndpoint}/admin-serving?tab=model-store`);
290+
await adminModelCardPage.waitForTableLoad();
291+
await adminModelCardPage.createModelCard({
292+
name: cardName,
293+
vfolderTitle: folderName,
294+
});
295+
296+
// Navigate back and filter for the created card
297+
await page.goto(`${webuiEndpoint}/admin-serving?tab=model-store`);
298+
await adminModelCardPage.waitForTableLoad();
299+
await adminModelCardPage.applyNameFilter(cardName);
300+
301+
// Open the delete confirmation dialog
302+
await adminModelCardPage.clickDeleteForRow(cardName);
303+
304+
// Verify the "Also delete the associated model folder" checkbox is visible
305+
await expect(
306+
adminModelCardPage.getAlsoDeleteFolderCheckbox(),
307+
).toBeVisible();
308+
309+
// Verify the folder link shows the expected folder name
310+
const folderLink = adminModelCardPage.getFolderNameLinkInDeleteDialog();
311+
await expect(folderLink).toBeVisible();
312+
await expect(folderLink).toHaveText(folderName);
313+
314+
// Check the "Also delete the associated model folder" checkbox
315+
await adminModelCardPage.getAlsoDeleteFolderCheckbox().check();
316+
await expect(
317+
adminModelCardPage.getAlsoDeleteFolderCheckbox(),
318+
).toBeChecked();
319+
320+
// Confirm deletion
321+
await adminModelCardPage.getDeleteConfirmButton().click();
322+
323+
// Verify the success notification for card + folder deletion
324+
await expect(
325+
page.getByText('Model card and folder have been moved to trash.'),
326+
).toBeVisible({ timeout: 15000 });
327+
328+
// Verify "Go to Data > Trash" link is visible in the notification
329+
const goToTrashLink = page.getByText('Go to Data > Trash');
330+
await expect(goToTrashLink).toBeVisible();
331+
332+
// Click "Go to Data > Trash" and verify URL includes folder filter
333+
await goToTrashLink.click();
334+
await page.waitForURL(
335+
(url) =>
336+
url.pathname === '/data' &&
337+
url.searchParams.get('statusCategory') === 'deleted' &&
338+
url.searchParams.get('filter') === `name == "${folderName}"`,
339+
{ timeout: 10000 },
340+
);
341+
});
342+
343+
// 5.8 Superadmin deletes card only: notification shows correct message and Go to Trash navigates correctly
344+
test('Superadmin can delete a model card only and navigate to trash without folder filter', async ({
345+
page,
346+
}) => {
347+
test.setTimeout(90000);
348+
const adminModelCardPage = new AdminModelCardPage(page);
349+
const timestamp = Date.now();
350+
const folderName = `e2e-test-keep-folder-${timestamp}`;
351+
const cardName = `e2e-test-delete-card-only-${timestamp}`;
352+
353+
// Setup: create a dedicated test VFolder to avoid affecting real folders
354+
await createVFolderAndVerify(page, folderName, 'model');
355+
356+
// Create a model card linked to the dedicated test folder
357+
await page.goto(`${webuiEndpoint}/admin-serving?tab=model-store`);
358+
await adminModelCardPage.waitForTableLoad();
359+
await adminModelCardPage.createModelCard({
360+
name: cardName,
361+
vfolderTitle: folderName,
362+
});
363+
364+
// Navigate back and filter
365+
await page.goto(`${webuiEndpoint}/admin-serving?tab=model-store`);
366+
await adminModelCardPage.waitForTableLoad();
367+
await adminModelCardPage.applyNameFilter(cardName);
368+
369+
// Open delete dialog
370+
await adminModelCardPage.clickDeleteForRow(cardName);
371+
372+
// Leave "Also delete folder" checkbox unchecked (default)
373+
await expect(
374+
adminModelCardPage.getAlsoDeleteFolderCheckbox(),
375+
).not.toBeChecked();
376+
377+
// Confirm deletion
378+
await adminModelCardPage.getDeleteConfirmButton().click();
379+
380+
// Verify the notification message for card-only deletion
381+
await expect(
382+
page.getByText(
383+
'Model card has been deleted. The model folder was not deleted.',
384+
),
385+
).toBeVisible({ timeout: 15000 });
386+
387+
// Verify "Go to Data > Trash" link is visible
388+
const goToTrashLink = page.getByText('Go to Data > Trash');
389+
await expect(goToTrashLink).toBeVisible();
390+
391+
// Click "Go to Data > Trash" and verify URL (no folder filter)
392+
await goToTrashLink.click();
393+
await page.waitForURL(
394+
(url) =>
395+
url.pathname === '/data' &&
396+
url.searchParams.get('statusCategory') === 'deleted' &&
397+
!url.searchParams.has('filter'),
398+
{ timeout: 10000 },
399+
);
400+
401+
// Cleanup: move the kept test folder to trash
402+
await moveToTrashAndVerify(page, folderName);
403+
});
269404
},
270405
);

e2e/utils/classes/AdminModelCardPage.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,14 @@ export class AdminModelCardPage {
301301
});
302302
}
303303

304+
getAlsoDeleteFolderCheckbox(): Locator {
305+
return this.getDeleteConfirmDialog().getByRole('checkbox').first();
306+
}
307+
308+
getFolderNameLinkInDeleteDialog(): Locator {
309+
return this.getDeleteConfirmDialog().getByRole('link').first();
310+
}
311+
304312
// ── Helper: create via UI and return ─────────────────────────────────────
305313

306314
async createModelCard(fields: {

0 commit comments

Comments
 (0)