lili 439115d8b5 test(studio): Task.vue 单测(3)——补齐 U6 创作流组件覆盖
src/views/create/Task.spec.ts:验进入即轮询(getTaskChain)、终态完成(2)+versionId 自动跳预览(带 gameId)、终态失败(3)不跳预览且重生成→regenerate→跳新任务链。真 store+mock studioApi 保 currentChain 响应式(watch 触发)。

至此 U6 创作流 4 组件(Create/Task/Modify/store)全有 spec;`npm test` 19/19 绿;build 绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:42:49 -07:00

88 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Task.spec.ts —— 生成进度页组件单测plan 002 U6
* 验:进入即轮询;终态完成(2)→自动跳预览(versionId+gameId);终态失败(3)→重生成→跳新任务链。
* 用真 store + mock studioApi(保 currentChain 真响应式,watch 能触发)+ mock router。跑 `npm test`。
*/
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { setActivePinia, createPinia } from 'pinia'
import { createI18n } from 'vue-i18n'
const replace = vi.fn()
const push = vi.fn()
vi.mock('vue-router', () => ({ useRouter: () => ({ replace, push }) }))
vi.mock('../../api/studio', () => ({
getTemplates: vi.fn(),
createGame: vi.fn(),
modifyGame: vi.fn(),
extendGame: vi.fn(),
getTaskChain: vi.fn(),
regenerate: vi.fn(),
}))
import * as studioApi from '../../api/studio'
import Task from './Task.vue'
const api = studioApi as unknown as Record<string, ReturnType<typeof vi.fn>>
const i18n = createI18n({ legacy: false, locale: 'zh-CN', messages: { 'zh-CN': {} }, missingWarn: false, fallbackWarn: false })
const AppButtonStub = {
props: ['disabled', 'loading', 'block', 'size', 'type'],
emits: ['click'],
template: '<button class="app-btn" :disabled="disabled" @click="$emit(\'click\')"><slot/></button>',
}
function mountTask(taskId = '1001') {
setActivePinia(createPinia())
return mount(Task, {
props: { taskId },
global: {
plugins: [i18n],
stubs: { LoadingBar: true, Icon: true, AppButton: AppButtonStub, EmptyState: { template: '<div class="empty"><slot name="action"/></div>' } },
},
})
}
describe('Task.vue生成进度页·studio 任务链)', () => {
beforeEach(() => {
vi.clearAllMocks()
replace.mockClear()
push.mockClear()
})
it('进入即对 taskChainId 启动轮询(getTaskChain)', async () => {
api.getTaskChain.mockResolvedValue({ id: 1001, gameId: 1, status: 1, progress: 20 })
mountTask('1001')
await flushPromises()
expect(api.getTaskChain).toHaveBeenCalledWith(1001)
})
it('终态完成(2)+versionId → 自动 router.replace 跳预览(带 gameId)', async () => {
api.getTaskChain.mockResolvedValue({ id: 1001, gameId: 1, status: 2, progress: 100, versionId: 9001 })
mountTask('1001')
await flushPromises()
expect(replace).toHaveBeenCalledOnce()
const nav = replace.mock.calls[0][0]
expect(nav.name).toBe('create-preview')
expect(nav.params.versionId).toBe('9001')
expect(nav.query.gameId).toBe('1')
})
it('终态失败(3) → 不跳预览;点重生成 → regenerate 并跳新任务链', async () => {
api.getTaskChain.mockResolvedValue({ id: 1001, gameId: 1, status: 3, progress: 0 })
api.regenerate.mockResolvedValue({ id: 1009, gameId: 1, status: 1, progress: 0, retryOf: 1001 })
const w = mountTask('1001')
await flushPromises()
expect(replace).not.toHaveBeenCalled() // 失败不跳预览
// 失败态有重生成按钮(EmptyState #action 内 primary 按钮)
const btns = w.findAll('.app-btn')
expect(btns.length).toBeGreaterThan(0)
await btns[btns.length - 1].trigger('click') // 重生成(末按钮=primary)
await flushPromises()
expect(api.regenerate).toHaveBeenCalledWith(1001)
const nav = replace.mock.calls[0][0]
expect(nav.name).toBe('create-task')
expect(nav.params.taskId).toBe('1009')
})
})