Skip to content

Commit 5d7906d

Browse files
committed
test(FR-2417): add E2E tests for Admin Model Card Management (#6520) (#6521)
Resolves #6520 ## Summary Add 33 comprehensive E2E tests for the Admin Model Card Management page (`/admin-model-store`). ### Test Coverage (33 tests / 8 spec files) | Spec File | Tests | Coverage | |-----------|-------|----------| | `page-load` | 4 | Page layout, pagination, column visibility | | `filter` | 3 | Name filter, clear filter, empty state | | `create` | 6 | Create modal, required/all fields, validation, cancel | | `edit` | 4 | Edit modal, update fields, validation, cancel | | `delete` | 6 | Single delete, cancel, bulk delete, bulk cancel, clear selection, select all | | `access-control` | 2 | Non-admin URL access blocked, menu hidden | | `sort-refresh` | 5 | Refresh, sort asc/desc, cross-column sort switch | | `url-state` | 3 | Filter/sort/pagination URL state persistence | ## Test Recordings ### Access Control (2 tests) | Test | Recording | |------|-----------| | Non-superadmin user cannot access the Admin Model Store page | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163245-access-control-non-superadmin-cannot-access.webm" controls width="960"></video> | | Non-superadmin user does not see the Admin Model Store menu item in the sidebar | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163250-access-control-non-superadmin-no-sidebar-menu.webm" controls width="960"></video> | ### Create (6 tests) | Test | Recording | |------|-----------| | Superadmin can open the Create Model Card modal | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163302-create-open-create-model-card-modal.webm" controls width="960"></video> | | Superadmin can create a model card with only required fields | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163307-create-with-only-required-fields.webm" controls width="960"></video> | | Superadmin can create a model card with all fields populated | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163313-create-with-all-fields-populated.webm" controls width="960"></video> | | Superadmin cannot create a model card without a Name | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163319-create-cannot-create-without-name.webm" controls width="960"></video> | | Superadmin cannot create a model card without a Model Storage Folder | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163324-create-cannot-create-without-storage-folder.webm" controls width="960"></video> | | Superadmin can cancel the Create Model Card modal without creating anything | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163328-create-cancel-without-creating.webm" controls width="960"></video> | ### Delete (6 tests) | Test | Recording | |------|-----------| | Superadmin can delete a model card via the trash icon with confirmation | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163345-delete-via-trash-icon-with-confirmation.webm" controls width="960"></video> | | Superadmin can cancel a single-delete confirmation without deleting | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163353-delete-cancel-single-delete-confirmation.webm" controls width="960"></video> | | Superadmin can select multiple model cards and delete them in bulk | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163357-delete-select-multiple-and-delete-in-bulk.webm" controls width="960"></video> | | Superadmin can cancel bulk deletion | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163402-delete-cancel-bulk-deletion.webm" controls width="960"></video> | | Superadmin can clear selection using the BAISelectionLabel clear button | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163406-delete-clear-selection-using-baiselectionlabel.webm" controls width="960"></video> | | Superadmin can select all model cards on the current page using the header checkbox | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163410-delete-select-all-using-header-checkbox.webm" controls width="960"></video> | ### Edit (4 tests) | Test | Recording | |------|-----------| | Superadmin can open the Edit Model Card modal from a table row | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163421-edit-open-edit-model-card-modal.webm" controls width="960"></video> | | Superadmin can update a model card's metadata fields | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163426-edit-update-model-card-metadata-fields.webm" controls width="960"></video> | | Superadmin cannot save an edit when the Name field is cleared | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163431-edit-cannot-save-when-name-field-cleared.webm" controls width="960"></video> | | Superadmin can cancel the Edit modal without saving changes | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163435-edit-cancel-edit-modal-without-saving.webm" controls width="960"></video> | ### Filtering (3 tests) | Test | Recording | |------|-----------| | Superadmin can filter model cards by name using BAIGraphQLPropertyFilter | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163445-filter-by-name-using-baigraphqlpropertyfilter.webm" controls width="960"></video> | | Superadmin can clear a filter to restore the full list | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163450-filter-clear-filter-to-restore-full-list.webm" controls width="960"></video> | | Superadmin sees empty table state when no model cards match the filter | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163454-filter-empty-state-when-no-cards-match.webm" controls width="960"></video> | ### Page Load and Table Display (4 tests) | Test | Recording | |------|-----------| | Superadmin can view the Admin Model Card management page | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163505-page-load-view-admin-model-card-management-page.webm" controls width="960"></video> | | Superadmin can see model card rows with correct data in the table | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163509-page-load-model-card-rows-with-correct-data.webm" controls width="960"></video> | | Superadmin can see pagination controls and navigate between pages | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163515-page-load-pagination-controls-and-navigate.webm" controls width="960"></video> | | Superadmin can change page size in the pagination | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163519-page-load-change-page-size-in-pagination.webm" controls width="960"></video> | ### Refresh and Sorting (5 tests) | Test | Recording | |------|-----------| | Superadmin can refresh the table using the fetch key button | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163531-sort-refresh-refresh-using-fetch-key-button.webm" controls width="960"></video> | | Superadmin can sort model cards by Name in ascending order | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163535-sort-refresh-sort-by-name-ascending.webm" controls width="960"></video> | | Superadmin can sort model cards by Name in descending order | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163539-sort-refresh-sort-by-name-descending.webm" controls width="960"></video> | | Superadmin can sort model cards by Created At | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163543-sort-refresh-sort-by-created-at.webm" controls width="960"></video> | | Superadmin can switch sort from Name to Created At | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163547-sort-refresh-switch-sort-from-name-to-created-at.webm" controls width="960"></video> | ### URL State Persistence (3 tests) | Test | Recording | |------|-----------| | Superadmin can persist filter state in the URL query parameters | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163556-url-state-persist-filter-state-in-url.webm" controls width="960"></video> | | Superadmin can persist sort order in the URL query parameters | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163559-url-state-persist-sort-order-in-url.webm" controls width="960"></video> | | Superadmin can persist pagination state in the URL query parameters | <video src="https://raw.githubusercontent.com/lablup/backend.ai-webui/assets/images/screenshots/pr-6521/20260409-163603-url-state-persist-pagination-state-in-url.webm" controls width="960"></video> |
1 parent 4e20153 commit 5d7906d

10 files changed

Lines changed: 1792 additions & 3 deletions

e2e/E2E_COVERAGE_REPORT.md

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

3-
> **Last Updated:** 2026-04-01
3+
> **Last Updated:** 2026-04-09
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): 231 / 388 features covered (60%)**
15+
**Overall (in-scope routes): 253 / 410 features covered (62%)**
1616

