import type { Page } from '@playwright/test'; import { adminStorageStatePath, expect, rootStorageStatePath, test, } from './fixtures/cluster'; function nextBatchName(prefix: string) { return `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1000)}`; } async function gotoUserPage(page: Page) { await page.goto('/console/user'); await expect(page.getByTestId('user-page')).toBeVisible(); } async function openMigrationTab(page: Page) { const migrationTab = page.getByTestId('user-migration-tab'); await expect(migrationTab).toBeVisible(); await migrationTab.click(); await expect(page.getByTestId('user-migration-center')).toBeVisible(); } async function createBatch(page: Page, batchName: string) { await page.getByTestId('migration-create-batch-button').click(); const dialog = page.getByRole('dialog'); await expect(dialog).toBeVisible(); const nameField = dialog.getByRole('textbox').first(); await expect(nameField).toBeVisible(); await nameField.fill(batchName); await dialog .getByRole('button', { name: /confirm|确定/i }) .click(); await expect(page.getByTestId('migration-batch-table')).toContainText(batchName); await page.getByTestId('migration-batch-table').getByText(batchName).click(); await expect(page.getByTestId('migration-execution-panel')).toBeVisible(); await expect(page.getByTestId('migration-batch-detail')).toBeVisible(); } test.describe('User Migration Access', () => { test.use({ storageState: adminStorageStatePath }); test('non-root admin cannot see migration tab', async ({ page }) => { await gotoUserPage(page); await expect(page.getByTestId('user-migration-tab')).toHaveCount(0); }); }); test.describe.serial('User Migration Smoke', () => { test.use({ storageState: rootStorageStatePath }); test('root can open migration center and create a batch', async ({ page }) => { const batchName = nextBatchName('ui-create'); await gotoUserPage(page); await openMigrationTab(page); await createBatch(page, batchName); await expect(page.getByTestId('migration-batch-status')).toHaveText('draft'); }); test('root can scan, resolve conflicts, execute, and verify a batch', async ({ page, }) => { const batchName = nextBatchName('ui-flow'); await gotoUserPage(page); await openMigrationTab(page); await createBatch(page, batchName); await page.getByTestId('migration-scan-button').click(); await expect(page.getByTestId('migration-batch-status')).toHaveText( /scanning|scanned/, ); await expect(page.getByTestId('migration-batch-status')).toHaveText( 'scanned', { timeout: 25_000, }, ); await expect(page.getByTestId('migration-conflict-table')).toBeVisible(); await page.getByTestId('migration-resolve-skip-10000003').click(); await page.getByTestId('migration-resolve-skip-10000004').click(); await expect(page.getByTestId('migration-batch-status')).toHaveText('ready'); await page.getByTestId('migration-execute-button').click(); await expect(page.getByTestId('migration-execute-confirm')).toBeVisible(); await page.getByTestId('migration-execute-confirm').click(); await expect(page.getByTestId('migration-batch-status')).toHaveText( /running|completed/, ); await expect(page.getByTestId('migration-batch-status')).toHaveText( 'completed', { timeout: 25_000, }, ); await page.getByTestId('migration-verify-button').click(); await expect(page.getByTestId('migration-verify-results-table')).toBeVisible(); await expect(page.getByTestId('migration-verify-results-table')).toContainText( '10000001', ); await expect(page.getByTestId('migration-batch-detail-table')).toContainText( 'migrated', ); }); test('page reload keeps batch list and detail loading available', async ({ page, }) => { const batchName = nextBatchName('ui-refresh'); await gotoUserPage(page); await openMigrationTab(page); await createBatch(page, batchName); await page.getByTestId('migration-scan-button').click(); await expect(page.getByTestId('migration-batch-status')).toHaveText( 'scanned', { timeout: 25_000, }, ); await page.reload(); await gotoUserPage(page); await openMigrationTab(page); await expect(page.getByTestId('migration-batch-table')).toContainText(batchName); await page.getByTestId('migration-batch-table').getByText(batchName).click(); await expect(page.getByTestId('migration-batch-detail')).toBeVisible(); await expect(page.getByTestId('migration-batch-status')).toHaveText('scanned'); }); });