/** * 心知益家小程序 - 自动化测试用例脚本 * * 测试策略: * 1. Web端(管理后台):浏览器自动化测试,管理员和成长规划师登录,测试过程截图 * 2. 小程序端:API接口测试,构造请求数据,验证响应,不进行UI点击测试 * * 最后更新时间:2026-04-14 */ const TEST_CONFIG = { // 测试环境配置 baseUrl: 'http://192.168.16.18:8080', // 后端API地址 webAdminUrl: 'http://192.168.16.18:8082', // Web管理端地址 // 测试账号 adminAccount: { phone: '13800138000', password: 'admin123' }, teacherAccount: { phone: '13800138003', password: 'teacher123' }, // API测试账号(小程序端) apiTestAccounts: { parent: { id: 1, phone: '13800138001', token: '' }, child: { id: 2, phone: '13800138002', token: '' } }, // 测试超时时间(毫秒) timeout: 30000, // 截图保存路径 screenshotPath: './screenshots' }; // ============================================================================ // 模块1: API接口测试基类(小程序端) // ============================================================================ /** * API测试基类 - 用于小程序端接口测试 * 只测试API接口,记录构造的请求数据和响应结果 */ class ApiTestCase { constructor(id, description, priority, endpoint, method = 'GET') { this.id = id; this.description = description; this.priority = priority; // P0, P1, P2 this.endpoint = endpoint; this.method = method; this.status = 'pending'; // pending, running, passed, failed this.error = null; this.requestData = null; this.responseData = null; this.screenshots = []; } /** * 发送API请求 */ async sendRequest(data = {}, headers = {}) { const url = `${TEST_CONFIG.baseUrl}${this.endpoint}`; const startTime = Date.now(); this.requestData = { url: url, method: this.method, headers: { 'Content-Type': 'application/json', ...headers }, body: data, timestamp: new Date().toISOString() }; console.log(`[${this.id}] 发送请求: ${this.method} ${url}`); console.log(`[${this.id}] 请求数据:`, JSON.stringify(data, null, 2)); try { // 这里需要实际的HTTP客户端,模拟请求 // 在实际运行时,可以使用 fetch 或 axios const response = await this.mockFetch(url, { method: this.method, headers: this.requestData.headers, body: this.method !== 'GET' ? JSON.stringify(data) : undefined }); this.responseData = { status: response.status, statusText: response.statusText, data: response.data, duration: Date.now() - startTime, timestamp: new Date().toISOString() }; console.log(`[${this.id}] 响应状态: ${response.status}`); console.log(`[${this.id}] 响应数据:`, JSON.stringify(response.data, null, 2)); return response; } catch (error) { this.responseData = { error: error.message, timestamp: new Date().toISOString() }; throw error; } } /** * 模拟fetch请求(实际运行时替换为真实HTTP客户端) */ async mockFetch(url, options) { // 模拟响应,实际测试时需要连接真实后端 return { status: 200, statusText: 'OK', data: { code: 200, message: 'success', data: {} } }; } /** * 记录测试结果 */ logResult(passed, error = null) { this.status = passed ? 'passed' : 'failed'; this.error = error; console.log(`[${this.id}] 测试${passed ? '通过 ✅' : '失败 ❌'}: ${this.description}`); if (error) { console.error(`[${this.id}] 错误信息:`, error); } } /** * 执行测试(子类实现) */ async run() { throw new Error('子类必须实现 run 方法'); } } // ============================================================================ // 模块2: Web浏览器测试基类(管理后台) // ============================================================================ /** * Web浏览器测试基类 - 用于管理后台UI测试 * 使用Chrome DevTools进行浏览器自动化,测试过程截图 */ // ============================================================================ // 模块0: Playwright MCP 工具封装 // ============================================================================ // 检测是否在 Agent 上下文(skill_mcp 可用) const isAgentContext = typeof skill_mcp === 'function'; /** * Puppeteer MCP 实现 - 用于 Node.js 独立运行 * 使用 puppeteer 包直接控制浏览器 */ let puppeteerBrowser = null; let puppeteerPage = null; class PuppeteerMCP { constructor() { this.page = null; this.browser = null; } async _ensureBrowser() { try { let needsNewBrowser = !this.browser; if (this.browser && this.page) { try { const isClosed = this.page.isClosed(); if (isClosed) needsNewBrowser = true; } catch (e) { needsNewBrowser = true; } } if (needsNewBrowser) { if (this.browser) { try { await this.browser.close(); } catch (e) {} } const puppeteer = require('puppeteer'); this.browser = await puppeteer.launch({ headless: 'new', executablePath: '/usr/bin/chromium-browser', args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu', '--disable-software-rasterizer', '--disable-dev-shm-usage'] }); this.browser.on('disconnected', () => { this.browser = null; this.page = null; }); const pages = await this.browser.pages(); this.page = pages.length > 0 ? pages[0] : await this.browser.newPage(); await this.page.setViewport({ width: 1920, height: 1080 }); } return { browser: this.browser, page: this.page }; } catch (e) { this.browser = null; this.page = null; throw e; } } async navigate(url) { let attempts = 0; while (attempts < 2) { try { const { browser, page } = await this._ensureBrowser(); await page.goto(url, { waitUntil: 'networkidle2', timeout: 45000 }); await page.waitForTimeout(3000); return { url: page.url() }; } catch (e) { if (e.message.includes('Target closed') || e.message.includes('Session closed') || e.message.includes('Protocol error')) { this.browser = null; this.page = null; attempts++; continue; } throw e; } } } async snapshot() { let attempts = 0; while (attempts < 2) { try { const { page } = await this._ensureBrowser(); const elements = await page.evaluate(() => { const items = []; const all = document.querySelectorAll('*'); all.forEach((el, idx) => { if (el.children.length === 0 || el.tagName === 'BUTTON' || el.tagName === 'INPUT' || el.tagName === 'A') { const text = el.innerText || el.textContent || ''; if (text.trim()) { items.push({ text: text.trim().substring(0, 100), tag: el.tagName, uid: `idx:${idx}`, ref: `idx:${idx}` }); } } }); return items; }); return { items: elements }; } catch (e) { if (e.message.includes('Target closed') || e.message.includes('Session closed') || e.message.includes('Protocol error') || e.message.includes('Execution context')) { this.browser = null; this.page = null; attempts++; continue; } throw e; } } return { items: [] }; } async click(element) { if (!element) return; let attempts = 0; while (attempts < 2) { try { const { page } = await this._ensureBrowser(); console.log('[click] page URL BEFORE:', page.url()); const rawUid = typeof element === 'object' ? (element.uid || element.text || '') : element; const selector = rawUid.replace('text:', ''); const selector = rawUid.replace('text:', ''); if (/[\u4e00-\u9fff]/.test(selector) && (selector === '登录' || selector.length <= 4)) { const debugResult = await page.evaluate(() => { const allEls = document.querySelectorAll('*'); const found = []; for (const el of allEls) { const vue = el.__vue__; if (vue && vue.$data && ('loginForm' in vue.$data)) { found.push('login_comp'); try { vue.handleLogin(); return 'login_comp_ok'; } catch(e) { return 'login_comp_err:' + e.message; } } } return 'no_comp_found:' + found.length; }); console.log('[click] Vue direct result:', debugResult); await page.waitForTimeout(2000); return; } if (selector.startsWith('idx:')) { const idx = parseInt(selector.replace('idx:', '')); const elements = await page.$$('*'); if (elements[idx]) await elements[idx].click(); } else { let clicked = false; try { const btnLoc = page.locator('.el-button').filter({ hasText: selector }); const count = await btnLoc.count(); if (count > 0) { await btnLoc.first().click(); clicked = true; } } catch (e) {} if (!clicked) { try { const btns = await page.$$('.el-button'); for (const btn of btns) { const txt = await btn.innerText().catch(() => ''); if (txt.trim() === selector || (selector.length <= 10 && txt.includes(selector))) { await btn.click(); clicked = true; break; } } } catch (e) {} } if (!clicked) { try { const els = await page.getByText(selector, { exact: false }).all(); if (els.length > 0) { await els[0].click(); clicked = true; } } catch (e) {} } if (!clicked) { try { const loc = page.locator('text=' + selector); const count = await loc.count(); if (count > 0) { await loc.first().click(); clicked = true; } } catch (e) {} } if (!clicked) { try { const allEls = await page.$$('*'); for (const el of allEls) { const txt = await el.innerText().catch(() => ''); if (txt.trim() === selector || (selector.length <= 10 && txt.includes(selector))) { await el.click(); clicked = true; break; } } } catch (e) {} } } await page.waitForTimeout(2000); return; } catch (e) { if (e.message.includes('Target closed') || e.message.includes('Session closed') || e.message.includes('Protocol error') || e.message.includes('Execution context')) { this.browser = null; this.page = null; attempts++; continue; } throw e; } } } async fill(element, value) { if (!element) return; let attempts = 0; while (attempts < 2) { try { const { page, browser } = await this._ensureBrowser(); console.log('[fill] page URL:', page.url()); const rawText = (element.uid || element.ref || '').replace('text:', ''); const idx = element.idx; if (rawText.includes('用户名') || rawText.includes('密码') || typeof idx === 'number') { const result = await page.evaluate((key, v) => { const allEls = document.querySelectorAll('*'); let comp = null; for (const el of allEls) { const vue = el.__vue__; if (vue && vue.$data && ('loginForm' in vue.$data)) { comp = vue; break; } } if (!comp) return 'no_login_comp'; const field = key.includes('密码') ? 'password' : 'username'; comp.loginForm[field] = v; return field + ':' + v; }, rawText, String(value)); console.log('[fill] result:', result, 'url:', page.url()); await page.waitForTimeout(500); } else { const selector = (element.uid || element.ref || element).replace('text:', ''); if (selector.startsWith('idx:')) { const i = parseInt(selector.replace('idx:', '')); const elements = await page.$$('*'); if (elements[i]) { await elements[i].click(); await page.keyboard.press('Control+A'); await page.keyboard.type(String(value)); await page.waitForTimeout(500); } } else { await page.evaluate((sel) => { const el = document.querySelector(sel); if (el) el.focus(); }, selector); await page.waitForTimeout(200); await page.keyboard.type(String(value)); await page.waitForTimeout(500); } } return; } catch (e) { if (e.message.includes('Target closed') || e.message.includes('Session closed') || e.message.includes('Protocol error') || e.message.includes('Execution context')) { this.browser = null; this.page = null; attempts++; continue; } throw e; } } } async wait(seconds) { const { page } = await this._ensureBrowser(); await page.waitForTimeout(seconds * 1000); } async screenshot(filename) { const { page } = await this._ensureBrowser(); await page.screenshot({ path: filename, fullPage: true }); return filename; } async resize(width, height) { const { page } = await this._ensureBrowser(); await page.setViewport({ width, height }); } async waitAndFind(text, timeout = 30) { await this.wait(1); let attempts = 0; while (attempts < timeout) { try { const { page } = await this._ensureBrowser(); // Try .el-input__inner elements matching by placeholder const allInner = await page.$$('.el-input__inner'); for (let i = 0; i < allInner.length; i++) { const ph = await allInner[i].getAttribute('placeholder').catch(() => ''); if (ph.includes(text)) { await allInner[i].scrollIntoViewIfNeeded().catch(() => {}); return { uid: '.el-input__inner', idx: i, text: ph, ref: '.el-input__inner' }; } } // Fall back to text search in DOM const snap = await this.snapshot(); const items = this._extractElements(snap); const found = items.find(el => el.text && el.text.includes(text)); if (found) return found; } catch (e) {} await this.wait(1); attempts++; } return null; } _extractElements(snapshot) { if (!snapshot) return []; if (Array.isArray(snapshot)) return snapshot; if (snapshot.items) return snapshot.items; if (snapshot.elements) return snapshot.elements; return []; } async close() { if (this.browser) { try { await this.browser.close(); } catch (e) {} this.browser = null; this.page = null; } } async reset() { await this.close(); } } /** * Playwright MCP 工具封装类(Agent 模式) * 封装 skill_mcp 调用 Playwright 浏览器自动化工具 */ class PlaywrightMCP { constructor() { this.mcpName = 'playwright'; } /** * 调用 Playwright MCP 工具 */ async call(toolName, args = {}) { try { const result = await skill_mcp({ mcp_name: this.mcpName, tool_name: toolName, arguments: args }); return result; } catch (error) { console.error(`[PlaywrightMCP] ${toolName} 调用失败:`, error.message); throw error; } } /** * 导航到 URL */ async navigate(url) { return await this.call('browser_navigate', { url }); } /** * 获取页面快照 */ async snapshot() { return await this.call('browser_snapshot', {}); } /** * 等待元素并返回元素引用 */ async waitAndFind(text, timeout = 30) { await this.call('browser_wait_for', { time: 3 }); // 先等待一下 let attempts = 0; while (attempts < timeout / 3) { try { const snap = await this.snapshot(); const elements = this._extractElements(snap); const found = elements.find(el => el.text && el.text.includes(text) ); if (found) { return found; } } catch (e) { // 继续尝试 } await this.call('browser_wait_for', { time: 3 }); attempts++; } return null; } /** * 从快照中提取元素列表 */ _extractElements(snapshot) { if (!snapshot) return []; if (typeof snapshot === 'string') { try { const parsed = JSON.parse(snapshot); return this._extractElements(parsed); } catch { return []; } } if (Array.isArray(snapshot)) return snapshot; if (snapshot.elements) return snapshot.elements; if (snapshot.nodes) return snapshot.nodes; if (snapshot.items) return snapshot.items; return []; } /** * 通过文本查找元素(兼容旧接口) */ findByText(text) { return { text, uid: `text:${text}` }; } /** * 点击元素 */ async click(element) { if (!element) return; const ref = element.ref || element.uid || `text:${element.text}`; return await this.call('browser_click', { element: element.text || ref, ref }); } /** * 填写表单字段 */ async fill(element, value) { if (!element) return; const ref = element.ref || element.uid || `text:${element.text}`; return await this.call('browser_type', { ref, text: value }); } /** * 等待指定时间 */ async wait(seconds) { return await this.call('browser_wait_for', { time: seconds }); } /** * 截图 */ async screenshot(filename) { return await this.call('browser_take_screenshot', { type: 'png', filename }); } /** * 调整浏览器窗口大小 */ async resize(width, height) { return await this.call('browser_resize', { width, height }); } } // 全局 Playwright MCP 实例 let pw = null; function getPlaywrightMCP() { if (!pw) { pw = isAgentContext ? new PlaywrightMCP() : new PuppeteerMCP(); } return pw; } // ============================================================================ // 模块2: Web浏览器测试基类(管理后台) // ============================================================================ /** * Web测试基类 - 用于管理后台浏览器自动化测试 * 使用 Playwright MCP 工具进行真实的浏览器自动化测试 */ class WebTestCase { constructor(id, description, priority) { this.id = id; this.description = description; this.priority = priority; this.status = 'pending'; this.error = null; this.screenshots = []; this.pageId = null; this.pw = null; // Playwright MCP 实例 } /** * 获取 Playwright MCP 实例 */ getPW() { if (!this.pw) { this.pw = getPlaywrightMCP(); } return this.pw; } /** * 初始化测试环境 - 打开浏览器并导航到页面 */ async setup(url = TEST_CONFIG.webAdminUrl) { console.log(`[${this.id}] 测试启动: ${this.description}`); this.status = 'running'; const pw = this.getPW(); await pw.navigate(url); await pw.resize(1920, 1080); await pw.wait(2); } /** * 等待指定秒数 */ async wait(seconds) { const pw = this.getPW(); await pw.wait(seconds); } /** * 截图 */ async screenshot(name) { const pw = this.getPW(); const filename = `${TEST_CONFIG.screenshotPath}/${this.id}_${name}.png`; try { await pw.screenshot(filename); console.log(`[${this.id}] 截图保存: ${filename}`); this.screenshots.push(filename); return filename; } catch (error) { console.log(`[${this.id}] 截图失败: ${error.message}`); return filename; } } /** * 等待元素出现并返回元素引用 */ async waitForElement(text, timeout = 30) { const pw = this.getPW(); const element = await pw.waitAndFind(text, timeout); if (element) { console.log(`[${this.id}] 找到元素: ${text}`); return element; } else { console.log(`[${this.id}] 未找到元素: ${text}`); return { text, uid: `text:${text}`, ref: `text:${text}` }; } } /** * 点击元素 */ async click(uid) { const pw = this.getPW(); try { const element = { uid, text: uid.replace('text:', '') }; await pw.click(element); console.log(`[${this.id}] 点击元素: ${uid}`); } catch (error) { console.log(`[${this.id}] 点击失败: ${uid} - ${error.message}`); } } /** * 填充输入框 */ async fill(uid, value) { const pw = this.getPW(); try { const element = { uid, text: uid.replace('text:', '') }; await pw.fill(element, value); console.log(`[${this.id}] 填充输入: ${uid} = ${value}`); } catch (error) { console.log(`[${this.id}] 填充失败: ${uid} = ${value} - ${error.message}`); } } /** * 获取页面快照 */ async getSnapshot() { const pw = this.getPW(); try { const snap = await pw.snapshot(); return pw._extractElements(snap); } catch (error) { console.log(`[${this.id}] 获取快照失败: ${error.message}`); return []; } } /** * 登录管理员账号 */ async loginAdmin() { console.log(`[${this.id}] 登录管理员账号: ${TEST_CONFIG.adminAccount.phone}`); const pw = this.getPW(); await pw.navigate(TEST_CONFIG.webAdminUrl); await pw.wait(3); await this.screenshot('01_login_page'); // 填写登录表单(placeholder="请输入用户名" / "请输入密码") const phoneEl = await this.waitForElement('请输入用户名'); await this.fill(phoneEl.uid || '请输入用户名', TEST_CONFIG.adminAccount.phone); const pwdEl = await this.waitForElement('请输入密码'); await this.fill(pwdEl.uid || '请输入密码', TEST_CONFIG.adminAccount.password); await pw.wait(1); await this.screenshot('02_form_filled'); const loginBtn = await this.waitForElement('登录'); await pw.click({ text: '登录', uid: '登录' }); await pw.wait(3); await this.screenshot('03_after_login'); } /** * 登录成长规划师账号 */ async loginTeacher() { console.log(`[${this.id}] 登录成长规划师账号: ${TEST_CONFIG.teacherAccount.phone}`); const pw = this.getPW(); await pw.navigate(TEST_CONFIG.webAdminUrl); await pw.wait(3); await this.screenshot('01_teacher_login_page'); const phoneEl = await this.waitForElement('请输入用户名'); await this.fill(phoneEl.uid || '请输入用户名', TEST_CONFIG.teacherAccount.phone); const pwdEl = await this.waitForElement('请输入密码'); await this.fill(pwdEl.uid || '请输入密码', TEST_CONFIG.teacherAccount.password); await this.screenshot('02_teacher_form_filled'); await pw.click({ text: '登录', uid: '登录' }); await pw.wait(3); await this.screenshot('03_teacher_after_login'); } /** * 记录测试结果 */ logResult(passed, error = null) { this.status = passed ? 'passed' : 'failed'; this.error = error; console.log(`[${this.id}] 测试${passed ? '通过 ✅' : '失败 ❌'}: ${this.description}`); if (error) { console.error(`[${this.id}] 错误信息:`, error); } } /** * 执行测试(子类实现) */ async run() { throw new Error('子类必须实现 run 方法'); } } // ============================================================================ // 小程序端 API 测试用例 // ============================================================================ /** * API-001: 家长登录接口 */ class API_001_TestCase extends ApiTestCase { constructor() { super('API-001', '家长登录接口', 'P0', '/api/auth/login', 'POST'); } async run() { try { this.requestData = { phone: '13800138001', code: '123456', role: 'parent' }; const response = await this.sendRequest(this.requestData); // 验证响应 const passed = response.status === 200 && response.data.code === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-002: 创建任务接口 */ class API_002_TestCase extends ApiTestCase { constructor() { super('API-002', '家长创建任务接口', 'P0', '/api/tasks', 'POST'); } async run() { try { this.requestData = { childId: 2, name: '完成语文作业', points: 5, category: 'study', deadline: '2026-04-15T18:00:00', description: '完成课本第10页到第15页的练习题' }; const response = await this.sendRequest(this.requestData); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-003: 获取今日任务列表 */ class API_003_TestCase extends ApiTestCase { constructor() { super('API-003', '获取孩子今日任务列表', 'P0', '/api/tasks/today/2', 'GET'); } async run() { try { this.requestData = { childId: 2, date: new Date().toISOString().split('T')[0] }; const response = await this.sendRequest(this.requestData); // 记录响应数据结构 console.log(`[${this.id}] 任务列表数据结构:`, JSON.stringify(response.data, null, 2)); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-004: 孩子完成任务 */ class API_004_TestCase extends ApiTestCase { constructor() { super('API-004', '孩子完成任务接口', 'P0', '/api/tasks/1/complete', 'POST'); } async run() { try { this.requestData = { taskId: 1, completedAt: new Date().toISOString(), proof: { type: 'photo', url: 'https://example.com/photo.jpg', description: '已完成作业拍照' } }; const response = await this.sendRequest(this.requestData); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-005: 获取积分记录 */ class API_005_TestCase extends ApiTestCase { constructor() { super('API-005', '获取积分记录接口', 'P0', '/api/points/records', 'GET'); } async run() { try { this.requestData = { childId: 2, startDate: '2026-04-01', endDate: '2026-04-30' }; const response = await this.sendRequest(this.requestData); console.log(`[${this.id}] 积分记录数据:`, JSON.stringify(response.data, null, 2)); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-006: 添加心愿到心愿单 */ class API_006_TestCase extends ApiTestCase { constructor() { super('API-006', '孩子添加心愿接口', 'P0', '/api/rewards/wishlist', 'POST'); } async run() { try { this.requestData = { childId: 2, name: '去游乐园玩', category: 'experience', description: '周末全家一起去游乐园' }; const response = await this.sendRequest(this.requestData); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-007: 兑换奖励 */ class API_007_TestCase extends ApiTestCase { constructor() { super('API-007', '孩子兑换奖励接口', 'P0', '/api/rewards/1/exchange', 'POST'); } async run() { try { this.requestData = { rewardId: 1, childId: 2, pointsUsed: 50 }; const response = await this.sendRequest(this.requestData); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-008: 家长审批奖励兑换 */ class API_008_TestCase extends ApiTestCase { constructor() { super('API-008', '家长审批奖励兑换接口', 'P0', '/api/rewards/1/approve', 'POST'); } async run() { try { this.requestData = { exchangeId: 1, approved: true, comment: '同意兑换,表现很好!' }; const response = await this.sendRequest(this.requestData); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-009: 获取连续打卡天数 */ class API_009_TestCase extends ApiTestCase { constructor() { super('API-009', '获取连续打卡天数接口', 'P0', '/api/streak/2', 'GET'); } async run() { try { this.requestData = { childId: 2 }; const response = await this.sendRequest(this.requestData); console.log(`[${this.id}] 连续打卡数据:`, JSON.stringify(response.data, null, 2)); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-010: 获取家庭信息 */ class API_010_TestCase extends ApiTestCase { constructor() { super('API-010', '获取家庭信息接口', 'P0', '/api/family/info', 'GET'); } async run() { try { this.requestData = { familyId: 1 }; const response = await this.sendRequest(this.requestData); console.log(`[${this.id}] 家庭信息数据:`, JSON.stringify(response.data, null, 2)); const passed = response.status === 200; this.logResult(passed); } catch (error) { this.logResult(false, error); } } } /** * API-011: 成长规划师首次登录角色选择 */ class API_011_TestCase extends ApiTestCase { constructor() { super('API-011', '成长规划师首次登录角色选择', 'P0', '/api/auth/role-select', 'POST'); } async run() { try { this.requestData = { userId: 1, role: 'teacher' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-012: 成长规划师信息录入 */ class API_012_TestCase extends ApiTestCase { constructor() { super('API-012', '成长规划师信息录入', 'P0', '/api/user/profile', 'PUT'); } async run() { try { this.requestData = { idCard: '110101199001011234', gender: 'male', teacherPhoto: 'https://example.com/photo.jpg', teacherNo: 'TEACHER20260001', certificateImage: 'https://example.com/cert.jpg' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-013: 成长规划师查看关联家庭 */ class API_013_TestCase extends ApiTestCase { constructor() { super('API-013', '成长规划师查看关联家庭列表', 'P0', '/api/guide/families', 'GET'); } async run() { try { this.requestData = { teacherId: 1 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-014: 成长规划师审核任务 */ class API_014_TestCase extends ApiTestCase { constructor() { super('API-014', '成长规划师审核家庭任务', 'P0', '/api/guide/tasks/1/review', 'POST'); } async run() { try { this.requestData = { taskId: 1, approved: true, comment: '审核通过' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-015: 小游戏-舒尔特方格 */ class API_015_TestCase extends ApiTestCase { constructor() { super('API-015', '舒尔特方格开始游戏', 'P1', '/api/mini-games/schulte/start', 'POST'); } async run() { try { this.requestData = { childId: 2, gridSize: 5 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-016: 小游戏-猜数字(1a2b) */ class API_016_TestCase extends ApiTestCase { constructor() { super('API-016', '猜数字(1a2b)开始游戏', 'P1', '/api/mini-games/1a2b/start', 'POST'); } async run() { try { this.requestData = { childId: 2 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-017: 任务模板创建 */ class API_017_TestCase extends ApiTestCase { constructor() { super('API-017', '创建任务模板', 'P1', '/api/task-templates', 'POST'); } async run() { try { this.requestData = { title: '每日阅读', description: '阅读30分钟课外书籍', category: 'study', points: 3, duration: 30, completeTypes: ['checkin', 'text'] }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-018: 创建小游戏类任务(minigameCode字段) */ class API_018_TestCase extends ApiTestCase { constructor() { super('API-018', '创建小游戏类任务', 'P1', '/api/tasks', 'POST'); } async run() { try { this.requestData = { childId: 2, title: '完成舒尔特方格训练', category: '小游戏类', minigameCode: 'schulte', points: 5, deadline: '2026-04-20T18:00:00', needReview: 0 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-019: 完成小游戏任务(调用MiniGameService) */ class API_019_TestCase extends ApiTestCase { constructor() { super('API-019', '完成小游戏任务获积分', 'P1', '/api/tasks/1/complete', 'POST'); } async run() { try { this.requestData = { childId: 2, completionTime: 45, score: 80 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 成长规划师功能模块 - 套餐测试用例 // ============================================================================ /** * API-020: 查看成长规划师套餐列表 */ class API_020_TestCase extends ApiTestCase { constructor() { super('API-020', '查看成长规划师套餐列表', 'P0', '/api/guide-packages', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-050b: 管理员获取服务内容详情 */ class API_050b_TestCase extends ApiTestCase { constructor() { super('API-050b', '管理员获取服务内容详情', 'P0', '/api/admin/service-contents', 'POST'); } async run() { try { this.requestData = { id: 1 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 成长规划师功能模块 - 服务测试用例 // ============================================================================ /** * API-025: 成长规划师创建测评服务 */ class API_025_TestCase extends ApiTestCase { constructor() { super('API-025', '成长规划师创建测评服务', 'P0', '/api/guide-services', 'POST'); } async run() { try { this.requestData = { teacherId: 1, serviceType: 'assessment', title: 'DAN能力测评服务', description: '基于双培强基工程的DAN素质能力测评', price: 99, duration: 60 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-026: 成长规划师创建自定义服务 */ class API_026_TestCase extends ApiTestCase { constructor() { super('API-026', '成长规划师创建自定义服务', 'P0', '/api/guide-services', 'POST'); } async run() { try { this.requestData = { teacherId: 1, serviceType: 'custom', title: '专注力训练指导服务', description: '专业专注力训练指导,30天见效', price: 199, duration: 30 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-027: 成长规划师查看已发布服务列表 */ class API_027_TestCase extends ApiTestCase { constructor() { super('API-027', '成长规划师查看已发布服务列表', 'P0', '/api/guide-services/my', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-028: 成长规划师编辑服务 */ class API_028_TestCase extends ApiTestCase { constructor() { super('API-028', '成长规划师编辑服务', 'P1', '/api/guide-services/1', 'PUT'); } async run() { try { this.requestData = { title: 'DAN能力测评服务(升级版)', description: '基于双培强基工程的DAN素质能力测评,增加详细报告', price: 129, duration: 90 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-029: 成长规划师删除服务 */ class API_029_TestCase extends ApiTestCase { constructor() { super('API-029', '成长规划师删除服务', 'P1', '/api/guide-services/1', 'DELETE'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-030: 家长购买成长规划师服务 */ class API_030_TestCase extends ApiTestCase { constructor() { super('API-030', '家长购买成长规划师服务', 'P0', '/api/guide-services/1/purchase', 'POST'); } async run() { try { this.requestData = { parentId: 1, childId: 2, serviceId: 1 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-031: 查看服务购买记录 */ class API_031_TestCase extends ApiTestCase { constructor() { super('API-031', '查看服务购买记录', 'P1', '/api/guide-services/orders', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 成长规划师功能模块 - 任务测试用例 // ============================================================================ /** * API-032: 成长规划师创建绑定服务的任务 */ class API_032_TestCase extends ApiTestCase { constructor() { super('API-032', '成长规划师创建绑定服务的任务', 'P0', '/api/guide-tasks', 'POST'); } async run() { try { this.requestData = { teacherId: 1, title: 'DAN测评后任务-专注力训练', category: '学习类', points: 5, deadline: '2026-05-10T18:00:00', serviceId: 1, needReview: 1 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-033: 成长规划师查看已创建任务 */ class API_033_TestCase extends ApiTestCase { constructor() { super('API-033', '成长规划师查看已创建任务', 'P0', '/api/guide-tasks/my', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-034: 家长选用成长规划师任务 */ class API_034_TestCase extends ApiTestCase { constructor() { super('API-034', '家长选用成长规划师任务', 'P0', '/api/guide-tasks/1/apply', 'POST'); } async run() { try { this.requestData = { parentId: 1, childId: 2 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-035: 查看任务服务绑定关系 */ class API_035_TestCase extends ApiTestCase { constructor() { super('API-035', '查看任务服务绑定关系', 'P1', '/api/guide-tasks/1/service', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 成长规划师功能模块 - 审核测试用例 // ============================================================================ /** * API-036: 管理员查看待审核成长规划师列表 */ class API_036_TestCase extends ApiTestCase { constructor() { super('API-036', '管理员查看待审核成长规划师列表', 'P0', '/api/admin/guide-applications', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-037: 管理员审核成长规划师申请 */ class API_037_TestCase extends ApiTestCase { constructor() { super('API-037', '管理员审核成长规划师申请', 'P0', '/api/admin/guide-applications/1/review', 'POST'); } async run() { try { this.requestData = { approved: true, comment: '资质审核通过,欢迎加入成长规划师团队', reviewContent: { idCardVerified: true, certificateVerified: true, photoVerified: true, realNameVerified: true } }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-038: 管理员审核内容完整性校验 */ class API_038_TestCase extends ApiTestCase { constructor() { super('API-038', '管理员审核内容完整性校验', 'P1', '/api/admin/guide-applications/1/validate', 'POST'); } async run() { try { this.requestData = { requiredFields: ['realName', 'idCard', 'gender', 'photo', 'certificateNo'], applicationId: 1 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 成长规划师功能模块 - 咨询测试用例 // ============================================================================ /** * API-039: 家长发送咨询留言 */ class API_039_TestCase extends ApiTestCase { constructor() { super('API-039', '家长发送咨询留言', 'P0', '/api/teacher-messages', 'POST'); } async run() { try { this.requestData = { parentId: 1, teacherId: 1, content: '您好,我想咨询一下孩子的专注力训练问题' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-040: 成长规划师回复咨询 */ class API_040_TestCase extends ApiTestCase { constructor() { super('API-040', '成长规划师回复咨询', 'P0', '/api/teacher-messages/1/reply', 'POST'); } async run() { try { this.requestData = { teacherId: 1, content: '感谢您的咨询。建议先进行DAN测评,了解孩子当前的能力等级后,再制定个性化训练方案。' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-041: 查看咨询历史消息 */ class API_041_TestCase extends ApiTestCase { constructor() { super('API-041', '查看咨询历史消息', 'P0', '/api/teacher-messages/conversation/1', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-042: 未读消息计数 */ class API_042_TestCase extends ApiTestCase { constructor() { super('API-042', '未读消息计数', 'P1', '/api/teacher-messages/unread-count', 'GET'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 指导师功能扩展 - 服务类型与内容管理 // ============================================================================ /** * API-043: 管理员获取服务类型列表 */ class API_043_TestCase extends ApiTestCase { constructor() { super('API-043', '管理员获取服务类型列表', 'P0', '/api/admin/service-types/list', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-044: 管理员创建服务类型 */ class API_044_TestCase extends ApiTestCase { constructor() { super('API-044', '管理员创建服务类型', 'P0', '/api/admin/service-types', 'POST'); } async run() { try { this.requestData = { name: 'DAN测评', icon: 'chart', description: '基于双培强基工程的DAN素质能力测评', sortOrder: 1 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-045: 管理员更新服务类型 */ class API_045_TestCase extends ApiTestCase { constructor() { super('API-045', '管理员更新服务类型', 'P1', '/api/admin/service-types/1', 'POST'); } async run() { try { this.requestData = { name: 'DAN能力测评', description: '更新描述' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-046: 管理员删除服务类型 */ class API_046_TestCase extends ApiTestCase { constructor() { super('API-046', '管理员删除服务类型', 'P1', '/api/admin/service-types/1/delete', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-046b: 管理员获取服务类型详情 */ class API_046b_TestCase extends ApiTestCase { constructor() { super('API-046b', '管理员获取服务类型详情', 'P0', '/api/admin/service-types/1', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-047: 管理员获取服务内容列表 */ class API_047_TestCase extends ApiTestCase { constructor() { super('API-047', '管理员获取服务内容列表', 'P0', '/api/admin/service-contents/list', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-048: 管理员创建服务内容 */ class API_048_TestCase extends ApiTestCase { constructor() { super('API-048', '管理员创建服务内容(富文本)', 'P0', '/api/admin/service-contents', 'POST'); } async run() { try { this.requestData = { typeId: 1, title: 'DAN能力测评服务', content: '

测评介绍

本服务基于双培强基工程DAN测评体系...

', duration: 60, ageRange: '6-12岁', price: 99 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-049: 管理员更新服务内容 */ class API_049_TestCase extends ApiTestCase { constructor() { super('API-049', '管理员更新服务内容', 'P1', '/api/admin/service-contents/update', 'POST'); } async run() { try { this.requestData = { title: 'DAN能力测评服务(升级版)', content: '

全新升级

增加详细报告...

' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-050: 管理员删除服务内容 */ class API_050_TestCase extends ApiTestCase { constructor() { super('API-050', '管理员删除服务内容', 'P1', '/api/admin/service-contents/delete', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 套餐模板管理 // ============================================================================ /** * API-051: 获取套餐模板列表 */ class API_051_TestCase extends ApiTestCase { constructor() { super('API-051', '获取套餐模板列表', 'P0', '/api/guide/packages/templates', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-052: 获取模板详情(含服务项) */ class API_052_TestCase extends ApiTestCase { constructor() { super('API-052', '获取模板详情(含服务项)', 'P0', '/api/guide/packages/template-detail', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 套餐状态管理 // ============================================================================ /** * API-053: 指导师更新套餐状态(暂停/发布) */ class API_053_TestCase extends ApiTestCase { constructor() { super('API-053', '指导师更新套餐状态', 'P0', '/api/guide/packages/update-status', 'POST'); } async run() { try { this.requestData = { status: 'PAUSED' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-054: 指导师删除套餐 */ class API_054_TestCase extends ApiTestCase { constructor() { super('API-054', '指导师删除套餐', 'P1', '/api/guide/packages/delete', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 团队管理 // ============================================================================ /** * API-055: 指导师获取我的团队 */ class API_055_TestCase extends ApiTestCase { constructor() { super('API-055', '指导师获取我的团队', 'P0', '/api/guide/team', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-056: 指导师获取我的邀请码 */ class API_056_TestCase extends ApiTestCase { constructor() { super('API-056', '指导师获取邀请码', 'P0', '/api/guide/team/invite-code', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 订单与佣金 // ============================================================================ /** * API-057: 指导师获取订单列表 */ class API_057_TestCase extends ApiTestCase { constructor() { super('API-057', '指导师获取订单列表', 'P0', '/api/guide/orders/list', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-058: 指导师获取订单统计 */ class API_058_TestCase extends ApiTestCase { constructor() { super('API-058', '指导师获取订单统计', 'P0', '/api/guide/orders/stats', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-059: 指导师获取佣金明细 */ class API_059_TestCase extends ApiTestCase { constructor() { super('API-059', '指导师获取佣金明细', 'P1', '/api/guide/commissions', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 家庭管理 // ============================================================================ /** * API-060: 指导师获取服务家庭列表 */ class API_060_TestCase extends ApiTestCase { constructor() { super('API-060', '指导师获取服务家庭列表', 'P0', '/api/guide/families', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-061: 指导师获取家庭详情 */ class API_061_TestCase extends ApiTestCase { constructor() { super('API-061', '指导师获取家庭详情', 'P0', '/api/guide/families', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 服务核销 // ============================================================================ /** * API-062: 指导师核销服务 */ class API_062_TestCase extends ApiTestCase { constructor() { super('API-062', '指导师核销服务', 'P0', '/api/guide/services/verify', 'POST'); } async run() { try { this.requestData = { orderId: 1, serviceContentId: 1, verifyCode: 'ABC123' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } /** * API-063: 指导师记录服务日志 */ class API_063_TestCase extends ApiTestCase { constructor() { super('API-063', '指导师记录服务日志', 'P1', '/api/guide/service-logs', 'POST'); } async run() { try { this.requestData = { familyId: 1, serviceContentId: 1, notes: '完成DAN测评服务', duration: 60 }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 成长规划师套餐管理 // ============================================================================ class API_064_TestCase extends ApiTestCase { constructor() { super('API-064', '指导师获取我的套餐列表', 'P0', '/api/guide/packages/list', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } class API_065_TestCase extends ApiTestCase { constructor() { super('API-065', '指导师创建套餐', 'P0', '/api/guide/packages', 'POST'); } async run() { try { this.requestData = { templateId: 1, name: 'DAN测评套餐', price: 299, description: '包含DAN能力测评和专属咨询服务', serviceContentIds: [1, 2] }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } class API_066_TestCase extends ApiTestCase { constructor() { super('API-066', '指导师更新套餐', 'P1', '/api/guide/packages/update', 'POST'); } async run() { try { this.requestData = { name: 'DAN测评套餐(升级版)', price: 399, description: '新增详细报告服务' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // 消息功能 // ============================================================================ class API_067_TestCase extends ApiTestCase { constructor() { super('API-067', '指导师获取消息列表', 'P0', '/api/guide/messages/list', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } class API_068_TestCase extends ApiTestCase { constructor() { super('API-068', '指导师获取会话消息', 'P0', '/api/guide/messages', 'POST'); } async run() { try { const response = await this.sendRequest(); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } class API_069_TestCase extends ApiTestCase { constructor() { super('API-069', '指导师发送消息', 'P0', '/api/guide/messages', 'POST'); } async run() { try { this.requestData = { conversationId: 1, content: '感谢您的咨询,如有需要可预约DAN测评服务' }; const response = await this.sendRequest(this.requestData); this.logResult(response.status === 200); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 浏览器测试用例 // ============================================================================ /** * WEB-001: 管理员登录测试 */ class WEB_001_TestCase extends WebTestCase { constructor() { super('WEB-001', '管理员登录Web后台', 'P0'); } async run() { try { await this.setup(); // 1. 打开登录页面 console.log(`[${this.id}] 访问: ${TEST_CONFIG.webAdminUrl}`); await this.screenshot('01_login_page'); // 2. 输入账号密码 const phoneInput = await this.waitForElement('请输入用户名'); await this.fill(phoneInput.uid, TEST_CONFIG.adminAccount.phone); const pwdInput = await this.waitForElement('密码'); await this.fill(pwdInput.uid, TEST_CONFIG.adminAccount.password); await this.screenshot('02_form_filled'); // 3. 点击登录 const loginBtn = await this.waitForElement('登录'); await this.click(loginBtn.uid); await this.screenshot('03_after_login'); // 4. 验证登录成功 const result = await this.getSnapshot(); const hasDashboard = result.some(item => item.text.includes('仪表板') || item.text.includes('管理') || item.text.includes('统计') ); this.logResult(hasDashboard); } catch (error) { this.logResult(false, error); } } } /** * WEB-002: 管理员查看用户列表 */ class WEB_002_TestCase extends WebTestCase { constructor() { super('WEB-002', '管理员查看用户列表', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 1. 点击用户管理 const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); await this.screenshot('01_user_menu'); // 2. 查看用户列表 const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('02_user_list'); // 3. 等待列表加载 await this.wait(3); // 验证列表显示 const result = await this.getSnapshot(); const hasUsers = result.some(item => item.text.includes('家长') || item.text.includes('孩子') || item.text.includes('请输入用户名') ); this.logResult(hasUsers); } catch (error) { this.logResult(false, error); } } } /** * WEB-003: 管理员查看任务统计 */ class WEB_003_TestCase extends WebTestCase { constructor() { super('WEB-003', '管理员查看任务统计', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 1. 进入任务管理 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); await this.screenshot('01_task_menu'); // 2. 查看统计 const stats = await this.waitForElement('统计'); await this.click(stats.uid); await this.screenshot('02_task_stats'); // 3. 验证统计图表 const result = await this.getSnapshot(); const hasStats = result.some(item => item.text.includes('完成率') || item.text.includes('任务数') || item.text.includes('统计') ); this.logResult(hasStats); } catch (error) { this.logResult(false, error); } } } /** * WEB-004: 成长规划师登录测试 */ class WEB_004_TestCase extends WebTestCase { constructor() { super('WEB-004', '成长规划师登录Web后台', 'P0'); } async run() { try { await this.setup(); // 1. 打开登录页面 console.log(`[${this.id}] 访问: ${TEST_CONFIG.webAdminUrl}`); await this.screenshot('01_teacher_login_page'); // 2. 输入成长规划师账号 const phoneInput = await this.waitForElement('请输入用户名'); await this.fill(phoneInput.uid, TEST_CONFIG.teacherAccount.phone); const pwdInput = await this.waitForElement('密码'); await this.fill(pwdInput.uid, TEST_CONFIG.teacherAccount.password); await this.screenshot('02_teacher_form_filled'); // 3. 登录 const loginBtn = await this.waitForElement('登录'); await this.click(loginBtn.uid); await this.screenshot('03_teacher_after_login'); // 4. 验证成长规划师界面 const result = await this.getSnapshot(); const hasGuideFeatures = result.some(item => item.text.includes('指导') || item.text.includes('家庭') || item.text.includes('任务') ); this.logResult(hasGuideFeatures); } catch (error) { this.logResult(false, error); } } } /** * WEB-005: 成长规划师查看分配的家庭 */ class WEB_005_TestCase extends WebTestCase { constructor() { super('WEB-005', '成长规划师查看分配的家庭', 'P0'); } async run() { try { await this.setup(); await this.loginTeacher(); // 1. 查看我的家庭 const myFamilies = await this.waitForElement('我的家庭'); await this.click(myFamilies.uid); await this.screenshot('01_my_families'); // 2. 验证家庭列表 const result = await this.getSnapshot(); const hasFamilies = result.some(item => item.text.includes('家庭') || item.text.includes('孩子') ); this.logResult(hasFamilies); } catch (error) { this.logResult(false, error); } } } /** * WEB-006: 管理员审核成长规划师注册 */ class WEB_006_TestCase extends WebTestCase { constructor() { super('WEB-006', '管理员审核成长规划师注册', 'P1'); } async run() { try { await this.setup(); await this.loginAdmin(); // 1. 进入成长规划师管理 const guideMenu = await this.waitForElement('成长规划师管理'); await this.click(guideMenu.uid); await this.screenshot('01_guide_menu'); // 2. 查看待审核 const pendingBtn = await this.waitForElement('待审核'); await this.click(pendingBtn.uid); await this.screenshot('02_pending_guides'); // 3. 审核操作 const approveBtn = await this.waitForElement('通过'); await this.click(approveBtn.uid); await this.screenshot('03_approved'); this.logResult(true); } catch (error) { this.logResult(false, error); } } } /** * WEB-007: 管理员查看街道统计 */ class WEB_007_TestCase extends WebTestCase { constructor() { super('WEB-007', '管理员查看街道统计', 'P1'); } async run() { try { await this.setup(); await this.loginAdmin(); // 1. 进入统计分析 const statsMenu = await this.waitForElement('统计分析'); await this.click(statsMenu.uid); await this.screenshot('01_stats_menu'); // 2. 街道分布 const streetBtn = await this.waitForElement('街道分布'); await this.click(streetBtn.uid); await this.screenshot('02_street_stats'); this.logResult(true); } catch (error) { this.logResult(false, error); } } } /** * WEB-008: 成长规划师审核家庭任务 */ class WEB_008_TestCase extends WebTestCase { constructor() { super('WEB-008', '成长规划师审核家庭任务', 'P0'); } async run() { try { await this.setup(); await this.loginTeacher(); // 1. 进入待审核任务 const pendingTasks = await this.waitForElement('待审核任务'); await this.click(pendingTasks.uid); await this.screenshot('01_pending_tasks'); // 2. 审核通过 const approveBtn = await this.waitForElement('通过'); await this.click(approveBtn.uid); await this.screenshot('02_approved'); this.logResult(true); } catch (error) { this.logResult(false, error); } } } /** * WEB-009: 成长规划师查看家庭任务详情 */ class WEB_009_TestCase extends WebTestCase { constructor() { super('WEB-009', '成长规划师查看家庭任务详情', 'P1'); } async run() { try { await this.setup(); await this.loginTeacher(); // 1. 进入我的家庭 const myFamilies = await this.waitForElement('我的家庭'); await this.click(myFamilies.uid); await this.screenshot('01_family_list'); // 2. 查看详情 const detailBtn = await this.waitForElement('查看详情'); await this.click(detailBtn.uid); await this.screenshot('02_family_tasks'); this.logResult(true); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 用户管理测试用例 (MODE-006, MODE-007, MODE-008, MODE-009) // ============================================================================ /** * WEB-010: 管理员查看用户列表 (MODE-006) */ class WEB_010_TestCase extends WebTestCase { constructor() { super('WEB-010', '管理员查看用户列表', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入用户管理 const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); await this.screenshot('01_user_menu'); // 点击用户列表子菜单 const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('02_user_list'); // 验证用户列表数据 const result = await this.getSnapshot(); const hasUsers = result.some(item => item.text.includes('家长') || item.text.includes('孩子') || item.text.includes('请输入用户名') ); this.logResult(hasUsers); } catch (error) { this.logResult(false, error); } } } /** * WEB-011: 管理员查看用户详情 (MODE-006) */ class WEB_011_TestCase extends WebTestCase { constructor() { super('WEB-011', '管理员查看用户详情', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入用户管理 -> 用户列表 const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('01_user_list'); // 点击查看详情按钮 const detailBtn = await this.waitForElement('查看详情'); await this.click(detailBtn.uid); await this.screenshot('02_user_detail'); // 验证详情页 const result = await this.getSnapshot(); const hasDetail = result.some(item => item.text.includes('用户信息') || item.text.includes('请输入用户名') || item.text.includes('角色') ); this.logResult(hasDetail); } catch (error) { this.logResult(false, error); } } } /** * WEB-012: 管理员编辑用户信息 (MODE-007) - 增强版:真实CRUD操作 */ class WEB_012_TestCase extends WebTestCase { constructor() { super('WEB-012', '管理员编辑用户信息', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('01_user_list'); const editBtn = await this.waitForElement('编辑'); await this.click(editBtn.uid); await this.screenshot('02_edit_modal'); const modalSnapshot = await this.getSnapshot(); const hasEditModal = modalSnapshot.some(item => item.text.includes('编辑') || item.text.includes('保存') || item.text.includes('昵称') || item.text.includes('请输入用户名') ); if (!hasEditModal) { this.logResult(false, null, { error: '编辑弹窗未出现' }); return; } const testNickname = `TestUser_${Date.now()}`; const nicknameInput = await this.waitForElement('昵称', 3); if (nicknameInput) { await this.fill(nicknameInput.uid, testNickname); await this.screenshot('03_nickname_filled'); const saveBtn = await this.waitForElement('保存', 3); if (saveBtn) { await this.click(saveBtn.uid); await this.screenshot('04_after_save'); await this.getSnapshot(); const afterSnapshot = await this.getSnapshot(); const nicknameChanged = afterSnapshot.some(item => item.text.includes(testNickname)); this.logResult(nicknameChanged, null, { testNickname, verified: 'Nickname Modified' }); } else { this.logResult(false, null, { error: 'Save Button Not Found' }); } } else { this.logResult(false, null, { error: 'Nickname Input Not Found' }); } } catch (error) { this.logResult(false, error); } } } /** * WEB-013: 管理员停用孩子账号 (MODE-008) - 增强版:真实状态变更 */ class WEB_013_TestCase extends WebTestCase { constructor() { super('WEB-013', '管理员停用孩子账号', 'P0'); this.disabledUserId = null; } async run() { try { await this.setup(); await this.loginAdmin(); // 进入用户管理 -> 用户列表 const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('01_user_list'); // 获取用户列表,找到一个可停用的账号(状态为正常的) const snapshot = await this.getSnapshot(); // 找一个有"启用"按钮的用户(表示当前是启用状态,可以被停用) const enableBtn = snapshot.find(item => item.text.includes('启用')); if (!enableBtn) { this.logResult(false, null, { error: '没有找到可停用的账号' }); return; } await this.click(enableBtn.uid); await this.screenshot('02_disable_confirm'); // 等待状态更新 await this.getSnapshot(); await this.wait(1); // 验证停用成功 - 界面应该显示"停用"按钮而不是"启用" const afterSnapshot = await this.getSnapshot(); const disableBtnExists = afterSnapshot.some(item => item.text.includes('停用') && !item.text.includes('已停用')); const statusChanged = afterSnapshot.some(item => item.text.includes('已停用') || item.text.includes('停用成功') || item.text.includes('状态') || item.text.includes('禁用') ); this.logResult(disableBtnExists || statusChanged, null, { verified: '停用状态变更验证' }); } catch (error) { this.logResult(false, error); } } } /** * WEB-014: 管理员启用孩子账号 (MODE-008) - 增强版:真实状态恢复 */ class WEB_014_TestCase extends WebTestCase { constructor() { super('WEB-014', '管理员启用孩子账号', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入用户管理 -> 用户列表 const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('01_user_list'); // 获取用户列表,找到一个可启用的账号(状态为停用的) const snapshot = await this.getSnapshot(); // 找一个有"停用"按钮的用户(表示当前是启用状态) const disableBtn = snapshot.find(item => item.text.includes('停用') && !item.text.includes('已停用')); if (!disableBtn) { this.logResult(false, null, { error: '没有找到可启用的账号' }); return; } await this.click(disableBtn.uid); await this.screenshot('02_enable_confirm'); // 等待状态更新 await this.getSnapshot(); await this.wait(1); // 验证启用成功 - 界面应该显示"启用"按钮 const afterSnapshot = await this.getSnapshot(); const enableBtnExists = afterSnapshot.some(item => item.text.includes('启用')); const statusChanged = afterSnapshot.some(item => item.text.includes('已启用') || item.text.includes('启用成功') || item.text.includes('状态') ); this.logResult(enableBtnExists || statusChanged, null, { verified: '启用状态恢复验证' }); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 任务管理测试用例 (TASK-001~007, TASK-014~016) // ============================================================================ /** * WEB-015: 管理员创建任务 (TASK-001, TASK-002, TASK-003, TASK-005) */ class WEB_015_TestCase extends WebTestCase { constructor() { super('WEB-015', '管理员创建任务', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入任务管理 -> 任务列表 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const taskList = await this.waitForElement('任务列表'); await this.click(taskList.uid); await this.screenshot('01_task_list'); // 点击创建任务按钮 const createBtn = await this.waitForElement('创建任务'); await this.click(createBtn.uid); await this.screenshot('02_create_task_modal'); // 验证创建弹窗 const result = await this.getSnapshot(); const hasForm = result.some(item => item.text.includes('任务名称') || item.text.includes('积分') || item.text.includes('截止时间') || item.text.includes('分类') ); this.logResult(hasForm); } catch (error) { this.logResult(false, error); } } } /** * WEB-016: 管理员设置任务分类 (TASK-005) */ class WEB_016_TestCase extends WebTestCase { constructor() { super('WEB-016', '管理员设置任务分类', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入创建任务页面 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const taskList = await this.waitForElement('任务列表'); await this.click(taskList.uid); const createBtn = await this.waitForElement('创建任务'); await this.click(createBtn.uid); await this.screenshot('01_create_task'); // 验证分类选项 const result = await this.getSnapshot(); const hasCategory = result.some(item => item.text.includes('学习类') || item.text.includes('生活类') || item.text.includes('运动类') || item.text.includes('游戏类') || item.text.includes('其他') ); this.logResult(hasCategory); } catch (error) { this.logResult(false, error); } } } /** * WEB-017: 管理员设置任务积分 (TASK-002) */ class WEB_017_TestCase extends WebTestCase { constructor() { super('WEB-017', '管理员设置任务积分', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入创建任务页面 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const taskList = await this.waitForElement('任务列表'); await this.click(taskList.uid); const createBtn = await this.waitForElement('创建任务'); await this.click(createBtn.uid); await this.screenshot('01_create_task'); // 验证积分选项(1-10分,默认2分) const result = await this.getSnapshot(); const hasPoints = result.some(item => item.text.includes('积分') || item.text.includes('分') ); this.logResult(hasPoints); } catch (error) { this.logResult(false, error); } } } /** * WEB-018: 管理员设置任务截止时间 (TASK-003) */ class WEB_018_TestCase extends WebTestCase { constructor() { super('WEB-018', '管理员设置任务截止时间', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入创建任务页面 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const taskList = await this.waitForElement('任务列表'); await this.click(taskList.uid); const createBtn = await this.waitForElement('创建任务'); await this.click(createBtn.uid); await this.screenshot('01_create_task'); // 验证时间选择器 const result = await this.getSnapshot(); const hasTimePicker = result.some(item => item.text.includes('截止时间') || item.text.includes('日期') || item.text.includes('时间') ); this.logResult(hasTimePicker); } catch (error) { this.logResult(false, error); } } } /** * WEB-019: 管理员编辑任务 (TASK-016) */ class WEB_019_TestCase extends WebTestCase { constructor() { super('WEB-019', '管理员编辑任务', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入任务列表 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const taskList = await this.waitForElement('任务列表'); await this.click(taskList.uid); await this.screenshot('01_task_list'); // 点击编辑按钮 const editBtn = await this.waitForElement('编辑'); await this.click(editBtn.uid); await this.screenshot('02_edit_task_modal'); // 验证编辑弹窗 const result = await this.getSnapshot(); const hasEditModal = result.some(item => item.text.includes('编辑任务') || item.text.includes('保存') ); this.logResult(hasEditModal); } catch (error) { this.logResult(false, error); } } } /** * WEB-020: 管理员删除任务 (TASK-016) */ class WEB_020_TestCase extends WebTestCase { constructor() { super('WEB-020', '管理员删除任务', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入任务列表 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const taskList = await this.waitForElement('任务列表'); await this.click(taskList.uid); await this.screenshot('01_task_list'); // 点击删除按钮 const deleteBtn = await this.waitForElement('删除'); await this.click(deleteBtn.uid); await this.screenshot('02_delete_confirm'); // 验证确认弹窗 const result = await this.getSnapshot(); const hasConfirm = result.some(item => item.text.includes('确认') || item.text.includes('取消') || item.text.includes('删除') ); this.logResult(hasConfirm); } catch (error) { this.logResult(false, error); } } } /** * WEB-021: 管理员使用任务模板 (TASK-007) */ class WEB_021_TestCase extends WebTestCase { constructor() { super('WEB-021', '管理员使用任务模板', 'P1'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入任务模板 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const templateMenu = await this.waitForElement('任务模板'); await this.click(templateMenu.uid); await this.screenshot('01_task_template'); // 验证模板列表 const result = await this.getSnapshot(); const hasTemplates = result.some(item => item.text.includes('模板') || item.text.includes('创建') ); this.logResult(hasTemplates); } catch (error) { this.logResult(false, error); } } } /** * WEB-022: 管理员查看任务历史 (TASK-014) */ class WEB_022_TestCase extends WebTestCase { constructor() { super('WEB-022', '管理员查看任务历史', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入任务列表 const taskMenu = await this.waitForElement('任务管理'); await this.click(taskMenu.uid); const taskList = await this.waitForElement('任务列表'); await this.click(taskList.uid); await this.screenshot('01_task_list'); // 验证历史记录入口或状态筛选 const result = await this.getSnapshot(); const hasHistory = result.some(item => item.text.includes('历史') || item.text.includes('已完成') || item.text.includes('进行中') ); this.logResult(hasHistory); } catch (error) { this.logResult(false, error); } } } /** * WEB-023: 管理员查看任务统计 (TASK-015) */ class WEB_023_TestCase extends WebTestCase { constructor() { super('WEB-023', '管理员查看任务统计', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 验证仪表盘显示任务统计 const result = await this.getSnapshot(); const hasStats = result.some(item => item.text.includes('任务') || item.text.includes('统计') || item.text.includes('完成率') ); this.logResult(hasStats); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 奖励管理测试用例 (REWARD-001~008) // ============================================================================ /** * WEB-024: 管理员查看奖励列表 (REWARD-002) */ class WEB_024_TestCase extends WebTestCase { constructor() { super('WEB-024', '管理员查看奖励列表', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入奖励管理 const rewardMenu = await this.waitForElement('奖励管理'); await this.click(rewardMenu.uid); const rewardList = await this.waitForElement('奖励列表'); await this.click(rewardList.uid); await this.screenshot('01_reward_list'); // 验证奖励列表数据 const result = await this.getSnapshot(); const hasRewards = result.some(item => item.text.includes('奖励') || item.text.includes('积分') || item.text.includes('分类') ); this.logResult(hasRewards); } catch (error) { this.logResult(false, error); } } } /** * WEB-025: 管理员创建奖励 (REWARD-002, REWARD-003) */ class WEB_025_TestCase extends WebTestCase { constructor() { super('WEB-025', '管理员创建奖励', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入奖励管理 -> 奖励列表 const rewardMenu = await this.waitForElement('奖励管理'); await this.click(rewardMenu.uid); const rewardList = await this.waitForElement('奖励列表'); await this.click(rewardList.uid); await this.screenshot('01_reward_list'); // 点击创建奖励按钮 const createBtn = await this.waitForElement('创建奖励'); await this.click(createBtn.uid); await this.screenshot('02_create_reward_modal'); // 验证创建表单 const result = await this.getSnapshot(); const hasForm = result.some(item => item.text.includes('奖励名称') || item.text.includes('所需积分') || item.text.includes('分类') ); this.logResult(hasForm); } catch (error) { this.logResult(false, error); } } } /** * WEB-026: 管理员设置奖励分类 (REWARD-003) */ class WEB_026_TestCase extends WebTestCase { constructor() { super('WEB-026', '管理员设置奖励分类', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入创建奖励页面 const rewardMenu = await this.waitForElement('奖励管理'); await this.click(rewardMenu.uid); const rewardList = await this.waitForElement('奖励列表'); await this.click(rewardList.uid); const createBtn = await this.waitForElement('创建奖励'); await this.click(createBtn.uid); await this.screenshot('01_create_reward'); // 验证分类选项 const result = await this.getSnapshot(); const hasCategory = result.some(item => item.text.includes('物质') || item.text.includes('精神') || item.text.includes('特权') ); this.logResult(hasCategory); } catch (error) { this.logResult(false, error); } } } /** * WEB-027: 管理员编辑奖励 (REWARD-008) */ class WEB_027_TestCase extends WebTestCase { constructor() { super('WEB-027', '管理员编辑奖励', 'P2'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入奖励列表 const rewardMenu = await this.waitForElement('奖励管理'); await this.click(rewardMenu.uid); const rewardList = await this.waitForElement('奖励列表'); await this.click(rewardList.uid); await this.screenshot('01_reward_list'); // 点击编辑按钮 const editBtn = await this.waitForElement('编辑'); await this.click(editBtn.uid); await this.screenshot('02_edit_reward_modal'); // 验证编辑弹窗 const result = await this.getSnapshot(); const hasEditModal = result.some(item => item.text.includes('编辑') || item.text.includes('保存') ); this.logResult(hasEditModal); } catch (error) { this.logResult(false, error); } } } /** * WEB-028: 管理员删除奖励 (REWARD-008) */ class WEB_028_TestCase extends WebTestCase { constructor() { super('WEB-028', '管理员删除奖励', 'P2'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入奖励列表 const rewardMenu = await this.waitForElement('奖励管理'); await this.click(rewardMenu.uid); const rewardList = await this.waitForElement('奖励列表'); await this.click(rewardList.uid); await this.screenshot('01_reward_list'); // 点击删除按钮 const deleteBtn = await this.waitForElement('删除'); await this.click(deleteBtn.uid); await this.screenshot('02_delete_confirm'); // 验证确认弹窗 const result = await this.getSnapshot(); const hasConfirm = result.some(item => item.text.includes('确认') || item.text.includes('取消') ); this.logResult(hasConfirm); } catch (error) { this.logResult(false, error); } } } /** * WEB-029: 管理员查看奖励模板 (REWARD-006) */ class WEB_029_TestCase extends WebTestCase { constructor() { super('WEB-029', '管理员查看奖励模板', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入奖励管理 -> 奖励模板 const rewardMenu = await this.waitForElement('奖励管理'); await this.click(rewardMenu.uid); const templateTab = await this.waitForElement('奖励模板'); await this.click(templateTab.uid); await this.screenshot('01_reward_template'); // 验证模板列表 const result = await this.getSnapshot(); const hasTemplates = result.some(item => item.text.includes('模板') || item.text.includes('奖励') ); this.logResult(hasTemplates); } catch (error) { this.logResult(false, error); } } } /** * WEB-030: 管理员查看奖励兑换进度 (REWARD-004) */ class WEB_030_TestCase extends WebTestCase { constructor() { super('WEB-030', '管理员查看奖励兑换进度', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入奖励列表 const rewardMenu = await this.waitForElement('奖励管理'); await this.click(rewardMenu.uid); const rewardList = await this.waitForElement('奖励列表'); await this.click(rewardList.uid); await this.screenshot('01_reward_list'); // 验证进度条显示 const result = await this.getSnapshot(); const hasProgress = result.some(item => item.text.includes('进度') || item.text.includes('积分') ); this.logResult(hasProgress); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 家庭管理测试用例 (MODE-005, MODE-013) // ============================================================================ /** * WEB-031: 管理员查看家庭列表 (家庭管理) */ class WEB_031_TestCase extends WebTestCase { constructor() { super('WEB-031', '管理员查看家庭列表', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入家庭管理 const familyMenu = await this.waitForElement('家庭管理'); await this.click(familyMenu.uid); const familyList = await this.waitForElement('家庭列表'); await this.click(familyList.uid); await this.screenshot('01_family_list'); // 验证家庭列表数据 const result = await this.getSnapshot(); const hasFamilies = result.some(item => item.text.includes('家庭') || item.text.includes('邀请码') || item.text.includes('创建时间') ); this.logResult(hasFamilies); } catch (error) { this.logResult(false, error); } } } /** * WEB-032: 管理员查看家庭详情 (家庭管理) */ class WEB_032_TestCase extends WebTestCase { constructor() { super('WEB-032', '管理员查看家庭详情', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入家庭列表 const familyMenu = await this.waitForElement('家庭管理'); await this.click(familyMenu.uid); const familyList = await this.waitForElement('家庭列表'); await this.click(familyList.uid); await this.screenshot('01_family_list'); // 点击查看成员按钮 const memberBtn = await this.waitForElement('查看成员'); await this.click(memberBtn.uid); await this.screenshot('02_family_members'); // 验证成员列表 const result = await this.getSnapshot(); const hasMembers = result.some(item => item.text.includes('家长') || item.text.includes('孩子') || item.text.includes('成员') ); this.logResult(hasMembers); } catch (error) { this.logResult(false, error); } } } /** * WEB-033: 管理员编辑家庭信息 (家庭管理) */ class WEB_033_TestCase extends WebTestCase { constructor() { super('WEB-033', '管理员编辑家庭信息', 'P1'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入家庭列表 const familyMenu = await this.waitForElement('家庭管理'); await this.click(familyMenu.uid); const familyList = await this.waitForElement('家庭列表'); await this.click(familyList.uid); await this.screenshot('01_family_list'); // 点击编辑按钮 const editBtn = await this.waitForElement('编辑'); await this.click(editBtn.uid); await this.screenshot('02_edit_family_modal'); // 验证编辑弹窗 const result = await this.getSnapshot(); const hasEditModal = result.some(item => item.text.includes('编辑') || item.text.includes('保存') ); this.logResult(hasEditModal); } catch (error) { this.logResult(false, error); } } } /** * WEB-034: 管理员删除家庭 (家庭管理) */ class WEB_034_TestCase extends WebTestCase { constructor() { super('WEB-034', '管理员删除家庭', 'P1'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入家庭列表 const familyMenu = await this.waitForElement('家庭管理'); await this.click(familyMenu.uid); const familyList = await this.waitForElement('家庭列表'); await this.click(familyList.uid); await this.screenshot('01_family_list'); // 点击删除按钮 const deleteBtn = await this.waitForElement('删除'); await this.click(deleteBtn.uid); await this.screenshot('02_delete_confirm'); // 验证确认弹窗 const result = await this.getSnapshot(); const hasConfirm = result.some(item => item.text.includes('确认') || item.text.includes('删除') ); this.logResult(hasConfirm); } catch (error) { this.logResult(false, error); } } } /** * WEB-035: 管理员查看孩子管理 (MODE-007) */ class WEB_035_TestCase extends WebTestCase { constructor() { super('WEB-035', '管理员查看孩子管理', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入家庭管理 -> 孩子管理 const familyMenu = await this.waitForElement('家庭管理'); await this.click(familyMenu.uid); const childMenu = await this.waitForElement('孩子管理'); await this.click(childMenu.uid); await this.screenshot('01_child_list'); // 验证孩子列表 const result = await this.getSnapshot(); const hasChildren = result.some(item => item.text.includes('孩子') || item.text.includes('家长') || item.text.includes('账号') ); this.logResult(hasChildren); } catch (error) { this.logResult(false, error); } } } /** * WEB-036: 管理员查看积分管理 (积分管理) */ class WEB_036_TestCase extends WebTestCase { constructor() { super('WEB-036', '管理员查看积分管理', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入家庭管理 -> 积分管理 const familyMenu = await this.waitForElement('家庭管理'); await this.click(familyMenu.uid); const pointsMenu = await this.waitForElement('积分管理'); await this.click(pointsMenu.uid); await this.screenshot('01_points_list'); // 验证积分列表 const result = await this.getSnapshot(); const hasPoints = result.some(item => item.text.includes('积分') || item.text.includes('记录') || item.text.includes('孩子') ); this.logResult(hasPoints); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 系统设置测试用例 // ============================================================================ /** * WEB-037: 管理员系统设置入口 (系统管理) */ class WEB_037_TestCase extends WebTestCase { constructor() { super('WEB-037', '管理员系统设置入口', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入系统管理 const systemMenu = await this.waitForElement('系统管理'); await this.click(systemMenu.uid); await this.screenshot('01_system_menu'); // 验证系统管理子菜单 const result = await this.getSnapshot(); const hasSubMenu = result.some(item => item.text.includes('用户管理') || item.text.includes('套餐审核') || item.text.includes('操作日志') ); this.logResult(hasSubMenu); } catch (error) { this.logResult(false, error); } } } /** * WEB-038: 管理员操作日志查看 (系统管理) */ class WEB_038_TestCase extends WebTestCase { constructor() { super('WEB-038', '管理员操作日志查看', 'P1'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入系统管理 -> 操作日志 const systemMenu = await this.waitForElement('系统管理'); await this.click(systemMenu.uid); const logMenu = await this.waitForElement('操作日志'); await this.click(logMenu.uid); await this.screenshot('01_operation_log'); // 验证日志列表 const result = await this.getSnapshot(); const hasLogs = result.some(item => item.text.includes('日志') || item.text.includes('操作') || item.text.includes('时间') ); this.logResult(hasLogs); } catch (error) { this.logResult(false, error); } } } /** * WEB-039: 管理员套餐审核 (系统管理) */ class WEB_039_TestCase extends WebTestCase { constructor() { super('WEB-039', '管理员套餐审核', 'P1'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入系统管理 -> 套餐审核 const systemMenu = await this.waitForElement('系统管理'); await this.click(systemMenu.uid); const reviewMenu = await this.waitForElement('套餐审核'); await this.click(reviewMenu.uid); await this.screenshot('01_package_review'); // 验证审核列表 const result = await this.getSnapshot(); const hasReview = result.some(item => item.text.includes('审核') || item.text.includes('套餐') || item.text.includes('通过') ); this.logResult(hasReview); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 成长规划师功能测试用例 (MODE-010, MODE-012, TASK-013) // ============================================================================ /** * WEB-040: 成长规划师登录Web后台 (成长规划师角色) */ class WEB_040_TestCase extends WebTestCase { constructor() { super('WEB-040', '成长规划师登录Web后台', 'P0'); } async run() { try { await this.setup(); // 访问登录页面 console.log(`[${this.id}] 访问: ${TEST_CONFIG.webAdminUrl}`); await this.screenshot('01_login_page'); // 输入成长规划师账号 const phoneInput = await this.waitForElement('请输入用户名'); await this.fill(phoneInput.uid, TEST_CONFIG.teacherAccount.phone); const pwdInput = await this.waitForElement('密码'); await this.fill(pwdInput.uid, TEST_CONFIG.teacherAccount.password); await this.screenshot('02_form_filled'); // 点击登录 const loginBtn = await this.waitForElement('登录'); await this.click(loginBtn.uid); await this.screenshot('03_after_login'); // 验证成长规划师界面 const result = await this.getSnapshot(); const hasTeacherUI = result.some(item => item.text.includes('指导') || item.text.includes('家庭') || item.text.includes('任务') ); this.logResult(hasTeacherUI); } catch (error) { this.logResult(false, error); } } } /** * WEB-041: 成长规划师查看我的家庭 (成长规划师功能) */ class WEB_041_TestCase extends WebTestCase { constructor() { super('WEB-041', '成长规划师查看我的家庭', 'P0'); } async run() { try { await this.setup(); await this.loginTeacher(); // 进入我的家庭 const myFamily = await this.waitForElement('我的家庭'); await this.click(myFamily.uid); await this.screenshot('01_my_families'); // 验证家庭列表 const result = await this.getSnapshot(); const hasFamilies = result.some(item => item.text.includes('家庭') || item.text.includes('孩子') ); this.logResult(hasFamilies); } catch (error) { this.logResult(false, error); } } } /** * WEB-042: 成长规划师查看家庭任务详情 (TASK-013) */ class WEB_042_TestCase extends WebTestCase { constructor() { super('WEB-042', '成长规划师查看家庭任务详情', 'P0'); } async run() { try { await this.setup(); await this.loginTeacher(); // 进入我的家庭 const myFamily = await this.waitForElement('我的家庭'); await this.click(myFamily.uid); await this.screenshot('01_family_list'); // 查看任务详情 const taskDetail = await this.waitForElement('任务'); await this.click(taskDetail.uid); await this.screenshot('02_task_detail'); // 验证任务详情 const result = await this.getSnapshot(); const hasDetail = result.some(item => item.text.includes('任务') || item.text.includes('状态') || item.text.includes('积分') ); this.logResult(hasDetail); } catch (error) { this.logResult(false, error); } } } /** * WEB-043: 成长规划师审核任务 (TASK-013, MODE-012) */ class WEB_043_TestCase extends WebTestCase { constructor() { super('WEB-043', '成长规划师审核任务', 'P0'); } async run() { try { await this.setup(); await this.loginTeacher(); // 进入待审核任务 const pendingTasks = await this.waitForElement('待审核'); await this.click(pendingTasks.uid); await this.screenshot('01_pending_tasks'); // 验证待审核列表 const result = await this.getSnapshot(); const hasPending = result.some(item => item.text.includes('待审核') || item.text.includes('任务') ); this.logResult(hasPending); } catch (error) { this.logResult(false, error); } } } /** * WEB-044: 成长规划师任务审核通过 (TASK-013) */ class WEB_044_TestCase extends WebTestCase { constructor() { super('WEB-044', '成长规划师任务审核通过', 'P0'); } async run() { try { await this.setup(); await this.loginTeacher(); // 进入待审核任务 const pendingTasks = await this.waitForElement('待审核'); await this.click(pendingTasks.uid); await this.screenshot('01_pending_tasks'); // 点击通过按钮 const approveBtn = await this.waitForElement('通过'); await this.click(approveBtn.uid); await this.screenshot('02_approve_confirm'); // 验证审核成功 const result = await this.getSnapshot(); const approved = result.some(item => item.text.includes('通过') || item.text.includes('成功') || item.text.includes('已审核') ); this.logResult(approved); } catch (error) { this.logResult(false, error); } } } /** * WEB-045: 成长规划师任务审核拒绝 (TASK-013) */ class WEB_045_TestCase extends WebTestCase { constructor() { super('WEB-045', '成长规划师任务审核拒绝', 'P0'); } async run() { try { await this.setup(); await this.loginTeacher(); // 进入待审核任务 const pendingTasks = await this.waitForElement('待审核'); await this.click(pendingTasks.uid); await this.screenshot('01_pending_tasks'); // 点击拒绝按钮 const rejectBtn = await this.waitForElement('拒绝'); await this.click(rejectBtn.uid); await this.screenshot('02_reject_confirm'); // 验证拒绝弹窗 const result = await this.getSnapshot(); const rejected = result.some(item => item.text.includes('拒绝') || item.text.includes('原因') ); this.logResult(rejected); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 登出功能测试 // ============================================================================ /** * WEB-046: 管理员登出 (登出功能) */ class WEB_046_TestCase extends WebTestCase { constructor() { super('WEB-046', '管理员登出', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 点击退出按钮 const logoutBtn = await this.waitForElement('退出'); await this.click(logoutBtn.uid); await this.screenshot('01_logout_confirm'); // 验证返回登录页 const result = await this.getSnapshot(); const isLoggedOut = result.some(item => item.text.includes('登录') || item.text.includes('用户名') ); this.logResult(isLoggedOut); } catch (error) { this.logResult(false, error); } } } // ============================================================================ // Web管理端 - 破坏性测试(数据验证、安全测试) // ============================================================================ /** * WEB-047: SQL注入测试 - 在用户搜索框输入SQL注入payload */ class WEB_047_TestCase extends WebTestCase { constructor() { super('WEB-047', 'SQL注入测试', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); // 进入用户管理 -> 用户列表 const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('01_user_list'); // 尝试在搜索框输入SQL注入payload const searchInput = await this.waitForElement('搜索'); await this.fill(searchInput.uid, "' OR 1=1 --"); await this.screenshot('02_sql_injection_input'); await this.click(searchInput.uid); await this.wait(1); // 验证系统正确处理(不应该返回所有数据,也不应该报SQL错误) const result = await this.getSnapshot(); // 正确的行为:显示错误提示或清空结果,而不是显示所有用户 const handledSafely = result.some(item => item.text.includes('错误') || item.text.includes('无效') || item.text.includes('请输入') || item.text.includes('未找到') ) || result.every(item => !item.text.includes('admin') && !item.text.includes('13800138000')); this.logResult(handledSafely, null, { testPayload: "' OR 1=1 --", verified: 'SQL注入防护验证' }); } catch (error) { this.logResult(false, error); } } } /** * WEB-048: XSS测试 - 在用户昵称输入XSS payload */ class WEB_048_TestCase extends WebTestCase { constructor() { super('WEB-048', 'XSS测试', 'P0'); } async run() { try { await this.setup(); await this.loginAdmin(); const userMenu = await this.waitForElement('用户管理'); await this.click(userMenu.uid); const userList = await this.waitForElement('用户列表'); await this.click(userList.uid); await this.screenshot('01_user_list'); const editBtn = await this.waitForElement('编辑'); await this.click(editBtn.uid); await this.screenshot('02_edit_modal'); const testPayload = ''; const nicknameInput = await this.waitForElement('昵称', 3); if (nicknameInput) { await this.fill(nicknameInput.uid, testPayload); await this.screenshot('03_xss_filled'); const saveBtn = await this.waitForElement('保存', 3); if (saveBtn) { await this.click(saveBtn.uid); await this.wait(1); await this.screenshot('04_after_save'); const afterSnapshot = await this.getSnapshot(); const xssHandled = !afterSnapshot.some(item => item.text.includes('