@deepstorm/cli 0.11.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +8 -8
  2. package/dist/build-registry.js +11 -5
  3. package/dist/cli.js +839 -585
  4. package/dist/mcp/code-hosting/github.json +14 -1
  5. package/dist/mcp/docs-reference/context7.json +1 -10
  6. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-read/SKILL.md +8 -5
  7. package/dist/mcp-skills/deepstorm-mcp-feishu-wiki-write/SKILL.md +10 -8
  8. package/dist/mcp-skills/deepstorm-mcp-figma-read/SKILL.md +21 -20
  9. package/dist/mcp-skills/deepstorm-mcp-github-read/SKILL.md +17 -17
  10. package/dist/mcp-skills/deepstorm-mcp-github-write/SKILL.md +20 -20
  11. package/dist/mcp-skills/deepstorm-mcp-jira-read/SKILL.md +8 -8
  12. package/dist/mcp-skills/deepstorm-mcp-jira-write/SKILL.md +13 -12
  13. package/dist/mcp-skills/deepstorm-mcp-playwright-read/SKILL.md +10 -10
  14. package/dist/skills/atoll-ops/SKILL.md +4 -0
  15. package/dist/skills/reef-commit/SKILL.md +9 -5
  16. package/dist/skills/reef-commit/scripts/branch-check.mjs +5 -11
  17. package/dist/skills/reef-commit/scripts/check-openspec-status.mjs +6 -12
  18. package/dist/skills/reef-commit/scripts/collect-git-context.mjs +13 -11
  19. package/dist/skills/reef-gen-backend/variants/java/steps.md +7 -7
  20. package/dist/skills/reef-gen-backend/variants/nodejs/steps.md +7 -7
  21. package/dist/skills/reef-gen-backend/variants/python/steps.md +7 -7
  22. package/dist/skills/reef-gen-frontend/variants/angular/steps.md +5 -5
  23. package/dist/skills/reef-gen-frontend/variants/react/steps.md +6 -6
  24. package/dist/skills/reef-gen-frontend/variants/vue/steps.md +6 -6
  25. package/dist/skills/reef-harden/EXAMPLES.md +12 -10
  26. package/dist/skills/reef-harden/SKILL.md +6 -0
  27. package/dist/skills/reef-harden/scripts/find-change-dir.mjs +13 -13
  28. package/dist/skills/reef-pr/SKILL.md +7 -0
  29. package/dist/skills/reef-pr/scripts/create-pr.mjs +31 -29
  30. package/dist/skills/reef-scope/SKILL.md +6 -6
  31. package/dist/skills/reef-start/references/jira-start-subagent.md +7 -7
  32. package/dist/skills/reef-start/references/risk-routing-card.md +28 -25
  33. package/dist/skills/reef-start/references/stage-4-implementation.md +33 -21
  34. package/dist/skills/reef-start/references/superpowers-gate.md +9 -9
  35. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/examples/structured-output.md +2 -2
  36. package/dist/skills/reef-style-backend/fragments/java/ai/spring-ai/quick-reference.md +11 -0
  37. package/dist/skills/reef-style-backend/fragments/java/api-spec/jackson-polymorphism.md +36 -40
  38. package/dist/skills/reef-style-backend/fragments/java/api-spec/quick-reference.md +11 -10
  39. package/dist/skills/reef-style-backend/fragments/java/db-migration/liquibase/examples/database-migration.md +7 -7
  40. package/dist/skills/reef-style-backend/fragments/java/dependency-management/quick-reference.md +24 -21
  41. package/dist/skills/reef-style-backend/fragments/java/exception-handling/examples/error-code-enum.md +7 -7
  42. package/dist/skills/reef-style-backend/fragments/java/exception-handling/quick-reference.md +10 -8
  43. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/dto-mapper.md +2 -2
  44. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/service-entity.md +5 -5
  45. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/examples/testing.md +1 -0
  46. package/dist/skills/reef-style-backend/fragments/java/framework/spring-boot/quick-reference.md +12 -12
  47. package/dist/skills/reef-style-backend/fragments/java/orm/hibernate/quick-reference.md +13 -12
  48. package/dist/skills/reef-style-backend/fragments/java/security-redlines/quick-reference.md +11 -9
  49. package/dist/skills/reef-style-backend/fragments/java/test/data-jpa-test/quick-reference.md +7 -7
  50. package/dist/skills/reef-style-backend/fragments/java/test/junit5/quick-reference.md +6 -6
  51. package/dist/skills/reef-style-backend/fragments/java/test/spring-mvc-test/quick-reference.md +8 -8
  52. package/dist/skills/reef-style-backend/fragments/java/test/spring-service-test/quick-reference.md +8 -7
  53. package/dist/skills/reef-style-backend/fragments/nodejs/eslint-config.json +1 -4
  54. package/dist/skills/reef-style-backend/fragments/nodejs/nestjs-structure.md +9 -9
  55. package/dist/skills/reef-style-backend/fragments/python/alembic-migration/quick-reference.md +2 -1
  56. package/dist/skills/reef-style-backend/fragments/python/api-spec/quick-reference.md +10 -10
  57. package/dist/skills/reef-style-backend/fragments/python/dependency-management/quick-reference.md +24 -22
  58. package/dist/skills/reef-style-backend/fragments/python/exception-handling/quick-reference.md +10 -9
  59. package/dist/skills/reef-style-backend/fragments/python/fastapi-quick-reference/quick-reference.md +3 -0
  60. package/dist/skills/reef-style-backend/fragments/python/langchain/quick-reference.md +10 -7
  61. package/dist/skills/reef-style-backend/fragments/python/pytest-testing/quick-reference.md +2 -0
  62. package/dist/skills/reef-style-backend/fragments/python/ruff-mypy-toolchain/quick-reference.md +2 -0
  63. package/dist/skills/reef-style-backend/fragments/python/security-redlines/quick-reference.md +11 -9
  64. package/dist/skills/reef-style-backend/fragments/python/sqlalchemy-orm/quick-reference.md +3 -0
  65. package/dist/skills/reef-style-backend/variants/java/examples/code-wrapping.md +3 -4
  66. package/dist/skills/reef-style-backend/variants/java/quick-reference.md +31 -29
  67. package/dist/skills/reef-style-backend/variants/nodejs/examples/module-example.md +2 -8
  68. package/dist/skills/reef-style-backend/variants/nodejs/quick-reference.md +35 -36
  69. package/dist/skills/reef-style-backend/variants/python/quick-reference.md +32 -31
  70. package/dist/skills/reef-style-frontend/fragments/css/tailwind/quick-reference.md +9 -7
  71. package/dist/skills/reef-style-frontend/fragments/test/vitest/examples/testing.md +9 -4
  72. package/dist/skills/reef-style-frontend/fragments/test/vitest/quick-reference.md +4 -4
  73. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/examples/testing.md +135 -140
  74. package/dist/skills/reef-style-frontend/fragments/test/vitest-react/quick-reference.md +32 -32
  75. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/examples/testing.md +161 -162
  76. package/dist/skills/reef-style-frontend/fragments/test/vitest-vue/quick-reference.md +42 -42
  77. package/dist/skills/reef-style-frontend/fragments/ts-config/strict/quick-reference.md +16 -10
  78. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/examples/ui-components.md +72 -87
  79. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd/quick-reference.md +14 -10
  80. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/examples/ui-components.md +93 -111
  81. package/dist/skills/reef-style-frontend/fragments/ui-lib/antd-vue/quick-reference.md +29 -33
  82. package/dist/skills/reef-style-frontend/fragments/ui-lib/primeng/examples/ui-components.md +14 -23
  83. package/dist/skills/reef-style-frontend/variants/angular/examples/code-wrapping.md +15 -17
  84. package/dist/skills/reef-style-frontend/variants/angular/examples/component-types-pipes.md +22 -5
  85. package/dist/skills/reef-style-frontend/variants/angular/examples/entity-types.md +52 -22
  86. package/dist/skills/reef-style-frontend/variants/angular/examples/forms-layer.md +17 -20
  87. package/dist/skills/reef-style-frontend/variants/angular/examples/service-routing.md +8 -11
  88. package/dist/skills/reef-style-frontend/variants/angular/quick-reference.md +27 -27
  89. package/dist/skills/reef-style-frontend/variants/react/examples/code-wrapping.md +14 -27
  90. package/dist/skills/reef-style-frontend/variants/react/examples/component-types-pipes.md +45 -52
  91. package/dist/skills/reef-style-frontend/variants/react/examples/entity-types.md +44 -44
  92. package/dist/skills/reef-style-frontend/variants/react/examples/forms-layer.md +56 -85
  93. package/dist/skills/reef-style-frontend/variants/react/examples/service-routing.md +114 -88
  94. package/dist/skills/reef-style-frontend/variants/react/quick-reference.md +48 -42
  95. package/dist/skills/reef-style-frontend/variants/vue/examples/code-wrapping.md +24 -43
  96. package/dist/skills/reef-style-frontend/variants/vue/examples/component-types-pipes.md +48 -49
  97. package/dist/skills/reef-style-frontend/variants/vue/examples/entity-types.md +45 -45
  98. package/dist/skills/reef-style-frontend/variants/vue/examples/forms-layer.md +64 -68
  99. package/dist/skills/reef-style-frontend/variants/vue/examples/service-routing.md +85 -84
  100. package/dist/skills/reef-style-frontend/variants/vue/quick-reference.md +46 -51
  101. package/dist/skills/reef-testcase/SKILL.md +19 -19
  102. package/dist/skills/reef-testcase/references/coverage-dimensions.md +8 -0
  103. package/dist/skills/reef-testcase/references/test-case-template.md +16 -16
  104. package/dist/skills/sweep-explore/SKILL.md +129 -100
  105. package/dist/skills/sweep-explore/references/explore-flow-template.md +9 -9
  106. package/dist/skills/sweep-init/SKILL.md +4 -0
  107. package/dist/skills/sweep-init/scripts/flow-selector.mjs +6 -11
  108. package/dist/skills/sweep-init/scripts/init-project.mjs +68 -51
  109. package/dist/skills/sweep-plan/references/test-flow-template.md +12 -6
  110. package/dist/skills/sweep-record/SKILL.md +38 -15
  111. package/dist/skills/sweep-run/SKILL.md +59 -50
  112. package/dist/skills/sweep-run/scripts/env-manager.mjs +4 -5
  113. package/dist/skills/sweep-run/scripts/flow-parser.mjs +7 -6
  114. package/dist/skills/sweep-run/scripts/flow-selector.mjs +4 -15
  115. package/dist/skills/sweep-run/scripts/generate-report.mjs +1 -2
  116. package/dist/skills/sweep-run/scripts/mcp-manager.mjs +107 -14
  117. package/dist/skills/sweep-run/scripts/spec-compiler.mjs +19 -9
  118. package/dist/skills/tide-discuss/references/checklists.md +32 -32
  119. package/dist/skills/tide-discuss/references/data-format.md +85 -77
  120. package/dist/skills/tide-discuss/references/prd-template.md +21 -19
  121. package/dist/skills/tide-discuss/references/publish-flow.md +30 -11
  122. package/dist/skills/tide-discuss/references/role-prompts.md +5 -5
  123. package/package.json +4 -3
