diff --git a/admin-v2/tests/pages/Accounts.test.tsx b/admin-v2/tests/pages/Accounts.test.tsx
new file mode 100644
index 0000000..8575efc
--- /dev/null
+++ b/admin-v2/tests/pages/Accounts.test.tsx
@@ -0,0 +1,114 @@
+// ============================================================
+// Accounts 页面冒烟测试
+// ============================================================
+
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+import { render, screen, waitFor } from '@testing-library/react'
+import { http, HttpResponse } from 'msw'
+import { setupServer } from 'msw/node'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+
+import Accounts from '@/pages/Accounts'
+
+// ── Mock data ────────────────────────────────────────────────
+
+const mockAccounts = {
+ items: [
+ {
+ id: 'acc-001',
+ username: 'zclaw_admin',
+ display_name: 'Admin',
+ email: 'admin@zclaw.ai',
+ role: 'super_admin' as const,
+ status: 'active' as const,
+ totp_enabled: true,
+ last_login_at: '2026-03-30T10:00:00Z',
+ created_at: '2026-01-01T00:00:00Z',
+ llm_routing: 'relay' as const,
+ },
+ {
+ id: 'acc-002',
+ username: 'test_user',
+ display_name: 'Test',
+ email: 'test@zclaw.ai',
+ role: 'user' as const,
+ status: 'active' as const,
+ totp_enabled: false,
+ last_login_at: null,
+ created_at: '2026-02-15T00:00:00Z',
+ llm_routing: 'local' as const,
+ },
+ ],
+ total: 2,
+ page: 1,
+ page_size: 20,
+}
+
+// ── MSW server ───────────────────────────────────────────────
+
+const server = setupServer()
+
+beforeEach(() => {
+ server.listen({ onUnhandledRequest: 'bypass' })
+})
+
+afterEach(() => {
+ server.close()
+})
+
+// ── Helper: render with QueryClient ──────────────────────────
+
+function renderWithProviders(ui: React.ReactElement) {
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: { retry: false },
+ },
+ })
+ return render(
+
+ {ui}
+ ,
+ )
+}
+
+// ── Tests ────────────────────────────────────────────────────
+
+describe('Accounts page', () => {
+ it('renders account usernames in the table', async () => {
+ server.use(
+ http.get('*/api/v1/accounts', () => {
+ return HttpResponse.json(mockAccounts)
+ }),
+ )
+
+ renderWithProviders()
+
+ // Wait for data to load and usernames to appear
+ await waitFor(() => {
+ expect(screen.getByText('zclaw_admin')).toBeInTheDocument()
+ })
+ expect(screen.getByText('test_user')).toBeInTheDocument()
+ })
+
+ it('shows loading state before data arrives', async () => {
+ // Use a delayed response to observe loading state
+ server.use(
+ http.get('*/api/v1/accounts', async () => {
+ await new Promise((resolve) => setTimeout(resolve, 500))
+ return HttpResponse.json(mockAccounts)
+ }),
+ )
+
+ renderWithProviders()
+
+ // Ant Design ProTable renders a spinner while loading
+ // Check that a .ant-spin element exists
+ const spinner = document.querySelector('.ant-spin')
+ expect(spinner).toBeTruthy()
+
+ // Wait for loading to complete so afterEach cleanup is clean
+ await waitFor(() => {
+ expect(screen.getByText('zclaw_admin')).toBeInTheDocument()
+ })
+ })
+})
diff --git a/admin-v2/tests/pages/AgentTemplates.test.tsx b/admin-v2/tests/pages/AgentTemplates.test.tsx
new file mode 100644
index 0000000..1480525
--- /dev/null
+++ b/admin-v2/tests/pages/AgentTemplates.test.tsx
@@ -0,0 +1,137 @@
+// ============================================================
+// AgentTemplates 页面冒烟测试
+// ============================================================
+
+import { describe, it, expect, beforeEach, afterEach } from 'vitest'
+import { render, screen, waitFor } from '@testing-library/react'
+import { http, HttpResponse } from 'msw'
+import { setupServer } from 'msw/node'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+
+import AgentTemplates from '@/pages/AgentTemplates'
+
+// ── Mock data ────────────────────────────────────────────────
+
+const mockTemplates = {
+ items: [
+ {
+ id: 'tmpl-001',
+ name: 'Medical Assistant',
+ description: 'AI health assistant',
+ category: 'assistant',
+ source: 'builtin' as const,
+ model: 'gpt-4o',
+ system_prompt: 'You are a medical assistant.',
+ tools: ['web_search'],
+ capabilities: ['conversation'],
+ temperature: 0.7,
+ max_tokens: 4096,
+ visibility: 'public' as const,
+ status: 'active' as const,
+ current_version: 2,
+ created_at: '2026-01-10T00:00:00Z',
+ updated_at: '2026-03-20T00:00:00Z',
+ soul_content: null,
+ scenarios: ['healthcare'],
+ welcome_message: 'Hello!',
+ quick_commands: [],
+ personality: 'professional',
+ communication_style: null,
+ emoji: 'hospital',
+ version: 2,
+ source_id: 'medical-v1',
+ },
+ {
+ id: 'tmpl-002',
+ name: 'Code Helper',
+ description: 'Programming assistant',
+ category: 'tool',
+ source: 'custom' as const,
+ model: null,
+ system_prompt: null,
+ tools: [],
+ capabilities: [],
+ temperature: null,
+ max_tokens: null,
+ visibility: 'team' as const,
+ status: 'active' as const,
+ current_version: 1,
+ created_at: '2026-02-01T00:00:00Z',
+ updated_at: '2026-02-01T00:00:00Z',
+ soul_content: null,
+ scenarios: [],
+ welcome_message: null,
+ quick_commands: [],
+ personality: null,
+ communication_style: null,
+ emoji: null,
+ version: 1,
+ source_id: null,
+ },
+ ],
+ total: 2,
+ page: 1,
+ page_size: 20,
+}
+
+// ── MSW server ───────────────────────────────────────────────
+
+const server = setupServer()
+
+beforeEach(() => {
+ server.listen({ onUnhandledRequest: 'bypass' })
+})
+
+afterEach(() => {
+ server.close()
+})
+
+// ── Helper: render with QueryClient ──────────────────────────
+
+function renderWithProviders(ui: React.ReactElement) {
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: { retry: false },
+ },
+ })
+ return render(
+
+ {ui}
+ ,
+ )
+}
+
+// ── Tests ────────────────────────────────────────────────────
+
+describe('AgentTemplates page', () => {
+ it('renders template names in the table', async () => {
+ server.use(
+ http.get('*/api/v1/agent-templates', () => {
+ return HttpResponse.json(mockTemplates)
+ }),
+ )
+
+ renderWithProviders()
+
+ // Wait for data to load and template names to appear
+ await waitFor(() => {
+ expect(screen.getByText('Medical Assistant')).toBeInTheDocument()
+ })
+ expect(screen.getByText('Code Helper')).toBeInTheDocument()
+ })
+
+ it('renders template categories', async () => {
+ server.use(
+ http.get('*/api/v1/agent-templates', () => {
+ return HttpResponse.json(mockTemplates)
+ }),
+ )
+
+ renderWithProviders()
+
+ await waitFor(() => {
+ expect(screen.getByText('assistant')).toBeInTheDocument()
+ })
+ expect(screen.getByText('tool')).toBeInTheDocument()
+ })
+})