M1: 桥引擎单测代码(T-M1-08,运行待工具链)
- entry/src/test/Bridge.test.ets:13 用例覆盖 MessageCodec(toJson省略/response/escape转义/toArray)、 HandlerRegistry(put/get/默认兜底不抛错)、 BridgeController(入站分发+回执/出站callHandler/启动队列补发/ responseId回执路由/未注册名默认兜底) —— 用 FakeWebController 纯逻辑、不依赖设备 - 接入本地单测入口 List.test.ets - ⚠ 运行受阻:devecocli 无 test 子命令,本地单测 hvigor task 未常规暴露, 待定运行方式(DevEco IDE / CI / 其他)后跑覆盖率(目标 ≥80%) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3e2b1282ba
commit
5587df0562
@@ -0,0 +1,148 @@
|
||||
import { describe, it, expect } from '@ohos/hypium';
|
||||
import {
|
||||
BridgeController, FakeWebController, MessageCodec, Message, HandlerRegistry
|
||||
} from 'feature_bridge';
|
||||
|
||||
/**
|
||||
* 桥引擎单测(T-M1-08)。纯逻辑,用 FakeWebController 模拟 H5 收发,不依赖设备。
|
||||
* 覆盖 MessageCodec(toJson/escape/toArray)、HandlerRegistry(兜底)、
|
||||
* BridgeController(入站分发/出站下发/回执路由/启动队列/默认兜底)。
|
||||
*/
|
||||
export default function bridgeTest() {
|
||||
describe('MessageCodec', () => {
|
||||
it('toJson_omits_undefined', 0, () => {
|
||||
const m = new Message();
|
||||
m.handlerName = 'h';
|
||||
m.data = 'd';
|
||||
const json = MessageCodec.toJson(m);
|
||||
expect(json.includes('"handlerName":"h"')).assertTrue();
|
||||
expect(json.includes('"data":"d"')).assertTrue();
|
||||
expect(json.includes('callbackId')).assertFalse();
|
||||
expect(json.includes('responseId')).assertFalse();
|
||||
});
|
||||
|
||||
it('toJson_response', 0, () => {
|
||||
const json = MessageCodec.toJson(Message.response('cb1', 'ok'));
|
||||
expect(json.includes('"responseId":"cb1"')).assertTrue();
|
||||
expect(json.includes('"responseData":"ok"')).assertTrue();
|
||||
});
|
||||
|
||||
it('escape_plain_unchanged', 0, () => {
|
||||
// 无双引号/反斜杠的纯文本不应被第一步改变(仅可能被第二步处理引号,这里无引号)
|
||||
const s = MessageCodec.escape('1782349257911');
|
||||
expect(s).assertEqual('1782349257911');
|
||||
});
|
||||
|
||||
it('escape_quotes_backslash', 0, () => {
|
||||
// JSON {"data":"a\"b"} → 结构引号转义、内部 \" 加倍
|
||||
const mm = new Message();
|
||||
mm.data = 'a"b';
|
||||
const escaped = MessageCodec.escape(MessageCodec.toJson(mm));
|
||||
// 结构引号被转义为 \"(前面非反斜杠)
|
||||
expect(escaped.includes('\\"data\\"')).assertTrue();
|
||||
});
|
||||
|
||||
it('toArray_parses_queue', 0, () => {
|
||||
const list = MessageCodec.toArray('[{"handlerName":"echo","data":"hi","callbackId":"cb1"}]');
|
||||
expect(list.length).assertEqual(1);
|
||||
expect(list[0].handlerName).assertEqual('echo');
|
||||
expect(list[0].data).assertEqual('hi');
|
||||
expect(list[0].callbackId).assertEqual('cb1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('HandlerRegistry', () => {
|
||||
it('put_get_has', 0, () => {
|
||||
const r = new HandlerRegistry();
|
||||
r.put('a', (_d, cb) => cb('A'));
|
||||
expect(r.has('a')).assertTrue();
|
||||
expect(r.has('b')).assertFalse();
|
||||
expect(r.size()).assertEqual(1);
|
||||
});
|
||||
|
||||
it('default_handler_no_throw', 0, () => {
|
||||
const r = new HandlerRegistry();
|
||||
let resp = 'none';
|
||||
// 默认兜底:未注册名不抛错,回空串
|
||||
r.default()('x', (d) => { resp = d; });
|
||||
expect(resp).assertEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('BridgeController', () => {
|
||||
it('inbound_dispatch_and_callback', 0, () => {
|
||||
const fake = new FakeWebController();
|
||||
const bridge = new BridgeController(fake);
|
||||
let got = '';
|
||||
bridge.registerHandler('echo', (data, cb) => { got = data; cb('R:' + data); });
|
||||
bridge.onPageEnd(); // 清空启动队列,进入直发模式
|
||||
|
||||
// 模拟 H5 触发取队列
|
||||
const intercepted = bridge.onLoadIntercept('yy://__QUEUE__/');
|
||||
expect(intercepted).assertTrue();
|
||||
// FakeWebController 应收到 _fetchQueue 触发脚本
|
||||
expect(fake.scripts.some((s) => s.includes('_fetchQueue'))).assertTrue();
|
||||
|
||||
// 模拟 H5 交回队列:一条 echo 调用
|
||||
fake.clear();
|
||||
bridge.onLoadIntercept('yy://return/_fetchQueue/' +
|
||||
encodeURIComponent('[{"handlerName":"echo","data":"hi","callbackId":"cb1"}]'));
|
||||
expect(got).assertEqual('hi');
|
||||
// 回执经 dispatch 下发,脚本含 _handleMessageFromNative 与 responseId cb1
|
||||
const last = fake.lastScript() ?? '';
|
||||
expect(last.includes('_handleMessageFromNative')).assertTrue();
|
||||
expect(last.includes('cb1')).assertTrue();
|
||||
});
|
||||
|
||||
it('outbound_callHandler', 0, () => {
|
||||
const fake = new FakeWebController();
|
||||
const bridge = new BridgeController(fake);
|
||||
bridge.onPageEnd();
|
||||
bridge.callHandler('getlocationinfo', '{"city":"x"}');
|
||||
const last = fake.lastScript() ?? '';
|
||||
expect(last.includes('_handleMessageFromNative')).assertTrue();
|
||||
expect(last.includes('getlocationinfo')).assertTrue();
|
||||
});
|
||||
|
||||
it('startup_queue_flush_after_onPageEnd', 0, () => {
|
||||
const fake = new FakeWebController();
|
||||
const bridge = new BridgeController(fake);
|
||||
// onPageEnd 之前 callHandler → 入启动队列,暂不下发
|
||||
bridge.callHandler('appservice', '1');
|
||||
expect(fake.scripts.length).assertEqual(0);
|
||||
// onPageEnd → 补发
|
||||
bridge.onPageEnd();
|
||||
expect(fake.scripts.some((s) => s.includes('appservice'))).assertTrue();
|
||||
});
|
||||
|
||||
it('response_route_by_responseId', 0, () => {
|
||||
const fake = new FakeWebController();
|
||||
const bridge = new BridgeController(fake);
|
||||
bridge.onPageEnd();
|
||||
let resp = '';
|
||||
// 原生 callHandler 带回调 → 生成 callbackId
|
||||
bridge.callHandler('getTime', '', (r) => { resp = r; });
|
||||
// H5 回执:responseId 对应刚才的 callbackId(从下发脚本里取)
|
||||
const sent = fake.lastScript() ?? '';
|
||||
// 提取 callbackId(JAVA_CB_...)
|
||||
const m = sent.match(/JAVA_CB_[0-9]+_[0-9]+/);
|
||||
expect(m !== null).assertTrue();
|
||||
const cbId = m![0];
|
||||
bridge.onLoadIntercept('yy://return/_fetchQueue/' +
|
||||
encodeURIComponent('[{"responseId":"' + cbId + '","responseData":"1700"}]'));
|
||||
expect(resp).assertEqual('1700');
|
||||
});
|
||||
|
||||
it('default_handler_unregistered_no_throw', 0, () => {
|
||||
const fake = new FakeWebController();
|
||||
const bridge = new BridgeController(fake);
|
||||
bridge.onPageEnd();
|
||||
// 未注册的 handler 名 → 默认兜底,不抛错
|
||||
bridge.onLoadIntercept('yy://return/_fetchQueue/' +
|
||||
encodeURIComponent('[{"handlerName":"finsh","data":"","callbackId":"cb9"}]'));
|
||||
// 兜底回空串回执
|
||||
const last = fake.lastScript() ?? '';
|
||||
expect(last.includes('cb9')).assertTrue();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import localUnitTest from './LocalUnit.test';
|
||||
import bridgeTest from './Bridge.test';
|
||||
|
||||
export default function testsuite() {
|
||||
localUnitTest();
|
||||
bridgeTest();
|
||||
}
|
||||
Reference in New Issue
Block a user