@wopr-network/platform-ui-core 1.27.7 → 1.27.9

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 (353) hide show
  1. package/next.config.ts +1 -2
  2. package/package.json +17 -17
  3. package/src/__tests__/account-switcher.test.tsx +21 -20
  4. package/src/__tests__/activity-page.test.tsx +2 -6
  5. package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
  6. package/src/__tests__/admin-api.test.ts +1 -6
  7. package/src/__tests__/admin-gpu-api.test.ts +1 -3
  8. package/src/__tests__/admin-marketplace-api.test.ts +1 -4
  9. package/src/__tests__/admin-middleware.test.ts +76 -83
  10. package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
  11. package/src/__tests__/api-401-redirect.test.ts +46 -9
  12. package/src/__tests__/api-client.test.ts +3 -5
  13. package/src/__tests__/api-config.test.ts +22 -42
  14. package/src/__tests__/api-fleet-resources.test.ts +1 -2
  15. package/src/__tests__/api-fleet-trpc.test.ts +2 -8
  16. package/src/__tests__/api-null-guards.test.ts +3 -1
  17. package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
  18. package/src/__tests__/auth-password-reset.test.tsx +7 -21
  19. package/src/__tests__/auth-redirect.test.tsx +8 -2
  20. package/src/__tests__/auth.test.tsx +25 -23
  21. package/src/__tests__/auto-topup-card.test.tsx +4 -12
  22. package/src/__tests__/backups-tab.test.tsx +3 -4
  23. package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
  24. package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
  25. package/src/__tests__/billing.test.tsx +8 -39
  26. package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
  27. package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
  28. package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
  29. package/src/__tests__/bot-settings-restart.test.tsx +1 -3
  30. package/src/__tests__/bot-settings.test.tsx +2 -6
  31. package/src/__tests__/brand.test.ts +6 -26
  32. package/src/__tests__/buy-credits-panel.test.tsx +1 -3
  33. package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
  34. package/src/__tests__/capability-conflicts.test.ts +2 -8
  35. package/src/__tests__/capability-resolver.test.tsx +2 -12
  36. package/src/__tests__/channel-wizard.test.tsx +4 -17
  37. package/src/__tests__/chat/chat-panel.test.tsx +1 -4
  38. package/src/__tests__/chat-store.test.ts +5 -15
  39. package/src/__tests__/command-center.test.tsx +10 -12
  40. package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
  41. package/src/__tests__/confirmation-tracker.test.tsx +3 -18
  42. package/src/__tests__/coupon-input.test.tsx +1 -3
  43. package/src/__tests__/create-instance.test.tsx +1 -3
  44. package/src/__tests__/credit-balance.test.tsx +4 -12
  45. package/src/__tests__/credits.test.tsx +32 -85
  46. package/src/__tests__/email-verification-banner.test.tsx +2 -6
  47. package/src/__tests__/error-boundaries.test.tsx +0 -1
  48. package/src/__tests__/fetch-pricing.test.ts +2 -1
  49. package/src/__tests__/field-oauth.test.tsx +2 -6
  50. package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
  51. package/src/__tests__/fixtures/mock-manifests.ts +2 -4
  52. package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
  53. package/src/__tests__/fleet-health-update.test.tsx +1 -8
  54. package/src/__tests__/gpu-dashboard.test.tsx +2 -6
  55. package/src/__tests__/instance-detail.test.tsx +3 -9
  56. package/src/__tests__/instance-list.test.tsx +1 -5
  57. package/src/__tests__/layout-snapshots.test.tsx +64 -11
  58. package/src/__tests__/marketplace-admin.test.tsx +2 -6
  59. package/src/__tests__/marketplace.test.tsx +11 -35
  60. package/src/__tests__/merge-api-rates.test.ts +1 -6
  61. package/src/__tests__/middleware.test.ts +32 -219
  62. package/src/__tests__/next-config-headers.test.ts +1 -3
  63. package/src/__tests__/notifications.test.tsx +4 -11
  64. package/src/__tests__/oauth-buttons.test.tsx +36 -59
  65. package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
  66. package/src/__tests__/observability.test.tsx +23 -36
  67. package/src/__tests__/onboarding-page.test.tsx +4 -6
  68. package/src/__tests__/org-billing-api.test.tsx +1 -6
  69. package/src/__tests__/plugin-install-flow.test.tsx +28 -58
  70. package/src/__tests__/plugin-registry.test.tsx +3 -11
  71. package/src/__tests__/plugin-tool-sync.test.ts +1 -3
  72. package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
  73. package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
  74. package/src/__tests__/portfolio-chart.test.tsx +2 -6
  75. package/src/__tests__/promotion-form.test.tsx +2 -6
  76. package/src/__tests__/promotions-list.test.tsx +1 -3
  77. package/src/__tests__/provider-key-api.test.ts +2 -1
  78. package/src/__tests__/resend-verification-button.test.tsx +8 -24
  79. package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
  80. package/src/__tests__/settings.test.tsx +11 -21
  81. package/src/__tests__/setup-checklist.test.tsx +3 -9
  82. package/src/__tests__/setup.ts +25 -6
  83. package/src/__tests__/snapshot-api.test.ts +2 -1
  84. package/src/__tests__/step-superpowers.test.tsx +1 -3
  85. package/src/__tests__/tenant-context.test.tsx +1 -6
  86. package/src/__tests__/tenant-keys-api.test.ts +3 -4
  87. package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
  88. package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
  89. package/src/__tests__/transaction-history.test.tsx +190 -238
  90. package/src/__tests__/trpc-types.test.ts +2 -6
  91. package/src/__tests__/use-chat.test.ts +1 -3
  92. package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
  93. package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
  94. package/src/__tests__/use-webmcp.test.ts +1 -3
  95. package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
  96. package/src/__tests__/verify-page.test.tsx +4 -13
  97. package/src/__tests__/verify-redirect.test.tsx +2 -6
  98. package/src/app/(auth)/error.tsx +1 -7
  99. package/src/app/(auth)/forgot-password/page.tsx +4 -18
  100. package/src/app/(auth)/login/page.tsx +5 -22
  101. package/src/app/(auth)/reset-password/page.tsx +2 -12
  102. package/src/app/(auth)/signup/page.tsx +10 -44
  103. package/src/app/(auth)/verify/page.tsx +47 -0
  104. package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
  105. package/src/app/(dashboard)/billing/error.tsx +2 -10
  106. package/src/app/(dashboard)/billing/layout.tsx +12 -62
  107. package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
  108. package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
  109. package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
  110. package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
  111. package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
  112. package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
  113. package/src/app/(dashboard)/changesets/error.tsx +1 -7
  114. package/src/app/(dashboard)/chat/page.tsx +2 -6
  115. package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
  116. package/src/app/(dashboard)/error.tsx +1 -7
  117. package/src/app/(dashboard)/layout.tsx +15 -36
  118. package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
  119. package/src/app/(dashboard)/marketplace/error.tsx +1 -7
  120. package/src/app/(dashboard)/marketplace/page.tsx +6 -27
  121. package/src/app/(dashboard)/not-found.tsx +2 -5
  122. package/src/app/(dashboard)/onboarding/page.tsx +5 -22
  123. package/src/app/(dashboard)/settings/account/page.tsx +1 -6
  124. package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
  125. package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
  126. package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
  127. package/src/app/(dashboard)/settings/error.tsx +2 -10
  128. package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
  129. package/src/app/(dashboard)/settings/org/page.tsx +13 -56
  130. package/src/app/(dashboard)/settings/page.tsx +1 -0
  131. package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
  132. package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
  133. package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
  134. package/src/app/(dashboard)/settings/security/page.tsx +31 -111
  135. package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
  136. package/src/app/admin/error.tsx +1 -7
  137. package/src/app/admin/fleet-updates/error.tsx +1 -7
  138. package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
  139. package/src/app/admin/layout.tsx +4 -0
  140. package/src/app/admin/payment-methods/page.tsx +9 -38
  141. package/src/app/admin/products/error.tsx +2 -7
  142. package/src/app/admin/products/page.tsx +1 -4
  143. package/src/app/admin/promotions/[id]/page.tsx +9 -38
  144. package/src/app/admin/promotions/page.tsx +9 -36
  145. package/src/app/admin/rate-overrides/page.tsx +9 -45
  146. package/src/app/auth/callback/[provider]/page.tsx +1 -8
  147. package/src/app/auth/verify/page.tsx +9 -36
  148. package/src/app/channels/error.tsx +2 -10
  149. package/src/app/channels/layout.tsx +9 -0
  150. package/src/app/channels/page.tsx +8 -20
  151. package/src/app/channels/setup/[plugin]/page.tsx +3 -5
  152. package/src/app/error.tsx +1 -7
  153. package/src/app/fleet/error.tsx +1 -7
  154. package/src/app/fleet/layout.tsx +5 -0
  155. package/src/app/fleet/settings/page.tsx +1 -3
  156. package/src/app/global-error.tsx +2 -10
  157. package/src/app/globals.css +1 -4
  158. package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
  159. package/src/app/instances/error.tsx +2 -10
  160. package/src/app/instances/instance-list-client.tsx +20 -69
  161. package/src/app/instances/layout.tsx +9 -0
  162. package/src/app/instances/new/create-instance-client.tsx +10 -31
  163. package/src/app/layout.tsx +2 -10
  164. package/src/app/not-found.tsx +1 -3
  165. package/src/app/page.tsx +1 -2
  166. package/src/app/plugins/error.tsx +2 -10
  167. package/src/app/plugins/layout.tsx +5 -0
  168. package/src/app/plugins/page.tsx +16 -48
  169. package/src/app/pricing/error.tsx +1 -7
  170. package/src/app/privacy/page.tsx +93 -150
  171. package/src/app/status/error.tsx +1 -7
  172. package/src/app/terms/page.tsx +89 -144
  173. package/src/components/account-switcher.tsx +25 -52
  174. package/src/components/admin/accounting-dashboard.tsx +1 -3
  175. package/src/components/admin/admin-guard.tsx +1 -3
  176. package/src/components/admin/admin-nav.tsx +1 -3
  177. package/src/components/admin/affiliate-dashboard.tsx +25 -94
  178. package/src/components/admin/audit-log-table.tsx +13 -49
  179. package/src/components/admin/billing-health-dashboard.tsx +7 -25
  180. package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
  181. package/src/components/admin/bulk-actions-bar.tsx +1 -3
  182. package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
  183. package/src/components/admin/bulk-export-dialog.tsx +6 -32
  184. package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
  185. package/src/components/admin/bulk-grant-dialog.tsx +4 -15
  186. package/src/components/admin/bulk-preview-dialog.tsx +3 -12
  187. package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
  188. package/src/components/admin/bulk-select-all-banner.tsx +1 -6
  189. package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
  190. package/src/components/admin/bulk-undo-toast.tsx +1 -2
  191. package/src/components/admin/compliance-dashboard.tsx +31 -101
  192. package/src/components/admin/gpu-dashboard.tsx +21 -70
  193. package/src/components/admin/grant-credits-dialog.tsx +4 -17
  194. package/src/components/admin/incident-dashboard.tsx +10 -25
  195. package/src/components/admin/inference-dashboard.tsx +14 -54
  196. package/src/components/admin/marketplace-admin.tsx +18 -60
  197. package/src/components/admin/migrations-dashboard.tsx +9 -42
  198. package/src/components/admin/onboarding-dashboard.tsx +14 -64
  199. package/src/components/admin/pool-config-dashboard.tsx +4 -10
  200. package/src/components/admin/products/fleet-form.tsx +2 -11
  201. package/src/components/admin/products/nav-editor.tsx +3 -10
  202. package/src/components/admin/promotions/promotion-form.tsx +9 -42
  203. package/src/components/admin/roles-dashboard.tsx +7 -34
  204. package/src/components/admin/suspend-dialog.tsx +4 -11
  205. package/src/components/admin/tenant-notes-panel.tsx +1 -3
  206. package/src/components/admin/tenant-row-actions.tsx +4 -20
  207. package/src/components/admin/tenant-table.tsx +12 -49
  208. package/src/components/auth/auth-redirect.tsx +11 -3
  209. package/src/components/auth/email-verification-result-banner.tsx +1 -3
  210. package/src/components/auth/resend-verification-button.tsx +2 -10
  211. package/src/components/auth/wopr-wordmark.tsx +1 -3
  212. package/src/components/billing/add-payment-method-dialog.tsx +1 -2
  213. package/src/components/billing/affiliate-dashboard.tsx +4 -16
  214. package/src/components/billing/amount-selector.tsx +1 -3
  215. package/src/components/billing/auto-topup-card.tsx +2 -11
  216. package/src/components/billing/buy-credits-panel.tsx +14 -17
  217. package/src/components/billing/byok-callout.tsx +6 -8
  218. package/src/components/billing/confirmation-tracker.tsx +4 -14
  219. package/src/components/billing/credit-balance-badge.tsx +22 -0
  220. package/src/components/billing/credit-balance.tsx +3 -9
  221. package/src/components/billing/crypto-checkout.tsx +5 -24
  222. package/src/components/billing/degraded-state-banner.tsx +1 -3
  223. package/src/components/billing/deposit-view.tsx +301 -41
  224. package/src/components/billing/dividend-banner.tsx +1 -3
  225. package/src/components/billing/dividend-eligibility.tsx +3 -12
  226. package/src/components/billing/dividend-pool-stats.tsx +6 -20
  227. package/src/components/billing/first-dividend-dialog.tsx +2 -2
  228. package/src/components/billing/org-billing-page.tsx +8 -31
  229. package/src/components/billing/payment-method-picker.tsx +2 -10
  230. package/src/components/billing/suspension-banner.tsx +2 -7
  231. package/src/components/billing/transaction-history.tsx +10 -58
  232. package/src/components/billing/unified-checkout.tsx +547 -0
  233. package/src/components/bot-settings/backups-tab.tsx +9 -33
  234. package/src/components/bot-settings/bot-settings-client.tsx +32 -134
  235. package/src/components/bot-settings/resources-tab.tsx +2 -9
  236. package/src/components/bot-settings/storage-tab.tsx +19 -48
  237. package/src/components/bot-settings/vps-info-panel.tsx +3 -11
  238. package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
  239. package/src/components/brand-hydrator.tsx +13 -0
  240. package/src/components/channel-wizard/field-interactive.tsx +1 -3
  241. package/src/components/channel-wizard/field-qr.tsx +10 -39
  242. package/src/components/channel-wizard/step-renderer.tsx +5 -28
  243. package/src/components/channel-wizard/wizard.tsx +6 -31
  244. package/src/components/chat/chat-message.tsx +1 -4
  245. package/src/components/chat/chat-panel.tsx +4 -18
  246. package/src/components/chat/chat-widget.tsx +3 -14
  247. package/src/components/dashboard/command-center.tsx +15 -61
  248. package/src/components/fleet/update-settings-card.tsx +7 -23
  249. package/src/components/instance-update-banner.tsx +130 -0
  250. package/src/components/instances/friends-tab.test.tsx +2 -9
  251. package/src/components/instances/friends-tab.tsx +18 -74
  252. package/src/components/instances/update-available-badge.tsx +2 -11
  253. package/src/components/landing/hero.tsx +3 -9
  254. package/src/components/landing/landing-page.tsx +1 -3
  255. package/src/components/landing/portfolio-chart.tsx +4 -9
  256. package/src/components/landing/story-sections.tsx +1 -3
  257. package/src/components/landing/terminal-sequence.tsx +4 -17
  258. package/src/components/marketplace/empty-state.tsx +2 -6
  259. package/src/components/marketplace/first-visit-hero.tsx +1 -3
  260. package/src/components/marketplace/install-wizard.tsx +20 -77
  261. package/src/components/marketplace/marketplace-tabs.tsx +1 -4
  262. package/src/components/marketplace/plugin-card.tsx +2 -9
  263. package/src/components/marketplace/superpower-content.tsx +1 -3
  264. package/src/components/marketplace/terminal-search.tsx +2 -8
  265. package/src/components/oauth-buttons.tsx +29 -14
  266. package/src/components/observability/fleet-health.tsx +5 -18
  267. package/src/components/observability/health-overview.tsx +7 -20
  268. package/src/components/observability/logs-viewer.tsx +8 -32
  269. package/src/components/observability/metrics-dashboard.tsx +2 -15
  270. package/src/components/onboarding/fallback-setup.tsx +6 -25
  271. package/src/components/onboarding/setup-checklist.tsx +18 -51
  272. package/src/components/onboarding/step-superpowers.tsx +1 -4
  273. package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
  274. package/src/components/pricing/dividend-calculator.tsx +6 -12
  275. package/src/components/pricing/dividend-stats.tsx +5 -17
  276. package/src/components/pricing/pricing-page.tsx +17 -36
  277. package/src/components/settings/create-org-wizard.tsx +2 -5
  278. package/src/components/sidebar.tsx +7 -42
  279. package/src/components/sidecar-frame.tsx +78 -0
  280. package/src/components/status/status-page.tsx +6 -28
  281. package/src/components/ui/alert-dialog.tsx +8 -25
  282. package/src/components/ui/badge.tsx +2 -8
  283. package/src/components/ui/banner.tsx +1 -6
  284. package/src/components/ui/card.tsx +5 -24
  285. package/src/components/ui/checkbox.tsx +1 -5
  286. package/src/components/ui/collapsible.tsx +3 -8
  287. package/src/components/ui/dialog.tsx +4 -10
  288. package/src/components/ui/dropdown-menu.tsx +9 -18
  289. package/src/components/ui/form.tsx +2 -16
  290. package/src/components/ui/popover.tsx +3 -23
  291. package/src/components/ui/progress.tsx +1 -5
  292. package/src/components/ui/radio-group.tsx +3 -15
  293. package/src/components/ui/select.tsx +4 -17
  294. package/src/components/ui/sheet.tsx +5 -19
  295. package/src/components/ui/skeleton.tsx +1 -7
  296. package/src/components/ui/table.tsx +5 -22
  297. package/src/components/ui/tabs.tsx +3 -13
  298. package/src/components/ui/tooltip.tsx +1 -1
  299. package/src/components/unified-sidebar.tsx +493 -0
  300. package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
  301. package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
  302. package/src/hooks/use-credit-balance.ts +27 -0
  303. package/src/hooks/use-my-org-role.ts +1 -3
  304. package/src/hooks/use-plugin-registry.ts +8 -14
  305. package/src/hooks/use-plugin-setup-chat.ts +2 -5
  306. package/src/hooks/use-sidecar-bridge.tsx +148 -0
  307. package/src/hooks/use-webmcp.ts +1 -4
  308. package/src/lib/__tests__/admin-api.test.ts +1 -3
  309. package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
  310. package/src/lib/__tests__/api-fetch.test.ts +4 -16
  311. package/src/lib/__tests__/org-billing-api.test.ts +1 -3
  312. package/src/lib/__tests__/pricing-data.test.ts +0 -8
  313. package/src/lib/__tests__/settings-api.test.ts +1 -3
  314. package/src/lib/admin-affiliate-api.ts +2 -7
  315. package/src/lib/admin-api.ts +6 -26
  316. package/src/lib/admin-incident-api.ts +11 -19
  317. package/src/lib/admin-marketplace-api.ts +1 -5
  318. package/src/lib/api-config.test.ts +5 -50
  319. package/src/lib/api.ts +143 -122
  320. package/src/lib/auth-client.ts +1 -2
  321. package/src/lib/bot-settings-data.ts +11 -36
  322. package/src/lib/brand-config.ts +56 -115
  323. package/src/lib/brand.ts +2 -15
  324. package/src/lib/chat/use-chat.ts +2 -7
  325. package/src/lib/cost-comparison-data.test.ts +1 -3
  326. package/src/lib/cost-comparison-data.ts +1 -4
  327. package/src/lib/errors.ts +1 -4
  328. package/src/lib/fetch-utils.test.ts +26 -9
  329. package/src/lib/fetch-utils.ts +40 -11
  330. package/src/lib/logger.ts +2 -0
  331. package/src/lib/marketplace-data.ts +3 -11
  332. package/src/lib/oauth-errors.ts +2 -4
  333. package/src/lib/onboarding-data.ts +3 -11
  334. package/src/lib/org-api.ts +2 -10
  335. package/src/lib/org-billing-api.ts +5 -19
  336. package/src/lib/plugin/tool-definitions.ts +1 -2
  337. package/src/lib/require-auth.ts +57 -0
  338. package/src/lib/settings-api.ts +1 -4
  339. package/src/lib/sidecar-routes.ts +43 -0
  340. package/src/lib/trpc-server.ts +49 -0
  341. package/src/lib/trpc-types.ts +4 -6
  342. package/src/lib/trpc.tsx +12 -4
  343. package/src/lib/validate-redirect-url.ts +1 -4
  344. package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
  345. package/src/lib/webmcp/register.ts +1 -4
  346. package/src/lib/webmcp/tools.ts +2 -9
  347. package/src/proxy.ts +35 -212
  348. package/src/types/missing-deps.d.ts +2 -8
  349. package/tsconfig.json +1 -8
  350. package/biome.json +0 -52
  351. package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
  352. package/src/__tests__/billing-byok-callout.test.tsx +0 -76
  353. package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +0 -112
