mirror of
https://github.com/Powerful-517/yys-editor.git
synced 2026-03-05 23:15:26 +00:00
test: 集成 Vitest 测试框架和开发规范
- 安装 vitest, @vue/test-utils, jsdom 等测试依赖 - 配置 vitest.config.js 测试环境 - 添加 schema.test.ts (7个数据结构验证测试) - 添加 useStore.test.ts (7个状态管理测试) - 创建测试指南文档 (docs/testing.md) - 创建测试规范文档 (docs/testing-rules.md) - 创建开发规范文档 (docs/development-rules.md) - 创建开发工作流程文档 (docs/1management/workflow.md) - 添加测试相关 npm scripts (test, test:watch, test:ui, test:coverage) - 所有测试通过 (14/14)
This commit is contained in:
98
src/__tests__/schema.test.ts
Normal file
98
src/__tests__/schema.test.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import {
|
||||
CURRENT_SCHEMA_VERSION,
|
||||
DefaultNodeStyle,
|
||||
type GraphNode,
|
||||
type GraphEdge,
|
||||
type NodeProperties,
|
||||
type RootDocument
|
||||
} from '../ts/schema'
|
||||
|
||||
describe('Schema 数据结构验证', () => {
|
||||
it('当前 schema 版本应该是 1.0.0', () => {
|
||||
expect(CURRENT_SCHEMA_VERSION).toBe('1.0.0')
|
||||
})
|
||||
|
||||
it('DefaultNodeStyle 应该包含正确的默认值', () => {
|
||||
expect(DefaultNodeStyle).toMatchObject({
|
||||
width: 180,
|
||||
height: 120,
|
||||
rotate: 0,
|
||||
fill: '#ffffff',
|
||||
stroke: '#dcdfe6'
|
||||
})
|
||||
})
|
||||
|
||||
it('创建 GraphNode 应该符合类型定义', () => {
|
||||
const node: GraphNode = {
|
||||
id: 'node-1',
|
||||
type: 'rect',
|
||||
x: 100,
|
||||
y: 200,
|
||||
properties: {
|
||||
style: {
|
||||
width: 200,
|
||||
height: 150,
|
||||
fill: '#ff0000'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(node.id).toBe('node-1')
|
||||
expect(node.type).toBe('rect')
|
||||
expect(node.properties.style.width).toBe(200)
|
||||
})
|
||||
|
||||
it('创建 GraphEdge 应该包含必需字段', () => {
|
||||
const edge: GraphEdge = {
|
||||
id: 'edge-1',
|
||||
sourceNodeId: 'node-1',
|
||||
targetNodeId: 'node-2'
|
||||
}
|
||||
|
||||
expect(edge.id).toBe('edge-1')
|
||||
expect(edge.sourceNodeId).toBe('node-1')
|
||||
expect(edge.targetNodeId).toBe('node-2')
|
||||
})
|
||||
|
||||
it('NodeProperties 应该支持式神数据', () => {
|
||||
const properties: NodeProperties = {
|
||||
style: DefaultNodeStyle,
|
||||
shikigami: {
|
||||
name: '茨木童子',
|
||||
avatar: '/assets/Shikigami/ibaraki.png',
|
||||
rarity: 'SSR'
|
||||
}
|
||||
}
|
||||
|
||||
expect(properties.shikigami?.name).toBe('茨木童子')
|
||||
expect(properties.shikigami?.rarity).toBe('SSR')
|
||||
})
|
||||
|
||||
it('NodeProperties 应该支持御魂数据', () => {
|
||||
const properties: NodeProperties = {
|
||||
style: DefaultNodeStyle,
|
||||
yuhun: {
|
||||
name: '破势',
|
||||
type: '攻击',
|
||||
avatar: '/assets/Yuhun/poshi.png'
|
||||
}
|
||||
}
|
||||
|
||||
expect(properties.yuhun?.name).toBe('破势')
|
||||
expect(properties.yuhun?.type).toBe('攻击')
|
||||
})
|
||||
|
||||
it('RootDocument 应该包含文件列表和活动文件', () => {
|
||||
const doc: RootDocument = {
|
||||
schemaVersion: '1.0.0',
|
||||
fileList: [],
|
||||
activeFile: 'File 1',
|
||||
activeFileId: 'f_123'
|
||||
}
|
||||
|
||||
expect(doc.schemaVersion).toBe('1.0.0')
|
||||
expect(doc.activeFile).toBe('File 1')
|
||||
expect(doc.activeFileId).toBe('f_123')
|
||||
})
|
||||
})
|
||||
157
src/__tests__/useStore.test.ts
Normal file
157
src/__tests__/useStore.test.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||||
import { setActivePinia, createPinia } from 'pinia'
|
||||
import { useFilesStore } from '../ts/useStore'
|
||||
|
||||
// Mock localStorage
|
||||
const localStorageMock = (() => {
|
||||
let store: Record<string, string> = {}
|
||||
return {
|
||||
getItem: (key: string) => store[key] || null,
|
||||
setItem: (key: string, value: string) => { store[key] = value },
|
||||
removeItem: (key: string) => { delete store[key] },
|
||||
clear: () => { store = {} }
|
||||
}
|
||||
})()
|
||||
|
||||
Object.defineProperty(global, 'localStorage', { value: localStorageMock })
|
||||
|
||||
// Mock ElMessageBox 和 useGlobalMessage
|
||||
vi.mock('element-plus', () => ({
|
||||
ElMessageBox: {
|
||||
confirm: vi.fn()
|
||||
}
|
||||
}))
|
||||
|
||||
vi.mock('../ts/useGlobalMessage', () => ({
|
||||
useGlobalMessage: () => ({
|
||||
showMessage: vi.fn()
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('../ts/useLogicFlow', () => ({
|
||||
getLogicFlowInstance: vi.fn(() => ({
|
||||
getGraphRawData: vi.fn(() => ({ nodes: [], edges: [] })),
|
||||
getTransform: vi.fn(() => ({
|
||||
SCALE_X: 1,
|
||||
SCALE_Y: 1,
|
||||
TRANSLATE_X: 0,
|
||||
TRANSLATE_Y: 0
|
||||
}))
|
||||
}))
|
||||
}))
|
||||
|
||||
describe('useFilesStore 数据操作测试', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
localStorageMock.clear()
|
||||
})
|
||||
|
||||
it('应该初始化默认文件列表', () => {
|
||||
const store = useFilesStore()
|
||||
store.initializeWithPrompt()
|
||||
|
||||
expect(store.fileList.length).toBeGreaterThan(0)
|
||||
expect(store.fileList[0].name).toBe('File 1')
|
||||
expect(store.fileList[0].type).toBe('FLOW')
|
||||
})
|
||||
|
||||
it('添加新文件应该增加文件列表长度', async () => {
|
||||
const store = useFilesStore()
|
||||
store.initializeWithPrompt()
|
||||
|
||||
const initialLength = store.fileList.length
|
||||
store.addTab()
|
||||
|
||||
// 等待 requestAnimationFrame 完成
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
expect(store.fileList.length).toBe(initialLength + 1)
|
||||
expect(store.fileList[store.fileList.length - 1].name).toContain('File')
|
||||
})
|
||||
|
||||
it('删除文件应该减少文件列表长度', async () => {
|
||||
const store = useFilesStore()
|
||||
store.initializeWithPrompt()
|
||||
store.addTab()
|
||||
|
||||
// 等待添加完成
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
const initialLength = store.fileList.length
|
||||
const fileToDelete = store.fileList[0]
|
||||
|
||||
store.removeTab(fileToDelete.id)
|
||||
|
||||
expect(store.fileList.length).toBe(initialLength - 1)
|
||||
})
|
||||
|
||||
it('切换活动文件应该更新 activeFileId', async () => {
|
||||
const store = useFilesStore()
|
||||
store.initializeWithPrompt()
|
||||
store.addTab()
|
||||
|
||||
// 等待添加完成
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
const secondFile = store.fileList[1]
|
||||
store.activeFileId = secondFile.id
|
||||
|
||||
expect(store.activeFileId).toBe(secondFile.id)
|
||||
})
|
||||
|
||||
it('visibleFiles 应该只返回可见文件', async () => {
|
||||
const store = useFilesStore()
|
||||
store.initializeWithPrompt()
|
||||
store.addTab()
|
||||
|
||||
// 等待添加完成
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
// 隐藏第一个文件
|
||||
store.fileList[0].visible = false
|
||||
|
||||
expect(store.visibleFiles.length).toBe(store.fileList.length - 1)
|
||||
expect(store.visibleFiles.every(f => f.visible)).toBe(true)
|
||||
})
|
||||
|
||||
it('导入数据应该正确恢复文件列表', () => {
|
||||
const store = useFilesStore()
|
||||
|
||||
const mockData = {
|
||||
schemaVersion: '1.0.0',
|
||||
fileList: [
|
||||
{
|
||||
id: 'test-1',
|
||||
name: 'Test File',
|
||||
label: 'Test File',
|
||||
visible: true,
|
||||
type: 'FLOW',
|
||||
graphRawData: { nodes: [], edges: [] }
|
||||
}
|
||||
],
|
||||
activeFileId: 'test-1',
|
||||
activeFile: 'Test File'
|
||||
}
|
||||
|
||||
store.importData(mockData)
|
||||
|
||||
expect(store.fileList.length).toBe(1)
|
||||
expect(store.fileList[0].name).toBe('Test File')
|
||||
expect(store.activeFileId).toBe('test-1')
|
||||
})
|
||||
|
||||
it('重置工作区应该恢复到默认状态', async () => {
|
||||
const store = useFilesStore()
|
||||
store.initializeWithPrompt()
|
||||
store.addTab()
|
||||
store.addTab()
|
||||
|
||||
// 等待添加完成
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
|
||||
store.resetWorkspace()
|
||||
|
||||
expect(store.fileList.length).toBe(1)
|
||||
expect(store.fileList[0].name).toBe('File 1')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user