@avi770/testteam 1.2.0 → 3.0.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 (324) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/README.md +72 -7
  3. package/agents/15-regression-sentinel.ts +3 -2
  4. package/agents/24-signup-onboarding-tester.ts +429 -0
  5. package/agents/25-crud-flow-tester.ts +302 -0
  6. package/agents/26-form-validator.ts +297 -0
  7. package/agents/27-search-filter-tester.ts +326 -0
  8. package/agents/28-navigation-routing-tester.ts +425 -0
  9. package/agents/29-responsive-interaction-tester.ts +350 -0
  10. package/agents/30-multi-user-scenario-tester.ts +319 -0
  11. package/agents/31-load-tester.ts +134 -0
  12. package/agents/32-memory-leak-detector.ts +194 -0
  13. package/agents/33-bundle-analyzer.ts +132 -0
  14. package/agents/34-xss-scanner.ts +191 -0
  15. package/agents/35-csrf-tester.ts +82 -0
  16. package/agents/36-auth-fuzzer.ts +194 -0
  17. package/agents/37-dependency-scanner.ts +176 -0
  18. package/agents/38-secrets-scanner.ts +137 -0
  19. package/agents/39-api-contract-tester.ts +199 -0
  20. package/agents/40-rate-limit-tester.ts +94 -0
  21. package/agents/41-api-pagination-tester.ts +97 -0
  22. package/agents/42-graphql-tester.ts +222 -0
  23. package/agents/43-data-consistency-checker.ts +205 -0
  24. package/agents/44-backup-recovery-tester.ts +152 -0
  25. package/agents/45-data-privacy-scanner.ts +125 -0
  26. package/agents/46-seo-auditor.ts +294 -0
  27. package/agents/47-social-preview-tester.ts +232 -0
  28. package/agents/48-lighthouse-auditor.ts +213 -0
  29. package/agents/49-i18n-tester.ts +198 -0
  30. package/agents/50-timezone-tester.ts +173 -0
  31. package/agents/51-error-recovery-tester.ts +155 -0
  32. package/agents/52-offline-mode-tester.ts +180 -0
  33. package/agents/53-graceful-degradation-tester.ts +156 -0
  34. package/agents/54-websocket-tester.ts +151 -0
  35. package/agents/55-realtime-sync-tester.ts +194 -0
  36. package/agents/56-file-upload-tester.ts +194 -0
  37. package/agents/57-export-tester.ts +174 -0
  38. package/agents/58-payment-flow-tester.ts +183 -0
  39. package/agents/59-ssl-tls-auditor.ts +141 -0
  40. package/agents/60-dns-cdn-tester.ts +117 -0
  41. package/agents/61-docker-health-checker.ts +111 -0
  42. package/agents/62-env-config-validator.ts +152 -0
  43. package/agents/63-log-quality-auditor.ts +136 -0
  44. package/agents/64-analytics-tracker-tester.ts +165 -0
  45. package/agents/65-gdpr-compliance-tester.ts +215 -0
  46. package/agents/66-soc2-control-validator.ts +210 -0
  47. package/agents/67-wcag-aaa-tester.ts +241 -0
  48. package/agents/68-dead-code-detector.ts +135 -0
  49. package/agents/69-type-safety-auditor.ts +164 -0
  50. package/agents/70-complexity-analyzer.ts +179 -0
  51. package/agents/__tests__/24-signup-onboarding-tester.test.ts +274 -0
  52. package/agents/__tests__/25-crud-flow-tester.test.ts +322 -0
  53. package/agents/__tests__/26-form-validator.test.ts +345 -0
  54. package/agents/__tests__/27-search-filter-tester.test.ts +311 -0
  55. package/agents/__tests__/28-navigation-routing-tester.test.ts +328 -0
  56. package/agents/__tests__/29-responsive-interaction-tester.test.ts +297 -0
  57. package/agents/__tests__/30-multi-user-scenario-tester.test.ts +328 -0
  58. package/agents/__tests__/31-load-tester.test.ts +189 -0
  59. package/agents/__tests__/32-memory-leak-detector.test.ts +251 -0
  60. package/agents/__tests__/33-bundle-analyzer.test.ts +237 -0
  61. package/agents/__tests__/34-xss-scanner.test.ts +258 -0
  62. package/agents/__tests__/35-csrf-tester.test.ts +200 -0
  63. package/agents/__tests__/36-auth-fuzzer.test.ts +214 -0
  64. package/agents/__tests__/37-dependency-scanner.test.ts +266 -0
  65. package/agents/__tests__/38-secrets-scanner.test.ts +224 -0
  66. package/agents/__tests__/39-api-contract-tester.test.ts +312 -0
  67. package/agents/__tests__/40-rate-limit-tester.test.ts +192 -0
  68. package/agents/__tests__/41-api-pagination-tester.test.ts +198 -0
  69. package/agents/__tests__/42-graphql-tester.test.ts +252 -0
  70. package/agents/__tests__/43-data-consistency-checker.test.ts +232 -0
  71. package/agents/__tests__/44-backup-recovery-tester.test.ts +222 -0
  72. package/agents/__tests__/45-data-privacy-scanner.test.ts +223 -0
  73. package/agents/__tests__/46-seo-auditor.test.ts +261 -0
  74. package/agents/__tests__/47-social-preview-tester.test.ts +245 -0
  75. package/agents/__tests__/48-lighthouse-auditor.test.ts +276 -0
  76. package/agents/__tests__/49-i18n-tester.test.ts +201 -0
  77. package/agents/__tests__/50-timezone-tester.test.ts +172 -0
  78. package/agents/__tests__/51-error-recovery-tester.test.ts +162 -0
  79. package/agents/__tests__/52-offline-mode-tester.test.ts +164 -0
  80. package/agents/__tests__/53-graceful-degradation-tester.test.ts +168 -0
  81. package/agents/__tests__/54-websocket-tester.test.ts +157 -0
  82. package/agents/__tests__/55-realtime-sync-tester.test.ts +181 -0
  83. package/agents/__tests__/56-file-upload-tester.test.ts +172 -0
  84. package/agents/__tests__/57-export-tester.test.ts +169 -0
  85. package/agents/__tests__/58-payment-flow-tester.test.ts +182 -0
  86. package/agents/__tests__/59-ssl-tls-auditor.test.ts +179 -0
  87. package/agents/__tests__/60-dns-cdn-tester.test.ts +176 -0
  88. package/agents/__tests__/61-docker-health-checker.test.ts +150 -0
  89. package/agents/__tests__/62-env-config-validator.test.ts +166 -0
  90. package/agents/__tests__/63-log-quality-auditor.test.ts +175 -0
  91. package/agents/__tests__/64-analytics-tracker-tester.test.ts +158 -0
  92. package/agents/__tests__/65-gdpr-compliance-tester.test.ts +174 -0
  93. package/agents/__tests__/66-soc2-control-validator.test.ts +183 -0
  94. package/agents/__tests__/67-wcag-aaa-tester.test.ts +190 -0
  95. package/agents/__tests__/68-dead-code-detector.test.ts +174 -0
  96. package/agents/__tests__/69-type-safety-auditor.test.ts +173 -0
  97. package/agents/__tests__/70-complexity-analyzer.test.ts +177 -0
  98. package/agents/__tests__/registry.test.ts +13 -13
  99. package/agents/base-agent.ts +8 -0
  100. package/agents/registry.ts +171 -28
  101. package/core/__tests__/integration.test.ts +4 -4
  102. package/core/__tests__/orchestrator.test.ts +17 -16
  103. package/core/cli.ts +128 -6
  104. package/core/license.ts +208 -211
  105. package/core/orchestrator.ts +78 -5
  106. package/dist/agents/15-regression-sentinel.d.ts +2 -1
  107. package/dist/agents/15-regression-sentinel.d.ts.map +1 -1
  108. package/dist/agents/15-regression-sentinel.js +2 -2
  109. package/dist/agents/15-regression-sentinel.js.map +1 -1
  110. package/dist/agents/24-signup-onboarding-tester.d.ts +35 -0
  111. package/dist/agents/24-signup-onboarding-tester.d.ts.map +1 -0
  112. package/dist/agents/24-signup-onboarding-tester.js +357 -0
  113. package/dist/agents/24-signup-onboarding-tester.js.map +1 -0
  114. package/dist/agents/25-crud-flow-tester.d.ts +11 -0
  115. package/dist/agents/25-crud-flow-tester.d.ts.map +1 -0
  116. package/dist/agents/25-crud-flow-tester.js +253 -0
  117. package/dist/agents/25-crud-flow-tester.js.map +1 -0
  118. package/dist/agents/26-form-validator.d.ts +12 -0
  119. package/dist/agents/26-form-validator.d.ts.map +1 -0
  120. package/dist/agents/26-form-validator.js +257 -0
  121. package/dist/agents/26-form-validator.js.map +1 -0
  122. package/dist/agents/27-search-filter-tester.d.ts +20 -0
  123. package/dist/agents/27-search-filter-tester.d.ts.map +1 -0
  124. package/dist/agents/27-search-filter-tester.js +267 -0
  125. package/dist/agents/27-search-filter-tester.js.map +1 -0
  126. package/dist/agents/28-navigation-routing-tester.d.ts +32 -0
  127. package/dist/agents/28-navigation-routing-tester.d.ts.map +1 -0
  128. package/dist/agents/28-navigation-routing-tester.js +363 -0
  129. package/dist/agents/28-navigation-routing-tester.js.map +1 -0
  130. package/dist/agents/29-responsive-interaction-tester.d.ts +26 -0
  131. package/dist/agents/29-responsive-interaction-tester.d.ts.map +1 -0
  132. package/dist/agents/29-responsive-interaction-tester.js +272 -0
  133. package/dist/agents/29-responsive-interaction-tester.js.map +1 -0
  134. package/dist/agents/30-multi-user-scenario-tester.d.ts +24 -0
  135. package/dist/agents/30-multi-user-scenario-tester.d.ts.map +1 -0
  136. package/dist/agents/30-multi-user-scenario-tester.js +254 -0
  137. package/dist/agents/30-multi-user-scenario-tester.js.map +1 -0
  138. package/dist/agents/31-load-tester.d.ts +12 -0
  139. package/dist/agents/31-load-tester.d.ts.map +1 -0
  140. package/dist/agents/31-load-tester.js +110 -0
  141. package/dist/agents/31-load-tester.js.map +1 -0
  142. package/dist/agents/32-memory-leak-detector.d.ts +12 -0
  143. package/dist/agents/32-memory-leak-detector.d.ts.map +1 -0
  144. package/dist/agents/32-memory-leak-detector.js +167 -0
  145. package/dist/agents/32-memory-leak-detector.js.map +1 -0
  146. package/dist/agents/33-bundle-analyzer.d.ts +10 -0
  147. package/dist/agents/33-bundle-analyzer.d.ts.map +1 -0
  148. package/dist/agents/33-bundle-analyzer.js +111 -0
  149. package/dist/agents/33-bundle-analyzer.js.map +1 -0
  150. package/dist/agents/34-xss-scanner.d.ts +11 -0
  151. package/dist/agents/34-xss-scanner.d.ts.map +1 -0
  152. package/dist/agents/34-xss-scanner.js +164 -0
  153. package/dist/agents/34-xss-scanner.js.map +1 -0
  154. package/dist/agents/35-csrf-tester.d.ts +11 -0
  155. package/dist/agents/35-csrf-tester.d.ts.map +1 -0
  156. package/dist/agents/35-csrf-tester.js +70 -0
  157. package/dist/agents/35-csrf-tester.js.map +1 -0
  158. package/dist/agents/36-auth-fuzzer.d.ts +13 -0
  159. package/dist/agents/36-auth-fuzzer.d.ts.map +1 -0
  160. package/dist/agents/36-auth-fuzzer.js +163 -0
  161. package/dist/agents/36-auth-fuzzer.js.map +1 -0
  162. package/dist/agents/37-dependency-scanner.d.ts +11 -0
  163. package/dist/agents/37-dependency-scanner.d.ts.map +1 -0
  164. package/dist/agents/37-dependency-scanner.js +139 -0
  165. package/dist/agents/37-dependency-scanner.js.map +1 -0
  166. package/dist/agents/38-secrets-scanner.d.ts +11 -0
  167. package/dist/agents/38-secrets-scanner.d.ts.map +1 -0
  168. package/dist/agents/38-secrets-scanner.js +116 -0
  169. package/dist/agents/38-secrets-scanner.js.map +1 -0
  170. package/dist/agents/39-api-contract-tester.d.ts +12 -0
  171. package/dist/agents/39-api-contract-tester.d.ts.map +1 -0
  172. package/dist/agents/39-api-contract-tester.js +142 -0
  173. package/dist/agents/39-api-contract-tester.js.map +1 -0
  174. package/dist/agents/40-rate-limit-tester.d.ts +12 -0
  175. package/dist/agents/40-rate-limit-tester.d.ts.map +1 -0
  176. package/dist/agents/40-rate-limit-tester.js +79 -0
  177. package/dist/agents/40-rate-limit-tester.js.map +1 -0
  178. package/dist/agents/41-api-pagination-tester.d.ts +12 -0
  179. package/dist/agents/41-api-pagination-tester.d.ts.map +1 -0
  180. package/dist/agents/41-api-pagination-tester.js +79 -0
  181. package/dist/agents/41-api-pagination-tester.js.map +1 -0
  182. package/dist/agents/42-graphql-tester.d.ts +13 -0
  183. package/dist/agents/42-graphql-tester.d.ts.map +1 -0
  184. package/dist/agents/42-graphql-tester.js +187 -0
  185. package/dist/agents/42-graphql-tester.js.map +1 -0
  186. package/dist/agents/43-data-consistency-checker.d.ts +11 -0
  187. package/dist/agents/43-data-consistency-checker.d.ts.map +1 -0
  188. package/dist/agents/43-data-consistency-checker.js +176 -0
  189. package/dist/agents/43-data-consistency-checker.js.map +1 -0
  190. package/dist/agents/44-backup-recovery-tester.d.ts +11 -0
  191. package/dist/agents/44-backup-recovery-tester.d.ts.map +1 -0
  192. package/dist/agents/44-backup-recovery-tester.js +128 -0
  193. package/dist/agents/44-backup-recovery-tester.js.map +1 -0
  194. package/dist/agents/45-data-privacy-scanner.d.ts +11 -0
  195. package/dist/agents/45-data-privacy-scanner.d.ts.map +1 -0
  196. package/dist/agents/45-data-privacy-scanner.js +100 -0
  197. package/dist/agents/45-data-privacy-scanner.js.map +1 -0
  198. package/dist/agents/46-seo-auditor.d.ts +12 -0
  199. package/dist/agents/46-seo-auditor.d.ts.map +1 -0
  200. package/dist/agents/46-seo-auditor.js +275 -0
  201. package/dist/agents/46-seo-auditor.js.map +1 -0
  202. package/dist/agents/47-social-preview-tester.d.ts +11 -0
  203. package/dist/agents/47-social-preview-tester.d.ts.map +1 -0
  204. package/dist/agents/47-social-preview-tester.js +219 -0
  205. package/dist/agents/47-social-preview-tester.js.map +1 -0
  206. package/dist/agents/48-lighthouse-auditor.d.ts +11 -0
  207. package/dist/agents/48-lighthouse-auditor.d.ts.map +1 -0
  208. package/dist/agents/48-lighthouse-auditor.js +192 -0
  209. package/dist/agents/48-lighthouse-auditor.js.map +1 -0
  210. package/dist/agents/49-i18n-tester.d.ts +13 -0
  211. package/dist/agents/49-i18n-tester.d.ts.map +1 -0
  212. package/dist/agents/49-i18n-tester.js +172 -0
  213. package/dist/agents/49-i18n-tester.js.map +1 -0
  214. package/dist/agents/50-timezone-tester.d.ts +11 -0
  215. package/dist/agents/50-timezone-tester.d.ts.map +1 -0
  216. package/dist/agents/50-timezone-tester.js +152 -0
  217. package/dist/agents/50-timezone-tester.js.map +1 -0
  218. package/dist/agents/51-error-recovery-tester.d.ts +11 -0
  219. package/dist/agents/51-error-recovery-tester.d.ts.map +1 -0
  220. package/dist/agents/51-error-recovery-tester.js +134 -0
  221. package/dist/agents/51-error-recovery-tester.js.map +1 -0
  222. package/dist/agents/52-offline-mode-tester.d.ts +12 -0
  223. package/dist/agents/52-offline-mode-tester.d.ts.map +1 -0
  224. package/dist/agents/52-offline-mode-tester.js +161 -0
  225. package/dist/agents/52-offline-mode-tester.js.map +1 -0
  226. package/dist/agents/53-graceful-degradation-tester.d.ts +12 -0
  227. package/dist/agents/53-graceful-degradation-tester.d.ts.map +1 -0
  228. package/dist/agents/53-graceful-degradation-tester.js +130 -0
  229. package/dist/agents/53-graceful-degradation-tester.js.map +1 -0
  230. package/dist/agents/54-websocket-tester.d.ts +10 -0
  231. package/dist/agents/54-websocket-tester.d.ts.map +1 -0
  232. package/dist/agents/54-websocket-tester.js +132 -0
  233. package/dist/agents/54-websocket-tester.js.map +1 -0
  234. package/dist/agents/55-realtime-sync-tester.d.ts +11 -0
  235. package/dist/agents/55-realtime-sync-tester.d.ts.map +1 -0
  236. package/dist/agents/55-realtime-sync-tester.js +175 -0
  237. package/dist/agents/55-realtime-sync-tester.js.map +1 -0
  238. package/dist/agents/56-file-upload-tester.d.ts +12 -0
  239. package/dist/agents/56-file-upload-tester.d.ts.map +1 -0
  240. package/dist/agents/56-file-upload-tester.js +166 -0
  241. package/dist/agents/56-file-upload-tester.js.map +1 -0
  242. package/dist/agents/57-export-tester.d.ts +11 -0
  243. package/dist/agents/57-export-tester.d.ts.map +1 -0
  244. package/dist/agents/57-export-tester.js +155 -0
  245. package/dist/agents/57-export-tester.js.map +1 -0
  246. package/dist/agents/58-payment-flow-tester.d.ts +11 -0
  247. package/dist/agents/58-payment-flow-tester.d.ts.map +1 -0
  248. package/dist/agents/58-payment-flow-tester.js +159 -0
  249. package/dist/agents/58-payment-flow-tester.js.map +1 -0
  250. package/dist/agents/59-ssl-tls-auditor.d.ts +10 -0
  251. package/dist/agents/59-ssl-tls-auditor.d.ts.map +1 -0
  252. package/dist/agents/59-ssl-tls-auditor.js +132 -0
  253. package/dist/agents/59-ssl-tls-auditor.js.map +1 -0
  254. package/dist/agents/60-dns-cdn-tester.d.ts +10 -0
  255. package/dist/agents/60-dns-cdn-tester.d.ts.map +1 -0
  256. package/dist/agents/60-dns-cdn-tester.js +105 -0
  257. package/dist/agents/60-dns-cdn-tester.js.map +1 -0
  258. package/dist/agents/61-docker-health-checker.d.ts +10 -0
  259. package/dist/agents/61-docker-health-checker.d.ts.map +1 -0
  260. package/dist/agents/61-docker-health-checker.js +95 -0
  261. package/dist/agents/61-docker-health-checker.js.map +1 -0
  262. package/dist/agents/62-env-config-validator.d.ts +10 -0
  263. package/dist/agents/62-env-config-validator.d.ts.map +1 -0
  264. package/dist/agents/62-env-config-validator.js +132 -0
  265. package/dist/agents/62-env-config-validator.js.map +1 -0
  266. package/dist/agents/63-log-quality-auditor.d.ts +9 -0
  267. package/dist/agents/63-log-quality-auditor.d.ts.map +1 -0
  268. package/dist/agents/63-log-quality-auditor.js +121 -0
  269. package/dist/agents/63-log-quality-auditor.js.map +1 -0
  270. package/dist/agents/64-analytics-tracker-tester.d.ts +10 -0
  271. package/dist/agents/64-analytics-tracker-tester.d.ts.map +1 -0
  272. package/dist/agents/64-analytics-tracker-tester.js +146 -0
  273. package/dist/agents/64-analytics-tracker-tester.js.map +1 -0
  274. package/dist/agents/65-gdpr-compliance-tester.d.ts +13 -0
  275. package/dist/agents/65-gdpr-compliance-tester.d.ts.map +1 -0
  276. package/dist/agents/65-gdpr-compliance-tester.js +186 -0
  277. package/dist/agents/65-gdpr-compliance-tester.js.map +1 -0
  278. package/dist/agents/66-soc2-control-validator.d.ts +14 -0
  279. package/dist/agents/66-soc2-control-validator.d.ts.map +1 -0
  280. package/dist/agents/66-soc2-control-validator.js +178 -0
  281. package/dist/agents/66-soc2-control-validator.js.map +1 -0
  282. package/dist/agents/67-wcag-aaa-tester.d.ts +13 -0
  283. package/dist/agents/67-wcag-aaa-tester.d.ts.map +1 -0
  284. package/dist/agents/67-wcag-aaa-tester.js +207 -0
  285. package/dist/agents/67-wcag-aaa-tester.js.map +1 -0
  286. package/dist/agents/68-dead-code-detector.d.ts +9 -0
  287. package/dist/agents/68-dead-code-detector.d.ts.map +1 -0
  288. package/dist/agents/68-dead-code-detector.js +116 -0
  289. package/dist/agents/68-dead-code-detector.js.map +1 -0
  290. package/dist/agents/69-type-safety-auditor.d.ts +9 -0
  291. package/dist/agents/69-type-safety-auditor.d.ts.map +1 -0
  292. package/dist/agents/69-type-safety-auditor.js +148 -0
  293. package/dist/agents/69-type-safety-auditor.js.map +1 -0
  294. package/dist/agents/70-complexity-analyzer.d.ts +10 -0
  295. package/dist/agents/70-complexity-analyzer.d.ts.map +1 -0
  296. package/dist/agents/70-complexity-analyzer.js +154 -0
  297. package/dist/agents/70-complexity-analyzer.js.map +1 -0
  298. package/dist/agents/base-agent.d.ts +3 -1
  299. package/dist/agents/base-agent.d.ts.map +1 -1
  300. package/dist/agents/base-agent.js +7 -1
  301. package/dist/agents/base-agent.js.map +1 -1
  302. package/dist/agents/registry.d.ts +5 -4
  303. package/dist/agents/registry.d.ts.map +1 -1
  304. package/dist/agents/registry.js +170 -29
  305. package/dist/agents/registry.js.map +1 -1
  306. package/dist/clients/agent-mvp.d.ts +66 -0
  307. package/dist/clients/agent-mvp.d.ts.map +1 -0
  308. package/dist/clients/agent-mvp.js +91 -0
  309. package/dist/clients/agent-mvp.js.map +1 -0
  310. package/dist/clients/total-recall.d.ts +37 -0
  311. package/dist/clients/total-recall.d.ts.map +1 -0
  312. package/dist/clients/total-recall.js +224 -0
  313. package/dist/clients/total-recall.js.map +1 -0
  314. package/dist/core/cli.d.ts +3 -0
  315. package/dist/core/cli.d.ts.map +1 -1
  316. package/dist/core/cli.js +122 -6
  317. package/dist/core/cli.js.map +1 -1
  318. package/dist/core/license.js +2 -5
  319. package/dist/core/license.js.map +1 -1
  320. package/dist/core/orchestrator.d.ts +10 -1
  321. package/dist/core/orchestrator.d.ts.map +1 -1
  322. package/dist/core/orchestrator.js +66 -5
  323. package/dist/core/orchestrator.js.map +1 -1
  324. package/package.json +2 -2
