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.
- package/AGENTS.md +71 -71
- package/CHANGELOG.md +1 -1
- package/README.md +14 -9
- package/dist/AGENTS.md +116 -116
- package/dist/README.md +21 -16
- package/dist/components.css +1 -1
- package/dist/microui.css +1 -1
- package/dist/microui.esm.js.map +1 -1
- package/dist/microui.min.js.map +1 -1
- package/dist/styles/components/switch.css +1 -1
- package/docs/getting-started.md +3 -3
- package/package.json +38 -10
- package/src/components/mu-schema-form.js +1 -1
- package/src/styles/components/switch.css +7 -8
- package/src/styles/components.css +6 -6
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -33
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
- package/.github/workflows/ci.yml +0 -42
- package/.github/workflows/deploy-pages.yml +0 -112
- package/CODE_OF_CONDUCT.md +0 -59
- package/CONTRIBUTING.md +0 -156
- package/SECURITY.md +0 -58
- package/app/.generated/routes/alerts.js +0 -8
- package/app/.generated/routes/avatars.js +0 -8
- package/app/.generated/routes/badges.js +0 -8
- package/app/.generated/routes/buttons.js +0 -10
- package/app/.generated/routes/cards.js +0 -10
- package/app/.generated/routes/checkboxes.js +0 -9
- package/app/.generated/routes/chips.js +0 -8
- package/app/.generated/routes/dropdowns.js +0 -9
- package/app/.generated/routes/home.js +0 -7
- package/app/.generated/routes/icons.js +0 -9
- package/app/.generated/routes/inputs.js +0 -10
- package/app/.generated/routes/installation.js +0 -7
- package/app/.generated/routes/layout.js +0 -9
- package/app/.generated/routes/modals.js +0 -9
- package/app/.generated/routes/navbar.js +0 -7
- package/app/.generated/routes/progress.js +0 -9
- package/app/.generated/routes/radios.js +0 -9
- package/app/.generated/routes/switches.js +0 -9
- package/app/.generated/routes/tabs.js +0 -8
- package/app/.generated/routes/toasts.js +0 -9
- package/app/index.html +0 -67
- package/app/pages/alerts.html +0 -23
- package/app/pages/avatars.html +0 -22
- package/app/pages/badges.html +0 -22
- package/app/pages/buttons.html +0 -71
- package/app/pages/cards.html +0 -54
- package/app/pages/checkboxes.html +0 -39
- package/app/pages/chips.html +0 -23
- package/app/pages/dropdowns.html +0 -41
- package/app/pages/home.html +0 -59
- package/app/pages/icons.html +0 -29
- package/app/pages/inputs.html +0 -66
- package/app/pages/installation.html +0 -34
- package/app/pages/layout.html +0 -30
- package/app/pages/modals.html +0 -21
- package/app/pages/navbar.html +0 -22
- package/app/pages/progress.html +0 -35
- package/app/pages/radios.html +0 -40
- package/app/pages/switches.html +0 -39
- package/app/pages/tabs.html +0 -30
- package/app/pages/toasts.html +0 -22
- package/app-dist/index.html +0 -67
- package/app-dist/pages/alerts.html +0 -23
- package/app-dist/pages/avatars.html +0 -22
- package/app-dist/pages/badges.html +0 -22
- package/app-dist/pages/buttons.html +0 -71
- package/app-dist/pages/cards.html +0 -54
- package/app-dist/pages/checkboxes.html +0 -39
- package/app-dist/pages/chips.html +0 -23
- package/app-dist/pages/dropdowns.html +0 -41
- package/app-dist/pages/home.html +0 -59
- package/app-dist/pages/icons.html +0 -29
- package/app-dist/pages/inputs.html +0 -66
- package/app-dist/pages/installation.html +0 -34
- package/app-dist/pages/layout.html +0 -30
- package/app-dist/pages/modals.html +0 -21
- package/app-dist/pages/navbar.html +0 -22
- package/app-dist/pages/progress.html +0 -35
- package/app-dist/pages/radios.html +0 -40
- package/app-dist/pages/switches.html +0 -39
- package/app-dist/pages/tabs.html +0 -30
- package/app-dist/pages/toasts.html +0 -22
- package/app-dist/pages.json +0 -217
- package/app-dist/routes/alerts.js +0 -5
- package/app-dist/routes/avatars.js +0 -1
- package/app-dist/routes/badges.js +0 -1
- package/app-dist/routes/buttons.js +0 -1
- package/app-dist/routes/cards.js +0 -1
- package/app-dist/routes/checkboxes.js +0 -9
- package/app-dist/routes/chips.js +0 -4
- package/app-dist/routes/chunk-019e5e2f.js +0 -5
- package/app-dist/routes/chunk-0m4j19yd.js +0 -2
- package/app-dist/routes/chunk-0tmmp5q0.js +0 -1
- package/app-dist/routes/chunk-10xn709r.js +0 -1
- package/app-dist/routes/chunk-15m2qcda.js +0 -2
- package/app-dist/routes/chunk-1bh8g23n.js +0 -1
- package/app-dist/routes/chunk-1vg0v937.js +0 -1
- package/app-dist/routes/chunk-1zvcgy3j.js +0 -1
- package/app-dist/routes/chunk-2afb0861.js +0 -1
- package/app-dist/routes/chunk-2c6ttpzt.js +0 -5
- package/app-dist/routes/chunk-3dy30fhs.js +0 -1
- package/app-dist/routes/chunk-426dnces.js +0 -13
- package/app-dist/routes/chunk-44kgxery.js +0 -1
- package/app-dist/routes/chunk-47fdnejd.js +0 -33
- package/app-dist/routes/chunk-49a6t2vq.js +0 -1
- package/app-dist/routes/chunk-4fe1rm5b.js +0 -1
- package/app-dist/routes/chunk-4ggmvkta.js +0 -33
- package/app-dist/routes/chunk-4vkz81q7.js +0 -33
- package/app-dist/routes/chunk-4w4tmj8f.js +0 -31
- package/app-dist/routes/chunk-532s62kr.js +0 -31
- package/app-dist/routes/chunk-5hm3bssy.js +0 -33
- package/app-dist/routes/chunk-5vrh24hc.js +0 -1
- package/app-dist/routes/chunk-61pcg25a.js +0 -1
- package/app-dist/routes/chunk-6nfhygvf.js +0 -1
- package/app-dist/routes/chunk-700e7je6.js +0 -33
- package/app-dist/routes/chunk-7fsn17kg.js +0 -1
- package/app-dist/routes/chunk-7k789b32.js +0 -1
- package/app-dist/routes/chunk-7r46q0ys.js +0 -36
- package/app-dist/routes/chunk-86fmc1fr.js +0 -5
- package/app-dist/routes/chunk-8qth37vw.js +0 -1
- package/app-dist/routes/chunk-924wv8n0.js +0 -1
- package/app-dist/routes/chunk-9mbhgxk9.js +0 -1
- package/app-dist/routes/chunk-a216hyd9.js +0 -1
- package/app-dist/routes/chunk-akzxykh9.js +0 -33
- package/app-dist/routes/chunk-b3dcvy8c.js +0 -1
- package/app-dist/routes/chunk-b74zahz5.js +0 -31
- package/app-dist/routes/chunk-bftj53p2.js +0 -5
- package/app-dist/routes/chunk-c01hnz3e.js +0 -1
- package/app-dist/routes/chunk-d8pvv5km.js +0 -1
- package/app-dist/routes/chunk-dev0aezr.js +0 -2
- package/app-dist/routes/chunk-dh6vnv0e.js +0 -1
- package/app-dist/routes/chunk-dn2cbpva.js +0 -36
- package/app-dist/routes/chunk-dvn0my90.js +0 -1
- package/app-dist/routes/chunk-dvq8mnve.js +0 -36
- package/app-dist/routes/chunk-e8c2gc4d.js +0 -5
- package/app-dist/routes/chunk-ejf9ak2x.js +0 -1
- package/app-dist/routes/chunk-f083m55s.js +0 -1
- package/app-dist/routes/chunk-fnrj28s1.js +0 -31
- package/app-dist/routes/chunk-fvg3yjdp.js +0 -31
- package/app-dist/routes/chunk-g7k381n1.js +0 -1
- package/app-dist/routes/chunk-h01kq2ae.js +0 -13
- package/app-dist/routes/chunk-h4dk761v.js +0 -5
- package/app-dist/routes/chunk-hmx91z2x.js +0 -5
- package/app-dist/routes/chunk-hxbg4m42.js +0 -36
- package/app-dist/routes/chunk-jbjnfp2b.js +0 -2
- package/app-dist/routes/chunk-jxtz5vv6.js +0 -36
- package/app-dist/routes/chunk-jxzcs0ey.js +0 -36
- package/app-dist/routes/chunk-kt7wwhcx.js +0 -1
- package/app-dist/routes/chunk-kzptszyc.js +0 -33
- package/app-dist/routes/chunk-mhgca4w4.js +0 -2
- package/app-dist/routes/chunk-mhswxa20.js +0 -1
- package/app-dist/routes/chunk-n8zfeex6.js +0 -1
- package/app-dist/routes/chunk-pee47b2r.js +0 -1
- package/app-dist/routes/chunk-pesmw829.js +0 -1
- package/app-dist/routes/chunk-pgc4c6f3.js +0 -36
- package/app-dist/routes/chunk-q8egegm1.js +0 -1
- package/app-dist/routes/chunk-q9mn2qyq.js +0 -36
- package/app-dist/routes/chunk-qh0rtaf3.js +0 -5
- package/app-dist/routes/chunk-qqhmk6ye.js +0 -2
- package/app-dist/routes/chunk-qrxygmf7.js +0 -33
- package/app-dist/routes/chunk-r46yzksx.js +0 -36
- package/app-dist/routes/chunk-rgpbw2w0.js +0 -5
- package/app-dist/routes/chunk-rnpzv3d8.js +0 -2
- package/app-dist/routes/chunk-s5v8cv05.js +0 -2
- package/app-dist/routes/chunk-sbwn5bpc.js +0 -1
- package/app-dist/routes/chunk-sqbg8jbt.js +0 -33
- package/app-dist/routes/chunk-sv8dqnf7.js +0 -1
- package/app-dist/routes/chunk-t67sw3za.js +0 -1
- package/app-dist/routes/chunk-tjdpqwdf.js +0 -31
- package/app-dist/routes/chunk-tq2mfghg.js +0 -1
- package/app-dist/routes/chunk-ttn10vt6.js +0 -1
- package/app-dist/routes/chunk-v2hzpjxr.js +0 -1
- package/app-dist/routes/chunk-wfjjkw9y.js +0 -1
- package/app-dist/routes/chunk-wt8cxzmf.js +0 -31
- package/app-dist/routes/chunk-x45d372k.js +0 -5
- package/app-dist/routes/chunk-y3wsazkt.js +0 -1
- package/app-dist/routes/chunk-y7pmgc7t.js +0 -33
- package/app-dist/routes/chunk-zefdt2q3.js +0 -31
- package/app-dist/routes/dropdowns.js +0 -6
- package/app-dist/routes/home.js +0 -1
- package/app-dist/routes/icons.js +0 -1
- package/app-dist/routes/inputs.js +0 -12
- package/app-dist/routes/installation.js +0 -1
- package/app-dist/routes/layout.js +0 -1
- package/app-dist/routes/modals.js +0 -7
- package/app-dist/routes/navbar.js +0 -1
- package/app-dist/routes/progress.js +0 -1
- package/app-dist/routes/radios.js +0 -6
- package/app-dist/routes/switches.js +0 -6
- package/app-dist/routes/tabs.js +0 -1
- package/app-dist/routes/toasts.js +0 -16
- package/assets/fonts/material-symbols-mini.woff2 +0 -0
- package/assets/fonts/material-symbols.woff2 +0 -0
- package/assets/fonts/roboto-400.woff2 +0 -0
- package/assets/fonts/roboto-500.woff2 +0 -0
- package/assets/fonts/roboto-700.woff2 +0 -0
- package/assets/logo-banner-400.jpg +0 -0
- package/assets/logo-banner-400.webp +0 -0
- package/assets/logo-banner-800.webp +0 -0
- package/assets/logo-banner.jpg +0 -0
- package/assets/logo-icon-64.jpg +0 -0
- package/assets/logo-icon-64.webp +0 -0
- package/assets/logo-icon.jpg +0 -0
- package/assets/logo-square.jpg +0 -0
- package/bun.lock +0 -312
- package/bunfig.toml +0 -4
- package/custom-elements.json +0 -1916
- package/demo/api/sample-data.json +0 -38
- package/demo/content/alerts.html +0 -115
- package/demo/content/avatars.html +0 -70
- package/demo/content/badges.html +0 -65
- package/demo/content/buttons.html +0 -188
- package/demo/content/callouts.html +0 -91
- package/demo/content/cards.html +0 -121
- package/demo/content/checkboxes.html +0 -178
- package/demo/content/chips.html +0 -67
- package/demo/content/codeblocks.html +0 -101
- package/demo/content/confirms.html +0 -115
- package/demo/content/datatables.html +0 -149
- package/demo/content/dividers.html +0 -119
- package/demo/content/dropdowns.html +0 -89
- package/demo/content/enterprise.html +0 -252
- package/demo/content/home.html +0 -149
- package/demo/content/icons.html +0 -89
- package/demo/content/inputs.html +0 -135
- package/demo/content/installation.html +0 -16
- package/demo/content/layout.html +0 -136
- package/demo/content/modals.html +0 -141
- package/demo/content/navbar.html +0 -70
- package/demo/content/progress.html +0 -119
- package/demo/content/radios.html +0 -88
- package/demo/content/skeletons.html +0 -109
- package/demo/content/spinners.html +0 -96
- package/demo/content/switches.html +0 -84
- package/demo/content/tables.html +0 -124
- package/demo/content/tabs.html +0 -85
- package/demo/content/toasts.html +0 -116
- package/demo/content/tooltips.html +0 -107
- package/demo/content/virtual-lists.html +0 -233
- package/demo/favicon.ico +0 -0
- package/demo/favicon.png +0 -0
- package/demo/full.html +0 -52
- package/demo/iife.html +0 -46
- package/demo/manifest.json +0 -34
- package/demo/pages/datatable-demo.html +0 -237
- package/demo/pages/prompt-ui-demo.html +0 -218
- package/demo/pages/responsive-demo.html +0 -122
- package/demo/pages/schema-form-demo.html +0 -270
- package/demo/robots.txt +0 -6
- package/demo/shell.html +0 -712
- package/demo/sw.js +0 -387
- package/lighthouse-audit.mjs +0 -113
- package/scripts/analyze-components.js +0 -105
- package/scripts/build-app.js +0 -193
- package/scripts/build-framework.js +0 -444
- package/scripts/build-utils.js +0 -101
- package/scripts/test-isolated.js +0 -151
- package/server.js +0 -256
- package/tests/agents/agent-integration.test.js +0 -76
- package/tests/benchmark.html +0 -296
- package/tests/build/scan-components.test.js +0 -173
- package/tests/components/all-components.test.js +0 -245
- package/tests/components/all-missing-components.test.js +0 -574
- package/tests/components/mu-alert.test.js +0 -113
- package/tests/components/mu-avatar.test.js +0 -148
- package/tests/components/mu-badge.test.js +0 -92
- package/tests/components/mu-button.test.js +0 -112
- package/tests/components/mu-card.test.js +0 -89
- package/tests/components/mu-checkbox.test.js +0 -158
- package/tests/components/mu-chip.test.js +0 -118
- package/tests/components/mu-container.test.js +0 -120
- package/tests/components/mu-divider.test.js +0 -98
- package/tests/components/mu-drawer-item.test.js +0 -199
- package/tests/components/mu-drawer.test.js +0 -96
- package/tests/components/mu-dropdown.test.js +0 -125
- package/tests/components/mu-form.test.js +0 -138
- package/tests/components/mu-grid.test.js +0 -135
- package/tests/components/mu-icon.test.js +0 -110
- package/tests/components/mu-input.test.js +0 -131
- package/tests/components/mu-lazy.test.js +0 -103
- package/tests/components/mu-modal.test.js +0 -275
- package/tests/components/mu-navbar.test.js +0 -101
- package/tests/components/mu-progress.test.js +0 -115
- package/tests/components/mu-radio.test.js +0 -114
- package/tests/components/mu-repeat.test.js +0 -106
- package/tests/components/mu-sidebar.test.js +0 -126
- package/tests/components/mu-skeleton.test.js +0 -162
- package/tests/components/mu-stack.test.js +0 -143
- package/tests/components/mu-switch.test.js +0 -292
- package/tests/components/mu-table.test.js +0 -124
- package/tests/components/mu-tabs.test.js +0 -104
- package/tests/components/mu-textarea.test.js +0 -115
- package/tests/components/mu-toast.test.js +0 -321
- package/tests/components/mu-tooltip.test.js +0 -133
- package/tests/components/mu-virtual-list.test.js +0 -109
- package/tests/core/MuElement.test.js +0 -120
- package/tests/core/agent-api.test.js +0 -125
- package/tests/core/all-core-modules.test.js +0 -442
- package/tests/core/bus.test.js +0 -364
- package/tests/core/component-schema.test.js +0 -160
- package/tests/core/feature-registry.test.js +0 -198
- package/tests/core/form-state.test.js +0 -167
- package/tests/core/http.test.js +0 -119
- package/tests/core/keyboard.test.js +0 -319
- package/tests/core/layers.test.js +0 -129
- package/tests/core/namespaced-stores.test.js +0 -114
- package/tests/core/render.test.js +0 -121
- package/tests/core/ripple.test.js +0 -131
- package/tests/core/router.test.js +0 -89
- package/tests/core/scheduler.test.js +0 -121
- package/tests/core/signals.test.js +0 -128
- package/tests/core/store.test.js +0 -171
- package/tests/core/transitions.test.js +0 -82
- package/tests/e2e/accessibility-harness.html +0 -58
- package/tests/e2e/accessibility.test.js +0 -401
- package/tests/e2e/agent-features.test.js +0 -372
- package/tests/e2e/card-spacing.test.js +0 -287
- package/tests/e2e/components.test.js +0 -439
- package/tests/e2e/demo-routes.test.js +0 -478
- package/tests/e2e/layout-css-fallback.test.js +0 -334
- package/tests/e2e/mu-alert.e2e.test.js +0 -111
- package/tests/e2e/mu-checkbox.test.js +0 -489
- package/tests/e2e/mu-chip.test.js +0 -347
- package/tests/e2e/mu-form.test.js +0 -499
- package/tests/e2e/mu-icon.test.js +0 -114
- package/tests/e2e/mu-radio.test.js +0 -113
- package/tests/e2e/mu-skeleton.test.js +0 -140
- package/tests/e2e/mu-switch.test.js +0 -415
- package/tests/e2e/mu-tabs.test.js +0 -494
- package/tests/e2e/mu-textarea.test.js +0 -242
- package/tests/e2e/mu-virtual-list.test.js +0 -427
- package/tests/e2e/perf-memory.test.js +0 -161
- package/tests/e2e/puppeteer-helper.js +0 -137
- package/tests/e2e/puppeteer.test.js +0 -226
- package/tests/e2e/pwa.test.js +0 -261
- package/tests/e2e/test-harness.html +0 -319
- package/tests/manual/test-components.html +0 -120
- package/tests/memory-test.html +0 -309
- package/tests/setup-dom.js +0 -93
- 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
|
-
});
|