@@ -6,15 +6,15 @@
6
6
  <!-- UserAvatar.vue -->
7
7
  <script setup lang="ts">
8
8
  interface Props {
9
- username: string
10
- avatar?: string
11
- size?: 'sm' | 'md' | 'lg'
12
- onClick?: () => void
9
+ username: string;
10
+ avatar?: string;
11
+ size?: 'sm' | 'md' | 'lg';
12
+ onClick?: () => void;
13
13
  }
14
14
 
15
15
  const props = withDefaults(defineProps<Props>(), {
16
16
  size: 'md',
17
- })
17
+ });
18
18
  </script>
19
19
 
20
20
  <template>
@@ -30,12 +30,12 @@ const props = withDefaults(defineProps<Props>(), {
30
30
 
31
31
  ```typescript
32
32
  // UserAvatar.test.ts
33
- import { mount } from '@vue/test-utils'
34
- import { describe, it, expect, vi } from 'vitest'
35
- import UserAvatar from './UserAvatar.vue'
33
+ import { mount } from '@vue/test-utils';
34
+ import { describe, it, expect, vi } from 'vitest';
35
+ import UserAvatar from './UserAvatar.vue';
36
36
 
37
37
  describe('UserAvatar', () => {
38
- const mockUser = { username: 'alice', avatar: 'https://example.com/avatar.png' }
38
+ const mockUser = { username: 'alice', avatar: 'https://example.com/avatar.png' };
39
39
 
40
40
  it('renders with avatar image', () => {
41
41
  const wrapper = mount(UserAvatar, {
@@ -43,12 +43,12 @@ describe('UserAvatar', () => {
43
43
  username: mockUser.username,
44
44
  avatar: mockUser.avatar,
45
45
  },
46
- })
46
+ });
47
47
 
48
- const img = wrapper.find('img')
49
- expect(img.attributes('alt')).toBe('alice')
50
- expect(img.attributes('src')).toBe(mockUser.avatar)
51
- })
48
+ const img = wrapper.find('img');
49
+ expect(img.attributes('alt')).toBe('alice');
50
+ expect(img.attributes('src')).toBe(mockUser.avatar);
51
+ });
52
52
 
53
53
  it('renders with size classes', () => {
54
54
  const wrapper = mount(UserAvatar, {
@@ -56,25 +56,25 @@ describe('UserAvatar', () => {
56
56
  username: mockUser.username,
57
57
  size: 'lg',
58
58
  },
59
- })
59
+ });
60
60
 
61
61
  // Ant Design Vue Avatar 通过 size 属性控制尺寸
62
- expect(wrapper.findComponent({ name: 'AAvatar' }).exists()).toBe(true)
63
- })
62
+ expect(wrapper.findComponent({ name: 'AAvatar' }).exists()).toBe(true);
63
+ });
64
64
 
65
65
  it('is clickable when onClick provided', async () => {
66
- const handleClick = vi.fn()
66
+ const handleClick = vi.fn();
67
67
  const wrapper = mount(UserAvatar, {
68
68
  props: {
69
69
  username: mockUser.username,
70
70
  onClick: handleClick,
71
71
  },
72
- })
72
+ });
73
73
 
74
- await wrapper.findComponent({ name: 'AAvatar' }).trigger('click')
75
- expect(handleClick).toHaveBeenCalledTimes(1)
76
- })
77
- })
74
+ await wrapper.findComponent({ name: 'AAvatar' }).trigger('click');
75
+ expect(handleClick).toHaveBeenCalledTimes(1);
76
+ });
77
+ });
78
78
  ```
79
79
 
80
80
  ## 表单测试
@@ -82,27 +82,27 @@ describe('UserAvatar', () => {
82
82
  ```vue
83
83
  <!-- CreateUserForm.vue -->
84
84
  <script setup lang="ts">
85
- import { reactive, ref } from 'vue'
86
- import { message } from 'ant-design-vue'
85
+ import { reactive, ref } from 'vue';
86
+ import { message } from 'ant-design-vue';
87
87
 
88
88
  interface FormState {
89
- username: string
90
- email: string
91
- role: string | undefined
89
+ username: string;
90
+ email: string;
91
+ role: string | undefined;
92
92
  }
93
93
 
94
94
  const emit = defineEmits<{
95
- success: []
96
- }>()
95
+ success: [];
96
+ }>();
97
97
 
98
98
  const formState = reactive<FormState>({
99
99
  username: '',
100
100
  email: '',
101
101
  role: undefined,
102
- })
102
+ });
103
103
 
104
- const loading = ref(false)
105
- const formRef = ref()
104
+ const loading = ref(false);
105
+ const formRef = ref();
106
106
 
107
107
  const rules = {
108
108
  username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
@@ -111,26 +111,26 @@ const rules = {
111
111
  { type: 'email', message: '请输入有效的邮箱地址', trigger: 'blur' },
112
112
  ],
113
113
  role: [{ required: true, message: '请选择角色', trigger: 'change' }],
114
- }
114
+ };
115
115
 
116
116
  async function handleSubmit() {
117
117
  try {
118
- await formRef.value?.validate()
119
- loading.value = true
118
+ await formRef.value?.validate();
119
+ loading.value = true;
120
120
 
121
121
  const res = await fetch('/api/v1/users', {
122
122
  method: 'POST',
123
123
  headers: { 'Content-Type': 'application/json' },
124
124
  body: JSON.stringify(formState),
125
- })
125
+ });
126
126
 
127
- if (!res.ok) throw new Error('创建失败')
128
- message.success('用户创建成功')
129
- emit('success')
127
+ if (!res.ok) throw new Error('创建失败');
128
+ message.success('用户创建成功');
129
+ emit('success');
130
130
  } catch (e) {
131
- if (e instanceof Error) message.error(e.message)
131
+ if (e instanceof Error) message.error(e.message);
132
132
  } finally {
133
- loading.value = false
133
+ loading.value = false;
134
134
  }
135
135
  }
136
136
  </script>
@@ -159,9 +159,7 @@ async function handleSubmit() {
159
159
  </a-form-item>
160
160
 
161
161
  <a-form-item :wrapper-col="{ offset: 6, span: 16 }">
162
- <a-button type="primary" html-type="submit" :loading="loading">
163
- 创建
164
- </a-button>
162
+ <a-button type="primary" html-type="submit" :loading="loading"> 创建 </a-button>
165
163
  </a-form-item>
166
164
  </a-form>
167
165
  </template>
@@ -169,183 +167,184 @@ async function handleSubmit() {
169
167
 
170
168
  ```typescript
171
169
  // CreateUserForm.test.ts
172
- import { mount } from '@vue/test-utils'
173
- import { describe, it, expect, vi, beforeEach } from 'vitest'
174
- import { nextTick } from 'vue'
175
- import CreateUserForm from './CreateUserForm.vue'
170
+ import { mount } from '@vue/test-utils';
171
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
172
+ import { nextTick } from 'vue';
173
+ import CreateUserForm from './CreateUserForm.vue';
176
174
 
177
175
  // Mock Ant Design Vue message
178
176
  vi.mock('ant-design-vue', async () => {
179
- const actual = await vi.importActual('ant-design-vue')
180
- return { ...actual, message: { success: vi.fn(), error: vi.fn() } }
181
- })
177
+ const actual = await vi.importActual('ant-design-vue');
178
+ return { ...actual, message: { success: vi.fn(), error: vi.fn() } };
179
+ });
182
180
 
183
181
  describe('CreateUserForm', () => {
184
182
  beforeEach(() => {
185
- vi.clearAllMocks()
186
- })
183
+ vi.clearAllMocks();
184
+ });
187
185
 
188
186
  it('renders all form fields', () => {
189
- const wrapper = mount(CreateUserForm)
187
+ const wrapper = mount(CreateUserForm);
190
188
 
191
- expect(wrapper.text()).toContain('用户名')
192
- expect(wrapper.text()).toContain('邮箱')
193
- expect(wrapper.text()).toContain('角色')
194
- })
189
+ expect(wrapper.text()).toContain('用户名');
190
+ expect(wrapper.text()).toContain('邮箱');
191
+ expect(wrapper.text()).toContain('角色');
192
+ });
195
193
 
