import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const adminRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const deepseekPagePath = path.join(adminRoot, 'src/pages/ai/deepseek/index.tsx'); const deepseekLocalePath = path.join(adminRoot, 'src/pages/ai/deepseek/locale/index.ts'); /** 账单式误导词(标题/指标/描述里禁止正向使用;disclaimer 可否定提及) */ const BILLING_MISLEAD_RE = /账本|账单|已出账|对账|划扣|本月账单|invoice|billed|billing|pay-as-you-go|ledger|reconcil/i; /** 前端不得填入的示例消耗数字 */ const SAMPLE_USAGE_RE = /totalTokens:\s*[1-9]\d*|promptTokens:\s*[1-9]\d*|completionTokens:\s*[1-9]\d*|callCount:\s*[1-9]\d*/; function readPage(): string { assert.ok(fs.existsSync(deepseekPagePath), 'DeepSeek 配置页必须存在'); return fs.readFileSync(deepseekPagePath, 'utf-8'); } function readLocale(): string { assert.ok(fs.existsSync(deepseekLocalePath), 'DeepSeek 语言包必须存在'); return fs.readFileSync(deepseekLocalePath, 'utf-8'); } /** 去掉 usage.notice 词条后再扫误导词,避免「不是账单」说明被误伤 */ function localeWithoutUsageNotice(locale: string): string { return locale.replace( /'ai\.deepseek\.usage\.notice'\s*:\s*(?:'(?:\\'|[^'])*'|"(?:\\"|[^"])*"|`(?:\\`|[^`])*`)\s*,?/g, '' ); } test('1. DeepSeek 页必须请求 usage,且无用量时回落 0 / 空,禁止示例消耗', () => { const content = readPage(); assert.ok( content.includes('/api/admin/ai/deepseek/usage'), '必须请求 POST /api/admin/ai/deepseek/usage' ); assert.ok( content.includes('/api/admin/ai/deepseek/config'), '必须请求配置端点' ); assert.ok( content.includes("from '@arco-design/web-react'"), '必须从 @arco-design/web-react 引入组件' ); assert.ok(content.includes('Statistic'), '必须用 Statistic 展示用量'); assert.ok(content.includes('Alert'), '必须用 Alert 标明进程内性质'); assert.ok( /totalTokens:\s*0/.test(content) && /promptTokens:\s*0/.test(content) && /completionTokens:\s*0/.test(content) && /callCount:\s*0/.test(content), '初始用量必须为 0,不得填示例消耗' ); assert.ok(!SAMPLE_USAGE_RE.test(content), '禁止硬编码非零示例 Token 消耗'); assert.ok( content.includes('usageRes.data?.data') || content.includes('usageRes.data.data'), '仅当接口返回 data 时才写入用量' ); assert.ok(!/\bany\b/.test(content), '禁止使用 any'); assert.ok( !content.includes('Mock.js') && !content.includes("from 'mockjs'"), '禁止用 Mock.js 假用量' ); }); test('2. Token 用量文案必须标明进程内统计,禁止账单式误导', () => { const page = readPage(); const locale = readLocale(); assert.ok( locale.includes("'ai.deepseek.usage.cardTitle'") || locale.includes('"ai.deepseek.usage.cardTitle"'), '必须有用量卡片标题词条' ); assert.ok( locale.includes("'ai.deepseek.usage.notice'") || locale.includes('"ai.deepseek.usage.notice"'), '必须有进程内用量说明词条' ); assert.ok( page.includes("t['ai.deepseek.usage.cardTitle']") || page.includes('t["ai.deepseek.usage.cardTitle"]'), '卡片标题必须走 locale,禁止硬编码「账本」' ); assert.ok( page.includes("t['ai.deepseek.usage.notice']") || page.includes('t["ai.deepseek.usage.notice"]'), '进程内说明必须走 locale' ); assert.ok( /进程内|本次进程/.test(locale), '中文词条必须标明「进程内 / 本次进程」' ); assert.ok( /process|in-process|current process|this process/i.test(locale), '英文词条必须标明 process / in-process' ); // disclaimer 必须明确否定账单语义 assert.ok( /不是已出账|不是.*账单|非.*账单/.test(locale) || /not billed|not .*invoice|not .*reconcil/i.test(locale), 'usage.notice 必须明确否定已出账/账单/可对账语义' ); const localeBody = localeWithoutUsageNotice(locale); assert.ok( !BILLING_MISLEAD_RE.test(localeBody), 'locale 标题/指标/描述禁止账单式误导词(notice 除外)' ); assert.ok(!BILLING_MISLEAD_RE.test(page), '页面禁止账单式硬编码文案'); for (const key of [ 'ai.deepseek.stats.totalTokens', 'ai.deepseek.stats.quotaProgress', 'ai.deepseek.stats.unlimited', 'ai.deepseek.desc', ]) { assert.ok(locale.includes(`'${key}'`) || locale.includes(`"${key}"`), `必须包含 ${key}`); } }); test('3. DeepSeek locale 覆盖中英,无 emoji,用量词条可被页面引用', () => { const locale = readLocale(); const page = readPage(); assert.ok(locale.includes("'en-US'"), '必须支持 en-US'); assert.ok(locale.includes("'zh-CN'"), '必须支持 zh-CN'); const emojiRegex = /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u; assert.ok(!emojiRegex.test(locale), '语言包严禁使用 emoji'); assert.ok(!/\bany\b/.test(locale), '语言包严禁使用 any'); assert.ok( page.includes("t['ai.deepseek.stats.totalTokens']") || page.includes('t["ai.deepseek.stats.totalTokens"]'), '总量标题必须走 locale' ); assert.ok( page.includes("t['ai.deepseek.stats.promptTokens']") || page.includes('t["ai.deepseek.stats.promptTokens"]'), 'Prompt 标题必须走 locale' ); assert.ok( page.includes("t['ai.deepseek.stats.completionTokens']") || page.includes('t["ai.deepseek.stats.completionTokens"]'), 'Completion 标题必须走 locale' ); assert.ok( page.includes("t['ai.deepseek.stats.callCount']") || page.includes('t["ai.deepseek.stats.callCount"]'), '调用次数标题必须走 locale' ); });