@avi770/testteam 1.2.0 → 2.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 (300) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/README.md +53 -6
  3. package/agents/24-signup-onboarding-tester.ts +429 -0
  4. package/agents/25-crud-flow-tester.ts +302 -0
  5. package/agents/26-form-validator.ts +297 -0
  6. package/agents/27-search-filter-tester.ts +326 -0
  7. package/agents/28-navigation-routing-tester.ts +425 -0
  8. package/agents/29-responsive-interaction-tester.ts +350 -0
  9. package/agents/30-multi-user-scenario-tester.ts +319 -0
  10. package/agents/31-load-tester.ts +134 -0
  11. package/agents/32-memory-leak-detector.ts +194 -0
  12. package/agents/33-bundle-analyzer.ts +132 -0
  13. package/agents/34-xss-scanner.ts +191 -0
  14. package/agents/35-csrf-tester.ts +82 -0
  15. package/agents/36-auth-fuzzer.ts +194 -0
  16. package/agents/37-dependency-scanner.ts +176 -0
  17. package/agents/38-secrets-scanner.ts +137 -0
  18. package/agents/39-api-contract-tester.ts +199 -0
  19. package/agents/40-rate-limit-tester.ts +94 -0
  20. package/agents/41-api-pagination-tester.ts +97 -0
  21. package/agents/42-graphql-tester.ts +222 -0
  22. package/agents/43-data-consistency-checker.ts +205 -0
  23. package/agents/44-backup-recovery-tester.ts +152 -0
  24. package/agents/45-data-privacy-scanner.ts +125 -0
  25. package/agents/46-seo-auditor.ts +294 -0
  26. package/agents/47-social-preview-tester.ts +232 -0
  27. package/agents/48-lighthouse-auditor.ts +213 -0
  28. package/agents/49-i18n-tester.ts +198 -0
  29. package/agents/50-timezone-tester.ts +173 -0
  30. package/agents/51-error-recovery-tester.ts +155 -0
  31. package/agents/52-offline-mode-tester.ts +180 -0
  32. package/agents/53-graceful-degradation-tester.ts +156 -0
  33. package/agents/54-websocket-tester.ts +151 -0
  34. package/agents/55-realtime-sync-tester.ts +194 -0
  35. package/agents/56-file-upload-tester.ts +194 -0
  36. package/agents/57-export-tester.ts +174 -0
  37. package/agents/58-payment-flow-tester.ts +183 -0
  38. package/agents/59-ssl-tls-auditor.ts +141 -0
  39. package/agents/60-dns-cdn-tester.ts +117 -0
  40. package/agents/61-docker-health-checker.ts +111 -0
  41. package/agents/62-env-config-validator.ts +152 -0
  42. package/agents/63-log-quality-auditor.ts +136 -0
  43. package/agents/64-analytics-tracker-tester.ts +165 -0
  44. package/agents/65-gdpr-compliance-tester.ts +215 -0
  45. package/agents/66-soc2-control-validator.ts +210 -0
  46. package/agents/67-wcag-aaa-tester.ts +241 -0
  47. package/agents/68-dead-code-detector.ts +135 -0
  48. package/agents/69-type-safety-auditor.ts +164 -0
  49. package/agents/70-complexity-analyzer.ts +179 -0
  50. package/agents/__tests__/24-signup-onboarding-tester.test.ts +274 -0
  51. package/agents/__tests__/25-crud-flow-tester.test.ts +322 -0
  52. package/agents/__tests__/26-form-validator.test.ts +345 -0
  53. package/agents/__tests__/27-search-filter-tester.test.ts +311 -0
  54. package/agents/__tests__/28-navigation-routing-tester.test.ts +328 -0
  55. package/agents/__tests__/29-responsive-interaction-tester.test.ts +297 -0
  56. package/agents/__tests__/30-multi-user-scenario-tester.test.ts +328 -0
  57. package/agents/__tests__/31-load-tester.test.ts +189 -0
  58. package/agents/__tests__/32-memory-leak-detector.test.ts +251 -0
  59. package/agents/__tests__/33-bundle-analyzer.test.ts +237 -0
  60. package/agents/__tests__/34-xss-scanner.test.ts +258 -0
  61. package/agents/__tests__/35-csrf-tester.test.ts +200 -0
  62. package/agents/__tests__/36-auth-fuzzer.test.ts +214 -0
  63. package/agents/__tests__/37-dependency-scanner.test.ts +266 -0
  64. package/agents/__tests__/38-secrets-scanner.test.ts +224 -0
  65. package/agents/__tests__/39-api-contract-tester.test.ts +312 -0
  66. package/agents/__tests__/40-rate-limit-tester.test.ts +192 -0
  67. package/agents/__tests__/41-api-pagination-tester.test.ts +198 -0
  68. package/agents/__tests__/42-graphql-tester.test.ts +252 -0
  69. package/agents/__tests__/43-data-consistency-checker.test.ts +232 -0
  70. package/agents/__tests__/44-backup-recovery-tester.test.ts +222 -0
  71. package/agents/__tests__/45-data-privacy-scanner.test.ts +223 -0
  72. package/agents/__tests__/46-seo-auditor.test.ts +261 -0
  73. package/agents/__tests__/47-social-preview-tester.test.ts +245 -0
  74. package/agents/__tests__/48-lighthouse-auditor.test.ts +276 -0
  75. package/agents/__tests__/49-i18n-tester.test.ts +201 -0
  76. package/agents/__tests__/50-timezone-tester.test.ts +172 -0
  77. package/agents/__tests__/51-error-recovery-tester.test.ts +162 -0
  78. package/agents/__tests__/52-offline-mode-tester.test.ts +164 -0
  79. package/agents/__tests__/53-graceful-degradation-tester.test.ts +168 -0
  80. package/agents/__tests__/54-websocket-tester.test.ts +157 -0
  81. package/agents/__tests__/55-realtime-sync-tester.test.ts +181 -0
  82. package/agents/__tests__/56-file-upload-tester.test.ts +172 -0
  83. package/agents/__tests__/57-export-tester.test.ts +169 -0
  84. package/agents/__tests__/58-payment-flow-tester.test.ts +182 -0
  85. package/agents/__tests__/59-ssl-tls-auditor.test.ts +179 -0
  86. package/agents/__tests__/60-dns-cdn-tester.test.ts +176 -0
  87. package/agents/__tests__/61-docker-health-checker.test.ts +150 -0
  88. package/agents/__tests__/62-env-config-validator.test.ts +166 -0
  89. package/agents/__tests__/63-log-quality-auditor.test.ts +175 -0
  90. package/agents/__tests__/64-analytics-tracker-tester.test.ts +158 -0
  91. package/agents/__tests__/65-gdpr-compliance-tester.test.ts +174 -0
  92. package/agents/__tests__/66-soc2-control-validator.test.ts +183 -0
  93. package/agents/__tests__/67-wcag-aaa-tester.test.ts +190 -0
  94. package/agents/__tests__/68-dead-code-detector.test.ts +174 -0
  95. package/agents/__tests__/69-type-safety-auditor.test.ts +173 -0
  96. package/agents/__tests__/70-complexity-analyzer.test.ts +177 -0
  97. package/agents/__tests__/registry.test.ts +13 -13
  98. package/agents/registry.ts +146 -5
  99. package/core/__tests__/integration.test.ts +4 -4
  100. package/core/__tests__/orchestrator.test.ts +17 -16
  101. package/core/license.ts +208 -211
  102. package/core/orchestrator.ts +6 -4
  103. package/dist/agents/24-signup-onboarding-tester.d.ts +35 -0
  104. package/dist/agents/24-signup-onboarding-tester.d.ts.map +1 -0
  105. package/dist/agents/24-signup-onboarding-tester.js +357 -0
  106. package/dist/agents/24-signup-onboarding-tester.js.map +1 -0
  107. package/dist/agents/25-crud-flow-tester.d.ts +11 -0
  108. package/dist/agents/25-crud-flow-tester.d.ts.map +1 -0
  109. package/dist/agents/25-crud-flow-tester.js +253 -0
  110. package/dist/agents/25-crud-flow-tester.js.map +1 -0
  111. package/dist/agents/26-form-validator.d.ts +12 -0
  112. package/dist/agents/26-form-validator.d.ts.map +1 -0
  113. package/dist/agents/26-form-validator.js +257 -0
  114. package/dist/agents/26-form-validator.js.map +1 -0
  115. package/dist/agents/27-search-filter-tester.d.ts +20 -0
  116. package/dist/agents/27-search-filter-tester.d.ts.map +1 -0
  117. package/dist/agents/27-search-filter-tester.js +267 -0
  118. package/dist/agents/27-search-filter-tester.js.map +1 -0
  119. package/dist/agents/28-navigation-routing-tester.d.ts +32 -0
  120. package/dist/agents/28-navigation-routing-tester.d.ts.map +1 -0
  121. package/dist/agents/28-navigation-routing-tester.js +363 -0
  122. package/dist/agents/28-navigation-routing-tester.js.map +1 -0
  123. package/dist/agents/29-responsive-interaction-tester.d.ts +26 -0
  124. package/dist/agents/29-responsive-interaction-tester.d.ts.map +1 -0
  125. package/dist/agents/29-responsive-interaction-tester.js +272 -0
  126. package/dist/agents/29-responsive-interaction-tester.js.map +1 -0
  127. package/dist/agents/30-multi-user-scenario-tester.d.ts +24 -0
  128. package/dist/agents/30-multi-user-scenario-tester.d.ts.map +1 -0
  129. package/dist/agents/30-multi-user-scenario-tester.js +254 -0
  130. package/dist/agents/30-multi-user-scenario-tester.js.map +1 -0
  131. package/dist/agents/31-load-tester.d.ts +12 -0
  132. package/dist/agents/31-load-tester.d.ts.map +1 -0
  133. package/dist/agents/31-load-tester.js +110 -0
  134. package/dist/agents/31-load-tester.js.map +1 -0
  135. package/dist/agents/32-memory-leak-detector.d.ts +12 -0
  136. package/dist/agents/32-memory-leak-detector.d.ts.map +1 -0
  137. package/dist/agents/32-memory-leak-detector.js +167 -0
  138. package/dist/agents/32-memory-leak-detector.js.map +1 -0
  139. package/dist/agents/33-bundle-analyzer.d.ts +10 -0
  140. package/dist/agents/33-bundle-analyzer.d.ts.map +1 -0
  141. package/dist/agents/33-bundle-analyzer.js +111 -0
  142. package/dist/agents/33-bundle-analyzer.js.map +1 -0
  143. package/dist/agents/34-xss-scanner.d.ts +11 -0
  144. package/dist/agents/34-xss-scanner.d.ts.map +1 -0
  145. package/dist/agents/34-xss-scanner.js +164 -0
  146. package/dist/agents/34-xss-scanner.js.map +1 -0
  147. package/dist/agents/35-csrf-tester.d.ts +11 -0
  148. package/dist/agents/35-csrf-tester.d.ts.map +1 -0
  149. package/dist/agents/35-csrf-tester.js +70 -0
  150. package/dist/agents/35-csrf-tester.js.map +1 -0
  151. package/dist/agents/36-auth-fuzzer.d.ts +13 -0
  152. package/dist/agents/36-auth-fuzzer.d.ts.map +1 -0
  153. package/dist/agents/36-auth-fuzzer.js +163 -0
  154. package/dist/agents/36-auth-fuzzer.js.map +1 -0
  155. package/dist/agents/37-dependency-scanner.d.ts +11 -0
  156. package/dist/agents/37-dependency-scanner.d.ts.map +1 -0
  157. package/dist/agents/37-dependency-scanner.js +139 -0
  158. package/dist/agents/37-dependency-scanner.js.map +1 -0
  159. package/dist/agents/38-secrets-scanner.d.ts +11 -0
  160. package/dist/agents/38-secrets-scanner.d.ts.map +1 -0
  161. package/dist/agents/38-secrets-scanner.js +116 -0
  162. package/dist/agents/38-secrets-scanner.js.map +1 -0
  163. package/dist/agents/39-api-contract-tester.d.ts +12 -0
  164. package/dist/agents/39-api-contract-tester.d.ts.map +1 -0
  165. package/dist/agents/39-api-contract-tester.js +142 -0
  166. package/dist/agents/39-api-contract-tester.js.map +1 -0
  167. package/dist/agents/40-rate-limit-tester.d.ts +12 -0
  168. package/dist/agents/40-rate-limit-tester.d.ts.map +1 -0
  169. package/dist/agents/40-rate-limit-tester.js +79 -0
  170. package/dist/agents/40-rate-limit-tester.js.map +1 -0
  171. package/dist/agents/41-api-pagination-tester.d.ts +12 -0
  172. package/dist/agents/41-api-pagination-tester.d.ts.map +1 -0
  173. package/dist/agents/41-api-pagination-tester.js +79 -0
  174. package/dist/agents/41-api-pagination-tester.js.map +1 -0
  175. package/dist/agents/42-graphql-tester.d.ts +13 -0
  176. package/dist/agents/42-graphql-tester.d.ts.map +1 -0
  177. package/dist/agents/42-graphql-tester.js +187 -0
  178. package/dist/agents/42-graphql-tester.js.map +1 -0
  179. package/dist/agents/43-data-consistency-checker.d.ts +11 -0
  180. package/dist/agents/43-data-consistency-checker.d.ts.map +1 -0
  181. package/dist/agents/43-data-consistency-checker.js +176 -0
  182. package/dist/agents/43-data-consistency-checker.js.map +1 -0
  183. package/dist/agents/44-backup-recovery-tester.d.ts +11 -0
  184. package/dist/agents/44-backup-recovery-tester.d.ts.map +1 -0
  185. package/dist/agents/44-backup-recovery-tester.js +128 -0
  186. package/dist/agents/44-backup-recovery-tester.js.map +1 -0
  187. package/dist/agents/45-data-privacy-scanner.d.ts +11 -0
  188. package/dist/agents/45-data-privacy-scanner.d.ts.map +1 -0
  189. package/dist/agents/45-data-privacy-scanner.js +100 -0
  190. package/dist/agents/45-data-privacy-scanner.js.map +1 -0
  191. package/dist/agents/46-seo-auditor.d.ts +12 -0
  192. package/dist/agents/46-seo-auditor.d.ts.map +1 -0
  193. package/dist/agents/46-seo-auditor.js +275 -0
  194. package/dist/agents/46-seo-auditor.js.map +1 -0
  195. package/dist/agents/47-social-preview-tester.d.ts +11 -0
  196. package/dist/agents/47-social-preview-tester.d.ts.map +1 -0
  197. package/dist/agents/47-social-preview-tester.js +219 -0
  198. package/dist/agents/47-social-preview-tester.js.map +1 -0
  199. package/dist/agents/48-lighthouse-auditor.d.ts +11 -0
  200. package/dist/agents/48-lighthouse-auditor.d.ts.map +1 -0
  201. package/dist/agents/48-lighthouse-auditor.js +192 -0
  202. package/dist/agents/48-lighthouse-auditor.js.map +1 -0
  203. package/dist/agents/49-i18n-tester.d.ts +13 -0
  204. package/dist/agents/49-i18n-tester.d.ts.map +1 -0
  205. package/dist/agents/49-i18n-tester.js +172 -0
  206. package/dist/agents/49-i18n-tester.js.map +1 -0
  207. package/dist/agents/50-timezone-tester.d.ts +11 -0
  208. package/dist/agents/50-timezone-tester.d.ts.map +1 -0
  209. package/dist/agents/50-timezone-tester.js +152 -0
  210. package/dist/agents/50-timezone-tester.js.map +1 -0
  211. package/dist/agents/51-error-recovery-tester.d.ts +11 -0
  212. package/dist/agents/51-error-recovery-tester.d.ts.map +1 -0
  213. package/dist/agents/51-error-recovery-tester.js +134 -0
  214. package/dist/agents/51-error-recovery-tester.js.map +1 -0
  215. package/dist/agents/52-offline-mode-tester.d.ts +12 -0
  216. package/dist/agents/52-offline-mode-tester.d.ts.map +1 -0
  217. package/dist/agents/52-offline-mode-tester.js +161 -0
  218. package/dist/agents/52-offline-mode-tester.js.map +1 -0
  219. package/dist/agents/53-graceful-degradation-tester.d.ts +12 -0
  220. package/dist/agents/53-graceful-degradation-tester.d.ts.map +1 -0
  221. package/dist/agents/53-graceful-degradation-tester.js +130 -0
  222. package/dist/agents/53-graceful-degradation-tester.js.map +1 -0
  223. package/dist/agents/54-websocket-tester.d.ts +10 -0
  224. package/dist/agents/54-websocket-tester.d.ts.map +1 -0
  225. package/dist/agents/54-websocket-tester.js +132 -0
  226. package/dist/agents/54-websocket-tester.js.map +1 -0
  227. package/dist/agents/55-realtime-sync-tester.d.ts +11 -0
  228. package/dist/agents/55-realtime-sync-tester.d.ts.map +1 -0
  229. package/dist/agents/55-realtime-sync-tester.js +175 -0
  230. package/dist/agents/55-realtime-sync-tester.js.map +1 -0
  231. package/dist/agents/56-file-upload-tester.d.ts +12 -0
  232. package/dist/agents/56-file-upload-tester.d.ts.map +1 -0
  233. package/dist/agents/56-file-upload-tester.js +166 -0
  234. package/dist/agents/56-file-upload-tester.js.map +1 -0
  235. package/dist/agents/57-export-tester.d.ts +11 -0
  236. package/dist/agents/57-export-tester.d.ts.map +1 -0
  237. package/dist/agents/57-export-tester.js +155 -0
  238. package/dist/agents/57-export-tester.js.map +1 -0
  239. package/dist/agents/58-payment-flow-tester.d.ts +11 -0
  240. package/dist/agents/58-payment-flow-tester.d.ts.map +1 -0
  241. package/dist/agents/58-payment-flow-tester.js +159 -0
  242. package/dist/agents/58-payment-flow-tester.js.map +1 -0
  243. package/dist/agents/59-ssl-tls-auditor.d.ts +10 -0
  244. package/dist/agents/59-ssl-tls-auditor.d.ts.map +1 -0
  245. package/dist/agents/59-ssl-tls-auditor.js +132 -0
  246. package/dist/agents/59-ssl-tls-auditor.js.map +1 -0
  247. package/dist/agents/60-dns-cdn-tester.d.ts +10 -0
  248. package/dist/agents/60-dns-cdn-tester.d.ts.map +1 -0
  249. package/dist/agents/60-dns-cdn-tester.js +105 -0
  250. package/dist/agents/60-dns-cdn-tester.js.map +1 -0
  251. package/dist/agents/61-docker-health-checker.d.ts +10 -0
  252. package/dist/agents/61-docker-health-checker.d.ts.map +1 -0
  253. package/dist/agents/61-docker-health-checker.js +95 -0
  254. package/dist/agents/61-docker-health-checker.js.map +1 -0
  255. package/dist/agents/62-env-config-validator.d.ts +10 -0
  256. package/dist/agents/62-env-config-validator.d.ts.map +1 -0
  257. package/dist/agents/62-env-config-validator.js +132 -0
  258. package/dist/agents/62-env-config-validator.js.map +1 -0
  259. package/dist/agents/63-log-quality-auditor.d.ts +9 -0
  260. package/dist/agents/63-log-quality-auditor.d.ts.map +1 -0
  261. package/dist/agents/63-log-quality-auditor.js +121 -0
  262. package/dist/agents/63-log-quality-auditor.js.map +1 -0
  263. package/dist/agents/64-analytics-tracker-tester.d.ts +10 -0
  264. package/dist/agents/64-analytics-tracker-tester.d.ts.map +1 -0
  265. package/dist/agents/64-analytics-tracker-tester.js +146 -0
  266. package/dist/agents/64-analytics-tracker-tester.js.map +1 -0
  267. package/dist/agents/65-gdpr-compliance-tester.d.ts +13 -0
  268. package/dist/agents/65-gdpr-compliance-tester.d.ts.map +1 -0
  269. package/dist/agents/65-gdpr-compliance-tester.js +186 -0
  270. package/dist/agents/65-gdpr-compliance-tester.js.map +1 -0
  271. package/dist/agents/66-soc2-control-validator.d.ts +14 -0
  272. package/dist/agents/66-soc2-control-validator.d.ts.map +1 -0
  273. package/dist/agents/66-soc2-control-validator.js +178 -0
  274. package/dist/agents/66-soc2-control-validator.js.map +1 -0
  275. package/dist/agents/67-wcag-aaa-tester.d.ts +13 -0
  276. package/dist/agents/67-wcag-aaa-tester.d.ts.map +1 -0
  277. package/dist/agents/67-wcag-aaa-tester.js +207 -0
  278. package/dist/agents/67-wcag-aaa-tester.js.map +1 -0
  279. package/dist/agents/68-dead-code-detector.d.ts +9 -0
  280. package/dist/agents/68-dead-code-detector.d.ts.map +1 -0
  281. package/dist/agents/68-dead-code-detector.js +116 -0
  282. package/dist/agents/68-dead-code-detector.js.map +1 -0
  283. package/dist/agents/69-type-safety-auditor.d.ts +9 -0
  284. package/dist/agents/69-type-safety-auditor.d.ts.map +1 -0
  285. package/dist/agents/69-type-safety-auditor.js +148 -0
  286. package/dist/agents/69-type-safety-auditor.js.map +1 -0
  287. package/dist/agents/70-complexity-analyzer.d.ts +10 -0
  288. package/dist/agents/70-complexity-analyzer.d.ts.map +1 -0
  289. package/dist/agents/70-complexity-analyzer.js +154 -0
  290. package/dist/agents/70-complexity-analyzer.js.map +1 -0
  291. package/dist/agents/registry.d.ts +3 -3
  292. package/dist/agents/registry.d.ts.map +1 -1
  293. package/dist/agents/registry.js +146 -5
  294. package/dist/agents/registry.js.map +1 -1
  295. package/dist/core/license.js +2 -5
  296. package/dist/core/license.js.map +1 -1
  297. package/dist/core/orchestrator.d.ts.map +1 -1
  298. package/dist/core/orchestrator.js +6 -4
  299. package/dist/core/orchestrator.js.map +1 -1
  300. package/package.json +2 -2