1717
| Page | Route | Features | Covered | Status |
1818
|------|-------|:--------:|:-------:|:------:|
@@ -27,6 +27,7 @@
2727
| Service Launcher | `/service/start` | 5 | 0 | ❌ 0% |
2828
| VFolder / Data | `/data` | 45 | 32 | 🔶 71% |
2929
| Model Store | `/model-store` | 6 | 0 | ❌ 0% |
30+
| Admin Model Store | `/admin-model-store` | 22 | 22 | ✅ 100% |
3031
| Storage Host | `/storage-settings/:hostname` | 3 | 0 | ❌ 0% |
3132
| My Environment | `/my-environment` | 2 | 2 | ✅ 100% |
3233
| Environment | `/environment` | 27 | 21 | 🔶 78% |
@@ -45,7 +46,7 @@
4546
| App Launcher | (modal) | 18 | 10 | 🔶 56% |
4647
| Chat | `/chat/:id?` | 6 | 6 | ✅ 100% |
4748
| Plugin System | (config-based) | 12 | 12 | ✅ 100% |
48-
| **Total** | | **335** | **181** | **54%** |
49+
| **Total** | | **357** | **203** | **57%** |
4950

5051
---
5152

@@ -377,6 +378,44 @@
377378

378379
---
379380

381+
### 10b. Admin Model Store (`/admin-model-store`)
382+
383+
**Test files:** [`e2e/admin-model-card/admin-model-card-page-load.spec.ts`](admin-model-card/admin-model-card-page-load.spec.ts), [`e2e/admin-model-card/admin-model-card-filter.spec.ts`](admin-model-card/admin-model-card-filter.spec.ts), [`e2e/admin-model-card/admin-model-card-create.spec.ts`](admin-model-card/admin-model-card-create.spec.ts), [`e2e/admin-model-card/admin-model-card-edit.spec.ts`](admin-model-card/admin-model-card-edit.spec.ts), [`e2e/admin-model-card/admin-model-card-delete.spec.ts`](admin-model-card/admin-model-card-delete.spec.ts), [`e2e/admin-model-card/admin-model-card-access-control.spec.ts`](admin-model-card/admin-model-card-access-control.spec.ts), [`e2e/admin-model-card/admin-model-card-sort-refresh.spec.ts`](admin-model-card/admin-model-card-sort-refresh.spec.ts), [`e2e/admin-model-card/admin-model-card-url-state.spec.ts`](admin-model-card/admin-model-card-url-state.spec.ts)
384+
385+
**Requires:** Superadmin login
386+
**Primary action:** "Create Model Card" → modal
387+
**Row actions:** Edit (setting icon), Delete (trash icon)
388+
**Bulk actions:** Bulk delete via header checkbox selection
389+
390+
| Feature | Status | Test |
391+
|---------|--------|------|
392+
| Page load and table rendering || `admin-model-card-page-load.spec.ts` |
393+
| Column visibility and pagination || `admin-model-card-page-load.spec.ts` |
394+
| Name filter search || `admin-model-card-filter.spec.ts` |
395+
| Filter clear and empty state || `admin-model-card-filter.spec.ts` |
396+
| Open create modal || `admin-model-card-create.spec.ts` |
397+
| Create with required fields only || `admin-model-card-create.spec.ts` |
398+
| Create with all fields || `admin-model-card-create.spec.ts` |
399+
| Create validation (name required) || `admin-model-card-create.spec.ts` |
400+
| Create validation (VFolder required) || `admin-model-card-create.spec.ts` |
401+
| Cancel create modal || `admin-model-card-create.spec.ts` |
402+
| Open edit modal || `admin-model-card-edit.spec.ts` |
403+
| Update model card fields || `admin-model-card-edit.spec.ts` |
404+
| Edit validation || `admin-model-card-edit.spec.ts` |
405+
| Cancel edit modal || `admin-model-card-edit.spec.ts` |
406+
| Single delete with confirmation || `admin-model-card-delete.spec.ts` |
407+
| Cancel single delete || `admin-model-card-delete.spec.ts` |
408+
| Bulk select and delete || `admin-model-card-delete.spec.ts` |
409+
| Cancel bulk delete || `admin-model-card-delete.spec.ts` |
410+
| Clear selection || `admin-model-card-delete.spec.ts` |
411+
| Select all via header checkbox || `admin-model-card-delete.spec.ts` |
412+
| Non-admin access blocked || `admin-model-card-access-control.spec.ts` |
413+
| URL state persistence (filter/sort/pagination) || `admin-model-card-url-state.spec.ts` |
414+
415+
**Coverage: ✅ 22/22 features**
416+
417+
---
418+
380419
### 11. Storage Host Settings (`/storage-settings/:hostname`)
381420

