retestkit 1.4.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 (327) hide show
  1. package/.claude/commands/openspec/apply.md +23 -0
  2. package/.claude/commands/openspec/archive.md +27 -0
  3. package/.claude/commands/openspec/proposal.md +28 -0
  4. package/.gemini/commands/openspec/apply.toml +21 -0
  5. package/.gemini/commands/openspec/archive.toml +25 -0
  6. package/.gemini/commands/openspec/proposal.toml +26 -0
  7. package/.github/prompts/openspec-apply.prompt.md +22 -0
  8. package/.github/prompts/openspec-archive.prompt.md +26 -0
  9. package/.github/prompts/openspec-proposal.prompt.md +27 -0
  10. package/.github/workflows/release.yml +33 -0
  11. package/.kilocode/workflows/openspec-apply.md +17 -0
  12. package/.kilocode/workflows/openspec-archive.md +21 -0
  13. package/.kilocode/workflows/openspec-proposal.md +22 -0
  14. package/.mcp.json +23 -0
  15. package/.opencode/command/openspec-apply.md +25 -0
  16. package/.opencode/command/openspec-archive.md +28 -0
  17. package/.opencode/command/openspec-proposal.md +30 -0
  18. package/.roo/commands/openspec-apply.md +20 -0
  19. package/.roo/commands/openspec-archive.md +24 -0
  20. package/.roo/commands/openspec-proposal.md +25 -0
  21. package/.vscode/mcp.json +23 -0
  22. package/AGENTS.md +18 -0
  23. package/CLAUDE.md +18 -0
  24. package/LICENSE +65 -0
  25. package/README.md +303 -0
  26. package/dist/config.d.ts +4 -0
  27. package/dist/config.d.ts.map +1 -0
  28. package/dist/config.js +27 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/elicitation/index.d.ts +17 -0
  31. package/dist/elicitation/index.d.ts.map +1 -0
  32. package/dist/elicitation/index.js +118 -0
  33. package/dist/elicitation/index.js.map +1 -0
  34. package/dist/elicitation/types.d.ts +35 -0
  35. package/dist/elicitation/types.d.ts.map +1 -0
  36. package/dist/elicitation/types.js +39 -0
  37. package/dist/elicitation/types.js.map +1 -0
  38. package/dist/index.d.ts +3 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +76 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/lifecycle/index.d.ts +31 -0
  43. package/dist/lifecycle/index.d.ts.map +1 -0
  44. package/dist/lifecycle/index.js +61 -0
  45. package/dist/lifecycle/index.js.map +1 -0
  46. package/dist/logger.d.ts +21 -0
  47. package/dist/logger.d.ts.map +1 -0
  48. package/dist/logger.js +182 -0
  49. package/dist/logger.js.map +1 -0
  50. package/dist/playwright-client/index.d.ts +29 -0
  51. package/dist/playwright-client/index.d.ts.map +1 -0
  52. package/dist/playwright-client/index.js +288 -0
  53. package/dist/playwright-client/index.js.map +1 -0
  54. package/dist/playwright-client/types.d.ts +44 -0
  55. package/dist/playwright-client/types.d.ts.map +1 -0
  56. package/dist/playwright-client/types.js +49 -0
  57. package/dist/playwright-client/types.js.map +1 -0
  58. package/dist/progress/index.d.ts +39 -0
  59. package/dist/progress/index.d.ts.map +1 -0
  60. package/dist/progress/index.js +106 -0
  61. package/dist/progress/index.js.map +1 -0
  62. package/dist/progress/types.d.ts +24 -0
  63. package/dist/progress/types.d.ts.map +1 -0
  64. package/dist/progress/types.js +2 -0
  65. package/dist/progress/types.js.map +1 -0
  66. package/dist/prompts/index.d.ts +19 -0
  67. package/dist/prompts/index.d.ts.map +1 -0
  68. package/dist/prompts/index.js +207 -0
  69. package/dist/prompts/index.js.map +1 -0
  70. package/dist/prompts/loader.d.ts +20 -0
  71. package/dist/prompts/loader.d.ts.map +1 -0
  72. package/dist/prompts/loader.js +47 -0
  73. package/dist/prompts/loader.js.map +1 -0
  74. package/dist/resources/index.d.ts +27 -0
  75. package/dist/resources/index.d.ts.map +1 -0
  76. package/dist/resources/index.js +186 -0
  77. package/dist/resources/index.js.map +1 -0
  78. package/dist/resources/subscriptions.d.ts +10 -0
  79. package/dist/resources/subscriptions.d.ts.map +1 -0
  80. package/dist/resources/subscriptions.js +23 -0
  81. package/dist/resources/subscriptions.js.map +1 -0
  82. package/dist/sampling/index.d.ts +11 -0
  83. package/dist/sampling/index.d.ts.map +1 -0
  84. package/dist/sampling/index.js +201 -0
  85. package/dist/sampling/index.js.map +1 -0
  86. package/dist/sampling/prompts.d.ts +56 -0
  87. package/dist/sampling/prompts.d.ts.map +1 -0
  88. package/dist/sampling/prompts.js +124 -0
  89. package/dist/sampling/prompts.js.map +1 -0
  90. package/dist/sampling/types.d.ts +57 -0
  91. package/dist/sampling/types.d.ts.map +1 -0
  92. package/dist/sampling/types.js +2 -0
  93. package/dist/sampling/types.js.map +1 -0
  94. package/dist/schemas/config.d.ts +40 -0
  95. package/dist/schemas/config.d.ts.map +1 -0
  96. package/dist/schemas/config.js +30 -0
  97. package/dist/schemas/config.js.map +1 -0
  98. package/dist/security/index.d.ts +38 -0
  99. package/dist/security/index.d.ts.map +1 -0
  100. package/dist/security/index.js +281 -0
  101. package/dist/security/index.js.map +1 -0
  102. package/dist/server.d.ts +9 -0
  103. package/dist/server.d.ts.map +1 -0
  104. package/dist/server.js +142 -0
  105. package/dist/server.js.map +1 -0
  106. package/dist/test-utils/index.d.ts +6 -0
  107. package/dist/test-utils/index.d.ts.map +1 -0
  108. package/dist/test-utils/index.js +6 -0
  109. package/dist/test-utils/index.js.map +1 -0
  110. package/dist/test-utils/mock-context.d.ts +64 -0
  111. package/dist/test-utils/mock-context.d.ts.map +1 -0
  112. package/dist/test-utils/mock-context.js +347 -0
  113. package/dist/test-utils/mock-context.js.map +1 -0
  114. package/dist/test-utils/mock-playwright-client.d.ts +62 -0
  115. package/dist/test-utils/mock-playwright-client.d.ts.map +1 -0
  116. package/dist/test-utils/mock-playwright-client.js +315 -0
  117. package/dist/test-utils/mock-playwright-client.js.map +1 -0
  118. package/dist/tools/index.d.ts +4 -0
  119. package/dist/tools/index.d.ts.map +1 -0
  120. package/dist/tools/index.js +8 -0
  121. package/dist/tools/index.js.map +1 -0
  122. package/dist/tools/webtest/crawl.d.ts +46 -0
  123. package/dist/tools/webtest/crawl.d.ts.map +1 -0
  124. package/dist/tools/webtest/crawl.js +678 -0
  125. package/dist/tools/webtest/crawl.js.map +1 -0
  126. package/dist/tools/webtest/discover-features.d.ts +30 -0
  127. package/dist/tools/webtest/discover-features.d.ts.map +1 -0
  128. package/dist/tools/webtest/discover-features.js +343 -0
  129. package/dist/tools/webtest/discover-features.js.map +1 -0
  130. package/dist/tools/webtest/discover-flows.d.ts +29 -0
  131. package/dist/tools/webtest/discover-flows.d.ts.map +1 -0
  132. package/dist/tools/webtest/discover-flows.js +341 -0
  133. package/dist/tools/webtest/discover-flows.js.map +1 -0
  134. package/dist/tools/webtest/generate-tests.d.ts +54 -0
  135. package/dist/tools/webtest/generate-tests.d.ts.map +1 -0
  136. package/dist/tools/webtest/generate-tests.js +364 -0
  137. package/dist/tools/webtest/generate-tests.js.map +1 -0
  138. package/dist/tools/webtest/index.d.ts +8 -0
  139. package/dist/tools/webtest/index.d.ts.map +1 -0
  140. package/dist/tools/webtest/index.js +8 -0
  141. package/dist/tools/webtest/index.js.map +1 -0
  142. package/dist/tools/webtest/run-test-case.d.ts +28 -0
  143. package/dist/tools/webtest/run-test-case.d.ts.map +1 -0
  144. package/dist/tools/webtest/run-test-case.js +420 -0
  145. package/dist/tools/webtest/run-test-case.js.map +1 -0
  146. package/dist/tools/webtest/schemas.d.ts +175 -0
  147. package/dist/tools/webtest/schemas.d.ts.map +1 -0
  148. package/dist/tools/webtest/schemas.js +156 -0
  149. package/dist/tools/webtest/schemas.js.map +1 -0
  150. package/dist/tools/webtest/start-analysis.d.ts +16 -0
  151. package/dist/tools/webtest/start-analysis.d.ts.map +1 -0
  152. package/dist/tools/webtest/start-analysis.js +137 -0
  153. package/dist/tools/webtest/start-analysis.js.map +1 -0
  154. package/dist/transports/http.d.ts +8 -0
  155. package/dist/transports/http.d.ts.map +1 -0
  156. package/dist/transports/http.js +9 -0
  157. package/dist/transports/http.js.map +1 -0
  158. package/dist/transports/index.d.ts +14 -0
  159. package/dist/transports/index.d.ts.map +1 -0
  160. package/dist/transports/index.js +20 -0
  161. package/dist/transports/index.js.map +1 -0
  162. package/dist/transports/stdio.d.ts +4 -0
  163. package/dist/transports/stdio.d.ts.map +1 -0
  164. package/dist/transports/stdio.js +6 -0
  165. package/dist/transports/stdio.js.map +1 -0
  166. package/dist/types/capabilities.d.ts +18 -0
  167. package/dist/types/capabilities.d.ts.map +1 -0
  168. package/dist/types/capabilities.js +35 -0
  169. package/dist/types/capabilities.js.map +1 -0
  170. package/dist/types/context.d.ts +20 -0
  171. package/dist/types/context.d.ts.map +1 -0
  172. package/dist/types/context.js +2 -0
  173. package/dist/types/context.js.map +1 -0
  174. package/dist/types/tool.d.ts +10 -0
  175. package/dist/types/tool.d.ts.map +1 -0
  176. package/dist/types/tool.js +2 -0
  177. package/dist/types/tool.js.map +1 -0
  178. package/dist/workspace/index.d.ts +99 -0
  179. package/dist/workspace/index.d.ts.map +1 -0
  180. package/dist/workspace/index.js +648 -0
  181. package/dist/workspace/index.js.map +1 -0
  182. package/dist/workspace/markdown.d.ts +50 -0
  183. package/dist/workspace/markdown.d.ts.map +1 -0
  184. package/dist/workspace/markdown.js +210 -0
  185. package/dist/workspace/markdown.js.map +1 -0
  186. package/dist/workspace/types.d.ts +173 -0
  187. package/dist/workspace/types.d.ts.map +1 -0
  188. package/dist/workspace/types.js +2 -0
  189. package/dist/workspace/types.js.map +1 -0
  190. package/openspec/AGENTS.md +456 -0
  191. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/proposal.md +33 -0
  192. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-resources/spec.md +27 -0
  193. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/specs/webtest-tools/spec.md +304 -0
  194. package/openspec/changes/archive/2025-12-18-add-hybrid-artifact-paths/tasks.md +43 -0
  195. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/design.md +209 -0
  196. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/proposal.md +41 -0
  197. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/specs/mcp-server-core/spec.md +183 -0
  198. package/openspec/changes/archive/2025-12-18-add-mcp-server-foundation/tasks.md +112 -0
  199. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/design.md +333 -0
  200. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/proposal.md +66 -0
  201. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/mcp-server-core/spec.md +129 -0
  202. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-lifecycle/spec.md +138 -0
  203. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-logging/spec.md +211 -0
  204. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-prompts/spec.md +157 -0
  205. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-resources/spec.md +213 -0
  206. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-sampling/spec.md +257 -0
  207. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/specs/webtest-tools/spec.md +501 -0
  208. package/openspec/changes/archive/2025-12-18-add-webtest-orchestrator/tasks.md +264 -0
  209. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/proposal.md +24 -0
  210. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/specs/webtest-tools/spec.md +80 -0
  211. package/openspec/changes/archive/2025-12-18-allow-analysis-of-incomplete-crawls/tasks.md +8 -0
  212. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/design.md +90 -0
  213. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/proposal.md +28 -0
  214. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/specs/webtest-sampling/spec.md +90 -0
  215. package/openspec/changes/archive/2025-12-18-fix-crawl-loop-stability/tasks.md +33 -0
  216. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/design.md +558 -0
  217. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/proposal.md +119 -0
  218. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-resources/spec.md +109 -0
  219. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/specs/webtest-tools/spec.md +121 -0
  220. package/openspec/changes/archive/2025-12-18-use-markdown-artifacts/tasks.md +133 -0
  221. package/openspec/changes/extract-prompts-to-markdown/design.md +86 -0
  222. package/openspec/changes/extract-prompts-to-markdown/proposal.md +50 -0
  223. package/openspec/changes/extract-prompts-to-markdown/specs/webtest-prompts/spec.md +74 -0
  224. package/openspec/changes/extract-prompts-to-markdown/tasks.md +40 -0
  225. package/openspec/changes/refactor-webtest-naming/design.md +95 -0
  226. package/openspec/changes/refactor-webtest-naming/proposal.md +66 -0
  227. package/openspec/changes/refactor-webtest-naming/specs/webtest-prompts/spec.md +79 -0
  228. package/openspec/changes/refactor-webtest-naming/specs/webtest-resources/spec.md +80 -0
  229. package/openspec/changes/refactor-webtest-naming/specs/webtest-sampling/spec.md +122 -0
  230. package/openspec/changes/refactor-webtest-naming/specs/webtest-tools/spec.md +113 -0
  231. package/openspec/changes/refactor-webtest-naming/tasks.md +119 -0
  232. package/openspec/changes/rename-package-to-retest/proposal.md +52 -0
  233. package/openspec/changes/rename-package-to-retest/specs/mcp-server-core/spec.md +53 -0
  234. package/openspec/changes/rename-package-to-retest/specs/retest-lifecycle/spec.md +68 -0
  235. package/openspec/changes/rename-package-to-retest/specs/retest-logging/spec.md +35 -0
  236. package/openspec/changes/rename-package-to-retest/specs/retest-prompts/spec.md +159 -0
  237. package/openspec/changes/rename-package-to-retest/specs/retest-resources/spec.md +251 -0
  238. package/openspec/changes/rename-package-to-retest/specs/retest-sampling/spec.md +99 -0
  239. package/openspec/changes/rename-package-to-retest/specs/retest-tools/spec.md +295 -0
  240. package/openspec/changes/rename-package-to-retest/tasks.md +71 -0
  241. package/openspec/project.md +31 -0
  242. package/openspec/specs/mcp-server-core/spec.md +178 -0
  243. package/openspec/specs/webtest-lifecycle/spec.md +136 -0
  244. package/openspec/specs/webtest-logging/spec.md +209 -0
  245. package/openspec/specs/webtest-prompts/spec.md +155 -0
  246. package/openspec/specs/webtest-resources/spec.md +248 -0
  247. package/openspec/specs/webtest-sampling/spec.md +344 -0
  248. package/openspec/specs/webtest-tools/spec.md +282 -0
  249. package/package.json +54 -0
  250. package/release.config.js +9 -0
  251. package/src/config.test.ts +96 -0
  252. package/src/config.ts +32 -0
  253. package/src/elicitation/index.test.ts +399 -0
  254. package/src/elicitation/index.ts +171 -0
  255. package/src/elicitation/types.ts +68 -0
  256. package/src/index.ts +83 -0
  257. package/src/lifecycle/index.test.ts +260 -0
  258. package/src/lifecycle/index.ts +101 -0
  259. package/src/logger.redaction.test.ts +322 -0
  260. package/src/logger.test.ts +123 -0
  261. package/src/logger.ts +229 -0
  262. package/src/playwright-client/index.ts +392 -0
  263. package/src/playwright-client/types.ts +99 -0
  264. package/src/progress/index.test.ts +327 -0
  265. package/src/progress/index.ts +170 -0
  266. package/src/progress/types.ts +25 -0
  267. package/src/prompts/index.test.ts +451 -0
  268. package/src/prompts/index.ts +246 -0
  269. package/src/prompts/loader.test.ts +100 -0
  270. package/src/prompts/loader.ts +59 -0
  271. package/src/prompts/templates/mcp/webtest-crawl.md +7 -0
  272. package/src/prompts/templates/mcp/webtest-discover-flows.md +11 -0
  273. package/src/prompts/templates/mcp/webtest-discover.md +12 -0
  274. package/src/prompts/templates/mcp/webtest-full-workflow.md +12 -0
  275. package/src/prompts/templates/mcp/webtest-generate-tests.md +11 -0
  276. package/src/prompts/templates/mcp/webtest-run-test.md +11 -0
  277. package/src/prompts/templates/mcp/webtest-start.md +8 -0
  278. package/src/prompts/templates/sampling/crawl-action.md +35 -0
  279. package/src/prompts/templates/sampling/feature-discovery.md +27 -0
  280. package/src/prompts/templates/sampling/flow-discovery.md +29 -0
  281. package/src/prompts/templates/sampling/page-content-wrapper.md +5 -0
  282. package/src/prompts/templates/sampling/system-prefix.md +12 -0
  283. package/src/prompts/templates/sampling/test-evaluation.md +17 -0
  284. package/src/prompts/templates/sampling/test-generation.md +31 -0
  285. package/src/resources/index.ts +250 -0
  286. package/src/resources/subscriptions.ts +37 -0
  287. package/src/sampling/index.test.ts +414 -0
  288. package/src/sampling/index.ts +286 -0
  289. package/src/sampling/prompts.ts +194 -0
  290. package/src/sampling/types.ts +60 -0
  291. package/src/schemas/config.ts +39 -0
  292. package/src/security/index.test.ts +441 -0
  293. package/src/security/index.ts +361 -0
  294. package/src/security/security-scenarios.test.ts +468 -0
  295. package/src/server.ts +211 -0
  296. package/src/test-utils/index.ts +6 -0
  297. package/src/test-utils/mock-context.ts +426 -0
  298. package/src/test-utils/mock-playwright-client.ts +422 -0
  299. package/src/tools/index.ts +11 -0
  300. package/src/tools/webtest/crawl.test.ts +834 -0
  301. package/src/tools/webtest/crawl.ts +901 -0
  302. package/src/tools/webtest/discover-features.ts +412 -0
  303. package/src/tools/webtest/discover-flows.ts +408 -0
  304. package/src/tools/webtest/generate-tests.test.ts +532 -0
  305. package/src/tools/webtest/generate-tests.ts +425 -0
  306. package/src/tools/webtest/index.ts +7 -0
  307. package/src/tools/webtest/integration.test.ts +536 -0
  308. package/src/tools/webtest/run-test-case.test.ts +659 -0
  309. package/src/tools/webtest/run-test-case.ts +508 -0
  310. package/src/tools/webtest/schemas.ts +201 -0
  311. package/src/tools/webtest/start-analysis.test.ts +151 -0
  312. package/src/tools/webtest/start-analysis.ts +158 -0
  313. package/src/transports/http.ts +19 -0
  314. package/src/transports/index.ts +30 -0
  315. package/src/transports/stdio.ts +7 -0
  316. package/src/types/capabilities.test.ts +193 -0
  317. package/src/types/capabilities.ts +50 -0
  318. package/src/types/context.ts +21 -0
  319. package/src/types/tool.ts +11 -0
  320. package/src/workspace/index.ts +945 -0
  321. package/src/workspace/markdown.ts +272 -0
  322. package/src/workspace/types.ts +186 -0
  323. package/tests/integration/server.test.ts +89 -0
  324. package/tests/integration/tools.test.ts +99 -0
  325. package/tsconfig.json +20 -0
  326. package/vitest.config.ts +9 -0
  327. package/vitest.integration.config.ts +10 -0
