@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,155 @@
1
+ import type { Browser, Page, Route } from 'playwright';
2
+ import type { Finding } from '../core/types';
3
+ import { BaseAgent } from './base-agent';
4
+ import { resolveEnvironment } from '../helpers/env-resolver';
5
+ import { login } from '../helpers/navigation';
6
+
7
+ /** How long to stay offline (ms). */
8
+ const OFFLINE_DURATION_MS = 3_000;
9
+
10
+ export class ErrorRecoveryTesterAgent extends BaseAgent {
11
+ readonly agentId = 51;
12
+ readonly agentName = 'Error Recovery Tester';
13
+ private baseUrl = '';
14
+
15
+ protected async preFlight(): Promise<void> {
16
+ if (!this.config.modules || this.config.modules.length === 0) {
17
+ throw new Error('ErrorRecoveryTesterAgent requires at least one module in config.modules');
18
+ }
19
+
20
+ const { env } = await resolveEnvironment(this.config, this.phase);
21
+ this.baseUrl = env.baseUrl;
22
+ }
23
+
24
+ protected async execute(): Promise<Finding[]> {
25
+ const findings: Finding[] = [];
26
+
27
+ const rawLoginUrl = this.config.auth.loginUrl ?? '/login';
28
+ const loginUrl = rawLoginUrl.startsWith('http') ? rawLoginUrl : `${this.baseUrl}${rawLoginUrl}`;
29
+ const credentials =
30
+ this.config.auth.credentials?.['admin'] ??
31
+ Object.values(this.config.auth.credentials ?? {})[0];
32
+
33
+ const { chromium } = await import('playwright');
34
+
35
+ let browser: Browser | null = null;
36
+
37
+ try {
38
+ browser = await chromium.launch({ headless: true });
39
+ const page = await browser.newPage();
40
+
41
+ if (credentials) {
42
+ try {
43
+ await login(page, credentials, loginUrl);
44
+ } catch {
45
+ findings.push({
46
+ id: `${this.agentId}-login-failed`,
47
+ type: 'infra-issue',
48
+ severity: 'medium',
49
+ agentId: this.agentId,
50
+ module: 'error-recovery-tester',
51
+ description: 'Login failed — continuing anonymously',
52
+ });
53
+ }
54
+ }
55
+
56
+ const firstModule = this.config.modules[0];
57
+ const fullUrl = firstModule.route.startsWith('http')
58
+ ? firstModule.route
59
+ : `${this.baseUrl}${firstModule.route}`;
60
+
61
+ try {
62
+ await page.goto(fullUrl, { waitUntil: 'domcontentloaded', timeout: 10_000 });
63
+ } catch {
64
+ findings.push({
65
+ id: `${this.agentId}-nav-failed`,
66
+ type: 'test-bug',
67
+ severity: 'medium',
68
+ agentId: this.agentId,
69
+ module: firstModule.id,
70
+ description: `Failed to navigate to ${firstModule.id}`,
71
+ });
72
+ await page.close().catch(() => undefined);
73
+ return findings;
74
+ }
75
+
76
+ // Go offline
77
+ const abortHandler = (route: Route) => route.abort();
78
+ await page.route('**/*', abortHandler);
79
+
80
+ // Wait while offline
81
+ await new Promise(resolve => setTimeout(resolve, OFFLINE_DURATION_MS));
82
+
83
+ // Go back online
84
+ await page.unroute('**/*', abortHandler);
85
+
86
+ // Wait for recovery
87
+ await new Promise(resolve => setTimeout(resolve, 2_000));
88
+
89
+ // Check if app recovered
90
+ const recoveryFindings = await this.checkRecovery(page, firstModule.id);
91
+ findings.push(...recoveryFindings);
92
+
93
+ await page.close().catch(() => undefined);
94
+ } catch (playwrightError) {
95
+ findings.push({
96
+ id: `${this.agentId}-playwright-failure`,
97
+ type: 'infra-issue',
98
+ severity: 'medium',
99
+ agentId: this.agentId,
100
+ module: 'error-recovery-tester',
101
+ description: `Playwright execution failed: ${playwrightError instanceof Error ? playwrightError.message.split('\n')[0] : String(playwrightError)}`,
102
+ });
103
+ } finally {
104
+ if (browser) await browser.close().catch(() => undefined);
105
+ }
106
+
107
+ return findings;
108
+ }
109
+
110
+ private async checkRecovery(page: Page, moduleId: string): Promise<Finding[]> {
111
+ const findings: Finding[] = [];
112
+
113
+ try {
114
+ const bodyContent = await page.evaluate(() => document.body.innerText?.trim() ?? '');
115
+
116
+ if (bodyContent.length === 0) {
117
+ findings.push({
118
+ id: `${this.agentId}-blank-screen-${moduleId}`,
119
+ type: 'test-bug',
120
+ severity: 'high',
121
+ agentId: this.agentId,
122
+ module: moduleId,
123
+ description: 'App shows blank screen after network recovery — no error recovery UI detected',
124
+ });
125
+ return findings;
126
+ }
127
+
128
+ // Check for recovery indicators
129
+ const hasRetryButton = await page.locator('button:has-text("Retry"), button:has-text("Reload"), button:has-text("Try Again")').count();
130
+ const hasErrorMessage = await page.locator('[role="alert"], .error, .offline').count();
131
+
132
+ if (hasRetryButton > 0 || hasErrorMessage > 0) {
133
+ findings.push({
134
+ id: `${this.agentId}-recovery-ui-${moduleId}`,
135
+ type: 'test-bug',
136
+ severity: 'low',
137
+ agentId: this.agentId,
138
+ module: moduleId,
139
+ description: 'App shows recovery/error UI after network restoration — manual reload may be needed',
140
+ });
141
+ }
142
+ } catch {
143
+ findings.push({
144
+ id: `${this.agentId}-recovery-check-failed-${moduleId}`,
145
+ type: 'test-bug',
146
+ severity: 'medium',
147
+ agentId: this.agentId,
148
+ module: moduleId,
149
+ description: 'Failed to check recovery state after network restoration',
150
+ });
151
+ }
152
+
153
+ return findings;
154
+ }
155
+ }
@@ -0,0 +1,180 @@
1
+ import type { Browser, Page, Route } from 'playwright';
2
+ import type { Finding } from '../core/types';
3
+ import { BaseAgent } from './base-agent';
4
+ import { resolveEnvironment } from '../helpers/env-resolver';
5
+ import { login } from '../helpers/navigation';
6
+
7
+ export class OfflineModeTesterAgent extends BaseAgent {
8
+ readonly agentId = 52;
9
+ readonly agentName = 'Offline Mode Tester';
10
+ private baseUrl = '';
11
+
12
+ protected async preFlight(): Promise<void> {
13
+ if (!this.config.modules || this.config.modules.length === 0) {
14
+ throw new Error('OfflineModeTesterAgent requires at least one module in config.modules');
15
+ }
16
+
17
+ const { env } = await resolveEnvironment(this.config, this.phase);
18
+ this.baseUrl = env.baseUrl;
19
+ }
20
+
21
+ protected async execute(): Promise<Finding[]> {
22
+ const findings: Finding[] = [];
23
+
24
+ const rawLoginUrl = this.config.auth.loginUrl ?? '/login';
25
+ const loginUrl = rawLoginUrl.startsWith('http') ? rawLoginUrl : `${this.baseUrl}${rawLoginUrl}`;
26
+ const credentials =
27
+ this.config.auth.credentials?.['admin'] ??
28
+ Object.values(this.config.auth.credentials ?? {})[0];
29
+
30
+ const { chromium } = await import('playwright');
31
+
32
+ let browser: Browser | null = null;
33
+
34
+ try {
35
+ browser = await chromium.launch({ headless: true });
36
+ const page = await browser.newPage();
37
+
38
+ if (credentials) {
39
+ try {
40
+ await login(page, credentials, loginUrl);
41
+ } catch {
42
+ findings.push({
43
+ id: `${this.agentId}-login-failed`,
44
+ type: 'infra-issue',
45
+ severity: 'medium',
46
+ agentId: this.agentId,
47
+ module: 'offline-mode-tester',
48
+ description: 'Login failed — continuing anonymously',
49
+ });
50
+ }
51
+ }
52
+
53
+ // Load first module (content should be cached)
54
+ const firstModule = this.config.modules[0];
55
+ const firstUrl = firstModule.route.startsWith('http')
56
+ ? firstModule.route
57
+ : `${this.baseUrl}${firstModule.route}`;
58
+
59
+ try {
60
+ await page.goto(firstUrl, { waitUntil: 'domcontentloaded', timeout: 10_000 });
61
+ } catch {
62
+ findings.push({
63
+ id: `${this.agentId}-nav-failed`,
64
+ type: 'test-bug',
65
+ severity: 'medium',
66
+ agentId: this.agentId,
67
+ module: firstModule.id,
68
+ description: `Failed to navigate to ${firstModule.id}`,
69
+ });
70
+ await page.close().catch(() => undefined);
71
+ return findings;
72
+ }
73
+
74
+ // Check for service worker
75
+ const hasServiceWorker = await this.checkServiceWorker(page);
76
+ if (!hasServiceWorker) {
77
+ findings.push({
78
+ id: `${this.agentId}-no-service-worker`,
79
+ type: 'test-bug',
80
+ severity: 'low',
81
+ agentId: this.agentId,
82
+ module: 'offline-mode-tester',
83
+ description: 'No service worker controller detected — offline caching likely not available',
84
+ });
85
+ }
86
+
87
+ // Go offline
88
+ const abortHandler = (route: Route) => route.abort();
89
+ await page.route('**/*', abortHandler);
90
+
91
+ // Try navigating to second module while offline
92
+ if (this.config.modules.length >= 2) {
93
+ const secondModule = this.config.modules[1];
94
+ const secondUrl = secondModule.route.startsWith('http')
95
+ ? secondModule.route
96
+ : `${this.baseUrl}${secondModule.route}`;
97
+
98
+ try {
99
+ await page.goto(secondUrl, { waitUntil: 'domcontentloaded', timeout: 5_000 });
100
+ } catch {
101
+ // Navigation failure expected offline
102
+ }
103
+
104
+ // Check for offline content
105
+ const offlineFindings = await this.checkOfflineContent(page, secondModule.id);
106
+ findings.push(...offlineFindings);
107
+ }
108
+
109
+ // Restore online
110
+ await page.unroute('**/*', abortHandler);
111
+
112
+ await page.close().catch(() => undefined);
113
+ } catch (playwrightError) {
114
+ findings.push({
115
+ id: `${this.agentId}-playwright-failure`,
116
+ type: 'infra-issue',
117
+ severity: 'medium',
118
+ agentId: this.agentId,
119
+ module: 'offline-mode-tester',
120
+ description: `Playwright execution failed: ${playwrightError instanceof Error ? playwrightError.message.split('\n')[0] : String(playwrightError)}`,
121
+ });
122
+ } finally {
123
+ if (browser) await browser.close().catch(() => undefined);
124
+ }
125
+
126
+ return findings;
127
+ }
128
+
129
+ private async checkServiceWorker(page: Page): Promise<boolean> {
130
+ try {
131
+ return await page.evaluate(() => Boolean(navigator.serviceWorker?.controller));
132
+ } catch {
133
+ return false;
134
+ }
135
+ }
136
+
137
+ private async checkOfflineContent(page: Page, moduleId: string): Promise<Finding[]> {
138
+ const findings: Finding[] = [];
139
+
140
+ try {
141
+ const bodyContent = await page.evaluate(() => document.body.innerText?.trim() ?? '');
142
+
143
+ if (bodyContent.length === 0) {
144
+ findings.push({
145
+ id: `${this.agentId}-blank-offline-${moduleId}`,
146
+ type: 'test-bug',
147
+ severity: 'medium',
148
+ agentId: this.agentId,
149
+ module: moduleId,
150
+ description: `Blank page when navigating to ${moduleId} while offline — no cached content or offline fallback`,
151
+ });
152
+ return findings;
153
+ }
154
+
155
+ // Check for explicit offline message
156
+ const lowerContent = bodyContent.toLowerCase();
157
+ if (lowerContent.includes('offline') || lowerContent.includes('no connection') || lowerContent.includes('network')) {
158
+ findings.push({
159
+ id: `${this.agentId}-offline-message-${moduleId}`,
160
+ type: 'test-bug',
161
+ severity: 'low',
162
+ agentId: this.agentId,
163
+ module: moduleId,
164
+ description: `Offline message displayed for ${moduleId} — app handles offline gracefully`,
165
+ });
166
+ }
167
+ } catch {
168
+ findings.push({
169
+ id: `${this.agentId}-offline-check-failed-${moduleId}`,
170
+ type: 'test-bug',
171
+ severity: 'medium',
172
+ agentId: this.agentId,
173
+ module: moduleId,
174
+ description: `Failed to evaluate page content while offline for ${moduleId}`,
175
+ });
176
+ }
177
+
178
+ return findings;
179
+ }
180
+ }
@@ -0,0 +1,156 @@
1
+ import type { Browser, Route } from 'playwright';
2
+ import type { Finding } from '../core/types';
3
+ import { BaseAgent } from './base-agent';
4
+ import { resolveEnvironment } from '../helpers/env-resolver';
5
+
6
+ export class GracefulDegradationTesterAgent extends BaseAgent {
7
+ readonly agentId = 53;
8
+ readonly agentName = 'Graceful Degradation Tester';
9
+ private baseUrl = '';
10
+
11
+ protected async preFlight(): Promise<void> {
12
+ if (!this.config.modules || this.config.modules.length === 0) {
13
+ throw new Error('GracefulDegradationTesterAgent requires at least one module in config.modules');
14
+ }
15
+
16
+ const { env } = await resolveEnvironment(this.config, this.phase);
17
+ this.baseUrl = env.baseUrl;
18
+ }
19
+
20
+ protected async execute(): Promise<Finding[]> {
21
+ const findings: Finding[] = [];
22
+
23
+ const { chromium } = await import('playwright');
24
+
25
+ let browser: Browser | null = null;
26
+
27
+ try {
28
+ browser = await chromium.launch({ headless: true });
29
+
30
+ const firstModule = this.config.modules[0];
31
+ const fullUrl = firstModule.route.startsWith('http')
32
+ ? firstModule.route
33
+ : `${this.baseUrl}${firstModule.route}`;
34
+
35
+ // Test 1: Disable JavaScript — check for SSR
36
+ const noJsFindings = await this.testNoJavaScript(browser, fullUrl, firstModule.id);
37
+ findings.push(...noJsFindings);
38
+
39
+ // Test 2: Block images — check alt text
40
+ const noImgFindings = await this.testNoImages(browser, fullUrl, firstModule.id);
41
+ findings.push(...noImgFindings);
42
+ } catch (playwrightError) {
43
+ findings.push({
44
+ id: `${this.agentId}-playwright-failure`,
45
+ type: 'infra-issue',
46
+ severity: 'medium',
47
+ agentId: this.agentId,
48
+ module: 'graceful-degradation-tester',
49
+ description: `Playwright execution failed: ${playwrightError instanceof Error ? playwrightError.message.split('\n')[0] : String(playwrightError)}`,
50
+ });
51
+ } finally {
52
+ if (browser) await browser.close().catch(() => undefined);
53
+ }
54
+
55
+ return findings;
56
+ }
57
+
58
+ private async testNoJavaScript(
59
+ browser: Browser,
60
+ url: string,
61
+ moduleId: string,
62
+ ): Promise<Finding[]> {
63
+ const findings: Finding[] = [];
64
+
65
+ const context = await browser.newContext({ javaScriptEnabled: false });
66
+ const page = await context.newPage();
67
+
68
+ try {
69
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 10_000 });
70
+
71
+ const bodyContent = await page.evaluate(() => document.body.innerText?.trim() ?? '');
72
+
73
+ if (bodyContent.length === 0) {
74
+ findings.push({
75
+ id: `${this.agentId}-no-ssr-${moduleId}`,
76
+ type: 'test-bug',
77
+ severity: 'medium',
78
+ agentId: this.agentId,
79
+ module: moduleId,
80
+ description: `No content renders with JavaScript disabled — SSR/static fallback not available for ${moduleId}`,
81
+ });
82
+ }
83
+ } catch {
84
+ // Navigation may fail without JS — that itself is a finding
85
+ findings.push({
86
+ id: `${this.agentId}-no-js-nav-failed-${moduleId}`,
87
+ type: 'test-bug',
88
+ severity: 'medium',
89
+ agentId: this.agentId,
90
+ module: moduleId,
91
+ description: `Page failed to load with JavaScript disabled for ${moduleId}`,
92
+ });
93
+ } finally {
94
+ await page.close().catch(() => undefined);
95
+ await context.close().catch(() => undefined);
96
+ }
97
+
98
+ return findings;
99
+ }
100
+
101
+ private async testNoImages(
102
+ browser: Browser,
103
+ url: string,
104
+ moduleId: string,
105
+ ): Promise<Finding[]> {
106
+ const findings: Finding[] = [];
107
+
108
+ const context = await browser.newContext();
109
+ const page = await context.newPage();
110
+
111
+ // Block all image requests
112
+ const imageBlocker = (route: Route) => route.abort();
113
+ await page.route('**/*.{png,jpg,jpeg,gif,webp,svg,ico}', imageBlocker);
114
+
115
+ try {
116
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 10_000 });
117
+
118
+ // Check alt text on img elements
119
+ const missingAltCount = await page.evaluate(() => {
120
+ const images = document.querySelectorAll('img');
121
+ let missing = 0;
122
+ for (const img of images) {
123
+ if (!img.alt || img.alt.trim().length === 0) {
124
+ missing++;
125
+ }
126
+ }
127
+ return missing;
128
+ });
129
+
130
+ if (missingAltCount > 0) {
131
+ findings.push({
132
+ id: `${this.agentId}-missing-alt-${moduleId}`,
133
+ type: 'test-bug',
134
+ severity: 'medium',
135
+ agentId: this.agentId,
136
+ module: moduleId,
137
+ description: `${missingAltCount} image(s) missing alt text in ${moduleId}`,
138
+ });
139
+ }
140
+ } catch {
141
+ findings.push({
142
+ id: `${this.agentId}-img-test-failed-${moduleId}`,
143
+ type: 'test-bug',
144
+ severity: 'low',
145
+ agentId: this.agentId,
146
+ module: moduleId,
147
+ description: `Failed to test image degradation for ${moduleId}`,
148
+ });
149
+ } finally {
150
+ await page.close().catch(() => undefined);
151
+ await context.close().catch(() => undefined);
152
+ }
153
+
154
+ return findings;
155
+ }
156
+ }
@@ -0,0 +1,151 @@
1
+ import type { Browser } from 'playwright';
2
+ import type { Finding } from '../core/types';
3
+ import { BaseAgent } from './base-agent';
4
+ import { resolveEnvironment } from '../helpers/env-resolver';
5
+ import { login } from '../helpers/navigation';
6
+
7
+ export class WebSocketTesterAgent extends BaseAgent {
8
+ readonly agentId = 54;
9
+ readonly agentName = 'WebSocket Tester';
10
+ private baseUrl = '';
11
+
12
+ protected async preFlight(): Promise<void> {
13
+ if (!this.config.modules || this.config.modules.length === 0) {
14
+ throw new Error('WebSocketTesterAgent requires at least one module in config.modules');
15
+ }
16
+
17
+ const { env } = await resolveEnvironment(this.config, this.phase);
18
+ this.baseUrl = env.baseUrl;
19
+ }
20
+
21
+ protected async execute(): Promise<Finding[]> {
22
+ const findings: Finding[] = [];
23
+
24
+ const rawLoginUrl = this.config.auth.loginUrl ?? '/login';
25
+ const loginUrl = rawLoginUrl.startsWith('http') ? rawLoginUrl : `${this.baseUrl}${rawLoginUrl}`;
26
+ const credentials =
27
+ this.config.auth.credentials?.['admin'] ??
28
+ Object.values(this.config.auth.credentials ?? {})[0];
29
+
30
+ // Check config for WS integrations
31
+ const hasWsConfig = this.config.integrations.some(
32
+ i => i.name.toLowerCase().includes('websocket') || i.name.toLowerCase().includes('ws') || i.name.toLowerCase().includes('socket'),
33
+ );
34
+
35
+ const { chromium } = await import('playwright');
36
+
37
+ let browser: Browser | null = null;
38
+
39
+ try {
40
+ browser = await chromium.launch({ headless: true });
41
+ const page = await browser.newPage();
42
+
43
+ if (credentials) {
44
+ try {
45
+ await login(page, credentials, loginUrl);
46
+ } catch {
47
+ findings.push({
48
+ id: `${this.agentId}-login-failed`,
49
+ type: 'infra-issue',
50
+ severity: 'medium',
51
+ agentId: this.agentId,
52
+ module: 'websocket-tester',
53
+ description: 'Login failed — continuing anonymously',
54
+ });
55
+ }
56
+ }
57
+
58
+ // Listen for WebSocket connections
59
+ const wsConnections: { url: string; error: boolean }[] = [];
60
+
61
+ page.on('websocket', ws => {
62
+ const entry = { url: ws.url(), error: false };
63
+ wsConnections.push(entry);
64
+
65
+ ws.on('socketerror', () => {
66
+ entry.error = true;
67
+ });
68
+
69
+ ws.on('close', () => {
70
+ // Track close events if needed
71
+ });
72
+ });
73
+
74
+ // Navigate through modules
75
+ for (const mod of this.config.modules) {
76
+ const fullUrl = mod.route.startsWith('http')
77
+ ? mod.route
78
+ : `${this.baseUrl}${mod.route}`;
79
+
80
+ try {
81
+ await page.goto(fullUrl, { waitUntil: 'domcontentloaded', timeout: 10_000 });
82
+ // Wait a moment for WS connections to establish
83
+ await new Promise(resolve => setTimeout(resolve, 2_000));
84
+ } catch {
85
+ // Navigation failure — non-critical for WS testing
86
+ }
87
+ }
88
+
89
+ // Report findings
90
+ if (wsConnections.length === 0 && hasWsConfig) {
91
+ findings.push({
92
+ id: `${this.agentId}-ws-configured-no-connection`,
93
+ type: 'test-bug',
94
+ severity: 'medium',
95
+ agentId: this.agentId,
96
+ module: 'websocket-tester',
97
+ description: 'WebSocket integration configured but no WS connections detected',
98
+ });
99
+ } else if (wsConnections.length === 0) {
100
+ findings.push({
101
+ id: `${this.agentId}-no-ws-connections`,
102
+ type: 'test-bug',
103
+ severity: 'low',
104
+ agentId: this.agentId,
105
+ module: 'websocket-tester',
106
+ description: 'No WebSocket connections detected during navigation',
107
+ });
108
+ }
109
+
110
+ // Check for failed connections
111
+ const failedWs = wsConnections.filter(ws => ws.error);
112
+ if (failedWs.length > 0) {
113
+ for (const ws of failedWs) {
114
+ findings.push({
115
+ id: `${this.agentId}-ws-error-${wsConnections.indexOf(ws)}`,
116
+ type: 'test-bug',
117
+ severity: 'medium',
118
+ agentId: this.agentId,
119
+ module: 'websocket-tester',
120
+ description: `WebSocket connection failed: ${ws.url}`,
121
+ });
122
+ }
123
+ }
124
+
125
+ // Report successful connections
126
+ const successfulWs = wsConnections.filter(ws => !ws.error);
127
+ if (successfulWs.length > 0) {
128
+ this.addEvidence({
129
+ type: 'log',
130
+ path: '',
131
+ description: `Detected ${successfulWs.length} successful WebSocket connection(s): ${successfulWs.map(ws => ws.url).join(', ')}`,
132
+ });
133
+ }
134
+
135
+ await page.close().catch(() => undefined);
136
+ } catch (playwrightError) {
137
+ findings.push({
138
+ id: `${this.agentId}-playwright-failure`,
139
+ type: 'infra-issue',
140
+ severity: 'medium',
141
+ agentId: this.agentId,
142
+ module: 'websocket-tester',
143
+ description: `Playwright execution failed: ${playwrightError instanceof Error ? playwrightError.message.split('\n')[0] : String(playwrightError)}`,
144
+ });
145
+ } finally {
146
+ if (browser) await browser.close().catch(() => undefined);
147
+ }
148
+
149
+ return findings;
150
+ }
151
+ }