import assert from 'node:assert/strict' import { afterEach, mock, test } from 'node:test' import { createUser, reviewClouds } from '../src/features/admin/api.ts' import { serializeCsv, visibilityLabel } from '../src/features/admin/models.ts' afterEach(() => mock.restoreAll()) test('admin review preserves completed batches when a later batch fails', async () => { const completed = [] let call = 0 mock.method(globalThis, 'fetch', async (url, options) => { assert.equal(new URL(url).pathname, '/admin/clouds/review') assert.equal(options.credentials, 'include') const body = JSON.parse(options.body) assert.equal(body.review_status, 'approved') assert.ok(body.cloud_ids.length <= 100) return ++call === 1 ? Response.json({ message: '成功' }) : Response.json({ message: '服务暂不可用' }, { status: 503 }) }) const ids = Array.from({ length: 101 }, (_, index) => `cloud-${index}`) await assert.rejects( reviewClouds(ids, 'approved', batch => completed.push(...batch)), /服务暂不可用/, ) assert.deepEqual(completed, ids.slice(0, 100)) assert.equal(call, 2) }) test('admin account creation returns email delivery status without retrying creation', async () => { const body = { username: '观云者', email: 'observer@example.test', password: 'test-password', role: 'user', } const fetch = mock.method(globalThis, 'fetch', async (url, options) => { assert.equal(new URL(url).pathname, '/admin/users') assert.equal(options.method, 'POST') assert.equal(options.credentials, 'include') assert.deepEqual(JSON.parse(options.body), body) return Response.json( { message: '已创建,邮件发送失败', user_id: 'new-user', email_sent: false }, { status: 201 }, ) }) assert.equal((await createUser(body)).email_sent, false) assert.equal(fetch.mock.callCount(), 1) }) test('CSV exports escape untrusted text, formulas, quotes and multiline descriptions', () => { const csv = serializeCsv( ['用户名', '说明'], [ ['=HYPERLINK("test")', '第一行\n第二行'], [' @SUM(1)', '云,"雨"'], ['-1+2', '\t=1'], ], ) assert.ok(csv.startsWith('\uFEFF')) assert.ok(csv.includes('"\'=HYPERLINK(""test"")"')) assert.ok(csv.includes('"\' @SUM(1)"')) assert.ok(csv.includes('"\'-1+2"')) assert.ok(csv.includes('"\'\t=1"')) assert.ok(csv.includes('"云,""雨"""')) assert.ok(csv.includes('"第一行\n第二行"')) }) test('pending and rejected images are never labeled publicly visible', () => { for (const status of ['pending', 'rejected']) { assert.equal(visibilityLabel({ status, is_hidden: false }), '尚未公开') } assert.equal(visibilityLabel({ status: 'approved', is_hidden: false }), '公开可见') assert.equal(visibilityLabel({ status: 'approved', is_hidden: true }), '用户隐藏') })