196
194
  it('shows validation errors on empty submit', async () => {
197
- const wrapper = mount(CreateUserForm)
195
+ const wrapper = mount(CreateUserForm);
198
196
 
199
- await wrapper.find('form').trigger('submit')
200
- await nextTick()
197
+ await wrapper.find('form').trigger('submit');
198
+ await nextTick();
201
199
 
202
- expect(wrapper.text()).toContain('请输入用户名')
203
- expect(wrapper.text()).toContain('请输入邮箱')
204
- })
200
+ expect(wrapper.text()).toContain('请输入用户名');
201
+ expect(wrapper.text()).toContain('请输入邮箱');
202
+ });
205
203
 
206
204
  it('submits form with valid data', async () => {
207
205
  global.fetch = vi.fn().mockResolvedValue({
208
206
  ok: true,
209
207
  json: () => Promise.resolve({ id: '1' }),
210
- })
208
+ });
211
209
 
212
- const wrapper = mount(CreateUserForm)
210
+ const wrapper = mount(CreateUserForm);
213
211
 
214
212
  // 填充表单
215
- await wrapper.find('input').setValue('newuser')
216
- const inputs = wrapper.findAll('input')
217
- await inputs[1].setValue('new@example.com')
213
+ await wrapper.find('input').setValue('newuser');
214
+ const inputs = wrapper.findAll('input');
215
+ await inputs[1].setValue('new@example.com');
218
216
 
