microui-wc 0.1.0 → 0.1.2

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 (343) hide show
  1. package/AGENTS.md +71 -71
  2. package/CHANGELOG.md +1 -1
  3. package/README.md +14 -9
  4. package/dist/AGENTS.md +116 -116
  5. package/dist/README.md +21 -16
  6. package/dist/components.css +1 -1
  7. package/dist/microui.css +1 -1
  8. package/dist/microui.esm.js.map +1 -1
  9. package/dist/microui.min.js.map +1 -1
  10. package/dist/styles/components/switch.css +1 -1
  11. package/docs/getting-started.md +3 -3
  12. package/package.json +38 -10
  13. package/src/components/mu-schema-form.js +1 -1
  14. package/src/styles/components/switch.css +7 -8
  15. package/src/styles/components.css +6 -6
  16. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  17. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -33
  18. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  19. package/.github/workflows/ci.yml +0 -42
  20. package/.github/workflows/deploy-pages.yml +0 -112
  21. package/CODE_OF_CONDUCT.md +0 -59
  22. package/CONTRIBUTING.md +0 -156
  23. package/SECURITY.md +0 -58
  24. package/app/.generated/routes/alerts.js +0 -8
  25. package/app/.generated/routes/avatars.js +0 -8
  26. package/app/.generated/routes/badges.js +0 -8
  27. package/app/.generated/routes/buttons.js +0 -10
  28. package/app/.generated/routes/cards.js +0 -10
  29. package/app/.generated/routes/checkboxes.js +0 -9
  30. package/app/.generated/routes/chips.js +0 -8
  31. package/app/.generated/routes/dropdowns.js +0 -9
  32. package/app/.generated/routes/home.js +0 -7
  33. package/app/.generated/routes/icons.js +0 -9
  34. package/app/.generated/routes/inputs.js +0 -10
  35. package/app/.generated/routes/installation.js +0 -7
  36. package/app/.generated/routes/layout.js +0 -9
  37. package/app/.generated/routes/modals.js +0 -9
  38. package/app/.generated/routes/navbar.js +0 -7
  39. package/app/.generated/routes/progress.js +0 -9
  40. package/app/.generated/routes/radios.js +0 -9
  41. package/app/.generated/routes/switches.js +0 -9
  42. package/app/.generated/routes/tabs.js +0 -8
  43. package/app/.generated/routes/toasts.js +0 -9
  44. package/app/index.html +0 -67
  45. package/app/pages/alerts.html +0 -23
  46. package/app/pages/avatars.html +0 -22
  47. package/app/pages/badges.html +0 -22
  48. package/app/pages/buttons.html +0 -71
  49. package/app/pages/cards.html +0 -54
  50. package/app/pages/checkboxes.html +0 -39
  51. package/app/pages/chips.html +0 -23
  52. package/app/pages/dropdowns.html +0 -41
  53. package/app/pages/home.html +0 -59
  54. package/app/pages/icons.html +0 -29
  55. package/app/pages/inputs.html +0 -66
  56. package/app/pages/installation.html +0 -34
  57. package/app/pages/layout.html +0 -30
  58. package/app/pages/modals.html +0 -21
  59. package/app/pages/navbar.html +0 -22
  60. package/app/pages/progress.html +0 -35
  61. package/app/pages/radios.html +0 -40
  62. package/app/pages/switches.html +0 -39
  63. package/app/pages/tabs.html +0 -30
  64. package/app/pages/toasts.html +0 -22
  65. package/app-dist/index.html +0 -67
  66. package/app-dist/pages/alerts.html +0 -23
  67. package/app-dist/pages/avatars.html +0 -22
  68. package/app-dist/pages/badges.html +0 -22
  69. package/app-dist/pages/buttons.html +0 -71
  70. package/app-dist/pages/cards.html +0 -54
  71. package/app-dist/pages/checkboxes.html +0 -39
  72. package/app-dist/pages/chips.html +0 -23
  73. package/app-dist/pages/dropdowns.html +0 -41
  74. package/app-dist/pages/home.html +0 -59
  75. package/app-dist/pages/icons.html +0 -29
  76. package/app-dist/pages/inputs.html +0 -66
  77. package/app-dist/pages/installation.html +0 -34
  78. package/app-dist/pages/layout.html +0 -30
  79. package/app-dist/pages/modals.html +0 -21
  80. package/app-dist/pages/navbar.html +0 -22
  81. package/app-dist/pages/progress.html +0 -35
  82. package/app-dist/pages/radios.html +0 -40
  83. package/app-dist/pages/switches.html +0 -39
  84. package/app-dist/pages/tabs.html +0 -30
  85. package/app-dist/pages/toasts.html +0 -22
  86. package/app-dist/pages.json +0 -217
  87. package/app-dist/routes/alerts.js +0 -5
  88. package/app-dist/routes/avatars.js +0 -1
  89. package/app-dist/routes/badges.js +0 -1
  90. package/app-dist/routes/buttons.js +0 -1
  91. package/app-dist/routes/cards.js +0 -1
  92. package/app-dist/routes/checkboxes.js +0 -9
  93. package/app-dist/routes/chips.js +0 -4
  94. package/app-dist/routes/chunk-019e5e2f.js +0 -5
  95. package/app-dist/routes/chunk-0m4j19yd.js +0 -2
  96. package/app-dist/routes/chunk-0tmmp5q0.js +0 -1
  97. package/app-dist/routes/chunk-10xn709r.js +0 -1
  98. package/app-dist/routes/chunk-15m2qcda.js +0 -2
  99. package/app-dist/routes/chunk-1bh8g23n.js +0 -1
  100. package/app-dist/routes/chunk-1vg0v937.js +0 -1
  101. package/app-dist/routes/chunk-1zvcgy3j.js +0 -1
  102. package/app-dist/routes/chunk-2afb0861.js +0 -1
  103. package/app-dist/routes/chunk-2c6ttpzt.js +0 -5
  104. package/app-dist/routes/chunk-3dy30fhs.js +0 -1
  105. package/app-dist/routes/chunk-426dnces.js +0 -13
  106. package/app-dist/routes/chunk-44kgxery.js +0 -1
  107. package/app-dist/routes/chunk-47fdnejd.js +0 -33
  108. package/app-dist/routes/chunk-49a6t2vq.js +0 -1
  109. package/app-dist/routes/chunk-4fe1rm5b.js +0 -1
  110. package/app-dist/routes/chunk-4ggmvkta.js +0 -33
  111. package/app-dist/routes/chunk-4vkz81q7.js +0 -33
  112. package/app-dist/routes/chunk-4w4tmj8f.js +0 -31
  113. package/app-dist/routes/chunk-532s62kr.js +0 -31
  114. package/app-dist/routes/chunk-5hm3bssy.js +0 -33
  115. package/app-dist/routes/chunk-5vrh24hc.js +0 -1
  116. package/app-dist/routes/chunk-61pcg25a.js +0 -1
  117. package/app-dist/routes/chunk-6nfhygvf.js +0 -1
  118. package/app-dist/routes/chunk-700e7je6.js +0 -33
  119. package/app-dist/routes/chunk-7fsn17kg.js +0 -1
  120. package/app-dist/routes/chunk-7k789b32.js +0 -1
  121. package/app-dist/routes/chunk-7r46q0ys.js +0 -36
  122. package/app-dist/routes/chunk-86fmc1fr.js +0 -5
  123. package/app-dist/routes/chunk-8qth37vw.js +0 -1
  124. package/app-dist/routes/chunk-924wv8n0.js +0 -1
  125. package/app-dist/routes/chunk-9mbhgxk9.js +0 -1
  126. package/app-dist/routes/chunk-a216hyd9.js +0 -1
  127. package/app-dist/routes/chunk-akzxykh9.js +0 -33
  128. package/app-dist/routes/chunk-b3dcvy8c.js +0 -1
  129. package/app-dist/routes/chunk-b74zahz5.js +0 -31
  130. package/app-dist/routes/chunk-bftj53p2.js +0 -5
  131. package/app-dist/routes/chunk-c01hnz3e.js +0 -1
  132. package/app-dist/routes/chunk-d8pvv5km.js +0 -1
  133. package/app-dist/routes/chunk-dev0aezr.js +0 -2
  134. package/app-dist/routes/chunk-dh6vnv0e.js +0 -1
  135. package/app-dist/routes/chunk-dn2cbpva.js +0 -36
  136. package/app-dist/routes/chunk-dvn0my90.js +0 -1
  137. package/app-dist/routes/chunk-dvq8mnve.js +0 -36
  138. package/app-dist/routes/chunk-e8c2gc4d.js +0 -5
  139. package/app-dist/routes/chunk-ejf9ak2x.js +0 -1
  140. package/app-dist/routes/chunk-f083m55s.js +0 -1
  141. package/app-dist/routes/chunk-fnrj28s1.js +0 -31
  142. package/app-dist/routes/chunk-fvg3yjdp.js +0 -31
  143. package/app-dist/routes/chunk-g7k381n1.js +0 -1
  144. package/app-dist/routes/chunk-h01kq2ae.js +0 -13
  145. package/app-dist/routes/chunk-h4dk761v.js +0 -5
  146. package/app-dist/routes/chunk-hmx91z2x.js +0 -5
  147. package/app-dist/routes/chunk-hxbg4m42.js +0 -36
  148. package/app-dist/routes/chunk-jbjnfp2b.js +0 -2
  149. package/app-dist/routes/chunk-jxtz5vv6.js +0 -36
  150. package/app-dist/routes/chunk-jxzcs0ey.js +0 -36
  151. package/app-dist/routes/chunk-kt7wwhcx.js +0 -1
  152. package/app-dist/routes/chunk-kzptszyc.js +0 -33
  153. package/app-dist/routes/chunk-mhgca4w4.js +0 -2
  154. package/app-dist/routes/chunk-mhswxa20.js +0 -1
  155. package/app-dist/routes/chunk-n8zfeex6.js +0 -1
  156. package/app-dist/routes/chunk-pee47b2r.js +0 -1
  157. package/app-dist/routes/chunk-pesmw829.js +0 -1
  158. package/app-dist/routes/chunk-pgc4c6f3.js +0 -36
  159. package/app-dist/routes/chunk-q8egegm1.js +0 -1
  160. package/app-dist/routes/chunk-q9mn2qyq.js +0 -36
  161. package/app-dist/routes/chunk-qh0rtaf3.js +0 -5
  162. package/app-dist/routes/chunk-qqhmk6ye.js +0 -2
  163. package/app-dist/routes/chunk-qrxygmf7.js +0 -33
  164. package/app-dist/routes/chunk-r46yzksx.js +0 -36
  165. package/app-dist/routes/chunk-rgpbw2w0.js +0 -5
  166. package/app-dist/routes/chunk-rnpzv3d8.js +0 -2
  167. package/app-dist/routes/chunk-s5v8cv05.js +0 -2
  168. package/app-dist/routes/chunk-sbwn5bpc.js +0 -1
  169. package/app-dist/routes/chunk-sqbg8jbt.js +0 -33
  170. package/app-dist/routes/chunk-sv8dqnf7.js +0 -1
  171. package/app-dist/routes/chunk-t67sw3za.js +0 -1
  172. package/app-dist/routes/chunk-tjdpqwdf.js +0 -31
  173. package/app-dist/routes/chunk-tq2mfghg.js +0 -1
  174. package/app-dist/routes/chunk-ttn10vt6.js +0 -1
  175. package/app-dist/routes/chunk-v2hzpjxr.js +0 -1
  176. package/app-dist/routes/chunk-wfjjkw9y.js +0 -1
  177. package/app-dist/routes/chunk-wt8cxzmf.js +0 -31
  178. package/app-dist/routes/chunk-x45d372k.js +0 -5
  179. package/app-dist/routes/chunk-y3wsazkt.js +0 -1
  180. package/app-dist/routes/chunk-y7pmgc7t.js +0 -33
  181. package/app-dist/routes/chunk-zefdt2q3.js +0 -31
  182. package/app-dist/routes/dropdowns.js +0 -6
  183. package/app-dist/routes/home.js +0 -1
  184. package/app-dist/routes/icons.js +0 -1
  185. package/app-dist/routes/inputs.js +0 -12
  186. package/app-dist/routes/installation.js +0 -1
  187. package/app-dist/routes/layout.js +0 -1
  188. package/app-dist/routes/modals.js +0 -7
  189. package/app-dist/routes/navbar.js +0 -1
  190. package/app-dist/routes/progress.js +0 -1
  191. package/app-dist/routes/radios.js +0 -6
  192. package/app-dist/routes/switches.js +0 -6
  193. package/app-dist/routes/tabs.js +0 -1
  194. package/app-dist/routes/toasts.js +0 -16
  195. package/assets/fonts/material-symbols-mini.woff2 +0 -0
  196. package/assets/fonts/material-symbols.woff2 +0 -0
  197. package/assets/fonts/roboto-400.woff2 +0 -0
  198. package/assets/fonts/roboto-500.woff2 +0 -0
  199. package/assets/fonts/roboto-700.woff2 +0 -0
  200. package/assets/logo-banner-400.jpg +0 -0
  201. package/assets/logo-banner-400.webp +0 -0
  202. package/assets/logo-banner-800.webp +0 -0
  203. package/assets/logo-banner.jpg +0 -0
  204. package/assets/logo-icon-64.jpg +0 -0
  205. package/assets/logo-icon-64.webp +0 -0
  206. package/assets/logo-icon.jpg +0 -0
  207. package/assets/logo-square.jpg +0 -0
  208. package/bun.lock +0 -312
  209. package/bunfig.toml +0 -4
  210. package/custom-elements.json +0 -1916
  211. package/demo/api/sample-data.json +0 -38
  212. package/demo/content/alerts.html +0 -115
  213. package/demo/content/avatars.html +0 -70
  214. package/demo/content/badges.html +0 -65
  215. package/demo/content/buttons.html +0 -188
  216. package/demo/content/callouts.html +0 -91
  217. package/demo/content/cards.html +0 -121
  218. package/demo/content/checkboxes.html +0 -178
  219. package/demo/content/chips.html +0 -67
  220. package/demo/content/codeblocks.html +0 -101
  221. package/demo/content/confirms.html +0 -115
  222. package/demo/content/datatables.html +0 -149
  223. package/demo/content/dividers.html +0 -119
  224. package/demo/content/dropdowns.html +0 -89
  225. package/demo/content/enterprise.html +0 -252
  226. package/demo/content/home.html +0 -149
  227. package/demo/content/icons.html +0 -89
  228. package/demo/content/inputs.html +0 -135
  229. package/demo/content/installation.html +0 -16
  230. package/demo/content/layout.html +0 -136
  231. package/demo/content/modals.html +0 -141
  232. package/demo/content/navbar.html +0 -70
  233. package/demo/content/progress.html +0 -119
  234. package/demo/content/radios.html +0 -88
  235. package/demo/content/skeletons.html +0 -109
  236. package/demo/content/spinners.html +0 -96
  237. package/demo/content/switches.html +0 -84
  238. package/demo/content/tables.html +0 -124
  239. package/demo/content/tabs.html +0 -85
  240. package/demo/content/toasts.html +0 -116
  241. package/demo/content/tooltips.html +0 -107
  242. package/demo/content/virtual-lists.html +0 -233
  243. package/demo/favicon.ico +0 -0
  244. package/demo/favicon.png +0 -0
  245. package/demo/full.html +0 -52
  246. package/demo/iife.html +0 -46
  247. package/demo/manifest.json +0 -34
  248. package/demo/pages/datatable-demo.html +0 -237
  249. package/demo/pages/prompt-ui-demo.html +0 -218
  250. package/demo/pages/responsive-demo.html +0 -122
  251. package/demo/pages/schema-form-demo.html +0 -270
  252. package/demo/robots.txt +0 -6
  253. package/demo/shell.html +0 -712
  254. package/demo/sw.js +0 -387
  255. package/lighthouse-audit.mjs +0 -113
  256. package/scripts/analyze-components.js +0 -105
  257. package/scripts/build-app.js +0 -193
  258. package/scripts/build-framework.js +0 -444
  259. package/scripts/build-utils.js +0 -101
  260. package/scripts/test-isolated.js +0 -151
  261. package/server.js +0 -256
  262. package/tests/agents/agent-integration.test.js +0 -76
  263. package/tests/benchmark.html +0 -296
  264. package/tests/build/scan-components.test.js +0 -173
  265. package/tests/components/all-components.test.js +0 -245
  266. package/tests/components/all-missing-components.test.js +0 -574
  267. package/tests/components/mu-alert.test.js +0 -113
  268. package/tests/components/mu-avatar.test.js +0 -148
  269. package/tests/components/mu-badge.test.js +0 -92
  270. package/tests/components/mu-button.test.js +0 -112
  271. package/tests/components/mu-card.test.js +0 -89
  272. package/tests/components/mu-checkbox.test.js +0 -158
  273. package/tests/components/mu-chip.test.js +0 -118
  274. package/tests/components/mu-container.test.js +0 -120
  275. package/tests/components/mu-divider.test.js +0 -98
  276. package/tests/components/mu-drawer-item.test.js +0 -199
  277. package/tests/components/mu-drawer.test.js +0 -96
  278. package/tests/components/mu-dropdown.test.js +0 -125
  279. package/tests/components/mu-form.test.js +0 -138
  280. package/tests/components/mu-grid.test.js +0 -135
  281. package/tests/components/mu-icon.test.js +0 -110
  282. package/tests/components/mu-input.test.js +0 -131
  283. package/tests/components/mu-lazy.test.js +0 -103
  284. package/tests/components/mu-modal.test.js +0 -275
  285. package/tests/components/mu-navbar.test.js +0 -101
  286. package/tests/components/mu-progress.test.js +0 -115
  287. package/tests/components/mu-radio.test.js +0 -114
  288. package/tests/components/mu-repeat.test.js +0 -106
  289. package/tests/components/mu-sidebar.test.js +0 -126
  290. package/tests/components/mu-skeleton.test.js +0 -162
  291. package/tests/components/mu-stack.test.js +0 -143
  292. package/tests/components/mu-switch.test.js +0 -292
  293. package/tests/components/mu-table.test.js +0 -124
  294. package/tests/components/mu-tabs.test.js +0 -104
  295. package/tests/components/mu-textarea.test.js +0 -115
  296. package/tests/components/mu-toast.test.js +0 -321
  297. package/tests/components/mu-tooltip.test.js +0 -133
  298. package/tests/components/mu-virtual-list.test.js +0 -109
  299. package/tests/core/MuElement.test.js +0 -120
  300. package/tests/core/agent-api.test.js +0 -125
  301. package/tests/core/all-core-modules.test.js +0 -442
  302. package/tests/core/bus.test.js +0 -364
  303. package/tests/core/component-schema.test.js +0 -160
  304. package/tests/core/feature-registry.test.js +0 -198
  305. package/tests/core/form-state.test.js +0 -167
  306. package/tests/core/http.test.js +0 -119
  307. package/tests/core/keyboard.test.js +0 -319
  308. package/tests/core/layers.test.js +0 -129
  309. package/tests/core/namespaced-stores.test.js +0 -114
  310. package/tests/core/render.test.js +0 -121
  311. package/tests/core/ripple.test.js +0 -131
  312. package/tests/core/router.test.js +0 -89
  313. package/tests/core/scheduler.test.js +0 -121
  314. package/tests/core/signals.test.js +0 -128
  315. package/tests/core/store.test.js +0 -171
  316. package/tests/core/transitions.test.js +0 -82
  317. package/tests/e2e/accessibility-harness.html +0 -58
  318. package/tests/e2e/accessibility.test.js +0 -401
  319. package/tests/e2e/agent-features.test.js +0 -372
  320. package/tests/e2e/card-spacing.test.js +0 -287
  321. package/tests/e2e/components.test.js +0 -439
  322. package/tests/e2e/demo-routes.test.js +0 -478
  323. package/tests/e2e/layout-css-fallback.test.js +0 -334
  324. package/tests/e2e/mu-alert.e2e.test.js +0 -111
  325. package/tests/e2e/mu-checkbox.test.js +0 -489
  326. package/tests/e2e/mu-chip.test.js +0 -347
  327. package/tests/e2e/mu-form.test.js +0 -499
  328. package/tests/e2e/mu-icon.test.js +0 -114
  329. package/tests/e2e/mu-radio.test.js +0 -113
  330. package/tests/e2e/mu-skeleton.test.js +0 -140
  331. package/tests/e2e/mu-switch.test.js +0 -415
  332. package/tests/e2e/mu-tabs.test.js +0 -494
  333. package/tests/e2e/mu-textarea.test.js +0 -242
  334. package/tests/e2e/mu-virtual-list.test.js +0 -427
  335. package/tests/e2e/perf-memory.test.js +0 -161
  336. package/tests/e2e/puppeteer-helper.js +0 -137
  337. package/tests/e2e/puppeteer.test.js +0 -226
  338. package/tests/e2e/pwa.test.js +0 -261
  339. package/tests/e2e/test-harness.html +0 -319
  340. package/tests/manual/test-components.html +0 -120
  341. package/tests/memory-test.html +0 -309
  342. package/tests/setup-dom.js +0 -93
  343. package/tests/visual-test.html +0 -301