@@ -26,9 +26,7 @@ vi.mock("@/lib/api", () => ({
26
26
  }));
27
27
 
28
28
  // Mock bot-settings-data with controlBot we can spy on
29
- const mockControlBot = vi
30
- .fn()
31
- .mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 100)));
29
+ const mockControlBot = vi.fn().mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 100)));
32
30
  const mockGetBotSettings = vi.fn().mockResolvedValue({
33
31
  id: "bot-1",
34
32
  identity: { name: "Test Bot", personality: "", avatar: "" },
@@ -335,9 +335,7 @@ describe("Channels tab", () => {
335
335
 
336
336
  await user.click(screen.getByRole("tab", { name: "Channels" }));
337
337
 
338
- expect(
339
- screen.getByText("Your Platform works everywhere you do. All channels are free."),
340
- ).toBeInTheDocument();
338
+ expect(screen.getByText("Your Platform works everywhere you do. All channels are free.")).toBeInTheDocument();
341
339
  });
342
340
  });
343
341
 
@@ -610,9 +608,7 @@ describe("Danger Zone tab", () => {
610
608
  describe("Error handling", () => {
611
609
  it("shows error when getBotSettings fails", async () => {
612
610
  const { getBotSettings } = await import("@/lib/bot-settings-data");
613
- vi.mocked(getBotSettings).mockRejectedValueOnce(
614
- new Error("API error: 500 Internal Server Error"),
615
- );
611
+ vi.mocked(getBotSettings).mockRejectedValueOnce(new Error("API error: 500 Internal Server Error"));
616
612
  const { BotSettingsClient } = await import("../components/bot-settings/bot-settings-client");
617
613
  render(<BotSettingsClient botId="bot-001" />);
618
614
  expect(await screen.findByText("API error: 500 Internal Server Error")).toBeInTheDocument();
@@ -78,15 +78,7 @@ describe("Brand Bible", () => {
78
78
 
79
79
  describe("Emotional arc", () => {
80
80
  it("defines feelings for all major page types", () => {
81
- const pages = [
82
- "landing",
83
- "onboarding",
84
- "dashboard",
85
- "marketplace",
86
- "billing",
87
- "settings",
88
- "fleet",
89
- ] as const;
81
+ const pages = ["landing", "onboarding", "dashboard", "marketplace", "billing", "settings", "fleet"] as const;
90
82
  for (const page of pages) {
91
83
  expect(typeof emotionalArc[page].feel).toBe("string");
92
84
  expect(typeof emotionalArc[page].job).toBe("string");
@@ -116,9 +108,9 @@ describe("Brand Bible", () => {
116
108
  expect(DOMAIN).toBe("localhost");
117
109
  });
118
110
 
119
- it("has a tagline", () => {
111
+ it("has a tagline (may be empty in default brand config)", () => {
120
112
  expect(typeof TAGLINE).toBe("string");
121
- expect(TAGLINE.length).toBeGreaterThan(0);
113
+ // Default brand config has empty tagline; specific brand deployments set it
122
114
  });
123
115
 
124
116
  it("defines the price from brand config", () => {
@@ -242,16 +234,12 @@ describe("Brand Bible", () => {
242
234
  });
243
235
 
244
236
  it("includes product name usage examples", () => {
245
- const hasNameExample = copyExamples.some(
246
- (e) => e.do.includes("Platform") || e.rule.includes("Platform"),
247
- );
237
+ const hasNameExample = copyExamples.some((e) => e.do.includes("Platform") || e.rule.includes("Platform"));
248
238
  expect(hasNameExample).toBe(true);
249
239
  });
250
240
 
251
241
  it("includes supercomputer angle", () => {
252
- const hasSupercomputer = copyExamples.some((e) =>
253
- e.do.toLowerCase().includes("supercomputer"),
254
- );
242
+ const hasSupercomputer = copyExamples.some((e) => e.do.toLowerCase().includes("supercomputer"));
255
243
  expect(hasSupercomputer).toBe(true);
256
244
  });
257
245
  });
@@ -304,15 +292,7 @@ describe("Brand Bible", () => {
304
292
 
305
293
  describe("Copy frameworks", () => {
306
294
  it("defines frameworks for all page types", () => {
307
- const pages = [
308
- "landing",
309
- "onboarding",
310
- "dashboard",
311
- "marketplace",
312
- "billing",
313
- "settings",
314
- "empty",
315
- ] as const;
295
+ const pages = ["landing", "onboarding", "dashboard", "marketplace", "billing", "settings", "empty"] as const;
316
296
  for (const page of pages) {
317
297
  expect(typeof copyFrameworks[page].headline).toBe("string");
318
298
  }
@@ -100,9 +100,7 @@ describe("BuyCreditsPanel", () => {
100
100
  mockGetCreditOptions.mockResolvedValue([]);
101
101
  render(<BuyCreditsPanel />);
102
102
 
103
- expect(
104
- await screen.findByText("Credit purchases are not available at this time."),
105
- ).toBeInTheDocument();
103
+ expect(await screen.findByText("Credit purchases are not available at this time.")).toBeInTheDocument();
106
104
  // Should NOT show retry button for intentionally empty tiers
107
105
  expect(screen.queryByRole("button", { name: "Try again" })).not.toBeInTheDocument();
108
106
  });
@@ -2,13 +2,11 @@ import { render, screen, waitFor } from "@testing-library/react";
2
2
  import userEvent from "@testing-library/user-event";
3
3
  import { afterEach, describe, expect, it, vi } from "vitest";
4
4
 
5
- const { mockCreateCheckout, mockGetSupportedPaymentMethods, mockGetChargeStatus } = vi.hoisted(
6
- () => ({
7
- mockCreateCheckout: vi.fn(),
8
- mockGetSupportedPaymentMethods: vi.fn(),
9
- mockGetChargeStatus: vi.fn(),
10
- }),
11
- );
5
+ const { mockCreateCheckout, mockGetSupportedPaymentMethods, mockGetChargeStatus } = vi.hoisted(() => ({
6
+ mockCreateCheckout: vi.fn(),
7
+ mockGetSupportedPaymentMethods: vi.fn(),
8
+ mockGetChargeStatus: vi.fn(),
9
+ }));
12
10
 
13
11
  vi.mock("@/lib/api", () => ({
14
12
  createCheckout: (...args: unknown[]) => mockCreateCheckout(...args),
@@ -17,6 +15,7 @@ vi.mock("@/lib/api", () => ({
17
15
  }));
18
16
 
19
17
  vi.mock("framer-motion", () => ({
18
+ AnimatePresence: ({ children }: React.PropsWithChildren<Record<string, unknown>>) => <>{children}</>,
20
19
  motion: {
21
20
  button: ({
22
21
  children,
@@ -51,28 +50,28 @@ vi.mock("better-auth/react", () => ({
51
50
  }),
52
51
  }));
53
52
 
54
- vi.mock("lucide-react", async (importOriginal) => {
55
- const actual = await importOriginal<typeof import("lucide-react")>();
56
- return {
57
- ...actual,
58
- Bitcoin: () => <span data-testid="bitcoin-icon" />,
59
- };
60
- });
53
+ vi.mock("qrcode.react", () => ({
54
+ QRCodeSVG: () => <div data-testid="qr-code" />,
55
+ }));
61
56
 
62
57
  const MOCK_USDC_METHOD = {
63
58
  id: "usdc:base",
64
59
  type: "erc20",
65
- label: "USDC on Base",
66
60
  token: "USDC",
67
61
  chain: "base",
62
+ displayName: "USDC on Base",
63
+ decimals: 6,
64
+ displayOrder: 1,
68
65
  iconUrl: "https://example.com/usdc.svg",
69
66
  };
70
67
  const MOCK_ETH_METHOD = {
71
68
  id: "eth:base",
72
69
  type: "native",
73
- label: "ETH on Base",
74
70
  token: "ETH",
75
71
  chain: "base",
72
+ displayName: "ETH on Base",
73
+ decimals: 18,
74
+ displayOrder: 2,
76
75
  iconUrl: "https://example.com/eth.svg",
77
76
  };
78
77
 
@@ -98,40 +97,61 @@ describe("BuyCryptoCreditPanel", () => {
98
97
  expect(screen.getByText("$100")).toBeInTheDocument();
99
98
  });
100
99
 
101
- it("Pay button is disabled when no amount selected", async () => {
100
+ it("Continue button is disabled when no amount selected", async () => {
102
101
  mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD, MOCK_ETH_METHOD]);
103
102
  const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
104
103
  render(<BuyCryptoCreditPanel />);
105
104
 
106
105
  await waitFor(() => {
107
- expect(screen.getByText("USDC")).toBeInTheDocument();
106
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
108
107
  });
109
108
 
110
- const payBtn = screen.getByRole("button", { name: "Pay with USDC" });
111
- expect(payBtn).toBeDisabled();
109
+ const continueBtn = screen.getByRole("button", { name: "Continue to payment" });
110
+ expect(continueBtn).toBeDisabled();
112
111
  });
113
112
 
114
- it("Pay button is enabled after selecting an amount", async () => {
113
+ it("Continue button is enabled after selecting an amount", async () => {
115
114
  mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD, MOCK_ETH_METHOD]);
116
115
  const user = userEvent.setup();
117
116
  const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
118
117
  render(<BuyCryptoCreditPanel />);
119
118
 
120
119
  await waitFor(() => {
121
- expect(screen.getByText("USDC")).toBeInTheDocument();
120
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
122
121
  });
123
122
 
124
123
  await user.click(screen.getByText("$25"));
125
- expect(screen.getByRole("button", { name: "Pay with USDC" })).toBeEnabled();
124
+ expect(screen.getByRole("button", { name: "Continue to payment" })).toBeEnabled();
126
125
  });
127
126
 
128
- it("calls createCheckout and shows deposit address", async () => {
127
+ it("shows payment method picker after selecting amount", async () => {
129
128
  mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD, MOCK_ETH_METHOD]);
129
+ const user = userEvent.setup();
130
+ const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
131
+ render(<BuyCryptoCreditPanel />);
132
+
133
+ await waitFor(() => {
134
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
135
+ });
136
+
137
+ await user.click(screen.getByText("$50"));
138
+ await user.click(screen.getByRole("button", { name: "Continue to payment" }));
139
+
140
+ await waitFor(() => {
141
+ expect(screen.getByText("USDC on Base")).toBeInTheDocument();
142
+ });
143
+ expect(screen.getByText("ETH on Base")).toBeInTheDocument();
144
+ });
145
+
146
+ it("calls createCheckout and shows deposit address", async () => {
147
+ mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD]);
130
148
  mockCreateCheckout.mockResolvedValue({
131
149
  depositAddress: "0xabc123def456",
132
150
  displayAmount: "50.000000 USDC",
151
+ amountUsd: 50,
133
152
  token: "USDC",
134
153
  chain: "base",
154
+ referenceId: "ref-123",
135
155
  });
136
156
 
137
157
  const user = userEvent.setup();
@@ -139,19 +159,27 @@ describe("BuyCryptoCreditPanel", () => {
139
159
  render(<BuyCryptoCreditPanel />);
140
160
 
141
161
  await waitFor(() => {
142
- expect(screen.getByText("USDC")).toBeInTheDocument();
162
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
143
163
  });
144
164
 
145
165
  await user.click(screen.getByText("$50"));
146
- await user.click(screen.getByRole("button", { name: "Pay with USDC" }));
166
+ await user.click(screen.getByRole("button", { name: "Continue to payment" }));
167
+
168
+ await waitFor(() => {
169
+ expect(screen.getByText("USDC on Base")).toBeInTheDocument();
170
+ });
171
+
172
+ await user.click(screen.getByText("USDC on Base"));
147
173
 
148
174
  expect(mockCreateCheckout).toHaveBeenCalledWith("usdc:base", 50);
149
- expect(await screen.findByText("0xabc123def456")).toBeInTheDocument();
175
+ await waitFor(() => {
176
+ expect(screen.getByText("0xabc123def456")).toBeInTheDocument();
177
+ });
150
178
  expect(screen.getByText("50.000000 USDC")).toBeInTheDocument();
151
179
  });
152
180
 
153
181
  it("shows Creating checkout... while checkout is in progress", async () => {
154
- mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD, MOCK_ETH_METHOD]);
182
+ mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD]);
155
183
  mockCreateCheckout.mockReturnValue(
156
184
  new Promise(() => {
157
185
  /* intentionally pending */
@@ -163,31 +191,21 @@ describe("BuyCryptoCreditPanel", () => {
163
191
  render(<BuyCryptoCreditPanel />);
164
192
 
165
193
  await waitFor(() => {
166
- expect(screen.getByText("USDC")).toBeInTheDocument();
194
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
167
195
  });
168
196
 
169
197
  await user.click(screen.getByText("$50"));
170
- await user.click(screen.getByRole("button", { name: "Pay with USDC" }));
171
-
172
- expect(await screen.findByText("Creating checkout...")).toBeInTheDocument();
173
- });
174
-
175
- it("shows error when checkout API call fails", async () => {
176
- mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD, MOCK_ETH_METHOD]);
177
- mockCreateCheckout.mockRejectedValue(new Error("API down"));
178
-
179
- const user = userEvent.setup();
180
- const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
181
- render(<BuyCryptoCreditPanel />);
198
+ await user.click(screen.getByRole("button", { name: "Continue to payment" }));
182
199
 
183
200
  await waitFor(() => {
184
- expect(screen.getByText("USDC")).toBeInTheDocument();
201
+ expect(screen.getByText("USDC on Base")).toBeInTheDocument();
185
202
  });
186
203
 
187
- await user.click(screen.getByText("$25"));
188
- await user.click(screen.getByRole("button", { name: "Pay with USDC" }));
204
+ await user.click(screen.getByText("USDC on Base"));
189
205
 
190
- expect(await screen.findByText("Checkout failed. Please try again.")).toBeInTheDocument();
206
+ await waitFor(() => {
207
+ expect(screen.getByText("Creating checkout...")).toBeInTheDocument();
208
+ });
191
209
  });
192
210
 
193
211
  it("hides panel when no payment methods available", async () => {
@@ -195,95 +213,40 @@ describe("BuyCryptoCreditPanel", () => {
195
213
  const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
196
214
  const { container } = render(<BuyCryptoCreditPanel />);
197
215
 
198
- // Component returns null when no methods
199
216
  await waitFor(() => {
200
217
  expect(container.innerHTML).toBe("");
201
218
  });
202
219
  });
203
220
 
204
- it("switches between payment methods", async () => {
221
+ it("renders icon for each payment method in picker", async () => {
205
222
  mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD, MOCK_ETH_METHOD]);
206
223
  const user = userEvent.setup();
207
224
  const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
208
225
  render(<BuyCryptoCreditPanel />);
209
226
 
210
227
  await waitFor(() => {
211
- expect(screen.getByText("USDC")).toBeInTheDocument();
228
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
212
229
  });
213
230
 
214
- // Default is first method (USDC)
215
- expect(screen.getByRole("button", { name: "Pay with USDC" })).toBeInTheDocument();
216
-
217
- // Switch to ETH
218
- await user.click(screen.getByText("ETH"));
219
- expect(screen.getByRole("button", { name: "Pay with ETH" })).toBeInTheDocument();
220
- });
221
-
222
- it("renders icon for each payment method", async () => {
223
- mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD, MOCK_ETH_METHOD]);
224
- const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
225
- render(<BuyCryptoCreditPanel />);
231
+ await user.click(screen.getByText("$25"));
232
+ await user.click(screen.getByRole("button", { name: "Continue to payment" }));
226
233
 
227
234
  await waitFor(() => {
228
- expect(screen.getByText("USDC")).toBeInTheDocument();
235
+ expect(screen.getByText("USDC on Base")).toBeInTheDocument();
229
236
  });
230
237
 
231
238
  const icons = screen.getAllByRole("img");
232
- expect(icons).toHaveLength(2);
239
+ expect(icons.length).toBeGreaterThanOrEqual(2);
233
240
  expect(icons[0]).toHaveAttribute("src", "https://example.com/usdc.svg");
234
241
  expect(icons[1]).toHaveAttribute("src", "https://example.com/eth.svg");
235
242
  });
236
243
 
237
- it("shows partial payment display", async () => {
238
- mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD]);
239
- mockCreateCheckout.mockResolvedValue({
240
- depositAddress: "0xabc123",
241
- displayAmount: "50.000000 USDC",
242
- token: "USDC",
243
- chain: "base",
244
- referenceId: "ref-123",
245
- });
246
- mockGetChargeStatus.mockResolvedValue({
247
- chargeId: "ch-1",
248
- status: "partial",
249
- amountExpectedCents: 5000,
250
- amountReceivedCents: 2500,
251
- confirmations: 0,
252
- confirmationsRequired: 6,
253
- credited: false,
254
- amountUsdCents: 5000,
255
- });
256
-
257
- const user = userEvent.setup();
258
- vi.useFakeTimers({ shouldAdvanceTime: true });
259
- const { BuyCryptoCreditPanel } = await import("../components/billing/buy-crypto-credits-panel");
260
- render(<BuyCryptoCreditPanel />);
261
-
262
- await waitFor(() => {
263
- expect(screen.getByText("USDC")).toBeInTheDocument();
264
- });
265
-
266
- await user.click(screen.getByText("$50"));
267
- await user.click(screen.getByRole("button", { name: "Pay with USDC" }));
268
-
269
- await waitFor(() => {
270
- expect(screen.getByText("0xabc123")).toBeInTheDocument();
271
- });
272
-
273
- vi.advanceTimersByTime(5000);
274
-
275
- await waitFor(() => {
276
- expect(screen.getByText(/Received \$25\.00 of \$50\.00/)).toBeInTheDocument();
277
- });
278
-
279
- vi.useRealTimers();
280
- });
281
-
282
- it("shows confirmation progress", async () => {
244
+ it("shows confirmation progress after payment received", async () => {
283
245
  mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD]);
284
246
  mockCreateCheckout.mockResolvedValue({
285
247
  depositAddress: "0xabc123",
286
248
  displayAmount: "50.000000 USDC",
249
+ amountUsd: 50,
287
250
  token: "USDC",
288
251
  chain: "base",
289
252
  referenceId: "ref-456",
@@ -305,11 +268,17 @@ describe("BuyCryptoCreditPanel", () => {
305
268
  render(<BuyCryptoCreditPanel />);
306
269
 
307
270
  await waitFor(() => {
308
- expect(screen.getByText("USDC")).toBeInTheDocument();
271
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
309
272
  });
310
273
 
311
274
  await user.click(screen.getByText("$50"));
312
- await user.click(screen.getByRole("button", { name: "Pay with USDC" }));
275
+ await user.click(screen.getByRole("button", { name: "Continue to payment" }));
276
+
277
+ await waitFor(() => {
278
+ expect(screen.getByText("USDC on Base")).toBeInTheDocument();
279
+ });
280
+
281
+ await user.click(screen.getByText("USDC on Base"));
313
282
 
314
283
  await waitFor(() => {
315
284
  expect(screen.getByText("0xabc123")).toBeInTheDocument();
@@ -318,17 +287,18 @@ describe("BuyCryptoCreditPanel", () => {
318
287
  vi.advanceTimersByTime(5000);
319
288
 
320
289
  await waitFor(() => {
321
- expect(screen.getByText(/Confirming \(3 of 6\)/)).toBeInTheDocument();
290
+ expect(screen.getByText("3 / 6")).toBeInTheDocument();
322
291
  });
323
292
 
324
293
  vi.useRealTimers();
325
294
  });
326
295
 
327
- it("shows expiry and Try Again button", async () => {
296
+ it("shows expired status", async () => {
328
297
  mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_USDC_METHOD]);
329
298
  mockCreateCheckout.mockResolvedValue({
330
299
  depositAddress: "0xabc123",
331
300
  displayAmount: "50.000000 USDC",
301
+ amountUsd: 50,
332
302
  token: "USDC",
333
303
  chain: "base",
334
304
  referenceId: "ref-789",
@@ -350,11 +320,17 @@ describe("BuyCryptoCreditPanel", () => {
350
320
  render(<BuyCryptoCreditPanel />);
351
321
 
352
322
  await waitFor(() => {
353
- expect(screen.getByText("USDC")).toBeInTheDocument();
323
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
354
324
  });
355
325
 
356
326
  await user.click(screen.getByText("$50"));
357
- await user.click(screen.getByRole("button", { name: "Pay with USDC" }));
327
+ await user.click(screen.getByRole("button", { name: "Continue to payment" }));
328
+
329
+ await waitFor(() => {
330
+ expect(screen.getByText("USDC on Base")).toBeInTheDocument();
331
+ });
332
+
333
+ await user.click(screen.getByText("USDC on Base"));
358
334
 
359
335
  await waitFor(() => {
360
336
  expect(screen.getByText("0xabc123")).toBeInTheDocument();
@@ -363,18 +339,18 @@ describe("BuyCryptoCreditPanel", () => {
363
339
  vi.advanceTimersByTime(5000);
364
340
 
365
341
  await waitFor(() => {
366
- expect(screen.getByText("Payment expired.")).toBeInTheDocument();
342
+ expect(screen.getByText("Payment expired")).toBeInTheDocument();
367
343
  });
368
- expect(screen.getByRole("button", { name: "Try Again" })).toBeInTheDocument();
369
344
 
370
345
  vi.useRealTimers();
371
346
  });
372
347
 
373
- it("calls createCheckout with methodId", async () => {
348
+ it("calls createCheckout with correct methodId and amount", async () => {
374
349
  mockGetSupportedPaymentMethods.mockResolvedValue([MOCK_ETH_METHOD]);
375
350
  mockCreateCheckout.mockResolvedValue({
376
351
  depositAddress: "0xdef456",
377
352
  displayAmount: "0.05 ETH",
353
+ amountUsd: 100,
378
354
  token: "ETH",
379
355
  chain: "base",
380
356
  referenceId: "ref-eth",
@@ -385,11 +361,17 @@ describe("BuyCryptoCreditPanel", () => {
385
361
  render(<BuyCryptoCreditPanel />);
386
362
 
387
363
  await waitFor(() => {
388
- expect(screen.getByText("ETH")).toBeInTheDocument();
364
+ expect(screen.getByText("Pay with Crypto")).toBeInTheDocument();
389
365
  });
390
366
 
391
367
  await user.click(screen.getByText("$100"));
392
- await user.click(screen.getByRole("button", { name: "Pay with ETH" }));
368
+ await user.click(screen.getByRole("button", { name: "Continue to payment" }));
369
+
370
+ await waitFor(() => {
371
+ expect(screen.getByText("ETH on Base")).toBeInTheDocument();
372
+ });
373
+
374
+ await user.click(screen.getByText("ETH on Base"));
393
375
 
394
376
  expect(mockCreateCheckout).toHaveBeenCalledWith("eth:base", 100);
395
377
  });
@@ -2,9 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import type { PluginManifest } from "../lib/marketplace-data";
3
3
  import { detectCapabilityConflictsClient } from "../lib/marketplace-data";
4
4
 
5
- const makePlugin = (
6
- overrides: Partial<PluginManifest> & { id: string; name: string },
7
- ): PluginManifest => ({
5
+ const makePlugin = (overrides: Partial<PluginManifest> & { id: string; name: string }): PluginManifest => ({
8
6
  description: "",
9
7
  version: "1.0.0",
10
8
  author: "Test",
@@ -43,11 +41,7 @@ const allPlugins = [ttsPlugin, sttPlugin, discordPlugin, anotherTts];
43
41
 
44
42
  describe("detectCapabilityConflictsClient", () => {
45
43
  it("returns empty array when no conflicts", () => {
46
- const conflicts = detectCapabilityConflictsClient(
47
- discordPlugin,
48
- ["elevenlabs-tts"],
49
- allPlugins,
50
- );
44
+ const conflicts = detectCapabilityConflictsClient(discordPlugin, ["elevenlabs-tts"], allPlugins);
51
45
  expect(conflicts).toEqual([]);
52
46
  });
53
47
 
@@ -101,11 +101,7 @@ describe("CapabilityProviderPicker", () => {
101
101
  it("renders hosted/BYOK options only for capabilities with hostedProvider", () => {
102
102
  const onChoose = vi.fn();
103
103
  render(
104
- <CapabilityProviderPicker
105
- capabilities={["transcription", "llm", "webhook"]}
106
- choices={{}}
107
- onChoose={onChoose}
108
- />,
104
+ <CapabilityProviderPicker capabilities={["transcription", "llm", "webhook"]} choices={{}} onChoose={onChoose} />,
109
105
  );
110
106
 
111
107
  expect(screen.getByText("Transcription")).toBeInTheDocument();
@@ -119,13 +115,7 @@ describe("CapabilityProviderPicker", () => {
119
115
  it("defaults to hosted and calls onChoose when BYOK clicked", async () => {
120
116
  const user = userEvent.setup();
121
117
  const onChoose = vi.fn();
122
- render(
123
- <CapabilityProviderPicker
124
- capabilities={["transcription"]}
125
- choices={{}}
126
- onChoose={onChoose}
127
- />,
128
- );
118
+ render(<CapabilityProviderPicker capabilities={["transcription"]} choices={{}} onChoose={onChoose} />);
129
119
 
130
120
  await user.click(screen.getByText("Use your key"));
131
121
  expect(onChoose).toHaveBeenCalledWith("transcription", "byok");
@@ -5,11 +5,7 @@ import { FieldInteractive } from "@/components/channel-wizard/field-interactive"
5
5
  import { FieldPaste } from "@/components/channel-wizard/field-paste";
6
6
  import { StepRenderer } from "@/components/channel-wizard/step-renderer";
7
7
  import type { SetupStep } from "@/lib/channel-manifests";
8
- import {
9
- CHANNEL_MANIFESTS_FIXTURE,
10
- DISCORD_MANIFEST,
11
- TELEGRAM_MANIFEST,
12
- } from "./fixtures/mock-manifests";
8
+ import { CHANNEL_MANIFESTS_FIXTURE, DISCORD_MANIFEST, TELEGRAM_MANIFEST } from "./fixtures/mock-manifests";
13
9
 
14
10
  // Mock @/lib/channel-manifests to use fixture data (sync for Wizard component tests)
15
11
  vi.mock("@/lib/channel-manifests", async () => {
@@ -17,9 +13,7 @@ vi.mock("@/lib/channel-manifests", async () => {
17
13
  return {
18
14
  ...actual,
19
15
  getChannelManifests: vi.fn().mockResolvedValue(CHANNEL_MANIFESTS_FIXTURE),
20
- getManifest: vi
21
- .fn()
22
- .mockImplementation(async (id: string) => CHANNEL_MANIFESTS_FIXTURE.find((m) => m.id === id)),
16
+ getManifest: vi.fn().mockImplementation(async (id: string) => CHANNEL_MANIFESTS_FIXTURE.find((m) => m.id === id)),
23
17
  };
24
18
  });
25
19
 
@@ -58,12 +52,7 @@ describe("channel-manifests", () => {
58
52
  const { getManifest } = await import("@/lib/channel-manifests");
59
53
  const discord = await getManifest("discord");
60
54
  expect(discord?.setup).toHaveLength(4);
61
- expect(discord?.setup.map((s) => s.id)).toEqual([
62
- "create-bot",
63
- "paste-token",
64
- "select-guild",
65
- "done",
66
- ]);
55
+ expect(discord?.setup.map((s) => s.id)).toEqual(["create-bot", "paste-token", "select-guild", "done"]);
67
56
  });
68
57
 
69
58
  it("Telegram manifest has secret token field with paste flow", async () => {
@@ -480,9 +469,7 @@ describe("Wizard connection test API integration", () => {
480
469
  });
481
470
 
482
471
  await waitFor(() => {
483
- expect(
484
- screen.getByText("Could not reach the server. Check your connection."),
485
- ).toBeInTheDocument();
472
+ expect(screen.getByText("Could not reach the server. Check your connection.")).toBeInTheDocument();
486
473
  });
487
474
  });
488
475
 
@@ -48,10 +48,7 @@ describe("ChatPanel", () => {
48
48
  });
49
49
 
50
50
  it("renders message list with user and bot messages", () => {
51
- const messages = [
52
- msg({ role: "user", content: "Question?" }),
53
- msg({ role: "bot", content: "Answer!" }),
54
- ];
51
+ const messages = [msg({ role: "user", content: "Question?" }), msg({ role: "bot", content: "Answer!" })];
55
52
  render(<ChatPanel {...baseProps} messages={messages} />);
56
53
  expect(screen.getByText("Question?")).toBeInTheDocument();
57
54
  expect(screen.getByText("Answer!")).toBeInTheDocument();