@@ -0,0 +1,258 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import type { ValidatedConfig } from '../../core/config';
3
+ import type { Phase } from '../../core/types';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Stub config helpers
7
+ // ---------------------------------------------------------------------------
8
+
9
+ function makeConfig(overrides: Partial<ValidatedConfig> = {}): ValidatedConfig {
10
+ return {
11
+ schemaVersion: 1,
12
+ name: 'test',
13
+ auth: {
14
+ loginUrl: 'http://localhost/login',
15
+ credentials: {
16
+ admin: { email: 'admin@test.com', password: 'secret' },
17
+ },
18
+ },
19
+ modules: [
20
+ { id: 'dashboard', route: '/dashboard', sidebarIcon: true },
21
+ ],
22
+ environments: {
23
+ alpha: { baseUrl: 'http://localhost:3000', seed: false },
24
+ },
25
+ portals: [],
26
+ breakpoints: [],
27
+ integrations: [],
28
+ workers: [],
29
+ workflows: [],
30
+ accuracy: { enabled: false, decimalPrecision: 2, currencySymbol: '$', timezone: 'UTC' },
31
+ tenancy: { enabled: false, isolationField: 'firmId', testFirms: [] },
32
+ costBudget: { maxPerRun: 100, maxPerAgent: 10, alertThreshold: 0.8, onExceeded: 'abort' },
33
+ agentClassification: { blocking: [], advisory: [34] },
34
+ thresholds: {
35
+ unitCoverage: { lines: 80, functions: 80, branches: 80, statements: 80 },
36
+ lighthouse: { accessibility: 90, performance: 90, bestPractices: 90, seo: 90 },
37
+ apiResponseTime: 2000,
38
+ bundleSizeLimit: 500000,
39
+ maxConsoleErrors: 0,
40
+ },
41
+ disabledAgents: [],
42
+ disabledAgentSet: new Set<number>(),
43
+ ...overrides,
44
+ };
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // Mock fetch
49
+ // ---------------------------------------------------------------------------
50
+
51
+ const fetchMock = vi.fn();
52
+ vi.stubGlobal('fetch', fetchMock);
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // Mock helpers
56
+ // ---------------------------------------------------------------------------
57
+
58
+ const loginMock = vi.fn().mockResolvedValue(undefined);
59
+
60
+ vi.mock('../../helpers/navigation', () => ({
61
+ login: (...args: unknown[]) => loginMock(...args),
62
+ waitForSectionLoad: vi.fn().mockResolvedValue(undefined),
63
+ navigateToSection: vi.fn().mockResolvedValue(undefined),
64
+ switchPortal: vi.fn().mockResolvedValue(undefined),
65
+ }));
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Mock Playwright
69
+ // ---------------------------------------------------------------------------
70
+
71
+ interface MockLocator {
72
+ count: ReturnType<typeof vi.fn>;
73
+ first: ReturnType<typeof vi.fn>;
74
+ nth: ReturnType<typeof vi.fn>;
75
+ fill: ReturnType<typeof vi.fn>;
76
+ }
77
+
78
+ function makeMockLocator(countVal = 0): MockLocator {
79
+ const locator: MockLocator = {
80
+ count: vi.fn().mockResolvedValue(countVal),
81
+ first: vi.fn(),
82
+ nth: vi.fn(),
83
+ fill: vi.fn().mockResolvedValue(undefined),
84
+ };
85
+ locator.first.mockReturnValue(locator);
86
+ locator.nth.mockReturnValue(locator);
87
+ return locator;
88
+ }
89
+
90
+ interface MockPage {
91
+ close: ReturnType<typeof vi.fn>;
92
+ goto: ReturnType<typeof vi.fn>;
93
+ locator: ReturnType<typeof vi.fn>;
94
+ on: ReturnType<typeof vi.fn>;
95
+ removeListener: ReturnType<typeof vi.fn>;
96
+ }
97
+
98
+ function makeMockPage(): MockPage {
99
+ const defaultLocator = makeMockLocator(0);
100
+ return {
101
+ close: vi.fn().mockResolvedValue(undefined),
102
+ goto: vi.fn().mockResolvedValue(undefined),
103
+ locator: vi.fn().mockReturnValue(defaultLocator),
104
+ on: vi.fn(),
105
+ removeListener: vi.fn(),
106
+ };
107
+ }
108
+
109
+ let currentMockPage: MockPage;
110
+ let mockBrowser: { newPage: ReturnType<typeof vi.fn>; close: ReturnType<typeof vi.fn> };
111
+
112
+ vi.mock('playwright', async () => ({
113
+ chromium: {
114
+ launch: vi.fn().mockImplementation(async () => mockBrowser),
115
+ },
116
+ }));
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Dynamic import AFTER mocks
120
+ // ---------------------------------------------------------------------------
121
+
122
+ const { XssScannerAgent } = await import('../34-xss-scanner');
123
+
124
+ function createAgent(
125
+ config: ValidatedConfig = makeConfig(),
126
+ phase: Phase = 'beta',
127
+ ): InstanceType<typeof XssScannerAgent> {
128
+ return new XssScannerAgent(config, phase, '/tmp/test-run');
129
+ }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Tests
133
+ // ---------------------------------------------------------------------------
134
+
135
+ describe('XssScannerAgent', () => {
136
+ beforeEach(() => {
137
+ fetchMock.mockReset().mockResolvedValue({ ok: true, status: 200 });
138
+ loginMock.mockReset().mockResolvedValue(undefined);
139
+
140
+ currentMockPage = makeMockPage();
141
+ mockBrowser = {
142
+ newPage: vi.fn().mockResolvedValue(currentMockPage),
143
+ close: vi.fn().mockResolvedValue(undefined),
144
+ };
145
+ });
146
+
147
+ it('has agentId 34 and correct agentName', () => {
148
+ const agent = createAgent();
149
+ expect(agent.agentId).toBe(34);
150
+ expect(agent.agentName).toBe('XSS Scanner');
151
+ });
152
+
153
+ it('throws when modules array is empty', async () => {
154
+ const config = makeConfig({ modules: [] });
155
+ const agent = createAgent(config);
156
+ const result = await agent.run();
157
+ expect(result.status).toBe('failed');
158
+ expect(result.findings[0].description).toContain('module');
159
+ });
160
+
161
+ it('produces low finding when no inputs found', async () => {
162
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0));
163
+
164
+ const agent = createAgent();
165
+ const result = await agent.run();
166
+
167
+ const noInputs = result.findings.find(f => f.id.includes('no-inputs'));
168
+ expect(noInputs).toBeDefined();
169
+ expect(noInputs!.severity).toBe('low');
170
+ });
171
+
172
+ it('tests XSS payloads on discovered inputs', async () => {
173
+ const inputLocator = makeMockLocator(1);
174
+ currentMockPage.locator.mockReturnValue(inputLocator);
175
+
176
+ const agent = createAgent();
177
+ await agent.run();
178
+
179
+ expect(inputLocator.fill).toHaveBeenCalled();
180
+ });
181
+
182
+ it('registers and removes dialog listeners', async () => {
183
+ const inputLocator = makeMockLocator(1);
184
+ currentMockPage.locator.mockReturnValue(inputLocator);
185
+
186
+ const agent = createAgent();
187
+ await agent.run();
188
+
189
+ expect(currentMockPage.on).toHaveBeenCalledWith('dialog', expect.any(Function));
190
+ expect(currentMockPage.removeListener).toHaveBeenCalledWith('dialog', expect.any(Function));
191
+ });
192
+
193
+ it('produces medium finding when login fails', async () => {
194
+ loginMock.mockRejectedValue(new Error('Auth failed'));
195
+
196
+ const agent = createAgent();
197
+ const result = await agent.run();
198
+
199
+ const loginFinding = result.findings.find(f => f.id.includes('login-failed'));
200
+ expect(loginFinding).toBeDefined();
201
+ expect(loginFinding!.severity).toBe('medium');
202
+ });
203
+
204
+ it('produces medium finding when navigation fails', async () => {
205
+ currentMockPage.goto.mockRejectedValue(new Error('Navigation failed'));
206
+
207
+ const agent = createAgent();
208
+ const result = await agent.run();
209
+
210
+ const navFinding = result.findings.find(f => f.id.includes('nav-failed'));
211
+ expect(navFinding).toBeDefined();
212
+ });
213
+
214
+ it('produces medium finding when Playwright crashes', async () => {
215
+ mockBrowser.newPage.mockRejectedValue(new Error('Browser crashed'));
216
+
217
+ const agent = createAgent();
218
+ const result = await agent.run();
219
+
220
+ const pwFinding = result.findings.find(f => f.id.includes('playwright-failure'));
221
+ expect(pwFinding).toBeDefined();
222
+ });
223
+
224
+ it('closes browser even when an error occurs', async () => {
225
+ mockBrowser.newPage.mockRejectedValue(new Error('Launch error'));
226
+ const agent = createAgent();
227
+ await agent.run();
228
+ expect(mockBrowser.close).toHaveBeenCalled();
229
+ });
230
+
231
+ it('tests at most 3 modules', async () => {
232
+ const manyModules = Array.from({ length: 6 }, (_, i) => ({
233
+ id: `mod-${i}`, route: `/mod-${i}`, sidebarIcon: true,
234
+ }));
235
+ const config = makeConfig({ modules: manyModules });
236
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0));
237
+
238
+ const agent = createAgent(config);
239
+ await agent.run();
240
+
241
+ const navCalls = currentMockPage.goto.mock.calls.filter(
242
+ (c: unknown[]) => typeof c[0] === 'string' && (c[0] as string).includes('/mod-'),
243
+ );
244
+ const uniqueModules = new Set(navCalls.map((c: unknown[]) => (c[0] as string)));
245
+ expect(uniqueModules.size).toBeLessThanOrEqual(3);
246
+ });
247
+
248
+ it('handles fill errors gracefully', async () => {
249
+ const inputLocator = makeMockLocator(1);
250
+ inputLocator.fill.mockRejectedValue(new Error('Fill failed'));
251
+ currentMockPage.locator.mockReturnValue(inputLocator);
252
+
253
+ const agent = createAgent();
254
+ const result = await agent.run();
255
+ // Should not crash
256
+ expect(result.status).toBeDefined();
257
+ });
258
+ });
@@ -0,0 +1,200 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import type { ValidatedConfig } from '../../core/config';
3
+ import type { Phase } from '../../core/types';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Stub config helpers
7
+ // ---------------------------------------------------------------------------
8
+
9
+ function makeConfig(overrides: Partial<ValidatedConfig> = {}): ValidatedConfig {
10
+ return {
11
+ schemaVersion: 1,
12
+ name: 'test',
13
+ auth: {
14
+ loginUrl: 'http://localhost/login',
15
+ credentials: {},
16
+ },
17
+ modules: [
18
+ { id: 'dashboard', route: '/dashboard', sidebarIcon: true },
19
+ ],
20
+ environments: {
21
+ alpha: { baseUrl: 'http://localhost:3000', seed: false },
22
+ },
23
+ portals: [],
24
+ breakpoints: [],
25
+ integrations: [],
26
+ workers: [],
27
+ workflows: [],
28
+ accuracy: { enabled: false, decimalPrecision: 2, currencySymbol: '$', timezone: 'UTC' },
29
+ tenancy: { enabled: false, isolationField: 'firmId', testFirms: [] },
30
+ costBudget: { maxPerRun: 100, maxPerAgent: 10, alertThreshold: 0.8, onExceeded: 'abort' },
31
+ agentClassification: { blocking: [], advisory: [35] },
32
+ thresholds: {
33
+ unitCoverage: { lines: 80, functions: 80, branches: 80, statements: 80 },
34
+ lighthouse: { accessibility: 90, performance: 90, bestPractices: 90, seo: 90 },
35
+ apiResponseTime: 2000,
36
+ bundleSizeLimit: 500000,
37
+ maxConsoleErrors: 0,
38
+ },
39
+ disabledAgents: [],
40
+ disabledAgentSet: new Set<number>(),
41
+ ...overrides,
42
+ };
43
+ }
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Mock fetch
47
+ // ---------------------------------------------------------------------------
48
+
49
+ const fetchMock = vi.fn();
50
+ vi.stubGlobal('fetch', fetchMock);
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Dynamic import AFTER mocks
54
+ // ---------------------------------------------------------------------------
55
+
56
+ const { CsrfTesterAgent } = await import('../35-csrf-tester');
57
+
58
+ function createAgent(
59
+ config: ValidatedConfig = makeConfig(),
60
+ phase: Phase = 'beta',
61
+ ): InstanceType<typeof CsrfTesterAgent> {
62
+ return new CsrfTesterAgent(config, phase, '/tmp/test-run');
63
+ }
64
+
65
+ // ---------------------------------------------------------------------------
66
+ // Tests
67
+ // ---------------------------------------------------------------------------
68
+
69
+ describe('CsrfTesterAgent', () => {
70
+ beforeEach(() => {
71
+ fetchMock.mockReset().mockResolvedValue({ ok: true, status: 200 });
72
+ });
73
+
74
+ it('has agentId 35 and correct agentName', () => {
75
+ const agent = createAgent();
76
+ expect(agent.agentId).toBe(35);
77
+ expect(agent.agentName).toBe('CSRF Tester');
78
+ });
79
+
80
+ it('produces high finding when POST returns 200 without CSRF', async () => {
81
+ fetchMock.mockResolvedValue({ ok: true, status: 200 });
82
+
83
+ const agent = createAgent();
84
+ const result = await agent.run();
85
+
86
+ const csrfFinding = result.findings.find(f => f.id.includes('no-csrf'));
87
+ expect(csrfFinding).toBeDefined();
88
+ expect(csrfFinding!.severity).toBe('high');
89
+ });
90
+
91
+ it('produces high finding when POST returns 201 without CSRF', async () => {
92
+ fetchMock
93
+ .mockResolvedValueOnce({ ok: true, status: 200 }) // env check
94
+ .mockResolvedValue({ ok: true, status: 201 });
95
+
96
+ const agent = createAgent();
97
+ const result = await agent.run();
98
+
99
+ const csrfFinding = result.findings.find(f => f.id.includes('no-csrf'));
100
+ expect(csrfFinding).toBeDefined();
101
+ });
102
+
103
+ it('does not flag when POST returns 403', async () => {
104
+ fetchMock
105
+ .mockResolvedValueOnce({ ok: true, status: 200 }) // env check
106
+ .mockResolvedValue({ ok: false, status: 403 });
107
+
108
+ const agent = createAgent();
109
+ const result = await agent.run();
110
+
111
+ const csrfFinding = result.findings.find(f => f.id.includes('no-csrf'));
112
+ expect(csrfFinding).toBeUndefined();
113
+ });
114
+
115
+ it('does not flag when POST returns 401', async () => {
116
+ fetchMock
117
+ .mockResolvedValueOnce({ ok: true, status: 200 }) // env check
118
+ .mockResolvedValue({ ok: false, status: 401 });
119
+
120
+ const agent = createAgent();
121
+ const result = await agent.run();
122
+
123
+ const csrfFinding = result.findings.find(f => f.id.includes('no-csrf'));
124
+ expect(csrfFinding).toBeUndefined();
125
+ });
126
+
127
+ it('handles fetch errors gracefully', async () => {
128
+ fetchMock
129
+ .mockResolvedValueOnce({ ok: true, status: 200 }) // env check
130
+ .mockRejectedValue(new Error('Network error'));
131
+
132
+ const agent = createAgent();
133
+ const result = await agent.run();
134
+
135
+ const errorFinding = result.findings.find(f => f.id.includes('request-failed'));
136
+ expect(errorFinding).toBeDefined();
137
+ expect(errorFinding!.severity).toBe('low');
138
+ });
139
+
140
+ it('tests module-derived endpoints', async () => {
141
+ const config = makeConfig({
142
+ modules: [{ id: 'invoices', route: '/invoices', sidebarIcon: true }],
143
+ });
144
+
145
+ fetchMock.mockResolvedValue({ ok: false, status: 403 });
146
+
147
+ const agent = createAgent(config);
148
+ await agent.run();
149
+
150
+ const invoiceCalls = fetchMock.mock.calls.filter(
151
+ (call: unknown[]) => typeof call[0] === 'string' && (call[0] as string).includes('/api/invoices'),
152
+ );
153
+ expect(invoiceCalls.length).toBeGreaterThan(0);
154
+ });
155
+
156
+ it('tests default endpoints when no modules', async () => {
157
+ const config = makeConfig({ modules: undefined as unknown as ValidatedConfig['modules'] });
158
+ fetchMock.mockResolvedValue({ ok: false, status: 403 });
159
+
160
+ const agent = createAgent(config);
161
+ await agent.run();
162
+
163
+ const loginCalls = fetchMock.mock.calls.filter(
164
+ (call: unknown[]) => typeof call[0] === 'string' && (call[0] as string).includes('/api/auth/login'),
165
+ );
166
+ expect(loginCalls.length).toBeGreaterThan(0);
167
+ });
168
+
169
+ it('records evidence for each endpoint test', async () => {
170
+ fetchMock.mockResolvedValue({ ok: false, status: 403 });
171
+
172
+ const agent = createAgent();
173
+ const result = await agent.run();
174
+
175
+ expect(result.evidence.length).toBeGreaterThan(0);
176
+ });
177
+
178
+ it('sends POST with JSON content type', async () => {
179
+ fetchMock.mockResolvedValue({ ok: false, status: 403 });
180
+
181
+ const agent = createAgent();
182
+ await agent.run();
183
+
184
+ const postCalls = fetchMock.mock.calls.filter(
185
+ (call: unknown[]) => {
186
+ const opts = call[1] as Record<string, unknown> | undefined;
187
+ return opts?.method === 'POST';
188
+ },
189
+ );
190
+ expect(postCalls.length).toBeGreaterThan(0);
191
+ const firstPost = postCalls[0][1] as Record<string, unknown>;
192
+ expect((firstPost.headers as Record<string, string>)['Content-Type']).toBe('application/json');
193
+ });
194
+
195
+ it('resolves environment in preFlight', async () => {
196
+ const agent = createAgent();
197
+ const result = await agent.run();
198
+ expect(result.findings.every(f => !f.description.includes('preFlight'))).toBe(true);
199
+ });
200
+ });
@@ -0,0 +1,214 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import type { ValidatedConfig } from '../../core/config';
3
+ import type { Phase } from '../../core/types';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Stub config helpers
7
+ // ---------------------------------------------------------------------------
8
+
9
+ function makeConfig(overrides: Partial<ValidatedConfig> = {}): ValidatedConfig {
10
+ return {
11
+ schemaVersion: 1,
12
+ name: 'test',
13
+ auth: {
14
+ loginUrl: 'http://localhost/login',
15
+ credentials: {},
16
+ },
17
+ modules: [],
18
+ environments: {
19
+ alpha: { baseUrl: 'http://localhost:3000', seed: false },
20
+ },
21
+ portals: [],
22
+ breakpoints: [],
23
+ integrations: [],
24
+ workers: [],
25
+ workflows: [],
26
+ accuracy: { enabled: false, decimalPrecision: 2, currencySymbol: '$', timezone: 'UTC' },
27
+ tenancy: { enabled: false, isolationField: 'firmId', testFirms: [] },
28
+ costBudget: { maxPerRun: 100, maxPerAgent: 10, alertThreshold: 0.8, onExceeded: 'abort' },
29
+ agentClassification: { blocking: [], advisory: [36] },
30
+ thresholds: {
31
+ unitCoverage: { lines: 80, functions: 80, branches: 80, statements: 80 },
32
+ lighthouse: { accessibility: 90, performance: 90, bestPractices: 90, seo: 90 },
33
+ apiResponseTime: 2000,
34
+ bundleSizeLimit: 500000,
35
+ maxConsoleErrors: 0,
36
+ },
37
+ disabledAgents: [],
38
+ disabledAgentSet: new Set<number>(),
39
+ ...overrides,
40
+ };
41
+ }
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Mock fetch
45
+ // ---------------------------------------------------------------------------
46
+
47
+ const fetchMock = vi.fn();
48
+ vi.stubGlobal('fetch', fetchMock);
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Dynamic import AFTER mocks
52
+ // ---------------------------------------------------------------------------
53
+
54
+ const { AuthFuzzerAgent } = await import('../36-auth-fuzzer');
55
+
56
+ function createAgent(
57
+ config: ValidatedConfig = makeConfig(),
58
+ phase: Phase = 'beta',
59
+ ): InstanceType<typeof AuthFuzzerAgent> {
60
+ return new AuthFuzzerAgent(config, phase, '/tmp/test-run');
61
+ }
62
+
63
+ // ---------------------------------------------------------------------------
64
+ // Tests
65
+ // ---------------------------------------------------------------------------
66
+
67
+ describe('AuthFuzzerAgent', () => {
68
+ beforeEach(() => {
69
+ fetchMock.mockReset().mockResolvedValue({ ok: false, status: 401 });
70
+ });
71
+
72
+ it('has agentId 36 and correct agentName', () => {
73
+ const agent = createAgent();
74
+ expect(agent.agentId).toBe(36);
75
+ expect(agent.agentName).toBe('Auth Fuzzer');
76
+ });
77
+
78
+ it('detects SQL injection vulnerability when login succeeds with malicious input', async () => {
79
+ fetchMock.mockResolvedValue({ ok: true, status: 200 });
80
+
81
+ const agent = createAgent();
82
+ const result = await agent.run();
83
+
84
+ const sqlFinding = result.findings.find(f => f.id.includes('sql-injection-login'));
85
+ expect(sqlFinding).toBeDefined();
86
+ expect(sqlFinding!.severity).toBe('critical');
87
+ });
88
+
89
+ it('does not flag SQL injection when login returns 401', async () => {
90
+ fetchMock.mockResolvedValue({ ok: false, status: 401 });
91
+
92
+ const agent = createAgent();
93
+ const result = await agent.run();
94
+
95
+ const sqlFinding = result.findings.find(f => f.id.includes('sql-injection-login'));
96
+ expect(sqlFinding).toBeUndefined();
97
+ });
98
+
99
+ it('detects missing account lockout when no 429 received', async () => {
100
+ fetchMock.mockResolvedValue({ ok: false, status: 401 });
101
+
102
+ const agent = createAgent();
103
+ const result = await agent.run();
104
+
105
+ const lockoutFinding = result.findings.find(f => f.id.includes('no-lockout'));
106
+ expect(lockoutFinding).toBeDefined();
107
+ expect(lockoutFinding!.severity).toBe('medium');
108
+ });
109
+
110
+ it('does not flag lockout when 429 is received', async () => {
111
+ let callCount = 0;
112
+ fetchMock.mockImplementation(() => {
113
+ callCount++;
114
+ if (callCount <= 1) return Promise.resolve({ ok: true, status: 200 }); // env check
115
+ if (callCount === 2) return Promise.resolve({ ok: false, status: 401 }); // SQL injection test
116
+ if (callCount <= 7) return Promise.resolve({ ok: false, status: 401 }); // lockout attempts
117
+ return Promise.resolve({ ok: false, status: 429 }); // lockout triggered
118
+ });
119
+
120
+ const agent = createAgent();
121
+ const result = await agent.run();
122
+
123
+ const lockoutFinding = result.findings.find(f => f.id.includes('no-lockout'));
124
+ expect(lockoutFinding).toBeUndefined();
125
+ });
126
+
127
+ it('detects JWT alg:none bypass when protected endpoint returns 200', async () => {
128
+ let callCount = 0;
129
+ fetchMock.mockImplementation(() => {
130
+ callCount++;
131
+ if (callCount <= 1) return Promise.resolve({ ok: true, status: 200 }); // env check
132
+ if (callCount === 2) return Promise.resolve({ ok: false, status: 401 }); // SQL injection
133
+ // lockout attempts - return 401
134
+ if (callCount <= 12) return Promise.resolve({ ok: false, status: 401 });
135
+ // JWT alg:none - return 200 (vulnerability!)
136
+ return Promise.resolve({ ok: true, status: 200 });
137
+ });
138
+
139
+ const agent = createAgent();
140
+ const result = await agent.run();
141
+
142
+ const jwtFinding = result.findings.find(f => f.id.includes('jwt-alg-none'));
143
+ expect(jwtFinding).toBeDefined();
144
+ expect(jwtFinding!.severity).toBe('critical');
145
+ });
146
+
147
+ it('does not flag JWT bypass when protected endpoint returns 401', async () => {
148
+ fetchMock.mockResolvedValue({ ok: false, status: 401 });
149
+
150
+ const agent = createAgent();
151
+ const result = await agent.run();
152
+
153
+ const jwtFinding = result.findings.find(f => f.id.includes('jwt-alg-none'));
154
+ expect(jwtFinding).toBeUndefined();
155
+ });
156
+
157
+ it('handles fetch errors gracefully for SQL injection test', async () => {
158
+ fetchMock
159
+ .mockResolvedValueOnce({ ok: true, status: 200 }) // env check
160
+ .mockRejectedValue(new Error('Network error'));
161
+
162
+ const agent = createAgent();
163
+ const result = await agent.run();
164
+
165
+ const errorFinding = result.findings.find(f => f.id.includes('sql-injection-error'));
166
+ expect(errorFinding).toBeDefined();
167
+ });
168
+
169
+ it('handles fetch errors gracefully for JWT test', async () => {
170
+ let callCount = 0;
171
+ fetchMock.mockImplementation(() => {
172
+ callCount++;
173
+ if (callCount <= 1) return Promise.resolve({ ok: true, status: 200 }); // env check
174
+ if (callCount === 2) return Promise.resolve({ ok: false, status: 401 }); // SQL injection
175
+ if (callCount <= 12) return Promise.resolve({ ok: false, status: 401 }); // lockout
176
+ return Promise.reject(new Error('Connection refused')); // JWT test
177
+ });
178
+
179
+ const agent = createAgent();
180
+ const result = await agent.run();
181
+
182
+ const jwtError = result.findings.find(f => f.id.includes('jwt-test-error'));
183
+ expect(jwtError).toBeDefined();
184
+ });
185
+
186
+ it('records evidence for each test', async () => {
187
+ fetchMock.mockResolvedValue({ ok: false, status: 401 });
188
+
189
+ const agent = createAgent();
190
+ const result = await agent.run();
191
+
192
+ expect(result.evidence.length).toBeGreaterThanOrEqual(2);
193
+ });
194
+
195
+ it('resolves environment in preFlight', async () => {
196
+ const agent = createAgent();
197
+ const result = await agent.run();
198
+ expect(result.findings.every(f => !f.description.includes('preFlight'))).toBe(true);
199
+ });
200
+
201
+ it('sends SQL injection payload in request body', async () => {
202
+ fetchMock.mockResolvedValue({ ok: false, status: 401 });
203
+
204
+ const agent = createAgent();
205
+ await agent.run();
206
+
207
+ const sqlCall = fetchMock.mock.calls.find((call: unknown[]) => {
208
+ const opts = call[1] as Record<string, unknown> | undefined;
209
+ const body = opts?.body as string | undefined;
210
+ return body?.includes("OR 1=1");
211
+ });
212
+ expect(sqlCall).toBeDefined();
213
+ });
214
+ });