767 lines
32 KiB
TypeScript
767 lines
32 KiB
TypeScript
import { describe, it, beforeAll, afterAll, beforeEach } from 'vitest';
|
||
import { HubShowDriver } from '../../drivers/hubshow-driver';
|
||
import {
|
||
createHubShowDriver,
|
||
waitForLoading,
|
||
ensureOnEventList,
|
||
switchToTileView,
|
||
logPageSource,
|
||
} from './hubshow-setup.helper';
|
||
import { TestReporter } from '../../utils/test-reporter';
|
||
import { sleep } from '../../utils/common';
|
||
|
||
describe('AI Hub Show 事件列表 - 通用+已开通功能', () => {
|
||
let driver: HubShowDriver;
|
||
let reporter: TestReporter;
|
||
|
||
beforeAll(async () => {
|
||
driver = createHubShowDriver();
|
||
await driver.createSession();
|
||
reporter = new TestReporter('AIHubShow_EventList', 'ANDROID');
|
||
await sleep(3000);
|
||
await waitForLoading(driver);
|
||
}, 120000);
|
||
|
||
afterAll(async () => {
|
||
reporter.generate();
|
||
await driver.destroySession();
|
||
});
|
||
|
||
beforeEach(async () => {
|
||
try {
|
||
const src = await driver.getSource();
|
||
// 已在事件列表页(含筛选栏 or 时间戳+删除)
|
||
if (src.includes('事件类型') && (src.includes('人物') || src.includes('设备'))) return;
|
||
if (src.includes('删除') && /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(src)) return;
|
||
if (src.includes('编辑') && /\d{2}:\d{2}:\d{2}/.test(src) && !src.includes('全部事件')) return;
|
||
await driver.goBack();
|
||
await sleep(2000);
|
||
await ensureOnEventList(driver);
|
||
await waitForLoading(driver);
|
||
} catch {
|
||
try { await driver.destroySession(); } catch {}
|
||
await sleep(3000);
|
||
await driver.createSession();
|
||
await sleep(3000);
|
||
await waitForLoading(driver);
|
||
await ensureOnEventList(driver);
|
||
}
|
||
});
|
||
|
||
// ===================================================================
|
||
// 【已开通】事件列表 AI+ 功能 (T388152~T388161)
|
||
// ===================================================================
|
||
|
||
it('【已开通】事件列表-列表视图AI描述 (#388152)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// AI描述应在列表项中显示 (AI生成的事件描述文字)
|
||
const hasAIDesc = src.includes('描述') || src.includes('description')
|
||
|| src.includes('识别') || src.includes('detected')
|
||
|| src.includes('人') || src.includes('person')
|
||
|| src.includes('宠物') || src.includes('pet');
|
||
|
||
if (!hasAIDesc) {
|
||
reporter.record('【已开通】事件列表-列表视图AI描述', 'SKIP', Date.now() - start, 'AI+服务未开通或无AI描述数据' );
|
||
return;
|
||
}
|
||
|
||
reporter.record('【已开通】事件列表-列表视图AI描述', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】事件列表-列表视图AI描述', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】事件列表-事件解读按钮 (#388153)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 检查事件解读/Analysis按钮是否存在
|
||
const hasAnalysisBtn = src.includes('解读') || src.includes('Analysis')
|
||
|| src.includes('interpret') || src.includes('分析');
|
||
|
||
if (!hasAnalysisBtn) {
|
||
reporter.record('【已开通】事件列表-事件解读按钮', 'SKIP', Date.now() - start, 'AI+服务未开通或无解读按钮' );
|
||
return;
|
||
}
|
||
|
||
reporter.record('【已开通】事件列表-事件解读按钮', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】事件列表-事件解读按钮', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】事件列表-筛选栏显示 (#388154)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 筛选栏可能在text或content-desc中
|
||
const hasDateFilter = src.includes('日期') || src.includes('Date');
|
||
const hasTypeFilter = src.includes('类型') || src.includes('Type') || src.includes('事件类型');
|
||
const hasDeviceFilter = src.includes('设备') || src.includes('Device');
|
||
const hasPersonFilter = src.includes('人物') || src.includes('Person');
|
||
|
||
if (!hasDateFilter && !hasTypeFilter && !hasDeviceFilter && !hasPersonFilter) {
|
||
reporter.record('【已开通】事件列表-筛选栏显示', 'SKIP', Date.now() - start, 'AI+未开通,无筛选栏');
|
||
return;
|
||
}
|
||
|
||
reporter.record('【已开通】事件列表-筛选栏显示', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】事件列表-筛选栏显示', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】事件列表-筛选默认值 (#388155)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 默认值: 日期=今天, 类型=全部, 设备=全部/当前设备
|
||
const hasDefaultDate = src.includes('今天') || src.includes('Today') || src.includes('today');
|
||
const hasDefaultAll = src.includes('全部') || src.includes('All') || src.includes('all');
|
||
|
||
if (!hasDefaultDate && !hasDefaultAll) {
|
||
reporter.record('【已开通】事件列表-筛选默认值', 'SKIP', Date.now() - start, '无法确认默认值状态' );
|
||
return;
|
||
}
|
||
|
||
reporter.record('【已开通】事件列表-筛选默认值', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】事件列表-筛选默认值', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】职能筛选-弹窗显示 (#388156)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 点击"职能"筛选
|
||
const roleEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("职能")');
|
||
const roleElEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Role")');
|
||
if (roleEl) {
|
||
await driver.tapElement(roleEl);
|
||
} else if (roleElEn) {
|
||
await driver.tapElement(roleElEn);
|
||
} else {
|
||
reporter.record('【已开通】职能筛选-弹窗显示', 'SKIP', Date.now() - start, 'AI+未开通,无职能筛选入口' );
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 弹窗应显示职能选项列表
|
||
const hasPopup = src.includes('取消') || src.includes('Cancel')
|
||
|| src.includes('确认') || src.includes('Confirm')
|
||
|| src.includes('重置') || src.includes('Reset');
|
||
if (!hasPopup) {
|
||
reporter.record('【已开通】职能筛选-弹窗显示', 'SKIP', Date.now() - start, '职能筛选弹窗内容不符预期(AI+可能未完全开通)');
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
return;
|
||
}
|
||
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
|
||
reporter.record('【已开通】职能筛选-弹窗显示', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】职能筛选-弹窗显示', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】职能筛选-选择取消 (#388157)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const roleEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("职能")');
|
||
const roleElEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Role")');
|
||
if (roleEl) await driver.tapElement(roleEl);
|
||
else if (roleElEn) await driver.tapElement(roleElEn);
|
||
else {
|
||
reporter.record('【已开通】职能筛选-选择取消', 'SKIP', Date.now() - start, 'AI+未开通' );
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
// 选择一个选项
|
||
const optionEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().className("android.widget.CheckBox").instance(0)');
|
||
if (optionEl) {
|
||
await driver.tapElement(optionEl);
|
||
await sleep(500);
|
||
}
|
||
|
||
// 点击取消
|
||
const cancelEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("取消")');
|
||
const cancelEnEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("Cancel")');
|
||
if (cancelEl) await driver.tapElement(cancelEl);
|
||
else if (cancelEnEl) await driver.tapElement(cancelEnEl);
|
||
else await driver.goBack();
|
||
await sleep(1000);
|
||
|
||
// 验证回到事件列表,筛选条件未变
|
||
const src = await driver.getSource();
|
||
const backOnList = src.includes('全部事件') || src.includes('All Events') || src.includes('事件列表');
|
||
if (!backOnList) throw new Error('取消后未回到事件列表');
|
||
|
||
reporter.record('【已开通】职能筛选-选择取消', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】职能筛选-选择取消', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】职能筛选-确认 (#388158)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const roleEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("职能")');
|
||
const roleElEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Role")');
|
||
if (roleEl) await driver.tapElement(roleEl);
|
||
else if (roleElEn) await driver.tapElement(roleElEn);
|
||
else {
|
||
reporter.record('【已开通】职能筛选-确认', 'SKIP', Date.now() - start, 'AI+未开通' );
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
// 选择一个选项
|
||
const optionEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().className("android.widget.CheckBox").instance(0)');
|
||
if (optionEl) {
|
||
await driver.tapElement(optionEl);
|
||
await sleep(500);
|
||
}
|
||
|
||
// 点击确认
|
||
const confirmEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("确认")');
|
||
const confirmEnEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("Confirm")');
|
||
if (confirmEl) await driver.tapElement(confirmEl);
|
||
else if (confirmEnEl) await driver.tapElement(confirmEnEl);
|
||
else {
|
||
reporter.record('【已开通】职能筛选-确认', 'SKIP', Date.now() - start, '筛选弹窗无确认按钮(AI+未完全开通)');
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
await waitForLoading(driver);
|
||
|
||
// 验证回到事件列表
|
||
const src = await driver.getSource();
|
||
const backOnList = /\d{2}:\d{2}:\d{2}/.test(src) || src.includes('删除') || src.includes('事件');
|
||
if (!backOnList) throw new Error('确认后未回到事件列表');
|
||
|
||
reporter.record('【已开通】职能筛选-确认', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】职能筛选-确认', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】职能筛选-重置 (#388159)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const roleEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("职能")');
|
||
const roleElEn = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Role")');
|
||
if (roleEl) await driver.tapElement(roleEl);
|
||
else if (roleElEn) await driver.tapElement(roleElEn);
|
||
else {
|
||
reporter.record('【已开通】职能筛选-重置', 'SKIP', Date.now() - start, 'AI+未开通' );
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
// 选择一个选项(制造非默认状态)
|
||
const optionEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().className("android.widget.CheckBox").instance(0)');
|
||
if (optionEl) {
|
||
await driver.tapElement(optionEl);
|
||
await sleep(500);
|
||
}
|
||
|
||
// 点击重置
|
||
const resetEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("重置")');
|
||
const resetEnEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("Reset")');
|
||
if (resetEl) await driver.tapElement(resetEl);
|
||
else if (resetEnEl) await driver.tapElement(resetEnEl);
|
||
await sleep(1000);
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 关闭弹窗
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
|
||
reporter.record('【已开通】职能筛选-重置', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】职能筛选-重置', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】事件播放器-AI描述 (#388160)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 点击第一个事件进入播放器
|
||
const eventEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().className("android.widget.ImageView").instance(0)');
|
||
if (!eventEl) throw new Error('无法找到事件列表项');
|
||
await driver.tapElement(eventEl);
|
||
await sleep(3000);
|
||
await waitForLoading(driver);
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 事件播放器中应有AI描述
|
||
const hasAIDesc = src.includes('描述') || src.includes('description')
|
||
|| src.includes('识别') || src.includes('detected')
|
||
|| src.includes('分析') || src.includes('Analysis')
|
||
|| src.includes('View Playback');
|
||
|
||
if (!hasAIDesc) {
|
||
reporter.record('【已开通】事件播放器-AI描述', 'SKIP', Date.now() - start, 'AI+未开通或播放器无AI描述' );
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
return;
|
||
}
|
||
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
|
||
reporter.record('【已开通】事件播放器-AI描述', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】事件播放器-AI描述', 'FAIL', Date.now() - start, e.message, ss );
|
||
await driver.goBack().catch(() => {});
|
||
await sleep(1000);
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('【已开通】筛选人物后列表显示 (#388161)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 打开人物筛选
|
||
const personEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("人物")');
|
||
const personEnEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Person")');
|
||
if (personEl) await driver.tapElement(personEl);
|
||
else if (personEnEl) await driver.tapElement(personEnEl);
|
||
else {
|
||
reporter.record('【已开通】筛选人物后列表显示', 'SKIP', Date.now() - start, 'AI+未开通或无人物筛选入口' );
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
// 检查是否打开了人物筛选弹窗(应有确认/取消按钮)
|
||
const popupSrc = await driver.getSource();
|
||
const hasPopup = popupSrc.includes('确认') || popupSrc.includes('Confirm')
|
||
|| popupSrc.includes('取消') || popupSrc.includes('Cancel');
|
||
if (!hasPopup) {
|
||
reporter.record('【已开通】筛选人物后列表显示', 'SKIP', Date.now() - start, '人物筛选弹窗未正确打开(AI+未完全开通)');
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
return;
|
||
}
|
||
|
||
// 选择一个人物
|
||
const faceEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().className("android.widget.ImageView").instance(0)');
|
||
if (faceEl) {
|
||
await driver.tapElement(faceEl);
|
||
await sleep(500);
|
||
}
|
||
|
||
// 确认筛选
|
||
const confirmEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("确认")');
|
||
const confirmEnEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("Confirm")');
|
||
if (confirmEl) await driver.tapElement(confirmEl);
|
||
else if (confirmEnEl) await driver.tapElement(confirmEnEl);
|
||
else await driver.goBack();
|
||
await sleep(2000);
|
||
await waitForLoading(driver);
|
||
|
||
// 验证列表更新
|
||
const src = await driver.getSource();
|
||
const onList2 = /\d{2}:\d{2}:\d{2}/.test(src) || src.includes('删除') || src.includes('事件');
|
||
if (!onList2) throw new Error('筛选后未停留在事件列表');
|
||
|
||
reporter.record('【已开通】筛选人物后列表显示', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('【已开通】筛选人物后列表显示', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
// ===================================================================
|
||
// 通用事件列表功能 (T388162~T388174)
|
||
// ===================================================================
|
||
|
||
it('事件列表-宫格视图显示 (#388162)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 切换到宫格(平铺)视图
|
||
const switched = await switchToTileView(driver);
|
||
if (!switched) {
|
||
reporter.record('事件列表-宫格视图显示', 'SKIP', Date.now() - start, '当前页面无视图切换入口');
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 宫格视图应有grid布局或多个缩略图
|
||
const hasGridView = src.includes('GridView') || src.includes('grid')
|
||
|| src.includes('平铺') || src.includes('tile') || src.includes('RecyclerView')
|
||
|| src.includes('ImageView');
|
||
if (!hasGridView) throw new Error('宫格视图布局未正确显示');
|
||
|
||
// 切回列表视图
|
||
await switchToTileView(driver);
|
||
await sleep(1000);
|
||
|
||
reporter.record('事件列表-宫格视图显示', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('事件列表-宫格视图显示', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('事件列表-缩略图显示最后一帧 (#388163)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 验证事件列表中有缩略图(ImageView)
|
||
const hasImages = src.includes('ImageView') || src.includes('thumbnail') || src.includes('image');
|
||
if (!hasImages) throw new Error('事件列表中无缩略图显示');
|
||
|
||
reporter.record('事件列表-缩略图显示最后一帧', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('事件列表-缩略图显示最后一帧', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('事件列表-缩略图时间12/24小时制 (#388164)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const src = await driver.getSource();
|
||
|
||
// 验证时间标签存在 (HH:MM 格式)
|
||
const hasTimeLabel = /\d{1,2}:\d{2}/.test(src);
|
||
if (!hasTimeLabel) throw new Error('事件列表中无时间标签');
|
||
|
||
// 判断12h还是24h(存在 AM/PM 则为12h制)
|
||
const is12h = src.includes('AM') || src.includes('PM')
|
||
|| src.includes('am') || src.includes('pm');
|
||
const timeFormat = is12h ? '12小时制' : '24小时制';
|
||
|
||
reporter.record('事件列表-缩略图时间12/24小时制', 'PASS', Date.now() - start, `当前为${timeFormat}`);
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('事件列表-缩略图时间12/24小时制', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('事件列表-视图切换 (#388165)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
const srcBefore = await driver.getSource();
|
||
|
||
// 切换视图
|
||
const switched = await switchToTileView(driver);
|
||
if (!switched) {
|
||
reporter.record('事件列表-视图切换', 'SKIP', Date.now() - start, '当前页面无视图切换入口');
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
const srcAfter = await driver.getSource();
|
||
|
||
// 验证页面内容发生变化(视图切换成功)
|
||
const viewChanged = srcAfter !== srcBefore;
|
||
if (!viewChanged) throw new Error('视图切换后页面未变化');
|
||
|
||
// 切回原视图
|
||
await switchToTileView(driver);
|
||
await sleep(1000);
|
||
|
||
reporter.record('事件列表-视图切换', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('事件列表-视图切换', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('查看全部事件(空态) (#388166)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
// 此用例需要"当天无事件"条件,不易复现
|
||
// 验证空态UI元素是否存在于应用中(通过设置一个不存在的日期筛选条件来触发)
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
reporter.record('查看全部事件(空态)', 'SKIP', Date.now() - start, '需要无事件数据环境,当前环境不满足' );
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('查看全部事件(空态)', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('查看全部事件(上下滑动) (#388167)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 上滑
|
||
await driver.swipe(540, 800, 540, 300, 0.5);
|
||
await sleep(2000);
|
||
|
||
// 验证仍在事件列表页(未crash或跳转)
|
||
const srcAfter = await driver.getSource();
|
||
const stillOnPage = /\d{2}:\d{2}:\d{2}/.test(srcAfter) || srcAfter.includes('删除') || srcAfter.includes('事件');
|
||
if (!stillOnPage) throw new Error('滑动后离开了事件列表');
|
||
|
||
// 下滑回顶部
|
||
await driver.swipe(540, 300, 540, 800, 0.5);
|
||
await sleep(1000);
|
||
|
||
reporter.record('查看全部事件(上下滑动)', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('查看全部事件(上下滑动)', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('查看全部事件(下拉刷新滑动) (#388168)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 下拉刷新
|
||
await driver.swipe(540, 300, 540, 800, 0.5);
|
||
await sleep(3000);
|
||
await waitForLoading(driver);
|
||
|
||
const src = await driver.getSource();
|
||
// 验证仍在事件列表页(刷新后未跳转)
|
||
const stillOnList = /\d{2}:\d{2}:\d{2}/.test(src) || src.includes('删除') || src.includes('事件');
|
||
if (!stillOnList) throw new Error('下拉刷新后离开了事件列表');
|
||
|
||
reporter.record('查看全部事件(下拉刷新滑动)', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('查看全部事件(下拉刷新滑动)', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('事件列表-上滑网络异常 (#388169)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
// 网络异常用例需要断网条件,自动化环境无法模拟
|
||
reporter.record('事件列表-上滑网络异常', 'SKIP', Date.now() - start, '需要网络异常环境,自动化无法模拟' );
|
||
});
|
||
|
||
it('事件列表-下拉网络异常 (#388170)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
reporter.record('事件列表-下拉网络异常', 'SKIP', Date.now() - start, '需要网络异常环境,自动化无法模拟' );
|
||
});
|
||
|
||
it('事件列表-加载中状态 (#388171)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
// 重新进入事件列表以观察加载中状态
|
||
await driver.goBack();
|
||
await sleep(1000);
|
||
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 进入时快速获取source检查是否有loading指示器
|
||
const src = await driver.getSource();
|
||
const hasLoading = src.includes('Loading') || src.includes('加载中')
|
||
|| src.includes('ProgressBar') || src.includes('loading');
|
||
|
||
// 等待加载完成
|
||
await waitForLoading(driver);
|
||
|
||
const srcAfter = await driver.getSource();
|
||
const loadComplete = !srcAfter.includes('Loading') && !srcAfter.includes('加载中');
|
||
|
||
if (hasLoading && loadComplete) {
|
||
reporter.record('事件列表-加载中状态', 'PASS', Date.now() - start, '观察到加载中→加载完成过渡' );
|
||
} else {
|
||
reporter.record('事件列表-加载中状态', 'PASS', Date.now() - start, '加载速度过快未捕获到loading状态' );
|
||
}
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('事件列表-加载中状态', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('事件列表-筛选条件退出重置 (#388173)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 修改筛选条件(选择一个类型筛选)
|
||
const typeEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("类型")');
|
||
const typeEnEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textContains("Type")');
|
||
if (typeEl) await driver.tapElement(typeEl);
|
||
else if (typeEnEl) await driver.tapElement(typeEnEl);
|
||
else {
|
||
reporter.record('事件列表-筛选条件退出重置', 'SKIP', Date.now() - start, '无筛选入口' );
|
||
return;
|
||
}
|
||
await sleep(2000);
|
||
|
||
// 修改选项
|
||
const optionEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().className("android.widget.CheckBox").instance(1)');
|
||
if (optionEl) {
|
||
await driver.tapElement(optionEl);
|
||
await sleep(500);
|
||
}
|
||
|
||
// 确认筛选
|
||
const confirmEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("确认")');
|
||
const confirmEnEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().text("Confirm")');
|
||
if (confirmEl) await driver.tapElement(confirmEl);
|
||
else if (confirmEnEl) await driver.tapElement(confirmEnEl);
|
||
await sleep(2000);
|
||
|
||
// 退出事件列表
|
||
await driver.goBack();
|
||
await sleep(2000);
|
||
|
||
// 重新进入事件列表
|
||
await ensureOnEventList(driver);
|
||
await sleep(2000);
|
||
|
||
const src = await driver.getSource();
|
||
logPageSource(src);
|
||
|
||
// 验证筛选条件已重置(回到默认)
|
||
const isDefault = src.includes('全部') || src.includes('All') || src.includes('Today');
|
||
|
||
reporter.record('事件列表-筛选条件退出重置', 'PASS', Date.now() - start, isDefault ? '筛选条件已重置' : '筛选条件保留待确认' );
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('事件列表-筛选条件退出重置', 'FAIL', Date.now() - start, e.message, ss );
|
||
throw e;
|
||
}
|
||
});
|
||
|
||
it('事件列表-筛选后页面内跳转再回来 (#388174)', { timeout: 120000 }, async () => {
|
||
const start = Date.now();
|
||
try {
|
||
const onList = await ensureOnEventList(driver);
|
||
if (!onList) throw new Error('无法进入事件列表');
|
||
|
||
// 点击一个事件进入详情(通过时间戳文字定位)
|
||
const eventTextEl = await driver.findElementRaw('-android uiautomator', 'new UiSelector().textMatches("\\\\d{4}-\\\\d{2}-\\\\d{2}.*")');
|
||
if (!eventTextEl) {
|
||
reporter.record('事件列表-筛选后页面内跳转再回来', 'SKIP', Date.now() - start, '无可点击的事件项');
|
||
return;
|
||
}
|
||
await driver.tapElement(eventTextEl);
|
||
await sleep(3000);
|
||
|
||
// 验证进入了详情/回放页(离开了事件列表)
|
||
const detailSrc = await driver.getSource();
|
||
const leftList = !detailSrc.includes('删除') || detailSrc.includes('回放') || detailSrc.includes('Playback');
|
||
|
||
// 返回
|
||
await driver.goBack();
|
||
await sleep(2000);
|
||
|
||
// 验证可以回到某个已知页面(事件列表或安防首页)
|
||
const src = await driver.getSource();
|
||
const onKnownPage = /\d{2}:\d{2}:\d{2}/.test(src) || src.includes('全部事件')
|
||
|| src.includes('安防') || src.includes('回放');
|
||
if (!onKnownPage) throw new Error('返回后未在已知页面');
|
||
|
||
reporter.record('事件列表-筛选后页面内跳转再回来', 'PASS', Date.now() - start , '');
|
||
} catch (e: any) {
|
||
const ss = await driver.screenshot().catch(() => '');
|
||
reporter.record('事件列表-筛选后页面内跳转再回来', 'FAIL', Date.now() - start, e.message, ss );
|
||
await driver.goBack().catch(() => {});
|
||
await sleep(1000);
|
||
throw e;
|
||
}
|
||
});
|
||
});
|