Files
MailUI4Agents/client/electron/test/harmony-push-optin.test.mjs
JianFeeeee cfe7808af4 ke: 鸿蒙 UI 整改:emoji→AmIcon 图标、宽屏侧栏、Md 第三方库、通知可配置项
- common/Icons.ets(生成器产出):43 枚与 WebUI icons.tsx 同几何的 Path 图标
- NavItems.ts:icon(emoji) → iconKey,与 WebUI 导航同图标
- 全页面 emoji 清除(空态改单行灰字,按钮/头像/刷新等换 AmIcon)
- MailDetailPage 接入 @luvi/lv-markdown-in(第三方,替代手写解析器)
- WideSidebar + MainPage isWide(≥768vp):宽屏侧栏 60vp 图标轨、藏底部条、onAreaChange 断点
- 通知=可配置项(默认关):PushService.isEnabled/setEnabled + reportToken 最前 gate (关=不取token/不弹权限/不打网关)+ SettingsPage Toggle + 服务端通道状态提示
- EntryAbility.onCreate 解析 want:冷启点通知也能路由(原来只有 onNewWant)
- 判据:harmony-widescreen(4) + harmony-push-optin(4) 新增;harmony-nav 同步 iconKey/条件 padding
2026-09-16 07:46:52 +08:00

86 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 通知开关判据 —— 钉「接入系统通知」**必须是可配置项**(用户强调多次,非可选)。
//
// 用户原话:「还有我强调多少遍了,接入系统通知是一个可配置项,因为用户可以自由的部署自己的
// agentmail」。
//
// 自部署常态:服务器没有配置华为推送凭证。关着 = 不取 token、不请求系统通知权限、
// 不上报、不打网关 —— 零开销、不弹任何东西、不阻塞启动。这条判据钉的就是这套"开关必须存在
// 且默认关、关着要走零路径"的契约。
//
// 四条:
// ① 默认关(契约常量 + PushService.isEnabled 读不到即 false);
// ② reportToken 在**最前** gate(关 ⇒ getToken 都不调 —— 否则零开销就不成立);
// ③ SettingsPage 有 Toggle 且接了回调(用户能看见开关);
// ④ EntryAbility 不因开关关而报错(gate 在 PushService 内部 ⇒ onCreate 不用改)。
import { code, prose, stripComments } from './lib/read.mjs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { test } from 'node:test';
import assert from 'node:assert/strict';
const HERE = dirname(fileURLToPath(import.meta.url));
const ROOT = join(HERE, '..', '..', '..');
const HARMONY_ETS = join(ROOT, 'client/harmony/entry/src/main/ets');
const read = p => prose(join(HARMONY_ETS, p));
const C = await import(join(HARMONY_ETS, 'model/PushContract.ts'));
test('① 契约默认关:DEFAULT_PUSH_ENABLED = false(自部署零开销的契约)', () => {
assert.equal(C.DEFAULT_PUSH_ENABLED, false,
'默认必须关 —— 自部署用户没配服务端推送凭证时不应被默认裹进推送链');
// 标签:关 ⇒ 'off'、开 ⇒ 'on'(口径稳定,给设置页用)
assert.equal(C.pushEnabledLabel(false), 'off');
assert.equal(C.pushEnabledLabel(true), 'on');
});
test('② PushService.isEnabled 读不到即 false(默认关落点) + setEnabled 存在', () => {
const svc = read('api/PushService.ets');
const code_ = stripComments(svc);
assert.match(code_, /static isEnabled\(context: common\.Context\): boolean \{/,
'要有静态 isEnabled(ability 阶段 onCreate 要读它,不能是实例方法)');
assert.match(code_, /return v === true;/,
'读到 true 才返回 true —— 其它(首次/异常)都 false(默认关)');
assert.match(code_, /static setEnabled\(context: common\.Context, enabled: boolean\): void \{/,
'要有静态 setEnabled(设置页 Toggle 回调用)');
});
test('③ reportToken 在最前 gate(关 ⇒ getToken 都不调 ⇒ 零开销)', () => {
const svc = read('api/PushService.ets');
const code_ = stripComments(svc);
/*
* 取 reportToken 的正文(从方法签名到下一个 async/方法声明),
* 判"开关检查在 getToken 之前" —— 这是"零开销"的关键:
* 关时根本不碰 Push Kit(不取 token、不触网络/权限路径)。
*/
const lines = code_.split('\n');
const start = lines.findIndex(l => /async reportToken\(/.test(l));
assert.ok(start > 0, '要能找到 reportToken');
let stop = lines.length;
for (let i = start + 1; i < lines.length; i++) {
if (/^\s*(async |private |static )\w/.test(lines[i]) || /^}\s*$/.test(lines[i])) {
// 粗略:下一段方法或闭合 — 取 200 行作截断
stop = Math.min(i + 1, start + 200);
break;
}
}
const body = lines.slice(start, stop).join('\n');
const gateAt = body.indexOf('PushService.isEnabled');
const getTokenAt = body.indexOf('this.getToken()');
assert.ok(gateAt > 0, 'reportToken 里要有 isEnabled gate');
assert.ok(getTokenAt > 0, 'reportToken 里要有 getToken');
assert.ok(gateAt < getTokenAt,
'开关 gate 必须在 getToken 之前 —— 否则关时仍会取 token(零开销不成立)');
});
test('④ SettingsPage 有 Toggle 且接了 togglePush 回调(用户能看见开关)', () => {
const settings = read('pages/SettingsPage.ets');
assert.match(settings, /Toggle\(\{ type: ToggleType\.Switch, isOn: this\.pushEnabled \}\)/,
'设置页要有 Toggle(Switch) 绑定 pushEnabled');
assert.match(settings, /togglePush\(isOn\)/, 'Toggle 的 onChange 要调 togglePush');
assert.match(settings, /PushService\.isEnabled/, 'aboutToAppear 要读一次开关回填');
assert.match(settings, /PushService\.setEnabled/, 'togglePush 要写持久化');
// 状态提示(服务器未配置推送时如实告诉用户)
assert.match(settings, /服务器未配置推送/, '服务器没配通道时要说清(否则用户开了以为有用)');
});