electrobun 0.5.0-beta.0 → 0.6.0-beta.0

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 (78) hide show
  1. package/{templates/multitab-browser/bun.lock → bun.lock} +20 -13
  2. package/dist/api/bun/proc/native.ts +84 -16
  3. package/package.json +14 -16
  4. package/BETA_RELEASE.md +0 -67
  5. package/BUILD.md +0 -90
  6. package/LICENSE +0 -21
  7. package/README.md +0 -102
  8. package/debug.js +0 -5
  9. package/templates/hello-world/README.md +0 -57
  10. package/templates/hello-world/bun.lock +0 -225
  11. package/templates/hello-world/electrobun.config.ts +0 -28
  12. package/templates/hello-world/package.json +0 -16
  13. package/templates/hello-world/src/bun/index.ts +0 -15
  14. package/templates/hello-world/src/mainview/index.css +0 -124
  15. package/templates/hello-world/src/mainview/index.html +0 -46
  16. package/templates/hello-world/src/mainview/index.ts +0 -1
  17. package/templates/interactive-playground/README.md +0 -26
  18. package/templates/interactive-playground/assets/tray-icon.png +0 -0
  19. package/templates/interactive-playground/electrobun.config.ts +0 -36
  20. package/templates/interactive-playground/package-lock.json +0 -1112
  21. package/templates/interactive-playground/package.json +0 -15
  22. package/templates/interactive-playground/src/bun/demos/files.ts +0 -70
  23. package/templates/interactive-playground/src/bun/demos/menus.ts +0 -139
  24. package/templates/interactive-playground/src/bun/demos/rpc.ts +0 -83
  25. package/templates/interactive-playground/src/bun/demos/system.ts +0 -72
  26. package/templates/interactive-playground/src/bun/demos/updates.ts +0 -105
  27. package/templates/interactive-playground/src/bun/demos/windows.ts +0 -90
  28. package/templates/interactive-playground/src/bun/index.ts +0 -124
  29. package/templates/interactive-playground/src/bun/types/rpc.ts +0 -109
  30. package/templates/interactive-playground/src/mainview/components/EventLog.ts +0 -107
  31. package/templates/interactive-playground/src/mainview/components/Sidebar.ts +0 -65
  32. package/templates/interactive-playground/src/mainview/components/Toast.ts +0 -57
  33. package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +0 -211
  34. package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +0 -102
  35. package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +0 -229
  36. package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +0 -132
  37. package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +0 -465
  38. package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +0 -207
  39. package/templates/interactive-playground/src/mainview/index.css +0 -538
  40. package/templates/interactive-playground/src/mainview/index.html +0 -103
  41. package/templates/interactive-playground/src/mainview/index.ts +0 -238
  42. package/templates/multitab-browser/README.md +0 -34
  43. package/templates/multitab-browser/electrobun.config.ts +0 -32
  44. package/templates/multitab-browser/package-lock.json +0 -20
  45. package/templates/multitab-browser/package.json +0 -12
  46. package/templates/multitab-browser/src/bun/index.ts +0 -144
  47. package/templates/multitab-browser/src/bun/tabManager.ts +0 -200
  48. package/templates/multitab-browser/src/bun/types/rpc.ts +0 -78
  49. package/templates/multitab-browser/src/mainview/index.css +0 -487
  50. package/templates/multitab-browser/src/mainview/index.html +0 -94
  51. package/templates/multitab-browser/src/mainview/index.ts +0 -634
  52. package/templates/photo-booth/README.md +0 -108
  53. package/templates/photo-booth/bun.lock +0 -239
  54. package/templates/photo-booth/electrobun.config.ts +0 -32
  55. package/templates/photo-booth/package.json +0 -17
  56. package/templates/photo-booth/src/bun/index.ts +0 -92
  57. package/templates/photo-booth/src/mainview/index.css +0 -465
  58. package/templates/photo-booth/src/mainview/index.html +0 -124
  59. package/templates/photo-booth/src/mainview/index.ts +0 -499
  60. package/test-new-window-events.ts +0 -26
  61. package/test-new-window.html +0 -75
  62. package/test-npm-install.sh +0 -34
  63. package/tests/bun.lock +0 -14
  64. package/tests/electrobun.config.ts +0 -45
  65. package/tests/package-lock.json +0 -36
  66. package/tests/package.json +0 -13
  67. package/tests/src/bun/index.ts +0 -100
  68. package/tests/src/bun/test-runner.ts +0 -508
  69. package/tests/src/mainview/index.html +0 -110
  70. package/tests/src/mainview/index.ts +0 -458
  71. package/tests/src/mainview/styles/main.css +0 -451
  72. package/tests/src/testviews/tray-test.html +0 -57
  73. package/tests/src/testviews/webview-mask.html +0 -114
  74. package/tests/src/testviews/webview-navigation.html +0 -36
  75. package/tests/src/testviews/window-create.html +0 -17
  76. package/tests/src/testviews/window-events.html +0 -29
  77. package/tests/src/testviews/window-focus.html +0 -37
  78. package/tests/src/webviewtag/index.ts +0 -11
