const assert = require('assert'); const fs = require('fs'); const os = require('os'); const path = require('path'); const vm = require('vm'); const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'batch-customer-name-')); const Config = require('../src/core/config'); Config.DATA_DIR = tempDir; Config.DB_PATH = path.join(tempDir, 'accounts.db'); const database = require('../src/core/database'); (async () => { try { database.initDB(); database.upsertAccount({ email: 'first@example.com', customer_name: '旧客户' }); database.upsertAccount({ email: 'second@example.com', customer_name: '旧客户' }); const changed = database.updateAccountsCustomerName( ['first@example.com', 'second@example.com', 'first@example.com', 'missing@example.com'], ' 新客户 ', ); assert.strictEqual(changed, 2, '批量客户名应去重并只统计存在的账号'); assert.strictEqual(database.getAccount('first@example.com').customer_name, '新客户'); assert.strictEqual(database.getAccount('second@example.com').customer_name, '新客户'); assert.strictEqual(database.updateAccountsCustomerName(['first@example.com'], ''), 1); assert.strictEqual(database.getAccount('first@example.com').customer_name, '', '空客户名应能清空'); const appSource = fs.readFileSync(path.join(__dirname, '..', 'public', 'app.js'), 'utf8'); const htmlSource = fs.readFileSync(path.join(__dirname, '..', 'public', 'index.html'), 'utf8'); const routeSource = fs.readFileSync(path.join(__dirname, '..', 'src', 'routes', 'accounts.js'), 'utf8'); let payload = null; const context = vm.createContext({ console, Set, Map, Date, JSON, Math, String, Number, Object, Array, RegExp, Promise, Uint8Array, setTimeout, clearTimeout, fetch: async (url, options = {}) => { assert.strictEqual(url, '/api/accounts/batch/customer-name'); payload = JSON.parse(options.body); return { ok: true, json: async () => ({ success: true, count: 2, customerName: payload.customerName }) }; }, }); vm.runInContext(`${appSource}\nthis.__geminiApp = geminiApp;`, context, { filename: 'public/app.js' }); const app = context.__geminiApp(); app.accounts = [ { email: 'first@example.com', customer_name: '旧客户', status: '未登录' }, { email: 'second@example.com', customer_name: '旧客户', status: '未登录' }, ]; app._accountByEmail = new Map(app.accounts.map(account => [account.email, account])); app.selectedEmails = new Set(app.accounts.map(account => account.email)); app.addLog = () => {}; app.openBatchCustomerNameModal(); assert.strictEqual(app.showBatchCustomerNameModal, true); app.batchCustomerName = ' 页面客户 '; await app.confirmBatchCustomerName(); assert.deepStrictEqual(Array.from(payload.emails), ['first@example.com', 'second@example.com']); assert.strictEqual(payload.customerName, '页面客户'); assert(app.accounts.every(account => account.customer_name === '页面客户')); assert.strictEqual(app.showBatchCustomerNameModal, false); assert(htmlSource.includes('openBatchCustomerNameModal()'), '换代理旁边应有批量客户名按钮'); assert(routeSource.includes("router.put('/batch/customer-name'"), '应提供单请求批量客户名接口'); console.log('batch_customer_name.test.js: PASS'); } finally { try { database.getDb().close(); } catch (_) {} fs.rmSync(tempDir, { recursive: true, force: true }); } })().catch(error => { console.error(error); process.exitCode = 1; });