93 lines
4.7 KiB
JavaScript
93 lines
4.7 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import { readFileSync } from 'node:fs'
|
|
import { compileFunction } from 'node:vm'
|
|
import { createRequire } from 'node:module'
|
|
|
|
const require = createRequire(new URL('../../frontend/package.json', import.meta.url))
|
|
const { computed, ref, watch, nextTick, effectScope } = require('vue')
|
|
const root = new URL('../../frontend/src/views/components/ConfigSettings/', import.meta.url)
|
|
const paginationSource = readFileSync(new URL('ConfigPagination/ConfigPagination.js', root), 'utf8')
|
|
const usePagination = compileFunction(
|
|
paginationSource.replace(/^import .*$/gm, '').replace('export function', 'function') + '\nreturn usePagination',
|
|
['computed', 'ref', 'watch']
|
|
)(computed, ref, watch)
|
|
|
|
test('列表分页保留源数据、绝对索引及最后一页边界', () => {
|
|
const scope = effectScope()
|
|
scope.run(() => {
|
|
const items = ref(Array.from({ length: 14 }, (_, index) => ({ id: index })))
|
|
const page = usePagination(items, 6)
|
|
assert.equal(page.pageCount.value, 3)
|
|
page.currentPage.value = 2.8
|
|
assert.equal(page.currentPage.value, 2)
|
|
assert.deepEqual(page.pageItems.value.map(item => item.index), [6, 7, 8, 9, 10, 11])
|
|
assert.equal(page.pageItems.value[0].entry, items.value[6])
|
|
page.currentPage.value = 999
|
|
assert.equal(page.pageItems.value.length, 2)
|
|
items.value.splice(12)
|
|
assert.equal(page.currentPage.value, 2)
|
|
items.value.push({ id: 14 })
|
|
assert.equal(page.currentPage.value, 2)
|
|
page.currentPage.value = -1
|
|
assert.equal(page.currentPage.value, 1)
|
|
assert.equal(items.value.length, 13)
|
|
items.value = []
|
|
assert.equal(page.pageCount.value, 1)
|
|
assert.deepEqual(page.pageItems.value, [])
|
|
})
|
|
scope.stop()
|
|
})
|
|
|
|
test('网络和文本列表跨页编辑、添加、删除仅更新目标条目', async () => {
|
|
const fieldSource = readFileSync(new URL('ConfigField/ConfigField.js', root), 'utf8')
|
|
const useField = compileFunction(
|
|
fieldSource.replace(/^import .*$/gm, '').replace(/^export \{.*$/gm, '').replace('export function', 'function') + '\nreturn useField',
|
|
['computed', 'nextTick', 'ref', 'watch', 'fieldKey', 'usePagination']
|
|
)(computed, nextTick, ref, watch, field => field.path.join('.'), usePagination)
|
|
for (const type of ['list', 'network']) {
|
|
const scope = effectScope()
|
|
const value = ref(type === 'list' ? ['a.example', 'b.example', 'c.example'] : [
|
|
{ scheme: 'https', host: 'a.example', port: 443 },
|
|
{ scheme: 'https', host: 'b.example', port: 443 },
|
|
{ scheme: 'https', host: 'c.example', port: 443 }
|
|
])
|
|
const props = { field: { path: ['targets'], type }, get value() { return value.value } }
|
|
const page = scope.run(() => useField(props, (_event, _path, updated) => { value.value = updated }))
|
|
const first = structuredClone(type === 'list' ? value.value[0] : { ...value.value[0] })
|
|
page.currentPage.value = 2
|
|
const index = page.pageItems.value[0].index
|
|
if (type === 'list') page.updateEntry(index, 'changed.example')
|
|
else page.updateTarget(index, 'host', 'changed.example')
|
|
assert.equal(type === 'list' ? value.value[2] : value.value[2].host, 'changed.example')
|
|
assert.deepEqual(type === 'list' ? value.value[0] : { ...value.value[0] }, first)
|
|
await page.addEntry()
|
|
assert.equal(page.currentPage.value, page.pageCount.value)
|
|
assert.equal(value.value.length, 4)
|
|
page.removeEntry(3)
|
|
page.removeEntry(2)
|
|
assert.equal(page.currentPage.value, 1)
|
|
assert.equal(value.value.length, 2)
|
|
scope.stop()
|
|
}
|
|
})
|
|
|
|
test('基础分区保留完整表单,分页和展开菜单模板均能编译', () => {
|
|
const { parse, compileScript, compileStyle } = require('@vue/compiler-sfc')
|
|
for (const name of ['ConfigPagination', 'ConfigForm', 'ConfigField', 'ConfigMaintenance']) {
|
|
const text = readFileSync(new URL(`${name}/${name}.vue`, root), 'utf8')
|
|
const { descriptor, errors } = parse(text)
|
|
assert.deepEqual(errors, [])
|
|
assert.doesNotThrow(() => compileScript(descriptor, { id: name, inlineTemplate: true }))
|
|
assert.doesNotMatch(text, /&#x[0-9a-f]+;/i)
|
|
}
|
|
const form = readFileSync(new URL('ConfigForm/ConfigForm.vue', root), 'utf8')
|
|
assert.doesNotMatch(form, /v-show="section !== 'base' \|\| activeGroup === group.id"/)
|
|
assert.doesNotMatch(form, /activeGroup|watch\(\(\) => props.errors/)
|
|
const css = readFileSync(new URL('ConfigForm/ConfigForm.css', root), 'utf8')
|
|
assert.deepEqual(compileStyle({ source: css, id: 'data-v-form', scoped: true }).errors, [])
|
|
const menu = readFileSync(new URL('../SettingsSubmenu/SettingsSubmenu.vue', root), 'utf8')
|
|
assert.match(menu, /v-if="item.children\?\.length"\s+class="settings-tertiary-list"/)
|
|
assert.doesNotMatch(menu, /v-if="item.children\?\.some/)
|
|
})
|