@@ -1,161 +0,0 @@
1
- /**
2
- * @fileoverview Performance and Memory Tests
3
- *
4
- * Uses test-harness.html which has microUI properly loaded.
5
- */
6
-
7
- import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
8
- import { launchBrowser, puppeteer } from './puppeteer-helper.js';
9
- import { fileURLToPath } from 'url';
10
- import { dirname, join } from 'path';
11
-
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = dirname(__filename);
14
-
15
- describe('Performance & Memory Tests', () => {
16
- let browser;
17
- let page;
18
- let server;
19
-
20
- beforeAll(async () => {
21
- const projectRoot = join(__dirname, '../..');
22
-
23
- server = Bun.serve({
24
- port: 0,
25
- async fetch(req) {
26
- const url = new URL(req.url);
27
- let filePath = join(projectRoot, url.pathname);
28
-
29
- if (url.pathname === '/') {
30
- filePath = join(__dirname, 'test-harness.html');
31
- }
32
-
33
- try {
34
- const file = Bun.file(filePath);
35
- if (!await file.exists()) {
36
- return new Response('Not Found', { status: 404 });
37
- }
38
-
39
- const content = await file.text();
40
- const ext = filePath.split('.').pop();
41
- const mimeTypes = {
42
- 'html': 'text/html',
43
- 'js': 'text/javascript',
44
- 'css': 'text/css'
45
- };
46
-
47
- return new Response(content, {
48
- headers: { 'Content-Type': mimeTypes[ext] || 'text/plain' }
49
- });
50
- } catch (e) {
51
- return new Response('Error', { status: 500 });
52
- }
53
- }
54
- });
55
-
56
- browser = await puppeteer.launch({
57
- headless: true,
58
- executablePath: '/tmp/puppeteer/chrome-headless-shell/mac_arm-144.0.7559.96/chrome-headless-shell-mac-arm64/chrome-headless-shell',
59
- args: ['--no-sandbox', '--disable-setuid-sandbox'],
60
- userDataDir: `./.tmp/puppeteer-perf_memory-${Date.now()}-${Math.random().toString(36).slice(2)}`
61
- });
62
- page = await browser.newPage();
63
-
64
- // Navigate to test harness first
65
- await page.goto(`http://localhost:${server.port}`, { waitUntil: 'networkidle0' });
66
- await page.waitForFunction(() => window.testsComplete === true, { timeout: 30000 });
67
- }, 60000);
68
-
69
- afterAll(async () => {
70
- if (browser) await browser.close();
71
- if (server) server.stop();
72
- });
73
-
74
- describe('Performance', () => {
75
- test('component creation: 500 components < 300ms', async () => {
76
- const result = await page.evaluate(() => {
77
- const testArea = document.getElementById('test-area');
78
- testArea.innerHTML = '';
79
-
80
- const start = performance.now();
81
- for (let i = 0; i < 500; i++) {
82
- const btn = document.createElement('mu-button');
83
- btn.textContent = `B${i}`;
84
- testArea.appendChild(btn);
85
- }
86
- const end = performance.now();
87
-
88
- testArea.innerHTML = '';
89
- return { total: end - start };
90
- });
91
-
92
- expect(result.total).toBeLessThan(300);
93
- });
94
-
95
- test('DOM updates: 500 updates < 50ms', async () => {
96
- const result = await page.evaluate(() => {
97
- const testArea = document.getElementById('test-area');
98
- testArea.innerHTML = '';
99
-
100
- const buttons = [];
101
- for (let i = 0; i < 50; i++) {
102
- const btn = document.createElement('mu-button');
103
- testArea.appendChild(btn);
104
- buttons.push(btn);
105
- }
106
-
107
- const start = performance.now();
108
- for (let i = 0; i < 500; i++) {
109
- buttons[i % 50].setAttribute('variant', i % 2 === 0 ? 'filled' : 'outlined');
110
- }
111
- const end = performance.now();
112
-
113
- testArea.innerHTML = '';
114
- return { total: end - start };
115
- });
116
-
117
- expect(result.total).toBeLessThan(50);
118
- });
119
- });
120
-
121
- describe('Memory Stability', () => {
122
- test('component lifecycle: 300 create/destroy cycles', async () => {
123
- const result = await page.evaluate(async () => {
124
- const testArea = document.getElementById('test-area');
125
-
126
- for (let i = 0; i < 300; i++) {
127
- const btn = document.createElement('mu-button');
128
- btn.textContent = `B${i}`;
129
- testArea.appendChild(btn);
130
- }
131
-
132
- testArea.innerHTML = '';
133
- await new Promise(r => setTimeout(r, 50));
134
-
135
- return { passed: true };
136
- });
137
-
138
- expect(result.passed).toBe(true);
139
- });
140
-
141
- test('stress test: 3 cycles of 500 components', async () => {
142
- const result = await page.evaluate(async () => {
143
- const testArea = document.getElementById('test-area');
144
-
145
- for (let cycle = 0; cycle < 3; cycle++) {
146
- for (let i = 0; i < 500; i++) {
147
- const btn = document.createElement('mu-button');
148
- btn.textContent = `${cycle}-${i}`;
149
- testArea.appendChild(btn);
150
- }
151
- testArea.innerHTML = '';
152
- }
153
-
154
- await new Promise(r => setTimeout(r, 20));
155
- return { passed: true };
156
- });
157
-
158
- expect(result.passed).toBe(true);
159
- });
160
- });
161
- });
@@ -1,137 +0,0 @@
1
- /**
2
- * @fileoverview Shared Puppeteer helper for E2E tests
3
- *
4
- * Uses puppeteer-core with globally installed Chrome:
5
- * - puppeteer-core: NO automatic Chrome download
6
- * - Chrome: Installed via `npx puppeteer browsers install chrome-headless-shell`
7
- * Location: ~/.cache/puppeteer/ (persistent) or /tmp/puppeteer/ (sandbox fallback)
8
- *
9
- * This eliminates:
10
- * - Hardcoded paths scattered across 19+ test files
11
- * - macOS sandbox EPERM issues (userDataDir in /tmp)
12
- * - Version drift between test files
13
- * - Automatic Chrome downloads per-project
14
- */
15
-
16
- import puppeteer from 'puppeteer-core';
17
- import { execSync } from 'child_process';
18
- import { existsSync, readdirSync } from 'fs';
19
- import { join } from 'path';
20
-
21
- /**
22
- * Find chrome-headless-shell in various cache locations
23
- * Searches: /tmp/puppeteer, ~/.cache/puppeteer
24
- * @returns {string|null} Path to Chrome executable
25
- */
26
- export function findGlobalChrome() {
27
- const cachePaths = [
28
- '/tmp/puppeteer', // macOS sandbox-friendly location
29
- join(process.env.HOME, '.cache', 'puppeteer') // Standard puppeteer cache
30
- ];
31
-
32
- for (const cachePath of cachePaths) {
33
- if (!existsSync(cachePath)) continue;
34
-
35
- const dirs = readdirSync(cachePath);
36
-
37
- // Look for chrome-headless-shell first (preferred), then chrome
38
- for (const browserType of ['chrome-headless-shell', 'chrome']) {
39
- for (const dir of dirs) {
40
- if (dir.startsWith(browserType)) {
41
- const chromeDir = join(cachePath, dir);
42
-
43
- // Check if it's a directory with versions
44
- try {
45
- const versions = readdirSync(chromeDir).sort().reverse(); // Latest first
46
-
47
- for (const version of versions) {
48
- // Check for mac_arm first, then mac x64
49
- const armPath = join(chromeDir, version, `${browserType}-mac-arm64`, browserType);
50
- const x64Path = join(chromeDir, version, `${browserType}-mac-x64`, browserType);
51
-
52
- if (existsSync(armPath)) return armPath;
53
- if (existsSync(x64Path)) return x64Path;
54
- }
55
- } catch (e) {
56
- // Not a directory with versions, skip
57
- }
58
- }
59
- }
60
- }
61
- }
62
-
63
- return null;
64
- }
65
-
66
- /**
67
- * Generate a unique userDataDir in /tmp to avoid macOS sandbox issues
68
- * @param {string} testName - Name of the test for identification
69
- * @returns {string} Path to userDataDir
70
- */
71
- export function getTmpUserDataDir(testName = 'e2e') {
72
- const sanitized = testName.replace(/[^a-z0-9_-]/gi, '_');
73
- return `/tmp/puppeteer-${sanitized}-${Date.now()}`;
74
- }
75
-
76
- /**
77
- * Launch Puppeteer browser with standardized configuration
78
- * Uses global Chrome from ~/.cache/puppeteer
79
- *
80
- * @param {Object} options - Optional overrides
81
- * @param {string} options.testName - Test name for userDataDir
82
- * @param {boolean} options.headless - Default: true
83
- * @param {string[]} options.args - Additional browser args
84
- * @returns {Promise<Browser>} Puppeteer browser instance
85
- */
86
- export async function launchBrowser(options = {}) {
87
- const {
88
- testName = 'test',
89
- headless = true,
90
- args = []
91
- } = options;
92
-
93
- const executablePath = findGlobalChrome();
94
-
95
- if (!executablePath) {
96
- throw new Error(
97
- '[puppeteer-helper] Chrome not found in ~/.cache/puppeteer.\n' +
98
- 'Install with: PUPPETEER_CACHE_DIR=~/.cache/puppeteer npx puppeteer browsers install chrome-headless-shell'
99
- );
100
- }
101
-
102
- const browser = await puppeteer.launch({
103
- headless,
104
- executablePath,
105
- args: [
106
- '--no-sandbox',
107
- '--disable-setuid-sandbox',
108
- '--disable-dev-shm-usage',
109
- ...args
110
- ],
111
- userDataDir: getTmpUserDataDir(testName)
112
- });
113
-
114
- return browser;
115
- }
116
-
117
- /**
118
- * Launch browser with remote debugging port (for Lighthouse)
119
- * @param {number} port - Debugging port (default: 9222)
120
- * @returns {Promise<Browser>} Puppeteer browser instance
121
- */
122
- export async function launchBrowserForLighthouse(port = 9222) {
123
- return launchBrowser({
124
- testName: `lighthouse-${port}`,
125
- args: [`--remote-debugging-port=${port}`]
126
- });
127
- }
128
-
129
- export default {
130
- findGlobalChrome,
131
- getTmpUserDataDir,
132
- launchBrowser,
133
- launchBrowserForLighthouse
134
- };
135
-
136
- // Re-export puppeteer-core for tests that need direct access
137
- export { default as puppeteer } from 'puppeteer-core';
@@ -1,226 +0,0 @@
1
- /**
2
- * @fileoverview Puppeteer E2E Tests for microUI features that require real browser
3
- *
4
- * Tests: signals, theme (matchMedia), component events (CustomEvent bubbling)
5
- * These tests cover functionality that cannot run in linkedom environment.
6
- */
7
-
8
- import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
9
- import { launchBrowser, puppeteer } from './puppeteer-helper.js';
10
- import { fileURLToPath } from 'url';
11
- import { dirname, join } from 'path';
12
-
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = dirname(__filename);
15
-
16
- describe('Puppeteer E2E Tests', () => {
17
- let browser;
18
- let page;
19
- let server;
20
- let testResults;
21
-
22
- beforeAll(async () => {
23
- // Start a simple HTTP server using Bun
24
- const projectRoot = join(__dirname, '../..');
25
-
26
- server = Bun.serve({
27
- port: 0, // Random available port
28
- async fetch(req) {
29
- const url = new URL(req.url);
30
- let filePath = join(projectRoot, url.pathname);
31
-
32
- // Default to test harness
33
- if (url.pathname === '/') {
34
- filePath = join(__dirname, 'test-harness.html');
35
- }
36
-
37
- try {
38
- const file = Bun.file(filePath);
39
- const exists = await file.exists();
40
- if (!exists) {
41
- console.error(`[404] ${url.pathname} -> ${filePath}`);
42
- return new Response('Not Found', { status: 404 });
43
- }
44
-
45
- const content = await file.text();
46
- const ext = filePath.split('.').pop();
47
- const mimeTypes = {
48
- 'html': 'text/html',
49
- 'js': 'text/javascript',
50
- 'css': 'text/css',
51
- 'json': 'application/json'
52
- };
53
-
54
- return new Response(content, {
55
- headers: { 'Content-Type': mimeTypes[ext] || 'text/plain' }
56
- });
57
- } catch (e) {
58
- console.error(`[500] ${url.pathname}: ${e.message}`);
59
- return new Response('Error: ' + e.message, { status: 500 });
60
- }
61
- }
62
- });
63
-
64
- const serverUrl = `http://localhost:${server.port}`;
65
- console.log(`Test server started at ${serverUrl}`);
66
-
67
- browser = await puppeteer.launch({
68
- headless: true,
69
- executablePath: '/tmp/puppeteer/chrome-headless-shell/mac_arm-144.0.7559.96/chrome-headless-shell-mac-arm64/chrome-headless-shell',
70
- args: ['--no-sandbox', '--disable-setuid-sandbox'],
71
- userDataDir: `./.tmp/puppeteer-puppeteer-${Date.now()}-${Math.random().toString(36).slice(2)}`
72
- });
73
- page = await browser.newPage();
74
-
75
- // Enable console logging for debugging
76
- page.on('console', msg => {
77
- console.log('BROWSER:', msg.text());
78
- });
79
- page.on('pageerror', err => {
80
- console.error('PAGE ERROR:', err.message);
81
- });
82
-
83
- // Navigate to test harness
84
- console.log('Navigating to test harness...');
85
- await page.goto(serverUrl, { waitUntil: 'domcontentloaded' });
86
-
87
- // Give some time for module loading
88
- console.log('Waiting for tests to complete...');
89
-
90
- try {
91
- await page.waitForFunction(() => window.testsComplete === true, {
92
- timeout: 30000
93
- });
94
- console.log('Tests completed!');
95
- } catch (e) {
96
- // If timeout, try to get partial results
97
- console.log('Timeout - checking what happened...');
98
- const pageContent = await page.content();
99
- console.log('Page has content:', pageContent.length, 'chars');
100
-
101
- const hasTestResults = await page.evaluate(() => !!window.testResults);
102
- console.log('Has testResults:', hasTestResults);
103
-
104
- const testsComplete = await page.evaluate(() => window.testsComplete);
105
- console.log('testsComplete:', testsComplete);
106
-
107
- if (!hasTestResults) {
108
- throw new Error('Page failed to load or execute tests');
109
- }
110
- }
111
-
112
- // Get results
113
- testResults = await page.evaluate(() => window.testResults);
114
- console.log('Test results:', JSON.stringify(testResults, null, 2));
115
- }, 60000);
116
-
117
- afterAll(async () => {
118
- if (browser) {
119
- await browser.close();
120
- }
121
- if (server) {
122
- server.stop();
123
- }
124
- });
125
-
126
- // ========================================
127
- // SIGNALS TESTS (require Function.name assignment)
128
- // ========================================
129
-
130
- describe('signals Module (Browser)', () => {
131
- test('signal should create reactive value with functional accessor', () => {
132
- expect(testResults?.signalCreate).toBe(true);
133
- });
134
-
135
- test('signal.set should update value', () => {
136
- expect(testResults?.signalSet).toBe(true);
137
- });
138
-
139
- test('signal.update should work with function', () => {
140
- expect(testResults?.signalUpdate).toBe(true);
141
- });
142
-
143
- test('signal.peek should return value without tracking', () => {
144
- expect(testResults?.signalPeek).toBe(true);
145
- });
146
-
147
- test('computed should derive value', () => {
148
- expect(testResults?.computed).toBe(true);
149
- });
150
- });
151
-
152
- // ========================================
153
- // THEME TESTS (require matchMedia)
154
- // ========================================
155
-
156
- describe('theme Module (Browser)', () => {
157
- test('Theme object should exist', () => {
158
- expect(testResults?.themeExists).toBe(true);
159
- });
160
-
161
- test('Theme.init should be a function', () => {
162
- expect(testResults?.themeHasInit).toBe(true);
163
- });
164
-
165
- test('Theme.set should be a function', () => {
166
- expect(testResults?.themeHasSet).toBe(true);
167
- });
168
-
169
- test('Theme.get should be a function', () => {
170
- expect(testResults?.themeHasGet).toBe(true);
171
- });
172
-
173
- test('Theme.toggle should be a function', () => {
174
- expect(testResults?.themeHasToggle).toBe(true);
175
- });
176
-
177
- test('Theme.set("dark") should set dark theme', () => {
178
- expect(testResults?.themeSetDark).toBe(true);
179
- });
180
-
181
- test('Theme.set("light") should set light theme', () => {
182
- expect(testResults?.themeSetLight).toBe(true);
183
- });
184
- });
185
-
186
- // ========================================
187
- // COMPONENT EVENT TESTS (require CustomEvent)
188
- // ========================================
189
-
190
- describe('Component Events (Browser)', () => {
191
- test('MuElement.emit() should dispatch custom event', () => {
192
- expect(testResults?.muElementEmit).toBe(true);
193
- });
194
-
195
- test('mu-modal.open() should emit mu-open event', () => {
196
- expect(testResults?.modalOpenEvent).toBe(true);
197
- });
198
-
199
- test('mu-modal.close() should emit mu-close event', () => {
200
- expect(testResults?.modalCloseEvent).toBe(true);
201
- });
202
-
203
- test('mu-checkbox.toggle() should toggle checked state', () => {
204
- expect(testResults?.checkboxToggle).toBe(true);
205
- });
206
-
207
- test('mu-switch.toggle() should toggle state', () => {
208
- expect(testResults?.switchToggle).toBe(true);
209
- });
210
-
211
- test('mu-chip.toggle() should toggle selection', () => {
212
- expect(testResults?.chipToggle).toBe(true);
213
- });
214
- });
215
-
216
- // ========================================
217
- // STRUCTURAL TESTS (verify all components render with baseClass)
218
- // ========================================
219
-
220
- describe('Component Structure (Browser)', () => {
221
- test('all 31 components should have correct baseClass', () => {
222
- expect(testResults?.structPass).toBe(31);
223
- expect(testResults?.structFail).toBe(0);
224
- });
225
- });
226
- });