jsgui3-server 0.0.145 → 0.0.146

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/docs/jsgui3-sass-patterns-book/01-vision-and-goals.md +31 -0
  2. package/docs/jsgui3-sass-patterns-book/02-stack-map.md +40 -0
  3. package/docs/jsgui3-sass-patterns-book/03-control-local-sass.md +60 -0
  4. package/docs/jsgui3-sass-patterns-book/04-extension-and-variants.md +76 -0
  5. package/docs/jsgui3-sass-patterns-book/05-theming-and-tokens.md +54 -0
  6. package/docs/jsgui3-sass-patterns-book/06-workspace-overrides.md +45 -0
  7. package/docs/jsgui3-sass-patterns-book/07-resource-and-bundling.md +46 -0
  8. package/docs/jsgui3-sass-patterns-book/08-examples.md +62 -0
  9. package/docs/jsgui3-sass-patterns-book/09-testing-and-adoption.md +27 -0
  10. package/docs/jsgui3-sass-patterns-book/README.md +23 -0
  11. package/docs/troubleshooting.md +44 -4
  12. package/examples/controls/14) window, canvas/client.js +1 -1
  13. package/examples/controls/14b) window, canvas (improved renderer)/client.js +1 -1
  14. package/examples/controls/14d) window, canvas globe/client.js +1 -1
  15. package/examples/controls/14e) window, canvas multithreaded/client.js +1 -1
  16. package/examples/controls/14f) window, canvas polyglobe/client.js +1 -1
  17. package/examples/controls/16) window, form container/client.js +254 -0
  18. package/examples/controls/16) window, form container/server.js +20 -0
  19. package/examples/controls/17) window, mvvm binding/client.js +530 -0
  20. package/examples/controls/17) window, mvvm binding/server.js +20 -0
  21. package/package.json +3 -3
  22. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +87 -100
  23. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +89 -60
  24. package/tests/README.md +45 -9
  25. package/tests/bundlers.test.js +53 -47
  26. package/tests/examples-controls.e2e.test.js +3 -1
  27. package/tests/sass-controls.e2e.test.js +123 -9
@@ -44,97 +44,84 @@ class Core_JS_Non_Minifying_Bundler_Using_ESBuild extends Bundler_Using_ESBuild
44
44
 
45
45
 
46
46
 
47
- bundle_js_string(js_string) {
48
- const res_obs = obs(async(next, complete, error) => {
49
- const o_build = {
50
- stdin: {
51
- contents: js_string,
52
- resolveDir: process.cwd()
53
- },
54
- bundle: true,
55
- treeShaking: true,
56
- write: false,
57
- // Remove outdir since we're keeping in memory
58
- }
59
-
60
- // Configure sourcemaps based on configuration
61
- const sourcemapsEnabled = this.sourcemap_config.enabled !== false; // Default: true in debug, false in production
62
- if (sourcemapsEnabled && (this.debug || this.sourcemap_config.includeInProduction)) {
63
- o_build.sourcemap = this.sourcemap_config.format || 'inline';
64
- }
65
-
66
- let result = await esbuild.build(o_build);
67
-
68
- if (result.outputFiles.length === 1) {
69
- const output_file = result.outputFiles[0];
70
- const res_bundle = new Bundle();
71
- const o_bundle_item = {
72
- type: 'JavaScript',
73
- extension: 'js',
74
- text: output_file.text
75
- }
76
- res_bundle.push(o_bundle_item);
77
- next(res_bundle);
78
- complete();
79
- } else {
80
- console.trace();
81
- throw 'NYI';
82
- }
83
- });
84
- return res_obs;
85
- }
47
+ bundle_js_string(js_string) {
48
+ const res_obs = obs(async(next, complete, error) => {
49
+ try {
50
+ const o_build = {
51
+ stdin: {
52
+ contents: js_string,
53
+ resolveDir: process.cwd()
54
+ },
55
+ bundle: true,
56
+ treeShaking: true,
57
+ write: false
58
+ };
59
+
60
+ // Configure sourcemaps based on configuration
61
+ const sourcemapsEnabled = this.sourcemap_config.enabled !== false;
62
+ if (sourcemapsEnabled && (this.debug || this.sourcemap_config.includeInProduction)) {
63
+ o_build.sourcemap = this.sourcemap_config.format || 'inline';
64
+ }
65
+
66
+ const result = await esbuild.build(o_build);
67
+
68
+ if (result.outputFiles.length === 1) {
69
+ const output_file = result.outputFiles[0];
70
+ const res_bundle = new Bundle();
71
+ const o_bundle_item = {
72
+ type: 'JavaScript',
73
+ extension: 'js',
74
+ text: output_file.text
75
+ };
76
+ res_bundle.push(o_bundle_item);
77
+ next(res_bundle);
78
+ complete(res_bundle);
79
+ } else {
80
+ console.trace();
81
+ throw 'NYI';
82
+ }
83
+ } catch (err) {
84
+ if (typeof error === 'function') error(err);
85
+ }
86
+ });
87
+ return res_obs;
88
+ }
86
89
 