219
217
  // 提交
220
- await wrapper.find('form').trigger('submit')
221
- await nextTick()
218
+ await wrapper.find('form').trigger('submit');
219
+ await nextTick();
222
220
 
223
- expect(global.fetch).toHaveBeenCalled()
224
- })
225
- })
221
+ expect(global.fetch).toHaveBeenCalled();
222
+ });
223
+ });
226
224
  ```
227
225
 
228
226
  ## 组合式函数测试
229
227
 
230
228
  ```typescript
231
229
  // useUsers.test.ts
232
- import { describe, it, expect, vi, beforeEach } from 'vitest'
233
- import { withSetup } from '@/test/utils'
230
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
231
+ import { withSetup } from '@/test/utils';
234
232
 
235
233
  // withSetup 辅助函数:在测试环境中执行组合式函数
236
234
  function withSetup<T>(hook: () => T): T {
237
- let result: T
235
+ let result: T;
238
236
  const wrapper = defineComponent({
239
237
  setup() {
240
- result = hook()
241
- return () => null
238
+ result = hook();
239
+ return () => null;
242
240
  },
243
- })
244
- mount(wrapper)
245
- return result!
241
+ });
242
+ mount(wrapper);
243
+ return result!;
246
244
  }
247
245
 
248
246
  describe('useUsers', () => {
249
- const mockUsers = [
250
- { id: '1', username: 'alice', email: 'alice@example.com', role: 'ADMIN' },
251
- ]
247
+ const mockUsers = [{ id: '1', username: 'alice', email: 'alice@example.com', role: 'ADMIN' }];
252
248
 
253
249
  beforeEach(() => {
254
- vi.clearAllMocks()
255
- })
250
+ vi.clearAllMocks();
251
+ });
256
252
 
