20260921231313

This commit is contained in:
oneao committed 2026-09-21 23:13:14 +08:00
1 parent ac710c1801
commit 583984c24f
81 files changed
+2523 -288

No files matched your search

@@ -0,0 +1,76 @@
/**
* 回归:路由过渡的页面外壳(.fms-page-holder,由 getPageWrapper 的渲染函数创建)。
*
* 路由页面是异步组件(懒加载 chunk),加载中的渲染是注释节点(非元素根)——
* <Transition> 无法动画化非元素根:既报 warning(Component inside <Transition>
* renders non-element root node that cannot be animated),out-in 下 enter 也会失败、
* 页面内容一直不显示。页面外壳是恒定元素,兜住该场景。
*
* 本用例用「先渲染 null 再渲染元素」的桩模拟异步组件加载过程,断言:
* 1. 全程不出现 non-element root 警告;
* 2. 异步就绪后内容正常显示(过渡没有吞掉页面)。
*/
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { flushPromises, mount } from '@vue/test-utils'
vi.mock('@/views/dashboard/index.vue', async () => {
const { h, onMounted, ref } = await import('vue')
return {
default: {
name: 'Dashboard',
setup() {
const ready = ref(false)
onMounted(() => {
setTimeout(() => {
ready.value = true
}, 30)
})
// 加载中渲染 null(Vue 渲染为注释节点),模拟异步组件解析前的状态
return () => (ready.value ? h('div', { 'data-page': 'Dashboard' }, 'DB') : null)
},
},
}
})
vi.mock('@/views/detail/DetailPage.vue', () => ({
default: { name: 'DetailPageStub', props: ['id'], template: '<div />' },
}))
vi.mock('@/services/api', () => ({
loadDataApi: vi.fn(() => Promise.resolve({ data: [], code: 0, success: true })),
describeApi: vi.fn(() => Promise.resolve({ data: [], code: 0, success: true })),
saveObjectApi: vi.fn(() => Promise.resolve({ code: 0, success: true })),
nextIdApi: vi.fn(() => Promise.resolve({ data: 1, code: 0, success: true })),
}))
import App from '@/App.vue'
import router from '@/router'
import { createTestPinia } from '../helpers/app.js'
import { useAuthStore } from '@/stores/auth'
beforeEach(async () => {
localStorage.clear()
sessionStorage.clear()
createTestPinia()
useAuthStore().setSession({ token: 't', user: { id: 1, account: 'g3soft', name: 'U' } }, 'ORG')
await router.push('/dashboard')
await router.isReady()
})
describe('路由过渡 · 页面外壳', () => {
it('异步页面加载中不产生 non-element root 警告,完成后内容正常显示', async () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
const wrapper = mount(App, { global: { plugins: [router] }, attachTo: document.body })
await flushPromises()
// 等待桩组件异步就绪(模拟 chunk 下载完成)
await new Promise((resolve) => setTimeout(resolve, 60))
await flushPromises()
const warnings = warnSpy.mock.calls.map((args) => String(args[0])).join('\n')
expect(warnings).not.toContain('non-element root node')
// 内容最终可见(过渡未吞掉页面)
expect(wrapper.find('[data-page="Dashboard"]').exists()).toBe(true)
warnSpy.mockRestore()
wrapper.unmount()
})
})