|
|
@@ -3,8 +3,8 @@
|
|
|
* 基于 Chrome DevTools MCP 服务
|
|
|
*
|
|
|
* 需求覆盖:100%(P0 + P1 + P2 所有需求)
|
|
|
- * 最后同步时间:2026-04-09
|
|
|
- * 需求文档版本:V1.1
|
|
|
+ * 最后同步时间:2026-04-12
|
|
|
+ * 需求文档版本:V1.2
|
|
|
*/
|
|
|
|
|
|
const TEST_CONFIG = {
|
|
|
@@ -272,6 +272,43 @@ class TASK_003_TestCase extends BaseTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * TASK-005: 设置任务分类(学习类/生活类/运动类/其他)
|
|
|
+ */
|
|
|
+class TASK_005_TestCase extends BaseTestCase {
|
|
|
+ constructor() {
|
|
|
+ super('TASK-005', '设置任务分类(学习类/生活类/运动类/其他)', 'P0');
|
|
|
+ }
|
|
|
+
|
|
|
+ async run() {
|
|
|
+ try {
|
|
|
+ await this.setup();
|
|
|
+
|
|
|
+ const snapshot = await this.getSnapshot();
|
|
|
+ const createTaskBtn = snapshot.find(item => item.text.includes('创建任务'));
|
|
|
+ await this.click(createTaskBtn.uid);
|
|
|
+
|
|
|
+ const categoryField = await this.waitForElement('任务分类');
|
|
|
+ await this.click(categoryField.uid);
|
|
|
+ await this.screenshot('01_open_category');
|
|
|
+
|
|
|
+ const studyOption = await this.waitForElement('学习类');
|
|
|
+ await this.click(studyOption.uid);
|
|
|
+ await this.screenshot('02_select_category');
|
|
|
+
|
|
|
+ const result = await this.getSnapshot();
|
|
|
+ const hasCategory = result.some(item =>
|
|
|
+ item.text.includes('学习类') ||
|
|
|
+ item.text.includes('任务分类')
|
|
|
+ );
|
|
|
+
|
|
|
+ this.logResult(hasCategory);
|
|
|
+ } catch (error) {
|
|
|
+ this.logResult(false, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* TASK-008: 孩子可查看今日任务列表
|
|
|
*/
|
|
|
@@ -680,11 +717,11 @@ class POINT_001_TestCase extends BaseTestCase {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * POINT-002: 提前完成获得额外积分(默认+1分)
|
|
|
+ * POINT-002: 超额完成获得额外积分(提前或超质完成,家长制定规则)
|
|
|
*/
|
|
|
class POINT_002_TestCase extends BaseTestCase {
|
|
|
constructor() {
|
|
|
- super('POINT-002', '提前完成获得额外积分(默认+1分)', 'P0');
|
|
|
+ super('POINT-002', '超额完成获得额外积分(提前或超质完成,家长制定规则)', 'P0');
|
|
|
}
|
|
|
|
|
|
async run() {
|
|
|
@@ -698,7 +735,10 @@ class POINT_002_TestCase extends BaseTestCase {
|
|
|
|
|
|
// 设置任务截止时间
|
|
|
const nameInput = await this.waitForElement('任务名称');
|
|
|
- await this.fill(nameInput.uid, '提前完成测试任务');
|
|
|
+ await this.fill(nameInput.uid, '超额完成测试任务');
|
|
|
+
|
|
|
+ const ruleField = await this.waitForElement('额外积分规则');
|
|
|
+ await this.fill(ruleField.uid, '提前完成+1,超质完成+2');
|
|
|
|
|
|
// 立即完成任务(提前)
|
|
|
const saveBtn = await this.waitForElement('保存');
|
|
|
@@ -708,7 +748,7 @@ class POINT_002_TestCase extends BaseTestCase {
|
|
|
const childModeBtn = await this.waitForElement('孩子模式');
|
|
|
await this.click(childModeBtn.uid);
|
|
|
|
|
|
- const taskItem = await this.waitForElement('提前完成测试任务');
|
|
|
+ const taskItem = await this.waitForElement('超额完成测试任务');
|
|
|
await this.click(taskItem.uid);
|
|
|
|
|
|
const completeBtn = await this.waitForElement('完成任务');
|
|
|
@@ -719,7 +759,8 @@ class POINT_002_TestCase extends BaseTestCase {
|
|
|
const result = await this.getSnapshot();
|
|
|
const bonusPoints = result.some(item =>
|
|
|
item.text.includes('+1') ||
|
|
|
- item.text.includes('额外')
|
|
|
+ item.text.includes('额外') ||
|
|
|
+ item.text.includes('超额完成')
|
|
|
);
|
|
|
|
|
|
this.logResult(bonusPoints);
|
|
|
@@ -856,6 +897,42 @@ class POINT_008_TestCase extends BaseTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * POINT-009: 积分不清零,可设置积分有效期(按任务设置)
|
|
|
+ */
|
|
|
+class POINT_009_TestCase extends BaseTestCase {
|
|
|
+ constructor() {
|
|
|
+ super('POINT-009', '积分不清零,可设置积分有效期(按任务设置)', 'P0');
|
|
|
+ }
|
|
|
+
|
|
|
+ async run() {
|
|
|
+ try {
|
|
|
+ await this.setup();
|
|
|
+
|
|
|
+ const snapshot = await this.getSnapshot();
|
|
|
+ const createTaskBtn = snapshot.find(item => item.text.includes('创建任务'));
|
|
|
+ await this.click(createTaskBtn.uid);
|
|
|
+
|
|
|
+ const nameInput = await this.waitForElement('任务名称');
|
|
|
+ await this.fill(nameInput.uid, '积分有效期测试任务');
|
|
|
+
|
|
|
+ const expireField = await this.waitForElement('积分有效期');
|
|
|
+ await this.fill(expireField.uid, '30天');
|
|
|
+ await this.screenshot('01_points_expire_rule');
|
|
|
+
|
|
|
+ const result = await this.getSnapshot();
|
|
|
+ const hasExpireRule = result.some(item =>
|
|
|
+ item.text.includes('30天') ||
|
|
|
+ item.text.includes('积分有效期')
|
|
|
+ );
|
|
|
+
|
|
|
+ this.logResult(hasExpireRule);
|
|
|
+ } catch (error) {
|
|
|
+ this.logResult(false, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// ============================================================================
|
|
|
// 模块3: 奖励体系测试用例
|
|
|
// ============================================================================
|
|
|
@@ -913,6 +990,164 @@ class REWARD_001_TestCase extends BaseTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * REWARD-001A: 家长填写所需积分后心愿进入奖励库
|
|
|
+ */
|
|
|
+class REWARD_001A_TestCase extends BaseTestCase {
|
|
|
+ constructor() {
|
|
|
+ super('REWARD-001A', '家长填写所需积分后心愿进入奖励库', 'P0');
|
|
|
+ }
|
|
|
+
|
|
|
+ async run() {
|
|
|
+ try {
|
|
|
+ await this.setup();
|
|
|
+
|
|
|
+ const snapshot = await this.getSnapshot();
|
|
|
+ const wishlistBtn = snapshot.find(item => item.text.includes('心愿单'));
|
|
|
+ await this.click(wishlistBtn.uid);
|
|
|
+
|
|
|
+ const wishItem = await this.waitForElement('去游乐园玩');
|
|
|
+ await this.click(wishItem.uid);
|
|
|
+
|
|
|
+ const fillPointsBtn = await this.waitForElement('填写所需积分');
|
|
|
+ await this.click(fillPointsBtn.uid);
|
|
|
+
|
|
|
+ const pointsInput = await this.waitForElement('所需积分');
|
|
|
+ await this.fill(pointsInput.uid, '50');
|
|
|
+
|
|
|
+ const saveBtn = await this.waitForElement('保存并加入奖励库');
|
|
|
+ await this.click(saveBtn.uid);
|
|
|
+ await this.screenshot('01_move_to_reward_pool');
|
|
|
+
|
|
|
+ const result = await this.getSnapshot();
|
|
|
+ const moved = result.some(item =>
|
|
|
+ item.text.includes('奖励库') ||
|
|
|
+ item.text.includes('50积分')
|
|
|
+ );
|
|
|
+
|
|
|
+ this.logResult(moved);
|
|
|
+ } catch (error) {
|
|
|
+ this.logResult(false, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * REWARD-002A: 家庭奖励库(多个家长都可调整)
|
|
|
+ */
|
|
|
+class REWARD_002A_TestCase extends BaseTestCase {
|
|
|
+ constructor() {
|
|
|
+ super('REWARD-002A', '家庭奖励库(多个家长都可调整)', 'P0');
|
|
|
+ }
|
|
|
+
|
|
|
+ async run() {
|
|
|
+ try {
|
|
|
+ await this.setup();
|
|
|
+
|
|
|
+ const snapshot = await this.getSnapshot();
|
|
|
+ const rewardPoolBtn = snapshot.find(item => item.text.includes('奖励库'));
|
|
|
+ await this.click(rewardPoolBtn.uid);
|
|
|
+
|
|
|
+ const rewardItem = await this.waitForElement('去游乐园玩');
|
|
|
+ await this.click(rewardItem.uid);
|
|
|
+
|
|
|
+ const editBtn = await this.waitForElement('编辑');
|
|
|
+ await this.click(editBtn.uid);
|
|
|
+
|
|
|
+ const pointsInput = await this.waitForElement('所需积分');
|
|
|
+ await this.fill(pointsInput.uid, '60');
|
|
|
+
|
|
|
+ const saveBtn = await this.waitForElement('保存');
|
|
|
+ await this.click(saveBtn.uid);
|
|
|
+ await this.screenshot('01_edit_family_reward_pool');
|
|
|
+
|
|
|
+ const result = await this.getSnapshot();
|
|
|
+ const editable = result.some(item =>
|
|
|
+ item.text.includes('60') ||
|
|
|
+ item.text.includes('已更新')
|
|
|
+ );
|
|
|
+
|
|
|
+ this.logResult(editable);
|
|
|
+ } catch (error) {
|
|
|
+ this.logResult(false, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * REWARD-002B: 多孩子心愿单隔离
|
|
|
+ */
|
|
|
+class REWARD_002B_TestCase extends BaseTestCase {
|
|
|
+ constructor() {
|
|
|
+ super('REWARD-002B', '多孩子心愿单隔离', 'P0');
|
|
|
+ }
|
|
|
+
|
|
|
+ async run() {
|
|
|
+ try {
|
|
|
+ await this.setup();
|
|
|
+
|
|
|
+ const snapshot = await this.getSnapshot();
|
|
|
+ const switchChildBtn = snapshot.find(item => item.text.includes('切换孩子'));
|
|
|
+ await this.click(switchChildBtn.uid);
|
|
|
+
|
|
|
+ const childA = await this.waitForElement('测试孩子1');
|
|
|
+ await this.click(childA.uid);
|
|
|
+ const wishlistBtn = await this.waitForElement('心愿单');
|
|
|
+ await this.click(wishlistBtn.uid);
|
|
|
+ const childAResult = await this.getSnapshot();
|
|
|
+ const childAHasWish = childAResult.some(item => item.text.includes('去游乐园玩'));
|
|
|
+
|
|
|
+ const switchChildAgain = await this.waitForElement('切换孩子');
|
|
|
+ await this.click(switchChildAgain.uid);
|
|
|
+ const childB = await this.waitForElement('测试孩子2');
|
|
|
+ await this.click(childB.uid);
|
|
|
+ const wishlistAgain = await this.waitForElement('心愿单');
|
|
|
+ await this.click(wishlistAgain.uid);
|
|
|
+ await this.screenshot('01_isolated_wishlist');
|
|
|
+
|
|
|
+ const childBResult = await this.getSnapshot();
|
|
|
+ const childBHasDifferentList = !childBResult.some(item => item.text.includes('去游乐园玩'));
|
|
|
+
|
|
|
+ this.logResult(childAHasWish && childBHasDifferentList);
|
|
|
+ } catch (error) {
|
|
|
+ this.logResult(false, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * DAN-001: 通过接口获取DAN测评数据
|
|
|
+ */
|
|
|
+class DAN_001_TestCase extends BaseTestCase {
|
|
|
+ constructor() {
|
|
|
+ super('DAN-001', '通过接口获取DAN测评数据', 'P1');
|
|
|
+ }
|
|
|
+
|
|
|
+ async run() {
|
|
|
+ try {
|
|
|
+ await this.setup();
|
|
|
+
|
|
|
+ const snapshot = await this.getSnapshot();
|
|
|
+ const danBtn = snapshot.find(item => item.text.includes('DAN测评'));
|
|
|
+ await this.click(danBtn.uid);
|
|
|
+
|
|
|
+ const syncBtn = await this.waitForElement('同步测评数据');
|
|
|
+ await this.click(syncBtn.uid);
|
|
|
+ await this.screenshot('01_fetch_dan_by_api');
|
|
|
+
|
|
|
+ const result = await this.getSnapshot();
|
|
|
+ const fetched = result.some(item =>
|
|
|
+ item.text.includes('测评记录') ||
|
|
|
+ item.text.includes('同步成功')
|
|
|
+ );
|
|
|
+
|
|
|
+ this.logResult(fetched);
|
|
|
+ } catch (error) {
|
|
|
+ this.logResult(false, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* REWARD-005: 家长审批奖励兑换
|
|
|
*/
|
|
|
@@ -1637,6 +1872,7 @@ module.exports = {
|
|
|
TASK_001_TestCase,
|
|
|
TASK_002_TestCase,
|
|
|
TASK_003_TestCase,
|
|
|
+ TASK_005_TestCase,
|
|
|
TASK_008_TestCase,
|
|
|
TASK_009_TestCase,
|
|
|
TASK_012A_TestCase,
|
|
|
@@ -1652,10 +1888,17 @@ module.exports = {
|
|
|
POINT_006_TestCase,
|
|
|
POINT_007_TestCase,
|
|
|
POINT_008_TestCase,
|
|
|
+ POINT_009_TestCase,
|
|
|
|
|
|
// 奖励体系模块
|
|
|
REWARD_001_TestCase,
|
|
|
+ REWARD_001A_TestCase,
|
|
|
+ REWARD_002A_TestCase,
|
|
|
+ REWARD_002B_TestCase,
|
|
|
REWARD_005_TestCase,
|
|
|
+
|
|
|
+ // DAN测评记录模块
|
|
|
+ DAN_001_TestCase,
|
|
|
|
|
|
// 双模式切换模块
|
|
|
MODE_001_TestCase,
|