@@ -0,0 +1,326 @@
1
+ import type { Browser, Page } 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
+ /** Timeout (ms) for individual search/filter operations. */
8
+ const OP_TIMEOUT_MS = 5_000;
9
+
10
+ /** Selectors for search inputs. */
11
+ const SEARCH_SELECTORS = [
12
+ 'input[type="search"]',
13
+ 'input[placeholder*="search" i]',
14
+ 'input[placeholder*="find" i]',
15
+ '[data-testid*="search"]',
16
+ '[role="searchbox"]',
17
+ ] as const;
18
+
19
+ /** Selectors for filter controls. */
20
+ const FILTER_SELECTORS = [
21
+ 'select',
22
+ '[role="combobox"]',
23
+ 'button:has-text("Filter")',
24
+ '[data-testid*="filter"]',
25
+ ] as const;
26
+
27
+ export class SearchFilterTesterAgent extends BaseAgent {
28
+ readonly agentId = 27;
29
+ readonly agentName = 'Search & Filter Tester';
30
+ private baseUrl = '';
31
+
32
+ protected async preFlight(): Promise<void> {
33
+ if (!this.config.modules || this.config.modules.length === 0) {
34
+ throw new Error('SearchFilterTesterAgent requires at least one module in config.modules');
35
+ }
36
+
37
+ const { env } = await resolveEnvironment(this.config, this.phase);
38
+ this.baseUrl = env.baseUrl;
39
+ }
40
+
41
+ protected async execute(): Promise<Finding[]> {
42
+ const findings: Finding[] = [];
43
+
44
+ const rawLoginUrl = this.config.auth.loginUrl ?? '/login';
45
+ const loginUrl = rawLoginUrl.startsWith('http') ? rawLoginUrl : `${this.baseUrl}${rawLoginUrl}`;
46
+ const credentials =
47
+ this.config.auth.credentials?.['admin'] ??
48
+ Object.values(this.config.auth.credentials ?? {})[0];
49
+
50
+ if (!credentials) {
51
+ findings.push({
52
+ id: `${this.agentId}-no-credentials`,
53
+ type: 'infra-issue',
54
+ severity: 'medium',
55
+ agentId: this.agentId,
56
+ module: 'search-filter-tester',
57
+ description: 'No credentials configured — continuing without authentication',
58
+ });
59
+ }
60
+
61
+ const { chromium } = await import('playwright');
62
+
63
+ let browser: Browser | null = null;
64
+
65
+ try {
66
+ browser = await chromium.launch({ headless: true });
67
+ const page = await browser.newPage();
68
+
69
+ if (credentials) {
70
+ try {
71
+ await login(page, credentials, loginUrl);
72
+ } catch (loginError) {
73
+ findings.push({
74
+ id: `${this.agentId}-login-failed`,
75
+ type: 'infra-issue',
76
+ severity: 'medium',
77
+ agentId: this.agentId,
78
+ module: 'search-filter-tester',
79
+ description: `Login failed — continuing anonymously: ${loginError instanceof Error ? loginError.message.split('\n')[0] : String(loginError)}`,
80
+ });
81
+ }
82
+ }
83
+
84
+ for (const mod of this.config.modules) {
85
+ const moduleFindings = await this.testModuleSearchFilter(page, mod.id, mod.route);
86
+ findings.push(...moduleFindings);
87
+ }
88
+
89
+ await page.close().catch(() => undefined);
90
+ } catch (playwrightError) {
91
+ findings.push({
92
+ id: `${this.agentId}-playwright-failure`,
93
+ type: 'infra-issue',
94
+ severity: 'medium',
95
+ agentId: this.agentId,
96
+ module: 'search-filter-tester',
97
+ description: `Playwright execution failed: ${playwrightError instanceof Error ? playwrightError.message.split('\n')[0] : String(playwrightError)}`,
98
+ });
99
+ } finally {
100
+ if (browser) await browser.close().catch(() => undefined);
101
+ }
102
+
103
+ return findings;
104
+ }
105
+
106
+ private async testModuleSearchFilter(
107
+ page: Page,
108
+ moduleId: string,
109
+ moduleRoute: string,
110
+ ): Promise<Finding[]> {
111
+ const findings: Finding[] = [];
112
+ const fullUrl = moduleRoute.startsWith('http')
113
+ ? moduleRoute
114
+ : `${this.baseUrl}${moduleRoute}`;
115
+
116
+ try {
117
+ await Promise.race([
118
+ page.goto(fullUrl, { waitUntil: 'domcontentloaded' }),
119
+ new Promise((_, reject) =>
120
+ setTimeout(() => reject(new Error('Navigation timeout')), OP_TIMEOUT_MS),
121
+ ),
122
+ ]);
123
+ } catch {
124
+ findings.push({
125
+ id: `${this.agentId}-nav-failed-${moduleId}`,
126
+ type: 'test-bug',
127
+ severity: 'medium',
128
+ agentId: this.agentId,
129
+ module: moduleId,
130
+ description: `Failed to navigate to module ${moduleId} at ${moduleRoute}`,
131
+ });
132
+ return findings;
133
+ }
134
+
135
+ // Find search inputs
136
+ const searchSelector = SEARCH_SELECTORS.join(', ');
137
+ let searchCount = 0;
138
+ try {
139
+ searchCount = await Promise.race([
140
+ page.locator(searchSelector).count(),
141
+ new Promise<number>((_, reject) =>
142
+ setTimeout(() => reject(new Error('Timeout')), OP_TIMEOUT_MS),
143
+ ),
144
+ ]) as number;
145
+ } catch {
146
+ // Timeout discovering search inputs
147
+ }
148
+
149
+ if (searchCount > 0) {
150
+ const searchFindings = await this.testSearch(page, moduleId);
151
+ findings.push(...searchFindings);
152
+ }
153
+
154
+ // Find filters
155
+ const filterSelector = FILTER_SELECTORS.join(', ');
156
+ let filterCount = 0;
157
+ try {
158
+ filterCount = await Promise.race([
159
+ page.locator(filterSelector).count(),
160
+ new Promise<number>((_, reject) =>
161
+ setTimeout(() => reject(new Error('Timeout')), OP_TIMEOUT_MS),
162
+ ),
163
+ ]) as number;
164
+ } catch {
165
+ // Timeout discovering filters
166
+ }
167
+
168
+ if (filterCount > 0) {
169
+ const filterFindings = await this.testFilter(page, moduleId, filterCount);
170
+ findings.push(...filterFindings);
171
+ }
172
+
173
+ if (searchCount === 0 && filterCount === 0) {
174
+ findings.push({
175
+ id: `${this.agentId}-no-search-filter-${moduleId}`,
176
+ type: 'test-bug',
177
+ severity: 'low',
178
+ agentId: this.agentId,
179
+ module: moduleId,
180
+ description: `No search or filter UI found in module ${moduleId}`,
181
+ });
182
+ }
183
+
184
+ return findings;
185
+ }
186
+
187
+ /**
188
+ * Test search functionality: type query, check results change,
189
+ * clear, check restore, type gibberish, check empty state.
190
+ */
191
+ private async testSearch(page: Page, moduleId: string): Promise<Finding[]> {
192
+ const findings: Finding[] = [];
193
+ const searchSelector = SEARCH_SELECTORS.join(', ');
194
+ const searchInput = page.locator(searchSelector).first();
195
+
196
+ try {
197
+ // Type "test" and wait for results
198
+ await Promise.race([
199
+ searchInput.fill('test'),
200
+ new Promise((_, reject) =>
201
+ setTimeout(() => reject(new Error('Timeout')), OP_TIMEOUT_MS),
202
+ ),
203
+ ]);
204
+
205
+ await page.waitForTimeout(1000);
206
+
207
+ // Clear search
208
+ await Promise.race([
209
+ searchInput.fill(''),
210
+ new Promise((_, reject) =>
211
+ setTimeout(() => reject(new Error('Timeout')), OP_TIMEOUT_MS),
212
+ ),
213
+ ]);
214
+
215
+ await page.waitForTimeout(1000);
216
+
217
+ // Type gibberish
218
+ await Promise.race([
219
+ searchInput.fill('zzz999xxx'),
220
+ new Promise((_, reject) =>
221
+ setTimeout(() => reject(new Error('Timeout')), OP_TIMEOUT_MS),
222
+ ),
223
+ ]);
224
+
225
+ await page.waitForTimeout(1000);
226
+
227
+ // Check if results area shows content (meaning search may not be filtering)
228
+ const noResultsIndicators = await page
229
+ .locator(
230
+ ':text("no results"), :text("not found"), :text("no matches"), [data-testid*="empty"], .empty-state',
231
+ )
232
+ .count()
233
+ .catch(() => 0);
234
+
235
+ // Check if list items still exist
236
+ const listItems = await page
237
+ .locator('tr, [class*="list-item"], [class*="card"], li')
238
+ .count()
239
+ .catch(() => 0);
240
+
241
+ if (noResultsIndicators === 0 && listItems > 0) {
242
+ findings.push({
243
+ id: `${this.agentId}-search-not-filtering-${moduleId}`,
244
+ type: 'test-bug',
245
+ severity: 'medium',
246
+ agentId: this.agentId,
247
+ module: moduleId,
248
+ description: 'Search may not be filtering — gibberish query still shows list items',
249
+ });
250
+ }
251
+
252
+ // Clear search for next tests
253
+ await searchInput.fill('').catch(() => undefined);
254
+ } catch (searchError) {
255
+ findings.push({
256
+ id: `${this.agentId}-search-error-${moduleId}`,
257
+ type: 'test-bug',
258
+ severity: 'medium',
259
+ agentId: this.agentId,
260
+ module: moduleId,
261
+ description: `Search test failed in module ${moduleId}: ${searchError instanceof Error ? searchError.message.split('\n')[0] : String(searchError)}`,
262
+ });
263
+ }
264
+
265
+ return findings;
266
+ }
267
+
268
+ /**
269
+ * Test filter controls: click/select, verify list updates.
270
+ */
271
+ private async testFilter(
272
+ page: Page,
273
+ moduleId: string,
274
+ filterCount: number,
275
+ ): Promise<Finding[]> {
276
+ const findings: Finding[] = [];
277
+ const filterSelector = FILTER_SELECTORS.join(', ');
278
+
279
+ try {
280
+ const firstFilter = page.locator(filterSelector).first();
281
+ const tagName = await firstFilter.evaluate((el) => el.tagName.toLowerCase()).catch(() => '');
282
+
283
+ if (tagName === 'select') {
284
+ const optionCount = await firstFilter.locator('option').count();
285
+ if (optionCount > 1) {
286
+ const value = await firstFilter.locator('option').nth(1).getAttribute('value');
287
+ if (value) {
288
+ await Promise.race([
289
+ firstFilter.selectOption(value),
290
+ new Promise((_, reject) =>
291
+ setTimeout(() => reject(new Error('Timeout')), OP_TIMEOUT_MS),
292
+ ),
293
+ ]);
294
+ }
295
+ }
296
+ } else {
297
+ await Promise.race([
298
+ firstFilter.click(),
299
+ new Promise((_, reject) =>
300
+ setTimeout(() => reject(new Error('Timeout')), OP_TIMEOUT_MS),
301
+ ),
302
+ ]);
303
+ }
304
+
305
+ findings.push({
306
+ id: `${this.agentId}-filter-found-${moduleId}`,
307
+ type: 'infra-issue',
308
+ severity: 'info',
309
+ agentId: this.agentId,
310
+ module: moduleId,
311
+ description: `Found ${filterCount} filter control(s) in module ${moduleId}`,
312
+ });
313
+ } catch (filterError) {
314
+ findings.push({
315
+ id: `${this.agentId}-filter-error-${moduleId}`,
316
+ type: 'test-bug',
317
+ severity: 'medium',
318
+ agentId: this.agentId,
319
+ module: moduleId,
320
+ description: `Filter test failed in module ${moduleId}: ${filterError instanceof Error ? filterError.message.split('\n')[0] : String(filterError)}`,
321
+ });
322
+ }
323
+
324
+ return findings;
325
+ }
326
+ }