@elizaos/cli 1.0.8 → 1.0.10

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 (242) hide show
  1. package/README.md +9 -16
  2. package/dist/assets/{index-CZAd5zm2.js → index-CmuPnu0u.js} +72 -89
  3. package/dist/assets/index-CmuPnu0u.js.br +0 -0
  4. package/dist/assets/index-CmuPnu0u.js.map +1 -0
  5. package/dist/assets/{index-CaEsCLCC.js → index-DDQnwxzL.js} +28798 -16391
  6. package/dist/assets/{index-CaEsCLCC.js.map → index-DDQnwxzL.js.map} +1 -1
  7. package/dist/assets/index-Df1AFSuJ.css +1 -0
  8. package/dist/assets/index-Df1AFSuJ.css.br +0 -0
  9. package/dist/assets/vendor-DSdxb8P-.js.map +1 -1
  10. package/dist/{chunk-REBZFQYE.js → chunk-7HYEGM5V.js} +967 -1597
  11. package/dist/{chunk-W3HS2NP6.js → chunk-B4KJXECB.js} +13 -18
  12. package/dist/{chunk-33BHGAF7.js → chunk-GWQB7PBK.js} +59 -32
  13. package/dist/{chunk-CVADLFW6.js → chunk-LQ6XHF53.js} +4543 -3043
  14. package/dist/{chunk-GYTAJJOD.js → chunk-RIAWNDYI.js} +16 -2
  15. package/dist/{chunk-IEKLJDUU.js → chunk-WS4DWCDZ.js} +54 -32
  16. package/dist/commands/agent/actions/index.d.ts +5 -1
  17. package/dist/commands/agent/actions/index.js +5 -4
  18. package/dist/commands/agent/index.js +3 -4
  19. package/dist/commands/create/actions/index.js +4 -5
  20. package/dist/commands/create/index.js +5 -6
  21. package/dist/{fileFromPath-DCRQMDLJ.js → fileFromPath-KB6XMTJ4.js} +1 -0
  22. package/dist/index.html +2 -2
  23. package/dist/index.js +9346 -102098
  24. package/dist/{migrator-KZLCVEIH.js → migrator-JREQPDN3.js} +42 -220
  25. package/dist/pglite.data +0 -0
  26. package/dist/pglite.wasm +0 -0
  27. package/dist/plugin-creator-T4K2673C.js +910 -0
  28. package/dist/{registry-XFOSZFU4.js → registry-CBMRMYCG.js} +3 -4
  29. package/dist/templates/plugin-starter/README.md +255 -0
  30. package/dist/templates/plugin-starter/bunfig.toml +6 -0
  31. package/dist/templates/plugin-starter/cypress.config.ts +18 -0
  32. package/dist/templates/plugin-starter/index.html +13 -0
  33. package/dist/templates/plugin-starter/package.json +95 -0
  34. package/dist/templates/plugin-starter/postcss.config.js +3 -0
  35. package/dist/templates/plugin-starter/scripts/test-e2e-manual.js +201 -0
  36. package/dist/templates/plugin-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +404 -0
  37. package/dist/templates/plugin-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +287 -0
  38. package/dist/templates/plugin-starter/src/__tests__/cypress/support/commands.ts +38 -0
  39. package/dist/templates/plugin-starter/src/__tests__/cypress/support/component-index.html +11 -0
  40. package/dist/templates/plugin-starter/src/__tests__/cypress/support/component.ts +33 -0
  41. package/dist/templates/plugin-starter/src/__tests__/cypress/support/e2e.ts +11 -0
  42. package/dist/templates/plugin-starter/src/__tests__/cypress/tsconfig.json +10 -0
  43. package/dist/templates/plugin-starter/src/__tests__/e2e/README.md +47 -0
  44. package/dist/templates/plugin-starter/src/__tests__/e2e/starter-plugin.ts +320 -0
  45. package/{templates/plugin-starter → dist/templates/plugin-starter/src}/__tests__/integration.test.ts +22 -17
  46. package/{templates/plugin-starter → dist/templates/plugin-starter/src}/__tests__/plugin.test.ts +8 -8
  47. package/{templates/plugin-starter → dist/templates/plugin-starter/src}/__tests__/test-utils.ts +17 -17
  48. package/dist/templates/plugin-starter/src/frontend/index.css +77 -0
  49. package/dist/templates/plugin-starter/src/frontend/index.tsx +164 -0
  50. package/dist/templates/plugin-starter/src/frontend/utils.ts +6 -0
  51. package/dist/templates/plugin-starter/src/index.ts +274 -0
  52. package/dist/templates/plugin-starter/src/tests.ts +6 -0
  53. package/dist/templates/plugin-starter/tailwind.config.js +62 -0
  54. package/dist/templates/plugin-starter/tsconfig.build.json +11 -0
  55. package/dist/templates/plugin-starter/tsconfig.json +28 -0
  56. package/dist/templates/plugin-starter/tsup.config.ts +20 -0
  57. package/dist/templates/plugin-starter/vite.config.ts +20 -0
  58. package/dist/templates/project-starter/.env.example +153 -0
  59. package/dist/templates/project-starter/README.md +109 -0
  60. package/dist/templates/project-starter/bunfig.toml +6 -0
  61. package/dist/templates/project-starter/cypress.config.ts +31 -0
  62. package/dist/templates/project-starter/index.html +13 -0
  63. package/dist/templates/project-starter/package.json +83 -0
  64. package/dist/templates/project-starter/postcss.config.js +3 -0
  65. package/dist/templates/project-starter/scripts/test-all.sh +101 -0
  66. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/actions.test.ts +6 -6
  67. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/character.test.ts +3 -3
  68. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/config.test.ts +18 -18
  69. package/dist/templates/project-starter/src/__tests__/cypress/component/Accessibility.cy.tsx +271 -0
  70. package/dist/templates/project-starter/src/__tests__/cypress/component/ApiIntegration.cy.tsx +220 -0
  71. package/dist/templates/project-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +146 -0
  72. package/dist/templates/project-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +51 -0
  73. package/dist/templates/project-starter/src/__tests__/cypress/e2e/agent-chat.cy.ts +235 -0
  74. package/dist/templates/project-starter/src/__tests__/cypress/e2e/dashboard.cy.ts +146 -0
  75. package/dist/templates/project-starter/src/__tests__/cypress/e2e/user-workflow.cy.ts +257 -0
  76. package/dist/templates/project-starter/src/__tests__/cypress/support/commands.ts +44 -0
  77. package/dist/templates/project-starter/src/__tests__/cypress/support/component-index.html +11 -0
  78. package/dist/templates/project-starter/src/__tests__/cypress/support/component.ts +33 -0
  79. package/dist/templates/project-starter/src/__tests__/cypress/support/e2e.ts +179 -0
  80. package/dist/templates/project-starter/src/__tests__/e2e/index.ts +14 -0
  81. package/dist/templates/project-starter/src/__tests__/e2e/natural-language.test.ts +246 -0
  82. package/dist/templates/project-starter/src/__tests__/e2e/project.test.ts +155 -0
  83. package/dist/templates/project-starter/src/__tests__/e2e/starter-plugin.test.ts +421 -0
  84. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/env.test.ts +2 -2
  85. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/error-handling.test.ts +17 -17
  86. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/events.test.ts +7 -7
  87. package/dist/templates/project-starter/src/__tests__/file-structure.test.ts +135 -0
  88. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/integration.test.ts +25 -25
  89. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/models.test.ts +6 -6
  90. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/plugin.test.ts +9 -9
  91. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/provider.test.ts +7 -7
  92. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/routes.test.ts +3 -3
  93. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/test-utils.ts +17 -17
  94. package/{templates/project-starter → dist/templates/project-starter/src}/__tests__/utils/core-test-utils.ts +3 -3
  95. package/dist/templates/project-starter/src/frontend/index.css +77 -0
  96. package/dist/templates/project-starter/src/frontend/index.html +19 -0
  97. package/dist/templates/project-starter/src/frontend/index.tsx +98 -0
  98. package/dist/templates/project-starter/src/frontend/utils.ts +6 -0
  99. package/dist/templates/project-starter/src/index.ts +153 -0
  100. package/dist/templates/project-starter/src/plugin.ts +255 -0
  101. package/dist/templates/project-starter/tailwind.config.js +62 -0
  102. package/dist/templates/project-starter/tsconfig.build.json +20 -0
  103. package/dist/templates/project-starter/tsconfig.json +39 -0
  104. package/dist/templates/project-starter/tsup.config.ts +19 -0
  105. package/dist/templates/project-starter/vite.config.ts +39 -0
  106. package/dist/templates/project-tee-starter/.dockerignore +20 -0
  107. package/dist/templates/project-tee-starter/.env.example +55 -0
  108. package/dist/templates/project-tee-starter/Dockerfile +66 -0
  109. package/dist/templates/project-tee-starter/GUIDE.md +235 -0
  110. package/dist/templates/project-tee-starter/README.md +173 -0
  111. package/dist/templates/project-tee-starter/__tests__/actions.test.ts +9 -0
  112. package/dist/templates/project-tee-starter/__tests__/character.test.ts +86 -0
  113. package/dist/templates/project-tee-starter/__tests__/config.test.ts +31 -0
  114. package/dist/templates/project-tee-starter/__tests__/env.test.ts +87 -0
  115. package/dist/templates/project-tee-starter/__tests__/error-handling.test.ts +30 -0
  116. package/dist/templates/project-tee-starter/__tests__/events.test.ts +21 -0
  117. package/{templates/project-starter → dist/templates/project-tee-starter}/__tests__/file-structure.test.ts +6 -6
  118. package/dist/templates/project-tee-starter/__tests__/integration.test.ts +205 -0
  119. package/dist/templates/project-tee-starter/__tests__/models.test.ts +22 -0
  120. package/dist/templates/project-tee-starter/__tests__/plugin.test.ts +38 -0
  121. package/dist/templates/project-tee-starter/__tests__/provider.test.ts +189 -0
  122. package/dist/templates/project-tee-starter/__tests__/routes.test.ts +21 -0
  123. package/dist/templates/project-tee-starter/__tests__/test-utils.ts +121 -0
  124. package/dist/templates/project-tee-starter/__tests__/utils/core-test-utils.ts +167 -0
  125. package/dist/templates/project-tee-starter/assets/mr-tee-portrait.jpg +0 -0
  126. package/dist/templates/project-tee-starter/bunfig.toml +6 -0
  127. package/dist/templates/project-tee-starter/docker-compose.yaml +57 -0
  128. package/dist/templates/project-tee-starter/e2e/project.test.ts +38 -0
  129. package/dist/templates/project-tee-starter/e2e/starter-plugin.test.ts +92 -0
  130. package/dist/templates/project-tee-starter/package.json +74 -0
  131. package/dist/templates/project-tee-starter/src/character.ts +257 -0
  132. package/dist/templates/project-tee-starter/src/index.ts +33 -0
  133. package/dist/templates/project-tee-starter/src/plugin.ts +169 -0
  134. package/dist/templates/project-tee-starter/tsconfig.build.json +13 -0
  135. package/dist/templates/project-tee-starter/tsconfig.json +30 -0
  136. package/dist/templates/project-tee-starter/tsup.config.ts +19 -0
  137. package/dist/{utils-DIZZ3HNZ.js → utils-TIALZU53.js} +9 -8
  138. package/package.json +29 -12
  139. package/templates/plugin-starter/README.md +38 -13
  140. package/templates/plugin-starter/bunfig.toml +6 -0
  141. package/templates/plugin-starter/cypress.config.ts +18 -0
  142. package/templates/plugin-starter/index.html +13 -0
  143. package/templates/plugin-starter/package.json +19 -7
  144. package/templates/plugin-starter/postcss.config.js +3 -0
  145. package/templates/plugin-starter/scripts/test-e2e-manual.js +201 -0
  146. package/templates/plugin-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +404 -0
  147. package/templates/plugin-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +287 -0
  148. package/templates/plugin-starter/src/__tests__/cypress/support/commands.ts +38 -0
  149. package/templates/plugin-starter/src/__tests__/cypress/support/component-index.html +11 -0
  150. package/templates/plugin-starter/src/__tests__/cypress/support/component.ts +33 -0
  151. package/templates/plugin-starter/src/__tests__/cypress/support/e2e.ts +11 -0
  152. package/templates/plugin-starter/src/__tests__/cypress/tsconfig.json +10 -0
  153. package/templates/plugin-starter/src/__tests__/e2e/README.md +47 -0
  154. package/templates/plugin-starter/src/__tests__/e2e/starter-plugin.ts +320 -0
  155. package/templates/plugin-starter/src/__tests__/integration.test.ts +138 -0
  156. package/templates/plugin-starter/src/__tests__/plugin.test.ts +182 -0
  157. package/templates/plugin-starter/src/__tests__/test-utils.ts +162 -0
  158. package/templates/plugin-starter/src/frontend/index.css +77 -0
  159. package/templates/plugin-starter/src/frontend/index.tsx +164 -0
  160. package/templates/plugin-starter/src/frontend/utils.ts +6 -0
  161. package/templates/plugin-starter/src/index.ts +31 -8
  162. package/templates/plugin-starter/src/tests.ts +6 -0
  163. package/templates/plugin-starter/tailwind.config.js +62 -0
  164. package/templates/plugin-starter/tsconfig.json +8 -8
  165. package/templates/plugin-starter/vite.config.ts +20 -0
  166. package/templates/project-starter/bunfig.toml +6 -0
  167. package/templates/project-starter/cypress.config.ts +31 -0
  168. package/templates/project-starter/index.html +13 -0
  169. package/templates/project-starter/package.json +37 -14
  170. package/templates/project-starter/postcss.config.js +3 -0
  171. package/templates/project-starter/scripts/test-all.sh +101 -0
  172. package/templates/project-starter/src/__tests__/actions.test.ts +155 -0
  173. package/templates/project-starter/src/__tests__/character.test.ts +86 -0
  174. package/templates/project-starter/src/__tests__/config.test.ts +193 -0
  175. package/templates/project-starter/src/__tests__/cypress/component/Accessibility.cy.tsx +271 -0
  176. package/templates/project-starter/src/__tests__/cypress/component/ApiIntegration.cy.tsx +220 -0
  177. package/templates/project-starter/src/__tests__/cypress/component/ExampleRoute.cy.tsx +146 -0
  178. package/templates/project-starter/src/__tests__/cypress/component/PanelComponent.cy.tsx +51 -0
  179. package/templates/project-starter/src/__tests__/cypress/e2e/agent-chat.cy.ts +235 -0
  180. package/templates/project-starter/src/__tests__/cypress/e2e/dashboard.cy.ts +146 -0
  181. package/templates/project-starter/src/__tests__/cypress/e2e/user-workflow.cy.ts +257 -0
  182. package/templates/project-starter/src/__tests__/cypress/support/commands.ts +44 -0
  183. package/templates/project-starter/src/__tests__/cypress/support/component-index.html +11 -0
  184. package/templates/project-starter/src/__tests__/cypress/support/component.ts +33 -0
  185. package/templates/project-starter/src/__tests__/cypress/support/e2e.ts +179 -0
  186. package/templates/project-starter/src/__tests__/e2e/index.ts +14 -0
  187. package/templates/project-starter/src/__tests__/e2e/natural-language.test.ts +246 -0
  188. package/templates/project-starter/src/__tests__/e2e/project.test.ts +155 -0
  189. package/templates/project-starter/src/__tests__/e2e/starter-plugin.test.ts +421 -0
  190. package/templates/project-starter/src/__tests__/env.test.ts +87 -0
  191. package/templates/project-starter/src/__tests__/error-handling.test.ts +177 -0
  192. package/templates/project-starter/src/__tests__/events.test.ts +144 -0
  193. package/templates/project-starter/src/__tests__/file-structure.test.ts +135 -0
  194. package/templates/project-starter/src/__tests__/integration.test.ts +209 -0
  195. package/templates/project-starter/src/__tests__/models.test.ts +152 -0
  196. package/templates/project-starter/src/__tests__/plugin.test.ts +393 -0
  197. package/templates/project-starter/src/__tests__/provider.test.ts +325 -0
  198. package/templates/project-starter/src/__tests__/routes.test.ts +79 -0
  199. package/templates/project-starter/src/__tests__/test-utils.ts +121 -0
  200. package/templates/project-starter/src/__tests__/utils/core-test-utils.ts +180 -0
  201. package/templates/project-starter/src/frontend/index.css +77 -0
  202. package/templates/project-starter/src/frontend/index.html +19 -0
  203. package/templates/project-starter/src/frontend/index.tsx +98 -0
  204. package/templates/project-starter/src/frontend/utils.ts +6 -0
  205. package/templates/project-starter/src/index.ts +9 -1
  206. package/templates/project-starter/tailwind.config.js +62 -0
  207. package/templates/project-starter/tsconfig.build.json +9 -2
  208. package/templates/project-starter/tsconfig.json +15 -6
  209. package/templates/project-starter/tsup.config.ts +1 -1
  210. package/templates/project-starter/vite.config.ts +39 -0
  211. package/templates/project-tee-starter/__tests__/actions.test.ts +1 -1
  212. package/templates/project-tee-starter/__tests__/character.test.ts +1 -1
  213. package/templates/project-tee-starter/__tests__/config.test.ts +1 -1
  214. package/templates/project-tee-starter/__tests__/env.test.ts +2 -2
  215. package/templates/project-tee-starter/__tests__/error-handling.test.ts +1 -1
  216. package/templates/project-tee-starter/__tests__/events.test.ts +1 -1
  217. package/templates/project-tee-starter/__tests__/file-structure.test.ts +5 -5
  218. package/templates/project-tee-starter/__tests__/integration.test.ts +22 -26
  219. package/templates/project-tee-starter/__tests__/models.test.ts +1 -1
  220. package/templates/project-tee-starter/__tests__/plugin.test.ts +6 -12
  221. package/templates/project-tee-starter/__tests__/provider.test.ts +6 -6
  222. package/templates/project-tee-starter/__tests__/routes.test.ts +1 -1
  223. package/templates/project-tee-starter/__tests__/test-utils.ts +15 -15
  224. package/templates/project-tee-starter/__tests__/utils/core-test-utils.ts +3 -3
  225. package/templates/project-tee-starter/bunfig.toml +6 -0
  226. package/templates/project-tee-starter/package.json +10 -12
  227. package/dist/assets/index-CZAd5zm2.js.br +0 -0
  228. package/dist/assets/index-CZAd5zm2.js.map +0 -1
  229. package/dist/assets/index-DyA-lndn.css +0 -1
  230. package/dist/assets/index-DyA-lndn.css.br +0 -0
  231. package/dist/chunk-CEE6RKN5.js +0 -2746
  232. package/dist/chunk-MA2ZXPG6.js +0 -260
  233. package/dist/chunk-TUAYJIF2.js +0 -3649
  234. package/dist/lib-NAGYZHVV.js +0 -9
  235. package/dist/plugin-creator-IC42XOHG.js +0 -29165
  236. package/templates/plugin-starter/e2e/starter-plugin.test.ts +0 -171
  237. package/templates/plugin-starter/images/README.md +0 -24
  238. package/templates/plugin-starter/vitest.config.ts +0 -16
  239. package/templates/project-starter/e2e/project.test.ts +0 -34
  240. package/templates/project-starter/e2e/starter-plugin.test.ts +0 -217
  241. package/templates/project-starter/vitest.config.ts +0 -16
  242. package/templates/project-tee-starter/vitest.config.ts +0 -19
