2026-10-18 23:35:28 +08:00
|
|
|
const test = require('node:test')
|
|
|
|
|
const assert = require('node:assert/strict')
|
|
|
|
|
const fs = require('node:fs')
|
|
|
|
|
const path = require('node:path')
|
|
|
|
|
const vm = require('node:vm')
|
|
|
|
|
const ts = require('typescript')
|
|
|
|
|
const root = path.resolve(__dirname, '..')
|
|
|
|
|
const read = file => fs.readFileSync(path.join(root, file), 'utf8')
|
|
|
|
|
|
|
|
|
|
function page(file, { guest = false, bound = false, element = false, routes = [] } = {}) {
|
|
|
|
|
const profile = guest ? null : { birthday: '1998-06-18', birthHour: '辰时' }
|
|
|
|
|
const factor = { description: '测试' }
|
|
|
|
|
const report = { scores: [], dayMaster: '甲', masterElement: '木', strength: '偏弱', strengthScore: 20,
|
|
|
|
|
pillars: [], favorable: '水木', unfavorable: '土', analysis: { season: factor, roots: factor, support: factor } }
|
|
|
|
|
const day = { label: '今日', date: '2026-10-18' }
|
|
|
|
|
const exports = {}
|
|
|
|
|
vm.runInNewContext(ts.transpileModule(read(file), { compilerOptions: {
|
|
|
|
|
module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019, jsx: ts.JsxEmit.ReactJSX
|
2026-10-21 20:33:50 +08:00
|
|
|
} }).outputText, { exports, process: { env: { TARO_ENV: 'weapp' } }, require: id => {
|
2026-10-18 23:35:28 +08:00
|
|
|
if (id === 'react/jsx-runtime') return require(id)
|
|
|
|
|
if (id === 'react') return { useEffect: () => {}, useMemo: fn => fn(), useRef: value => ({ current: value }),
|
|
|
|
|
useState: value => [element && value === 'home' ? 'element' : typeof value === 'function' ? value() : value, () => {}] }
|
2026-10-21 20:33:50 +08:00
|
|
|
if (id === '@tarojs/taro') return { useDidShow: () => {}, default: {
|
|
|
|
|
getWindowInfo: () => ({ statusBarHeight: 44, safeArea: { top: 44 } })
|
|
|
|
|
} }
|
2026-10-18 23:35:28 +08:00
|
|
|
if (id === '@tarojs/components') return { View: 'View', Text: 'Text', Button: 'Button', Image: 'Image' }
|
|
|
|
|
if (id.endsWith('/LoginGate')) return { LoginGate: 'shared-login-gate' }
|
|
|
|
|
if (id.endsWith('/tabNavigation')) return { switchMainTab: (target, active) => routes.push([target, active]) }
|
|
|
|
|
if (id.endsWith('/useTiangongSnapshot')) return { useTiangongSnapshot: () => ({}) }
|
|
|
|
|
if (id.endsWith('/tiangongMock')) return { hasBoundDeity: () => bound }
|
|
|
|
|
if (id.endsWith('/tiangong')) return { deityCatalog: [] }
|
|
|
|
|
if (id.endsWith('/frontendPreview')) return { isFrontendPreview: () => false }
|
|
|
|
|
if (id.endsWith('/avatarDemo')) return { isAvatarDemo: () => false }
|
|
|
|
|
if (id.endsWith('/request')) return { getCachedProfile: () => profile, getToken: () => guest ? '' : 'test' }
|
|
|
|
|
if (id.endsWith('/zodiacWeekly')) return { getBeijingDate: () => '2026-10-18', calculateWeeklyZodiacFortune: () => null }
|
|
|
|
|
if (id.endsWith('/zodiac')) return { calculateZodiac: () => null }
|
|
|
|
|
if (id.endsWith('/fiveElements')) return { calculateFiveElements: () => report }
|
|
|
|
|
if (id.endsWith('/homeOverview')) return { HOME_DIMENSION_IDS: [], generateHomeOverview: () => ({ days: [day, day, day], dimensions: [], luckyColors: [], luckyNumbers: [], luckyHours: [] }) }
|
|
|
|
|
return {}
|
|
|
|
|
} })
|
|
|
|
|
return exports.default()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test('首页和我的未登录入口使用同一登录组件;天宫包装也复用它', () => {
|
|
|
|
|
assert.equal(page('src/pages/home/index.tsx', { guest: true }).type, 'shared-login-gate')
|
|
|
|
|
assert.equal(page('src/pages/my/index.tsx', { guest: true }).type, 'shared-login-gate')
|
|
|
|
|
assert.match(read('src/components/TiangongLoginGate.tsx'), /return <LoginGate/)
|
2026-11-03 00:16:16 +08:00
|
|
|
assert.doesNotMatch(read('src/pages/login/index.tsx'), /brand-mark|一触即吉|祈运/)
|
2026-10-18 23:35:28 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('首页头像点击使用主Tab导航前往我的页面', () => {
|
|
|
|
|
const routes = [], tree = page('src/pages/home/index.tsx', { routes })
|
|
|
|
|
function find(node) {
|
|
|
|
|
if (!node || typeof node !== 'object') return null
|
|
|
|
|
if (node.props?.['aria-label'] === '前往我的页面') return node
|
|
|
|
|
const children = node.props?.children
|
|
|
|
|
return (Array.isArray(children) ? children : [children]).map(find).find(Boolean)
|
|
|
|
|
}
|
|
|
|
|
const avatar = find(tree)
|
|
|
|
|
assert.ok(avatar)
|
|
|
|
|
avatar.props.onClick()
|
|
|
|
|
assert.deepEqual(routes, [['my', 'home']])
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('未绑定首页与元素报告固定首屏;绑定后移除锁定类恢复滚动', () => {
|
|
|
|
|
for (const [file, element] of [['src/pages/home/index.tsx', false], ['src/pages/my/index.tsx', true]]) {
|
|
|
|
|
const locked = page(file, { bound: false, element }), unlocked = page(file, { bound: true, element })
|
|
|
|
|
assert.match(locked.props.className, /binding-viewport-locked/)
|
|
|
|
|
assert.equal(locked.props.catchMove, true)
|
|
|
|
|
assert.doesNotMatch(unlocked.props.className, /binding-viewport-locked/)
|
|
|
|
|
assert.equal(unlocked.props.catchMove, false)
|
|
|
|
|
}
|
|
|
|
|
const runner = require.resolve('@tarojs/webpack5-runner')
|
|
|
|
|
const sass = require(require.resolve('sass', { paths: [runner] }))
|
|
|
|
|
const postcss = require(require.resolve('postcss', { paths: [runner] }))
|
|
|
|
|
const css = sass.renderSync({ file: path.join(root, 'src/components/DeityBinding.scss') }).css.toString()
|
|
|
|
|
let checked = false
|
|
|
|
|
postcss.parse(css).walkRules(rule => {
|
|
|
|
|
if (!rule.selector.includes('.home-page.binding-viewport-locked')) return
|
|
|
|
|
const declarations = Object.fromEntries(rule.nodes.filter(node => node.type === 'decl').map(node => [node.prop, node.value]))
|
|
|
|
|
assert.equal(declarations.position, 'fixed')
|
|
|
|
|
assert.equal(declarations.overflow, 'hidden')
|
|
|
|
|
assert.equal(declarations.height, '100%')
|
|
|
|
|
checked = true
|
|
|
|
|
})
|
|
|
|
|
assert.ok(checked)
|
|
|
|
|
assert.match(read('src/components/DeityBinding.tsx'), /className='binding-gate' catchMove/)
|
|
|
|
|
})
|