Files
hera-web/scripts/loginPresentation.test.cjs
T

89 lines
5.2 KiB
JavaScript

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
} }).outputText, { exports, process: { env: { TARO_ENV: 'weapp' } }, require: id => {
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, () => {}] }
if (id === '@tarojs/taro') return { useDidShow: () => {}, default: {
getWindowInfo: () => ({ statusBarHeight: 44, safeArea: { top: 44 } })
} }
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/)
assert.doesNotMatch(read('src/pages/login/index.tsx'), /brand-mark|一触即吉|那吉/)
})
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/)
})