验证20%

This commit is contained in:
rain
2026-07-31 11:31:26 +08:00
parent 309598bfa6
commit ac5823547a
24 changed files with 751 additions and 279 deletions
+24
View File
@@ -118,3 +118,27 @@ test('authentication captcha ticket is removed from the form when consumed', ()
assert.equal(field.value, '');
assert.equal(AuthPages.takeCaptchaToken(form), '');
});
test('successful login enters one real genealogy directly and otherwise opens the chooser', async () => {
assert.equal(
AuthPages.getPostLoginUrl([{ genealogyId: '2062179707935264769' }]),
'profile-family-home.html?genealogyId=2062179707935264769'
);
assert.equal(AuthPages.getPostLoginUrl([]), 'profile-families.html');
assert.equal(
AuthPages.getPostLoginUrl([{ genealogyId: '1' }, { genealogyId: '2' }]),
'profile-families.html'
);
assert.equal(
AuthPages.getPostLoginUrl([{ genealogyId: Number.MAX_SAFE_INTEGER + 1 }]),
'profile-families.html'
);
assert.equal(
await AuthPages.resolvePostLoginUrl({
genealogiesMine: async () => {
throw new Error('temporary failure');
}
}, 'login'),
'profile.html'
);
});
+33 -4
View File
@@ -213,19 +213,48 @@ test('家谱业务模块运行时统一委托 ProfileUI 读取和传播上下文
});
});
test('个人中心和内容发布在缺少家谱上下文时统一进入家谱入口', () => {
test('个人中心只保留真实家谱入口,内容发布仍会透传家谱上下文', () => {
const profile = read('profile.html');
const content = read('profile-content.html');
const familyHome = read('profile-family-home.html');
const familyEntry = read('profile-families.html');
const profileCommon = read('public/js/profile-common.js');
const profileMain = profile.slice(0, profile.indexOf('</main>'));
assert.match(profile, /进入我的家谱/);
assert.doesNotMatch(profile, /四川武胜汤氏族|四川达州刘氏族/);
assert.match(profile, /href="profile-family-admin\.html" data-genealogy-context-link/);
assert.match(profileMain, /进入我的家谱/);
assert.match(profileMain, /href="profile-families\.html"/);
assert.doesNotMatch(profileMain, /鹿野 Loyel|待处理|已发布内容|资料完善度/);
assert.doesNotMatch(profileMain, /href="profile-(?:article|album|video|merit|gift|join-review)\.html"/);
assert.match(content, /href="profile-feed\.html" data-feature-link="available" data-genealogy-context-link/);
assert.match(familyHome, /href="profile-family-admin\.html" data-genealogy-context-link/);
assert.match(familyEntry, /href="profile-family-admin\.html" data-genealogy-context-link/);
assert.match(profileCommon, /function getGenealogyEntryUrl\(href\)/);
assert.match(profileCommon, /genealogyId \? withGenealogyId\([^\n]+\) : getGenealogyEntryUrl\(/);
assert.match(read('public/js/genealogy-entry-pages.js'), /if \(shouldRedirectToLogin\(api\)\) \{\s+redirectToLogin\(api\);/);
});
test('当前家谱名称从真实家谱响应写入会话上下文,并在页头提供切换入口', () => {
const common = read('public/js/profile-common.js');
const entry = read('public/js/genealogy-entry-pages.js');
const familyHome = read('public/js/family-home-pages.js');
assert.match(common, /genealogyContextStorageKey/);
assert.match(common, /function setCurrentGenealogyContext\(genealogyId, genealogyName\)/);
assert.match(common, /class="profile-current-genealogy"/);
assert.match(common, /href="profile-families\.html"/);
assert.match(entry, /data-genealogy-name=/);
assert.match(entry, /root\.ProfileUI\.setCurrentGenealogyContext\(verified\.genealogyId, verified\.genealogyName\)/);
assert.match(familyHome, /root\.ProfileUI\.setCurrentGenealogyContext\(result\.overview\.genealogyId, result\.overview\.genealogyName\)/);
});
test('小屏导航提供统一入口,并且所有家谱内链接继续透传当前上下文', () => {
const common = read('public/js/profile-common.js');
const css = read('public/css/public.css');
assert.match(common, /data-profile-mobile-menu-toggle/);
assert.match(common, /data-profile-mobile-menu/);
assert.match(common, /profile-family-home\.html" data-genealogy-context-link/);
assert.match(common, /profile-family-admin\.html" data-genealogy-context-link/);
assert.match(css, /\.profile-mobile-menu\.is-open/);
assert.match(css, /\.profile-current-genealogy/);
});
+36
View File
@@ -0,0 +1,36 @@
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const test = require('node:test');
const root = path.join(__dirname, '..');
function read(file) {
return fs.readFileSync(path.join(root, file), 'utf8');
}
test('profile navigation has a medium-desktop compact mode and no mobile duplicate sidebar', () => {
const publicCss = read('public/css/public.css');
const moduleCss = read('public/css/profile-module.css');
assert.match(
publicCss,
/@media \(max-width: 1320px\) \{[\s\S]*?\.page-profile \.nav-links,[\s\S]*?\.page-profile-module \.nav-links \{\s*display: none;/
);
assert.match(
moduleCss,
/@media \(max-width: 720px\) \{[\s\S]*?\.page-profile-module \.module-nav \{\s*display: none;/
);
});
test('my genealogies keeps one primary create action and the compact menu marks the current page', () => {
const page = read('profile-families.html');
const header = page.slice(0, page.indexOf('</header>'));
const common = read('public/js/profile-common.js');
const publicCss = read('public/css/public.css');
assert.doesNotMatch(header, /href="profile-create-family\.html"/);
assert.match(page, /module-title-row[\s\S]*?href="profile-create-family\.html"/);
assert.match(common, /addClass\('is-current'\)\.attr\('aria-current', 'page'\)/);
assert.match(publicCss, /\.profile-mobile-menu a\.is-current/);
});
+10
View File
@@ -38,6 +38,16 @@ test('profile view reads only the documented profile fields', () => {
});
});
test('profile loading failure has an explicit non-demo view', () => {
assert.deepEqual(ProfilePages.buildUnavailableProfileView(), {
displayName: '账户资料暂时无法读取',
avatarText: '',
phone: '暂无数据',
birthday: '暂无数据',
regionText: '暂无数据'
});
});
test('profile update emits only the six fields defined by ProfileUpdateBody', () => {
assert.deepEqual(ProfilePages.buildProfileUpdateBody({
nickName: '小林',
+20 -5
View File
@@ -26,12 +26,12 @@ test('家谱主页公开谱文、相册、视频、功德和祭祀活动入口
});
});
test('个人中心功能入口没有把家谱业务页当作无上下文普通链接', () => {
test('个人中心先引导进入真实家谱列表,不展示无上下文的业务入口', () => {
const page = read('profile.html');
const main = page.slice(0, page.indexOf('</main>'));
['profile-article.html', 'profile-album.html', 'profile-video.html', 'profile-merit.html', 'profile-gift.html'].forEach((href) => {
assert.match(page, new RegExp('href="' + href.replace('.', '\\.') + '"[^>]*data-genealogy-context-link'), `${href} 缺少个人中心上下文入口`);
});
assert.match(main, /href="profile-families\.html"/);
assert.doesNotMatch(main, /href="profile-(?:article|album|video|merit|gift|join-review)\.html"/);
});
test('加入申请与管理员审核入口使用真实页面和家谱上下文', () => {
@@ -42,7 +42,7 @@ test('加入申请与管理员审核入口使用真实页面和家谱上下文',
assert.match(families, /href="profile-join-family\.html"/);
assert.doesNotMatch(families, /邀请码|分享码|手填.*ID/);
assert.match(familyAdmin, /href="profile-join-review\.html"[^>]*data-genealogy-context-link/);
assert.match(profile, /href="profile-join-review\.html"[^>]*data-genealogy-context-link/);
assert.match(profile, /href="profile-families\.html"/);
});
test('帮助中心和服务中心开放同一反馈记录闭环', () => {
@@ -54,3 +54,18 @@ test('帮助中心和服务中心开放同一反馈记录闭环', () => {
assert.match(services, /href="profile-feedback\.html"[^>]*data-feature-link="available"/);
assert.doesNotMatch(help + services, /手填.*feedbackId|独立.*ticket.*接口/i);
});
test('个人中心、我的家谱和当前家谱主页使用明确且可返回的三级路径', () => {
const account = read('profile.html');
const families = read('profile-families.html');
const familyHome = read('profile-family-home.html');
const familyHomeRuntime = read('public/js/family-home-pages.js');
const coreHeaders = [account, families, familyHome].map((page) => page.slice(0, page.indexOf('</header>'))).join('');
assert.match(account, /<a class="active" href="profile\.html">个人中心<\/a>/);
assert.match(account, /<a href="profile-families\.html">我的家谱<\/a>/);
assert.match(families, /<nav class="profile-path" aria-label="当前位置">[\s\S]*个人中心[\s\S]*我的家谱/);
assert.match(familyHome, /<nav class="profile-path" aria-label="当前位置">[\s\S]*profile-families\.html[\s\S]*data-family-home-context/);
assert.match(familyHomeRuntime, /setText\('\[data-family-home-context\]', result\.overview\.genealogyName\)/);
assert.doesNotMatch(coreHeaders, /返回中心|数字家谱/);
});