retestkit 1.4.1 → 1.5.0

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 (238) hide show
  1. package/README.md +59 -40
  2. package/dist/config.js +8 -8
  3. package/dist/config.js.map +1 -1
  4. package/dist/logger.js +1 -1
  5. package/dist/logger.js.map +1 -1
  6. package/dist/prompts/index.d.ts +1 -1
  7. package/dist/prompts/index.d.ts.map +1 -1
  8. package/dist/prompts/index.js +21 -21
  9. package/dist/prompts/index.js.map +1 -1
  10. package/dist/prompts/templates/mcp/retest-crawl.md +7 -0
  11. package/{src/prompts/templates/mcp/webtest-discover-flows.md → dist/prompts/templates/mcp/retest-discover-flows.md} +1 -1
  12. package/{src/prompts/templates/mcp/webtest-discover.md → dist/prompts/templates/mcp/retest-discover.md} +2 -2
  13. package/dist/prompts/templates/mcp/retest-full-workflow.md +12 -0
  14. package/{src/prompts/templates/mcp/webtest-generate-tests.md → dist/prompts/templates/mcp/retest-generate-tests.md} +1 -1
  15. package/{src/prompts/templates/mcp/webtest-run-test.md → dist/prompts/templates/mcp/retest-run-test.md} +1 -1
  16. package/{src/prompts/templates/mcp/webtest-start.md → dist/prompts/templates/mcp/retest-start.md} +1 -1
  17. package/{src → dist}/prompts/templates/sampling/system-prefix.md +1 -1
  18. package/dist/resources/index.js +7 -7
  19. package/dist/resources/index.js.map +1 -1
  20. package/dist/schemas/config.js +2 -2
  21. package/dist/schemas/config.js.map +1 -1
  22. package/dist/security/index.js +1 -1
  23. package/dist/security/index.js.map +1 -1
  24. package/dist/server.js +3 -3
  25. package/dist/server.js.map +1 -1
  26. package/dist/test-utils/mock-context.js +22 -22
  27. package/dist/test-utils/mock-context.js.map +1 -1
  28. package/dist/tools/index.d.ts +1 -1
  29. package/dist/tools/index.d.ts.map +1 -1
  30. package/dist/tools/index.js +5 -5
  31. package/dist/tools/index.js.map +1 -1
  32. package/dist/tools/retest/crawl.d.ts.map +1 -0
  33. package/dist/tools/{webtest → retest}/crawl.js +7 -7
  34. package/dist/tools/retest/crawl.js.map +1 -0
  35. package/dist/tools/retest/discover-features.d.ts.map +1 -0
  36. package/dist/tools/{webtest → retest}/discover-features.js +6 -6
  37. package/dist/tools/retest/discover-features.js.map +1 -0
  38. package/dist/tools/retest/discover-flows.d.ts.map +1 -0
  39. package/dist/tools/{webtest → retest}/discover-flows.js +6 -6
  40. package/dist/tools/retest/discover-flows.js.map +1 -0
  41. package/dist/tools/retest/generate-tests.d.ts.map +1 -0
  42. package/dist/tools/{webtest → retest}/generate-tests.js +5 -5
  43. package/dist/tools/retest/generate-tests.js.map +1 -0
  44. package/dist/tools/retest/index.d.ts.map +1 -0
  45. package/dist/tools/retest/index.js.map +1 -0
  46. package/dist/tools/retest/run-test-case.d.ts.map +1 -0
  47. package/dist/tools/{webtest → retest}/run-test-case.js +3 -3
  48. package/dist/tools/retest/run-test-case.js.map +1 -0
  49. package/dist/tools/retest/schemas.d.ts.map +1 -0
  50. package/dist/tools/retest/schemas.js.map +1 -0
  51. package/dist/tools/retest/start-analysis.d.ts.map +1 -0
  52. package/dist/tools/{webtest → retest}/start-analysis.js +5 -5
  53. package/dist/tools/retest/start-analysis.js.map +1 -0
  54. package/dist/workspace/index.js +8 -8
  55. package/dist/workspace/index.js.map +1 -1
  56. package/dist/workspace/types.d.ts +2 -2
  57. package/dist/workspace/types.d.ts.map +1 -1
  58. package/package.json +6 -2
  59. package/.claude/commands/openspec/apply.md +0 -23
  60. package/.claude/commands/openspec/archive.md +0 -27
  61. package/.claude/commands/openspec/proposal.md +0 -28
  62. package/.gemini/commands/openspec/apply.toml +0 -21
  63. package/.gemini/commands/openspec/archive.toml +0 -25
  64. package/.gemini/commands/openspec/proposal.toml +0 -26
  65. package/.github/prompts/openspec-apply.prompt.md +0 -22
  66. package/.github/prompts/openspec-archive.prompt.md +0 -26
  67. package/.github/prompts/openspec-proposal.prompt.md +0 -27
  68. package/.github/workflows/release.yml +0 -33
  69. package/.kilocode/workflows/openspec-apply.md +0 -17
  70. package/.kilocode/workflows/openspec-archive.md +0 -21
  71. package/.kilocode/workflows/openspec-proposal.md +0 -22
  72. package/.mcp.json +0 -23
  73. package/.opencode/command/openspec-apply.md +0 -25
  74. package/.opencode/command/openspec-archive.md +0 -28
  75. package/.opencode/command/openspec-proposal.md +0 -30
  76. package/.roo/commands/openspec-apply.md +0 -20
  77. package/.roo/commands/openspec-archive.md +0 -24
  78. package/.roo/commands/openspec-proposal.md +0 -25
  79. package/.vscode/mcp.json +0 -23
  80. package/AGENTS.md +0 -18
  81. package/CLAUDE.md +0 -18
  82. package/dist/tools/webtest/crawl.d.ts.map +0 -1
  83. package/dist/tools/webtest/crawl.js.map +0 -1
  84. package/dist/tools/webtest/discover-features.d.ts.map +0 -1
  85. package/dist/tools/webtest/discover-features.js.map +0 -1
  86. package/dist/tools/webtest/discover-flows.d.ts.map +0 -1
  87. package/dist/tools/webtest/discover-flows.js.map +0 -1
  88. package/dist/tools/webtest/generate-tests.d.ts.map +0 -1
  89. package/dist/tools/webtest/generate-tests.js.map +0 -1
  90. package/dist/tools/webtest/index.d.ts.map +0 -1
  91. package/dist/tools/webtest/index.js.map +0 -1
  92. package/dist/tools/webtest/run-test-case.d.ts.map +0 -1
  93. package/dist/tools/webtest/run-test-case.js.map +0 -1
  94. package/dist/tools/webtest/schemas.d.ts.map +0 -1
  95. package/dist/tools/webtest/schemas.js.map +0 -1
  96. package/dist/tools/webtest/start-analysis.d.ts.map +0 -1
  97. package/dist/tools/webtest/start-analysis.js.map +0 -1
  98. package/openspec/AGENTS.md +0 -456
  99. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/proposal.md +0 -33
  100. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-resources/spec.md +0 -27
  101. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-tools/spec.md +0 -304
  102. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/tasks.md +0 -43
  103. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/design.md +0 -209
  104. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/proposal.md +0 -41
  105. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/specs/mcp-server-core/spec.md +0 -183
  106. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/tasks.md +0 -112
  107. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/design.md +0 -333
  108. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/proposal.md +0 -66
  109. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/mcp-server-core/spec.md +0 -129
  110. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-lifecycle/spec.md +0 -138
  111. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-logging/spec.md +0 -211
  112. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-prompts/spec.md +0 -157
  113. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-resources/spec.md +0 -213
  114. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-sampling/spec.md +0 -257
  115. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-tools/spec.md +0 -501
  116. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/tasks.md +0 -264
  117. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/proposal.md +0 -24
  118. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/specs/webtest-tools/spec.md +0 -80
  119. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/tasks.md +0 -8
  120. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/design.md +0 -90
  121. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/proposal.md +0 -28
  122. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/specs/webtest-sampling/spec.md +0 -90
  123. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/tasks.md +0 -33
  124. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/design.md +0 -558
  125. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/proposal.md +0 -119
  126. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-resources/spec.md +0 -109
  127. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-tools/spec.md +0 -121
  128. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/tasks.md +0 -133
  129. package/openspec/changes/extract-prompts-to-markdown/design.md +0 -86
  130. package/openspec/changes/extract-prompts-to-markdown/proposal.md +0 -50
  131. package/openspec/changes/extract-prompts-to-markdown/specs/webtest-prompts/spec.md +0 -74
  132. package/openspec/changes/extract-prompts-to-markdown/tasks.md +0 -40
  133. package/openspec/changes/refactor-webtest-naming/design.md +0 -95
  134. package/openspec/changes/refactor-webtest-naming/proposal.md +0 -66
  135. package/openspec/changes/refactor-webtest-naming/specs/webtest-prompts/spec.md +0 -79
  136. package/openspec/changes/refactor-webtest-naming/specs/webtest-resources/spec.md +0 -80
  137. package/openspec/changes/refactor-webtest-naming/specs/webtest-sampling/spec.md +0 -122
  138. package/openspec/changes/refactor-webtest-naming/specs/webtest-tools/spec.md +0 -113
  139. package/openspec/changes/refactor-webtest-naming/tasks.md +0 -119
  140. package/openspec/changes/rename-package-to-retest/proposal.md +0 -52
  141. package/openspec/changes/rename-package-to-retest/specs/mcp-server-core/spec.md +0 -53
  142. package/openspec/changes/rename-package-to-retest/specs/retest-lifecycle/spec.md +0 -68
  143. package/openspec/changes/rename-package-to-retest/specs/retest-logging/spec.md +0 -35
  144. package/openspec/changes/rename-package-to-retest/specs/retest-prompts/spec.md +0 -159
  145. package/openspec/changes/rename-package-to-retest/specs/retest-resources/spec.md +0 -251
  146. package/openspec/changes/rename-package-to-retest/specs/retest-sampling/spec.md +0 -99
  147. package/openspec/changes/rename-package-to-retest/specs/retest-tools/spec.md +0 -295
  148. package/openspec/changes/rename-package-to-retest/tasks.md +0 -71
  149. package/openspec/project.md +0 -31
  150. package/openspec/specs/mcp-server-core/spec.md +0 -178
  151. package/openspec/specs/webtest-lifecycle/spec.md +0 -136
  152. package/openspec/specs/webtest-logging/spec.md +0 -209
  153. package/openspec/specs/webtest-prompts/spec.md +0 -155
  154. package/openspec/specs/webtest-resources/spec.md +0 -248
  155. package/openspec/specs/webtest-sampling/spec.md +0 -344
  156. package/openspec/specs/webtest-tools/spec.md +0 -282
  157. package/release.config.js +0 -9
  158. package/src/config.test.ts +0 -96
  159. package/src/config.ts +0 -32
  160. package/src/elicitation/index.test.ts +0 -399
  161. package/src/elicitation/index.ts +0 -171
  162. package/src/elicitation/types.ts +0 -68
  163. package/src/index.ts +0 -83
  164. package/src/lifecycle/index.test.ts +0 -260
  165. package/src/lifecycle/index.ts +0 -101
  166. package/src/logger.redaction.test.ts +0 -322
  167. package/src/logger.test.ts +0 -123
  168. package/src/logger.ts +0 -229
  169. package/src/playwright-client/index.ts +0 -392
  170. package/src/playwright-client/types.ts +0 -99
  171. package/src/progress/index.test.ts +0 -327
  172. package/src/progress/index.ts +0 -170
  173. package/src/progress/types.ts +0 -25
  174. package/src/prompts/index.test.ts +0 -451
  175. package/src/prompts/index.ts +0 -246
  176. package/src/prompts/loader.test.ts +0 -100
  177. package/src/prompts/loader.ts +0 -59
  178. package/src/prompts/templates/mcp/webtest-crawl.md +0 -7
  179. package/src/prompts/templates/mcp/webtest-full-workflow.md +0 -12
  180. package/src/resources/index.ts +0 -250
  181. package/src/resources/subscriptions.ts +0 -37
  182. package/src/sampling/index.test.ts +0 -414
  183. package/src/sampling/index.ts +0 -286
  184. package/src/sampling/prompts.ts +0 -194
  185. package/src/sampling/types.ts +0 -60
  186. package/src/schemas/config.ts +0 -39
  187. package/src/security/index.test.ts +0 -441
  188. package/src/security/index.ts +0 -361
  189. package/src/security/security-scenarios.test.ts +0 -468
  190. package/src/server.ts +0 -211
  191. package/src/test-utils/index.ts +0 -6
  192. package/src/test-utils/mock-context.ts +0 -426
  193. package/src/test-utils/mock-playwright-client.ts +0 -422
  194. package/src/tools/index.ts +0 -11
  195. package/src/tools/webtest/crawl.test.ts +0 -834
  196. package/src/tools/webtest/crawl.ts +0 -901
  197. package/src/tools/webtest/discover-features.ts +0 -412
  198. package/src/tools/webtest/discover-flows.ts +0 -408
  199. package/src/tools/webtest/generate-tests.test.ts +0 -532
  200. package/src/tools/webtest/generate-tests.ts +0 -425
  201. package/src/tools/webtest/index.ts +0 -7
  202. package/src/tools/webtest/integration.test.ts +0 -536
  203. package/src/tools/webtest/run-test-case.test.ts +0 -659
  204. package/src/tools/webtest/run-test-case.ts +0 -508
  205. package/src/tools/webtest/schemas.ts +0 -201
  206. package/src/tools/webtest/start-analysis.test.ts +0 -151
  207. package/src/tools/webtest/start-analysis.ts +0 -158
  208. package/src/transports/http.ts +0 -19
  209. package/src/transports/index.ts +0 -30
  210. package/src/transports/stdio.ts +0 -7
  211. package/src/types/capabilities.test.ts +0 -193
  212. package/src/types/capabilities.ts +0 -50
  213. package/src/types/context.ts +0 -21
  214. package/src/types/tool.ts +0 -11
  215. package/src/workspace/index.ts +0 -945
  216. package/src/workspace/markdown.ts +0 -272
  217. package/src/workspace/types.ts +0 -186
  218. package/tests/integration/server.test.ts +0 -89
  219. package/tests/integration/tools.test.ts +0 -99
  220. package/tsconfig.json +0 -20
  221. package/vitest.config.ts +0 -9
  222. package/vitest.integration.config.ts +0 -10
  223. /package/{src → dist}/prompts/templates/sampling/crawl-action.md +0 -0
  224. /package/{src → dist}/prompts/templates/sampling/feature-discovery.md +0 -0
  225. /package/{src → dist}/prompts/templates/sampling/flow-discovery.md +0 -0
  226. /package/{src → dist}/prompts/templates/sampling/page-content-wrapper.md +0 -0
  227. /package/{src → dist}/prompts/templates/sampling/test-evaluation.md +0 -0
  228. /package/{src → dist}/prompts/templates/sampling/test-generation.md +0 -0
  229. /package/dist/tools/{webtest → retest}/crawl.d.ts +0 -0
  230. /package/dist/tools/{webtest → retest}/discover-features.d.ts +0 -0
  231. /package/dist/tools/{webtest → retest}/discover-flows.d.ts +0 -0
  232. /package/dist/tools/{webtest → retest}/generate-tests.d.ts +0 -0
  233. /package/dist/tools/{webtest → retest}/index.d.ts +0 -0
  234. /package/dist/tools/{webtest → retest}/index.js +0 -0
  235. /package/dist/tools/{webtest → retest}/run-test-case.d.ts +0 -0
  236. /package/dist/tools/{webtest → retest}/schemas.d.ts +0 -0
  237. /package/dist/tools/{webtest → retest}/schemas.js +0 -0
  238. /package/dist/tools/{webtest → retest}/start-analysis.d.ts +0 -0
