254 lines
9.2 KiB
JavaScript
254 lines
9.2 KiB
JavaScript
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const path = require('node:path')
|
|
const test = require('node:test')
|
|
const ts = require('typescript')
|
|
const vue = require('vue')
|
|
const { parse, compileScript, compileTemplate } = require('@vue/compiler-sfc')
|
|
|
|
const root = path.resolve(__dirname, '..')
|
|
const apiPath = path.join(root, 'src/api/setting/prescription_ai_visibility.ts')
|
|
const pagePath = path.join(root, 'src/views/setting/prescription_ai_visibility/index.vue')
|
|
const { descriptor, errors } = parse(fs.readFileSync(pagePath, 'utf8'), { filename: pagePath })
|
|
assert.deepEqual(errors, [])
|
|
const script = compileScript(descriptor, { id: 'prescription-ai-visibility' })
|
|
|
|
function moduleFrom(source, dependencies) {
|
|
const compiled = ts.transpileModule(source, {
|
|
compilerOptions: {
|
|
target: ts.ScriptTarget.ES2022,
|
|
module: ts.ModuleKind.CommonJS,
|
|
esModuleInterop: true
|
|
}
|
|
}).outputText
|
|
const module = { exports: {} }
|
|
new Function('require', 'module', 'exports', compiled)(dependencies, module, module.exports)
|
|
return module.exports
|
|
}
|
|
|
|
const makeApi = (request) =>
|
|
moduleFrom(fs.readFileSync(apiPath, 'utf8'), (name) => {
|
|
assert.equal(name, '@/utils/request')
|
|
return request
|
|
})
|
|
|
|
const tick = () => new Promise((resolve) => setImmediate(resolve))
|
|
const deferred = () => {
|
|
let resolve
|
|
let reject
|
|
const promise = new Promise((yes, no) => {
|
|
resolve = yes
|
|
reject = no
|
|
})
|
|
return { promise, resolve, reject }
|
|
}
|
|
|
|
function makePage(overrides = {}) {
|
|
const saved = []
|
|
const messages = []
|
|
const calls = []
|
|
const api = {
|
|
getPrescriptionAiCapabilities: async () => {
|
|
calls.push('capabilities')
|
|
return { agreement_visible: false, can_manage_visibility: true }
|
|
},
|
|
getPrescriptionAiVisibilityConfig: async () => {
|
|
calls.push('config')
|
|
return { role_ids: [2, 90], admin_ids: [3, 91] }
|
|
},
|
|
getPrescriptionAiVisibilityOptions: async () => {
|
|
calls.push('options')
|
|
return {
|
|
roles: [{ id: 2, name: '医生' }],
|
|
admins: [{ id: 3, name: '张医生', account: 'zhang.doctor' }]
|
|
}
|
|
},
|
|
setPrescriptionAiVisibilityConfig: async (params) => {
|
|
saved.push(params)
|
|
return params
|
|
},
|
|
...overrides
|
|
}
|
|
const component = moduleFrom(script.content, (name) => {
|
|
if (name === 'vue') return vue
|
|
if (name === '@/api/setting/prescription_ai_visibility') return api
|
|
if (name === '@/utils/feedback') {
|
|
return { msgSuccess: (message) => messages.push(message) }
|
|
}
|
|
throw new Error(`Unexpected import: ${name}`)
|
|
}).default
|
|
const page = component.setup({}, { expose() {} })
|
|
return { page, api, saved, messages, calls }
|
|
}
|
|
|
|
test('API uses the dedicated routes and rejects malformed policy responses', async () => {
|
|
const calls = []
|
|
let response = { role_ids: [2], admin_ids: [3] }
|
|
const api = makeApi({
|
|
get: async (params) => {
|
|
calls.push(['get', params])
|
|
return response
|
|
},
|
|
post: async (params) => {
|
|
calls.push(['post', params])
|
|
return response
|
|
}
|
|
})
|
|
const data = await api.getPrescriptionAiVisibilityConfig()
|
|
data.role_ids.push(5)
|
|
assert.deepEqual(response.role_ids, [2])
|
|
await api.setPrescriptionAiVisibilityConfig({ role_ids: [], admin_ids: [] })
|
|
await api.getPrescriptionAiVisibilityOptions()
|
|
await api.getPrescriptionAiCapabilities()
|
|
assert.deepEqual(calls, [
|
|
['get', { url: '/tcm.prescriptionAi/getVisibilityConfig' }],
|
|
[
|
|
'post',
|
|
{
|
|
url: '/tcm.prescriptionAi/setVisibilityConfig',
|
|
params: { role_ids: [], admin_ids: [] }
|
|
}
|
|
],
|
|
['get', { url: '/tcm.prescriptionAi/visibilityOptions' }],
|
|
['get', { url: '/tcm.prescriptionAi/capabilities' }]
|
|
])
|
|
for (response of [
|
|
null,
|
|
{},
|
|
{ role_ids: [], admin_ids: ['3'] },
|
|
{ role_ids: [-1], admin_ids: [] }
|
|
]) {
|
|
await assert.rejects(api.getPrescriptionAiVisibilityConfig(), /响应格式不正确/)
|
|
await assert.rejects(
|
|
api.setPrescriptionAiVisibilityConfig({ role_ids: [], admin_ids: [] }),
|
|
/响应格式不正确/
|
|
)
|
|
}
|
|
})
|
|
|
|
test('initial loading is pending and cannot submit before the real policy is read', async () => {
|
|
const pending = deferred()
|
|
const { page, saved } = makePage({ getPrescriptionAiVisibilityConfig: () => pending.promise })
|
|
assert.equal(page.loading.value, true)
|
|
assert.equal(page.ready.value, false)
|
|
assert.equal(page.hasLoaded.value, false)
|
|
await page.handleSubmit()
|
|
assert.deepEqual(saved, [])
|
|
pending.reject(new Error('offline'))
|
|
await tick()
|
|
assert.equal(page.loading.value, false)
|
|
assert.equal(page.ready.value, false)
|
|
assert.match(page.loadError.value, /加载失败/)
|
|
await page.handleSubmit()
|
|
assert.deepEqual(saved, [])
|
|
})
|
|
|
|
test('a failed reload cannot apply a partial policy or overwrite saved selections', async () => {
|
|
const { page, api, saved } = makePage()
|
|
await tick()
|
|
api.getPrescriptionAiVisibilityConfig = async () => ({ role_ids: [], admin_ids: [] })
|
|
api.getPrescriptionAiVisibilityOptions = async () => {
|
|
throw new Error('options failed')
|
|
}
|
|
await page.loadConfig()
|
|
assert.deepEqual(page.formData.role_ids, [2, 90])
|
|
assert.deepEqual(page.formData.admin_ids, [3, 91])
|
|
assert.equal(page.hasLoaded.value, true)
|
|
assert.equal(page.ready.value, false)
|
|
await page.handleSubmit()
|
|
assert.deepEqual(saved, [])
|
|
api.getPrescriptionAiVisibilityOptions = async () => ({ roles: [], admins: [] })
|
|
await page.loadConfig()
|
|
assert.equal(page.ready.value, true)
|
|
assert.equal(page.loadError.value, '')
|
|
assert.deepEqual(page.formData.role_ids, [])
|
|
})
|
|
|
|
test('missing selected IDs stay visible and user labels support both name and account search', async () => {
|
|
const { page, saved } = makePage()
|
|
await tick()
|
|
assert.equal(page.canManage.value, true)
|
|
assert.equal(page.ready.value, true)
|
|
assert.deepEqual(
|
|
page.roleOptions.value.map((row) => row.id),
|
|
[2, 90]
|
|
)
|
|
assert.match(page.roleOptions.value[1].name, /#90.*当前不在可选列表/)
|
|
assert.deepEqual(
|
|
page.adminOptions.value.map((row) => row.id),
|
|
[3, 91]
|
|
)
|
|
assert.match(page.adminOptions.value[0].label, /张医生.*zhang\.doctor/)
|
|
assert.match(page.adminOptions.value[1].label, /#91.*当前不在可选列表/)
|
|
await page.handleSubmit()
|
|
assert.deepEqual(saved, [{ role_ids: [2, 90], admin_ids: [3, 91] }])
|
|
})
|
|
|
|
test('explicitly clearing both selectors saves the empty policy and applies normalized response', async () => {
|
|
const { page, saved, messages, api } = makePage()
|
|
await tick()
|
|
page.formData.role_ids = []
|
|
page.formData.admin_ids = []
|
|
await page.handleSubmit()
|
|
assert.deepEqual(saved, [{ role_ids: [], admin_ids: [] }])
|
|
assert.equal(messages.length, 1)
|
|
page.formData.role_ids = [90, 2, 90]
|
|
api.setPrescriptionAiVisibilityConfig = async () => ({ role_ids: [2, 90], admin_ids: [] })
|
|
await page.handleSubmit()
|
|
assert.deepEqual(page.formData.role_ids, [2, 90])
|
|
assert.equal(page.saving.value, false)
|
|
})
|
|
|
|
test('pending save blocks duplicate writes and reload; failed write keeps the user selection', async () => {
|
|
const pending = deferred()
|
|
const saved = []
|
|
const { page, calls } = makePage({
|
|
setPrescriptionAiVisibilityConfig: (params) => {
|
|
saved.push(params)
|
|
return pending.promise
|
|
}
|
|
})
|
|
await tick()
|
|
page.formData.role_ids = [90]
|
|
const first = page.handleSubmit()
|
|
assert.equal(page.saving.value, true)
|
|
await page.handleSubmit()
|
|
await page.loadConfig()
|
|
assert.equal(saved.length, 1)
|
|
assert.equal(calls.filter((name) => name === 'capabilities').length, 1)
|
|
pending.reject(new Error('offline'))
|
|
await first
|
|
assert.equal(page.saving.value, false)
|
|
assert.equal(page.ready.value, true)
|
|
assert.deepEqual(page.formData.role_ids, [90])
|
|
assert.deepEqual(page.formData.admin_ids, [3, 91])
|
|
assert.match(page.saveError.value, /当前选择已保留/)
|
|
})
|
|
|
|
test('management capability is independent from viewing and denies policy reads when absent', async () => {
|
|
const { page, calls, saved } = makePage({
|
|
getPrescriptionAiCapabilities: async () => ({
|
|
agreement_visible: true,
|
|
can_manage_visibility: false
|
|
})
|
|
})
|
|
await tick()
|
|
assert.deepEqual(calls, [])
|
|
assert.equal(page.canManage.value, false)
|
|
assert.equal(page.hasLoaded.value, false)
|
|
assert.equal(page.ready.value, false)
|
|
assert.match(page.loadError.value, /无权管理/)
|
|
await page.handleSubmit()
|
|
assert.deepEqual(saved, [])
|
|
})
|
|
|
|
test('actual settings template compiles with its script bindings', () => {
|
|
const compiled = compileTemplate({
|
|
source: descriptor.template.content,
|
|
filename: pagePath,
|
|
id: 'prescription-ai-visibility',
|
|
compilerOptions: { bindingMetadata: script.bindings }
|
|
})
|
|
assert.deepEqual(compiled.errors, [])
|
|
})
|