@@ -0,0 +1,422 @@
1
+ /**
2
+ * Mock Playwright MCP Client for testing
3
+ *
4
+ * Provides a controllable mock implementation of PlaywrightClient
5
+ * for testing crawl, test execution, and other Playwright-dependent flows.
6
+ */
7
+
8
+ import { vi } from "vitest";
9
+ import type {
10
+ PlaywrightClient,
11
+ PlaywrightSnapshot,
12
+ PlaywrightScreenshot,
13
+ } from "../playwright-client/index.js";
14
+ import type { PlaywrightToolMapping, PlaywrightToolCallResult } from "../playwright-client/types.js";
15
+
16
+ export interface MockPage {
17
+ url: string;
18
+ title: string;
19
+ html: string;
20
+ links?: Array<{ selector: string; href: string; text: string }>;
21
+ forms?: Array<{ selector: string; action: string; inputs: string[] }>;
22
+ buttons?: Array<{ selector: string; text: string }>;
23
+ }
24
+
25
+ export interface MockPlaywrightClientOptions {
26
+ /** Starting pages - keyed by URL */
27
+ pages: Record<string, MockPage>;
28
+ /** Custom tool call handler for testing specific behaviors */
29
+ onToolCall?: (
30
+ tool: keyof PlaywrightToolMapping,
31
+ args: Record<string, unknown>
32
+ ) => PlaywrightToolCallResult | undefined;
33
+ /** Simulated errors by tool name */
34
+ errors?: Partial<Record<keyof PlaywrightToolMapping, string>>;
35
+ /** Delay in ms to simulate network latency */
36
+ latencyMs?: number;
37
+ }
38
+
39
+ export interface MockPlaywrightClient extends PlaywrightClient {
40
+ /** Get the current page state */
41
+ getCurrentPage(): MockPage | undefined;
42
+ /** Set custom pages for testing */
43
+ setPages(pages: Record<string, MockPage>): void;
44
+ /** Get action history */
45
+ getActionHistory(): Array<{ tool: string; args: Record<string, unknown> }>;
46
+ /** Clear action history */
47
+ clearActionHistory(): void;
48
+ /** Set error for specific tool */
49
+ setError(tool: keyof PlaywrightToolMapping, message: string | null): void;
50
+ }
51
+
52
+ export function createMockPlaywrightClient(
53
+ options: MockPlaywrightClientOptions
54
+ ): MockPlaywrightClient {
55
+ let pages = { ...options.pages };
56
+ let currentUrl: string | undefined;
57
+ let connected = false;
58
+ const actionHistory: Array<{ tool: string; args: Record<string, unknown> }> = [];
59
+ const errors: Partial<Record<keyof PlaywrightToolMapping, string>> = {
60
+ ...options.errors,
61
+ };
62
+
63
+ const toolMapping: PlaywrightToolMapping = {
64
+ snapshot: "browser_snapshot",
65
+ screenshot: "browser_take_screenshot",
66
+ click: "browser_click",
67
+ type: "browser_type",
68
+ navigate: "browser_navigate",
69
+ fill: "browser_type", // Microsoft Playwright MCP uses browser_type for fill
70
+ hover: "browser_hover",
71
+ select: "browser_select_option",
72
+ evaluate: "browser_evaluate",
73
+ press: "browser_press_key",
74
+ scroll: "browser_scroll",
75
+ wait: "browser_wait",
76
+ };
77
+
78
+ function getCurrentPage(): MockPage | undefined {
79
+ if (!currentUrl) return undefined;
80
+ return pages[currentUrl];
81
+ }
82
+
83
+ async function delay(): Promise<void> {
84
+ if (options.latencyMs) {
85
+ await new Promise((resolve) => setTimeout(resolve, options.latencyMs));
86
+ }
87
+ }
88
+
89
+ function recordAction(tool: string, args: Record<string, unknown>): void {
90
+ actionHistory.push({ tool, args });
91
+ }
92
+
93
+ const client: MockPlaywrightClient = {
94
+ connect: vi.fn().mockImplementation(async () => {
95
+ await delay();
96
+ connected = true;
97
+ }),
98
+
99
+ disconnect: vi.fn().mockImplementation(async () => {
100
+ await delay();
101
+ connected = false;
102
+ currentUrl = undefined;
103
+ }),
104
+
105
+ isConnected: vi.fn().mockImplementation(() => {
106
+ return connected;
107
+ }),
108
+
109
+ getToolMapping: vi.fn().mockImplementation(() => {
110
+ return connected ? toolMapping : null;
111
+ }),
112
+
113
+ callTool: vi.fn().mockImplementation(async (
114
+ canonicalName: keyof PlaywrightToolMapping,
115
+ args: Record<string, unknown>
116
+ ): Promise<PlaywrightToolCallResult> => {
117
+ await delay();
118
+ recordAction(canonicalName, args);
119
+
120
+ // Check for configured errors
121
+ if (errors[canonicalName]) {
122
+ return {
123
+ content: [{ type: "text", text: `Error: ${errors[canonicalName]}` }],
124
+ isError: true,
125
+ };
126
+ }
127
+
128
+ // Check for custom handler
129
+ if (options.onToolCall) {
130
+ const customResult = options.onToolCall(canonicalName, args);
131
+ if (customResult) return customResult;
132
+ }
133
+
134
+ // Default implementations
135
+ const actualName = toolMapping[canonicalName];
136
+ return {
137
+ content: [{ type: "text", text: `${actualName} executed successfully` }],
138
+ };
139
+ }),
140
+
141
+ snapshot: vi.fn().mockImplementation(async (): Promise<PlaywrightSnapshot> => {
142
+ await delay();
143
+ recordAction("snapshot", {});
144
+
145
+ if (errors.snapshot) {
146
+ throw new Error(errors.snapshot);
147
+ }
148
+
149
+ const page = getCurrentPage();
150
+ if (!page) {
151
+ return {
152
+ url: currentUrl || "",
153
+ title: "",
154
+ content: "No page loaded",
155
+ };
156
+ }
157
+
158
+ return {
159
+ url: page.url,
160
+ title: page.title,
161
+ content: JSON.stringify({
162
+ url: page.url,
163
+ title: page.title,
164
+ links: page.links,
165
+ forms: page.forms,
166
+ buttons: page.buttons,
167
+ }),
168
+ };
169
+ }),
170
+
171
+ screenshot: vi.fn().mockImplementation(async (): Promise<PlaywrightScreenshot> => {
172
+ await delay();
173
+ recordAction("screenshot", {});
174
+
175
+ if (errors.screenshot) {
176
+ throw new Error(errors.screenshot);
177
+ }
178
+
179
+ // Return a minimal valid PNG (1x1 transparent pixel)
180
+ const minimalPng =
181
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
182
+
183
+ return {
184
+ data: minimalPng,
185
+ mimeType: "image/png",
186
+ };
187
+ }),
188
+
189
+ navigate: vi.fn().mockImplementation(async (url: string): Promise<void> => {
190
+ await delay();
191
+ recordAction("navigate", { url });
192
+
193
+ if (errors.navigate) {
194
+ throw new Error(errors.navigate);
195
+ }
196
+
197
+ currentUrl = url;
198
+
199
+ // Auto-create a default page if not defined
200
+ if (!pages[url]) {
201
+ pages[url] = {
202
+ url,
203
+ title: `Page: ${url}`,
204
+ html: `<html><head><title>Page: ${url}</title></head><body></body></html>`,
205
+ };
206
+ }
207
+ }),
208
+
209
+ click: vi.fn().mockImplementation(async (element: string, ref: string): Promise<void> => {
210
+ await delay();
211
+ recordAction("click", { element, ref });
212
+
213
+ if (errors.click) {
214
+ throw new Error(errors.click);
215
+ }
216
+
217
+ // Check if clicking a link triggers navigation (use ref as selector for mock lookup)
218
+ const page = getCurrentPage();
219
+ if (page?.links) {
220
+ const link = page.links.find((l) => l.selector === ref || l.text === element);
221
+ if (link?.href) {
222
+ currentUrl = link.href;
223
+ }
224
+ }
225
+ }),
226
+
227
+ type: vi.fn().mockImplementation(async (
228
+ element: string,
229
+ ref: string,
230
+ text: string,
231
+ options?: { submit?: boolean; slowly?: boolean }
232
+ ): Promise<void> => {
233
+ await delay();
234
+ recordAction("type", { element, ref, text, submit: options?.submit, slowly: options?.slowly });
235
+
236
+ if (errors.type) {
237
+ throw new Error(errors.type);
238
+ }
239
+ }),
240
+
241
+ fill: vi.fn().mockImplementation(async (element: string, ref: string, value: string): Promise<void> => {
242
+ await delay();
243
+ recordAction("fill", { element, ref, value });
244
+
245
+ if (errors.fill) {
246
+ throw new Error(errors.fill);
247
+ }
248
+ }),
249
+
250
+ hover: vi.fn().mockImplementation(async (element: string, ref: string): Promise<void> => {
251
+ await delay();
252
+ recordAction("hover", { element, ref });
253
+
254
+ if (errors.hover) {
255
+ throw new Error(errors.hover);
256
+ }
257
+ }),
258
+
259
+ select: vi.fn().mockImplementation(async (element: string, ref: string, values: string[]): Promise<void> => {
260
+ await delay();
261
+ recordAction("select", { element, ref, values });
262
+
263
+ if (errors.select) {
264
+ throw new Error(errors.select);
265
+ }
266
+ }),
267
+
268
+ evaluate: vi.fn().mockImplementation(async (fn: string, element?: string, ref?: string): Promise<unknown> => {
269
+ await delay();
270
+ const args: Record<string, unknown> = { function: fn };
271
+ if (element) args.element = element;
272
+ if (ref) args.ref = ref;
273
+ recordAction("evaluate", args);
274
+
275
+ if (errors.evaluate) {
276
+ throw new Error(errors.evaluate);
277
+ }
278
+
279
+ // Return the current page HTML as a default evaluation result
280
+ const page = getCurrentPage();
281
+ return page?.html || "";
282
+ }),
283
+
284
+ press: vi.fn().mockImplementation(async (key: string): Promise<void> => {
285
+ await delay();
286
+ recordAction("press", { key });
287
+
288
+ if (errors.press) {
289
+ throw new Error(errors.press);
290
+ }
291
+ }),
292
+
293
+ scroll: vi.fn().mockImplementation(async (x: number, y: number): Promise<void> => {
294
+ await delay();
295
+ recordAction("scroll", { x, y });
296
+
297
+ if (errors.scroll) {
298
+ throw new Error(errors.scroll);
299
+ }
300
+ }),
301
+
302
+ wait: vi.fn().mockImplementation(async (ms: number): Promise<void> => {
303
+ await delay();
304
+ recordAction("wait", { ms });
305
+
306
+ if (errors.wait) {
307
+ throw new Error(errors.wait);
308
+ }
309
+
310
+ // Actually wait for the specified time
311
+ await new Promise((resolve) => setTimeout(resolve, ms));
312
+ }),
313
+
314
+ // Test helpers
315
+ getCurrentPage,
316
+
317
+ setPages(newPages: Record<string, MockPage>): void {
318
+ pages = { ...newPages };
319
+ },
320
+
321
+ getActionHistory(): Array<{ tool: string; args: Record<string, unknown> }> {
322
+ return [...actionHistory];
323
+ },
324
+
325
+ clearActionHistory(): void {
326
+ actionHistory.length = 0;
327
+ },
328
+
329
+ setError(tool: keyof PlaywrightToolMapping, message: string | null): void {
330
+ if (message === null) {
331
+ delete errors[tool];
332
+ } else {
333
+ errors[tool] = message;
334
+ }
335
+ },
336
+ };
337
+
338
+ return client;
339
+ }
340
+
341
+ /**
342
+ * Create a simple mock page for testing
343
+ */
344
+ export function createMockPage(
345
+ url: string,
346
+ options: Partial<MockPage> = {}
347
+ ): MockPage {
348
+ const hostname = new URL(url).hostname;
349
+ return {
350
+ url,
351
+ title: options.title || `Page - ${hostname}`,
352
+ html:
353
+ options.html ||
354
+ `<html><head><title>${options.title || hostname}</title></head><body><h1>Welcome</h1></body></html>`,
355
+ links: options.links || [],
356
+ forms: options.forms || [],
357
+ buttons: options.buttons || [],
358
+ };
359
+ }
360
+
361
+ /**
362
+ * Create a typical e-commerce site mock for testing
363
+ */
364
+ export function createEcommerceMock(): Record<string, MockPage> {
365
+ const baseUrl = "https://shop.example.com";
366
+
367
+ return {
368
+ [baseUrl]: createMockPage(baseUrl, {
369
+ title: "Shop - Home",
370
+ links: [
371
+ { selector: 'a[href="/products"]', href: `${baseUrl}/products`, text: "Products" },
372
+ { selector: 'a[href="/cart"]', href: `${baseUrl}/cart`, text: "Cart" },
373
+ { selector: 'a[href="/login"]', href: `${baseUrl}/login`, text: "Login" },
374
+ ],
375
+ buttons: [{ selector: "button.search", text: "Search" }],
376
+ }),
377
+ [`${baseUrl}/products`]: createMockPage(`${baseUrl}/products`, {
378
+ title: "Shop - Products",
379
+ links: [
380
+ { selector: 'a[href="/"]', href: baseUrl, text: "Home" },
381
+ { selector: 'a[href="/product/1"]', href: `${baseUrl}/product/1`, text: "Product 1" },
382
+ { selector: 'a[href="/product/2"]', href: `${baseUrl}/product/2`, text: "Product 2" },
383
+ ],
384
+ }),
385
+ [`${baseUrl}/product/1`]: createMockPage(`${baseUrl}/product/1`, {
386
+ title: "Product 1 - Shop",
387
+ buttons: [
388
+ { selector: "button.add-to-cart", text: "Add to Cart" },
389
+ { selector: "button.buy-now", text: "Buy Now" },
390
+ ],
391
+ }),
392
+ [`${baseUrl}/cart`]: createMockPage(`${baseUrl}/cart`, {
393
+ title: "Shopping Cart - Shop",
394
+ buttons: [
395
+ { selector: "button.checkout", text: "Checkout" },
396
+ { selector: "button.continue-shopping", text: "Continue Shopping" },
397
+ ],
398
+ }),
399
+ [`${baseUrl}/login`]: createMockPage(`${baseUrl}/login`, {
400
+ title: "Login - Shop",
401
+ forms: [
402
+ {
403
+ selector: "form#login",
404
+ action: "/auth/login",
405
+ inputs: ["email", "password"],
406
+ },
407
+ ],
408
+ buttons: [{ selector: "button.submit", text: "Sign In" }],
409
+ }),
410
+ [`${baseUrl}/checkout`]: createMockPage(`${baseUrl}/checkout`, {
411
+ title: "Checkout - Shop",
412
+ forms: [
413
+ {
414
+ selector: "form#checkout",
415
+ action: "/process-order",
416
+ inputs: ["name", "address", "card"],
417
+ },
418
+ ],
419
+ buttons: [{ selector: "button.place-order", text: "Place Order" }],
420
+ }),
421
+ };
422
+ }
@@ -0,0 +1,11 @@
1
+ // Tools are now registered directly in server.ts via the webtest tools
2
+ // This file is kept for backwards compatibility but tools array is empty
3
+ // The hello tool has been removed as part of the webtest orchestrator implementation
4
+
5
+ import type { McpTool } from "../types/tool.js";
6
+
7
+ // Webtest tools are exported from the webtest module
8
+ export * from "./webtest/index.js";
9
+
10
+ // Legacy tools array - empty since webtest tools are registered differently
11
+ export const tools: McpTool[] = [];