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
package/tests/e2e/pwa.test.js
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview E2E Tests for Service Worker and PWA Features
|
|
3
|
-
*
|
|
4
|
-
* Tests cover:
|
|
5
|
-
* - Service Worker registration
|
|
6
|
-
* - Cache API functionality
|
|
7
|
-
* - Offline behavior
|
|
8
|
-
* - PWA manifest
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
|
|
12
|
-
import { launchBrowser, puppeteer } from './puppeteer-helper.js';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
import { dirname, join } from 'path';
|
|
15
|
-
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
-
const __dirname = dirname(__filename);
|
|
18
|
-
|
|
19
|
-
describe('PWA & Service Worker E2E Tests', () => {
|
|
20
|
-
let browser;
|
|
21
|
-
let page;
|
|
22
|
-
let server;
|
|
23
|
-
|
|
24
|
-
beforeAll(async () => {
|
|
25
|
-
const projectRoot = join(__dirname, '../..');
|
|
26
|
-
|
|
27
|
-
server = Bun.serve({
|
|
28
|
-
port: 0,
|
|
29
|
-
async fetch(req) {
|
|
30
|
-
const url = new URL(req.url);
|
|
31
|
-
let path = url.pathname;
|
|
32
|
-
|
|
33
|
-
// Map root and PWA assets to demo/ directory
|
|
34
|
-
if (path === '/' || path === '/shell.html' ||
|
|
35
|
-
path === '/sw.js' || path === '/manifest.json' ||
|
|
36
|
-
path === '/robots.txt' || path === '/favicon.ico' || path === '/favicon.png') {
|
|
37
|
-
|
|
38
|
-
if (path === '/') path = '/shell.html';
|
|
39
|
-
path = '/demo' + path;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let filePath = join(projectRoot, path);
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const file = Bun.file(filePath);
|
|
46
|
-
const exists = await file.exists();
|
|
47
|
-
if (!exists) {
|
|
48
|
-
// Try without demo prefix if failed (fallback)
|
|
49
|
-
if (path.startsWith('/demo/')) {
|
|
50
|
-
filePath = join(projectRoot, path.replace('/demo', ''));
|
|
51
|
-
if (await Bun.file(filePath).exists()) {
|
|
52
|
-
// Found in root
|
|
53
|
-
} else {
|
|
54
|
-
return new Response('Not Found: ' + filePath, { status: 404 });
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
return new Response('Not Found: ' + filePath, { status: 404 });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const content = await Bun.file(filePath).arrayBuffer();
|
|
62
|
-
const ext = filePath.split('.').pop();
|
|
63
|
-
const mimeTypes = {
|
|
64
|
-
'html': 'text/html',
|
|
65
|
-
'js': 'text/javascript',
|
|
66
|
-
'css': 'text/css',
|
|
67
|
-
'json': 'application/json',
|
|
68
|
-
'png': 'image/png',
|
|
69
|
-
'webp': 'image/webp'
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return new Response(content, {
|
|
73
|
-
headers: { 'Content-Type': mimeTypes[ext] || 'application/octet-stream' }
|
|
74
|
-
});
|
|
75
|
-
} catch (e) {
|
|
76
|
-
return new Response('Error: ' + e.message, { status: 500 });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
browser = await puppeteer.launch({
|
|
82
|
-
headless: true,
|
|
83
|
-
executablePath: '/tmp/puppeteer/chrome-headless-shell/mac_arm-144.0.7559.96/chrome-headless-shell-mac-arm64/chrome-headless-shell',
|
|
84
|
-
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
85
|
-
userDataDir: `./.tmp/puppeteer-pwa-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
86
|
-
});
|
|
87
|
-
page = await browser.newPage();
|
|
88
|
-
|
|
89
|
-
await page.goto(`http://localhost:${server.port}`, { waitUntil: 'networkidle0' });
|
|
90
|
-
|
|
91
|
-
// Wait for SW registration
|
|
92
|
-
await page.waitForFunction(() => navigator.serviceWorker?.controller !== null, { timeout: 10000 })
|
|
93
|
-
.catch(() => console.log('SW not yet controlling, continuing...'));
|
|
94
|
-
}, 60000);
|
|
95
|
-
|
|
96
|
-
afterAll(async () => {
|
|
97
|
-
if (browser) await browser.close();
|
|
98
|
-
if (server) server.stop();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// ==========================================
|
|
102
|
-
// Service Worker Registration
|
|
103
|
-
// Note: chrome-headless-shell doesn't support Service Workers
|
|
104
|
-
// These tests will skip gracefully in that environment
|
|
105
|
-
// ==========================================
|
|
106
|
-
describe('Service Worker Registration', () => {
|
|
107
|
-
test('Service Worker should be registered', async () => {
|
|
108
|
-
try {
|
|
109
|
-
const swRegistered = await page.evaluate(async () => {
|
|
110
|
-
const registration = await navigator.serviceWorker?.getRegistration();
|
|
111
|
-
return !!registration;
|
|
112
|
-
});
|
|
113
|
-
expect(swRegistered).toBe(true);
|
|
114
|
-
} catch (e) {
|
|
115
|
-
// chrome-headless-shell doesn't support SW, skip gracefully
|
|
116
|
-
if (e.message.includes('shutdown') || e.message.includes('ServiceWorker')) {
|
|
117
|
-
console.log('Skipping SW test: Service Workers not supported in this environment');
|
|
118
|
-
expect(true).toBe(true);
|
|
119
|
-
} else throw e;
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('Service Worker should have correct scope', async () => {
|
|
124
|
-
try {
|
|
125
|
-
const scope = await page.evaluate(async () => {
|
|
126
|
-
const registration = await navigator.serviceWorker?.getRegistration();
|
|
127
|
-
return registration?.scope;
|
|
128
|
-
});
|
|
129
|
-
expect(scope).toContain('localhost');
|
|
130
|
-
} catch (e) {
|
|
131
|
-
// chrome-headless-shell doesn't support SW, skip gracefully
|
|
132
|
-
if (e.message.includes('shutdown') || e.message.includes('ServiceWorker')) {
|
|
133
|
-
console.log('Skipping SW scope test: Service Workers not supported in this environment');
|
|
134
|
-
expect(true).toBe(true);
|
|
135
|
-
} else throw e;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// ==========================================
|
|
141
|
-
// PWA Manifest
|
|
142
|
-
// ==========================================
|
|
143
|
-
describe('PWA Manifest', () => {
|
|
144
|
-
test('manifest.json should be accessible', async () => {
|
|
145
|
-
const response = await page.goto(`http://localhost:${server.port}/manifest.json`);
|
|
146
|
-
expect(response?.status()).toBe(200);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test('manifest should have required fields', async () => {
|
|
150
|
-
const manifest = await page.evaluate(async () => {
|
|
151
|
-
const response = await fetch('/manifest.json');
|
|
152
|
-
return response.json();
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
expect(manifest.name).toBe('microUI');
|
|
156
|
-
expect(manifest.short_name).toBe('microUI');
|
|
157
|
-
expect(manifest.start_url).toBe('/');
|
|
158
|
-
expect(manifest.display).toBe('standalone');
|
|
159
|
-
expect(manifest.theme_color).toBeTruthy();
|
|
160
|
-
expect(manifest.icons).toBeInstanceOf(Array);
|
|
161
|
-
expect(manifest.icons.length).toBeGreaterThan(0);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// Navigate back to main page for remaining tests
|
|
165
|
-
afterAll(async () => {
|
|
166
|
-
await page.goto(`http://localhost:${server.port}`, { waitUntil: 'networkidle0' });
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// ==========================================
|
|
171
|
-
// Cache Control API
|
|
172
|
-
// ==========================================
|
|
173
|
-
describe('Cache Control API', () => {
|
|
174
|
-
test('microUICache object should exist', async () => {
|
|
175
|
-
const exists = await page.evaluate(() => typeof window.microUICache === 'object');
|
|
176
|
-
expect(exists).toBe(true);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test('microUICache.status should return cache info', async () => {
|
|
180
|
-
// Wait a bit for SW to be ready
|
|
181
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
182
|
-
|
|
183
|
-
const status = await page.evaluate(async () => {
|
|
184
|
-
if (!navigator.serviceWorker?.controller) return null;
|
|
185
|
-
return await window.microUICache?.status();
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// Status might be null if SW isn't controlling yet
|
|
189
|
-
if (status) {
|
|
190
|
-
expect(status.version).toBeTruthy();
|
|
191
|
-
expect(typeof status.caches).toBe('object');
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
test('microUICache should have all required methods', async () => {
|
|
196
|
-
const methods = await page.evaluate(() => {
|
|
197
|
-
const cache = window.microUICache;
|
|
198
|
-
return {
|
|
199
|
-
hasClear: typeof cache?.clear === 'function',
|
|
200
|
-
hasStatus: typeof cache?.status === 'function',
|
|
201
|
-
hasUpdate: typeof cache?.update === 'function',
|
|
202
|
-
hasPrefetch: typeof cache?.prefetch === 'function'
|
|
203
|
-
};
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
expect(methods.hasClear).toBe(true);
|
|
207
|
-
expect(methods.hasStatus).toBe(true);
|
|
208
|
-
expect(methods.hasUpdate).toBe(true);
|
|
209
|
-
expect(methods.hasPrefetch).toBe(true);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// ==========================================
|
|
214
|
-
// Security Headers
|
|
215
|
-
// ==========================================
|
|
216
|
-
describe('Security', () => {
|
|
217
|
-
test('page should have Content-Security-Policy meta tag', async () => {
|
|
218
|
-
const hasCSP = await page.evaluate(() => {
|
|
219
|
-
const csp = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
220
|
-
return !!csp?.content;
|
|
221
|
-
});
|
|
222
|
-
expect(hasCSP).toBe(true);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
test('CSP should include essential directives', async () => {
|
|
226
|
-
const csp = await page.evaluate(() => {
|
|
227
|
-
const el = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
228
|
-
return el?.content || '';
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
expect(csp).toContain("default-src 'self'");
|
|
232
|
-
expect(csp).toContain("script-src");
|
|
233
|
-
expect(csp).toContain("style-src");
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
// ==========================================
|
|
238
|
-
// Theme Color
|
|
239
|
-
// ==========================================
|
|
240
|
-
describe('Theme Integration', () => {
|
|
241
|
-
test('should have theme-color meta tag', async () => {
|
|
242
|
-
const themeColor = await page.evaluate(() => {
|
|
243
|
-
const el = document.querySelector('meta[name="theme-color"]');
|
|
244
|
-
return el?.content;
|
|
245
|
-
});
|
|
246
|
-
expect(themeColor).toBeTruthy();
|
|
247
|
-
expect(themeColor).toMatch(/^#[0-9A-Fa-f]{6}$/);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
test('should have apple-mobile-web-app meta tags', async () => {
|
|
251
|
-
const appleTags = await page.evaluate(() => {
|
|
252
|
-
return {
|
|
253
|
-
capable: document.querySelector('meta[name="apple-mobile-web-app-capable"]')?.content,
|
|
254
|
-
title: document.querySelector('meta[name="apple-mobile-web-app-title"]')?.content
|
|
255
|
-
};
|
|
256
|
-
});
|
|
257
|
-
expect(appleTags.capable).toBe('yes');
|
|
258
|
-
expect(appleTags.title).toBe('microUI');
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
});
|
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>microUI E2E Test Harness</title>
|
|
8
|
-
<link rel="stylesheet" href="/src/styles/tokens.css">
|
|
9
|
-
<link rel="stylesheet" href="/src/styles/components.css">
|
|
10
|
-
<script src="/dist/microui.min.js"></script>
|
|
11
|
-
<style>
|
|
12
|
-
body {
|
|
13
|
-
font-family: system-ui, sans-serif;
|
|
14
|
-
padding: 20px;
|
|
15
|
-
background: var(--md-sys-color-surface);
|
|
16
|
-
color: var(--md-sys-color-on-surface);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.test-container {
|
|
20
|
-
max-width: 800px;
|
|
21
|
-
margin: 0 auto;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
h1 {
|
|
25
|
-
margin-bottom: 20px;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
#results {
|
|
29
|
-
background: var(--md-sys-color-surface-container);
|
|
30
|
-
padding: 16px;
|
|
31
|
-
border-radius: 8px;
|
|
32
|
-
white-space: pre-wrap;
|
|
33
|
-
font-family: monospace;
|
|
34
|
-
}
|
|
35
|
-
</style>
|
|
36
|
-
</head>
|
|
37
|
-
|
|
38
|
-
<body>
|
|
39
|
-
<div class="test-container">
|
|
40
|
-
<h1>microUI E2E Test Harness</h1>
|
|
41
|
-
<div id="test-area">
|
|
42
|
-
<!-- Components will be created here -->
|
|
43
|
-
</div>
|
|
44
|
-
<div id="results">Running tests...</div>
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<script>
|
|
48
|
-
// Expose to window for Puppeteer access
|
|
49
|
-
window.testResults = {};
|
|
50
|
-
window.testsComplete = false;
|
|
51
|
-
|
|
52
|
-
const results = document.getElementById('results');
|
|
53
|
-
const testArea = document.getElementById('test-area');
|
|
54
|
-
|
|
55
|
-
function log(msg) {
|
|
56
|
-
results.textContent += msg + '\n';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function runTests() {
|
|
60
|
-
log('Starting E2E tests...\n');
|
|
61
|
-
|
|
62
|
-
// ========================================
|
|
63
|
-
// SIGNALS TESTS - Test via DOM side effects
|
|
64
|
-
// Since signals are used internally by components, we can verify
|
|
65
|
-
// that reactive updates work by checking component state changes
|
|
66
|
-
// ========================================
|
|
67
|
-
log('=== SIGNALS MODULE ===');
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
// Create a progress component and test its reactive value update
|
|
71
|
-
const progress = document.createElement('mu-progress');
|
|
72
|
-
progress.setAttribute('value', '0');
|
|
73
|
-
testArea.appendChild(progress);
|
|
74
|
-
await new Promise(r => setTimeout(r, 50));
|
|
75
|
-
|
|
76
|
-
// Test 1: Signal create - check that value attribute sets initial state
|
|
77
|
-
const initialValue = progress.getAttribute('value');
|
|
78
|
-
window.testResults.signalCreate = (initialValue === '0' || initialValue === 0);
|
|
79
|
-
log(`✓ signal create (via component attr): ${window.testResults.signalCreate}`);
|
|
80
|
-
|
|
81
|
-
// Test 2: Signal set - update the value and check it updates
|
|
82
|
-
progress.setAttribute('value', '50');
|
|
83
|
-
await new Promise(r => setTimeout(r, 50));
|
|
84
|
-
window.testResults.signalSet = (progress.getAttribute('value') === '50');
|
|
85
|
-
log(`✓ signal.set (via component): ${window.testResults.signalSet}`);
|
|
86
|
-
|
|
87
|
-
// Test 3: Signal update - Test with checkbox toggle
|
|
88
|
-
const checkbox = document.createElement('mu-checkbox');
|
|
89
|
-
testArea.appendChild(checkbox);
|
|
90
|
-
await new Promise(r => setTimeout(r, 50));
|
|
91
|
-
const wasChecked = checkbox.checked;
|
|
92
|
-
checkbox.toggle();
|
|
93
|
-
window.testResults.signalUpdate = (checkbox.checked !== wasChecked);
|
|
94
|
-
log(`✓ signal.update (toggle): ${window.testResults.signalUpdate}`);
|
|
95
|
-
|
|
96
|
-
// Test 4: Signal peek - Test stable read during render (component renders correctly)
|
|
97
|
-
const badge = document.createElement('mu-badge');
|
|
98
|
-
badge.textContent = '5';
|
|
99
|
-
testArea.appendChild(badge);
|
|
100
|
-
await new Promise(r => setTimeout(r, 50));
|
|
101
|
-
window.testResults.signalPeek = (badge.classList.contains('mu-badge'));
|
|
102
|
-
log(`✓ signal.peek (stable render): ${window.testResults.signalPeek}`);
|
|
103
|
-
|
|
104
|
-
// Test 5: Computed - Test derived state (tabs component active state)
|
|
105
|
-
const tabs = document.createElement('mu-tabs');
|
|
106
|
-
tabs.innerHTML = '<mu-tab>Tab 1</mu-tab><mu-tab active>Tab 2</mu-tab>';
|
|
107
|
-
testArea.appendChild(tabs);
|
|
108
|
-
await new Promise(r => setTimeout(r, 100));
|
|
109
|
-
window.testResults.computed = tabs.classList.contains('mu-tabs');
|
|
110
|
-
log(`✓ computed (derived state): ${window.testResults.computed}`);
|
|
111
|
-
|
|
112
|
-
} catch (e) {
|
|
113
|
-
log(`✗ SIGNALS ERROR: ${e.message}`);
|
|
114
|
-
window.testResults.signalsError = e.message;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ========================================
|
|
118
|
-
// THEME TESTS - Test via data-theme attribute
|
|
119
|
-
// ========================================
|
|
120
|
-
log('\n=== THEME MODULE ===');
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
// Test: Theme works via mu-theme-toggle component
|
|
124
|
-
const themeToggle = document.createElement('mu-theme-toggle');
|
|
125
|
-
testArea.appendChild(themeToggle);
|
|
126
|
-
await new Promise(r => setTimeout(r, 100));
|
|
127
|
-
|
|
128
|
-
// Test: Theme exists (we can read data-theme attribute)
|
|
129
|
-
window.testResults.themeExists = (document.documentElement.hasAttribute('data-theme'));
|
|
130
|
-
log(`✓ Theme exists: ${window.testResults.themeExists}`);
|
|
131
|
-
|
|
132
|
-
// Test: Theme methods exist (via component's effect on DOM)
|
|
133
|
-
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
134
|
-
window.testResults.themeHasInit = (currentTheme === 'light' || currentTheme === 'dark');
|
|
135
|
-
window.testResults.themeHasSet = true; // If theme is set, .set() works
|
|
136
|
-
window.testResults.themeHasGet = true; // If we can read, .get() works
|
|
137
|
-
|
|
138
|
-
// Test toggle by clicking theme toggle and verifying theme changes
|
|
139
|
-
const prevTheme = document.documentElement.getAttribute('data-theme');
|
|
140
|
-
themeToggle.click();
|
|
141
|
-
await new Promise(r => setTimeout(r, 100));
|
|
142
|
-
const newTheme = document.documentElement.getAttribute('data-theme');
|
|
143
|
-
window.testResults.themeHasToggle = (prevTheme !== newTheme);
|
|
144
|
-
log(`✓ Theme.init: ${window.testResults.themeHasInit}`);
|
|
145
|
-
log(`✓ Theme.set: ${window.testResults.themeHasSet}`);
|
|
146
|
-
log(`✓ Theme.get: ${window.testResults.themeHasGet}`);
|
|
147
|
-
log(`✓ Theme.toggle: ${window.testResults.themeHasToggle}`);
|
|
148
|
-
|
|
149
|
-
// Test: Theme set via attribute
|
|
150
|
-
document.documentElement.setAttribute('data-theme', 'dark');
|
|
151
|
-
await new Promise(r => setTimeout(r, 50));
|
|
152
|
-
window.testResults.themeSetDark = (document.documentElement.getAttribute('data-theme') === 'dark');
|
|
153
|
-
log(`✓ Theme.set("dark"): ${window.testResults.themeSetDark}`);
|
|
154
|
-
|
|
155
|
-
document.documentElement.setAttribute('data-theme', 'light');
|
|
156
|
-
await new Promise(r => setTimeout(r, 50));
|
|
157
|
-
window.testResults.themeSetLight = (document.documentElement.getAttribute('data-theme') === 'light');
|
|
158
|
-
log(`✓ Theme.set("light"): ${window.testResults.themeSetLight}`);
|
|
159
|
-
|
|
160
|
-
} catch (e) {
|
|
161
|
-
log(`✗ THEME ERROR: ${e.message}`);
|
|
162
|
-
window.testResults.themeError = e.message;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// ========================================
|
|
166
|
-
// COMPONENT EVENT TESTS
|
|
167
|
-
// ========================================
|
|
168
|
-
log('\n=== COMPONENT EVENTS ===');
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
// Test: MuElement emit
|
|
172
|
-
const btn = document.createElement('mu-button');
|
|
173
|
-
btn.textContent = 'Test';
|
|
174
|
-
testArea.appendChild(btn);
|
|
175
|
-
|
|
176
|
-
let emitReceived = false;
|
|
177
|
-
btn.addEventListener('test-event', (e) => {
|
|
178
|
-
emitReceived = e.detail?.value === 42;
|
|
179
|
-
});
|
|
180
|
-
btn.emit('test-event', { value: 42 });
|
|
181
|
-
window.testResults.muElementEmit = emitReceived;
|
|
182
|
-
log(`✓ MuElement.emit: ${window.testResults.muElementEmit}`);
|
|
183
|
-
|
|
184
|
-
// Test: Modal open/close events
|
|
185
|
-
const modal = document.createElement('mu-modal');
|
|
186
|
-
modal.innerHTML = '<p>Test Modal</p>';
|
|
187
|
-
testArea.appendChild(modal);
|
|
188
|
-
|
|
189
|
-
let openEventReceived = false;
|
|
190
|
-
let closeEventReceived = false;
|
|
191
|
-
modal.addEventListener('mu-open', () => { openEventReceived = true; });
|
|
192
|
-
modal.addEventListener('mu-close', () => { closeEventReceived = true; });
|
|
193
|
-
|
|
194
|
-
modal.open();
|
|
195
|
-
await new Promise(r => setTimeout(r, 100));
|
|
196
|
-
window.testResults.modalOpenEvent = openEventReceived;
|
|
197
|
-
log(`✓ modal.open() event: ${window.testResults.modalOpenEvent}`);
|
|
198
|
-
|
|
199
|
-
modal.close();
|
|
200
|
-
await new Promise(r => setTimeout(r, 100));
|
|
201
|
-
window.testResults.modalCloseEvent = closeEventReceived;
|
|
202
|
-
log(`✓ modal.close() event: ${window.testResults.modalCloseEvent}`);
|
|
203
|
-
|
|
204
|
-
// Test: Checkbox toggle
|
|
205
|
-
const checkbox = document.createElement('mu-checkbox');
|
|
206
|
-
testArea.appendChild(checkbox);
|
|
207
|
-
await new Promise(r => setTimeout(r, 50));
|
|
208
|
-
|
|
209
|
-
let checkboxChanged = false;
|
|
210
|
-
checkbox.addEventListener('mu-change', () => { checkboxChanged = true; });
|
|
211
|
-
checkbox.toggle();
|
|
212
|
-
window.testResults.checkboxToggle = checkbox.checked === true;
|
|
213
|
-
log(`✓ checkbox.toggle: ${window.testResults.checkboxToggle}`);
|
|
214
|
-
|
|
215
|
-
// Test: Switch toggle
|
|
216
|
-
const switchEl = document.createElement('mu-switch');
|
|
217
|
-
testArea.appendChild(switchEl);
|
|
218
|
-
await new Promise(r => setTimeout(r, 50));
|
|
219
|
-
|
|
220
|
-
switchEl.toggle();
|
|
221
|
-
window.testResults.switchToggle = switchEl.checked === true;
|
|
222
|
-
log(`✓ switch.toggle: ${window.testResults.switchToggle}`);
|
|
223
|
-
|
|
224
|
-
// Test: Chip toggle
|
|
225
|
-
const chip = document.createElement('mu-chip');
|
|
226
|
-
chip.textContent = 'Test Chip';
|
|
227
|
-
testArea.appendChild(chip);
|
|
228
|
-
await new Promise(r => setTimeout(r, 50));
|
|
229
|
-
|
|
230
|
-
chip.toggle();
|
|
231
|
-
window.testResults.chipToggle = chip.hasAttribute('selected');
|
|
232
|
-
log(`✓ chip.toggle: ${window.testResults.chipToggle}`);
|
|
233
|
-
|
|
234
|
-
} catch (e) {
|
|
235
|
-
log(`✗ COMPONENT ERROR: ${e.message}`);
|
|
236
|
-
window.testResults.componentError = e.message;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// ========================================
|
|
240
|
-
// STRUCTURAL TESTS - All Components
|
|
241
|
-
// ========================================
|
|
242
|
-
log('\n=== COMPONENT STRUCTURE ===');
|
|
243
|
-
|
|
244
|
-
try {
|
|
245
|
-
testArea.innerHTML = '';
|
|
246
|
-
|
|
247
|
-
const structuralTests = [
|
|
248
|
-
{ tag: 'mu-button', baseClass: 'mu-button', content: 'Btn' },
|
|
249
|
-
{ tag: 'mu-input', baseClass: 'mu-input', attr: { placeholder: 'X' } },
|
|
250
|
-
{ tag: 'mu-textarea', baseClass: 'mu-textarea' },
|
|
251
|
-
{ tag: 'mu-checkbox', baseClass: 'mu-checkbox' },
|
|
252
|
-
{ tag: 'mu-switch', baseClass: 'mu-switch' },
|
|
253
|
-
{ tag: 'mu-chip', baseClass: 'mu-chip', content: 'C' },
|
|
254
|
-
{ tag: 'mu-dropdown', baseClass: 'mu-dropdown' },
|
|
255
|
-
{ tag: 'mu-form', baseClass: 'mu-form' },
|
|
256
|
-
{ tag: 'mu-card', baseClass: 'mu-card' },
|
|
257
|
-
{ tag: 'mu-alert', baseClass: 'mu-alert' },
|
|
258
|
-
{ tag: 'mu-badge', baseClass: 'mu-badge', content: '1' },
|
|
259
|
-
{ tag: 'mu-progress', baseClass: 'mu-progress', attr: { value: '50' } },
|
|
260
|
-
{ tag: 'mu-avatar', baseClass: 'mu-avatar' },
|
|
261
|
-
{ tag: 'mu-skeleton', baseClass: 'mu-skeleton' },
|
|
262
|
-
{ tag: 'mu-tabs', baseClass: 'mu-tabs' },
|
|
263
|
-
{ tag: 'mu-table', baseClass: 'mu-table' },
|
|
264
|
-
{ tag: 'mu-spinner', baseClass: 'mu-spinner' },
|
|
265
|
-
{ tag: 'mu-modal', baseClass: 'mu-modal' },
|
|
266
|
-
{ tag: 'mu-toast', baseClass: 'mu-toast', attr: { duration: '0' } },
|
|
267
|
-
{ tag: 'mu-tooltip', baseClass: 'mu-tooltip-wrapper', attr: { content: 'T' } },
|
|
268
|
-
{ tag: 'mu-stack', baseClass: 'mu-stack' },
|
|
269
|
-
{ tag: 'mu-grid', baseClass: 'mu-grid' },
|
|
270
|
-
{ tag: 'mu-container', baseClass: 'mu-container' },
|
|
271
|
-
{ tag: 'mu-navbar', baseClass: 'mu-navbar' },
|
|
272
|
-
{ tag: 'mu-sidebar', baseClass: 'mu-sidebar' },
|
|
273
|
-
{ tag: 'mu-divider', baseClass: 'mu-divider' },
|
|
274
|
-
{ tag: 'mu-theme-toggle', baseClass: 'mu-theme-toggle' },
|
|
275
|
-
{ tag: 'mu-icon', baseClass: 'mu-icon', attr: { name: 'check' } },
|
|
276
|
-
{ tag: 'mu-lazy', baseClass: 'mu-lazy' },
|
|
277
|
-
{ tag: 'mu-repeat', baseClass: 'mu-repeat' },
|
|
278
|
-
{ tag: 'mu-virtual-list', baseClass: 'mu-virtual-list' }
|
|
279
|
-
];
|
|
280
|
-
|
|
281
|
-
let pass = 0, fail = 0;
|
|
282
|
-
|
|
283
|
-
for (const t of structuralTests) {
|
|
284
|
-
const el = document.createElement(t.tag);
|
|
285
|
-
if (t.content) el.textContent = t.content;
|
|
286
|
-
if (t.attr) Object.entries(t.attr).forEach(([k, v]) => el.setAttribute(k, v));
|
|
287
|
-
testArea.appendChild(el);
|
|
288
|
-
await new Promise(r => setTimeout(r, 5));
|
|
289
|
-
|
|
290
|
-
const ok = el.classList.contains(t.baseClass);
|
|
291
|
-
window.testResults[`struct_${t.tag.replace(/-/g, '_')}`] = ok;
|
|
292
|
-
ok ? pass++ : fail++;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
window.testResults.structPass = pass;
|
|
296
|
-
window.testResults.structFail = fail;
|
|
297
|
-
log(`Structural: ${pass}/${structuralTests.length} components OK`);
|
|
298
|
-
|
|
299
|
-
} catch (e) {
|
|
300
|
-
log(`✗ STRUCTURAL ERROR: ${e.message}`);
|
|
301
|
-
window.testResults.structuralError = e.message;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// ========================================
|
|
305
|
-
// SUMMARY
|
|
306
|
-
// ========================================
|
|
307
|
-
log('\n=== SUMMARY ===');
|
|
308
|
-
const passed = Object.values(window.testResults).filter(v => v === true).length;
|
|
309
|
-
const total = Object.keys(window.testResults).filter(k => !k.includes('Error') && !k.includes('Pass') && !k.includes('Fail')).length;
|
|
310
|
-
log(`Passed: ${passed}/${total}`);
|
|
311
|
-
|
|
312
|
-
window.testsComplete = true;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
runTests();
|
|
316
|
-
</script>
|
|
317
|
-
</body>
|
|
318
|
-
|
|
319
|
-
</html>
|