2026-09-13 21:24:54 +08:00
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
|
import vm from 'node:vm'
|
2026-09-23 09:55:40 +08:00
|
|
|
// 首页会 require 顶部安全区工具(utils/nav-metrics.js)。这里直接注入**真实模块**而不是手写桩:
|
|
|
|
|
// 沙箱里没有 getWindowInfo / getMenuButtonBoundingClientRect,正好走它的兜底分支,
|
|
|
|
|
// 等于顺带验证了「系统接口不可用时也能给出安全值」。
|
|
|
|
|
import navMetrics from '../miniapp/utils/nav-metrics.js'
|
2026-09-13 21:24:54 +08:00
|
|
|
|
|
|
|
|
const source = readFileSync(new URL('../miniapp/pages/index/index.ts', import.meta.url), 'utf8')
|
|
|
|
|
let page
|
|
|
|
|
|
|
|
|
|
const sandbox = {
|
|
|
|
|
require(request) {
|
|
|
|
|
if (request === '../../stores') {
|
|
|
|
|
return {
|
|
|
|
|
authStore: { state: { isLoggedIn: false } },
|
|
|
|
|
appStore: { toastSuccess() {} },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (request === '../../utils/api') {
|
|
|
|
|
return { get: async () => { throw new Error('未登录时不应请求首页接口') } }
|
|
|
|
|
}
|
2026-09-23 09:55:40 +08:00
|
|
|
if (request === '../../utils/nav-metrics') {
|
|
|
|
|
return navMetrics
|
|
|
|
|
}
|
2026-09-13 21:24:54 +08:00
|
|
|
throw new Error(`未预期依赖:${request}`)
|
|
|
|
|
},
|
|
|
|
|
Page(config) { page = config },
|
|
|
|
|
wx: {
|
|
|
|
|
getAccountInfoSync() {
|
|
|
|
|
return { miniProgram: { envVersion: 'develop' } }
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
console,
|
|
|
|
|
setTimeout,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm.runInNewContext(source, sandbox, { filename: 'miniapp/pages/index/index.ts' })
|
|
|
|
|
assert.ok(page, '首页必须注册 Page 配置')
|
|
|
|
|
|
|
|
|
|
const pageState = { ...page.data }
|
|
|
|
|
await page.checkAuthAndLoad.call({
|
|
|
|
|
data: pageState,
|
|
|
|
|
setData(data) { Object.assign(pageState, data) },
|
|
|
|
|
loadHomeData() { throw new Error('未登录时不应进入首页数据加载流程') },
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
assert.equal(pageState.isOnboarding, true, '未登录时应进入登录引导状态')
|
|
|
|
|
assert.equal(pageState.userState, null, '未登录状态不得伪造实名用户,实名状态必须来自服务端数据库')
|
|
|
|
|
|
2026-09-23 09:55:40 +08:00
|
|
|
// 顶部安全区:无系统接口时必须退回兜底值(宁可多留不可少留),且四个 CSS 变量齐备
|
|
|
|
|
const fallbackVars = navMetrics.navSafeData(true)
|
|
|
|
|
assert.match(
|
|
|
|
|
fallbackVars.navVars,
|
|
|
|
|
/--nav-status:\d+px;--nav-h:\d+px;--nav-right:\d+px;--nav-top:\d+px;/,
|
|
|
|
|
'顶部安全区必须给出四个 CSS 变量(状态栏 / 导航行 / 胶囊安全区 / 内容起点)',
|
|
|
|
|
)
|
|
|
|
|
assert.ok(fallbackVars.navTopPx >= 64, '拿不到胶囊信息时也要留足顶部空间,避免压住操作按钮')
|
|
|
|
|
|
2026-09-13 21:24:54 +08:00
|
|
|
console.log('Phase 03 verification contracts passed')
|