From 159dcf2687c240be1a86198cf5a1ad7a928f01c8 Mon Sep 17 00:00:00 2001 From: lanterngamescn Date: Thu, 25 Jun 2026 12:26:23 +0800 Subject: [PATCH] =?UTF-8?q?M1:=20=E6=A1=A5=E5=BC=95=E6=93=8E=E5=8D=95?= =?UTF-8?q?=E6=B5=8B=E8=B7=91=E9=80=9A=EF=BC=8C=E6=A1=A5=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E7=8E=87=2087.3%=EF=BC=88T-M1-08=20=E5=AE=8C?= =?UTF-8?q?=E6=88=90=EF=BC=8CR-18=20=E5=A4=84=E7=BD=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 2 个测试用例(漏先触发 flushMessageQueue 注册 _fetchQueue 回调) - 补 set_default/remove、FakeWebController、send 用例,共 15 用例全通过 - 桥核心覆盖率 87.3%(MessageCodec/Message 100%、BridgeController 83%、 HandlerRegistry 88%)≥80% 达标;Adapter/BridgeJsLoader 系统耦合由 V1 真机覆盖 - scripts/test.sh:本地单测 + 覆盖率运行脚本(devecocli 无 test,用 DevEco hvigorw + 强制 DEVECO_SDK_HOME 指向自带 sdk);ci.sh 集成单测(SKIP_TESTS=1 可跳过) Co-Authored-By: Claude Opus 4.8 (1M context) --- entry/src/test/Bridge.test.ets | 42 ++++++++++++++++++++++++++++++++++ scripts/ci.sh | 11 +++++---- scripts/test.sh | 29 +++++++++++++++++++++++ 3 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 scripts/test.sh diff --git a/entry/src/test/Bridge.test.ets b/entry/src/test/Bridge.test.ets index 525a705..fc2dc8f 100644 --- a/entry/src/test/Bridge.test.ets +++ b/entry/src/test/Bridge.test.ets @@ -67,6 +67,34 @@ export default function bridgeTest() { r.default()('x', (d) => { resp = d; }); expect(resp).assertEqual(''); }); + + it('set_default_and_remove', 0, () => { + const r = new HandlerRegistry(); + let v = ''; + r.setDefault((d, cb) => cb('D:' + d)); + r.default()('x', (s) => { v = s; }); + expect(v).assertEqual('D:x'); + r.put('a', (_d, cb) => cb('A')); + expect(r.size()).assertEqual(1); + r.remove('a'); + expect(r.has('a')).assertFalse(); + }); + }); + + describe('FakeWebController', () => { + it('records_and_clears', 0, () => { + const f = new FakeWebController(); + expect(f.lastScript() === undefined).assertTrue(); + f.runJavaScript('s1'); + f.loadUrl('u1'); + expect(f.scripts.length).assertEqual(1); + expect(f.loadedUrls.length).assertEqual(1); + expect(f.lastScript()).assertEqual('s1'); + f.dispose(); + f.clear(); + expect(f.scripts.length).assertEqual(0); + expect(f.lastScript() === undefined).assertTrue(); + }); }); describe('BridgeController', () => { @@ -104,6 +132,16 @@ export default function bridgeTest() { expect(last.includes('getlocationinfo')).assertTrue(); }); + it('send_no_handlerName', 0, () => { + const fake = new FakeWebController(); + const bridge = new BridgeController(fake); + bridge.onPageEnd(); + bridge.send('hello'); + const last = fake.lastScript() ?? ''; + expect(last.includes('_handleMessageFromNative')).assertTrue(); + expect(last.includes('hello')).assertTrue(); + }); + it('startup_queue_flush_after_onPageEnd', 0, () => { const fake = new FakeWebController(); const bridge = new BridgeController(fake); @@ -128,6 +166,8 @@ export default function bridgeTest() { const m = sent.match(/JAVA_CB_[0-9]+_[0-9]+/); expect(m !== null).assertTrue(); const cbId = m![0]; + // 先触发 flushMessageQueue 注册 _fetchQueue 回调,回执经队列机制路由 + bridge.onLoadIntercept('yy://__queue__/'); bridge.onLoadIntercept('yy://return/_fetchQueue/' + encodeURIComponent('[{"responseId":"' + cbId + '","responseData":"1700"}]')); expect(resp).assertEqual('1700'); @@ -137,6 +177,8 @@ export default function bridgeTest() { const fake = new FakeWebController(); const bridge = new BridgeController(fake); bridge.onPageEnd(); + // 先触发 flushMessageQueue 注册 _fetchQueue 回调 + bridge.onLoadIntercept('yy://__queue__/'); // 未注册的 handler 名 → 默认兜底,不抛错 bridge.onLoadIntercept('yy://return/_fetchQueue/' + encodeURIComponent('[{"handlerName":"finsh","data":"","callbackId":"cb9"}]')); diff --git a/scripts/ci.sh b/scripts/ci.sh index a5d5f08..69a9830 100644 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -21,10 +21,11 @@ fi echo "==> [CI] 多模块构建校验:devecocli build --build-mode ${MODE}" devecocli build --build-mode "${MODE}" -# 单元测试:当前 devecocli 无 test 子命令;待 M1 桥引擎单测(T-M1-08, -# MessageCodec/HandlerRegistry/BridgeController ≥80% 覆盖)落地并确定运行方式 -# (hypium)后,在此启用,例如: -# echo "==> [CI] 单元测试" -# +# 单元测试 + 覆盖率(本地单测)。devecocli 无 test 子命令,故经 DevEco hvigorw(见 test.sh)。 +# 需 DevEco 环境;CI runner 无 DevEco 时设 SKIP_TESTS=1 跳过。 +if [ "${SKIP_TESTS:-0}" != "1" ]; then + echo "==> [CI] 单元测试 + 覆盖率" + bash "${ROOT}/scripts/test.sh" +fi echo "==> [CI] 校验通过 (${MODE})" diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100644 index 0000000..b12bdf8 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# 本地单元测试 + 覆盖率(T-M1-08,R-18 处置)。 +# +# devecocli 无 test 子命令,故用 DevEco 自带 hvigorw 跑本地单测(已获授权的例外)。 +# 注意:本机环境变量 DEVECO_SDK_HOME 可能指向不含目标 SDK 的位置,这里强制指向 +# DevEco Studio 自带 sdk(含 6.1.1(24))。CI 环境需装 DevEco 或用 DEVECO_HOME 覆盖。 +# +# 用法:bash scripts/test.sh +# 报告:entry/.test/default/outputs/test/reports/(含 coverageReport.json + html) +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +DEVECO="${DEVECO_HOME:-/c/Program Files/Huawei/DevEco Studio}" +export DEVECO_SDK_HOME="${DEVECO_SDK_HOME_OVERRIDE:-${DEVECO}/sdk}" +NODE="${DEVECO}/tools/node/node.exe" +HVIGOR="${DEVECO}/tools/hvigor/bin/hvigorw.js" + +echo "==> [test] 本地单测 + 覆盖率 (DEVECO_SDK_HOME=${DEVECO_SDK_HOME})" +"${NODE}" "${HVIGOR}" test \ + --mode module \ + -p module=entry@default \ + -p product=default \ + -p buildMode=test \ + -p coverage=true \ + "$@" + +echo "==> [test] 完成。覆盖率报告:entry/.test/default/outputs/test/reports/coverageReport.json"