Smail/test/frontend/email-detail.test.mjs
smail 316071bfee
Some checks are pending
Security Checks / security (push) Waiting to run
补齐已发送邮件密送名单展示并保持收件隐私
2026-10-03 21:35:41 +08:00

145 lines
6.2 KiB
JavaScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { readFileSync } from 'node:fs'
import { compileFunction } from 'node:vm'
import { reactive, ref, watch } from './vue.mjs'
const source = readFileSync(new URL('../../frontend/src/views/EmailDetail/EmailDetail.js', import.meta.url), 'utf8')
const createPage = compileFunction(
source.replace(/^import .*$/gm, '').replace('export function usePage', 'function usePage').replace(/export \{[^}]+\}/g, '') + '\nreturn usePage()',
['ref', 'watch', 'onBeforeUnmount', 'useRoute', 'useRouter', 'useGroupStore', 'http', 'ElMessage', 'ElMessageBox', 'lang', 'Document', 'Back', 'Delete', 'Download']
)
const settle = () => new Promise(resolve => setImmediate(resolve))
const email = id => ({errorNo: 0, data: {id, subject: `mail-${id}`, to: '[{"EmailAddress":"test@example.com"}]', cc: '[]', attachments: []}})
function fixture(post, id = '15') {
const route = reactive({params: {id}})
const requests = []
const navigations = []
let unmount
const page = createPage(ref, watch, callback => { unmount = callback }, () => route,
() => ({push: target => navigations.push(target)}), () => ({tag: ''}),
{post: async (...args) => { requests.push(args); return post(...args) }}, {}, {}, {}, {}, {}, {}, {})
return {page, route, requests, navigations, unmount: () => unmount()}
}
test('邮件业务错误不渲染空数据,允许重试后读取正文与附件', async () => {
let response = {errorNo: 500, errorMsg: '读取邮件失败', data: ''}
const {page, requests} = fixture(async () => response)
assert.equal(page.loading.value, true)
await settle()
assert.equal(page.loading.value, false)
assert.equal(page.loadError.value, '读取邮件失败')
assert.equal(page.detailData.value.id, undefined)
page.handleDelete()
assert.equal(requests.length, 1)
response = email(15)
response.data.attachments = [{Index: 0, Filename: '中文附件.txt'}]
await page.loadDetail()
assert.equal(page.loadError.value, '')
assert.equal(page.detailData.value.subject, 'mail-15')
assert.equal(page.detailData.value.attachments[0].Filename, '中文附件.txt')
assert.equal(page.tos.value[0].EmailAddress, 'test@example.com')
})
test('网络失败提供中文错误,返回操作明确进入邮件列表', async () => {
const {page, navigations} = fixture(async () => { throw new Error('Network Error') })
await settle()
assert.equal(page.loading.value, false)
assert.equal(page.loadError.value, '网络连接失败,请稍后重试')
page.backToList()
assert.equal(navigations[0].name, 'list')
})
test('无效编号不发请求,空响应或编号不匹配不当作成功', async () => {
for (const id of ['abc', '15abc', '-1', '0', '9007199254740992']) {
const {page, requests} = fixture(async () => email(15), id)
await settle()
assert.equal(requests.length, 0)
assert.equal(page.loadError.value, '邮件地址无效,请返回邮件列表')
}
for (const data of [null, '', [], {}, {id: 14}]) {
const {page} = fixture(async () => ({errorNo: 0, data}))
await settle()
assert.equal(page.loadError.value, '邮件不可用,请返回邮件列表')
assert.equal(page.detailData.value.id, undefined)
}
})
test('异常地址和附件字段不导致页面异常,切换邮件清除旧收件人', async () => {
const {page, route} = fixture(async (_, {id}) => ({errorNo: 0, data: {id, to: id === 15 ? '[{"EmailAddress":"old@example.com"}]' : 'null', cc: id === 15 ? '[{"EmailAddress":"copy@example.com"}]' : '{', attachments: 'bad'}}))
await settle()
assert.equal(page.showCC.value, true)
assert.equal(page.detailData.value.attachments.length, 0)
route.params.id = '16'
await settle()
assert.equal(page.detailData.value.id, 16)
assert.equal(page.tos.value.length, 0)
assert.equal(page.ccs.value.length, 0)
assert.equal(page.showCC.value, false)
})
test('仅发件副本展示密送名单,切换到收件副本立即清除', async () => {
const addresses = '[{"Name":"","EmailAddress":"hidden@example.com"}]'
const {page, route} = fixture(async (_, {id}) => ({
errorNo: 0,
data: {...email(id).data, type: id === 15 ? 1 : 0, bcc: addresses}
}))
await settle()
assert.equal(page.showBCC.value, true)
assert.equal(page.bccs.value[0].EmailAddress, 'hidden@example.com')
route.params.id = '16'
await settle()
assert.equal(page.showBCC.value, false)
assert.deepEqual(page.bccs.value, [])
})
test('未知邮件类型和无效密送字段不展示名单,加载失败不残留旧名单', async () => {
for (const data of [
{bcc: '[{"EmailAddress":"hidden@example.com"}]'},
{type: 1, bcc: '{'},
{type: 1, bcc: 'null'},
{type: 1, bcc: '[]'}
]) {
const {page} = fixture(async () => ({errorNo: 0, data: {...email(15).data, ...data}}))
await settle()
assert.equal(page.showBCC.value, false)
assert.deepEqual(page.bccs.value, [])
}
const {page, route} = fixture(async (_, {id}) => id === 15
? {errorNo: 0, data: {...email(id).data, type: 1, bcc: '[{"EmailAddress":"hidden@example.com"}]'}}
: {errorNo: 403, errorMsg: '无权查看邮件'})
await settle()
assert.equal(page.showBCC.value, true)
route.params.id = '16'
await settle()
assert.equal(page.showBCC.value, false)
assert.deepEqual(page.bccs.value, [])
})
test('切换邮件后旧请求成功或失败均不能覆盖新邮件', async () => {
for (const staleFailure of [false, true]) {
let finish
let fail
const {page, route} = fixture((_, {id}) => id === 15 ? new Promise((resolve, reject) => { finish = resolve; fail = reject }) : Promise.resolve(email(id)))
route.params.id = '16'
await settle()
assert.equal(page.detailData.value.id, 16)
if (staleFailure) fail(new Error('Network Error'))
else finish(email(15))
await settle()
assert.equal(page.detailData.value.id, 16)
assert.equal(page.loadError.value, '')
assert.equal(page.loading.value, false)
}
})
test('离开详情后未完成请求不再写入状态', async () => {
let finish
const {page, unmount} = fixture(() => new Promise(resolve => { finish = resolve }))
unmount()
finish(email(15))
await settle()
assert.equal(page.detailData.value.id, undefined)
})