electrobun 0.4.1 โ 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.
- package/{templates/multitab-browser/bun.lock โ bun.lock} +20 -13
- package/dist/api/bun/proc/native.ts +84 -16
- package/package.json +14 -16
- package/BETA_RELEASE.md +0 -67
- package/BUILD.md +0 -90
- package/LICENSE +0 -21
- package/README.md +0 -102
- package/debug.js +0 -5
- package/templates/hello-world/README.md +0 -57
- package/templates/hello-world/bun.lock +0 -225
- package/templates/hello-world/electrobun.config.ts +0 -28
- package/templates/hello-world/package.json +0 -16
- package/templates/hello-world/src/bun/index.ts +0 -15
- package/templates/hello-world/src/mainview/index.css +0 -124
- package/templates/hello-world/src/mainview/index.html +0 -46
- package/templates/hello-world/src/mainview/index.ts +0 -1
- package/templates/interactive-playground/README.md +0 -26
- package/templates/interactive-playground/assets/tray-icon.png +0 -0
- package/templates/interactive-playground/electrobun.config.ts +0 -36
- package/templates/interactive-playground/package-lock.json +0 -1112
- package/templates/interactive-playground/package.json +0 -15
- package/templates/interactive-playground/src/bun/demos/files.ts +0 -70
- package/templates/interactive-playground/src/bun/demos/menus.ts +0 -139
- package/templates/interactive-playground/src/bun/demos/rpc.ts +0 -83
- package/templates/interactive-playground/src/bun/demos/system.ts +0 -72
- package/templates/interactive-playground/src/bun/demos/updates.ts +0 -105
- package/templates/interactive-playground/src/bun/demos/windows.ts +0 -90
- package/templates/interactive-playground/src/bun/index.ts +0 -124
- package/templates/interactive-playground/src/bun/types/rpc.ts +0 -109
- package/templates/interactive-playground/src/mainview/components/EventLog.ts +0 -107
- package/templates/interactive-playground/src/mainview/components/Sidebar.ts +0 -65
- package/templates/interactive-playground/src/mainview/components/Toast.ts +0 -57
- package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +0 -211
- package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +0 -102
- package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +0 -229
- package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +0 -132
- package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +0 -465
- package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +0 -207
- package/templates/interactive-playground/src/mainview/index.css +0 -538
- package/templates/interactive-playground/src/mainview/index.html +0 -103
- package/templates/interactive-playground/src/mainview/index.ts +0 -238
- package/templates/multitab-browser/README.md +0 -34
- package/templates/multitab-browser/electrobun.config.ts +0 -32
- package/templates/multitab-browser/package-lock.json +0 -20
- package/templates/multitab-browser/package.json +0 -12
- package/templates/multitab-browser/src/bun/index.ts +0 -144
- package/templates/multitab-browser/src/bun/tabManager.ts +0 -200
- package/templates/multitab-browser/src/bun/types/rpc.ts +0 -78
- package/templates/multitab-browser/src/mainview/index.css +0 -487
- package/templates/multitab-browser/src/mainview/index.html +0 -94
- package/templates/multitab-browser/src/mainview/index.ts +0 -634
- package/templates/photo-booth/README.md +0 -108
- package/templates/photo-booth/bun.lock +0 -239
- package/templates/photo-booth/electrobun.config.ts +0 -32
- package/templates/photo-booth/package.json +0 -17
- package/templates/photo-booth/src/bun/index.ts +0 -92
- package/templates/photo-booth/src/mainview/index.css +0 -465
- package/templates/photo-booth/src/mainview/index.html +0 -124
- package/templates/photo-booth/src/mainview/index.ts +0 -499
- package/test-new-window-events.ts +0 -26
- package/test-new-window.html +0 -75
- package/test-npm-install.sh +0 -34
- package/tests/bun.lock +0 -14
- package/tests/electrobun.config.ts +0 -45
- package/tests/package-lock.json +0 -36
- package/tests/package.json +0 -13
- package/tests/src/bun/index.ts +0 -100
- package/tests/src/bun/test-runner.ts +0 -508
- package/tests/src/mainview/index.html +0 -110
- package/tests/src/mainview/index.ts +0 -458
- package/tests/src/mainview/styles/main.css +0 -451
- package/tests/src/testviews/tray-test.html +0 -57
- package/tests/src/testviews/webview-mask.html +0 -114
- package/tests/src/testviews/webview-navigation.html +0 -36
- package/tests/src/testviews/window-create.html +0 -17
- package/tests/src/testviews/window-events.html +0 -29
- package/tests/src/testviews/window-focus.html +0 -37
- package/tests/src/webviewtag/index.ts +0 -11
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Electrobun Test Harness</title>
|
|
7
|
-
<link rel="stylesheet" href="styles/main.css">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div class="app-container">
|
|
11
|
-
<header class="header">
|
|
12
|
-
<h1>๐งช Electrobun Test Harness</h1>
|
|
13
|
-
<div class="header-actions">
|
|
14
|
-
<button id="run-all-btn" class="btn btn-primary">Run All Tests</button>
|
|
15
|
-
<button id="cleanup-btn" class="btn btn-secondary">Cleanup</button>
|
|
16
|
-
<div class="platform-info">
|
|
17
|
-
<span id="platform-name">Platform: Loading...</span>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
</header>
|
|
21
|
-
|
|
22
|
-
<div class="main-content">
|
|
23
|
-
<aside class="sidebar">
|
|
24
|
-
<div class="test-categories">
|
|
25
|
-
<h3>Test Categories</h3>
|
|
26
|
-
<div id="category-filters">
|
|
27
|
-
<label class="filter-item">
|
|
28
|
-
<input type="checkbox" value="Windows" checked> Windows
|
|
29
|
-
</label>
|
|
30
|
-
<label class="filter-item">
|
|
31
|
-
<input type="checkbox" value="WebViews" checked> WebViews
|
|
32
|
-
</label>
|
|
33
|
-
<label class="filter-item">
|
|
34
|
-
<input type="checkbox" value="System" checked> System
|
|
35
|
-
</label>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
|
|
39
|
-
<div class="test-status-summary">
|
|
40
|
-
<h3>Status Summary</h3>
|
|
41
|
-
<div class="status-counts">
|
|
42
|
-
<div class="count-item">
|
|
43
|
-
<span class="count" id="passed-count">0</span>
|
|
44
|
-
<span class="label">Passed</span>
|
|
45
|
-
</div>
|
|
46
|
-
<div class="count-item">
|
|
47
|
-
<span class="count" id="failed-count">0</span>
|
|
48
|
-
<span class="label">Failed</span>
|
|
49
|
-
</div>
|
|
50
|
-
<div class="count-item">
|
|
51
|
-
<span class="count" id="pending-count">0</span>
|
|
52
|
-
<span class="label">Pending</span>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
</aside>
|
|
57
|
-
|
|
58
|
-
<main class="test-area">
|
|
59
|
-
<div class="auto-tests-section">
|
|
60
|
-
<h2>๐ค Auto-Detected Tests</h2>
|
|
61
|
-
<p class="section-description">These tests can automatically detect success/failure</p>
|
|
62
|
-
<div id="auto-tests-container" class="tests-container">
|
|
63
|
-
<!-- Auto tests will be populated here -->
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
<div class="manual-tests-section">
|
|
68
|
-
<h2>๐๏ธ Manual Verification Tests</h2>
|
|
69
|
-
<p class="section-description">These tests require human verification - follow instructions carefully</p>
|
|
70
|
-
<div id="manual-tests-container" class="tests-container">
|
|
71
|
-
<!-- Manual tests will be populated here -->
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
|
-
<div class="hybrid-tests-section">
|
|
76
|
-
<h2>๐ Hybrid Tests</h2>
|
|
77
|
-
<p class="section-description">These tests have both automatic detection and manual verification components</p>
|
|
78
|
-
<div id="hybrid-tests-container" class="tests-container">
|
|
79
|
-
<!-- Hybrid tests will be populated here -->
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
</main>
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
<div class="event-log">
|
|
86
|
-
<h3>Event Log</h3>
|
|
87
|
-
<div id="event-log-content" class="log-content">
|
|
88
|
-
<div class="log-entry">
|
|
89
|
-
<span class="timestamp">Starting test harness...</span>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
<!-- Modal for detailed test results -->
|
|
96
|
-
<div id="test-modal" class="modal" style="display: none;">
|
|
97
|
-
<div class="modal-content">
|
|
98
|
-
<div class="modal-header">
|
|
99
|
-
<h3 id="modal-title">Test Details</h3>
|
|
100
|
-
<button class="modal-close">×</button>
|
|
101
|
-
</div>
|
|
102
|
-
<div class="modal-body" id="modal-body">
|
|
103
|
-
<!-- Test details will be shown here -->
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
|
|
108
|
-
<script type="module" src="index.js"></script>
|
|
109
|
-
</body>
|
|
110
|
-
</html>
|
|
@@ -1,458 +0,0 @@
|
|
|
1
|
-
import { Electroview } from "electrobun/view";
|
|
2
|
-
import type { TestRPCSchema } from "../bun/index";
|
|
3
|
-
|
|
4
|
-
interface TestData {
|
|
5
|
-
id: string;
|
|
6
|
-
name: string;
|
|
7
|
-
category: string;
|
|
8
|
-
type: 'auto' | 'manual' | 'hybrid';
|
|
9
|
-
status: 'pending' | 'running' | 'passed' | 'failed';
|
|
10
|
-
description?: string;
|
|
11
|
-
instructions?: string[];
|
|
12
|
-
lastResult?: { success: boolean; message?: string; timestamp: number };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
class TestHarnessUI {
|
|
16
|
-
private electroview: Electroview<TestRPCSchema>;
|
|
17
|
-
private tests = new Map<string, TestData>();
|
|
18
|
-
private logContainer: HTMLElement;
|
|
19
|
-
|
|
20
|
-
constructor() {
|
|
21
|
-
this.electroview = new Electroview({
|
|
22
|
-
rpc: Electroview.defineRPC<TestRPCSchema>({
|
|
23
|
-
handlers: {
|
|
24
|
-
requests: {
|
|
25
|
-
markTestResult: async ({ testId, passed, notes }) => {
|
|
26
|
-
this.handleManualTestResult(testId, passed, notes);
|
|
27
|
-
return { acknowledged: true };
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
messages: {
|
|
31
|
-
showInstructions: ({ testId, instructions }) => {
|
|
32
|
-
this.showInstructions(testId, instructions);
|
|
33
|
-
},
|
|
34
|
-
updateStatus: ({ testId, status, details }) => {
|
|
35
|
-
this.updateTestStatus(testId, status, details);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
this.logContainer = document.getElementById('event-log-content')!;
|
|
43
|
-
this.initialize();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private async initialize() {
|
|
47
|
-
this.log('Initializing test harness UI...');
|
|
48
|
-
|
|
49
|
-
// Set platform info
|
|
50
|
-
this.updatePlatformInfo();
|
|
51
|
-
|
|
52
|
-
// Set up event listeners
|
|
53
|
-
this.setupEventListeners();
|
|
54
|
-
|
|
55
|
-
// Load tests from backend
|
|
56
|
-
await this.loadTests();
|
|
57
|
-
|
|
58
|
-
this.log('Test harness UI ready', 'info');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private updatePlatformInfo() {
|
|
62
|
-
const platformEl = document.getElementById('platform-name');
|
|
63
|
-
const userAgent = navigator.userAgent;
|
|
64
|
-
let platform = 'Unknown';
|
|
65
|
-
|
|
66
|
-
if (userAgent.includes('Mac')) {
|
|
67
|
-
platform = 'macOS';
|
|
68
|
-
} else if (userAgent.includes('Win')) {
|
|
69
|
-
platform = 'Windows';
|
|
70
|
-
} else if (userAgent.includes('Linux')) {
|
|
71
|
-
platform = 'Linux';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (platformEl) {
|
|
75
|
-
platformEl.textContent = `Platform: ${platform}`;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
private setupEventListeners() {
|
|
80
|
-
// Run all tests button
|
|
81
|
-
document.getElementById('run-all-btn')?.addEventListener('click', () => {
|
|
82
|
-
this.runAllTests();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Cleanup button
|
|
86
|
-
document.getElementById('cleanup-btn')?.addEventListener('click', () => {
|
|
87
|
-
this.cleanup();
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// Category filters
|
|
91
|
-
const filters = document.querySelectorAll('#category-filters input[type="checkbox"]');
|
|
92
|
-
filters.forEach(filter => {
|
|
93
|
-
filter.addEventListener('change', () => {
|
|
94
|
-
this.filterTests();
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// Modal close
|
|
99
|
-
document.querySelector('.modal-close')?.addEventListener('click', () => {
|
|
100
|
-
this.closeModal();
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
document.getElementById('test-modal')?.addEventListener('click', (e) => {
|
|
104
|
-
if (e.target === e.currentTarget) {
|
|
105
|
-
this.closeModal();
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private async loadTests() {
|
|
111
|
-
try {
|
|
112
|
-
const response = await this.electroview.rpc.request.getTestStatus({});
|
|
113
|
-
|
|
114
|
-
for (const testData of response.tests) {
|
|
115
|
-
this.tests.set(testData.id, testData);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
this.renderTests();
|
|
119
|
-
this.updateStatusCounts();
|
|
120
|
-
this.log(`Loaded ${response.tests.length} tests`);
|
|
121
|
-
} catch (error) {
|
|
122
|
-
this.log(`Failed to load tests: ${error.message}`, 'error');
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private renderTests() {
|
|
127
|
-
const autoContainer = document.getElementById('auto-tests-container')!;
|
|
128
|
-
const manualContainer = document.getElementById('manual-tests-container')!;
|
|
129
|
-
const hybridContainer = document.getElementById('hybrid-tests-container')!;
|
|
130
|
-
|
|
131
|
-
// Clear containers
|
|
132
|
-
autoContainer.innerHTML = '';
|
|
133
|
-
manualContainer.innerHTML = '';
|
|
134
|
-
hybridContainer.innerHTML = '';
|
|
135
|
-
|
|
136
|
-
for (const test of this.tests.values()) {
|
|
137
|
-
const testElement = this.createTestElement(test);
|
|
138
|
-
|
|
139
|
-
switch (test.type) {
|
|
140
|
-
case 'auto':
|
|
141
|
-
autoContainer.appendChild(testElement);
|
|
142
|
-
break;
|
|
143
|
-
case 'manual':
|
|
144
|
-
manualContainer.appendChild(testElement);
|
|
145
|
-
break;
|
|
146
|
-
case 'hybrid':
|
|
147
|
-
hybridContainer.appendChild(testElement);
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
private createTestElement(test: TestData): HTMLElement {
|
|
154
|
-
const card = document.createElement('div');
|
|
155
|
-
card.className = `test-card ${test.type} ${test.status}`;
|
|
156
|
-
card.id = `test-${test.id}`;
|
|
157
|
-
|
|
158
|
-
const statusIcon = this.getStatusIcon(test.status, test.type);
|
|
159
|
-
const typeIcon = this.getTypeIcon(test.type);
|
|
160
|
-
|
|
161
|
-
card.innerHTML = `
|
|
162
|
-
<div class="test-header">
|
|
163
|
-
<div>
|
|
164
|
-
<div class="test-title">${typeIcon} ${test.name}</div>
|
|
165
|
-
<div class="test-meta">
|
|
166
|
-
<span class="test-badge">${test.category}</span>
|
|
167
|
-
<span class="test-badge">${test.type}</span>
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
170
|
-
<div class="test-actions">
|
|
171
|
-
${test.status === 'pending' || test.status === 'failed' ?
|
|
172
|
-
`<button class="btn btn-run" onclick="testUI.runTest('${test.id}')">Run Test</button>` :
|
|
173
|
-
''}
|
|
174
|
-
</div>
|
|
175
|
-
</div>
|
|
176
|
-
|
|
177
|
-
${test.description ? `<div class="test-description">${test.description}</div>` : ''}
|
|
178
|
-
|
|
179
|
-
<div class="test-status">
|
|
180
|
-
<span class="status-indicator">${statusIcon}</span>
|
|
181
|
-
<span class="status-text">${this.getStatusText(test.status)}</span>
|
|
182
|
-
${test.lastResult?.message ?
|
|
183
|
-
`<span class="status-details">- ${test.lastResult.message}</span>` :
|
|
184
|
-
''}
|
|
185
|
-
</div>
|
|
186
|
-
|
|
187
|
-
${test.type === 'manual' || test.type === 'hybrid' ? this.createInstructionsHTML(test) : ''}
|
|
188
|
-
|
|
189
|
-
${test.type === 'manual' ? this.createManualVerifyHTML(test) : ''}
|
|
190
|
-
`;
|
|
191
|
-
|
|
192
|
-
return card;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
private createInstructionsHTML(test: TestData): string {
|
|
196
|
-
if (!test.instructions || test.instructions.length === 0) {
|
|
197
|
-
return '';
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return `
|
|
201
|
-
<div class="test-instructions">
|
|
202
|
-
<h4>Instructions:</h4>
|
|
203
|
-
<ol>
|
|
204
|
-
${test.instructions.map(instruction => `<li>${instruction}</li>`).join('')}
|
|
205
|
-
</ol>
|
|
206
|
-
</div>
|
|
207
|
-
`;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private createManualVerifyHTML(test: TestData): string {
|
|
211
|
-
if (test.status === 'passed' || test.status === 'failed') {
|
|
212
|
-
return '';
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return `
|
|
216
|
-
<div class="manual-verify">
|
|
217
|
-
<span class="manual-verify-text">Did this test work correctly?</span>
|
|
218
|
-
<button class="btn btn-success" onclick="testUI.markTestPassed('${test.id}')">โ
Pass</button>
|
|
219
|
-
<button class="btn btn-danger" onclick="testUI.markTestFailed('${test.id}')">โ Fail</button>
|
|
220
|
-
</div>
|
|
221
|
-
`;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
private getStatusIcon(status: string, type: string): string {
|
|
225
|
-
switch (status) {
|
|
226
|
-
case 'passed': return 'โ
';
|
|
227
|
-
case 'failed': return 'โ';
|
|
228
|
-
case 'running': return 'โณ';
|
|
229
|
-
default: return 'โช';
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
private getTypeIcon(type: string): string {
|
|
234
|
-
switch (type) {
|
|
235
|
-
case 'auto': return '๐ค';
|
|
236
|
-
case 'manual': return '๐๏ธ';
|
|
237
|
-
case 'hybrid': return '๐';
|
|
238
|
-
default: return '๐';
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
private getStatusText(status: string): string {
|
|
243
|
-
switch (status) {
|
|
244
|
-
case 'passed': return 'PASSED';
|
|
245
|
-
case 'failed': return 'FAILED';
|
|
246
|
-
case 'running': return 'RUNNING';
|
|
247
|
-
case 'pending': return 'PENDING';
|
|
248
|
-
default: return 'UNKNOWN';
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
private async runTest(testId: string) {
|
|
253
|
-
const test = this.tests.get(testId);
|
|
254
|
-
if (!test) return;
|
|
255
|
-
|
|
256
|
-
this.log(`Starting test: ${test.name}`);
|
|
257
|
-
test.status = 'running';
|
|
258
|
-
this.updateTestDisplay(test);
|
|
259
|
-
|
|
260
|
-
try {
|
|
261
|
-
const result = await this.electroview.rpc.request.runTest({ testId });
|
|
262
|
-
|
|
263
|
-
if (result.success) {
|
|
264
|
-
this.log(`Test setup completed: ${test.name}`, 'info');
|
|
265
|
-
} else {
|
|
266
|
-
this.log(`Test setup failed: ${test.name} - ${result.message}`, 'error');
|
|
267
|
-
}
|
|
268
|
-
} catch (error) {
|
|
269
|
-
this.log(`Test error: ${test.name} - ${error.message}`, 'error');
|
|
270
|
-
test.status = 'failed';
|
|
271
|
-
this.updateTestDisplay(test);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private async runAllTests() {
|
|
276
|
-
this.log('Running all tests...', 'info');
|
|
277
|
-
|
|
278
|
-
const pendingTests = Array.from(this.tests.values()).filter(t => t.status === 'pending');
|
|
279
|
-
|
|
280
|
-
for (const test of pendingTests) {
|
|
281
|
-
await this.runTest(test.id);
|
|
282
|
-
// Add small delay between tests
|
|
283
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
this.log(`Completed running ${pendingTests.length} tests`, 'info');
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
markTestPassed(testId: string) {
|
|
290
|
-
this.electroview.rpc.send.markTestResult({
|
|
291
|
-
testId,
|
|
292
|
-
passed: true,
|
|
293
|
-
notes: 'Manual verification: User confirmed test passed'
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
markTestFailed(testId: string) {
|
|
298
|
-
const notes = prompt('Optional: Describe what went wrong:');
|
|
299
|
-
this.electroview.rpc.send.markTestResult({
|
|
300
|
-
testId,
|
|
301
|
-
passed: false,
|
|
302
|
-
notes: notes || 'Manual verification: User reported test failed'
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
private handleManualTestResult(testId: string, passed: boolean, notes?: string) {
|
|
307
|
-
const test = this.tests.get(testId);
|
|
308
|
-
if (!test) return;
|
|
309
|
-
|
|
310
|
-
test.status = passed ? 'passed' : 'failed';
|
|
311
|
-
test.lastResult = {
|
|
312
|
-
success: passed,
|
|
313
|
-
message: notes,
|
|
314
|
-
timestamp: Date.now()
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
this.updateTestDisplay(test);
|
|
318
|
-
this.updateStatusCounts();
|
|
319
|
-
|
|
320
|
-
const status = passed ? 'PASSED' : 'FAILED';
|
|
321
|
-
this.log(`Manual test ${status}: ${test.name}${notes ? ` - ${notes}` : ''}`, passed ? 'success' : 'error');
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
private updateTestStatus(testId: string, status: string, details?: string) {
|
|
325
|
-
const test = this.tests.get(testId);
|
|
326
|
-
if (!test) return;
|
|
327
|
-
|
|
328
|
-
test.status = status as any;
|
|
329
|
-
if (details) {
|
|
330
|
-
test.lastResult = {
|
|
331
|
-
success: status === 'passed',
|
|
332
|
-
message: details,
|
|
333
|
-
timestamp: Date.now()
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
this.updateTestDisplay(test);
|
|
338
|
-
this.updateStatusCounts();
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
private updateTestDisplay(test: TestData) {
|
|
342
|
-
const element = document.getElementById(`test-${test.id}`);
|
|
343
|
-
if (!element) return;
|
|
344
|
-
|
|
345
|
-
// Update classes
|
|
346
|
-
element.className = `test-card ${test.type} ${test.status}`;
|
|
347
|
-
|
|
348
|
-
// Flash animation for status changes
|
|
349
|
-
if (test.status === 'passed') {
|
|
350
|
-
element.classList.add('flash-success');
|
|
351
|
-
setTimeout(() => element.classList.remove('flash-success'), 600);
|
|
352
|
-
} else if (test.status === 'failed') {
|
|
353
|
-
element.classList.add('flash-error');
|
|
354
|
-
setTimeout(() => element.classList.remove('flash-error'), 600);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Re-render the element
|
|
358
|
-
const newElement = this.createTestElement(test);
|
|
359
|
-
element.innerHTML = newElement.innerHTML;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
private updateStatusCounts() {
|
|
363
|
-
const counts = { passed: 0, failed: 0, pending: 0, running: 0 };
|
|
364
|
-
|
|
365
|
-
for (const test of this.tests.values()) {
|
|
366
|
-
counts[test.status]++;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
document.getElementById('passed-count')!.textContent = counts.passed.toString();
|
|
370
|
-
document.getElementById('failed-count')!.textContent = counts.failed.toString();
|
|
371
|
-
document.getElementById('pending-count')!.textContent = (counts.pending + counts.running).toString();
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
private filterTests() {
|
|
375
|
-
const checkboxes = document.querySelectorAll('#category-filters input[type="checkbox"]') as NodeListOf<HTMLInputElement>;
|
|
376
|
-
const activeCategories = Array.from(checkboxes)
|
|
377
|
-
.filter(cb => cb.checked)
|
|
378
|
-
.map(cb => cb.value);
|
|
379
|
-
|
|
380
|
-
for (const test of this.tests.values()) {
|
|
381
|
-
const element = document.getElementById(`test-${test.id}`);
|
|
382
|
-
if (element) {
|
|
383
|
-
element.style.display = activeCategories.includes(test.category) ? 'block' : 'none';
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
private showInstructions(testId: string, instructions: string[]) {
|
|
389
|
-
// Instructions are already shown in the test cards
|
|
390
|
-
this.log(`Instructions shown for test: ${testId}`, 'info');
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
private async cleanup() {
|
|
394
|
-
this.log('Cleaning up all tests...', 'info');
|
|
395
|
-
|
|
396
|
-
try {
|
|
397
|
-
const result = await this.electroview.rpc.request.cleanup({});
|
|
398
|
-
|
|
399
|
-
if (result.success) {
|
|
400
|
-
this.log(result.message, 'success');
|
|
401
|
-
|
|
402
|
-
setTimeout(() => {
|
|
403
|
-
// Reset all test statuses to pending
|
|
404
|
-
this.tests.forEach(test => {
|
|
405
|
-
test.status = 'pending';
|
|
406
|
-
test.lastResult = undefined;
|
|
407
|
-
});
|
|
408
|
-
// Refresh the UI
|
|
409
|
-
this.renderTests();
|
|
410
|
-
this.updateStatusCounts();
|
|
411
|
-
}, 100)
|
|
412
|
-
|
|
413
|
-
this.log('All tests reset to pending state', 'info');
|
|
414
|
-
} else {
|
|
415
|
-
this.log(result.message, 'error');
|
|
416
|
-
}
|
|
417
|
-
} catch (error) {
|
|
418
|
-
this.log(`Cleanup failed: ${error}`, 'error');
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
private closeModal() {
|
|
423
|
-
const modal = document.getElementById('test-modal');
|
|
424
|
-
if (modal) {
|
|
425
|
-
modal.style.display = 'none';
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
private log(message: string, type: 'info' | 'success' | 'error' = 'info') {
|
|
430
|
-
const timestamp = new Date().toLocaleTimeString();
|
|
431
|
-
const entry = document.createElement('div');
|
|
432
|
-
entry.className = 'log-entry';
|
|
433
|
-
|
|
434
|
-
const typeClass = type === 'success' ? 'log-success' :
|
|
435
|
-
type === 'error' ? 'log-error' : 'log-info';
|
|
436
|
-
|
|
437
|
-
entry.innerHTML = `
|
|
438
|
-
<span class="timestamp">[${timestamp}]</span>
|
|
439
|
-
<span class="${typeClass}">${message}</span>
|
|
440
|
-
`;
|
|
441
|
-
|
|
442
|
-
this.logContainer.appendChild(entry);
|
|
443
|
-
this.logContainer.scrollTop = this.logContainer.scrollHeight;
|
|
444
|
-
|
|
445
|
-
console.log(`[TestHarness] ${message}`);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Make testUI available globally for button onclick handlers
|
|
450
|
-
declare global {
|
|
451
|
-
interface Window {
|
|
452
|
-
testUI: TestHarnessUI;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Initialize the test harness UI
|
|
457
|
-
const testUI = new TestHarnessUI();
|
|
458
|
-
window.testUI = testUI;
|