76 lines
3.0 KiB
JavaScript
76 lines
3.0 KiB
JavaScript
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 }), '用户隐藏')
|
|
})
|