257
253
  it('returns loading state initially', () => {
258
- global.fetch = vi.fn().mockImplementation(() => new Promise(() => {}))
254
+ global.fetch = vi.fn().mockImplementation(() => new Promise(() => {}));
259
255
 
260
- const { loading, users, error } = useUsers()
256
+ const { loading, users, error } = useUsers();
261
257
 
262
- expect(loading.value).toBe(true)
263
- expect(users.value).toEqual([])
264
- expect(error.value).toBeNull()
265
- })
258
+ expect(loading.value).toBe(true);
259
+ expect(users.value).toEqual([]);
260
+ expect(error.value).toBeNull();
261
+ });
266
262
 
267
263
  it('returns users on successful fetch', async () => {
268
264
  global.fetch = vi.fn().mockResolvedValue({
269
265
  ok: true,
270
266
  json: () => Promise.resolve({ content: mockUsers, totalElements: 1 }),
271
- })
267
+ });
272
268
 
273
269
  // 在 setup 中调用组合式函数
274
- let result: ReturnType<typeof useUsers>
270
+ let result: ReturnType<typeof useUsers>;
275
271
  mount(
276
272
  defineComponent({
277
273
  setup() {
278
- result = useUsers()
279
- return () => null
274
+ result = useUsers();
275
+ return () => null;
280
276
  },
281
- })
282
- )
277
+ }),
278
+ );
283
279
 
