@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,311 @@
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
+ { id: 'tasks', route: '/tasks', sidebarIcon: true },
22
+ ],
23
+ environments: {
24
+ alpha: { baseUrl: 'http://localhost:3000', seed: false },
25
+ },
26
+ portals: [],
27
+ breakpoints: [],
28
+ integrations: [],
29
+ workers: [],
30
+ workflows: [],
31
+ accuracy: { enabled: false, decimalPrecision: 2, currencySymbol: '$', timezone: 'UTC' },
32
+ tenancy: { enabled: false, isolationField: 'firmId', testFirms: [] },
33
+ costBudget: { maxPerRun: 100, maxPerAgent: 10, alertThreshold: 0.8, onExceeded: 'abort' },
34
+ agentClassification: { blocking: [], advisory: [27] },
35
+ thresholds: {
36
+ unitCoverage: { lines: 80, functions: 80, branches: 80, statements: 80 },
37
+ lighthouse: { accessibility: 90, performance: 90, bestPractices: 90, seo: 90 },
38
+ apiResponseTime: 2000,
39
+ bundleSizeLimit: 500000,
40
+ maxConsoleErrors: 0,
41
+ },
42
+ disabledAgents: [],
43
+ disabledAgentSet: new Set<number>(),
44
+ ...overrides,
45
+ };
46
+ }
47
+
48
+ // ---------------------------------------------------------------------------
49
+ // Mock fetch
50
+ // ---------------------------------------------------------------------------
51
+
52
+ const fetchMock = vi.fn();
53
+ vi.stubGlobal('fetch', fetchMock);
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Mock helpers
57
+ // ---------------------------------------------------------------------------
58
+
59
+ const loginMock = vi.fn().mockResolvedValue(undefined);
60
+
61
+ vi.mock('../../helpers/navigation', () => ({
62
+ login: (...args: unknown[]) => loginMock(...args),
63
+ waitForSectionLoad: vi.fn().mockResolvedValue(undefined),
64
+ navigateToSection: vi.fn().mockResolvedValue(undefined),
65
+ switchPortal: vi.fn().mockResolvedValue(undefined),
66
+ }));
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Mock Playwright
70
+ // ---------------------------------------------------------------------------
71
+
72
+ interface MockLocator {
73
+ count: ReturnType<typeof vi.fn>;
74
+ first: ReturnType<typeof vi.fn>;
75
+ nth: ReturnType<typeof vi.fn>;
76
+ click: ReturnType<typeof vi.fn>;
77
+ fill: ReturnType<typeof vi.fn>;
78
+ evaluate: ReturnType<typeof vi.fn>;
79
+ selectOption: ReturnType<typeof vi.fn>;
80
+ locator: ReturnType<typeof vi.fn>;
81
+ getAttribute: ReturnType<typeof vi.fn>;
82
+ }
83
+
84
+ function makeMockLocator(countVal = 0): MockLocator {
85
+ const locator: MockLocator = {
86
+ count: vi.fn().mockResolvedValue(countVal),
87
+ first: vi.fn(),
88
+ nth: vi.fn(),
89
+ click: vi.fn().mockResolvedValue(undefined),
90
+ fill: vi.fn().mockResolvedValue(undefined),
91
+ evaluate: vi.fn().mockResolvedValue('div'),
92
+ selectOption: vi.fn().mockResolvedValue(undefined),
93
+ locator: vi.fn().mockReturnValue({ count: vi.fn().mockResolvedValue(0), nth: vi.fn(), getAttribute: vi.fn() }),
94
+ getAttribute: vi.fn().mockResolvedValue(null),
95
+ };
96
+ locator.first.mockReturnValue(locator);
97
+ locator.nth.mockReturnValue(locator);
98
+ return locator;
99
+ }
100
+
101
+ interface MockPage {
102
+ close: ReturnType<typeof vi.fn>;
103
+ goto: ReturnType<typeof vi.fn>;
104
+ locator: ReturnType<typeof vi.fn>;
105
+ waitForTimeout: ReturnType<typeof vi.fn>;
106
+ }
107
+
108
+ function makeMockPage(): MockPage {
109
+ const defaultLocator = makeMockLocator(0);
110
+ return {
111
+ close: vi.fn().mockResolvedValue(undefined),
112
+ goto: vi.fn().mockResolvedValue(undefined),
113
+ locator: vi.fn().mockReturnValue(defaultLocator),
114
+ waitForTimeout: vi.fn().mockResolvedValue(undefined),
115
+ };
116
+ }
117
+
118
+ let currentMockPage: MockPage;
119
+ let mockBrowser: { newPage: ReturnType<typeof vi.fn>; close: ReturnType<typeof vi.fn> };
120
+
121
+ vi.mock('playwright', async () => ({
122
+ chromium: {
123
+ launch: vi.fn().mockImplementation(async () => mockBrowser),
124
+ },
125
+ }));
126
+
127
+ // ---------------------------------------------------------------------------
128
+ // Dynamic import AFTER mocks are hoisted
129
+ // ---------------------------------------------------------------------------
130
+
131
+ const { SearchFilterTesterAgent } = await import('../27-search-filter-tester');
132
+
133
+ function createAgent(
134
+ config: ValidatedConfig = makeConfig(),
135
+ phase: Phase = 'beta',
136
+ ): InstanceType<typeof SearchFilterTesterAgent> {
137
+ return new SearchFilterTesterAgent(config, phase, '/tmp/test-run');
138
+ }
139
+
140
+ // ---------------------------------------------------------------------------
141
+ // Tests
142
+ // ---------------------------------------------------------------------------
143
+
144
+ describe('SearchFilterTesterAgent', () => {
145
+ beforeEach(() => {
146
+ fetchMock.mockReset().mockResolvedValue({ ok: true, status: 200 });
147
+ loginMock.mockReset().mockResolvedValue(undefined);
148
+
149
+ currentMockPage = makeMockPage();
150
+ mockBrowser = {
151
+ newPage: vi.fn().mockResolvedValue(currentMockPage),
152
+ close: vi.fn().mockResolvedValue(undefined),
153
+ };
154
+ });
155
+
156
+ // Identity
157
+ it('has agentId 27 and correct agentName', () => {
158
+ const agent = createAgent();
159
+ expect(agent.agentId).toBe(27);
160
+ expect(agent.agentName).toBe('Search & Filter Tester');
161
+ });
162
+
163
+ // preFlight
164
+ it('throws when modules array is empty', async () => {
165
+ const config = makeConfig({ modules: [] });
166
+ const agent = createAgent(config);
167
+ const result = await agent.run();
168
+
169
+ expect(result.status).toBe('failed');
170
+ expect(result.findings[0].description).toContain('module');
171
+ });
172
+
173
+ it('resolves environment in preFlight', async () => {
174
+ const agent = createAgent();
175
+ const result = await agent.run();
176
+ expect(result.findings.every(f => !f.description.includes('preFlight'))).toBe(true);
177
+ });
178
+
179
+ // No search or filter found
180
+ it('produces low finding when no search or filter UI found', async () => {
181
+ const agent = createAgent();
182
+ const result = await agent.run();
183
+
184
+ const noSearchFilter = result.findings.filter(f => f.description.includes('No search or filter'));
185
+ expect(noSearchFilter.length).toBeGreaterThan(0);
186
+ expect(noSearchFilter[0].severity).toBe('low');
187
+ });
188
+
189
+ // Search found and tested
190
+ it('tests search functionality when search input exists', async () => {
191
+ const searchLocator = makeMockLocator(1);
192
+ const noResultsLocator = makeMockLocator(0);
193
+
194
+ currentMockPage.locator.mockImplementation((sel: string) => {
195
+ if (sel.includes('search') || sel.includes('find') || sel.includes('searchbox'))
196
+ return searchLocator;
197
+ if (sel.includes('no results') || sel.includes('empty'))
198
+ return noResultsLocator;
199
+ return makeMockLocator(0);
200
+ });
201
+
202
+ const agent = createAgent();
203
+ const result = await agent.run();
204
+
205
+ // Search fill should have been called
206
+ expect(searchLocator.fill).toHaveBeenCalled();
207
+ });
208
+
209
+ // Search not filtering
210
+ it('produces medium finding when gibberish search still shows items', async () => {
211
+ const searchLocator = makeMockLocator(1);
212
+ const listLocator = makeMockLocator(5); // 5 list items still showing
213
+ const noResultsLocator = makeMockLocator(0);
214
+
215
+ currentMockPage.locator.mockImplementation((sel: string) => {
216
+ if (sel.includes('search') || sel.includes('find') || sel.includes('searchbox'))
217
+ return searchLocator;
218
+ if (sel.includes('no results') || sel.includes('not found') || sel.includes('empty'))
219
+ return noResultsLocator;
220
+ if (sel.includes('tr,') || sel.includes('list-item') || sel.includes('card'))
221
+ return listLocator;
222
+ return makeMockLocator(0);
223
+ });
224
+
225
+ const agent = createAgent();
226
+ const result = await agent.run();
227
+
228
+ const searchFinding = result.findings.find(f => f.description.includes('Search may not be filtering'));
229
+ expect(searchFinding).toBeDefined();
230
+ expect(searchFinding!.severity).toBe('medium');
231
+ });
232
+
233
+ // Filter found
234
+ it('reports filter controls when found', async () => {
235
+ const filterLocator = makeMockLocator(2);
236
+ filterLocator.evaluate.mockResolvedValue('select');
237
+ const optionLocator = makeMockLocator(3);
238
+ optionLocator.nth = vi.fn().mockReturnValue({ getAttribute: vi.fn().mockResolvedValue('val1') });
239
+ filterLocator.locator.mockReturnValue(optionLocator);
240
+
241
+ currentMockPage.locator.mockImplementation((sel: string) => {
242
+ if (sel.includes('select') || sel.includes('combobox') || sel.includes('Filter') || sel.includes('filter'))
243
+ return filterLocator;
244
+ return makeMockLocator(0);
245
+ });
246
+
247
+ const agent = createAgent();
248
+ const result = await agent.run();
249
+
250
+ const filterFinding = result.findings.find(f => f.description.includes('filter control'));
251
+ expect(filterFinding).toBeDefined();
252
+ });
253
+
254
+ // Login failure
255
+ it('produces medium finding and continues when login fails', async () => {
256
+ loginMock.mockRejectedValue(new Error('Invalid credentials'));
257
+
258
+ const agent = createAgent();
259
+ const result = await agent.run();
260
+
261
+ const loginFinding = result.findings.find(f => f.id.includes('login-failed'));
262
+ expect(loginFinding).toBeDefined();
263
+ expect(loginFinding!.severity).toBe('medium');
264
+ });
265
+
266
+ // No credentials
267
+ it('produces medium finding when no credentials configured', async () => {
268
+ const config = makeConfig({
269
+ auth: { loginUrl: 'http://localhost/login', credentials: {} },
270
+ });
271
+ const agent = createAgent(config);
272
+ const result = await agent.run();
273
+
274
+ const noCredsFinding = result.findings.find(f => f.id.includes('no-credentials'));
275
+ expect(noCredsFinding).toBeDefined();
276
+ });
277
+
278
+ // Playwright crash
279
+ it('produces medium finding when Playwright crashes', async () => {
280
+ mockBrowser.newPage.mockRejectedValue(new Error('Browser crashed'));
281
+
282
+ const agent = createAgent();
283
+ const result = await agent.run();
284
+
285
+ const pwFinding = result.findings.find(f => f.id.includes('playwright-failure'));
286
+ expect(pwFinding).toBeDefined();
287
+ expect(pwFinding!.severity).toBe('medium');
288
+ });
289
+
290
+ // Navigation failure
291
+ it('produces medium finding when module navigation fails', async () => {
292
+ currentMockPage.goto.mockRejectedValue(new Error('Navigation failed'));
293
+
294
+ const agent = createAgent();
295
+ const result = await agent.run();
296
+
297
+ const navFinding = result.findings.find(f => f.id.includes('nav-failed'));
298
+ expect(navFinding).toBeDefined();
299
+ expect(navFinding!.severity).toBe('medium');
300
+ });
301
+
302
+ // Browser closed in finally
303
+ it('closes browser even when an error occurs', async () => {
304
+ mockBrowser.newPage.mockRejectedValue(new Error('Launch error'));
305
+
306
+ const agent = createAgent();
307
+ await agent.run();
308
+
309
+ expect(mockBrowser.close).toHaveBeenCalled();
310
+ });
311
+ });
@@ -0,0 +1,328 @@
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
+ { id: 'tasks', route: '/tasks', sidebarIcon: true },
22
+ { id: 'settings', route: '/settings', sidebarIcon: false },
23
+ ],
24
+ environments: {
25
+ alpha: { baseUrl: 'http://localhost:3000', seed: false },
26
+ },
27
+ portals: [],
28
+ breakpoints: [],
29
+ integrations: [],
30
+ workers: [],
31
+ workflows: [],
32
+ accuracy: { enabled: false, decimalPrecision: 2, currencySymbol: '$', timezone: 'UTC' },
33
+ tenancy: { enabled: false, isolationField: 'firmId', testFirms: [] },
34
+ costBudget: { maxPerRun: 100, maxPerAgent: 10, alertThreshold: 0.8, onExceeded: 'abort' },
35
+ agentClassification: { blocking: [], advisory: [28] },
36
+ thresholds: {
37
+ unitCoverage: { lines: 80, functions: 80, branches: 80, statements: 80 },
38
+ lighthouse: { accessibility: 90, performance: 90, bestPractices: 90, seo: 90 },
39
+ apiResponseTime: 2000,
40
+ bundleSizeLimit: 500000,
41
+ maxConsoleErrors: 0,
42
+ },
43
+ disabledAgents: [],
44
+ disabledAgentSet: new Set<number>(),
45
+ ...overrides,
46
+ };
47
+ }
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Mock fetch
51
+ // ---------------------------------------------------------------------------
52
+
53
+ const fetchMock = vi.fn();
54
+ vi.stubGlobal('fetch', fetchMock);
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // Mock helpers
58
+ // ---------------------------------------------------------------------------
59
+
60
+ const loginMock = vi.fn().mockResolvedValue(undefined);
61
+
62
+ vi.mock('../../helpers/navigation', () => ({
63
+ login: (...args: unknown[]) => loginMock(...args),
64
+ waitForSectionLoad: vi.fn().mockResolvedValue(undefined),
65
+ navigateToSection: vi.fn().mockResolvedValue(undefined),
66
+ switchPortal: vi.fn().mockResolvedValue(undefined),
67
+ }));
68
+
69
+ // ---------------------------------------------------------------------------
70
+ // Mock Playwright
71
+ // ---------------------------------------------------------------------------
72
+
73
+ interface MockLocator {
74
+ count: ReturnType<typeof vi.fn>;
75
+ innerText: ReturnType<typeof vi.fn>;
76
+ evaluateAll: ReturnType<typeof vi.fn>;
77
+ }
78
+
79
+ function makeMockLocator(countVal = 0, text = 'Content'): MockLocator {
80
+ return {
81
+ count: vi.fn().mockResolvedValue(countVal),
82
+ innerText: vi.fn().mockResolvedValue(text),
83
+ evaluateAll: vi.fn().mockResolvedValue([]),
84
+ };
85
+ }
86
+
87
+ interface MockPage {
88
+ close: ReturnType<typeof vi.fn>;
89
+ goto: ReturnType<typeof vi.fn>;
90
+ url: ReturnType<typeof vi.fn>;
91
+ locator: ReturnType<typeof vi.fn>;
92
+ goBack: ReturnType<typeof vi.fn>;
93
+ goForward: ReturnType<typeof vi.fn>;
94
+ }
95
+
96
+ function makeMockPage(urlOverride?: string): MockPage {
97
+ return {
98
+ close: vi.fn().mockResolvedValue(undefined),
99
+ goto: vi.fn().mockResolvedValue(undefined),
100
+ url: vi.fn().mockReturnValue(urlOverride ?? 'http://localhost:3000/dashboard'),
101
+ locator: vi.fn().mockReturnValue(makeMockLocator(0, 'Page Content')),
102
+ goBack: vi.fn().mockResolvedValue(undefined),
103
+ goForward: vi.fn().mockResolvedValue(undefined),
104
+ };
105
+ }
106
+
107
+ let currentMockPage: MockPage;
108
+ let mockBrowser: {
109
+ newPage: ReturnType<typeof vi.fn>;
110
+ close: ReturnType<typeof vi.fn>;
111
+ newContext: ReturnType<typeof vi.fn>;
112
+ };
113
+
114
+ function makeMockIncognitoPage(url?: string): MockPage {
115
+ return makeMockPage(url ?? 'http://localhost:3000/login');
116
+ }
117
+
118
+ vi.mock('playwright', async () => ({
119
+ chromium: {
120
+ launch: vi.fn().mockImplementation(async () => mockBrowser),
121
+ },
122
+ }));
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // Dynamic import AFTER mocks are hoisted
126
+ // ---------------------------------------------------------------------------
127
+
128
+ const { NavigationRoutingTesterAgent } = await import('../28-navigation-routing-tester');
129
+
130
+ function createAgent(
131
+ config: ValidatedConfig = makeConfig(),
132
+ phase: Phase = 'beta',
133
+ ): InstanceType<typeof NavigationRoutingTesterAgent> {
134
+ return new NavigationRoutingTesterAgent(config, phase, '/tmp/test-run');
135
+ }
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // Tests
139
+ // ---------------------------------------------------------------------------
140
+
141
+ describe('NavigationRoutingTesterAgent', () => {
142
+ beforeEach(() => {
143
+ fetchMock.mockReset().mockResolvedValue({ ok: true, status: 200 });
144
+ loginMock.mockReset().mockResolvedValue(undefined);
145
+
146
+ currentMockPage = makeMockPage();
147
+
148
+ const incognitoPage = makeMockIncognitoPage();
149
+ const incognitoContext = {
150
+ newPage: vi.fn().mockResolvedValue(incognitoPage),
151
+ close: vi.fn().mockResolvedValue(undefined),
152
+ };
153
+
154
+ mockBrowser = {
155
+ newPage: vi.fn().mockResolvedValue(currentMockPage),
156
+ close: vi.fn().mockResolvedValue(undefined),
157
+ newContext: vi.fn().mockResolvedValue(incognitoContext),
158
+ };
159
+ });
160
+
161
+ // Identity
162
+ it('has agentId 28 and correct agentName', () => {
163
+ const agent = createAgent();
164
+ expect(agent.agentId).toBe(28);
165
+ expect(agent.agentName).toBe('Navigation & Routing Tester');
166
+ });
167
+
168
+ // preFlight
169
+ it('throws when modules array is empty', async () => {
170
+ const config = makeConfig({ modules: [] });
171
+ const agent = createAgent(config);
172
+ const result = await agent.run();
173
+
174
+ expect(result.status).toBe('failed');
175
+ expect(result.findings[0].description).toContain('module');
176
+ });
177
+
178
+ // Sidebar navigation — happy path
179
+ it('navigates to each sidebar module without findings on success', async () => {
180
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0, 'Page Content'));
181
+
182
+ const agent = createAgent();
183
+ const result = await agent.run();
184
+
185
+ // Should not produce sidebar blank page findings
186
+ const sidebarBlank = result.findings.filter(f => f.id.includes('sidebar-blank'));
187
+ expect(sidebarBlank.length).toBe(0);
188
+ });
189
+
190
+ // Sidebar navigation — blank page
191
+ it('produces medium finding when sidebar navigation results in blank page', async () => {
192
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0, ''));
193
+
194
+ const agent = createAgent();
195
+ const result = await agent.run();
196
+
197
+ const blankFindings = result.findings.filter(f => f.id.includes('sidebar-blank'));
198
+ expect(blankFindings.length).toBeGreaterThan(0);
199
+ expect(blankFindings[0].severity).toBe('medium');
200
+ });
201
+
202
+ // 404 handling — app shows 404 page
203
+ it('produces no finding when app properly handles 404 routes', async () => {
204
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0, 'Page not found'));
205
+
206
+ const agent = createAgent();
207
+ const result = await agent.run();
208
+
209
+ const notFoundFindings = result.findings.filter(f => f.id.includes('404'));
210
+ expect(notFoundFindings.length).toBe(0);
211
+ });
212
+
213
+ // 404 handling — blank page
214
+ it('produces high finding when 404 route shows blank page', async () => {
215
+ // URL stays on fake route, body is empty
216
+ currentMockPage.url.mockReturnValue('http://localhost:3000/this-page-does-not-exist-12345');
217
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0, ''));
218
+
219
+ const agent = createAgent();
220
+ const result = await agent.run();
221
+
222
+ const blankFindings = result.findings.filter(f => f.id === '28-404-blank');
223
+ expect(blankFindings.length).toBe(1);
224
+ expect(blankFindings[0].severity).toBe('high');
225
+ });
226
+
227
+ // Protected routes — redirects to login (good)
228
+ it('produces no critical finding when protected routes redirect to login', async () => {
229
+ // Incognito page URL returns /login — correct behavior
230
+ const incognitoPage = makeMockIncognitoPage('http://localhost:3000/login');
231
+ const incognitoContext = {
232
+ newPage: vi.fn().mockResolvedValue(incognitoPage),
233
+ close: vi.fn().mockResolvedValue(undefined),
234
+ };
235
+ mockBrowser.newContext.mockResolvedValue(incognitoContext);
236
+
237
+ const agent = createAgent();
238
+ const result = await agent.run();
239
+
240
+ const unprotectedFindings = result.findings.filter(f => f.id.includes('unprotected'));
241
+ expect(unprotectedFindings.length).toBe(0);
242
+ });
243
+
244
+ // Protected routes — accessible without auth (critical)
245
+ it('produces critical finding when module is accessible without authentication', async () => {
246
+ // Incognito page stays on original URL with content
247
+ const incognitoPage = makeMockPage('http://localhost:3000/dashboard');
248
+ incognitoPage.locator.mockReturnValue(makeMockLocator(0, 'Sensitive data visible'));
249
+ const incognitoContext = {
250
+ newPage: vi.fn().mockResolvedValue(incognitoPage),
251
+ close: vi.fn().mockResolvedValue(undefined),
252
+ };
253
+ mockBrowser.newContext.mockResolvedValue(incognitoContext);
254
+
255
+ const agent = createAgent();
256
+ const result = await agent.run();
257
+
258
+ const unprotectedFindings = result.findings.filter(f => f.id.includes('unprotected'));
259
+ expect(unprotectedFindings.length).toBeGreaterThan(0);
260
+ expect(unprotectedFindings[0].severity).toBe('critical');
261
+ });
262
+
263
+ // Link integrity — all links work
264
+ it('produces no findings when all internal links load correctly', async () => {
265
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0, 'Page Content'));
266
+
267
+ const agent = createAgent();
268
+ const result = await agent.run();
269
+
270
+ const brokenLinkFindings = result.findings.filter(f => f.id.includes('broken-link'));
271
+ expect(brokenLinkFindings.length).toBe(0);
272
+ });
273
+
274
+ // Back/forward navigation — success
275
+ it('produces no findings when back/forward works correctly', async () => {
276
+ let callCount = 0;
277
+ currentMockPage.url.mockImplementation(() => {
278
+ callCount++;
279
+ // After goBack, return first module URL; after goForward, return second
280
+ if (callCount <= 2) return 'http://localhost:3000/dashboard';
281
+ return 'http://localhost:3000/tasks';
282
+ });
283
+
284
+ currentMockPage.locator.mockReturnValue(makeMockLocator(0, 'Page Content'));
285
+
286
+ const agent = createAgent();
287
+ const result = await agent.run();
288
+
289
+ const historyFindings = result.findings.filter(f =>
290
+ f.id.includes('back-nav') || f.id.includes('forward-nav'),
291
+ );
292
+ expect(historyFindings.length).toBe(0);
293
+ });
294
+
295
+ // Login failure — graceful degradation
296
+ it('produces medium finding and continues when login fails', async () => {
297
+ loginMock.mockRejectedValue(new Error('Invalid credentials'));
298
+
299
+ const agent = createAgent();
300
+ const result = await agent.run();
301
+
302
+ const loginFinding = result.findings.find(f => f.id.includes('login-failed'));
303
+ expect(loginFinding).toBeDefined();
304
+ expect(loginFinding!.severity).toBe('medium');
305
+ });
306
+
307
+ // Playwright crash
308
+ it('produces medium finding when Playwright crashes', async () => {
309
+ mockBrowser.newPage.mockRejectedValue(new Error('Browser crashed'));
310
+
311
+ const agent = createAgent();
312
+ const result = await agent.run();
313
+
314
+ const pwFinding = result.findings.find(f => f.id.includes('playwright-failure'));
315
+ expect(pwFinding).toBeDefined();
316
+ expect(pwFinding!.severity).toBe('medium');
317
+ });
318
+
319
+ // Browser closed in finally
320
+ it('closes browser even when an error occurs', async () => {
321
+ mockBrowser.newPage.mockRejectedValue(new Error('Launch error'));
322
+
323
+ const agent = createAgent();
324
+ await agent.run();
325
+
326
+ expect(mockBrowser.close).toHaveBeenCalled();
327
+ });
328
+ });