microui-wc 0.1.1 → 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 (339) 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 +71 -71
  5. package/dist/README.md +14 -9
  6. package/dist/microui.css +1 -1
  7. package/dist/microui.esm.js.map +1 -1
  8. package/dist/microui.min.js.map +1 -1
  9. package/docs/getting-started.md +3 -3
  10. package/package.json +39 -11
  11. package/src/components/mu-schema-form.js +1 -1
  12. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  13. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -33
  14. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  15. package/.github/workflows/ci.yml +0 -42
  16. package/.github/workflows/deploy-pages.yml +0 -112
  17. package/CODE_OF_CONDUCT.md +0 -59
  18. package/CONTRIBUTING.md +0 -156
  19. package/SECURITY.md +0 -58
  20. package/app/.generated/routes/alerts.js +0 -8
  21. package/app/.generated/routes/avatars.js +0 -8
  22. package/app/.generated/routes/badges.js +0 -8
  23. package/app/.generated/routes/buttons.js +0 -10
  24. package/app/.generated/routes/cards.js +0 -10
  25. package/app/.generated/routes/checkboxes.js +0 -9
  26. package/app/.generated/routes/chips.js +0 -8
  27. package/app/.generated/routes/dropdowns.js +0 -9
  28. package/app/.generated/routes/home.js +0 -7
  29. package/app/.generated/routes/icons.js +0 -9
  30. package/app/.generated/routes/inputs.js +0 -10
  31. package/app/.generated/routes/installation.js +0 -7
  32. package/app/.generated/routes/layout.js +0 -9
  33. package/app/.generated/routes/modals.js +0 -9
  34. package/app/.generated/routes/navbar.js +0 -7
  35. package/app/.generated/routes/progress.js +0 -9
  36. package/app/.generated/routes/radios.js +0 -9
  37. package/app/.generated/routes/switches.js +0 -9
  38. package/app/.generated/routes/tabs.js +0 -8
  39. package/app/.generated/routes/toasts.js +0 -9
  40. package/app/index.html +0 -67
  41. package/app/pages/alerts.html +0 -23
  42. package/app/pages/avatars.html +0 -22
  43. package/app/pages/badges.html +0 -22
  44. package/app/pages/buttons.html +0 -71
  45. package/app/pages/cards.html +0 -54
  46. package/app/pages/checkboxes.html +0 -39
  47. package/app/pages/chips.html +0 -23
  48. package/app/pages/dropdowns.html +0 -41
  49. package/app/pages/home.html +0 -59
  50. package/app/pages/icons.html +0 -29
  51. package/app/pages/inputs.html +0 -66
  52. package/app/pages/installation.html +0 -34
  53. package/app/pages/layout.html +0 -30
  54. package/app/pages/modals.html +0 -21
  55. package/app/pages/navbar.html +0 -22
  56. package/app/pages/progress.html +0 -35
  57. package/app/pages/radios.html +0 -40
  58. package/app/pages/switches.html +0 -39
  59. package/app/pages/tabs.html +0 -30
  60. package/app/pages/toasts.html +0 -22
  61. package/app-dist/index.html +0 -67
  62. package/app-dist/pages/alerts.html +0 -23
  63. package/app-dist/pages/avatars.html +0 -22
  64. package/app-dist/pages/badges.html +0 -22
  65. package/app-dist/pages/buttons.html +0 -71
  66. package/app-dist/pages/cards.html +0 -54
  67. package/app-dist/pages/checkboxes.html +0 -39
  68. package/app-dist/pages/chips.html +0 -23
  69. package/app-dist/pages/dropdowns.html +0 -41
  70. package/app-dist/pages/home.html +0 -59
  71. package/app-dist/pages/icons.html +0 -29
  72. package/app-dist/pages/inputs.html +0 -66
  73. package/app-dist/pages/installation.html +0 -34
  74. package/app-dist/pages/layout.html +0 -30
  75. package/app-dist/pages/modals.html +0 -21
  76. package/app-dist/pages/navbar.html +0 -22
  77. package/app-dist/pages/progress.html +0 -35
  78. package/app-dist/pages/radios.html +0 -40
  79. package/app-dist/pages/switches.html +0 -39
  80. package/app-dist/pages/tabs.html +0 -30
  81. package/app-dist/pages/toasts.html +0 -22
  82. package/app-dist/pages.json +0 -217
  83. package/app-dist/routes/alerts.js +0 -5
  84. package/app-dist/routes/avatars.js +0 -1
  85. package/app-dist/routes/badges.js +0 -1
  86. package/app-dist/routes/buttons.js +0 -1
  87. package/app-dist/routes/cards.js +0 -1
  88. package/app-dist/routes/checkboxes.js +0 -9
  89. package/app-dist/routes/chips.js +0 -4
  90. package/app-dist/routes/chunk-019e5e2f.js +0 -5
  91. package/app-dist/routes/chunk-0m4j19yd.js +0 -2
  92. package/app-dist/routes/chunk-0tmmp5q0.js +0 -1
  93. package/app-dist/routes/chunk-10xn709r.js +0 -1
  94. package/app-dist/routes/chunk-15m2qcda.js +0 -2
  95. package/app-dist/routes/chunk-1bh8g23n.js +0 -1
  96. package/app-dist/routes/chunk-1vg0v937.js +0 -1
  97. package/app-dist/routes/chunk-1zvcgy3j.js +0 -1
  98. package/app-dist/routes/chunk-2afb0861.js +0 -1
  99. package/app-dist/routes/chunk-2c6ttpzt.js +0 -5
  100. package/app-dist/routes/chunk-3dy30fhs.js +0 -1
  101. package/app-dist/routes/chunk-426dnces.js +0 -13
  102. package/app-dist/routes/chunk-44kgxery.js +0 -1
  103. package/app-dist/routes/chunk-47fdnejd.js +0 -33
  104. package/app-dist/routes/chunk-49a6t2vq.js +0 -1
  105. package/app-dist/routes/chunk-4fe1rm5b.js +0 -1
  106. package/app-dist/routes/chunk-4ggmvkta.js +0 -33
  107. package/app-dist/routes/chunk-4vkz81q7.js +0 -33
  108. package/app-dist/routes/chunk-4w4tmj8f.js +0 -31
  109. package/app-dist/routes/chunk-532s62kr.js +0 -31
  110. package/app-dist/routes/chunk-5hm3bssy.js +0 -33
  111. package/app-dist/routes/chunk-5vrh24hc.js +0 -1
  112. package/app-dist/routes/chunk-61pcg25a.js +0 -1
  113. package/app-dist/routes/chunk-6nfhygvf.js +0 -1
  114. package/app-dist/routes/chunk-700e7je6.js +0 -33
  115. package/app-dist/routes/chunk-7fsn17kg.js +0 -1
  116. package/app-dist/routes/chunk-7k789b32.js +0 -1
  117. package/app-dist/routes/chunk-7r46q0ys.js +0 -36
  118. package/app-dist/routes/chunk-86fmc1fr.js +0 -5
  119. package/app-dist/routes/chunk-8qth37vw.js +0 -1
  120. package/app-dist/routes/chunk-924wv8n0.js +0 -1
  121. package/app-dist/routes/chunk-9mbhgxk9.js +0 -1
  122. package/app-dist/routes/chunk-a216hyd9.js +0 -1
  123. package/app-dist/routes/chunk-akzxykh9.js +0 -33
  124. package/app-dist/routes/chunk-b3dcvy8c.js +0 -1
  125. package/app-dist/routes/chunk-b74zahz5.js +0 -31
  126. package/app-dist/routes/chunk-bftj53p2.js +0 -5
  127. package/app-dist/routes/chunk-c01hnz3e.js +0 -1
  128. package/app-dist/routes/chunk-d8pvv5km.js +0 -1
  129. package/app-dist/routes/chunk-dev0aezr.js +0 -2
  130. package/app-dist/routes/chunk-dh6vnv0e.js +0 -1
  131. package/app-dist/routes/chunk-dn2cbpva.js +0 -36
  132. package/app-dist/routes/chunk-dvn0my90.js +0 -1
  133. package/app-dist/routes/chunk-dvq8mnve.js +0 -36
  134. package/app-dist/routes/chunk-e8c2gc4d.js +0 -5
  135. package/app-dist/routes/chunk-ejf9ak2x.js +0 -1
  136. package/app-dist/routes/chunk-f083m55s.js +0 -1
  137. package/app-dist/routes/chunk-fnrj28s1.js +0 -31
  138. package/app-dist/routes/chunk-fvg3yjdp.js +0 -31
  139. package/app-dist/routes/chunk-g7k381n1.js +0 -1
  140. package/app-dist/routes/chunk-h01kq2ae.js +0 -13
  141. package/app-dist/routes/chunk-h4dk761v.js +0 -5
  142. package/app-dist/routes/chunk-hmx91z2x.js +0 -5
  143. package/app-dist/routes/chunk-hxbg4m42.js +0 -36
  144. package/app-dist/routes/chunk-jbjnfp2b.js +0 -2
  145. package/app-dist/routes/chunk-jxtz5vv6.js +0 -36
  146. package/app-dist/routes/chunk-jxzcs0ey.js +0 -36
  147. package/app-dist/routes/chunk-kt7wwhcx.js +0 -1
  148. package/app-dist/routes/chunk-kzptszyc.js +0 -33
  149. package/app-dist/routes/chunk-mhgca4w4.js +0 -2
  150. package/app-dist/routes/chunk-mhswxa20.js +0 -1
  151. package/app-dist/routes/chunk-n8zfeex6.js +0 -1
  152. package/app-dist/routes/chunk-pee47b2r.js +0 -1
  153. package/app-dist/routes/chunk-pesmw829.js +0 -1
  154. package/app-dist/routes/chunk-pgc4c6f3.js +0 -36
  155. package/app-dist/routes/chunk-q8egegm1.js +0 -1
  156. package/app-dist/routes/chunk-q9mn2qyq.js +0 -36
  157. package/app-dist/routes/chunk-qh0rtaf3.js +0 -5
  158. package/app-dist/routes/chunk-qqhmk6ye.js +0 -2
  159. package/app-dist/routes/chunk-qrxygmf7.js +0 -33
  160. package/app-dist/routes/chunk-r46yzksx.js +0 -36
  161. package/app-dist/routes/chunk-rgpbw2w0.js +0 -5
  162. package/app-dist/routes/chunk-rnpzv3d8.js +0 -2
  163. package/app-dist/routes/chunk-s5v8cv05.js +0 -2
  164. package/app-dist/routes/chunk-sbwn5bpc.js +0 -1
  165. package/app-dist/routes/chunk-sqbg8jbt.js +0 -33
  166. package/app-dist/routes/chunk-sv8dqnf7.js +0 -1
  167. package/app-dist/routes/chunk-t67sw3za.js +0 -1
  168. package/app-dist/routes/chunk-tjdpqwdf.js +0 -31
  169. package/app-dist/routes/chunk-tq2mfghg.js +0 -1
  170. package/app-dist/routes/chunk-ttn10vt6.js +0 -1
  171. package/app-dist/routes/chunk-v2hzpjxr.js +0 -1
  172. package/app-dist/routes/chunk-wfjjkw9y.js +0 -1
  173. package/app-dist/routes/chunk-wt8cxzmf.js +0 -31
  174. package/app-dist/routes/chunk-x45d372k.js +0 -5
  175. package/app-dist/routes/chunk-y3wsazkt.js +0 -1
  176. package/app-dist/routes/chunk-y7pmgc7t.js +0 -33
  177. package/app-dist/routes/chunk-zefdt2q3.js +0 -31
  178. package/app-dist/routes/dropdowns.js +0 -6
  179. package/app-dist/routes/home.js +0 -1
  180. package/app-dist/routes/icons.js +0 -1
  181. package/app-dist/routes/inputs.js +0 -12
  182. package/app-dist/routes/installation.js +0 -1
  183. package/app-dist/routes/layout.js +0 -1
  184. package/app-dist/routes/modals.js +0 -7
  185. package/app-dist/routes/navbar.js +0 -1
  186. package/app-dist/routes/progress.js +0 -1
  187. package/app-dist/routes/radios.js +0 -6
  188. package/app-dist/routes/switches.js +0 -6
  189. package/app-dist/routes/tabs.js +0 -1
  190. package/app-dist/routes/toasts.js +0 -16
  191. package/assets/fonts/material-symbols-mini.woff2 +0 -0
  192. package/assets/fonts/material-symbols.woff2 +0 -0
  193. package/assets/fonts/roboto-400.woff2 +0 -0
  194. package/assets/fonts/roboto-500.woff2 +0 -0
  195. package/assets/fonts/roboto-700.woff2 +0 -0
  196. package/assets/logo-banner-400.jpg +0 -0
  197. package/assets/logo-banner-400.webp +0 -0
  198. package/assets/logo-banner-800.webp +0 -0
  199. package/assets/logo-banner.jpg +0 -0
  200. package/assets/logo-icon-64.jpg +0 -0
  201. package/assets/logo-icon-64.webp +0 -0
  202. package/assets/logo-icon.jpg +0 -0
  203. package/assets/logo-square.jpg +0 -0
  204. package/bun.lock +0 -312
  205. package/bunfig.toml +0 -4
  206. package/custom-elements.json +0 -1916
  207. package/demo/api/sample-data.json +0 -38
  208. package/demo/content/alerts.html +0 -115
  209. package/demo/content/avatars.html +0 -70
  210. package/demo/content/badges.html +0 -65
  211. package/demo/content/buttons.html +0 -188
  212. package/demo/content/callouts.html +0 -91
  213. package/demo/content/cards.html +0 -121
  214. package/demo/content/checkboxes.html +0 -178
  215. package/demo/content/chips.html +0 -67
  216. package/demo/content/codeblocks.html +0 -101
  217. package/demo/content/confirms.html +0 -115
  218. package/demo/content/datatables.html +0 -149
  219. package/demo/content/dividers.html +0 -119
  220. package/demo/content/dropdowns.html +0 -89
  221. package/demo/content/enterprise.html +0 -252
  222. package/demo/content/home.html +0 -149
  223. package/demo/content/icons.html +0 -89
  224. package/demo/content/inputs.html +0 -135
  225. package/demo/content/installation.html +0 -16
  226. package/demo/content/layout.html +0 -136
  227. package/demo/content/modals.html +0 -141
  228. package/demo/content/navbar.html +0 -70
  229. package/demo/content/progress.html +0 -119
  230. package/demo/content/radios.html +0 -88
  231. package/demo/content/skeletons.html +0 -109
  232. package/demo/content/spinners.html +0 -96
  233. package/demo/content/switches.html +0 -84
  234. package/demo/content/tables.html +0 -124
  235. package/demo/content/tabs.html +0 -85
  236. package/demo/content/toasts.html +0 -116
  237. package/demo/content/tooltips.html +0 -107
  238. package/demo/content/virtual-lists.html +0 -233
  239. package/demo/favicon.ico +0 -0
  240. package/demo/favicon.png +0 -0
  241. package/demo/full.html +0 -52
  242. package/demo/iife.html +0 -46
  243. package/demo/manifest.json +0 -34
  244. package/demo/pages/datatable-demo.html +0 -237
  245. package/demo/pages/prompt-ui-demo.html +0 -218
  246. package/demo/pages/responsive-demo.html +0 -122
  247. package/demo/pages/schema-form-demo.html +0 -270
  248. package/demo/robots.txt +0 -6
  249. package/demo/shell.html +0 -712
  250. package/demo/sw.js +0 -387
  251. package/lighthouse-audit.mjs +0 -113
  252. package/scripts/analyze-components.js +0 -105
  253. package/scripts/build-app.js +0 -193
  254. package/scripts/build-framework.js +0 -444
  255. package/scripts/build-utils.js +0 -101
  256. package/scripts/test-isolated.js +0 -151
  257. package/server.js +0 -256
  258. package/tests/agents/agent-integration.test.js +0 -76
  259. package/tests/benchmark.html +0 -296
  260. package/tests/build/scan-components.test.js +0 -173
  261. package/tests/components/all-components.test.js +0 -245
  262. package/tests/components/all-missing-components.test.js +0 -574
  263. package/tests/components/mu-alert.test.js +0 -113
  264. package/tests/components/mu-avatar.test.js +0 -148
  265. package/tests/components/mu-badge.test.js +0 -92
  266. package/tests/components/mu-button.test.js +0 -112
  267. package/tests/components/mu-card.test.js +0 -89
  268. package/tests/components/mu-checkbox.test.js +0 -158
  269. package/tests/components/mu-chip.test.js +0 -118
  270. package/tests/components/mu-container.test.js +0 -120
  271. package/tests/components/mu-divider.test.js +0 -98
  272. package/tests/components/mu-drawer-item.test.js +0 -199
  273. package/tests/components/mu-drawer.test.js +0 -96
  274. package/tests/components/mu-dropdown.test.js +0 -125
  275. package/tests/components/mu-form.test.js +0 -138
  276. package/tests/components/mu-grid.test.js +0 -135
  277. package/tests/components/mu-icon.test.js +0 -110
  278. package/tests/components/mu-input.test.js +0 -131
  279. package/tests/components/mu-lazy.test.js +0 -103
  280. package/tests/components/mu-modal.test.js +0 -275
  281. package/tests/components/mu-navbar.test.js +0 -101
  282. package/tests/components/mu-progress.test.js +0 -115
  283. package/tests/components/mu-radio.test.js +0 -114
  284. package/tests/components/mu-repeat.test.js +0 -106
  285. package/tests/components/mu-sidebar.test.js +0 -126
  286. package/tests/components/mu-skeleton.test.js +0 -162
  287. package/tests/components/mu-stack.test.js +0 -143
  288. package/tests/components/mu-switch.test.js +0 -292
  289. package/tests/components/mu-table.test.js +0 -124
  290. package/tests/components/mu-tabs.test.js +0 -104
  291. package/tests/components/mu-textarea.test.js +0 -115
  292. package/tests/components/mu-toast.test.js +0 -321
  293. package/tests/components/mu-tooltip.test.js +0 -133
  294. package/tests/components/mu-virtual-list.test.js +0 -109
  295. package/tests/core/MuElement.test.js +0 -120
  296. package/tests/core/agent-api.test.js +0 -125
  297. package/tests/core/all-core-modules.test.js +0 -442
  298. package/tests/core/bus.test.js +0 -364
  299. package/tests/core/component-schema.test.js +0 -160
  300. package/tests/core/feature-registry.test.js +0 -198
  301. package/tests/core/form-state.test.js +0 -167
  302. package/tests/core/http.test.js +0 -119
  303. package/tests/core/keyboard.test.js +0 -319
  304. package/tests/core/layers.test.js +0 -129
  305. package/tests/core/namespaced-stores.test.js +0 -114
  306. package/tests/core/render.test.js +0 -121
  307. package/tests/core/ripple.test.js +0 -131
  308. package/tests/core/router.test.js +0 -89
  309. package/tests/core/scheduler.test.js +0 -121
  310. package/tests/core/signals.test.js +0 -128
  311. package/tests/core/store.test.js +0 -171
  312. package/tests/core/transitions.test.js +0 -82
  313. package/tests/e2e/accessibility-harness.html +0 -58
  314. package/tests/e2e/accessibility.test.js +0 -401
  315. package/tests/e2e/agent-features.test.js +0 -372
  316. package/tests/e2e/card-spacing.test.js +0 -287
  317. package/tests/e2e/components.test.js +0 -439
  318. package/tests/e2e/demo-routes.test.js +0 -478
  319. package/tests/e2e/layout-css-fallback.test.js +0 -334
  320. package/tests/e2e/mu-alert.e2e.test.js +0 -111
  321. package/tests/e2e/mu-checkbox.test.js +0 -489
  322. package/tests/e2e/mu-chip.test.js +0 -347
  323. package/tests/e2e/mu-form.test.js +0 -499
  324. package/tests/e2e/mu-icon.test.js +0 -114
  325. package/tests/e2e/mu-radio.test.js +0 -113
  326. package/tests/e2e/mu-skeleton.test.js +0 -140
  327. package/tests/e2e/mu-switch.test.js +0 -415
  328. package/tests/e2e/mu-tabs.test.js +0 -494
  329. package/tests/e2e/mu-textarea.test.js +0 -242
  330. package/tests/e2e/mu-virtual-list.test.js +0 -427
  331. package/tests/e2e/perf-memory.test.js +0 -161
  332. package/tests/e2e/puppeteer-helper.js +0 -137
  333. package/tests/e2e/puppeteer.test.js +0 -226
  334. package/tests/e2e/pwa.test.js +0 -261
  335. package/tests/e2e/test-harness.html +0 -319
  336. package/tests/manual/test-components.html +0 -120
  337. package/tests/memory-test.html +0 -309
  338. package/tests/setup-dom.js +0 -93
  339. 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
- });