补齐平台订阅、外部登录、CRM 同步与用户端页面;Nginx 转发用户端接口,登录页使用 Google 与 Apple 标志。 Co-authored-by: Cursor <cursoragent@cursor.com>
289 行
10 KiB
TypeScript
289 行
10 KiB
TypeScript
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 billingPagePath = path.join(
|
|
adminRoot,
|
|
'src/pages/settings/billing/index.tsx'
|
|
);
|
|
const billingLocalePath = path.join(
|
|
adminRoot,
|
|
'src/pages/settings/billing/locale/index.ts'
|
|
);
|
|
const mainLocalePath = path.join(adminRoot, 'src/locale/index.ts');
|
|
|
|
function readPage(): string {
|
|
assert.ok(fs.existsSync(billingPagePath), '订阅账单页面必须存在');
|
|
return fs.readFileSync(billingPagePath, 'utf-8');
|
|
}
|
|
|
|
function readLocale(): string {
|
|
assert.ok(fs.existsSync(billingLocalePath), '订阅账单语言包必须存在');
|
|
return fs.readFileSync(billingLocalePath, 'utf-8');
|
|
}
|
|
|
|
function assertNoFabricatedCheckoutUrl(content: string, label: string) {
|
|
assert.ok(!content.includes('cs_test_'), `${label}禁止前端自造 cs_test_`);
|
|
assert.ok(
|
|
!content.includes('https://checkout.stripe.com'),
|
|
`${label}禁止前端自造完整 checkout URL`
|
|
);
|
|
assert.ok(!content.includes('sk_live'), `${label}禁止出现 sk_live`);
|
|
}
|
|
|
|
function assertNoFakePayPalCheckout(content: string, label: string) {
|
|
assert.ok(
|
|
!/paypal\.com/i.test(content),
|
|
`${label}禁止出现 paypal.com 假结账地址`
|
|
);
|
|
assert.ok(
|
|
!/www\.paypal\.com/i.test(content),
|
|
`${label}禁止出现 www.paypal.com`
|
|
);
|
|
assert.ok(
|
|
!content.includes('paypal-checkout') &&
|
|
!content.includes('billing/paypal'),
|
|
`${label}禁止伪造 PayPal 结账接口`
|
|
);
|
|
}
|
|
|
|
test('1. settings/billing 必须请求 billing/currentPlan', () => {
|
|
const content = readPage();
|
|
|
|
assert.ok(
|
|
content.includes('billing/currentPlan'),
|
|
'必须请求 POST /api/admin/team/billing/currentPlan'
|
|
);
|
|
assert.ok(
|
|
content.includes('admin/team/billing/currentPlan'),
|
|
'必须请求完整后台路径 /api/admin/team/billing/currentPlan'
|
|
);
|
|
assert.ok(content.includes('axios'), '必须使用 axios 发请求');
|
|
assert.ok(
|
|
content.includes('{}'),
|
|
'进入页必须 POST currentPlan {}'
|
|
);
|
|
assert.ok(
|
|
content.includes("from '@arco-design/web-react'"),
|
|
'必须从 @arco-design/web-react 引入组件'
|
|
);
|
|
assert.ok(
|
|
content.includes('code === 1000') || content.includes('code ===1000'),
|
|
'必须按 Cool-Admin code === 1000 判断成功'
|
|
);
|
|
assert.ok(content.includes('Message.error'), '失败必须使用 Arco Message.error');
|
|
assert.ok(content.includes('BillingQuota'), '必须使用 BillingQuota 类型');
|
|
assert.ok(content.includes('TenantPlanType'), '必须使用 TenantPlanType 类型');
|
|
assert.ok(content.includes("from '@/types/omni'"), '必须复用 admin/src/types/omni.ts');
|
|
assert.ok(
|
|
!content.includes('Mock.js') && !content.includes("from 'mockjs'"),
|
|
'禁止用 Mock.js 假数据冒充成功'
|
|
);
|
|
assert.ok(!/\bany\b/.test(content), '禁止使用 any');
|
|
assertNoFabricatedCheckoutUrl(content, '页面');
|
|
assertNoFakePayPalCheckout(content, '页面');
|
|
});
|
|
|
|
test('2. settings/billing 必须使用 Card / Progress / Tag', () => {
|
|
const content = readPage();
|
|
|
|
assert.ok(content.includes('Card'), '必须使用 Arco Card');
|
|
assert.ok(content.includes('Progress'), '必须使用 Arco Progress');
|
|
assert.ok(content.includes('Tag'), '必须使用 Arco Tag');
|
|
assert.ok(content.includes('Alert'), '必须使用 Arco Alert 说明后续接入');
|
|
assert.ok(content.includes('planType'), 'Card 必须展示 planType');
|
|
assert.ok(content.includes('seatsUsed'), 'Progress 必须展示 seatsUsed');
|
|
assert.ok(content.includes('seatsLimit'), 'Progress 必须展示 seatsLimit');
|
|
assert.ok(content.includes('cardsUsed'), 'Progress 必须展示 cardsUsed');
|
|
assert.ok(content.includes('cardsLimit'), 'Progress 必须展示 cardsLimit');
|
|
assert.ok(content.includes("'free'"), '必须说明 free 套餐');
|
|
assert.ok(content.includes("'pro'"), '必须说明 pro 套餐');
|
|
assert.ok(content.includes("'enterprise'"), '必须说明 enterprise 套餐');
|
|
assert.ok(content.includes('lightColors'), '颜色必须引用 lightColors token');
|
|
assert.ok(content.includes('type="primary"'), '必须有一个主 CTA 刷新配额');
|
|
assert.ok(
|
|
!/#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})\b/.test(content),
|
|
'禁止硬编码颜色'
|
|
);
|
|
assert.ok(
|
|
!content.includes('#000') && !content.includes('#000000'),
|
|
'禁止纯黑'
|
|
);
|
|
assert.ok(
|
|
!content.includes('Mock.js') && !content.includes("from 'mockjs'"),
|
|
'禁止用 Mock.js'
|
|
);
|
|
assert.ok(!/\bany\b/.test(content), '禁止使用 any');
|
|
assertNoFabricatedCheckoutUrl(content, '页面');
|
|
assertNoFakePayPalCheckout(content, '页面');
|
|
});
|
|
|
|
test('3. settings/billing locale 必须包含 menu.settings.billing', () => {
|
|
const content = readLocale();
|
|
|
|
assert.ok(
|
|
content.includes("'menu.settings.billing'"),
|
|
'页面语言包必须包含 menu.settings.billing'
|
|
);
|
|
assert.ok(content.includes("'en-US'"), '必须包含英文案');
|
|
assert.ok(content.includes("'zh-CN'"), '必须包含中文案');
|
|
assert.ok(content.includes("'ar-SA'"), '必须包含阿语文案');
|
|
assert.ok(
|
|
content.includes('settingsBilling.request.fail'),
|
|
'必须包含失败提示文案'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.action.refresh'),
|
|
'必须包含刷新配额主 CTA 文案'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.alert'),
|
|
'必须包含国际卡与发票后续接入提示'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.checkout.stripeMissing'),
|
|
'必须包含未配置 Stripe 无法打开支付的 i18n'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.action.upgrade'),
|
|
'必须包含升级/结账文案'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.checkout.paypalUnavailable'),
|
|
'必须包含 PayPal 暂不可用文案 key'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.action.paypal'),
|
|
'必须包含 PayPal 按钮文案 key'
|
|
);
|
|
assert.ok(!/\bany\b/.test(content), 'locale 禁止使用 any');
|
|
assert.ok(
|
|
!/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u.test(content),
|
|
'locale 禁止使用 emoji'
|
|
);
|
|
assertNoFabricatedCheckoutUrl(content, 'locale');
|
|
assertNoFakePayPalCheckout(content, 'locale');
|
|
|
|
const mainLocale = fs.readFileSync(mainLocalePath, 'utf-8');
|
|
assert.ok(
|
|
/'en-US'[\s\S]*'menu\.settings\.billing':\s*'Billing'/.test(mainLocale),
|
|
'主词典 en-US menu.settings.billing 应为 Billing'
|
|
);
|
|
assert.ok(
|
|
/'zh-CN'[\s\S]*'menu\.settings\.billing':\s*'订阅账单'/.test(mainLocale),
|
|
'主词典 zh-CN menu.settings.billing 应为 订阅账单'
|
|
);
|
|
});
|
|
|
|
test('4. settings/billing 升级结账仅信任 Stripe 结账域', () => {
|
|
const content = readPage();
|
|
const locale = readLocale();
|
|
|
|
assert.ok(
|
|
content.includes('stripe-checkout') ||
|
|
content.includes('billing/stripe-checkout'),
|
|
'必须请求 POST /api/admin/team/billing/stripe-checkout'
|
|
);
|
|
assert.ok(content.includes('window.open'), '成功时必须 window.open 打开结账页');
|
|
assert.ok(content.includes('Message.error'), '失败必须 Message.error');
|
|
assert.ok(
|
|
content.includes('checkout.stripe.com'),
|
|
'必须校验返回 url 主机为 checkout.stripe.com'
|
|
);
|
|
assert.ok(
|
|
content.includes("protocol === 'https:'") ||
|
|
content.includes('protocol === "https:"') ||
|
|
content.includes("protocol==='https:'"),
|
|
'必须校验返回 url 协议为 https'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.checkout.stripeMissing'),
|
|
'缺服务端文案时必须回退到 Stripe 未配置 i18n'
|
|
);
|
|
assert.ok(
|
|
locale.includes("'settingsBilling.checkout.stripeMissing'"),
|
|
'locale 必须声明 Stripe 未配置文案 key'
|
|
);
|
|
assert.ok(
|
|
/'zh-CN'[\s\S]*settingsBilling\.checkout\.stripeMissing'[\s\S]*未配置 Stripe/.test(
|
|
locale
|
|
),
|
|
'中文案必须含「未配置 Stripe」'
|
|
);
|
|
assert.ok(
|
|
/'en-US'[\s\S]*settingsBilling\.checkout\.stripeMissing'/.test(locale),
|
|
'英文案必须含 Stripe missing 提示'
|
|
);
|
|
assert.ok(
|
|
/'ar-SA'[\s\S]*settingsBilling\.checkout\.stripeMissing'/.test(locale),
|
|
'阿语文案必须含 Stripe missing 提示'
|
|
);
|
|
assertNoFabricatedCheckoutUrl(content, '结账逻辑');
|
|
assertNoFakePayPalCheckout(content, '结账逻辑');
|
|
assert.ok(!/\bany\b/.test(content), '结账逻辑禁止 any');
|
|
});
|
|
|
|
test('5. settings/billing PayPal 按钮必须禁用且不可假结账', () => {
|
|
const content = readPage();
|
|
const locale = readLocale();
|
|
|
|
assert.ok(
|
|
content.includes('settingsBilling.action.paypal'),
|
|
'页面必须渲染 PayPal 按钮文案'
|
|
);
|
|
assert.ok(
|
|
content.includes('settingsBilling.checkout.paypalUnavailable'),
|
|
'页面必须展示 PayPal 暂不可用说明'
|
|
);
|
|
assert.ok(
|
|
/disabled(\s*=\s*\{?\s*true\s*\}?)?/.test(content) ||
|
|
content.includes('disabled={true}') ||
|
|
content.includes('disabled'),
|
|
'PayPal 按钮必须 disabled'
|
|
);
|
|
assert.ok(
|
|
!content.includes('Message.success'),
|
|
'PayPal 点击不得 Message.success'
|
|
);
|
|
assert.ok(
|
|
!content.includes('window.open') ||
|
|
content.includes('isTrustedStripeCheckoutUrl'),
|
|
'window.open 仅允许用于受信 Stripe URL'
|
|
);
|
|
assert.ok(
|
|
!content.includes('paypal-checkout') &&
|
|
!content.includes('billing/paypal'),
|
|
'禁止请求不存在的 PayPal 结账接口'
|
|
);
|
|
assert.ok(
|
|
locale.includes("'settingsBilling.action.paypal'"),
|
|
'locale 必须声明 PayPal 按钮文案'
|
|
);
|
|
assert.ok(
|
|
locale.includes("'settingsBilling.checkout.paypalUnavailable'"),
|
|
'locale 必须声明 PayPal 暂不可用文案'
|
|
);
|
|
assert.ok(
|
|
/'zh-CN'[\s\S]*settingsBilling\.checkout\.paypalUnavailable'[\s\S]*暂不可用/.test(
|
|
locale
|
|
),
|
|
'中文案必须说明 PayPal 暂不可用'
|
|
);
|
|
assert.ok(
|
|
/'en-US'[\s\S]*settingsBilling\.checkout\.paypalUnavailable'[\s\S]*(unavailable|not available|temporarily)/i.test(
|
|
locale
|
|
),
|
|
'英文案必须说明 PayPal 暂不可用'
|
|
);
|
|
assert.ok(
|
|
/'ar-SA'[\s\S]*settingsBilling\.checkout\.paypalUnavailable'/.test(locale),
|
|
'阿语文案必须含 PayPal 暂不可用提示'
|
|
);
|
|
assertNoFakePayPalCheckout(content, 'PayPal 按钮');
|
|
assertNoFakePayPalCheckout(locale, 'PayPal locale');
|
|
assert.ok(!/\bany\b/.test(content), 'PayPal 逻辑禁止 any');
|
|
});
|