382421
**Test files:** None
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// spec: e2e/.agent-output/test-plan-admin-model-card.md
2+
// section: 9. Access Control
3+
import { loginAsUser, webuiEndpoint } from '../utils/test-util';
4+
import { test, expect } from '@playwright/test';
5+
6+
test.describe(
7+
'Admin Model Card Management - Access Control',
8+
{ tag: ['@admin-model-card', '@admin', '@functional'] },
9+
() => {
10+
// 9.1 Non-superadmin user cannot access the Admin Model Store page
11+
test('Non-superadmin user cannot access the Admin Model Store page', async ({
12+
page,
13+
request,
14+
}) => {
15+
// Login as a regular user
16+
await loginAsUser(page, request);
17+
18+
// Attempt to navigate directly to /admin-serving?tab=model-store
19+
await page.goto(`${webuiEndpoint}/admin-serving?tab=model-store`);
20+
21+
// Verify the page does NOT show the Admin Model Card management table
22+
// The page should either redirect or show an access denied state
23+
await expect(
24+
page.getByRole('button', { name: 'Create Model Card' }),
25+
).toBeHidden({ timeout: 5000 });
26+
});
27+
28+
// 9.2 The Admin Model Store menu item is not visible to non-superadmin users
29+
test('Non-superadmin user does not see the Admin Model Store menu item in the sidebar', async ({
30+
page,
31+
request,
32+
}) => {
33+
// Login as a regular user
34+
await loginAsUser(page, request);
35+
36+
// Wait for the sidebar to appear
37+
await page.waitForSelector('[data-testid="user-dropdown-button"]');
38+
39+
// Verify no admin model store link appears in the navigation
40+
await expect(
41+
page.getByRole('link', { name: 'Model Cards' }),
42+
).toBeHidden();
43+
44+
await expect(
45+
page.getByRole('link', { name: 'Model Store Management' }),
46+
).toBeHidden();
47+
});
48+
},
49+
);

0 commit comments

Comments
 (0)