107 lines
5.7 KiB
JavaScript
107 lines
5.7 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
|
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'account-refund-status-'));
|
|
const Config = require('../src/core/config');
|
|
Config.DATA_DIR = tempDir;
|
|
Config.DB_PATH = path.join(tempDir, 'accounts.db');
|
|
const database = require('../src/core/database');
|
|
|
|
try {
|
|
database.initDB();
|
|
const columns = database.getDb().pragma('table_info(accounts)').map(row => row.name);
|
|
assert(columns.includes('account_refund_status'), '账号表应包含 account_refund_status');
|
|
assert(columns.includes('refund_process_status'), '账号表应包含独立的 refund_process_status');
|
|
|
|
database.upsertAccount({ email: 'default@example.com' });
|
|
assert.strictEqual(
|
|
database.getAccount('default@example.com').account_refund_status,
|
|
'无状态',
|
|
'新账号退款状态应默认为无状态',
|
|
);
|
|
assert.strictEqual(
|
|
database.getAccount('default@example.com').refund_process_status,
|
|
'未发起',
|
|
'新账号退款流程状态应默认为未发起',
|
|
);
|
|
assert.strictEqual(database.updateAccountRefundProcessStatus('default@example.com', '已发起'), true);
|
|
assert.strictEqual(database.getAccount('default@example.com').refund_process_status, '已发起');
|
|
assert.strictEqual(database.updateAccountRefundProcessStatus('default@example.com', '发起失败'), true);
|
|
assert.strictEqual(database.getAccount('default@example.com').refund_process_status, '发起失败');
|
|
|
|
database.upsertAccount({ email: 'refunded@example.com', account_refund_status: '已退款' });
|
|
assert.strictEqual(database.getAccount('refunded@example.com').account_refund_status, '已退款');
|
|
database.upsertAccount({ email: 'refunded@example.com', account_refund_status: '' });
|
|
assert.strictEqual(
|
|
database.getAccount('refunded@example.com').account_refund_status,
|
|
'无状态',
|
|
'空退款状态应恢复默认值',
|
|
);
|
|
assert.strictEqual(database.updateAccountRefundStatus('refunded@example.com', '未操作'), true);
|
|
assert.strictEqual(
|
|
database.getAccount('refunded@example.com').account_refund_status,
|
|
'无状态',
|
|
'未操作应统一保存为无状态',
|
|
);
|
|
assert.strictEqual(database.updateAccountRefundStatus('refunded@example.com', '已申请退款'), true);
|
|
assert.strictEqual(database.getAccount('refunded@example.com').account_refund_status, '已申请退款');
|
|
|
|
const staged = database.stageAccounts(
|
|
['refunded@example.com'],
|
|
'退款状态导出',
|
|
['email', 'account_refund_status'],
|
|
);
|
|
const stagedDetail = database.getStagingBatch(staged.batchId);
|
|
assert.deepStrictEqual(
|
|
JSON.parse(stagedDetail.batch.selected_fields),
|
|
['email', 'account_refund_status'],
|
|
'暂存箱导出应保留账号退款字段',
|
|
);
|
|
|
|
const html = fs.readFileSync(path.join(__dirname, '..', 'public', 'index.html'), 'utf8');
|
|
const customerColumn = html.indexOf('<th>客户名</th>');
|
|
const refundColumn = html.indexOf('<th>账号退款</th>');
|
|
const refundProcessColumn = html.indexOf('<th>是否已发起退款流程</th>');
|
|
const statusColumn = html.indexOf('<th>状态</th>');
|
|
assert(customerColumn >= 0
|
|
&& refundColumn > customerColumn
|
|
&& refundProcessColumn > refundColumn
|
|
&& statusColumn > refundProcessColumn,
|
|
'独立退款流程状态列应位于账号退款右侧');
|
|
assert(html.includes("account.account_refund_status || '无状态'"), '列表空退款状态应显示无状态');
|
|
assert(html.includes("account.refund_process_status || '未发起'"), '列表空退款流程状态应显示未发起');
|
|
assert(html.includes('startInlineEditAccountRefund(account.email)'), '账号退款列应支持双击编辑');
|
|
assert(html.includes('startInlineEditRefundProcess(account.email)'), '退款流程状态列应支持双击编辑');
|
|
const inlineRefundProcessSelect = html.match(/<template x-if="inlineEditRefundProcessEmail === account\.email">([\s\S]*?)<\/template>/);
|
|
assert(inlineRefundProcessSelect, '退款流程状态列应渲染原地下拉编辑器');
|
|
for (const status of ['未发起', '已发起', '发起失败']) {
|
|
assert(inlineRefundProcessSelect[1].includes(`<option value="${status}">${status}</option>`),
|
|
`退款流程状态编辑器应包含:${status}`);
|
|
}
|
|
const inlineRefundSelect = html.match(/<template x-if="inlineEditAccountRefundEmail === account\.email">([\s\S]*?)<\/template>/);
|
|
assert(inlineRefundSelect && inlineRefundSelect[1].includes('<option value="无状态">无状态</option>'),
|
|
'账号退款编辑器必须预先渲染无状态选项,避免动态选项导致初始值错误');
|
|
assert(!inlineRefundSelect[1].includes('x-for="status in accountRefundStatusOptions"'),
|
|
'账号退款编辑器不能在 select 赋值后再异步生成 option');
|
|
const appSource = fs.readFileSync(path.join(__dirname, '..', 'public', 'app.js'), 'utf8');
|
|
const routeSource = fs.readFileSync(path.join(__dirname, '..', 'src', 'routes', 'accounts.js'), 'utf8');
|
|
assert(appSource.includes('/refund-process-status'), '前端应调用退款流程状态专用保存接口');
|
|
assert(routeSource.includes("router.put('/:email/refund-process-status'"), '服务端应提供退款流程状态专用保存接口');
|
|
for (const status of [
|
|
'无状态', '已退款', '未退款', '退款失败', '已申请退款', 'google封号无法查询',
|
|
'gpt封号退款失败', 'gpt警告', '已被改密无法查询', '已被改2FA无法查询',
|
|
'需要手机号查询', '无订阅',
|
|
]) {
|
|
assert(appSource.includes(`'${status}'`), `前端应包含退款状态:${status}`);
|
|
}
|
|
|
|
console.log('account_refund_status.test.js: PASS');
|
|
} finally {
|
|
try { database.getDb().close(); } catch (_) {}
|
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
}
|