@@ -0,0 +1,271 @@
1
+ import React from 'react';
2
+ import '../../../frontend/index.css';
3
+
4
+ /**
5
+ * Example accessible form component
6
+ */
7
+ const AccessibleForm: React.FC<{ onSubmit: (data: any) => void }> = ({ onSubmit }) => {
8
+ const [formData, setFormData] = React.useState({
9
+ name: '',
10
+ email: '',
11
+ message: '',
12
+ });
13
+ const [errors, setErrors] = React.useState<Record<string, string>>({});
14
+
15
+ const handleSubmit = (e: React.FormEvent) => {
16
+ e.preventDefault();
17
+ const newErrors: Record<string, string> = {};
18
+
19
+ if (!formData.name) newErrors.name = 'Name is required';
20
+ if (!formData.email) newErrors.email = 'Email is required';
21
+ if (formData.email && !formData.email.includes('@')) {
22
+ newErrors.email = 'Please enter a valid email';
23
+ }
24
+
25
+ if (Object.keys(newErrors).length > 0) {
26
+ setErrors(newErrors);
27
+ return;
28
+ }
29
+
30
+ onSubmit(formData);
31
+ };
32
+
33
+ return (
34
+ <form onSubmit={handleSubmit} className="space-y-4 p-4">
35
+ <h1 className="text-2xl font-bold">Contact Agent</h1>
36
+
37
+ <div>
38
+ <label htmlFor="name" className="block text-sm font-medium mb-1">
39
+ Name{' '}
40
+ <span className="text-red-500" aria-label="required">
41
+ *
42
+ </span>
43
+ </label>
44
+ <input
45
+ id="name"
46
+ type="text"
47
+ value={formData.name}
48
+ onChange={(e) => setFormData({ ...formData, name: e.target.value })}
49
+ aria-invalid={!!errors.name}
50
+ aria-describedby={errors.name ? 'name-error' : undefined}
51
+ className="w-full px-3 py-2 border rounded-md"
52
+ />
53
+ {errors.name && (
54
+ <p id="name-error" role="alert" className="text-red-500 text-sm mt-1">
55
+ {errors.name}
56
+ </p>
57
+ )}
58
+ </div>
59
+
60
+ <div>
61
+ <label htmlFor="email" className="block text-sm font-medium mb-1">
62
+ Email{' '}
63
+ <span className="text-red-500" aria-label="required">
64
+ *
65
+ </span>
66
+ </label>
67
+ <input
68
+ id="email"
69
+ type="email"
70
+ value={formData.email}
71
+ onChange={(e) => setFormData({ ...formData, email: e.target.value })}
72
+ aria-invalid={!!errors.email}
73
+ aria-describedby={errors.email ? 'email-error' : undefined}
74
+ className="w-full px-3 py-2 border rounded-md"
75
+ />
76
+ {errors.email && (
77
+ <p id="email-error" role="alert" className="text-red-500 text-sm mt-1">
78
+ {errors.email}
79
+ </p>
80
+ )}
81
+ </div>
82
+
83
+ <div>
84
+ <label htmlFor="message" className="block text-sm font-medium mb-1">
85
+ Message
86
+ </label>
87
+ <textarea
88
+ id="message"
89
+ value={formData.message}
90
+ onChange={(e) => setFormData({ ...formData, message: e.target.value })}
91
+ rows={4}
92
+ className="w-full px-3 py-2 border rounded-md"
93
+ />
94
+ </div>
95
+
96
+ <button
97
+ type="submit"
98
+ className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
99
+ >
100
+ Send Message
101
+ </button>
102
+ </form>
103
+ );
104
+ };
105
+
106
+ describe('Accessibility Tests', () => {
107
+ describe('Form Accessibility', () => {
108
+ it('should have proper labels for all form fields', () => {
109
+ cy.mount(<AccessibleForm onSubmit={cy.stub()} />);
110
+
111
+ // Check that labels are properly associated
112
+ cy.get('label[for="name"]').should('exist');
113
+ cy.get('label[for="email"]').should('exist');
114
+ cy.get('label[for="message"]').should('exist');
115
+
116
+ // Check that inputs have matching IDs
117
+ cy.get('input#name').should('exist');
118
+ cy.get('input#email').should('exist');
119
+ cy.get('textarea#message').should('exist');
120
+ });
121
+
122
+ it('should indicate required fields', () => {
123
+ cy.mount(<AccessibleForm onSubmit={cy.stub()} />);
124
+
125
+ // Check for required field indicators
126
+ cy.get('label[for="name"]').within(() => {
127
+ cy.get('[aria-label="required"]').should('exist');
128
+ });
129
+ cy.get('label[for="email"]').within(() => {
130
+ cy.get('[aria-label="required"]').should('exist');
131
+ });
132
+ });
133
+
134
+ it('should show accessible error messages', () => {
135
+ cy.mount(<AccessibleForm onSubmit={cy.stub()} />);
136
+
137
+ // Submit empty form
138
+ cy.get('button[type="submit"]').click();
139
+
140
+ // Check error messages have proper ARIA attributes
141
+ cy.get('#name-error').should('have.attr', 'role', 'alert');
142
+ cy.get('#email-error').should('have.attr', 'role', 'alert');
143
+
144
+ // Check inputs are marked as invalid
145
+ cy.get('input#name').should('have.attr', 'aria-invalid', 'true');
146
+ cy.get('input#email').should('have.attr', 'aria-invalid', 'true');
147
+
148
+ // Check aria-describedby links errors to inputs
149
+ cy.get('input#name').should('have.attr', 'aria-describedby', 'name-error');
150
+ cy.get('input#email').should('have.attr', 'aria-describedby', 'email-error');
151
+ });
152
+
153
+ it('should be keyboard navigable', () => {
154
+ cy.mount(<AccessibleForm onSubmit={cy.stub()} />);
155
+
156
+ // Verify all form elements can receive focus
157
+ cy.get('input#name').focus();
158
+ cy.focused().should('have.attr', 'id', 'name');
159
+
160
+ cy.get('input#email').focus();
161
+ cy.focused().should('have.attr', 'id', 'email');
162
+
163
+ cy.get('textarea#message').focus();
164
+ cy.focused().should('have.attr', 'id', 'message');
165
+
166
+ cy.get('button[type="submit"]').focus();
167
+ cy.focused().should('contain', 'Send Message');
168
+
169
+ // Verify tabindex is not preventing keyboard access
170
+ cy.get('input, textarea, button').should('not.have.attr', 'tabindex', '-1');
171
+ });
172
+
173
+ it('should have proper focus indicators', () => {
174
+ cy.mount(<AccessibleForm onSubmit={cy.stub()} />);
175
+
176
+ // Check focus ring on button
177
+ cy.get('button[type="submit"]').focus();
178
+ cy.get('button[type="submit"]').should('have.class', 'focus:ring-2');
179
+ });
180
+ });
181
+
182
+ describe('Color Contrast', () => {
183
+ it('should maintain readable contrast in dark mode', () => {
184
+ cy.mount(
185
+ <div className="dark bg-gray-900 p-4">
186
+ <h1 className="text-white">High Contrast Title</h1>
187
+ <p className="text-gray-300">Body text with good contrast</p>
188
+ <button className="bg-blue-600 text-white px-4 py-2">Action Button</button>
189
+ </div>
190
+ );
191
+
192
+ // Visual check - in real tests you might use cypress-axe
193
+ cy.get('h1').should('have.class', 'text-white');
194
+ cy.get('p').should('have.class', 'text-gray-300');
195
+ });
196
+ });
197
+
198
+ describe('Screen Reader Support', () => {
199
+ it('should have proper heading hierarchy', () => {
200
+ cy.mount(
201
+ <article>
202
+ <h1>Main Title</h1>
203
+ <section>
204
+ <h2>Section Title</h2>
205
+ <p>Content</p>
206
+ <h3>Subsection</h3>
207
+ <p>More content</p>
208
+ </section>
209
+ </article>
210
+ );
211
+
212
+ // Check heading hierarchy
213
+ cy.get('h1').should('have.length', 1);
214
+ cy.get('h2').should('exist');
215
+ cy.get('h3').should('exist');
216
+ });
217
+
218
+ it('should use semantic HTML elements', () => {
219
+ cy.mount(
220
+ <nav aria-label="Main navigation">
221
+ <ul>
222
+ <li>
223
+ <a href="#home">Home</a>
224
+ </li>
225
+ <li>
226
+ <a href="#about">About</a>
227
+ </li>
228
+ </ul>
229
+ </nav>
230
+ );
231
+
232
+ cy.get('nav').should('have.attr', 'aria-label', 'Main navigation');
233
+ cy.get('nav ul').should('exist');
234
+ cy.get('nav a').should('have.length', 2);
235
+ });
236
+ });
237
+ });
238
+
239
+ /**
240
+ * ACCESSIBILITY TESTING PATTERNS
241
+ *
242
+ * 1. ARIA ATTRIBUTES
243
+ * - Test aria-label, aria-describedby, aria-invalid
244
+ * - Verify role attributes for dynamic content
245
+ * - Check live regions for updates
246
+ *
247
+ * 2. KEYBOARD NAVIGATION
248
+ * - Test tab order
249
+ * - Verify all interactive elements are reachable
250
+ * - Check focus indicators
251
+ *
252
+ * 3. FORM ACCESSIBILITY
253
+ * - Labels properly associated with inputs
254
+ * - Error messages linked to fields
255
+ * - Required fields indicated
256
+ *
257
+ * 4. COLOR CONTRAST
258
+ * - Test in both light and dark modes
259
+ * - Ensure text is readable
260
+ * - Check focus indicators visibility
261
+ *
262
+ * 5. SCREEN READER SUPPORT
263
+ * - Proper heading hierarchy
264
+ * - Semantic HTML usage
265
+ * - Alternative text for images
266
+ *
267
+ * TOOLS TO CONSIDER:
268
+ * - cypress-axe: Automated accessibility testing
269
+ * - cypress-tab: Better keyboard navigation testing
270
+ * - cypress-real-events: Test with real browser events
271
+ */
@@ -0,0 +1,220 @@
1
+ import React from 'react';
2
+ import '../../../frontend/index.css';
3
+
4
+ /**
5
+ * Example component that fetches data from an API using React state
6
+ */
7
+ const DataFetchingComponent: React.FC<{ agentId: string }> = ({ agentId }) => {
8
+ const [data, setData] = React.useState<any>(null);
9
+ const [isLoading, setIsLoading] = React.useState(true);
10
+ const [error, setError] = React.useState<Error | null>(null);
11
+
12
+ React.useEffect(() => {
13
+ const fetchData = async () => {
14
+ try {
15
+ setIsLoading(true);
16
+ setError(null);
17
+ const response = await fetch(`/api/agent/${agentId}/data`);
18
+ if (!response.ok) {
19
+ throw new Error('Failed to fetch data');
20
+ }
21
+ const result = await response.json();
22
+ setData(result);
23
+ } catch (err) {
24
+ setError(err as Error);
25
+ } finally {
26
+ setIsLoading(false);
27
+ }
28
+ };
29
+
30
+ fetchData();
31
+ }, [agentId]);
32
+
33
+ if (isLoading) return <div data-testid="loading">Loading agent data...</div>;
34
+ if (error)
35
+ return (
36
+ <div data-testid="error" className="text-red-500">
37
+ Error: {error.message}
38
+ </div>
39
+ );
40
+
41
+ return (
42
+ <div data-testid="data-display">
43
+ <h2>Agent: {agentId}</h2>
44
+ <ul>{data?.items?.map((item: string, index: number) => <li key={index}>{item}</li>)}</ul>
45
+ </div>
46
+ );
47
+ };
48
+
49
+ describe('API Integration Tests', () => {
50
+ describe('Data Fetching', () => {
51
+ it('should display loading state initially', () => {
52
+ cy.intercept('GET', '/api/agent/*/data', {
53
+ delay: 1000,
54
+ body: { items: [] },
55
+ });
56
+
57
+ cy.mount(<DataFetchingComponent agentId="test-123" />);
58
+ cy.get('[data-testid="loading"]').should('be.visible');
59
+ cy.get('[data-testid="loading"]').should('contain', 'Loading agent data...');
60
+ });
61
+
62
+ it('should fetch and display data successfully', () => {
63
+ const mockData = {
64
+ items: ['Action 1', 'Action 2', 'Action 3'],
65
+ };
66
+
67
+ cy.intercept('GET', '/api/agent/test-123/data', {
68
+ statusCode: 200,
69
+ body: mockData,
70
+ }).as('getAgentData');
71
+
72
+ cy.mount(<DataFetchingComponent agentId="test-123" />);
73
+
74
+ // Wait for the API call
75
+ cy.wait('@getAgentData');
76
+
77
+ // Check data is displayed
78
+ cy.get('[data-testid="data-display"]').should('be.visible');
79
+ cy.contains('Agent: test-123').should('be.visible');
80
+ cy.contains('Action 1').should('be.visible');
81
+ cy.contains('Action 2').should('be.visible');
82
+ cy.contains('Action 3').should('be.visible');
83
+ });
84
+
85
+ it('should handle API errors gracefully', () => {
86
+ cy.intercept('GET', '/api/agent/test-123/data', {
87
+ statusCode: 500,
88
+ body: { error: 'Internal Server Error' },
89
+ }).as('getAgentDataError');
90
+
91
+ cy.mount(<DataFetchingComponent agentId="test-123" />);
92
+
93
+ // Wait for the failed API call
94
+ cy.wait('@getAgentDataError');
95
+
96
+ // Check error is displayed
97
+ cy.get('[data-testid="error"]').should('be.visible');
98
+ cy.get('[data-testid="error"]').should('contain', 'Failed to fetch data');
99
+ cy.get('[data-testid="error"]').should('have.class', 'text-red-500');
100
+ });
101
+
102
+ it('should handle network errors', () => {
103
+ cy.intercept('GET', '/api/agent/test-123/data', {
104
+ forceNetworkError: true,
105
+ }).as('networkError');
106
+
107
+ cy.mount(<DataFetchingComponent agentId="test-123" />);
108
+
109
+ // Network errors might not trigger the wait, so we check for error directly
110
+ cy.get('[data-testid="error"]', { timeout: 10000 }).should('be.visible');
111
+ });
112
+
113
+ it('should refetch data when agent ID changes', () => {
114
+ const firstMockData = { items: ['First Agent Action'] };
115
+ const secondMockData = { items: ['Second Agent Action'] };
116
+
117
+ cy.intercept('GET', '/api/agent/agent-1/data', {
118
+ body: firstMockData,
119
+ }).as('getFirstAgent');
120
+
121
+ cy.intercept('GET', '/api/agent/agent-2/data', {
122
+ body: secondMockData,
123
+ }).as('getSecondAgent');
124
+
125
+ // Create a component that can change agent ID
126
+ const TestWrapper = () => {
127
+ const [agentId, setAgentId] = React.useState('agent-1');
128
+
129
+ return (
130
+ <>
131
+ <button onClick={() => setAgentId('agent-2')} data-testid="change-agent">
132
+ Change Agent
133
+ </button>
134
+ <DataFetchingComponent agentId={agentId} />
135
+ </>
136
+ );
137
+ };
138
+
139
+ cy.mount(<TestWrapper />);
140
+ cy.wait('@getFirstAgent');
141
+ cy.contains('First Agent Action').should('be.visible');
142
+
143
+ // Click to change agent
144
+ cy.get('[data-testid="change-agent"]').click();
145
+ cy.wait('@getSecondAgent');
146
+ cy.contains('Second Agent Action').should('be.visible');
147
+ cy.contains('First Agent Action').should('not.exist');
148
+ });
149
+ });
150
+
151
+ describe('Request Validation', () => {
152
+ it('should send correct headers', () => {
153
+ cy.intercept('GET', '/api/agent/*/data', (req) => {
154
+ expect(req.headers).to.have.property('accept');
155
+ req.reply({ items: [] });
156
+ }).as('checkHeaders');
157
+
158
+ cy.mount(<DataFetchingComponent agentId="test-123" />);
159
+ cy.wait('@checkHeaders');
160
+ });
161
+
162
+ it('should handle different response formats', () => {
163
+ // Test empty response
164
+ cy.intercept('GET', '/api/agent/empty/data', {
165
+ body: {},
166
+ }).as('emptyResponse');
167
+ cy.mount(<DataFetchingComponent agentId="empty" />);
168
+ cy.wait('@emptyResponse');
169
+ cy.get('[data-testid="data-display"]').should('be.visible');
170
+
171
+ // Test null items
172
+ cy.intercept('GET', '/api/agent/null/data', {
173
+ body: { items: null },
174
+ }).as('nullResponse');
175
+ // Create a new mount point for the second test
176
+ cy.then(() => {
177
+ cy.mount(<DataFetchingComponent agentId="null" />);
178
+ cy.wait('@nullResponse');
179
+ cy.get('[data-testid="data-display"]').should('be.visible');
180
+ });
181
+ });
182
+ });
183
+ });
184
+
185
+ /**
186
+ * API TESTING PATTERNS IN CYPRESS
187
+ *
188
+ * 1. INTERCEPTING REQUESTS
189
+ * cy.intercept() allows you to:
190
+ * - Mock responses
191
+ * - Delay responses
192
+ * - Force errors
193
+ * - Validate request data
194
+ *
195
+ * 2. WAITING FOR REQUESTS
196
+ * Use aliases with .as() and cy.wait() to ensure
197
+ * requests complete before making assertions
198
+ *
199
+ * 3. ERROR SCENARIOS
200
+ * Test all error cases:
201
+ * - Server errors (4xx, 5xx)
202
+ * - Network failures
203
+ * - Timeout scenarios
204
+ * - Invalid responses
205
+ *
206
+ * 4. LOADING STATES
207
+ * Always test loading indicators
208
+ * Use delays to ensure they appear
209
+ *
210
+ * 5. DATA UPDATES
211
+ * Test how components handle:
212
+ * - Prop changes
213
+ * - Refetching
214
+ * - Cache invalidation
215
+ *
216
+ * NOTE: This example uses plain React state instead of React Query
217
+ * to avoid dependency optimization issues in the test environment.
218
+ * In production, you would typically use React Query or similar
219
+ * libraries for better caching and request management.
220
+ */
@@ -0,0 +1,146 @@
1
+ import React from 'react';
2
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
+ import '../../../frontend/index.css';
4
+
5
+ // We need to import the component directly since it's not exported
6
+ // In a real scenario, you'd export the component from index.tsx
7
+ const ExampleRoute = () => {
8
+ const [config, setConfig] = React.useState(window.ELIZA_CONFIG);
9
+
10
+ React.useEffect(() => {
11
+ document.documentElement.classList.add('dark');
12
+ }, []);
13
+
14
+ if (!config?.agentId) {
15
+ return (
16
+ <div className="p-4 text-center">
17
+ <div className="text-red-600 font-medium">Error: Agent ID not found</div>
18
+ <div className="text-sm text-gray-600 mt-2">
19
+ The server should inject the agent ID configuration.
20
+ </div>
21
+ </div>
22
+ );
23
+ }
24
+
25
+ return (
26
+ <QueryClientProvider client={new QueryClient()}>
27
+ <div>Hello {config.agentId}</div>
28
+ </QueryClientProvider>
29
+ );
30
+ };
31
+
32
+ describe('ExampleRoute Component Tests', () => {
33
+ describe('Component Rendering', () => {
34
+ it('should apply dark mode on mount', () => {
35
+ cy.mount(<ExampleRoute />);
36
+ cy.shouldBeDarkMode();
37
+ });
38
+
39
+ it('should show error when agent ID is missing', () => {
40
+ // Clear the config before mounting
41
+ cy.window().then((win) => {
42
+ win.ELIZA_CONFIG = undefined;
43
+ });
44
+
45
+ cy.mount(<ExampleRoute />);
46
+
47
+ // Check error message is displayed
48
+ cy.contains('Error: Agent ID not found').should('be.visible');
49
+ cy.contains('The server should inject the agent ID configuration.').should('be.visible');
50
+ });
51
+
52
+ it('should render correctly with agent ID', () => {
53
+ const testAgentId = '12345678-1234-1234-1234-123456789abc';
54
+
55
+ // Set config before mounting
56
+ cy.window().then((win) => {
57
+ win.ELIZA_CONFIG = {
58
+ agentId: testAgentId,
59
+ apiBase: 'http://localhost:3000',
60
+ };
61
+ });
62
+
63
+ cy.mount(<ExampleRoute />);
64
+
65
+ // Check that the agent ID is displayed
66
+ cy.contains(`Hello ${testAgentId}`).should('be.visible');
67
+ });
68
+ });
69
+
70
+ describe('Configuration Handling', () => {
71
+ it('should handle ELIZA_CONFIG changes', () => {
72
+ const initialAgentId = 'initial-agent-id';
73
+ const updatedAgentId = 'updated-agent-id';
74
+
75
+ // Set initial config
76
+ cy.window().then((win) => {
77
+ win.ELIZA_CONFIG = {
78
+ agentId: initialAgentId,
79
+ apiBase: 'http://localhost:3000',
80
+ };
81
+ });
82
+
83
+ cy.mount(<ExampleRoute />);
84
+ cy.contains(`Hello ${initialAgentId}`).should('be.visible');
85
+ });
86
+ });
87
+ });
88
+
89
+ /**
90
+ * TESTING PATTERNS FOR FRONTEND COMPONENTS IN ELIZAOS
91
+ *
92
+ * 1. COMPONENT ISOLATION
93
+ * - Test components in isolation using cy.mount()
94
+ * - Mock external dependencies (like API calls)
95
+ * - Use data-testid attributes for reliable element selection
96
+ *
97
+ * 2. CONFIGURATION TESTING
98
+ * - Always test with and without ELIZA_CONFIG
99
+ * - Test with invalid/malformed configurations
100
+ * - Verify error states and fallbacks
101
+ *
102
+ * 3. DARK MODE SUPPORT
103
+ * - Ensure components work in both light and dark modes
104
+ * - Use the custom shouldBeDarkMode() command
105
+ *
106
+ * 4. QUERY CLIENT TESTING
107
+ * - Mock API responses for react-query
108
+ * - Test loading, error, and success states
109
+ * - Verify cache behavior
110
+ *
111
+ * 5. ACCESSIBILITY
112
+ * - Use Testing Library queries (findByRole, findByText)
113
+ * - Test keyboard navigation
114
+ * - Verify ARIA attributes
115
+ *
116
+ * EXAMPLE TEST STRUCTURE:
117
+ *
118
+ * describe('Component Name', () => {
119
+ * beforeEach(() => {
120
+ * // Set up common test data
121
+ * cy.setElizaConfig({ agentId: 'test-id', apiBase: 'http://localhost:3000' });
122
+ * });
123
+ *
124
+ * describe('Rendering', () => {
125
+ * it('should render correctly', () => {
126
+ * cy.mount(<Component />);
127
+ * // Assertions
128
+ * });
129
+ * });
130
+ *
131
+ * describe('User Interactions', () => {
132
+ * it('should handle click events', () => {
133
+ * cy.mount(<Component />);
134
+ * cy.findByRole('button').click();
135
+ * // Assertions
136
+ * });
137
+ * });
138
+ *
139
+ * describe('API Integration', () => {
140
+ * it('should fetch and display data', () => {
141
+ * cy.intercept('GET', '/api/data', { fixture: 'mockData.json' });
142
+ * cy.mount(<Component />);
143
+ * // Assertions
144
+ * });
145
+ * });
146
+ * }); */
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { panels } from '../../../frontend/index';
3
+
4
+ describe('PanelComponent Tests', () => {
5
+ // Get the Panel component from the exported panels
6
+ const PanelComponent = panels[0]?.component;
7
+
8
+ describe('Panel Registration', () => {
9
+ it('should export panels array with correct structure', () => {
10
+ expect(panels).to.be.an('array');
11
+ expect(panels).to.have.length.greaterThan(0);
12
+
13
+ const panel = panels[0];
14
+ expect(panel).to.have.property('name', 'Example');
15
+ expect(panel).to.have.property('path', 'example');
16
+ expect(panel).to.have.property('component');
17
+ expect(panel).to.have.property('icon', 'Book');
18
+ expect(panel).to.have.property('public', false);
19
+ expect(panel).to.have.property('shortLabel', 'Example');
20
+ });
21
+ });
22
+
23
+ describe('Component Rendering', () => {
24
+ it('should render with agent ID', () => {
25
+ const testAgentId = 'test-agent-12345';
26
+
27
+ if (!PanelComponent) {
28
+ throw new Error('PanelComponent not found in panels export');
29
+ }
30
+
31
+ cy.mount(<PanelComponent agentId={testAgentId} />);
32
+
33
+ // Note: The component has a typo "Helllo" instead of "Hello"
34
+ cy.contains(`Helllo ${testAgentId}!`).should('be.visible');
35
+ });
36
+
37
+ it('should handle different agent IDs', () => {
38
+ const agentIds = ['agent-1', 'agent-2', '12345678-1234-1234-1234-123456789abc', 'test-agent'];
39
+
40
+ agentIds.forEach((agentId) => {
41
+ cy.mount(<PanelComponent agentId={agentId} />);
42
+ cy.contains(`Helllo ${agentId}!`).should('be.visible');
43
+ });
44
+ });
45
+
46
+ it('should render without crashing with empty agent ID', () => {
47
+ cy.mount(<PanelComponent agentId="" />);
48
+ cy.contains('Helllo !').should('be.visible');
49
+ });
50
+ });
51
+ });