feat: 同步质量校验修复并精简工作台操作
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import { flushPromises, mount, type VueWrapper } from '@vue/test-utils'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { NInput, NDropdown } from 'naive-ui'
|
||||
import ActionMenu from './ActionMenu.vue'
|
||||
import DetailDisclosure from './DetailDisclosure.vue'
|
||||
import StyleEditor from '../../features/visual-style/components/StyleEditor.vue'
|
||||
import SubjectList from '../../features/breakdown/components/SubjectList.vue'
|
||||
import { selectMenu } from '../../testing/naive'
|
||||
import type { SubjectCandidate } from '../../features/breakdown/types'
|
||||
|
||||
let wrapper: VueWrapper | undefined
|
||||
afterEach(() => {
|
||||
wrapper?.unmount()
|
||||
wrapper = undefined
|
||||
document.body.innerHTML = ''
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
describe('精简入口保留功能', () => {
|
||||
it('菜单按点击展开,禁用项不能绕过,触发器有可访问名称', async () => {
|
||||
wrapper = mount(ActionMenu, {
|
||||
attachTo: document.body,
|
||||
props: {
|
||||
label: '测试更多操作',
|
||||
items: [
|
||||
{ key: 'history', label: '执行记录' },
|
||||
{ key: 'export', label: '导出', disabled: true }
|
||||
]
|
||||
}
|
||||
})
|
||||
expect(wrapper.get('button').attributes('aria-haspopup')).toBe('menu')
|
||||
expect(wrapper.get('button').attributes('aria-expanded')).toBe('false')
|
||||
expect(document.querySelector('.n-dropdown-option-body')).toBeNull()
|
||||
await selectMenu('测试更多操作', '执行记录')
|
||||
expect(wrapper.emitted('select')).toEqual([['history']])
|
||||
wrapper.getComponent(NDropdown).vm.$emit('select', 'export')
|
||||
expect(wrapper.emitted('select')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('补充说明默认不展开,键盘可聚焦的标题可查看原文', async () => {
|
||||
wrapper = mount(DetailDisclosure, { props: { title: '规则说明' }, slots: { default: '完整规则仍然保留' } })
|
||||
expect(wrapper.text()).not.toContain('完整规则仍然保留')
|
||||
await wrapper.get('.n-collapse-item__header-main').trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.text()).toContain('完整规则仍然保留')
|
||||
})
|
||||
|
||||
it('风格高级字段收起不丢失保存值,展开后仍可修改', async () => {
|
||||
wrapper = mount(StyleEditor, { props: { visualStyle: null, disabled: false } })
|
||||
expect(wrapper.find('#style-constraints').exists()).toBe(false)
|
||||
await wrapper.get('.n-collapse-item__header-main').trigger('click')
|
||||
await flushPromises()
|
||||
await wrapper.get('#style-constraints').setValue('["保留硬约束"]')
|
||||
const fields = wrapper.findAllComponents(NInput)
|
||||
fields.find(item => item.props('placeholder')?.includes('人物质感'))!.vm.$emit('update:value', '人物风格')
|
||||
await flushPromises()
|
||||
await wrapper.get('.n-collapse-item__header-main').trigger('click')
|
||||
await wrapper.get('form').trigger('submit')
|
||||
expect(wrapper.emitted('save')).toMatchObject([
|
||||
[{ characterPrompt: '人物风格', hardConstraints: ['保留硬约束'] }]
|
||||
])
|
||||
})
|
||||
|
||||
it('主体长文收起仅影响显示,完整内容与图片入口不丢失', async () => {
|
||||
const description = '主体完整经历。'.repeat(30)
|
||||
wrapper = mount(SubjectList, {
|
||||
props: {
|
||||
projectId: 'p',
|
||||
subjects: [
|
||||
{
|
||||
profileId: 'p1',
|
||||
ref: '@CH0001',
|
||||
name: '人物',
|
||||
module: 'character',
|
||||
description,
|
||||
appearance_prompt: '外观',
|
||||
aliases: []
|
||||
} as SubjectCandidate
|
||||
],
|
||||
forms: []
|
||||
},
|
||||
global: { stubs: { RouterLink: true } }
|
||||
})
|
||||
const text = wrapper.get('.line-clamp-3')
|
||||
expect(text.text()).toBe(description)
|
||||
await wrapper.get('button').trigger('click')
|
||||
expect(wrapper.find('.line-clamp-3').exists()).toBe(false)
|
||||
expect(wrapper.findAll('router-link-stub')).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { NButton, NDropdown } from 'naive-ui'
|
||||
import { Ellipsis } from '@lucide/vue'
|
||||
|
||||
/** 低频操作集中到键盘可访问的菜单;选中禁用项也不会向外触发动作。 */
|
||||
const props = withDefaults(
|
||||
defineProps<{ label?: string; items: { key: string; label: string; disabled?: boolean }[] }>(),
|
||||
{ label: '更多操作' }
|
||||
)
|
||||
const emit = defineEmits<{ select: [key: string] }>()
|
||||
const open = ref(false)
|
||||
function select(key: string) {
|
||||
const item = props.items.find(option => option.key === key)
|
||||
if (!item || item.disabled) return
|
||||
emit('select', key)
|
||||
open.value = false
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<NDropdown trigger="click" placement="bottom-end" :options="items" v-model:show="open" @select="select">
|
||||
<NButton
|
||||
quaternary
|
||||
class="icon-button"
|
||||
:aria-label="label"
|
||||
:title="label"
|
||||
aria-haspopup="menu"
|
||||
:aria-expanded="open"
|
||||
><template #icon><Ellipsis :size="18" /></template
|
||||
></NButton>
|
||||
</NDropdown>
|
||||
</template>
|
||||
@@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { NButton, NCollapse, NCollapseItem } from 'naive-ui'
|
||||
|
||||
/** 保留说明与诊断的可发现入口,默认不占据主内容区域;阻塞错误不应放入此组件。 */
|
||||
withDefaults(defineProps<{ title?: string }>(), { title: '使用说明' })
|
||||
const expanded = ref<string[]>([])
|
||||
/** 原生按钮保留 Enter/Space 键盘激活;文字点击不再向外重复触发折叠。 */
|
||||
function toggle() {
|
||||
expanded.value = expanded.value.length ? [] : ['details']
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<NCollapse v-model:expanded-names="expanded" class="detail-disclosure"
|
||||
><NCollapseItem name="details"
|
||||
><template #header
|
||||
><NButton text size="small" :aria-expanded="expanded.length > 0" @click.stop="toggle">{{
|
||||
title
|
||||
}}</NButton></template
|
||||
>
|
||||
<div class="detail-disclosure-content"><slot /></div></NCollapseItem
|
||||
></NCollapse>
|
||||
</template>
|
||||
Reference in New Issue
Block a user