Files
wehub-resource-sync 9b395f5cc3
E2E Headed Chrome / e2e-headed (macos-15) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (ubuntu-latest) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (windows-latest) (push) Has been cancelled
CI / build (macos-latest) (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / unit-test (push) Has been cancelled
CI / bun-test (push) Has been cancelled
CI / adapter-test (push) Has been cancelled
CI / smoke-test (macos-latest) (push) Has been cancelled
CI / smoke-test (ubuntu-latest) (push) Has been cancelled
Security Audit / audit (push) Has been cancelled
Build Chrome Extension / build (push) Has been cancelled
Trigger Website Rebuild (Docs Updated) / dispatch (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:48 +08:00

291 lines
11 KiB
JavaScript

import { describe, expect, it } from 'vitest';
import { MAX_TIEBA_LIMIT, buildTiebaPostCardsFromPagePc, buildTiebaPostItems, buildTiebaSearchItems, buildTiebaReadItems, normalizeTiebaLimit, signTiebaPcParams, } from './utils.js';
describe('normalizeTiebaLimit', () => {
it('caps list commands at the declared tieba maximum', () => {
expect(MAX_TIEBA_LIMIT).toBe(20);
expect(normalizeTiebaLimit(undefined)).toBe(20);
expect(normalizeTiebaLimit(25)).toBe(20);
expect(normalizeTiebaLimit(7)).toBe(7);
});
});
describe('signTiebaPcParams', () => {
it('matches Tieba PC forum-list signing for stable page_pc requests', () => {
expect(signTiebaPcParams({
kw: encodeURIComponent('李毅'),
pn: '1',
sort_type: '-1',
is_newfrs: '1',
is_newfeed: '1',
rn: '30',
rn_need: '20',
tbs: '',
subapp_type: 'pc',
_client_type: '20',
})).toBe('466f2e091dd4ed17c6661a842b5ec342');
});
});
describe('buildTiebaPostCardsFromPagePc', () => {
it('extracts thread cards from signed page_pc feed payloads', () => {
const cards = buildTiebaPostCardsFromPagePc([
{
layout: 'feed',
feed: {
schema: 'tiebaapp://router/portal?params=%7B%22pageParams%22%3A%7B%22tid%22%3A10596901456%7D%7D',
log_param: [
{ key: 'tid', value: '10596901456' },
],
business_info_map: {
thread_id: '10596901456',
title: '崇拜希特勒的人都是日本的汉奸走狗',
},
components: [
{
component: 'feed_head',
feed_head: {
extra_data: [
{
business_info_map: { time_prefix: '回复于' },
text: { text: '1774343231' },
},
],
main_data: [
{
text: { text: '上帝的子民º♬' },
},
],
},
},
{
component: 'feed_title',
feed_title: {
data: [{ text_info: { text: '崇拜希特勒的人都是日本的汉奸走狗' } }],
},
},
{
component: 'feed_social',
feed_social: {
comment_num: 12,
},
},
],
},
},
]);
expect(cards).toEqual([
{
title: '崇拜希特勒的人都是日本的汉奸走狗',
author: '上帝的子民º♬',
descInfo: '回复于2026-03-24 17:07',
commentCount: 12,
actionTexts: [],
threadId: '10596901456',
url: 'https://tieba.baidu.com/p/10596901456',
},
]);
});
});
describe('buildTiebaPostItems', () => {
it('builds stable thread ids and urls from card props without page hops', () => {
const items = buildTiebaPostItems([
{
title: '我来说个事',
author: '暴躁的小伙子',
descInfo: '回复于2分钟前',
actionTexts: ['分享', '评论 5', '点赞 2'],
threadId: '10590564788',
},
], 5);
expect(items).toEqual([
{
rank: 1,
title: '我来说个事',
author: '暴躁的小伙子',
replies: 5,
last_reply: '2分钟前',
id: '10590564788',
url: 'https://tieba.baidu.com/p/10590564788',
},
]);
});
it('honors the public 20-item limit contract', () => {
const raw = Array.from({ length: 25 }, (_, index) => ({
title: `帖子 ${index + 1}`,
author: `作者 ${index + 1}`,
descInfo: '回复于刚刚',
actionTexts: ['分享', `评论 ${index + 1}`],
threadId: String(1000 + index),
}));
const items = buildTiebaPostItems(raw, 25);
expect(items).toHaveLength(20);
expect(items[19]).toMatchObject({
rank: 20,
id: '1019',
url: 'https://tieba.baidu.com/p/1019',
});
});
it('parses Chinese count units and keeps date-time last-reply text intact', () => {
const items = buildTiebaPostItems([
{
title: '复杂格式帖子',
author: '作者',
descInfo: '回复于03-29 11:35',
actionTexts: ['分享', '评论 1.2万'],
url: 'https://tieba.baidu.com/p/123456',
},
], 5);
expect(items[0]).toMatchObject({
replies: 12000,
last_reply: '03-29 11:35',
id: '123456',
url: 'https://tieba.baidu.com/p/123456',
});
});
});
describe('buildTiebaSearchItems', () => {
it('keeps up to 20 search results when the page provides more than 10 cards', () => {
const raw = Array.from({ length: 25 }, (_, index) => ({
title: `结果 ${index + 1}`,
forum: '编程吧',
author: `作者 ${index + 1}`,
time: '2026-03-29',
snippet: `摘要 ${index + 1}`,
id: String(2000 + index),
url: `https://tieba.baidu.com/p/${2000 + index}`,
}));
const items = buildTiebaSearchItems(raw, 25);
expect(items).toHaveLength(20);
expect(items[19]).toMatchObject({
rank: 20,
id: '2019',
url: 'https://tieba.baidu.com/p/2019',
});
});
it('fills missing search ids from stable thread urls', () => {
const items = buildTiebaSearchItems([
{
title: '搜索结果',
forum: '编程吧',
author: '作者',
time: '2026-03-29 11:35',
snippet: '摘要',
id: '',
url: 'https://tieba.baidu.com/p/654321',
},
], 5);
expect(items[0]).toMatchObject({
id: '654321',
url: 'https://tieba.baidu.com/p/654321',
});
});
});
describe('buildTiebaReadItems', () => {
it('prefers visible main-post fields and still keeps floor 1 for media-only threads', () => {
const items = buildTiebaReadItems({
mainPost: {
title: '刚开始读博士的人据说都这样',
author: '湖水之岸',
contentText: '',
structuredText: '',
visibleTime: '03-24',
structuredTime: 1774343231,
hasMedia: true,
},
replies: [],
}, { limit: 5, includeMainPost: true });
expect(items).toEqual([
{
floor: 1,
author: '湖水之岸',
content: '刚开始读博士的人据说都这样 [media]',
time: '03-24',
},
]);
});
it('falls back to structured main-post data when visible text is missing', () => {
const items = buildTiebaReadItems({
mainPost: {
title: '标题',
author: '',
fallbackAuthor: '结构化作者',
contentText: '',
structuredText: '结构化正文',
visibleTime: '',
structuredTime: 1774343231,
hasMedia: false,
},
replies: [
{ floor: 2, author: '回复者', content: '二楼内容', time: '第2楼 2026-03-25 12:34 广东' },
],
}, { limit: 5, includeMainPost: true });
expect(items[0]).toMatchObject({
floor: 1,
author: '结构化作者',
content: '标题 结构化正文',
time: '2026-03-24 17:07',
});
expect(items[1]).toMatchObject({
floor: 2,
author: '回复者',
content: '二楼内容',
time: '2026-03-25 12:34',
});
});
it('strips trailing location metadata from reply times', () => {
const items = buildTiebaReadItems({
mainPost: {
title: '主楼',
author: '楼主',
contentText: '正文',
visibleTime: '03-24',
},
replies: [
{ floor: 2, author: '二楼', content: '二楼内容', time: '第2楼 3小时前 福建' },
{ floor: 3, author: '三楼', content: '三楼内容', time: '第3楼 刚刚 江苏' },
],
}, { limit: 5, includeMainPost: false });
expect(items).toEqual([
{
floor: 2,
author: '二楼',
content: '二楼内容',
time: '3小时前',
},
{
floor: 3,
author: '三楼',
content: '三楼内容',
time: '刚刚',
},
]);
});
it('counts limit as replies and skips main post on later pages', () => {
const items = buildTiebaReadItems({
mainPost: {
title: '主楼',
author: '楼主',
contentText: '正文',
visibleTime: '03-24',
},
replies: [
{ floor: 2, author: '二楼', content: '二楼内容', time: '第2楼 03-25' },
{ floor: 3, author: '三楼', content: '三楼内容', time: '第3楼 03-26' },
{ floor: 4, author: '四楼', content: '四楼内容', time: '第4楼 03-27' },
],
}, { limit: 2, includeMainPost: true });
expect(items).toHaveLength(3);
expect(items.map((item) => item.floor)).toEqual([1, 2, 3]);
const page2 = buildTiebaReadItems({
mainPost: {
title: '主楼',
author: '楼主',
contentText: '正文',
visibleTime: '03-24',
},
replies: [
{ floor: 26, author: '二十六楼', content: '二十六楼内容', time: '第26楼 03-29' },
],
}, { limit: 2, includeMainPost: false });
expect(page2.map((item) => item.floor)).toEqual([26]);
});
});