@@ -1,532 +0,0 @@
1
- /**
2
- * Unit Tests for webtest-generate_tests tool (Phase 6.7)
3
- */
4
-
5
- import { describe, it, expect, vi, beforeEach } from "vitest";
6
- import { createGenerateTestsTool } from "./generate-tests.js";
7
- import {
8
- createMockContext,
9
- type MockContext,
10
- } from "../../test-utils/index.js";
11
-
12
- describe("webtest-generate_tests", () => {
13
- let context: MockContext;
14
- let tool: ReturnType<typeof createGenerateTestsTool>;
15
-
16
- beforeEach(() => {
17
- context = createMockContext();
18
- tool = createGenerateTestsTool(() => context as any);
19
-
20
- // Set up workspace with features and featureFlows
21
- context.workspaceManager.readWorkspaceIndex = vi.fn().mockResolvedValue({
22
- url: "https://shop.example.com",
23
- domain: "shop.example.com",
24
- focus: "Test checkout flow",
25
- crawls: [],
26
- features: {
27
- createdAt: new Date().toISOString(),
28
- featuresFilePath: "/test/features.md",
29
- featuresUri: "webtest://test/features.md",
30
- featureCount: 2,
31
- features: [
32
- {
33
- slug: "product-browsing",
34
- name: "Product Browsing",
35
- description: "Browse and view products",
36
- entities: ["Product"],
37
- entryPoints: ["/products"],
38
- },
39
- {
40
- slug: "checkout",
41
- name: "Checkout",
42
- description: "Complete purchase",
43
- entities: ["Cart", "Order"],
44
- entryPoints: ["/cart"],
45
- },
46
- ],
47
- },
48
- featureFlows: [
49
- {
50
- featureSlug: "product-browsing",
51
- createdAt: new Date().toISOString(),
52
- flowsFilePath: "/test/features/product-browsing/flows.md",
53
- flowsUri: "webtest://test/features/product-browsing/flows.md",
54
- flowCount: 1,
55
- },
56
- {
57
- featureSlug: "checkout",
58
- createdAt: new Date().toISOString(),
59
- flowsFilePath: "/test/features/checkout/flows.md",
60
- flowsUri: "webtest://test/features/checkout/flows.md",
61
- flowCount: 1,
62
- },
63
- ],
64
- limits: { maxSteps: 100, maxMinutes: 30, maxPages: 50 },
65
- });
66
-
67
- // Set up resource reading for features and flows
68
- context.resourceManager.readResource = vi.fn().mockImplementation((uri: string) => {
69
- if (uri.includes("features.md") && !uri.includes("features/")) {
70
- return Promise.resolve({
71
- text: "# Features\n\n## Product Browsing\n\nBrowse and view products\n\n## Checkout\n\nComplete purchase",
72
- });
73
- }
74
- if (uri.includes("product-browsing/flows")) {
75
- return Promise.resolve({
76
- text: `---
77
- flows:
78
- - id: browse-products
79
- name: Browse Products
80
- entryPoint: /products
81
- description: User views products
82
- steps:
83
- - Navigate to products
84
- - View list
85
- ---
86
-
87
- # Product Browsing Flows
88
-
89
- ## Browse Products
90
- ...
91
- `,
92
- });
93
- }
94
- if (uri.includes("checkout/flows")) {
95
- return Promise.resolve({
96
- text: `---
97
- flows:
98
- - id: checkout
99
- name: Checkout Flow
100
- entryPoint: /cart
101
- description: User completes purchase
102
- steps:
103
- - Add to cart
104
- - Enter details
105
- - Pay
106
- ---
107
-
108
- # Checkout Flows
109
-
110
- ## Checkout Flow
111
- ...
112
- `,
113
- });
114
- }
115
- return Promise.resolve({ text: "" });
116
- });
117
-
118
- // Set up sampling with mock test generation result
119
- context.samplingClient.createMessage = vi.fn().mockResolvedValue({
120
- success: true,
121
- data: {
122
- tests: [
123
- {
124
- id: "test-browse-001",
125
- name: "Browse products successfully",
126
- category: "happy_path",
127
- purpose: "Verify user can browse product list",
128
- preconditions: ["User is on home page"],
129
- steps: [
130
- {
131
- stepNumber: 1,
132
- action: "Click",
133
- target: "a.products-link",
134
- expected: "Products page loads",
135
- },
136
- {
137
- stepNumber: 2,
138
- action: "Verify",
139
- expected: "Product list is visible",
140
- },
141
- ],
142
- expectedOutcomes: ["Products page is displayed", "Products are listed"],
143
- tags: ["browse", "products"],
144
- },
145
- {
146
- id: "test-checkout-001",
147
- name: "Complete checkout",
148
- category: "happy_path",
149
- purpose: "Verify user can complete checkout",
150
- preconditions: ["User has item in cart"],
151
- steps: [
152
- {
153
- stepNumber: 1,
154
- action: "Navigate to",
155
- target: "/cart",
156
- expected: "Cart page loads",
157
- },
158
- {
159
- stepNumber: 2,
160
- action: "Click",
161
- target: "button.checkout",
162
- expected: "Checkout form appears",
163
- },
164
- ],
165
- expectedOutcomes: ["Order is placed", "Confirmation shown"],
166
- tags: ["checkout", "payment"],
167
- },
168
- ],
169
- coverage: {
170
- flows: ["browse-products", "checkout"],
171
- assertionsCovered: 5,
172
- },
173
- },
174
- });
175
- });
176
-
177
- describe("tool metadata", () => {
178
- it("has correct name", () => {
179
- expect(tool.name).toBe("webtest_generate_tests");
180
- });
181
-
182
- it("has a description", () => {
183
- expect(tool.description).toBeDefined();
184
- expect(tool.description.length).toBeGreaterThan(0);
185
- });
186
-
187
- it("has an input schema", () => {
188
- expect(tool.inputSchema).toBeDefined();
189
- });
190
- });
191
-
192
- describe("handler - validation", () => {
193
- it("returns error for non-existent workspace", async () => {
194
- context.workspaceManager.workspaceExists = vi.fn().mockResolvedValue(false);
195
-
196
- const result = await tool.handler({
197
- analysisId: "00000000-0000-0000-0000-000000000000",
198
- });
199
-
200
- expect(result.isError).toBe(true);
201
- expect(result.content[0].text).toContain("not found");
202
- });
203
-
204
- it("returns error when no features exist", async () => {
205
- context.workspaceManager.readWorkspaceIndex = vi.fn().mockResolvedValue({
206
- url: "https://example.com",
207
- domain: "example.com",
208
- crawls: [],
209
- features: null,
210
- limits: { maxSteps: 100, maxMinutes: 30, maxPages: 50 },
211
- });
212
-
213
- const result = await tool.handler({
214
- analysisId: context.testAnalysisId,
215
- });
216
-
217
- expect(result.isError).toBe(true);
218
- expect(result.content[0].text).toContain("No features");
219
- });
220
-
221
- it("returns error when features data fails to load", async () => {
222
- context.resourceManager.readResource = vi.fn().mockRejectedValue(
223
- new Error("File not found")
224
- );
225
-
226
- const result = await tool.handler({
227
- analysisId: context.testAnalysisId,
228
- });
229
-
230
- expect(result.isError).toBe(true);
231
- expect(result.content[0].text).toContain("Error loading");
232
- });
233
- });
234
-
235
- describe("handler - test generation", () => {
236
- it("calls sampling with test generation prompt", async () => {
237
- await tool.handler({
238
- analysisId: context.testAnalysisId,
239
- });
240
-
241
- expect(context.samplingClient.createMessage).toHaveBeenCalledWith(
242
- expect.objectContaining({
243
- systemPrompt: expect.stringContaining("QA engineer"),
244
- userPrompt: expect.any(String),
245
- schema: expect.any(Object),
246
- })
247
- );
248
- });
249
-
250
- it("saves generated tests to workspace", async () => {
251
- await tool.handler({
252
- analysisId: context.testAnalysisId,
253
- });
254
-
255
- expect(context.workspaceManager.saveTests).toHaveBeenCalledWith(
256
- context.testAnalysisId,
257
- expect.objectContaining({
258
- markdown: expect.any(String),
259
- frontmatter: expect.objectContaining({
260
- tests: expect.any(Array),
261
- }),
262
- })
263
- );
264
- });
265
-
266
- it("returns test count and URIs", async () => {
267
- const result = await tool.handler({
268
- analysisId: context.testAnalysisId,
269
- });
270
-
271
- expect(result.isError).toBeFalsy();
272
- const content = JSON.parse(result.content[0].text!);
273
- expect(content.testsUri).toBeDefined();
274
- expect(content.testCount).toBeGreaterThan(0);
275
- });
276
-
277
- it("returns test summary with categories", async () => {
278
- const result = await tool.handler({
279
- analysisId: context.testAnalysisId,
280
- });
281
-
282
- const content = JSON.parse(result.content[0].text!);
283
- expect(content.categories).toBeDefined();
284
- expect(content.testSummary).toBeInstanceOf(Array);
285
- });
286
-
287
- it("notifies about new resources", async () => {
288
- vi.clearAllMocks();
289
-
290
- await tool.handler({
291
- analysisId: context.testAnalysisId,
292
- });
293
-
294
- expect(context.resourceManager.notifyListChanged).toHaveBeenCalled();
295
- });
296
- });
297
-
298
- describe("handler - strategies", () => {
299
- it("accepts comprehensive strategy", async () => {
300
- const result = await tool.handler({
301
- analysisId: context.testAnalysisId,
302
- testStrategy: "comprehensive",
303
- });
304
-
305
- expect(result.isError).toBeFalsy();
306
- const content = JSON.parse(result.content[0].text!);
307
- expect(content.strategy).toBe("comprehensive");
308
- });
309
-
310
- it("accepts happy_path strategy", async () => {
311
- const result = await tool.handler({
312
- analysisId: context.testAnalysisId,
313
- testStrategy: "happy_path",
314
- });
315
-
316
- expect(result.isError).toBeFalsy();
317
- const content = JSON.parse(result.content[0].text!);
318
- expect(content.strategy).toBe("happy_path");
319
- });
320
-
321
- it("accepts edge_cases strategy", async () => {
322
- const result = await tool.handler({
323
- analysisId: context.testAnalysisId,
324
- testStrategy: "edge_cases",
325
- });
326
-
327
- expect(result.isError).toBeFalsy();
328
- });
329
-
330
- it("accepts critical_paths strategy", async () => {
331
- const result = await tool.handler({
332
- analysisId: context.testAnalysisId,
333
- testStrategy: "critical_paths",
334
- });
335
-
336
- expect(result.isError).toBeFalsy();
337
- });
338
- });
339
-
340
- describe("handler - focus flows", () => {
341
- it("filters flows when focusFlows provided", async () => {
342
- await tool.handler({
343
- analysisId: context.testAnalysisId,
344
- focusFlows: ["checkout"],
345
- });
346
-
347
- expect(context.samplingClient.createMessage).toHaveBeenCalled();
348
- // The prompt should only include the checkout flow
349
- });
350
-
351
- it("uses all flows when focusFlows not provided", async () => {
352
- await tool.handler({
353
- analysisId: context.testAnalysisId,
354
- });
355
-
356
- expect(context.samplingClient.createMessage).toHaveBeenCalled();
357
- });
358
- });
359
-
360
- describe("handler - max tests limit", () => {
361
- it("respects maxTests parameter", async () => {
362
- context.samplingClient.createMessage = vi.fn().mockResolvedValue({
363
- success: true,
364
- data: {
365
- tests: [
366
- { id: "test-1", name: "Test 1", category: "happy_path", purpose: "P", preconditions: [], steps: [], expectedOutcomes: [] },
367
- { id: "test-2", name: "Test 2", category: "happy_path", purpose: "P", preconditions: [], steps: [], expectedOutcomes: [] },
368
- { id: "test-3", name: "Test 3", category: "happy_path", purpose: "P", preconditions: [], steps: [], expectedOutcomes: [] },
369
- ],
370
- coverage: { flows: [], assertionsCovered: 0 },
371
- },
372
- });
373
-
374
- await tool.handler({
375
- analysisId: context.testAnalysisId,
376
- maxTests: 2,
377
- });
378
-
379
- // Verify saved tests are limited
380
- expect(context.workspaceManager.saveTests).toHaveBeenCalledWith(
381
- context.testAnalysisId,
382
- expect.objectContaining({
383
- frontmatter: expect.objectContaining({
384
- tests: expect.any(Array),
385
- }),
386
- })
387
- );
388
-
389
- const saveCall = context.workspaceManager.saveTests.mock.calls[0];
390
- expect(saveCall[1].frontmatter.tests.length).toBeLessThanOrEqual(2);
391
- });
392
-
393
- it("uses default maxTests of 20 by calling sampling", async () => {
394
- await tool.handler({
395
- analysisId: context.testAnalysisId,
396
- });
397
-
398
- // The tool calls sampling with a system prompt mentioning the limit
399
- expect(context.samplingClient.createMessage).toHaveBeenCalled();
400
- });
401
- });
402
-
403
- describe("handler - fallback mode", () => {
404
- beforeEach(() => {
405
- context.samplingClient.hasSampling = vi.fn().mockReturnValue(false);
406
- });
407
-
408
- it("returns prompt when sampling unavailable", async () => {
409
- const result = await tool.handler({
410
- analysisId: context.testAnalysisId,
411
- });
412
-
413
- expect(result.isError).toBeFalsy();
414
- const content = JSON.parse(result.content[0].text!);
415
- expect(content.needsManualInput).toBe(true);
416
- expect(content.prompt).toBeDefined();
417
- });
418
-
419
- it("includes expected schema in fallback response", async () => {
420
- const result = await tool.handler({
421
- analysisId: context.testAnalysisId,
422
- });
423
-
424
- const content = JSON.parse(result.content[0].text!);
425
- expect(content.expectedResponseSchema).toBeDefined();
426
- });
427
- });
428
-
429
- describe("handler - error handling", () => {
430
- it("handles sampling failure", async () => {
431
- context.samplingClient.createMessage = vi.fn().mockResolvedValue({
432
- success: false,
433
- error: "LLM error",
434
- });
435
-
436
- const result = await tool.handler({
437
- analysisId: context.testAnalysisId,
438
- });
439
-
440
- expect(result.isError).toBe(true);
441
- expect(result.content[0].text).toContain("Error");
442
- });
443
-
444
- it("logs errors appropriately", async () => {
445
- context.samplingClient.createMessage = vi.fn().mockRejectedValue(
446
- new Error("Network error")
447
- );
448
-
449
- await tool.handler({
450
- analysisId: context.testAnalysisId,
451
- });
452
-
453
- expect(context.logger.error).toHaveBeenCalled();
454
- });
455
- });
456
-
457
- describe("handler - markdown generation", () => {
458
- it("generates markdown with test cases", async () => {
459
- await tool.handler({
460
- analysisId: context.testAnalysisId,
461
- });
462
-
463
- const saveCall = context.workspaceManager.saveTests.mock.calls[0];
464
- const markdown = saveCall[1].markdown;
465
-
466
- expect(markdown).toContain("# Test Cases");
467
- expect(markdown).toContain("## Overview");
468
- expect(markdown).toContain("## Test Cases");
469
- });
470
-
471
- it("includes test steps in markdown", async () => {
472
- await tool.handler({
473
- analysisId: context.testAnalysisId,
474
- });
475
-
476
- const saveCall = context.workspaceManager.saveTests.mock.calls[0];
477
- const markdown = saveCall[1].markdown;
478
-
479
- expect(markdown).toContain("**Steps**");
480
- });
481
-
482
- it("includes expected outcomes in markdown", async () => {
483
- await tool.handler({
484
- analysisId: context.testAnalysisId,
485
- });
486
-
487
- const saveCall = context.workspaceManager.saveTests.mock.calls[0];
488
- const markdown = saveCall[1].markdown;
489
-
490
- expect(markdown).toContain("**Expected Outcomes**");
491
- });
492
- });
493
-
494
- describe("handler - next steps", () => {
495
- it("returns next steps with first test suggestion", async () => {
496
- const result = await tool.handler({
497
- analysisId: context.testAnalysisId,
498
- });
499
-
500
- const content = JSON.parse(result.content[0].text!);
501
- expect(content.nextSteps).toBeInstanceOf(Array);
502
- expect(content.nextSteps.length).toBeGreaterThan(0);
503
- expect(content.nextSteps.some((s: string) => s.includes("run_tests"))).toBe(true);
504
- });
505
- });
506
-
507
- describe("handler - logging", () => {
508
- it("logs test generation start", async () => {
509
- await tool.handler({
510
- analysisId: context.testAnalysisId,
511
- });
512
-
513
- expect(context.logger.info).toHaveBeenCalledWith(
514
- expect.stringContaining("test generation"),
515
- expect.any(Object)
516
- );
517
- });
518
-
519
- it("logs completion with test count", async () => {
520
- await tool.handler({
521
- analysisId: context.testAnalysisId,
522
- });
523
-
524
- expect(context.logger.info).toHaveBeenCalledWith(
525
- expect.stringContaining("completed"),
526
- expect.objectContaining({
527
- testCount: expect.any(Number),
528
- })
529
- );
530
- });
531
- });
532
- });