284
280
  await vi.waitFor(() => {
285
- expect(result!.loading.value).toBe(false)
286
- })
281
+ expect(result!.loading.value).toBe(false);
282
+ });
287
283
 
288
- expect(result!.users.value).toEqual(mockUsers)
289
- expect(result!.error.value).toBeNull()
290
- })
284
+ expect(result!.users.value).toEqual(mockUsers);
285
+ expect(result!.error.value).toBeNull();
286
+ });
291
287
 
292
288
  it('returns error on fetch failure', async () => {
293
- global.fetch = vi.fn().mockRejectedValue(new Error('Network error'))
289
+ global.fetch = vi.fn().mockRejectedValue(new Error('Network error'));
294
290
 
295
- let result: ReturnType<typeof useUsers>
291
+ let result: ReturnType<typeof useUsers>;
296
292
  mount(
297
293
  defineComponent({
298
294
  setup() {
299
- result = useUsers()
300
- return () => null
295
+ result = useUsers();
296
+ return () => null;
301
297
  },
302
- })
303
- )
298
+ }),
299
+ );
304
300
 
305
301
  await vi.waitFor(() => {
306
- expect(result!.loading.value).toBe(false)
307
- })
302
+ expect(result!.loading.value).toBe(false);
303
+ });
308
304
 