@@ -1,36 +0,0 @@
1
- {
2
- "name": "electrobun-tests",
3
- "version": "1.0.0",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "electrobun-tests",
9
- "version": "1.0.0",
10
- "dependencies": {
11
- "electrobun": "file:../"
12
- }
13
- },
14
- "..": {
15
- "version": "0.0.19-beta.118",
16
- "license": "MIT",
17
- "dependencies": {
18
- "@oneidentity/zstd-js": "^1.0.3",
19
- "archiver": "^7.0.1",
20
- "rpc-anywhere": "1.5.0",
21
- "tar": "^6.2.1"
22
- },
23
- "bin": {
24
- "electrobun": "bin/electrobun.cjs"
25
- },
26
- "devDependencies": {
27
- "@types/archiver": "^6.0.3",
28
- "@types/bun": "1.1.9"
29
- }
30
- },
31
- "node_modules/electrobun": {
32
- "resolved": "..",
33
- "link": true
34
- }
35
- }
36
- }
@@ -1,13 +0,0 @@
1
- {
2
- "name": "electrobun-tests",
3
- "version": "1.0.0",
4
- "description": "Interactive test harness for Electrobun",
5
- "type": "module",
6
- "scripts": {
7
- "start": "electrobun dev",
8
- "build:dev": "electrobun build"
9
- },
10
- "dependencies": {
11
- "electrobun": "file:../"
12
- }
13
- }
@@ -1,100 +0,0 @@
1
- import { BrowserWindow, BrowserView } from "electrobun/bun";
2
- import { TestRunner } from "./test-runner";
3
-
4
- // Define RPC schema for test communication
5
- export type TestRPCSchema = {
6
- bun: {
7
- requests: {
8
- runTest: {
9
- params: { testId: string };
10
- response: { success: boolean; message: string };
11
- };
12
- getTestStatus: {
13
- params: {};
14
- response: { tests: any[] };
15
- };
16
- cleanup: {
17
- params: {};
18
- response: { success: boolean; message: string };
19
- };
20
- };
21
- messages: {
22
- testEvent: { testId: string; status: string; data: any };
23
- };
24
- };
25
- webview: {
26
- requests: {
27
- markTestResult: {
28
- params: { testId: string; passed: boolean; notes?: string };
29
- response: { acknowledged: boolean };
30
- };
31
- };
32
- messages: {
33
- showInstructions: { testId: string; instructions: string[] };
34
- updateStatus: { testId: string; status: string; details?: string };
35
- };
36
- };
37
- };
38
-
39
- const testRunner = new TestRunner();
40
-
41
- // Create RPC handler
42
- const testRPC = BrowserView.defineRPC<TestRPCSchema>({
43
- maxRequestTime: 5000,
44
- handlers: {
45
- requests: {
46
- runTest: async ({ testId }) => {
47
- const result = await testRunner.runTest(testId);
48
- return result;
49
- },
50
- getTestStatus: async () => {
51
- return {
52
- tests: testRunner.getAllTestStatus()
53
- };
54
- },
55
- cleanup: async () => {
56
- try {
57
- await testRunner.cleanup();
58
- return { success: true, message: 'Cleanup completed successfully' };
59
- } catch (error) {
60
- console.error('Cleanup failed:', error);
61
- return { success: false, message: `Cleanup failed: ${error}` };
62
- }
63
- }
64
- },
65
- messages: {
66
- markTestResult: ({ testId, passed, notes }) => {
67
- testRunner.markManualTestResult(testId, passed, notes);
68
- console.log(`Manual test ${testId}: ${passed ? 'PASSED' : 'FAILED'}${notes ? ` - ${notes}` : ''}`);
69
- }
70
- }
71
- }
72
- });
73
-
74
- // Create main test window
75
- const mainWindow = new BrowserWindow({
76
- title: "Electrobun Test Harness",
77
- url: "views://mainview/index.html",
78
- renderer: "cef",
79
- frame: {
80
- x: 100,
81
- y: 100,
82
- width: 1200,
83
- height: 800
84
- },
85
- rpc: testRPC
86
- });
87
-
88
- // Set up test runner with main window reference
89
- testRunner.setMainWindow(mainWindow);
90
-
91
- // Initialize all tests
92
- testRunner.initialize();
93
-
94
- console.log("Electrobun Test Harness started");
95
- console.log("Main window created, loading test interface...");
96
-
97
- mainWindow.on("close", () => {
98
- console.log("Test harness closing, cleaning up...");
99
- testRunner.cleanup();
100
- });
@@ -1,508 +0,0 @@
1
- import { BrowserWindow, Tray } from "electrobun/bun";
2
- import type { TestRPCSchema } from "./index";
3
-
4
- export interface TestCase {
5
- id: string;
6
- name: string;
7
- category: string;
8
- type: 'auto' | 'manual' | 'hybrid';
9
- description?: string;
10
- setup: () => Promise<void> | void;
11
- cleanup?: () => Promise<void> | void;
12
- verify?: () => boolean; // Only for 'auto' tests
13
- instructions?: string[]; // For 'manual' tests
14
- status: 'pending' | 'running' | 'passed' | 'failed';
15
- lastResult?: { success: boolean; message?: string; timestamp: number };
16
- }
17
-
18
- export class TestRunner {
19
- private tests = new Map<string, TestCase>();
20
- private mainWindow: BrowserWindow | null = null;
21
- private testWindows: BrowserWindow[] = [];
22
- private trayInstance: Tray | null = null;
23
- private trayWindow: BrowserWindow | null = null;
24
-
25
- constructor() {
26
- this.registerAllTests();
27
- }
28
-
29
- setMainWindow(window: BrowserWindow) {
30
- this.mainWindow = window;
31
- }
32
-
33
- initialize() {
34
- console.log(`Registered ${this.tests.size} tests`);
35
-
36
- // Send initial test list to UI
37
- if (this.mainWindow) {
38
- setTimeout(() => {
39
- this.mainWindow!.webview.rpc?.send.updateStatus({
40
- testId: 'init',
41
- status: 'ready',
42
- details: `${this.tests.size} tests loaded`
43
- });
44
- }, 1000);
45
- }
46
- }
47
-
48
- private registerAllTests() {
49
- // Window Management Tests
50
- this.registerTest({
51
- id: 'window-creation',
52
- name: 'Window Creation',
53
- category: 'Windows',
54
- type: 'auto',
55
- description: 'Test creating and destroying windows',
56
- setup: async () => {
57
- const testWindow = new BrowserWindow({
58
- title: 'Test Window',
59
- frame: { width: 400, height: 300, x: 200, y: 200 },
60
- url: 'views://testviews/window-create.html'
61
- });
62
-
63
- this.testWindows.push(testWindow);
64
-
65
- // Auto-pass after window creation
66
- setTimeout(() => {
67
- this.markTestPassed('window-creation', 'Window created successfully');
68
- testWindow.close();
69
- }, 2000);
70
- }
71
- });
72
-
73
- this.registerTest({
74
- id: 'window-events',
75
- name: 'Window Move & Resize Events',
76
- category: 'Windows',
77
- type: 'auto',
78
- description: 'Test window event detection',
79
- setup: async () => {
80
- const testWindow = new BrowserWindow({
81
- title: 'Move and Resize Me!',
82
- frame: { width: 500, height: 400, x: 300, y: 200 },
83
- url: 'views://testviews/window-events.html'
84
- });
85
-
86
- this.testWindows.push(testWindow);
87
-
88
- let moveDetected = false;
89
- let resizeDetected = false;
90
-
91
- testWindow.on('move', ({data}) => {
92
- // if (!moveDetected) {
93
- moveDetected = true;
94
- const x = data?.x || 'unknown';
95
- const y = data?.y || 'unknown';
96
- testWindow.webview.executeJavascript(`
97
- document.getElementById('events').innerHTML = '<div>✅ Move detected: (${x}, ${y})</div>';
98
- `);
99
- this.updateTestStatus('window-events', moveDetected && resizeDetected);
100
- // }
101
- });
102
-
103
- testWindow.on('resize', ({data}) => {
104
- // if (!resizeDetected) {
105
- resizeDetected = true;
106
- const width = data?.width || 'unknown';
107
- const height = data?.height || 'unknown';
108
- testWindow.webview.executeJavascript(`
109
- document.getElementById('events').innerHTML = '<div>✅ Resize detected: ${width}x${height}</div>';
110
- `);
111
- this.updateTestStatus('window-events', moveDetected && resizeDetected);
112
- // }
113
- });
114
-
115
- testWindow.on('close', () => {
116
- if (moveDetected && resizeDetected) {
117
- this.markTestPassed('window-events', 'Both move and resize events detected');
118
- } else {
119
- this.markTestFailed('window-events', `Missing events - Move: ${moveDetected}, Resize: ${resizeDetected}`);
120
- }
121
- });
122
- }
123
- });
124
-
125
- // WebView Tests
126
- this.registerTest({
127
- id: 'webview-mask-layer',
128
- name: 'WebView Mask Layer',
129
- category: 'WebViews',
130
- type: 'manual',
131
- instructions: [
132
- 'A window will open with a WebView and a RED overlay button',
133
- 'Scroll the window up and down',
134
- 'Verify the RED button ALWAYS stays on top of the WebView',
135
- 'The button should NEVER disappear behind the WebView content',
136
- 'Click PASS if the button stays on top, FAIL if it goes behind'
137
- ],
138
- setup: async () => {
139
- const maskTestWindow = new BrowserWindow({
140
- title: 'Mask Test - SCROLL TO TEST',
141
- frame: { width: 700, height: 500, x: 400, y: 100 },
142
- url: 'views://testviews/webview-mask.html'
143
- });
144
-
145
- this.testWindows.push(maskTestWindow);
146
- }
147
- });
148
-
149
- this.registerTest({
150
- id: 'webview-navigation',
151
- name: 'WebView Navigation',
152
- category: 'WebViews',
153
- type: 'hybrid',
154
- instructions: [
155
- 'A WebView will load example.com',
156
- 'Verify the page content loads correctly',
157
- 'Try navigating to different URLs if possible',
158
- 'Check that navigation events are detected (shown below)'
159
- ],
160
- setup: async () => {
161
- const navTestWindow = new BrowserWindow({
162
- title: 'WebView Navigation Test',
163
- frame: { width: 800, height: 600, x: 200, y: 150 },
164
- url: 'views://testviews/webview-navigation.html'
165
- });
166
-
167
- this.testWindows.push(navTestWindow);
168
-
169
- // Auto-detect navigation events
170
- navTestWindow.webview.on('did-navigate', ({data: {detail: url}}) => {
171
- navTestWindow.webview.executeJavascript(`
172
- document.getElementById('nav-events').innerHTML +=
173
- '<div>✅ Navigation: ${url} at ' + new Date().toLocaleTimeString() + '</div>';
174
- `);
175
- this.markTestPassed('webview-navigation', `Navigation detected to: ${url}`);
176
- });
177
- }
178
- });
179
-
180
- // System Integration Tests
181
- this.registerTest({
182
- id: 'system-tray',
183
- name: 'System Tray',
184
- category: 'System',
185
- type: 'manual',
186
- instructions: [
187
- 'Look for a test tray icon in your system tray/menu bar',
188
- 'Click the tray icon to open the menu',
189
- 'Try clicking "Test Item 1" and "Test Item 2"',
190
- 'Try the submenu items',
191
- 'Verify menu items work and events are logged below'
192
- ],
193
- setup: async () => {
194
- this.trayInstance = new Tray({
195
- title: "Test",
196
- image: ""
197
- });
198
-
199
- // Set up tray event listener
200
- this.trayInstance.on('tray-clicked', (eventData) => {
201
- console.log('Tray clicked:', eventData);
202
- // TODO: Note: trim() is currently necessary even though nothing is being trimmed.
203
- // Could be an issue with this version of bun or something else.
204
- const action = eventData?.data?.action?.trim();
205
-
206
- switch (action) {
207
- case 'test-item-1':
208
- this.logTrayEvent("Test Item 1 clicked");
209
- break;
210
- case 'test-item-2':
211
- this.logTrayEvent("Test Item 2 clicked");
212
- break;
213
- case 'submenu-item-a':
214
- this.logTrayEvent("Submenu Item A clicked");
215
- break;
216
- case 'submenu-item-b':
217
- this.logTrayEvent("Submenu Item B clicked");
218
- break;
219
- case 'mark-passed':
220
- this.markTestPassed('system-tray', 'User confirmed tray functionality works');
221
- break;
222
- default:
223
- console.log(`Unknown tray action: "${action}"`);
224
- }
225
- });
226
-
227
- // Set the menu separately
228
- this.trayInstance.setMenu([
229
- {
230
- type: "normal",
231
- label: "Test Item 1",
232
- action: "test-item-1"
233
- },
234
- {
235
- type: "normal",
236
- label: "Test Item 2",
237
- action: "test-item-2"
238
- },
239
- { type: "separator" },
240
- {
241
- type: "normal",
242
- label: "Submenu Test",
243
- submenu: [
244
- {
245
- type: "normal",
246
- label: "Submenu Item A",
247
- action: "submenu-item-a"
248
- },
249
- {
250
- type: "normal",
251
- label: "Submenu Item B",
252
- action: "submenu-item-b"
253
- }
254
- ]
255
- },
256
- { type: "separator" },
257
- {
258
- type: "normal",
259
- label: "Mark Tray Test as Passed",
260
- action: "mark-passed"
261
- }
262
- ]);
263
-
264
- // Show tray test window with instructions
265
- this.trayWindow = new BrowserWindow({
266
- title: 'Tray Test Instructions',
267
- frame: { width: 500, height: 400, x: 100, y: 300 },
268
- url: 'views://testviews/tray-test.html'
269
- });
270
-
271
- this.testWindows.push(this.trayWindow);
272
- },
273
- cleanup: async () => {
274
- if (this.trayInstance) {
275
- this.trayInstance.remove();
276
- this.trayInstance = null;
277
- }
278
- this.trayWindow = null;
279
- }
280
- });
281
-
282
- // Multi-window test
283
- this.registerTest({
284
- id: 'multi-window',
285
- name: 'Multi-Window Management',
286
- category: 'Windows',
287
- type: 'manual',
288
- instructions: [
289
- 'Multiple windows will be created',
290
- 'Try focusing different windows by clicking on them',
291
- 'Verify window focus changes are detected',
292
- 'Try overlapping and arranging windows',
293
- 'Check that each window behaves independently'
294
- ],
295
- setup: async () => {
296
- // Create multiple test windows
297
- for (let i = 1; i <= 3; i++) {
298
- const testWindow = new BrowserWindow({
299
- title: `Test Window ${i}`,
300
- frame: {
301
- width: 300,
302
- height: 250,
303
- x: 200 + (i * 50),
304
- y: 200 + (i * 50)
305
- },
306
- url: `views://testviews/window-focus.html?num=${i}`
307
- });
308
-
309
- this.testWindows.push(testWindow);
310
-
311
- let focusCount = 0;
312
- testWindow.on('focus', () => {
313
- focusCount++;
314
- testWindow.webview.executeJavascript(`
315
- document.getElementById('focus-status').textContent = 'Focused';
316
- document.getElementById('focus-count').textContent = 'Focus events: ${focusCount}';
317
- document.body.style.borderLeft = '5px solid green';
318
- `);
319
- });
320
-
321
- testWindow.on('blur', () => {
322
- testWindow.webview.executeJavascript(`
323
- document.getElementById('focus-status').textContent = 'Not Focused';
324
- document.body.style.borderLeft = '5px solid gray';
325
- `);
326
- });
327
- }
328
-
329
- // Auto-pass after windows are created
330
- setTimeout(() => {
331
- this.markTestPassed('multi-window', 'Multiple windows created successfully');
332
- }, 1000);
333
- }
334
- });
335
- }
336
-
337
- private registerTest(test: Omit<TestCase, 'status' | 'lastResult'>) {
338
- this.tests.set(test.id, {
339
- ...test,
340
- status: 'pending'
341
- });
342
- }
343
-
344
- async runTest(testId: string): Promise<{ success: boolean; message: string }> {
345
- const test = this.tests.get(testId);
346
- if (!test) {
347
- return { success: false, message: `Test ${testId} not found` };
348
- }
349
-
350
- test.status = 'running';
351
- this.notifyStatusChange(testId);
352
-
353
- try {
354
- await test.setup();
355
-
356
- if (test.type === 'auto' && test.verify) {
357
- const result = test.verify();
358
- if (result) {
359
- this.markTestPassed(testId, 'Auto-verification passed');
360
- } else {
361
- this.markTestFailed(testId, 'Auto-verification failed');
362
- }
363
- }
364
-
365
- return { success: true, message: `Test ${testId} setup completed` };
366
- } catch (error) {
367
- console.error(`Test ${testId} failed:`, error);
368
- this.markTestFailed(testId, `Setup failed: ${error.message}`);
369
- return { success: false, message: error.message };
370
- }
371
- }
372
-
373
- markManualTestResult(testId: string, passed: boolean, notes?: string) {
374
- if (passed) {
375
- this.markTestPassed(testId, notes || 'Manual verification passed');
376
- } else {
377
- this.markTestFailed(testId, notes || 'Manual verification failed');
378
- }
379
- }
380
-
381
- private markTestPassed(testId: string, message: string) {
382
- const test = this.tests.get(testId);
383
- if (test) {
384
- test.status = 'passed';
385
- test.lastResult = { success: true, message, timestamp: Date.now() };
386
- this.notifyStatusChange(testId);
387
- console.log(`✅ Test PASSED: ${test.name} - ${message}`);
388
- }
389
- }
390
-
391
- private markTestFailed(testId: string, message: string) {
392
- const test = this.tests.get(testId);
393
- if (test) {
394
- test.status = 'failed';
395
- test.lastResult = { success: false, message, timestamp: Date.now() };
396
- this.notifyStatusChange(testId);
397
- console.log(`❌ Test FAILED: ${test.name} - ${message}`);
398
- }
399
- }
400
-
401
- private updateTestStatus(testId: string, success: boolean) {
402
- if (success) {
403
- this.markTestPassed(testId, 'All conditions met');
404
- }
405
- }
406
-
407
- private notifyStatusChange(testId: string) {
408
- if (this.mainWindow) {
409
- const test = this.tests.get(testId);
410
- this.mainWindow.webview.rpc?.send.updateStatus({
411
- testId,
412
- status: test?.status || 'unknown',
413
- details: test?.lastResult?.message
414
- });
415
- }
416
- }
417
-
418
- private logTrayEvent(message: string) {
419
- console.log(`Tray event: ${message}`);
420
- // Use the stored tray window reference
421
- if (this.trayWindow) {
422
- try {
423
- // Add a small delay to ensure the DOM is ready and use a more robust approach
424
- setTimeout(() => {
425
- this.trayWindow?.webview.executeJavascript(`
426
- console.log('Trying to update tray events with: ${message}');
427
-
428
- // Wait for DOM to be ready
429
- function updateTrayEvents() {
430
- const eventsDiv = document.getElementById('tray-events');
431
- console.log('Found tray-events div:', eventsDiv);
432
-
433
- if (eventsDiv) {
434
- const eventHtml = '<div class="event-item">✅ ${message} at ' + new Date().toLocaleTimeString() + '</div>';
435
- console.log('Adding event HTML:', eventHtml);
436
- eventsDiv.innerHTML += eventHtml;
437
- console.log('Updated tray events successfully');
438
- } else {
439
- console.error('tray-events element not found in tray window');
440
- // Try to find any element with id containing 'tray'
441
- const allElements = document.querySelectorAll('[id*="tray"]');
442
- console.log('Elements with tray in id:', allElements);
443
- }
444
- }
445
-
446
- if (document.readyState === 'loading') {
447
- document.addEventListener('DOMContentLoaded', updateTrayEvents);
448
- } else {
449
- updateTrayEvents();
450
- }
451
- `);
452
- }, 100);
453
- } catch (error) {
454
- console.error('Failed to update tray window:', error);
455
- }
456
- } else {
457
- console.error('Tray window not available');
458
- }
459
- }
460
-
461
- getAllTestStatus() {
462
- return Array.from(this.tests.values()).map(test => ({
463
- id: test.id,
464
- name: test.name,
465
- category: test.category,
466
- type: test.type,
467
- status: test.status,
468
- description: test.description,
469
- instructions: test.instructions,
470
- lastResult: test.lastResult
471
- }));
472
- }
473
-
474
- async cleanup() {
475
- console.log('Cleaning up test runner...');
476
-
477
- // Close all test windows
478
- for (const window of this.testWindows) {
479
- try {
480
- window.close();
481
- } catch (e) {
482
- // Window might already be closed
483
- }
484
- }
485
- this.testWindows = [];
486
-
487
- // Remove tray
488
- if (this.trayInstance) {
489
- this.trayInstance.remove();
490
- this.trayInstance = null;
491
- }
492
-
493
- // Run individual test cleanup
494
- for (const test of this.tests.values()) {
495
- if (test.cleanup) {
496
- try {
497
- await test.cleanup();
498
- } catch (e) {
499
- console.warn(`Cleanup failed for test ${test.id}:`, e);
500
- }
501
- }
502
-
503
- // Reset test status to pending
504
- test.status = 'pending';
505
- delete test.lastResult;
506
- }
507
- }
508
- }