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,282 @@
1
+ # webtest-tools Specification
2
+
3
+ ## Purpose
4
+ TBD - created by archiving change add-webtest-orchestrator. Update Purpose after archive.
5
+ ## Requirements
6
+ ### Requirement: webtest_init Tool
7
+
8
+ The system SHALL provide a `webtest_init` tool that initializes an analysis workspace for a target URL and focus, storing metadata in markdown format.
9
+
10
+ #### Scenario: Start analysis with valid URL
11
+
12
+ - **GIVEN** the tool is called with a valid URL and focus
13
+ - **WHEN** execution completes
14
+ - **THEN** it SHALL generate a unique `analysisId`
15
+ - **AND** create workspace directories
16
+ - **AND** write initial `index.md` metadata with YAML frontmatter
17
+ - **AND** return `{ analysisId, workspaceRootPath, workspaceRootUri, statusUri }` where statusUri points to `index.md`
18
+
19
+ ### Requirement: webtest_crawl_app Tool
20
+
21
+ The system SHALL provide a `webtest_crawl_app` tool that dynamically explores a web application, storing all crawl artifacts in markdown format.
22
+
23
+ #### Scenario: Crawl captures artifacts at each checkpoint
24
+
25
+ - **GIVEN** a crawl iteration completes an action
26
+ - **WHEN** state is captured
27
+ - **THEN** it SHALL call Playwright MCP `browser_snapshot` for accessibility tree
28
+ - **AND** call `browser_take_screenshot` for visual evidence
29
+ - **AND** optionally extract HTML DOM
30
+ - **AND** store snapshot as `snapshot.md` with formatted accessibility tree and YAML frontmatter
31
+ - **AND** store screenshot as PNG
32
+ - **AND** store DOM as HTML
33
+
34
+ #### Scenario: Crawl outputs complete results
35
+
36
+ - **GIVEN** crawl has finalized
37
+ - **WHEN** output is returned
38
+ - **THEN** it SHALL include `crawlId`, `crawlIndexFilePath`, `crawlIndexUri` (pointing to `index.md`), `pages[]`, `summaryUri`
39
+
40
+ ### Requirement: webtest_analyze_app Tool
41
+
42
+ The system SHALL provide a `webtest_analyze_app` tool that reverse-engineers application structure from crawl data, outputting all results in markdown format.
43
+
44
+ #### Scenario: Analyze app writes markdown report
45
+
46
+ - **GIVEN** analysis is complete
47
+ - **WHEN** output is generated
48
+ - **THEN** it SHALL write `app-analysis.md` resource to workspace
49
+
50
+ #### Scenario: Analyze app writes flows
51
+
52
+ - **GIVEN** analysis is complete
53
+ - **WHEN** output is generated
54
+ - **THEN** it SHALL write `flows.md` resource to workspace as markdown with YAML frontmatter containing structured flow definitions
55
+
56
+ #### Scenario: Analyze app outputs URIs
57
+
58
+ - **GIVEN** analysis is complete
59
+ - **WHEN** tool returns
60
+ - **THEN** it SHALL include `appAnalysisFilePath`, `appAnalysisUri`, `flowsFilePath`, `flowsUri` all pointing to `.md` files
61
+
62
+ ### Requirement: webtest_generate_tests Tool
63
+
64
+ The system SHALL provide a `webtest_generate_tests` tool that produces test cases from application analysis in a single markdown format.
65
+
66
+ #### Scenario: Generate tests outputs structured format
67
+
68
+ - **GIVEN** test generation completes
69
+ - **WHEN** results are written
70
+ - **THEN** it SHALL produce `tests.md` with human-readable format AND YAML frontmatter containing structured test definitions
71
+ - **AND** there SHALL NOT be a separate `tests.json` file
72
+
73
+ #### Scenario: Generate tests outputs URIs
74
+
75
+ - **GIVEN** generation is complete
76
+ - **WHEN** tool returns
77
+ - **THEN** it SHALL include `testsFilePath` and `testsUri` pointing to `tests.md`
78
+
79
+ ### Requirement: webtest_run_tests Tool
80
+
81
+ The system SHALL provide a `webtest_run_tests` tool that executes a test case with evidence capture, storing all results in markdown format.
82
+
83
+ #### Scenario: Run test case captures evidence
84
+
85
+ - **GIVEN** a step is executed
86
+ - **WHEN** evidence is captured
87
+ - **THEN** it SHALL take screenshot after action (stored as PNG)
88
+ - **AND** capture accessibility snapshot (stored as `snapshot.md` with formatted tree and YAML frontmatter)
89
+ - **AND** store with step identifier
90
+
91
+ #### Scenario: Run test case outputs report
92
+
93
+ - **GIVEN** test execution completes
94
+ - **WHEN** output is generated
95
+ - **THEN** it SHALL write `report.md` with pass/fail summary, step details, evidence links, and YAML frontmatter containing structured run data
96
+ - **AND** there SHALL NOT be a separate `index.json` or `artifacts.json` file
97
+
98
+ #### Scenario: Run test case returns URIs
99
+
100
+ - **GIVEN** execution is complete
101
+ - **WHEN** tool returns
102
+ - **THEN** it SHALL include `testRunId`, `reportFilePath`, `reportUri` pointing to `report.md`
103
+
104
+ ### Requirement: Playwright MCP Integration
105
+
106
+ The system SHALL orchestrate an external Playwright MCP server for browser automation with dynamic tool discovery.
107
+
108
+ #### Scenario: Playwright MCP is spawned on first use
109
+
110
+ - **GIVEN** a webtest tool needs browser access
111
+ - **WHEN** Playwright client is accessed
112
+ - **THEN** it SHALL spawn Playwright MCP server as subprocess if not running
113
+ - **AND** connect via stdio transport
114
+
115
+ #### Scenario: Playwright MCP tools are discovered dynamically
116
+
117
+ - **GIVEN** Playwright MCP is connected
118
+ - **WHEN** connection is established
119
+ - **THEN** it SHALL call `tools/list` to discover available tools
120
+ - **AND** build a capability adapter mapping canonical operations to actual tool names
121
+ - **AND** cache the mapping for the session lifetime
122
+
123
+ #### Scenario: Capability adapter maps canonical operations
124
+
125
+ - **GIVEN** Playwright MCP tools have been discovered
126
+ - **WHEN** the adapter is queried for operation "snapshot"
127
+ - **THEN** it SHALL return the matching tool (e.g., `browser_snapshot` or `playwright_snapshot`)
128
+ - **AND** if multiple matches exist, prefer the most specific
129
+
130
+ #### Scenario: Missing required capability logs warning
131
+
132
+ - **GIVEN** Playwright MCP tools have been discovered
133
+ - **WHEN** a required capability (snapshot, screenshot, click, type, navigate) is missing
134
+ - **THEN** it SHALL log a warning with the missing capability
135
+ - **AND** tools requiring that capability SHALL return an error when invoked
136
+
137
+ #### Scenario: Playwright actions are executed via adapter
138
+
139
+ - **GIVEN** a crawl action specifies `{ tool: "click", args: { selector: "button" } }`
140
+ - **WHEN** action is executed
141
+ - **THEN** it SHALL resolve "click" through the capability adapter
142
+ - **AND** call the resolved Playwright MCP tool with appropriate arguments
143
+ - **AND** return the result
144
+
145
+ #### Scenario: Playwright MCP version differences are handled
146
+
147
+ - **GIVEN** different Playwright MCP implementations may have different tool names
148
+ - **WHEN** the adapter maps tools
149
+ - **THEN** it SHALL check for common variants:
150
+ - `browser_*` prefix (Microsoft implementation)
151
+ - `playwright_*` prefix (alternative implementations)
152
+ - unprefixed names
153
+ - **AND** log the detected implementation variant
154
+
155
+ #### Scenario: Playwright MCP is terminated on shutdown
156
+
157
+ - **GIVEN** the server receives shutdown signal
158
+ - **WHEN** shutdown begins
159
+ - **THEN** it SHALL terminate Playwright MCP subprocess
160
+ - **AND** wait for clean exit
161
+
162
+ ### Requirement: Crawl Checkpointing
163
+
164
+ The system SHALL implement checkpointing during crawl using markdown format to enable resumption and provide human-readable partial results on failure.
165
+
166
+ #### Scenario: Checkpoint is written periodically
167
+
168
+ - **GIVEN** a crawl is in progress
169
+ - **WHEN** N steps have completed (configurable, default 5)
170
+ - **THEN** it SHALL write a checkpoint to `webtest://{analysisId}/crawls/{crawlId}/checkpoint.md`
171
+ - **AND** the checkpoint SHALL be markdown with YAML frontmatter including: current step, visited pages, action history, goal progress
172
+ - **AND** the checkpoint body SHALL contain human-readable progress summary
173
+
174
+ #### Scenario: Crawl can resume from checkpoint
175
+
176
+ - **GIVEN** a crawl was interrupted (cancelled, error, timeout)
177
+ - **AND** a checkpoint exists as `checkpoint.md`
178
+ - **WHEN** `webtest_crawl_app` is called with `resume: true`
179
+ - **THEN** it SHALL parse the checkpoint YAML frontmatter
180
+ - **AND** continue from the last recorded state
181
+
182
+ ### Requirement: Crawl Loop Detection and Prevention
183
+
184
+ The system SHALL detect and prevent infinite crawl loops.
185
+
186
+ #### Scenario: Same page state detected consecutively
187
+
188
+ - **GIVEN** crawl detects same DOM signature 3 times consecutively
189
+ - **WHEN** loop is detected
190
+ - **THEN** it SHALL log a warning with loop details
191
+ - **AND** inform sampling of the loop condition
192
+ - **AND** request alternative action with loop context
193
+
194
+ #### Scenario: URL cycle detected
195
+
196
+ - **GIVEN** crawl visits the same URL more than 3 times
197
+ - **WHEN** cycle is detected
198
+ - **THEN** it SHALL log a warning
199
+ - **AND** exclude that URL from future navigation suggestions
200
+
201
+ #### Scenario: Action repeat detected
202
+
203
+ - **GIVEN** the same action (tool + args) is attempted 3 times consecutively
204
+ - **WHEN** repeat is detected
205
+ - **THEN** it SHALL reject the repeated action
206
+ - **AND** request a different action from sampling with repeat context
207
+
208
+ #### Scenario: Loop detection state is included in sampling prompts
209
+
210
+ - **GIVEN** loop detection has flagged potential issues
211
+ - **WHEN** the next sampling prompt is built
212
+ - **THEN** it SHALL include:
213
+ - URLs visited more than once
214
+ - Recently repeated actions
215
+ - DOM signature history
216
+ - **AND** instruct the model to avoid these patterns
217
+
218
+ ### Requirement: Crawl Budget Enforcement
219
+
220
+ The system SHALL enforce time, step, and page limits during crawl.
221
+
222
+ #### Scenario: Step limit is enforced
223
+
224
+ - **GIVEN** crawl has a `maxSteps` limit
225
+ - **WHEN** the step count reaches the limit
226
+ - **THEN** crawl SHALL finalize with status "limits_reached"
227
+ - **AND** include all artifacts collected up to that point
228
+
229
+ #### Scenario: Time limit is enforced
230
+
231
+ - **GIVEN** crawl has a `maxMinutes` limit
232
+ - **WHEN** elapsed time reaches the limit
233
+ - **THEN** crawl SHALL finalize with status "timeout"
234
+ - **AND** complete current action before stopping
235
+ - **AND** preserve all collected artifacts
236
+
237
+ #### Scenario: Page limit is enforced
238
+
239
+ - **GIVEN** crawl has a `maxPages` limit
240
+ - **WHEN** the unique page count reaches the limit
241
+ - **THEN** crawl SHALL stop discovering new pages
242
+ - **AND** continue actions on already-visited pages until goal or step limit
243
+
244
+ #### Scenario: Budget status is reported in progress
245
+
246
+ - **GIVEN** crawl is running with limits
247
+ - **WHEN** progress notification is emitted
248
+ - **THEN** it SHALL include budget status:
249
+ - `stepsUsed` / `maxSteps`
250
+ - `minutesElapsed` / `maxMinutes`
251
+ - `pagesDiscovered` / `maxPages`
252
+
253
+ ### Requirement: Security Domain Enforcement
254
+
255
+ The system SHALL enforce domain allowlists for all navigation actions.
256
+
257
+ #### Scenario: Navigation to allowed domain succeeds
258
+
259
+ - **GIVEN** allowedDomains includes "example.com"
260
+ - **WHEN** Playwright action navigates to "https://example.com/page"
261
+ - **THEN** navigation SHALL be allowed
262
+
263
+ #### Scenario: Navigation to disallowed domain is blocked
264
+
265
+ - **GIVEN** allowedDomains includes only "example.com"
266
+ - **WHEN** sampling returns action to navigate to "https://malicious.com"
267
+ - **THEN** the action SHALL be rejected
268
+ - **AND** error logged with attempted URL
269
+
270
+ #### Scenario: Subdomain matching follows rules
271
+
272
+ - **GIVEN** allowedDomains includes "example.com"
273
+ - **WHEN** navigation to "sub.example.com" is attempted
274
+ - **THEN** it SHALL be allowed (subdomain of allowed domain)
275
+
276
+ #### Scenario: Link clicks are validated
277
+
278
+ - **GIVEN** a click action may navigate to external domain
279
+ - **WHEN** click is executed
280
+ - **THEN** resulting URL SHALL be checked post-navigation
281
+ - **AND** if disallowed, navigate back and report error
282
+
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "retestkit",
3
+ "version": "1.4.1",
4
+ "description": "MCP server for web application testing",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./dist/index.js"
8
+ },
9
+ "bin": {
10
+ "retestkit": "./dist/index.js"
11
+ },
12
+ "scripts": {
13
+ "dev": "tsx watch src/index.ts",
14
+ "build": "tsc",
15
+ "start": "node dist/index.js",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "test:integration": "vitest run --config vitest.integration.config.ts"
19
+ },
20
+ "engines": {
21
+ "node": ">=22.18.0"
22
+ },
23
+ "keywords": [
24
+ "mcp",
25
+ "model-context-protocol",
26
+ "testing",
27
+ "web-testing"
28
+ ],
29
+ "license": "UNLICENSED",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/jan-beranek/testing-mcp.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/jan-beranek/testing-mcp/issues"
36
+ },
37
+ "homepage": "https://github.com/jan-beranek/testing-mcp#readme",
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.25.1",
43
+ "gray-matter": "^4.0.3",
44
+ "zod": "^4.2.1",
45
+ "zod-to-json-schema": "^3.25.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^25.0.3",
49
+ "semantic-release": "^24.2.0",
50
+ "tsx": "^4.21.0",
51
+ "typescript": "^5.9.3",
52
+ "vitest": "^4.0.16"
53
+ }
54
+ }
@@ -0,0 +1,9 @@
1
+ export default {
2
+ branches: ['main'],
3
+ plugins: [
4
+ '@semantic-release/commit-analyzer',
5
+ '@semantic-release/release-notes-generator',
6
+ '@semantic-release/npm',
7
+ '@semantic-release/github',
8
+ ],
9
+ };
@@ -0,0 +1,96 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { loadConfig } from "./config.js";
3
+
4
+ describe("config", () => {
5
+ const originalEnv = process.env;
6
+
7
+ beforeEach(() => {
8
+ // Reset environment before each test
9
+ process.env = { ...originalEnv };
10
+ delete process.env.TRANSPORT;
11
+ delete process.env.PORT;
12
+ delete process.env.LOG_LEVEL;
13
+ });
14
+
15
+ afterEach(() => {
16
+ process.env = originalEnv;
17
+ });
18
+
19
+ describe("defaults", () => {
20
+ it("uses stdio transport by default", () => {
21
+ const config = loadConfig();
22
+ expect(config.transport).toBe("stdio");
23
+ });
24
+
25
+ it("uses port 3000 by default", () => {
26
+ const config = loadConfig();
27
+ expect(config.port).toBe(3000);
28
+ });
29
+
30
+ it("uses info log level by default", () => {
31
+ const config = loadConfig();
32
+ expect(config.logLevel).toBe("info");
33
+ });
34
+ });
35
+
36
+ describe("transport", () => {
37
+ it("accepts stdio transport", () => {
38
+ process.env.TRANSPORT = "stdio";
39
+ const config = loadConfig();
40
+ expect(config.transport).toBe("stdio");
41
+ });
42
+
43
+ it("accepts http transport", () => {
44
+ process.env.TRANSPORT = "http";
45
+ const config = loadConfig();
46
+ expect(config.transport).toBe("http");
47
+ });
48
+
49
+ it("rejects invalid transport", () => {
50
+ process.env.TRANSPORT = "invalid";
51
+ expect(() => loadConfig()).toThrow();
52
+ });
53
+ });
54
+
55
+ describe("port", () => {
56
+ it("accepts valid port number", () => {
57
+ process.env.PORT = "8080";
58
+ const config = loadConfig();
59
+ expect(config.port).toBe(8080);
60
+ });
61
+
62
+ it("rejects invalid port", () => {
63
+ process.env.PORT = "invalid";
64
+ expect(() => loadConfig()).toThrow();
65
+ });
66
+
67
+ it("rejects port below 1", () => {
68
+ process.env.PORT = "0";
69
+ expect(() => loadConfig()).toThrow();
70
+ });
71
+
72
+ it("rejects port above 65535", () => {
73
+ process.env.PORT = "70000";
74
+ expect(() => loadConfig()).toThrow();
75
+ });
76
+ });
77
+
78
+ describe("log level", () => {
79
+ it("accepts debug level", () => {
80
+ process.env.LOG_LEVEL = "debug";
81
+ const config = loadConfig();
82
+ expect(config.logLevel).toBe("debug");
83
+ });
84
+
85
+ it("accepts error level", () => {
86
+ process.env.LOG_LEVEL = "error";
87
+ const config = loadConfig();
88
+ expect(config.logLevel).toBe("error");
89
+ });
90
+
91
+ it("rejects invalid log level", () => {
92
+ process.env.LOG_LEVEL = "invalid";
93
+ expect(() => loadConfig()).toThrow();
94
+ });
95
+ });
96
+ });
package/src/config.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { ConfigSchema, type Config } from "./schemas/config.js";
2
+
3
+ export function loadConfig(): Config {
4
+ const rawConfig = {
5
+ transport: process.env.TRANSPORT,
6
+ port: process.env.PORT,
7
+ logLevel: process.env.LOG_LEVEL,
8
+ // Webtest configuration
9
+ workspaceDir: process.env.WEBTEST_WORKSPACE_DIR,
10
+ playwrightMcpCommand: process.env.PLAYWRIGHT_MCP_COMMAND,
11
+ playwrightMcpArgs: process.env.PLAYWRIGHT_MCP_ARGS,
12
+ checkpointInterval: process.env.WEBTEST_CHECKPOINT_INTERVAL,
13
+ screenshotFormat: process.env.WEBTEST_SCREENSHOT_FORMAT,
14
+ screenshotQuality: process.env.WEBTEST_SCREENSHOT_QUALITY,
15
+ defaultMaxSteps: process.env.WEBTEST_DEFAULT_MAX_STEPS,
16
+ defaultMaxMinutes: process.env.WEBTEST_DEFAULT_MAX_MINUTES,
17
+ defaultMaxPages: process.env.WEBTEST_DEFAULT_MAX_PAGES,
18
+ };
19
+
20
+ const result = ConfigSchema.safeParse(rawConfig);
21
+
22
+ if (!result.success) {
23
+ const errors = result.error.issues
24
+ .map((issue) => `${issue.path.join(".")}: ${issue.message}`)
25
+ .join(", ");
26
+ throw new Error(`Invalid configuration: ${errors}`);
27
+ }
28
+
29
+ return result.data;
30
+ }
31
+
32
+ export type { Config };