309
- expect(result!.error.value).toBeInstanceOf(Error)
310
- expect(result!.error.value?.message).toBe('Network error')
311
- })
305
+ expect(result!.error.value).toBeInstanceOf(Error);
306
+ expect(result!.error.value?.message).toBe('Network error');
307
+ });
312
308
 
313
309
  it('refresh resets loading state', async () => {
314
- let resolvePromise!: (value: unknown) => void
310
+ let resolvePromise!: (value: unknown) => void;
315
311
  global.fetch = vi.fn().mockImplementation(
316
- () => new Promise((resolve) => { resolvePromise = resolve })
317
- )
312
+ () =>
313
+ new Promise((resolve) => {
314
+ resolvePromise = resolve;
315
+ }),
316
+ );
318
317
 
319
- let result: ReturnType<typeof useUsers>
318
+ let result: ReturnType<typeof useUsers>;
320
319
  mount(
321
320
  defineComponent({
322
321
  setup() {
323
- result = useUsers()
324
- return () => null
322
+ result = useUsers();
323
+ return () => null;
325
324
  },
326
- })
327
- )
325
+ }),
326
+ );
328
327
 
329
- result!.refresh()
330
- expect(result!.loading.value).toBe(true)
331
- })
332
- })
328
+ result!.refresh();
329
+ expect(result!.loading.value).toBe(true);
330
+ });
331
+ });
333
332
  ```
334
333
 
335
334
  ## Ant Design Vue 组件集成测试
336
335
 
337
336
  ```typescript
338
337
  // UserTable.test.ts
339
- import { mount } from '@vue/test-utils'
340
- import { describe, it, expect, vi } from 'vitest'
341
- import { defineComponent } from 'vue'
342
- import { Table } from 'ant-design-vue'
338
+ import { mount } from '@vue/test-utils';
339
+ import { describe, it, expect, vi } from 'vitest';
340
+ import { defineComponent } from 'vue';
341
+ import { Table } from 'ant-design-vue';
343
342
 
344
343
  interface User {
345
- id: string
346
- username: string
347
- email: string
348
- role: string
344
+ id: string;
345
+ username: string;
346
+ email: string;
347
+ role: string;
349
348
  }
350
349
 
