jsgui3-server 0.0.148 → 0.0.149
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/.github/workflows/control-scan-manifest-check.yml +31 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-071799b982906680f5fd699d.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-07352945ad5c92654fcb8b65.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-138a601fadb6191ea314c6fd.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-171f6c381c2cadf2e9fa7087.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-1d973388156b84a04373fac9.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-20e117bc8a10d2cd16234bbe.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-2b028a82b0e5efddba42425f.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-4518556cd5c7e059e82b22b8.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5bac1aa0f213902f718ed74f.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5f9996ac7822caf777d92f56.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-60a92c702e65fd9cf748e3ec.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6164c1f8f738995c541895d2.js +44 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6718a85eb9e5aa782dd47a05.js +45 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-69e280f14e37aee76a1d4675.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7570d1b030d44b111ed59c4c.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7798c9bbd55e510d5039f936.js +42 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-78cd511ea1ef18ecb03d1be5.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7d482e0b95bcb5e3c543118b.js +43 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-80e9476d1127c55b40fdb36f.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-810ced55d5320a3088a05b13.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-8423565f1a40e329afc8c6cf.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-900bef783b8cee36506ec282.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-a1a37aff6416fdad74040ddf.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-ad48d5e8eda40f175b4df090.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-aec5a2d963015528c9099462.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-af9d34e0f1722fab9e28c269.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-b818e4015e2f1fe86280b5ab.js +41 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bcb2541adc70b7aba61768c5.js +44 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bfe89d2c78ed44f95ed7dd73.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c06f04806a1e688e1187110c.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c3f3adf904f585afc544b96a.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-d45acb873e1d8e32d5e60f2e.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-db06f132533706f4a0163b8c.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f660f40d78b135fc8560a862.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f9dee4ec18a96e09bee06bae.js +39 -0
- package/README.md +85 -3
- package/admin-ui/client.js +8 -8
- package/dev-status.svg +139 -0
- package/docs/api-reference.md +301 -43
- package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
- package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
- package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
- package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
- package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
- package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
- package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
- package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
- package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
- package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
- package/docs/bundling-system-deep-dive.md +9 -4
- package/docs/comprehensive-documentation.md +49 -18
- package/docs/configuration-reference.md +152 -27
- package/docs/core/README.md +19 -0
- package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
- package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
- package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
- package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
- package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
- package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
- package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
- package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
- package/docs/publishers-guide.md +59 -4
- package/docs/resources-guide.md +184 -35
- package/docs/simple-server-api-design.md +72 -17
- package/docs/system-architecture.md +18 -14
- package/examples/controls/15) window, observable SSE/server.js +6 -1
- package/examples/controls/19) window, auto observable ui/server.js +9 -0
- package/examples/controls/20) window, task manager app/README.md +133 -0
- package/examples/controls/20) window, task manager app/client.js +797 -0
- package/examples/controls/20) window, task manager app/server.js +178 -0
- package/examples/controls/6) window, color_palette/client.js +165 -68
- package/examples/controls/9) window, date picker/client.js +362 -76
- package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
- package/examples/jsgui3-html/06) theming/client.js +22 -1
- package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
- package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
- package/lab/experiments/capture-color-controls.js +196 -0
- package/lab/results/screenshots/color-controls/full_page.png +0 -0
- package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
- package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
- package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
- package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
- package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
- package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
- package/lab/screenshot-utils.js +248 -0
- package/module.js +11 -4
- package/package.json +12 -2
- package/publishers/Publishers.js +4 -3
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
- package/publishers/http-sse-publisher.js +341 -0
- package/resources/process-resource.js +950 -0
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +129 -33
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
- package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
- package/resources/remote-process-resource.js +355 -0
- package/resources/server-resource-pool.js +354 -41
- package/serve-factory.js +441 -259
- package/server.js +89 -13
- package/tests/README.md +66 -4
- package/tests/admin-ui-render.test.js +24 -0
- package/tests/assigners.test.js +56 -40
- package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
- package/tests/configuration-validation.test.js +21 -18
- package/tests/content-analysis.test.js +7 -6
- package/tests/control-optimizer-cache-behavior.test.js +52 -0
- package/tests/control-scan-manifest-regression.test.js +144 -0
- package/tests/end-to-end.test.js +15 -14
- package/tests/error-handling.test.js +222 -179
- package/tests/fixtures/bundling-default-button-client.js +37 -0
- package/tests/fixtures/bundling-default-window-client.js +34 -0
- package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
- package/tests/fixtures/resource-monitor-client.js +319 -0
- package/tests/helpers/puppeteer-e2e-harness.js +317 -0
- package/tests/http-sse-publisher.test.js +136 -0
- package/tests/performance.test.js +69 -65
- package/tests/process-resource.test.js +138 -0
- package/tests/publishers.test.js +7 -7
- package/tests/remote-process-resource.test.js +160 -0
- package/tests/sass-controls.e2e.test.js +7 -1
- package/tests/serve-resources.test.js +270 -0
- package/tests/serve.test.js +120 -50
- package/tests/server-resource-pool.test.js +106 -0
- package/tests/small-controls-bundle-size.test.js +252 -0
- package/tests/test-runner.js +13 -1
- package/tests/window-examples.puppeteer.test.js +204 -1
- package/tests/window-resource-integration.puppeteer.test.js +585 -0
- package/tests/temp_invalid.js +0 -7
- package/tests/temp_invalid_utf8.js +0 -1
- package/tests/temp_malformed.js +0 -10
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const { describe, it, before, after } = require('mocha');
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const Advanced_JS_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild');
|
|
7
|
+
|
|
8
|
+
const window_markers = [
|
|
9
|
+
'Minimize window',
|
|
10
|
+
'window_manager',
|
|
11
|
+
'__type_name = "window"',
|
|
12
|
+
"__type_name = 'window'",
|
|
13
|
+
"__type_name='window'",
|
|
14
|
+
'add_class("window")',
|
|
15
|
+
"add_class('window')"
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const to_module_literal = (file_path) => file_path.replace(/\\/g, '\\\\');
|
|
19
|
+
|
|
20
|
+
const find_window_markers = (js_text, css_text) => {
|
|
21
|
+
const search_text = `${js_text || ''}\n${css_text || ''}`;
|
|
22
|
+
return window_markers.filter(marker => search_text.includes(marker));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const bundle_fixture = async (bundler, fixture_path) => {
|
|
26
|
+
const bundle_result = await bundler.bundle(fixture_path);
|
|
27
|
+
const bundle = bundle_result[0];
|
|
28
|
+
|
|
29
|
+
const js_item = bundle._arr.find(item => item.type === 'JavaScript');
|
|
30
|
+
const css_item = bundle._arr.find(item => item.type === 'CSS');
|
|
31
|
+
|
|
32
|
+
const js_text = (js_item && js_item.text) || '';
|
|
33
|
+
const css_text = (css_item && css_item.text) || '';
|
|
34
|
+
const markers_found = find_window_markers(js_text, css_text);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
js_bytes: Buffer.byteLength(js_text, 'utf8'),
|
|
38
|
+
css_bytes: Buffer.byteLength(css_text, 'utf8'),
|
|
39
|
+
markers_found,
|
|
40
|
+
bundle_analysis: bundle.bundle_analysis || null
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('Small Controls Bundle Size and Window Exclusion Tests', function () {
|
|
45
|
+
this.timeout(180000);
|
|
46
|
+
|
|
47
|
+
const fixture_paths = [];
|
|
48
|
+
const fixture_metrics = {};
|
|
49
|
+
|
|
50
|
+
const fixture_dir = __dirname;
|
|
51
|
+
const jsgui_html_root = path.dirname(require.resolve('jsgui3-html'));
|
|
52
|
+
|
|
53
|
+
const active_html_document_path = to_module_literal(path.join(jsgui_html_root, 'controls/organised/1-standard/5-ui/Active_HTML_Document.js'));
|
|
54
|
+
const button_control_path = to_module_literal(path.join(jsgui_html_root, 'controls/organised/0-core/0-basic/0-native-compositional/button.js'));
|
|
55
|
+
const date_picker_control_path = to_module_literal(path.join(jsgui_html_root, 'controls/organised/0-core/0-basic/0-native-compositional/date-picker.js'));
|
|
56
|
+
const color_picker_control_path = to_module_literal(path.join(jsgui_html_root, 'controls/organised/0-core/0-basic/1-compositional/color-picker.js'));
|
|
57
|
+
|
|
58
|
+
const write_fixture = async (file_name, source_text) => {
|
|
59
|
+
const fixture_path = path.join(fixture_dir, file_name);
|
|
60
|
+
await fs.writeFile(fixture_path, source_text, 'utf8');
|
|
61
|
+
fixture_paths.push(fixture_path);
|
|
62
|
+
return fixture_path;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
before(async function () {
|
|
66
|
+
const broad_import_fixture = await write_fixture('temp_small_controls_broad_client.js', `
|
|
67
|
+
const jsgui = require('jsgui3-html');
|
|
68
|
+
const controls = jsgui.controls;
|
|
69
|
+
|
|
70
|
+
class Tiny_Broad_Import_App extends controls.Active_HTML_Document {
|
|
71
|
+
constructor(spec = {}) {
|
|
72
|
+
super(spec);
|
|
73
|
+
if (!spec.el) {
|
|
74
|
+
const button = new controls.Button({ context: this.context });
|
|
75
|
+
button.add('ok');
|
|
76
|
+
this.body.add(button);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { Tiny_Broad_Import_App };
|
|
82
|
+
`);
|
|
83
|
+
|
|
84
|
+
const button_only_fixture = await write_fixture('temp_small_controls_button_only_client.js', `
|
|
85
|
+
const Active_HTML_Document = require('${active_html_document_path}');
|
|
86
|
+
const Button = require('${button_control_path}');
|
|
87
|
+
|
|
88
|
+
class Tiny_Button_Only_App extends Active_HTML_Document {
|
|
89
|
+
constructor(spec = {}) {
|
|
90
|
+
super(spec);
|
|
91
|
+
if (!spec.el) {
|
|
92
|
+
const button = new Button({ context: this.context });
|
|
93
|
+
button.add('ok');
|
|
94
|
+
this.body.add(button);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = { Tiny_Button_Only_App };
|
|
100
|
+
`);
|
|
101
|
+
|
|
102
|
+
const date_picker_only_fixture = await write_fixture('temp_small_controls_date_picker_only_client.js', `
|
|
103
|
+
const Active_HTML_Document = require('${active_html_document_path}');
|
|
104
|
+
const Date_Picker = require('${date_picker_control_path}');
|
|
105
|
+
|
|
106
|
+
class Tiny_Date_Picker_Only_App extends Active_HTML_Document {
|
|
107
|
+
constructor(spec = {}) {
|
|
108
|
+
super(spec);
|
|
109
|
+
if (!spec.el) {
|
|
110
|
+
const date_picker = new Date_Picker({ context: this.context });
|
|
111
|
+
this.body.add(date_picker);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = { Tiny_Date_Picker_Only_App };
|
|
117
|
+
`);
|
|
118
|
+
|
|
119
|
+
const color_picker_only_fixture = await write_fixture('temp_small_controls_color_picker_only_client.js', `
|
|
120
|
+
const Active_HTML_Document = require('${active_html_document_path}');
|
|
121
|
+
const Color_Picker = require('${color_picker_control_path}');
|
|
122
|
+
|
|
123
|
+
class Tiny_Color_Picker_Only_App extends Active_HTML_Document {
|
|
124
|
+
constructor(spec = {}) {
|
|
125
|
+
super(spec);
|
|
126
|
+
if (!spec.el) {
|
|
127
|
+
const color_picker = new Color_Picker({ context: this.context });
|
|
128
|
+
this.body.add(color_picker);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = { Tiny_Color_Picker_Only_App };
|
|
134
|
+
`);
|
|
135
|
+
|
|
136
|
+
const default_bundler = new Advanced_JS_Bundler_Using_ESBuild({
|
|
137
|
+
debug: false,
|
|
138
|
+
bundler: {
|
|
139
|
+
minify: {
|
|
140
|
+
enabled: true,
|
|
141
|
+
level: 'normal'
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const disabled_elimination_bundler = new Advanced_JS_Bundler_Using_ESBuild({
|
|
147
|
+
debug: false,
|
|
148
|
+
bundler: {
|
|
149
|
+
minify: {
|
|
150
|
+
enabled: true,
|
|
151
|
+
level: 'normal'
|
|
152
|
+
},
|
|
153
|
+
elimination: {
|
|
154
|
+
enabled: false,
|
|
155
|
+
jsgui3_html_controls: {
|
|
156
|
+
enabled: false
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const cache_disabled_bundler = new Advanced_JS_Bundler_Using_ESBuild({
|
|
163
|
+
debug: false,
|
|
164
|
+
bundler: {
|
|
165
|
+
minify: {
|
|
166
|
+
enabled: true,
|
|
167
|
+
level: 'normal'
|
|
168
|
+
},
|
|
169
|
+
elimination: {
|
|
170
|
+
enabled: true,
|
|
171
|
+
jsgui3_html_controls: {
|
|
172
|
+
cache: {
|
|
173
|
+
enabled: false
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
fixture_metrics.broad_import_default = await bundle_fixture(default_bundler, broad_import_fixture);
|
|
181
|
+
fixture_metrics.broad_import_elimination_disabled = await bundle_fixture(disabled_elimination_bundler, broad_import_fixture);
|
|
182
|
+
fixture_metrics.broad_import_cache_disabled = await bundle_fixture(cache_disabled_bundler, broad_import_fixture);
|
|
183
|
+
fixture_metrics.button_only = await bundle_fixture(default_bundler, button_only_fixture);
|
|
184
|
+
fixture_metrics.date_picker_only = await bundle_fixture(default_bundler, date_picker_only_fixture);
|
|
185
|
+
fixture_metrics.color_picker_only = await bundle_fixture(default_bundler, color_picker_only_fixture);
|
|
186
|
+
|
|
187
|
+
console.log('[small-controls-bundle-size] metrics', JSON.stringify(fixture_metrics, null, 2));
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
after(async function () {
|
|
191
|
+
await Promise.all(fixture_paths.map(async fixture_path => {
|
|
192
|
+
try {
|
|
193
|
+
await fs.unlink(fixture_path);
|
|
194
|
+
} catch (err) {
|
|
195
|
+
// Ignore missing temp fixture files.
|
|
196
|
+
}
|
|
197
|
+
}));
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should exclude Window markers in broad jsgui3-html imports by default', function () {
|
|
201
|
+
assert.strictEqual(fixture_metrics.broad_import_default.markers_found.length, 0,
|
|
202
|
+
`Unexpected Window markers in broad default bundle: ${fixture_metrics.broad_import_default.markers_found.join(', ')}`);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should include Window markers when control elimination is explicitly disabled', function () {
|
|
206
|
+
assert(fixture_metrics.broad_import_elimination_disabled.markers_found.length > 0,
|
|
207
|
+
'Expected broad import bundle with elimination disabled to contain Window markers');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should keep elimination behavior when cache is disabled', function () {
|
|
211
|
+
assert.strictEqual(fixture_metrics.broad_import_cache_disabled.markers_found.length, 0,
|
|
212
|
+
`Unexpected Window markers in cache-disabled elimination bundle: ${fixture_metrics.broad_import_cache_disabled.markers_found.join(', ')}`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should exclude Window markers when only Button control is directly imported', function () {
|
|
216
|
+
assert.strictEqual(fixture_metrics.button_only.markers_found.length, 0,
|
|
217
|
+
`Unexpected Window markers in button-only bundle: ${fixture_metrics.button_only.markers_found.join(', ')}`);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should exclude Window markers when only Date_Picker control is directly imported', function () {
|
|
221
|
+
assert.strictEqual(fixture_metrics.date_picker_only.markers_found.length, 0,
|
|
222
|
+
`Unexpected Window markers in date-picker-only bundle: ${fixture_metrics.date_picker_only.markers_found.join(', ')}`);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should exclude Window markers when only Color_Picker control is directly imported', function () {
|
|
226
|
+
assert.strictEqual(fixture_metrics.color_picker_only.markers_found.length, 0,
|
|
227
|
+
`Unexpected Window markers in color-picker-only bundle: ${fixture_metrics.color_picker_only.markers_found.join(', ')}`);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should produce smaller JS bundles for direct small-control imports than broad import', function () {
|
|
231
|
+
assert(fixture_metrics.button_only.js_bytes < fixture_metrics.broad_import_elimination_disabled.js_bytes,
|
|
232
|
+
'Button-only bundle should be smaller than broad import bundle with elimination disabled');
|
|
233
|
+
assert(fixture_metrics.date_picker_only.js_bytes < fixture_metrics.broad_import_elimination_disabled.js_bytes,
|
|
234
|
+
'Date-picker-only bundle should be smaller than broad import bundle with elimination disabled');
|
|
235
|
+
assert(fixture_metrics.color_picker_only.js_bytes < fixture_metrics.broad_import_elimination_disabled.js_bytes,
|
|
236
|
+
'Color-picker-only bundle should be smaller than broad import bundle with elimination disabled');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should reduce broad-import JS size when default elimination scan is active', function () {
|
|
240
|
+
assert(fixture_metrics.broad_import_default.js_bytes < fixture_metrics.broad_import_elimination_disabled.js_bytes,
|
|
241
|
+
'Default broad-import bundle should be smaller than broad-import bundle with elimination disabled');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should expose control scan analysis metadata for default broad import bundle', function () {
|
|
245
|
+
const analysis = fixture_metrics.broad_import_default.bundle_analysis &&
|
|
246
|
+
fixture_metrics.broad_import_default.bundle_analysis.jsgui3_html_control_scan;
|
|
247
|
+
assert(analysis, 'Expected bundle_analysis.jsgui3_html_control_scan metadata');
|
|
248
|
+
assert(Array.isArray(analysis.selected_controls), 'Expected selected_controls array in control scan metadata');
|
|
249
|
+
assert(analysis.selected_controls.includes('Button'), 'Expected Button in selected_controls');
|
|
250
|
+
assert(!analysis.selected_controls.includes('Window'), 'Expected Window not to be selected');
|
|
251
|
+
});
|
|
252
|
+
});
|
package/tests/test-runner.js
CHANGED
|
@@ -27,14 +27,26 @@ class TestRunner {
|
|
|
27
27
|
'assigners.test.js',
|
|
28
28
|
'publishers.test.js',
|
|
29
29
|
'configuration-validation.test.js',
|
|
30
|
+
'admin-ui-render.test.js',
|
|
31
|
+
'serve.test.js',
|
|
32
|
+
'serve-resources.test.js',
|
|
33
|
+
'process-resource.test.js',
|
|
34
|
+
'remote-process-resource.test.js',
|
|
35
|
+
'server-resource-pool.test.js',
|
|
36
|
+
'http-sse-publisher.test.js',
|
|
30
37
|
'end-to-end.test.js',
|
|
31
38
|
'content-analysis.test.js',
|
|
39
|
+
'small-controls-bundle-size.test.js',
|
|
40
|
+
'control-optimizer-cache-behavior.test.js',
|
|
41
|
+
'control-scan-manifest-regression.test.js',
|
|
32
42
|
'performance.test.js',
|
|
33
43
|
'error-handling.test.js',
|
|
34
44
|
'examples-controls.e2e.test.js',
|
|
35
45
|
'sass-controls.e2e.test.js',
|
|
36
46
|
'jsgui3-html-examples.puppeteer.test.js',
|
|
37
|
-
'
|
|
47
|
+
'bundling-default-control-elimination.puppeteer.test.js',
|
|
48
|
+
'window-examples.puppeteer.test.js',
|
|
49
|
+
'window-resource-integration.puppeteer.test.js'
|
|
38
50
|
];
|
|
39
51
|
}
|
|
40
52
|
|
|
@@ -166,6 +166,35 @@ const get_checkbox_state = async (page) => {
|
|
|
166
166
|
return page.$eval('.checkbox input[type="checkbox"]', (el) => el.checked);
|
|
167
167
|
};
|
|
168
168
|
|
|
169
|
+
const set_input_value_with_events = async (page, selector, next_value, event_names = ['input']) => {
|
|
170
|
+
await page.$eval(selector, (el, value, events) => {
|
|
171
|
+
el.value = value;
|
|
172
|
+
for (const event_name of events) {
|
|
173
|
+
el.dispatchEvent(new Event(event_name, { bubbles: true }));
|
|
174
|
+
}
|
|
175
|
+
}, String(next_value), event_names);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const click_datetime_tab = async (page, root_selector, tab_label_fragment) => {
|
|
179
|
+
const click_result = await page.evaluate((picker_root_selector, text_fragment) => {
|
|
180
|
+
const root_el = document.querySelector(picker_root_selector);
|
|
181
|
+
if (!root_el) return false;
|
|
182
|
+
const tab_el = Array.from(root_el.querySelectorAll('.dtp-tab')).find((tab) => {
|
|
183
|
+
const tab_text = String(tab.textContent || '').toLowerCase();
|
|
184
|
+
return tab_text.includes(String(text_fragment || '').toLowerCase());
|
|
185
|
+
});
|
|
186
|
+
if (!tab_el) return false;
|
|
187
|
+
tab_el.click();
|
|
188
|
+
return true;
|
|
189
|
+
}, root_selector, tab_label_fragment);
|
|
190
|
+
|
|
191
|
+
return click_result === true;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const get_text_content = async (page, selector) => {
|
|
195
|
+
return page.$eval(selector, (el) => (el.textContent || '').trim());
|
|
196
|
+
};
|
|
197
|
+
|
|
169
198
|
describe('Window Examples Puppeteer Tests', function () {
|
|
170
199
|
this.timeout(180000);
|
|
171
200
|
|
|
@@ -432,7 +461,68 @@ describe('Window Examples Puppeteer Tests', function () {
|
|
|
432
461
|
}
|
|
433
462
|
});
|
|
434
463
|
|
|
435
|
-
it('
|
|
464
|
+
it('color picker controls stay interactive in "6) window, color_palette"', async function () {
|
|
465
|
+
const { server, port } = await start_example_server({
|
|
466
|
+
dir_name: '6) window, color_palette',
|
|
467
|
+
ctrl_name: 'Demo_UI'
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
let page;
|
|
471
|
+
try {
|
|
472
|
+
page = await open_example_page(port);
|
|
473
|
+
await page.waitForSelector('.demo-color-picker-default .cp-hex-input');
|
|
474
|
+
await page.waitForSelector('.demo-color-picker-compact .cp-rgb-r');
|
|
475
|
+
|
|
476
|
+
const wheel_drawn = await page.$eval('.demo-color-picker-default .cp-wheel-canvas', (canvas) => {
|
|
477
|
+
const ctx = canvas.getContext('2d');
|
|
478
|
+
if (!ctx) return false;
|
|
479
|
+
const pixel = ctx.getImageData(90, 2, 1, 1).data;
|
|
480
|
+
return pixel[3] > 0;
|
|
481
|
+
});
|
|
482
|
+
assert.strictEqual(wheel_drawn, true, 'Expected Color_Picker hue wheel canvas to be drawn');
|
|
483
|
+
|
|
484
|
+
const initial_hex = await page.$eval('.demo-color-picker-default .cp-hex-input', (el) => el.value);
|
|
485
|
+
await set_input_value_with_events(page, '.demo-color-picker-default .cp-slider-h', 0, ['input']);
|
|
486
|
+
await page.waitForFunction(
|
|
487
|
+
(selector, before_hex) => {
|
|
488
|
+
const el = document.querySelector(selector);
|
|
489
|
+
return !!el && String(el.value || '').toLowerCase() !== String(before_hex || '').toLowerCase();
|
|
490
|
+
},
|
|
491
|
+
{},
|
|
492
|
+
'.demo-color-picker-default .cp-hex-input',
|
|
493
|
+
initial_hex
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
await set_input_value_with_events(page, '.demo-color-picker-compact .cp-rgb-r', 0, ['input']);
|
|
497
|
+
await set_input_value_with_events(page, '.demo-color-picker-compact .cp-rgb-g', 255, ['input']);
|
|
498
|
+
await set_input_value_with_events(page, '.demo-color-picker-compact .cp-rgb-b', 0, ['input']);
|
|
499
|
+
|
|
500
|
+
await page.waitForFunction(() => {
|
|
501
|
+
const readout_el = document.querySelector('.demo-color-picker-readout');
|
|
502
|
+
if (!readout_el) return false;
|
|
503
|
+
const text = String(readout_el.textContent || '');
|
|
504
|
+
return /rgba\(\s*0,\s*255,\s*0/i.test(text);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
await capture_screenshot(page, '6) window, color_palette', 'after_picker_interaction');
|
|
508
|
+
|
|
509
|
+
await drag_window_by(page, '.window .title.bar', 90, 60);
|
|
510
|
+
await page.waitForTimeout(120);
|
|
511
|
+
|
|
512
|
+
await set_input_value_with_events(page, '.demo-color-picker-default .cp-slider-l', 25, ['input']);
|
|
513
|
+
await page.waitForFunction(() => {
|
|
514
|
+
const hex_el = document.querySelector('.demo-color-picker-default .cp-hex-input');
|
|
515
|
+
return !!hex_el && /^#[0-9a-f]{6}$/i.test(String(hex_el.value || ''));
|
|
516
|
+
});
|
|
517
|
+
} finally {
|
|
518
|
+
if (page) {
|
|
519
|
+
await page.close();
|
|
520
|
+
}
|
|
521
|
+
await stop_example_server(server);
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
it('date and datetime picker interactions work in "9) window, date picker"', async function () {
|
|
436
526
|
const { server, port } = await start_example_server({
|
|
437
527
|
dir_name: '9) window, date picker',
|
|
438
528
|
ctrl_name: 'Demo_UI'
|
|
@@ -442,9 +532,122 @@ describe('Window Examples Puppeteer Tests', function () {
|
|
|
442
532
|
try {
|
|
443
533
|
page = await open_example_page(port);
|
|
444
534
|
await page.waitForSelector('input.date-picker[type="date"]');
|
|
535
|
+
await page.waitForSelector('.demo-datetime-picker.datetime-picker');
|
|
445
536
|
|
|
446
537
|
const input_type = await page.$eval('input.date-picker', (el) => el.getAttribute('type'));
|
|
447
538
|
assert.strictEqual(input_type, 'date', 'Expected native date input');
|
|
539
|
+
|
|
540
|
+
const date_attrs = await page.$eval('input.date-picker', (el) => ({
|
|
541
|
+
min: el.getAttribute('min'),
|
|
542
|
+
max: el.getAttribute('max'),
|
|
543
|
+
lang: el.getAttribute('lang')
|
|
544
|
+
}));
|
|
545
|
+
assert.strictEqual(date_attrs.min, '2026-01-01');
|
|
546
|
+
assert.strictEqual(date_attrs.max, '2026-12-31');
|
|
547
|
+
assert.strictEqual(date_attrs.lang, 'en-GB');
|
|
548
|
+
|
|
549
|
+
await set_input_value_with_events(page, 'input.date-picker', '2026-07-04', ['input', 'change']);
|
|
550
|
+
await page.waitForFunction(() => {
|
|
551
|
+
const out_el = document.querySelector('.demo-date-output');
|
|
552
|
+
return !!out_el && String(out_el.textContent || '').includes('2026-07-04');
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const initial_datetime_text = await get_text_content(page, '.demo-datetime-output');
|
|
556
|
+
const initial_time_display = await get_text_content(page, '.demo-datetime-picker .tp-display-time');
|
|
557
|
+
const clicked_time_tab = await click_datetime_tab(page, '.demo-datetime-picker', 'time');
|
|
558
|
+
assert.strictEqual(clicked_time_tab, true, 'Expected to locate and click DateTime "Time" tab');
|
|
559
|
+
|
|
560
|
+
await page.waitForFunction(() => {
|
|
561
|
+
const tp = document.querySelector('.demo-datetime-picker .time-picker');
|
|
562
|
+
return !!tp && window.getComputedStyle(tp).display !== 'none';
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
const did_click_spinners = await page.evaluate(() => {
|
|
566
|
+
const hour_spinner = document.querySelector('.demo-datetime-picker .tp-spinner-up.tp-h-up');
|
|
567
|
+
const minute_spinner = document.querySelector('.demo-datetime-picker .tp-spinner-up.tp-m-up');
|
|
568
|
+
if (!hour_spinner || !minute_spinner) return false;
|
|
569
|
+
hour_spinner.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
570
|
+
minute_spinner.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
571
|
+
return true;
|
|
572
|
+
});
|
|
573
|
+
assert.strictEqual(did_click_spinners, true, 'Expected DateTime spinner controls to be present');
|
|
574
|
+
await page.waitForFunction(
|
|
575
|
+
(before_output_text, before_time_text) => {
|
|
576
|
+
const out_el = document.querySelector('.demo-datetime-output');
|
|
577
|
+
const time_el = document.querySelector('.demo-datetime-picker .tp-display-time');
|
|
578
|
+
if (!out_el && !time_el) return false;
|
|
579
|
+
const after_text = String(out_el.textContent || '');
|
|
580
|
+
const after_time_text = String((time_el && time_el.textContent) || '').trim();
|
|
581
|
+
return (
|
|
582
|
+
after_text !== before_output_text
|
|
583
|
+
|| after_time_text !== before_time_text
|
|
584
|
+
) && /DateTime value:\s*\d{4}-\d{2}-\d{2}T.+/.test(after_text);
|
|
585
|
+
},
|
|
586
|
+
{},
|
|
587
|
+
initial_datetime_text,
|
|
588
|
+
initial_time_display
|
|
589
|
+
);
|
|
590
|
+
|
|
591
|
+
const clicked_date_tab = await click_datetime_tab(page, '.demo-datetime-picker', 'date');
|
|
592
|
+
assert.strictEqual(clicked_date_tab, true, 'Expected to locate and click DateTime "Date" tab');
|
|
593
|
+
await page.waitForFunction(() => {
|
|
594
|
+
const mv = document.querySelector('.demo-datetime-picker .month-view');
|
|
595
|
+
return !!mv && window.getComputedStyle(mv).display !== 'none';
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
await drag_window_by(page, '.window .title.bar', 80, 50);
|
|
599
|
+
await resize_window_by(page, '.window .bottom-right.resize-handle', 100, 80);
|
|
600
|
+
await page.waitForTimeout(120);
|
|
601
|
+
|
|
602
|
+
await set_input_value_with_events(page, 'input.date-picker', '2026-09-09', ['input', 'change']);
|
|
603
|
+
await page.waitForFunction(() => {
|
|
604
|
+
const out_el = document.querySelector('.demo-date-output');
|
|
605
|
+
return !!out_el && String(out_el.textContent || '').includes('2026-09-09');
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
await capture_screenshot(page, '9) window, date picker', 'after_datetime_interaction');
|
|
609
|
+
} finally {
|
|
610
|
+
if (page) {
|
|
611
|
+
await page.close();
|
|
612
|
+
}
|
|
613
|
+
await stop_example_server(server);
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('shared Date_Picker controls mirror values in "9b) window, shared data.model mirrored date pickers"', async function () {
|
|
618
|
+
const { server, port } = await start_example_server({
|
|
619
|
+
dir_name: '9b) window, shared data.model mirrored date pickers',
|
|
620
|
+
ctrl_name: 'Demo_UI'
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
let page;
|
|
624
|
+
try {
|
|
625
|
+
page = await open_example_page(port);
|
|
626
|
+
await page.waitForSelector('input.date-picker');
|
|
627
|
+
|
|
628
|
+
await page.waitForFunction(() => document.querySelectorAll('input.date-picker').length >= 2);
|
|
629
|
+
const set_date_value_at_index = async (index, next_value) => {
|
|
630
|
+
await page.evaluate((picker_index, value) => {
|
|
631
|
+
const inputs = Array.from(document.querySelectorAll('input.date-picker'));
|
|
632
|
+
const target = inputs[picker_index];
|
|
633
|
+
if (!target) return;
|
|
634
|
+
target.value = value;
|
|
635
|
+
target.dispatchEvent(new Event('input', { bubbles: true }));
|
|
636
|
+
target.dispatchEvent(new Event('change', { bubbles: true }));
|
|
637
|
+
}, index, next_value);
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
await set_date_value_at_index(0, '2026-05-10');
|
|
641
|
+
await page.waitForFunction((expected_value) => {
|
|
642
|
+
const inputs = Array.from(document.querySelectorAll('input.date-picker'));
|
|
643
|
+
return inputs.length >= 2 && inputs[1].value === expected_value;
|
|
644
|
+
}, {}, '2026-05-10');
|
|
645
|
+
|
|
646
|
+
await set_date_value_at_index(1, '2026-11-21');
|
|
647
|
+
await page.waitForFunction((expected_value) => {
|
|
648
|
+
const inputs = Array.from(document.querySelectorAll('input.date-picker'));
|
|
649
|
+
return inputs.length >= 2 && inputs[0].value === expected_value;
|
|
650
|
+
}, {}, '2026-11-21');
|
|
448
651
|
} finally {
|
|
449
652
|
if (page) {
|
|
450
653
|
await page.close();
|