87
90
  bundle(js_file_path) {
88
91
 
89
92
 
90
- const res_obs = obs(async(next, complete, error) => {
91
-
92
- // Validate input
93
- if (typeof js_file_path !== 'string' || js_file_path.trim() === '') {
94
- throw new Error('bundle() expects a valid file path string');
95
- }
96
-
97
- //console.log('Core_JS_Bundler_Using_ESBuild bundle js_file_path:', js_file_path);
98
-
99
- // Looks like we need better linking build options....
100
-
101
- const o_build = {
102
- entryPoints: [js_file_path],
103
-
104
-
105
- //format: 'iife',
106
- bundle: true,
107
-
108
- // Possibly no minification here....
109
- // Want to use non-minified or only partially minified version to separate the JS and the CSS.
110
-
111
- treeShaking: true,
112
-
113
- //sourcemap: 'external',
114
- write: false,
115
- // Remove outdir since we're keeping in memory
116
- }
117
-
118
- // Configure sourcemaps based on configuration
119
- const sourcemapsEnabled = this.sourcemap_config.enabled !== false; // Default: true in debug, false in production
120
- if (sourcemapsEnabled && (this.debug || this.sourcemap_config.includeInProduction)) {
121
- o_build.sourcemap = this.sourcemap_config.format || 'inline';
122
- }
123
-
124
-
125
-
126
- let result = await esbuild.build(o_build);
127
- //console.log('result.outputFiles:\n\n');
128
- //for (let out of result.outputFiles) {
129
- //console.log('out.path, out.contents, out.hash, out.text', out.path, out.contents, out.hash, out.text)
130
- //}
93
+ const res_obs = obs(async(next, complete, error) => {
94
+ try {
95
+ // Validate input
96
+ if (typeof js_file_path !== 'string' || js_file_path.trim() === '') {
97
+ throw new Error('bundle() expects a valid file path string');
98
+ }
99
+
100
+ const o_build = {
101
+ entryPoints: [js_file_path],
102
+ bundle: true,
103
+ treeShaking: true,
104
+ write: false
105
+ };
106
+
107
+ // Configure sourcemaps based on configuration
108
+ const sourcemapsEnabled = this.sourcemap_config.enabled !== false;
109
+ if (sourcemapsEnabled && (this.debug || this.sourcemap_config.includeInProduction)) {
110
+ o_build.sourcemap = this.sourcemap_config.format || 'inline';
111
+ }
112
+
113
+ const result = await esbuild.build(o_build);
114
+ //console.log('result.outputFiles:\n\n');
115
+ //for (let out of result.outputFiles) {
116
+ //console.log('out.path, out.contents, out.hash, out.text', out.path, out.contents, out.hash, out.text)
117
+ //}
131
118
 
132
119
  //console.log('result.outputFiles.length', result.outputFiles.length);
133
120
 
134
121
 
135
- if (result.outputFiles.length === 1) {
136
-
137
- const output_file = result.outputFiles[0];
122
+ if (result.outputFiles.length === 1) {
123
+
124
+ const output_file = result.outputFiles[0];
138
125
 
139
126
  //console.log('output_file.text.length', output_file.text.length);
140
127
  //console.log('output_file.text', output_file.text);
@@ -169,10 +156,10 @@ class Core_JS_Non_Minifying_Bundler_Using_ESBuild extends Bundler_Using_ESBuild
169
156
  text: output_file.text
170
157
  }
171
158
 
172
- res_bundle.push(o_bundle_item);
173
-
174
- next(res_bundle);
175
- complete();
159
+ res_bundle.push(o_bundle_item);
160
+
161
+ next(res_bundle);
162
+ complete(res_bundle);
176
163
 
177
164
 
178
165
 
@@ -206,18 +193,18 @@ class Core_JS_Non_Minifying_Bundler_Using_ESBuild extends Bundler_Using_ESBuild
206
193
  //console.trace();
207
194
  //throw 'NYI';
208
195
 
209
- } else {
210
-
211
-
212
- console.trace();
213
- throw 'NYI';
214
-
215
- }
216
-
217
-
218
- // The core bundler....
219
- // Maybe later even use a Static_Response_Preparer???
220
- // And have the relevant Publisher use it?
196
+ } else {
197
+ console.trace();
198
+ throw 'NYI';
199
+ }
200
+ } catch (err) {
201
+ if (typeof error === 'function') error(err);
202
+ }
203
+
204
+
205
+ // The core bundler....
206
+ // Maybe later even use a Static_Response_Preparer???
207
+ // And have the relevant Publisher use it?
221
208
 
222
209
 
223
210
 
@@ -235,4 +222,4 @@ class Core_JS_Non_Minifying_Bundler_Using_ESBuild extends Bundler_Using_ESBuild
235
222
 
236
223
  }
237
224
 
238
- module.exports = Core_JS_Non_Minifying_Bundler_Using_ESBuild;
225
+ module.exports = Core_JS_Non_Minifying_Bundler_Using_ESBuild;
@@ -55,12 +55,58 @@ class Core_JS_Single_File_Minifying_Bundler_Using_ESBuild extends Bundler_Using_
55
55
  return options;
56
56
  }
57
57
 
58
- get_default_minify_config() {
59
- return {
60
- enabled: true,
61
- level: 'normal'
62
- };
63
- }
58
+ get_default_minify_config() {
59
+ return {
60
+ enabled: true,
61
+ level: 'normal'
62
+ };
63
+ }
64
+
65
+ apply_minify_options(o_build) {
66
+ const enabled = this.minify_config.enabled !== false;
67
+ if (!enabled) {
68
+ o_build.minify = false;
69
+ return;
70
+ }
71
+
72
+ const level = this.minify_config.level || 'normal';
73
+ const level_overrides = {
74
+ conservative: {
75
+ minifyIdentifiers: false,
76
+ minifyWhitespace: false,
77
+ minifySyntax: false
78
+ },
79
+ aggressive: {
80
+ drop: ['console', 'debugger']
81
+ }
82
+ };
83
+
84
+ o_build.minify = true;
85
+ if (level_overrides[level]) {
86
+ Object.assign(o_build, level_overrides[level]);
87
+ }
88
+
89
+ const minify_options = this.get_minify_options();
90
+ if (minify_options && typeof minify_options === 'object') {
91
+ if (minify_options.mangle === false) {
92
+ o_build.minifyIdentifiers = false;
93
+ }
94
+ if (minify_options.compress === false) {
95
+ o_build.minifySyntax = false;
96
+ o_build.minifyWhitespace = false;
97
+ } else if (minify_options.compress && typeof minify_options.compress === 'object') {
98
+ if (minify_options.compress.sequences === false) {
99
+ o_build.minifySyntax = false;
100
+ }
101
+ const drop = [];
102
+ if (minify_options.compress.drop_console) drop.push('console');
103
+ if (minify_options.compress.drop_debugger) drop.push('debugger');
104
+ if (drop.length) {
105
+ o_build.drop = Array.from(new Set([...(o_build.drop || []), ...drop]));
106
+ }
107
+ }
108
+ }
109
+ }
64
110
 
65
111
 
66
112
 
@@ -75,40 +121,23 @@ class Core_JS_Single_File_Minifying_Bundler_Using_ESBuild extends Bundler_Using_
75
121
  if (typeof str_js !== 'string') {
76
122
  throw new Error('bundle() expects a string parameter');
77
123
  }
78
- const res_obs = obs(async(next, complete, error) => {
79
-
80
-
81
-
82
- //console.log('Core_JS_Bundler_Using_ESBuild bundle js_file_path:', js_file_path);
83
-
84
- // Looks like we need better linking build options....
85
-
86
- let result = await esbuild.build({
87
- stdin: {
88
- contents: str_js,
89
-
90
- // These are all optional:
91
- //resolveDir: './src',
92
- //sourcefile: 'imaginary-file.js',
93
- //loader: 'ts',
94
- },
95
- bundle: true,
96
-
97
- // Possibly no minification here....
98
- // Want to use non-minified or only partially minified version to separate the JS and the CSS.
99
-
100
- treeShaking: true,
101
- minify: true,
102
- //format: 'iife',
103
-
104
- //sourcemap: 'external',
105
- write: false,
106
- // Remove outdir since we're keeping in memory
107
- })
108
- //console.log('result.outputFiles:\n\n');
109
- for (let out of result.outputFiles) {
110
- //console.log('out.path, out.contents, out.hash, out.text', out.path, out.contents, out.hash, out.text)
111
- }
124
+ const res_obs = obs(async(next, complete, error) => {
125
+ try {
126
+ const o_build = {
127
+ stdin: {
128
+ contents: str_js
129
+ },
130
+ bundle: true,
131
+ treeShaking: true,
132
+ write: false
133
+ };
134
+
135
+ this.apply_minify_options(o_build);
136
+
137
+ const result = await esbuild.build(o_build);
138
+ for (let out of result.outputFiles) {
139
+ //console.log('out.path, out.contents, out.hash, out.text', out.path, out.contents, out.hash, out.text)
140
+ }
112
141
 
113
142
  //console.log('result.outputFiles.length', result.outputFiles.length);
114
143
 
@@ -116,9 +145,9 @@ class Core_JS_Single_File_Minifying_Bundler_Using_ESBuild extends Bundler_Using_
116
145
  //throw 'stop';
117
146
 
118
147
 
119
- if (result.outputFiles.length === 1) {
120
-
121
- const output_file = result.outputFiles[0];
148
+ if (result.outputFiles.length === 1) {
149
+
150
+ const output_file = result.outputFiles[0];
122
151
 
123
152
  //console.log('output_file', output_file);
124
153
 
@@ -155,10 +184,10 @@ class Core_JS_Single_File_Minifying_Bundler_Using_ESBuild extends Bundler_Using_
155
184
  text: output_file.text
156
185
  }
157
186
 
158
- res_bundle.push(o_bundle_item);
159
-
160
- next(res_bundle);
161
- complete();
187
+ res_bundle.push(o_bundle_item);
188
+
189
+ next(res_bundle);
190
+ complete(res_bundle);
162
191
 
163
192
 
164
193
 
@@ -192,18 +221,18 @@ class Core_JS_Single_File_Minifying_Bundler_Using_ESBuild extends Bundler_Using_
192
221
  //console.trace();
193
222
  //throw 'NYI';
194
223
 
195
- } else {
196
-
197
-
198
- console.trace();
199
- throw 'NYI';
200
-
201
- }
202
-
203
-
204
- // The core bundler....
205
- // Maybe later even use a Static_Response_Preparer???
206
- // And have the relevant Publisher use it?
224
+ } else {
225
+ console.trace();
226
+ throw 'NYI';
227
+ }
228
+ } catch (err) {
229
+ if (typeof error === 'function') error(err);
230
+ }
231
+
232
+
233
+ // The core bundler....
234
+ // Maybe later even use a Static_Response_Preparer???
235
+ // And have the relevant Publisher use it?
207
236
 
208
237
 
209
238
 
@@ -221,4 +250,4 @@ class Core_JS_Single_File_Minifying_Bundler_Using_ESBuild extends Bundler_Using_
221
250
 
222
251
  }
223
252
 
224
- module.exports = Core_JS_Single_File_Minifying_Bundler_Using_ESBuild;
253
+ module.exports = Core_JS_Single_File_Minifying_Bundler_Using_ESBuild;
package/tests/README.md CHANGED
@@ -63,15 +63,50 @@ npm run test:puppeteer:windows
63
63
  ```bash
64
64
  # Debug mode (enables sourcemaps)
65
65
  node tests/test-runner.js --debug
66
-
67
- # Verbose output
68
- node tests/test-runner.js --verbose
69
-
70
- # Specific test with debug
71
- node tests/test-runner.js --test=end-to-end.test.js --debug
72
- ```
73
-
74
- ## Test Coverage
66
+
67
+ # Verbose output
68
+ node tests/test-runner.js --verbose
69
+
70
+ # Specific test with debug
71
+ node tests/test-runner.js --test=end-to-end.test.js --debug
72
+ ```
73
+
74
+ ## Recommended Testing Workflow
75
+
76
+ 1. Run a focused suite first (fast feedback).
77
+ 2. Run the example regression suite next (HTML/CSS/JS smoke checks).
78
+ 3. Run Puppeteer interaction tests last (heavier, requires a browser).
79
+ 4. Run the full suite only when changes are broad or before release.
80
+
81
+ Suggested sequence:
82
+ ```bash
83
+ node tests/test-runner.js --test=bundlers.test.js
84
+ npm run test:examples:controls
85
+ npm run test:puppeteer:windows
86
+ npm test
87
+ ```
88
+
89
+ ## Patterns That Work
90
+
91
+ - Use per-test temporary client files and delete them in `finally`.
92
+ - Always close servers in `finally` to avoid port leaks.
93
+ - Prefer `get_free_port` over hard-coded ports.
94
+ - Keep style config explicit in tests that validate sourcemaps.
95
+ - Inject Sass overrides via `style.scss_sources` when testing themes.
96
+
97
+ ## Antipatterns To Avoid
98
+
99
+ - Copying `node_modules` between Windows and WSL or across OSes.
100
+ - Leaving servers running after a failed test (leaks ports and state).
101
+ - Tests that rely on global bundler state or implicit ordering.
102
+ - Hard-coded ports or shared temp file names across tests.
103
+
104
+ ## Common Failure Signatures
105
+
106
+ - `waiting for wp_publisher ready` + test timeout usually means the JS/CSS bundler failed before the server emitted `ready`. Check for esbuild or Sass errors earlier in the log.
107
+ - `You installed esbuild for another platform` indicates a native esbuild binary mismatch (see troubleshooting docs).
108
+
109
+ ## Test Coverage
75
110
 
76
111
  ### 1. Component Isolation Tests (`bundlers.test.js`, `assigners.test.js`, `publishers.test.js`)
77
112
 
@@ -157,6 +192,7 @@ Server-level integration tests for controls that define `.scss` or `.sass` style
157
192
  - Confirms indented Sass compiles and is removed from JS bundles
158
193
  - Checks inline CSS sourcemaps include original Sass/SCSS sources
159
194
  - Ensures mixed CSS + Sass output preserves order without emitting inaccurate sourcemaps
195
+ - Confirms server `scss_sources` overrides are applied during compilation
160
196
 
161
197
  Note: These tests are skipped if the `sass` dependency is not installed.
162
198
 
@@ -4,12 +4,17 @@ const fs = require('fs').promises;
4
4
  const path = require('path');
5
5
 
6
6
  // Import bundler classes
7
- const Core_JS_Non_Minifying_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild');
8
- const Core_JS_Single_File_Minifying_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild');
9
- const Advanced_JS_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild');
10
-
11
- describe('Bundler Component Isolation Tests', function() {
12
- this.timeout(30000); // Increase timeout for bundling operations
7
+ const Core_JS_Non_Minifying_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild');
8
+ const Core_JS_Single_File_Minifying_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild');
9
+ const Advanced_JS_Bundler_Using_ESBuild = require('../resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild');
10
+
11
+ const await_observable = observable => new Promise((resolve, reject) => {
12
+ observable.on('error', reject);
13
+ observable.on('complete', resolve);
14
+ });
15
+
16
+ describe('Bundler Component Isolation Tests', function() {
17
+ this.timeout(30000); // Increase timeout for bundling operations
13
18
 
14
19
  let testJsFile;
15
20
  let testJsContent;
@@ -108,29 +113,30 @@ this.timeout(30000); // Increase timeout for bundling operations
108
113
  assert(!bundleItem.text.includes('//# sourceMappingURL='), 'Production bundle should not include sourcemap');
109
114
  });
110
115
 
111
- it('should bundle JavaScript string directly', async function() {
112
- const bundler = new Core_JS_Non_Minifying_Bundler_Using_ESBuild();
113
-
114
- const jsString = `
115
- function directTest() {
116
- return 'direct result';
117
- }
118
- console.log('Direct bundle test');
119
- `;
120
-
121
- const result = await bundler.bundle_js_string(jsString);
122
-
123
- assert(Array.isArray(result), 'Result should be an array');
124
- const bundle = result[0];
125
- const bundleItem = bundle._arr[0];
126
-
127
- assert.strictEqual(bundleItem.type, 'JavaScript');
128
- assert(bundleItem.text.includes('directTest'), 'Should contain the direct test function');
129
- assert(bundleItem.text.includes('Direct bundle test'), 'Should contain the test log');
130
- // Verify the function is actually executable
131
- const testFunction = new Function(bundleItem.text + '; return directTest;')();
132
- assert.strictEqual(testFunction(), 'direct result', 'Bundled function should be executable');
133
- });
116
+ it('should bundle JavaScript string directly', async function() {
117
+ const bundler = new Core_JS_Non_Minifying_Bundler_Using_ESBuild();
118
+
119
+ const jsString = `
120
+ globalThis.directTest = function directTest() {
121
+ return 'direct result';
122
+ };
123
+ console.log(globalThis.directTest());
124
+ console.log('Direct bundle test');
125
+ `;
126
+
127
+ const result = await bundler.bundle_js_string(jsString);
128
+
129
+ assert(Array.isArray(result), 'Result should be an array');
130
+ const bundle = result[0];
131
+ const bundleItem = bundle._arr[0];
132
+
133
+ assert.strictEqual(bundleItem.type, 'JavaScript');
134
+ assert(bundleItem.text.includes('direct result'), 'Should contain the direct result string');
135
+ assert(bundleItem.text.includes('Direct bundle test'), 'Should contain the test log');
136
+ // Verify the function is actually executable
137
+ const testFunction = new Function(bundleItem.text + '; return globalThis.directTest;')();
138
+ assert.strictEqual(testFunction(), 'direct result', 'Bundled function should be executable');
139
+ });
134
140
  });
135
141
 
136
142
  describe('Core_JS_Single_File_Minifying_Bundler_Using_ESBuild', function() {
@@ -316,23 +322,23 @@ this.timeout(30000); // Increase timeout for bundling operations
316
322
  console.log('invalid syntax'
317
323
  `;
318
324
 
319
- try {
320
- await bundler.bundle_js_string(invalidJs);
321
- assert.fail('Should have thrown an error for invalid JavaScript');
322
- } catch (error) {
323
- assert(error, 'Should throw an error for invalid JavaScript');
324
- }
325
- });
326
-
327
- it('should handle non-existent files', async function() {
328
- const bundler = new Core_JS_Non_Minifying_Bundler_Using_ESBuild();
329
-
330
- try {
331
- await bundler.bundle('/non/existent/file.js');
332
- assert.fail('Should have thrown an error for non-existent file');
333
- } catch (error) {
334
- assert(error, 'Should throw an error for non-existent file');
335
- }
336
- });
325
+ try {
326
+ await await_observable(bundler.bundle_js_string(invalidJs));
327
+ assert.fail('Should have thrown an error for invalid JavaScript');
328
+ } catch (error) {
329
+ assert(error, 'Should throw an error for invalid JavaScript');
330
+ }
331
+ });
332
+
333
+ it('should handle non-existent files', async function() {
334
+ const bundler = new Core_JS_Non_Minifying_Bundler_Using_ESBuild();
335
+
336
+ try {
337
+ await await_observable(bundler.bundle('/non/existent/file.js'));
338
+ assert.fail('Should have thrown an error for non-existent file');
339
+ } catch (error) {
340
+ assert(error, 'Should throw an error for non-existent file');
341
+ }
342
+ });
337
343
  });
338
344
  });
@@ -33,7 +33,9 @@ const examples = [
33
33
  ctrl_name: 'Demo_UI',
34
34
  expected_window_count: 1,
35
35
  expected_canvas_id: 'globeCanvas'
36
- }
36
+ },
37
+ { dir_name: '16) window, form container', ctrl_name: 'Demo_UI', expected_window_count: 1 },
38
+ { dir_name: '17) window, mvvm binding', ctrl_name: 'Demo_UI', expected_window_count: 1 }
37
39
  ];
38
40
 
39
41
  function make_request(url, { headers = {} } = {}) {