351
350
  describe('UserTable with Ant Design Vue', () => {
@@ -353,12 +352,12 @@ describe('UserTable with Ant Design Vue', () => {
353
352
  { title: '用户名', dataIndex: 'username', key: 'username' },
354
353
  { title: '邮箱', dataIndex: 'email', key: 'email' },
355
354
  { title: '角色', dataIndex: 'role', key: 'role' },
356
- ]
355
+ ];
357
356
 
358
357
  const mockData: User[] = [
359
358
  { id: '1', username: 'alice', email: 'alice@example.com', role: 'ADMIN' },
360
359
  { id: '2', username: 'bob', email: 'bob@example.com', role: 'EDITOR' },
361
- ]
360
+ ];
362
361
 
363
362
  it('renders table with data', () => {
364
363
  const wrapper = mount(
@@ -372,12 +371,12 @@ describe('UserTable with Ant Design Vue', () => {
372
371
  `,
373
372
  components: { ATable: Table },
374
373
  setup: () => ({ data: mockData, columns }),
375
- })
376
- )
374
+ }),
375
+ );
377
376
 
378
- expect(wrapper.text()).toContain('alice')
379
- expect(wrapper.text()).toContain('bob')
380
- })
377
+ expect(wrapper.text()).toContain('alice');
378
+ expect(wrapper.text()).toContain('bob');
379
+ });
381
380
 
382
381
  it('shows empty state when no data', () => {
383
382
  const wrapper = mount(
@@ -392,12 +391,12 @@ describe('UserTable with Ant Design Vue', () => {
392
391
  `,
393
392
  components: { ATable: Table },
394
393
  setup: () => ({ columns }),
395
- })
396
- )
394
+ }),
395
+ );
397
396
 
398
- expect(wrapper.text()).toContain('暂无数据')
399
- })
400
- })
397
+ expect(wrapper.text()).toContain('暂无数据');
398
+ });
399
+ });
401
400
  ```
402
401
 
403
402
  ## 路由组件测试
@@ -405,14 +404,14 @@ describe('UserTable with Ant Design Vue', () => {
405
404
  ```vue
406
405
  <!-- ProtectedRoute.vue -->
407
406
  <script setup lang="ts">
408
- import { useAuthStore } from '@/stores/auth'
409
- import { useRouter } from 'vue-router'
407
+ import { useAuthStore } from '@/stores/auth';
408
+ import { useRouter } from 'vue-router';
410
409
 
411
- const auth = useAuthStore()
412
- const router = useRouter()
410
+ const auth = useAuthStore();
411
+ const router = useRouter();
413
412
 
414
413
  if (!auth.isAuthenticated) {
415
- router.replace({ name: 'login' })
414
+ router.replace({ name: 'login' });
416
415
  }
417
416
  </script>
418
417
 
@@ -423,11 +422,11 @@ if (!auth.isAuthenticated) {
423
422
 
424
423
  ```typescript
425
424
  // ProtectedRoute.test.ts
426
- import { mount } from '@vue/test-utils'
427
- import { describe, it, expect, vi } from 'vitest'
428
- import { createRouter, createWebHistory } from 'vue-router'
429
- import { createTestingPinia } from '@pinia/testing'
430
- import ProtectedRoute from './ProtectedRoute.vue'
425
+ import { mount } from '@vue/test-utils';
426
+ import { describe, it, expect, vi } from 'vitest';
427
+ import { createRouter, createWebHistory } from 'vue-router';
428
+ import { createTestingPinia } from '@pinia/testing';
429
+ import ProtectedRoute from './ProtectedRoute.vue';
431
430
 
432
431
  describe('ProtectedRoute', () => {
433
432
  it('redirects to login when not authenticated', () => {
@@ -449,9 +448,9 @@ describe('ProtectedRoute', () => {
449
448
  }),
450
449
  ],
451
450
  },
452
- })
451
+ });
453
452
 
454
- expect(wrapper.text()).not.toContain('Protected Content')
455
- })
456
- })
453
+ expect(wrapper.text()).not.toContain('Protected Content');
454
+ });
455
+ });
457
456
  ```