const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const ts = require('typescript'); function loadUtility() { const filename = path.resolve(__dirname, '../src/utils/account-events.ts'); const source = fs.readFileSync(filename, 'utf8'); const compiled = ts.transpileModule(source, {compilerOptions:{module:ts.ModuleKind.CommonJS, target:ts.ScriptTarget.ES2020}}).outputText; const module = {exports:{}}; new Function('module','exports',compiled)(module,module.exports); return module.exports; } test('event links require real profile identifiers and matching canonical work URLs', () => { const {eventUserProfileURL,eventWorkURL}=loadUtility(); assert.equal(eventUserProfileURL('MS4wLjABAAAAprofile'),'https://www.douyin.com/user/MS4wLjABAAAAprofile'); for(const id of [undefined,'','../123','not a profile']) assert.equal(eventUserProfileURL(id),undefined); assert.equal(eventWorkURL('123'),'https://www.douyin.com/video/123'); assert.equal(eventWorkURL('123','https://www.douyin.com/note/123'),'https://www.douyin.com/note/123'); for(const url of ['https://www.douyin.com/video/456','https://wwwXdouyinYcom/video/123','https://example.com/video/123']) assert.equal(eventWorkURL('123',url),undefined); for(const id of ['', '0', '../123']) assert.equal(eventWorkURL(id),undefined); }); test('listener status distinguishes stopped, startup, ready, interruption and error', () => { const {listenerStatusLabel} = loadUtility(); assert.equal(listenerStatusLabel('stopped'), '已关闭'); assert.equal(listenerStatusLabel('starting'), '启动中'); assert.equal(listenerStatusLabel('ready'), '接收正常'); assert.equal(listenerStatusLabel('gap'), '可能有遗漏'); assert.equal(listenerStatusLabel('stopping'), '关闭中'); assert.equal(listenerStatusLabel('error'), '异常'); assert.equal(listenerStatusLabel('unrecognized'), 'unrecognized'); }); test('aggregation query includes pagination and filters without inventing defaults', () => { const {eventQuery} = loadUtility(); const query = new URLSearchParams(eventQuery({accountId:'account 1', eventType:'comment', hours:0},2,50)); assert.equal(query.get('account_id'), 'account 1'); assert.equal(query.get('event_type'), 'comment'); assert.equal(query.get('hours'), '0'); assert.equal(query.get('page'), '2'); assert.equal(query.get('page_size'), '50'); const empty = new URLSearchParams(eventQuery({hours:24},1,25)); assert.equal(empty.has('account_id'),false); assert.equal(empty.has('event_type'),false); }); test('all supported event types and non-text messages have readable labels', () => { const {eventTypeLabel,messageTypeLabel} = loadUtility(); for (const kind of ['like','comment','follow','repost']) assert.notEqual(eventTypeLabel(kind),kind); for (const kind of ['image','voice','video','sticker','non_text']) assert.notEqual(messageTypeLabel(kind),kind); assert.equal(messageTypeLabel('text'),'—'); }); test('owned account list has an opt-in listener column and blocks pending environments', () => { const source = fs.readFileSync(path.resolve(__dirname,'../src/components/accounts/AccountManagementList.tsx'),'utf8'); assert.match(source,/title: '监听状态'/); assert.match(source,/checked=\{Boolean\(row.listener_enabled\)\}/); assert.match(source,/row.login_status !== 'logged_in' && !row.listener_enabled/); assert.match(source,/if \(row.pending_environment\) return/); assert.match(source,/\/listener/); }); test('event aggregation is listed in the left menu and keeps source scope explicit', () => { const metadata = fs.readFileSync(path.resolve(__dirname,'../src/utils/metadata.tsx'),'utf8'); assert.match(metadata,/\/creator\/events/); assert.match(metadata,/事件聚合/); const source = fs.readFileSync(path.resolve(__dirname,'../src/pages/creator/events/index.tsx'),'utf8'); assert.match(source,/listener_enabled/); assert.match(source,/setPagination\(\{ page: 1/); assert.match(source,/停止监听的账号不在此列表展示/); assert.doesNotMatch(source,/label: '私信'/); assert.match(source,/私信在独立收件箱展示/); assert.match(source,/开启后通知/); });