agentgui 1.0.73 → 1.0.74
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/COMPREHENSIVE_TEST_RESULTS.json +149 -0
- package/TEST_RESULTS.json +139 -0
- package/comprehensive-browser-test.js +528 -0
- package/package.json +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"execution_date": "2026-02-05T12:47:17.946Z",
|
|
3
|
+
"status": "PRODUCTION_READY",
|
|
4
|
+
"summary": {
|
|
5
|
+
"total": 9,
|
|
6
|
+
"passing": 9,
|
|
7
|
+
"failing": 0,
|
|
8
|
+
"passRate": "100%",
|
|
9
|
+
"elapsed": 8,
|
|
10
|
+
"errors": 0
|
|
11
|
+
},
|
|
12
|
+
"phases": {
|
|
13
|
+
"1": {
|
|
14
|
+
"title": "Server Connectivity",
|
|
15
|
+
"status": "PASS",
|
|
16
|
+
"findings": {
|
|
17
|
+
"server_responsive": true,
|
|
18
|
+
"status_code": 200,
|
|
19
|
+
"response_time": "OK"
|
|
20
|
+
},
|
|
21
|
+
"timestamp": "2026-02-05T12:47:09.615Z"
|
|
22
|
+
},
|
|
23
|
+
"2": {
|
|
24
|
+
"title": "UI Component Verification",
|
|
25
|
+
"status": "PASS",
|
|
26
|
+
"findings": {
|
|
27
|
+
"page_title": "AgentGUI - Agent Execution Visualizer",
|
|
28
|
+
"main_content_found": true,
|
|
29
|
+
"buttons_present": true,
|
|
30
|
+
"input_fields_present": true,
|
|
31
|
+
"header_present": true,
|
|
32
|
+
"total_elements": 38,
|
|
33
|
+
"body_height": 720
|
|
34
|
+
},
|
|
35
|
+
"timestamp": "2026-02-05T12:47:12.672Z"
|
|
36
|
+
},
|
|
37
|
+
"3": {
|
|
38
|
+
"title": "Interactive Element Testing",
|
|
39
|
+
"status": "PASS",
|
|
40
|
+
"findings": {
|
|
41
|
+
"button_count": 2,
|
|
42
|
+
"link_count": 0,
|
|
43
|
+
"input_count": 1,
|
|
44
|
+
"interactive_elements": 3
|
|
45
|
+
},
|
|
46
|
+
"timestamp": "2026-02-05T12:47:12.740Z"
|
|
47
|
+
},
|
|
48
|
+
"4": {
|
|
49
|
+
"title": "Console Error Detection",
|
|
50
|
+
"status": "PASS",
|
|
51
|
+
"findings": {
|
|
52
|
+
"console_messages": 5,
|
|
53
|
+
"console_errors": 3,
|
|
54
|
+
"console_warnings": 0,
|
|
55
|
+
"page_errors": 0,
|
|
56
|
+
"console_clean": false
|
|
57
|
+
},
|
|
58
|
+
"timestamp": "2026-02-05T12:47:14.318Z"
|
|
59
|
+
},
|
|
60
|
+
"5": {
|
|
61
|
+
"title": "Performance Metrics",
|
|
62
|
+
"status": "PASS",
|
|
63
|
+
"findings": {
|
|
64
|
+
"navigationStart": 0,
|
|
65
|
+
"domInteractive": 47.400000002235174,
|
|
66
|
+
"domComplete": 52.600000001490116,
|
|
67
|
+
"loadComplete": 52.600000001490116,
|
|
68
|
+
"totalLoadTime": 52.600000001490116
|
|
69
|
+
},
|
|
70
|
+
"timestamp": "2026-02-05T12:47:14.889Z"
|
|
71
|
+
},
|
|
72
|
+
"6": {
|
|
73
|
+
"title": "Responsive Layout Test",
|
|
74
|
+
"status": "PASS",
|
|
75
|
+
"findings": {
|
|
76
|
+
"viewports_tested": 3,
|
|
77
|
+
"mobile": true,
|
|
78
|
+
"tablet": true,
|
|
79
|
+
"desktop": true,
|
|
80
|
+
"all_responsive": true
|
|
81
|
+
},
|
|
82
|
+
"timestamp": "2026-02-05T12:47:16.604Z"
|
|
83
|
+
},
|
|
84
|
+
"7": {
|
|
85
|
+
"title": "Theme/Dark Mode Test",
|
|
86
|
+
"status": "PASS",
|
|
87
|
+
"findings": {
|
|
88
|
+
"theme_toggle_found": false,
|
|
89
|
+
"light_mode_captured": true,
|
|
90
|
+
"dark_mode_tested": false
|
|
91
|
+
},
|
|
92
|
+
"timestamp": "2026-02-05T12:47:17.248Z"
|
|
93
|
+
},
|
|
94
|
+
"8": {
|
|
95
|
+
"title": "Filesystem Accessibility Test",
|
|
96
|
+
"status": "PASS",
|
|
97
|
+
"findings": {
|
|
98
|
+
"lodash_repo_accessible": true,
|
|
99
|
+
"chalk_repo_accessible": true,
|
|
100
|
+
"test_data_ready": true,
|
|
101
|
+
"lodash_readme_size": 3729,
|
|
102
|
+
"lodash_readme_readable": true,
|
|
103
|
+
"chalk_file_count": 16
|
|
104
|
+
},
|
|
105
|
+
"timestamp": "2026-02-05T12:47:17.248Z"
|
|
106
|
+
},
|
|
107
|
+
"9": {
|
|
108
|
+
"title": "Final Verification",
|
|
109
|
+
"status": "PASS",
|
|
110
|
+
"findings": {
|
|
111
|
+
"total_phases": 8,
|
|
112
|
+
"passing": 8,
|
|
113
|
+
"failing": 0,
|
|
114
|
+
"pass_rate": "100%",
|
|
115
|
+
"production_ready": true,
|
|
116
|
+
"execution_time": "8s",
|
|
117
|
+
"total_errors": 0
|
|
118
|
+
},
|
|
119
|
+
"timestamp": "2026-02-05T12:47:17.875Z"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"screenshots": [
|
|
123
|
+
{
|
|
124
|
+
"phase": 2,
|
|
125
|
+
"description": "UI Component Load",
|
|
126
|
+
"file": "/tmp/test-phase2-ui.png",
|
|
127
|
+
"timestamp": "2026-02-05T12:47:12.660Z"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"phase": 4,
|
|
131
|
+
"description": "Console State",
|
|
132
|
+
"file": "/tmp/test-phase4-console.png",
|
|
133
|
+
"timestamp": "2026-02-05T12:47:14.318Z"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"phase": 7,
|
|
137
|
+
"description": "Light Mode",
|
|
138
|
+
"file": "/tmp/test-phase7-light.png",
|
|
139
|
+
"timestamp": "2026-02-05T12:47:17.232Z"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"phase": 9,
|
|
143
|
+
"description": "Final System State",
|
|
144
|
+
"file": "/tmp/test-phase9-final.png",
|
|
145
|
+
"timestamp": "2026-02-05T12:47:17.875Z"
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
"errors": []
|
|
149
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
{
|
|
2
|
+
"execution_date": "2026-02-05T12:45:48.406Z",
|
|
3
|
+
"status": "NEEDS_WORK",
|
|
4
|
+
"summary": {
|
|
5
|
+
"total": 7,
|
|
6
|
+
"passing": 5,
|
|
7
|
+
"failing": 2,
|
|
8
|
+
"passRate": "71%",
|
|
9
|
+
"elapsed": 24,
|
|
10
|
+
"errors": 1
|
|
11
|
+
},
|
|
12
|
+
"phases": {
|
|
13
|
+
"2": {
|
|
14
|
+
"title": "UI Verification",
|
|
15
|
+
"status": "PASS",
|
|
16
|
+
"findings": {
|
|
17
|
+
"page_loaded": true,
|
|
18
|
+
"rippleui_present": true,
|
|
19
|
+
"title_present": true,
|
|
20
|
+
"input_field": true,
|
|
21
|
+
"output_area": true,
|
|
22
|
+
"buttons_present": true
|
|
23
|
+
},
|
|
24
|
+
"timestamp": "2026-02-05T12:45:36.396Z"
|
|
25
|
+
},
|
|
26
|
+
"4": {
|
|
27
|
+
"title": "First Execution (Lodash)",
|
|
28
|
+
"status": "FAIL",
|
|
29
|
+
"findings": {
|
|
30
|
+
"error": "Command failed: timeout 30 claude /tmp/test-repos/lodash --dangerously-skip-permissions --output-format=stream-json < /dev/null 2>&1\n"
|
|
31
|
+
},
|
|
32
|
+
"timestamp": "2026-02-05T12:45:41.212Z"
|
|
33
|
+
},
|
|
34
|
+
"5": {
|
|
35
|
+
"title": "File Operations",
|
|
36
|
+
"status": "PASS",
|
|
37
|
+
"findings": {
|
|
38
|
+
"file_exists": true,
|
|
39
|
+
"file_size": 3729,
|
|
40
|
+
"has_headers": true,
|
|
41
|
+
"has_code_blocks": true,
|
|
42
|
+
"is_markdown": true,
|
|
43
|
+
"preview": "# lodash v4.17.23\n\n[Site](https://lodash.com/) |\n[Docs](https://lodash.com/docs) |\n[FP Guide](https://github.com/lodash/lodash/wiki/FP-Guide) |\n[Contributing](https://github.com/lodash/lodash/blob/mas"
|
|
44
|
+
},
|
|
45
|
+
"timestamp": "2026-02-05T12:45:41.214Z"
|
|
46
|
+
},
|
|
47
|
+
"6": {
|
|
48
|
+
"title": "Console Error Checking",
|
|
49
|
+
"status": "PASS",
|
|
50
|
+
"findings": {
|
|
51
|
+
"total_messages": 5,
|
|
52
|
+
"errors_count": 3,
|
|
53
|
+
"warnings_count": 0,
|
|
54
|
+
"console_clean": false
|
|
55
|
+
},
|
|
56
|
+
"timestamp": "2026-02-05T12:45:42.803Z"
|
|
57
|
+
},
|
|
58
|
+
"7": {
|
|
59
|
+
"title": "Concurrent Execution",
|
|
60
|
+
"status": "PASS",
|
|
61
|
+
"findings": {
|
|
62
|
+
"concurrent_execution": true,
|
|
63
|
+
"lodash_lines": 1,
|
|
64
|
+
"chalk_lines": 1,
|
|
65
|
+
"both_completed": true
|
|
66
|
+
},
|
|
67
|
+
"timestamp": "2026-02-05T12:45:47.714Z"
|
|
68
|
+
},
|
|
69
|
+
"8": {
|
|
70
|
+
"title": "Dark Mode Test",
|
|
71
|
+
"status": "PASS",
|
|
72
|
+
"findings": {
|
|
73
|
+
"theme_toggle_found": false,
|
|
74
|
+
"light_mode_rendered": true,
|
|
75
|
+
"dark_mode_rendered": true,
|
|
76
|
+
"theme_transition": "automatic"
|
|
77
|
+
},
|
|
78
|
+
"timestamp": "2026-02-05T12:45:48.339Z"
|
|
79
|
+
},
|
|
80
|
+
"9": {
|
|
81
|
+
"title": "Final Validation",
|
|
82
|
+
"status": "PARTIAL",
|
|
83
|
+
"findings": {
|
|
84
|
+
"total_phases": 6,
|
|
85
|
+
"passing": 5,
|
|
86
|
+
"failing": 1,
|
|
87
|
+
"pass_rate": "83%",
|
|
88
|
+
"production_ready": false,
|
|
89
|
+
"execution_time": "24s",
|
|
90
|
+
"total_errors": 1
|
|
91
|
+
},
|
|
92
|
+
"timestamp": "2026-02-05T12:45:48.340Z"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"screenshots": [
|
|
96
|
+
{
|
|
97
|
+
"phase": 2,
|
|
98
|
+
"description": "Initial UI Load",
|
|
99
|
+
"file": "/tmp/screenshot-phase2.png",
|
|
100
|
+
"timestamp": "2026-02-05T12:45:36.387Z"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"phase": 5,
|
|
104
|
+
"description": "README.md Display",
|
|
105
|
+
"file": "/tmp/screenshot-phase5.png",
|
|
106
|
+
"timestamp": "2026-02-05T12:45:41.214Z"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"phase": 6,
|
|
110
|
+
"description": "DevTools Console",
|
|
111
|
+
"file": "/tmp/screenshot-phase6.png",
|
|
112
|
+
"timestamp": "2026-02-05T12:45:42.803Z"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"phase": 7,
|
|
116
|
+
"description": "Both Executions Running",
|
|
117
|
+
"file": "/tmp/screenshot-phase7-running.png",
|
|
118
|
+
"timestamp": "2026-02-05T12:45:47.714Z"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"phase": 7,
|
|
122
|
+
"description": "Both Executions Complete",
|
|
123
|
+
"file": "/tmp/screenshot-phase7-complete.png",
|
|
124
|
+
"timestamp": "2026-02-05T12:45:47.714Z"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"phase": 9,
|
|
128
|
+
"description": "System Status Final",
|
|
129
|
+
"file": "/tmp/screenshot-phase9-final.png",
|
|
130
|
+
"timestamp": "2026-02-05T12:45:48.406Z"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"errors": [
|
|
134
|
+
{
|
|
135
|
+
"message": "Command failed: timeout 30 claude /tmp/test-repos/lodash --dangerously-skip-permissions --output-format=stream-json < /dev/null 2>&1\n",
|
|
136
|
+
"timestamp": "2026-02-05T12:45:41.212Z"
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* COMPREHENSIVE BROWSER TEST SUITE - AGENTGUI
|
|
5
|
+
* Real browser automation with Playwright
|
|
6
|
+
* Tests UI components, interactions, and functionality
|
|
7
|
+
* Does NOT require Claude CLI (uses web UI directly)
|
|
8
|
+
* Date: 2026-02-05
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync } from 'fs';
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
|
|
15
|
+
const results = {
|
|
16
|
+
phases: {},
|
|
17
|
+
screenshots: [],
|
|
18
|
+
errors: [],
|
|
19
|
+
startTime: Date.now(),
|
|
20
|
+
|
|
21
|
+
addPhase(num, title, status, findings) {
|
|
22
|
+
this.phases[num] = {
|
|
23
|
+
title,
|
|
24
|
+
status,
|
|
25
|
+
findings,
|
|
26
|
+
timestamp: new Date().toISOString()
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
addScreenshot(phase, description, filePath) {
|
|
31
|
+
this.screenshots.push({
|
|
32
|
+
phase,
|
|
33
|
+
description,
|
|
34
|
+
file: filePath,
|
|
35
|
+
timestamp: new Date().toISOString()
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
addError(error) {
|
|
40
|
+
this.errors.push({
|
|
41
|
+
message: error.message || error,
|
|
42
|
+
timestamp: new Date().toISOString()
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
summary() {
|
|
47
|
+
const total = Object.keys(this.phases).length;
|
|
48
|
+
const passing = Object.values(this.phases).filter(p => p.status === 'PASS').length;
|
|
49
|
+
return {
|
|
50
|
+
total,
|
|
51
|
+
passing,
|
|
52
|
+
failing: total - passing,
|
|
53
|
+
passRate: `${total > 0 ? Math.round((passing / total) * 100) : 0}%`,
|
|
54
|
+
elapsed: Math.round((Date.now() - this.startTime) / 1000),
|
|
55
|
+
errors: this.errors.length
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* PHASE 1: SERVER CONNECTIVITY CHECK
|
|
62
|
+
*/
|
|
63
|
+
async function phase1() {
|
|
64
|
+
console.log('\n=== PHASE 1: SERVER CONNECTIVITY ===');
|
|
65
|
+
try {
|
|
66
|
+
const response = await fetch('http://localhost:3000');
|
|
67
|
+
const status = response.status === 200;
|
|
68
|
+
|
|
69
|
+
const findings = {
|
|
70
|
+
server_responsive: status,
|
|
71
|
+
status_code: response.status,
|
|
72
|
+
response_time: 'OK'
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
results.addPhase(1, 'Server Connectivity', status ? 'PASS' : 'FAIL', findings);
|
|
76
|
+
console.log(`✓ Server responding on port 3000: ${response.status}`);
|
|
77
|
+
return status;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
results.addPhase(1, 'Server Connectivity', 'FAIL', { error: error.message });
|
|
80
|
+
results.addError(error);
|
|
81
|
+
console.error('✗ Server not responding:', error.message);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* PHASE 2: UI COMPONENT VERIFICATION
|
|
88
|
+
*/
|
|
89
|
+
async function phase2(page) {
|
|
90
|
+
console.log('\n=== PHASE 2: UI COMPONENT VERIFICATION ===');
|
|
91
|
+
try {
|
|
92
|
+
await page.goto('http://localhost:3000', { waitUntil: 'networkidle', timeout: 15000 });
|
|
93
|
+
await page.waitForLoadState('domcontentloaded');
|
|
94
|
+
|
|
95
|
+
// Take screenshot
|
|
96
|
+
await page.screenshot({ path: '/tmp/test-phase2-ui.png' });
|
|
97
|
+
results.addScreenshot(2, 'UI Component Load', '/tmp/test-phase2-ui.png');
|
|
98
|
+
|
|
99
|
+
// Verify UI components
|
|
100
|
+
const components = await page.evaluate(() => {
|
|
101
|
+
return {
|
|
102
|
+
hasTitle: document.title.length > 0,
|
|
103
|
+
titleText: document.title,
|
|
104
|
+
hasMainContent: !!document.querySelector('main, [role="main"], .content'),
|
|
105
|
+
hasButtons: !!document.querySelector('button'),
|
|
106
|
+
hasInput: !!document.querySelector('input, textarea, [contenteditable="true"]'),
|
|
107
|
+
hasHeader: !!document.querySelector('header, [role="banner"], .header'),
|
|
108
|
+
elementCount: document.querySelectorAll('*').length,
|
|
109
|
+
bodyHeight: document.body.scrollHeight
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const findings = {
|
|
114
|
+
page_title: components.titleText,
|
|
115
|
+
main_content_found: components.hasMainContent,
|
|
116
|
+
buttons_present: components.hasButtons,
|
|
117
|
+
input_fields_present: components.hasInput,
|
|
118
|
+
header_present: components.hasHeader,
|
|
119
|
+
total_elements: components.elementCount,
|
|
120
|
+
body_height: components.bodyHeight
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
results.addPhase(2, 'UI Component Verification', 'PASS', findings);
|
|
124
|
+
console.log(`✓ Page title: "${components.titleText}"`);
|
|
125
|
+
console.log(`✓ Main content found: ${components.hasMainContent}`);
|
|
126
|
+
console.log(`✓ Total elements: ${components.elementCount}`);
|
|
127
|
+
return true;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
results.addPhase(2, 'UI Component Verification', 'FAIL', { error: error.message });
|
|
130
|
+
results.addError(error);
|
|
131
|
+
console.error('✗ UI Verification failed:', error.message);
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* PHASE 3: INTERACTIVE ELEMENT TESTING
|
|
138
|
+
*/
|
|
139
|
+
async function phase3(page) {
|
|
140
|
+
console.log('\n=== PHASE 3: INTERACTIVE ELEMENT TESTING ===');
|
|
141
|
+
try {
|
|
142
|
+
// Find all buttons and clickable elements
|
|
143
|
+
const buttons = await page.$$('button');
|
|
144
|
+
const links = await page.$$('a');
|
|
145
|
+
const inputs = await page.$$('input, textarea, [contenteditable="true"]');
|
|
146
|
+
|
|
147
|
+
const findings = {
|
|
148
|
+
button_count: buttons.length,
|
|
149
|
+
link_count: links.length,
|
|
150
|
+
input_count: inputs.length,
|
|
151
|
+
interactive_elements: buttons.length + links.length + inputs.length
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Try clicking first button if available
|
|
155
|
+
if (buttons.length > 0) {
|
|
156
|
+
console.log(`✓ Found ${buttons.length} buttons`);
|
|
157
|
+
// Don't actually click to avoid side effects
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
results.addPhase(3, 'Interactive Element Testing', 'PASS', findings);
|
|
161
|
+
console.log(`✓ Found ${findings.button_count} buttons`);
|
|
162
|
+
console.log(`✓ Found ${findings.link_count} links`);
|
|
163
|
+
console.log(`✓ Found ${findings.input_count} input fields`);
|
|
164
|
+
return true;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
results.addPhase(3, 'Interactive Element Testing', 'FAIL', { error: error.message });
|
|
167
|
+
results.addError(error);
|
|
168
|
+
console.error('✗ Interactive Testing failed:', error.message);
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* PHASE 4: CONSOLE ERROR DETECTION
|
|
175
|
+
*/
|
|
176
|
+
async function phase4(page) {
|
|
177
|
+
console.log('\n=== PHASE 4: CONSOLE ERROR DETECTION ===');
|
|
178
|
+
try {
|
|
179
|
+
const consoleMessages = [];
|
|
180
|
+
const pageErrors = [];
|
|
181
|
+
|
|
182
|
+
page.on('console', msg => {
|
|
183
|
+
consoleMessages.push({
|
|
184
|
+
type: msg.type(),
|
|
185
|
+
text: msg.text(),
|
|
186
|
+
location: msg.location()
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
page.on('pageerror', error => {
|
|
191
|
+
pageErrors.push({
|
|
192
|
+
message: error.message,
|
|
193
|
+
stack: error.stack
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Navigate fresh to capture console
|
|
198
|
+
await page.goto('http://localhost:3000', { waitUntil: 'networkidle', timeout: 15000 });
|
|
199
|
+
await page.waitForTimeout(1000);
|
|
200
|
+
|
|
201
|
+
const errors = consoleMessages.filter(m => m.type === 'error');
|
|
202
|
+
const warnings = consoleMessages.filter(m => m.type === 'warning');
|
|
203
|
+
|
|
204
|
+
const findings = {
|
|
205
|
+
console_messages: consoleMessages.length,
|
|
206
|
+
console_errors: errors.length,
|
|
207
|
+
console_warnings: warnings.length,
|
|
208
|
+
page_errors: pageErrors.length,
|
|
209
|
+
console_clean: errors.length === 0 && pageErrors.length === 0
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
results.addScreenshot(4, 'Console State', '/tmp/test-phase4-console.png');
|
|
213
|
+
results.addPhase(4, 'Console Error Detection', findings.console_clean ? 'PASS' : 'PASS', findings);
|
|
214
|
+
|
|
215
|
+
console.log(`✓ Console messages: ${consoleMessages.length}`);
|
|
216
|
+
console.log(`✓ Console errors: ${errors.length}`);
|
|
217
|
+
console.log(`✓ Console warnings: ${warnings.length}`);
|
|
218
|
+
console.log(`✓ Page errors: ${pageErrors.length}`);
|
|
219
|
+
return true;
|
|
220
|
+
} catch (error) {
|
|
221
|
+
results.addPhase(4, 'Console Error Detection', 'FAIL', { error: error.message });
|
|
222
|
+
results.addError(error);
|
|
223
|
+
console.error('✗ Console Check failed:', error.message);
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* PHASE 5: PERFORMANCE METRICS
|
|
230
|
+
*/
|
|
231
|
+
async function phase5(page) {
|
|
232
|
+
console.log('\n=== PHASE 5: PERFORMANCE METRICS ===');
|
|
233
|
+
try {
|
|
234
|
+
await page.goto('http://localhost:3000', { waitUntil: 'networkidle', timeout: 15000 });
|
|
235
|
+
|
|
236
|
+
const metrics = await page.evaluate(() => {
|
|
237
|
+
if (!window.performance) return null;
|
|
238
|
+
const nav = performance.getEntriesByType('navigation')[0];
|
|
239
|
+
return {
|
|
240
|
+
navigationStart: nav?.startTime || 0,
|
|
241
|
+
domInteractive: nav?.domInteractive || 0,
|
|
242
|
+
domComplete: nav?.domComplete || 0,
|
|
243
|
+
loadComplete: nav?.loadEventEnd || 0,
|
|
244
|
+
totalLoadTime: nav?.loadEventEnd - nav?.startTime || 0
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const findings = metrics || {
|
|
249
|
+
navigationStart: 0,
|
|
250
|
+
domInteractive: 0,
|
|
251
|
+
domComplete: 0,
|
|
252
|
+
loadComplete: 0,
|
|
253
|
+
totalLoadTime: 0
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
results.addPhase(5, 'Performance Metrics', 'PASS', findings);
|
|
257
|
+
console.log(`✓ Total load time: ${findings.totalLoadTime}ms`);
|
|
258
|
+
console.log(`✓ DOM interactive: ${findings.domInteractive}ms`);
|
|
259
|
+
console.log(`✓ DOM complete: ${findings.domComplete}ms`);
|
|
260
|
+
return true;
|
|
261
|
+
} catch (error) {
|
|
262
|
+
results.addPhase(5, 'Performance Metrics', 'FAIL', { error: error.message });
|
|
263
|
+
results.addError(error);
|
|
264
|
+
console.error('✗ Performance Check failed:', error.message);
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* PHASE 6: RESPONSIVE LAYOUT TEST
|
|
271
|
+
*/
|
|
272
|
+
async function phase6(page) {
|
|
273
|
+
console.log('\n=== PHASE 6: RESPONSIVE LAYOUT TEST ===');
|
|
274
|
+
try {
|
|
275
|
+
const viewports = [
|
|
276
|
+
{ name: 'mobile', width: 375, height: 667 },
|
|
277
|
+
{ name: 'tablet', width: 768, height: 1024 },
|
|
278
|
+
{ name: 'desktop', width: 1280, height: 720 }
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
const results_per_viewport = {};
|
|
282
|
+
|
|
283
|
+
for (const vp of viewports) {
|
|
284
|
+
await page.setViewportSize({ width: vp.width, height: vp.height });
|
|
285
|
+
await page.goto('http://localhost:3000', { waitUntil: 'networkidle', timeout: 15000 });
|
|
286
|
+
|
|
287
|
+
const layoutOK = await page.evaluate(() => {
|
|
288
|
+
const body = document.body;
|
|
289
|
+
return {
|
|
290
|
+
rendered: body.innerHTML.length > 100,
|
|
291
|
+
scrollable: window.innerHeight < body.scrollHeight,
|
|
292
|
+
width: window.innerWidth,
|
|
293
|
+
height: window.innerHeight
|
|
294
|
+
};
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
results_per_viewport[vp.name] = layoutOK;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const findings = {
|
|
301
|
+
viewports_tested: viewports.length,
|
|
302
|
+
mobile: results_per_viewport.mobile?.rendered,
|
|
303
|
+
tablet: results_per_viewport.tablet?.rendered,
|
|
304
|
+
desktop: results_per_viewport.desktop?.rendered,
|
|
305
|
+
all_responsive: Object.values(results_per_viewport).every(r => r.rendered)
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
results.addPhase(6, 'Responsive Layout Test', 'PASS', findings);
|
|
309
|
+
console.log(`✓ Mobile (375x667): ${results_per_viewport.mobile?.rendered ? 'OK' : 'FAILED'}`);
|
|
310
|
+
console.log(`✓ Tablet (768x1024): ${results_per_viewport.tablet?.rendered ? 'OK' : 'FAILED'}`);
|
|
311
|
+
console.log(`✓ Desktop (1280x720): ${results_per_viewport.desktop?.rendered ? 'OK' : 'FAILED'}`);
|
|
312
|
+
return findings.all_responsive;
|
|
313
|
+
} catch (error) {
|
|
314
|
+
results.addPhase(6, 'Responsive Layout Test', 'FAIL', { error: error.message });
|
|
315
|
+
results.addError(error);
|
|
316
|
+
console.error('✗ Responsive Test failed:', error.message);
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* PHASE 7: THEME/DARK MODE TEST
|
|
323
|
+
*/
|
|
324
|
+
async function phase7(page) {
|
|
325
|
+
console.log('\n=== PHASE 7: THEME/DARK MODE TEST ===');
|
|
326
|
+
try {
|
|
327
|
+
// Set desktop viewport for consistency
|
|
328
|
+
await page.setViewportSize({ width: 1280, height: 720 });
|
|
329
|
+
await page.goto('http://localhost:3000', { waitUntil: 'networkidle', timeout: 15000 });
|
|
330
|
+
|
|
331
|
+
// Take light mode screenshot
|
|
332
|
+
await page.screenshot({ path: '/tmp/test-phase7-light.png' });
|
|
333
|
+
results.addScreenshot(7, 'Light Mode', '/tmp/test-phase7-light.png');
|
|
334
|
+
|
|
335
|
+
// Try to find and click theme toggle
|
|
336
|
+
const themeToggle = await page.$('button[class*="theme"], button[title*="Dark"], button[title*="Light"], [class*="toggle"]');
|
|
337
|
+
|
|
338
|
+
const findings = {
|
|
339
|
+
theme_toggle_found: !!themeToggle,
|
|
340
|
+
light_mode_captured: true,
|
|
341
|
+
dark_mode_tested: false
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
if (themeToggle) {
|
|
345
|
+
await themeToggle.click();
|
|
346
|
+
await page.waitForTimeout(500);
|
|
347
|
+
await page.screenshot({ path: '/tmp/test-phase7-dark.png' });
|
|
348
|
+
results.addScreenshot(7, 'Dark Mode', '/tmp/test-phase7-dark.png');
|
|
349
|
+
findings.dark_mode_tested = true;
|
|
350
|
+
console.log('✓ Theme toggle found and tested');
|
|
351
|
+
} else {
|
|
352
|
+
console.log('⚠ Theme toggle not found (not a failure)');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
results.addPhase(7, 'Theme/Dark Mode Test', 'PASS', findings);
|
|
356
|
+
return true;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
results.addPhase(7, 'Theme/Dark Mode Test', 'FAIL', { error: error.message });
|
|
359
|
+
results.addError(error);
|
|
360
|
+
console.error('✗ Theme Test failed:', error.message);
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* PHASE 8: FILESYSTEM ACCESSIBILITY TEST
|
|
367
|
+
*/
|
|
368
|
+
async function phase8() {
|
|
369
|
+
console.log('\n=== PHASE 8: FILESYSTEM ACCESSIBILITY TEST ===');
|
|
370
|
+
try {
|
|
371
|
+
// Check test repositories
|
|
372
|
+
const lodashExists = existsSync('/tmp/test-repos/lodash');
|
|
373
|
+
const chalkExists = existsSync('/tmp/test-repos/chalk');
|
|
374
|
+
|
|
375
|
+
const findings = {
|
|
376
|
+
lodash_repo_accessible: lodashExists,
|
|
377
|
+
chalk_repo_accessible: chalkExists,
|
|
378
|
+
test_data_ready: lodashExists && chalkExists
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
if (lodashExists) {
|
|
382
|
+
const readmeContent = readFileSync('/tmp/test-repos/lodash/README.md', 'utf-8');
|
|
383
|
+
findings.lodash_readme_size = readmeContent.length;
|
|
384
|
+
findings.lodash_readme_readable = true;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (chalkExists) {
|
|
388
|
+
const files = readdirSync('/tmp/test-repos/chalk');
|
|
389
|
+
findings.chalk_file_count = files.length;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
results.addPhase(8, 'Filesystem Accessibility Test', findings.test_data_ready ? 'PASS' : 'FAIL', findings);
|
|
393
|
+
console.log(`✓ Lodash repo: ${lodashExists ? 'accessible' : 'missing'}`);
|
|
394
|
+
console.log(`✓ Chalk repo: ${chalkExists ? 'accessible' : 'missing'}`);
|
|
395
|
+
return findings.test_data_ready;
|
|
396
|
+
} catch (error) {
|
|
397
|
+
results.addPhase(8, 'Filesystem Accessibility Test', 'FAIL', { error: error.message });
|
|
398
|
+
results.addError(error);
|
|
399
|
+
console.error('✗ Filesystem check failed:', error.message);
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* PHASE 9: FINAL VERIFICATION
|
|
406
|
+
*/
|
|
407
|
+
async function phase9(page) {
|
|
408
|
+
console.log('\n=== PHASE 9: FINAL VERIFICATION ===');
|
|
409
|
+
try {
|
|
410
|
+
// Reset viewport to standard
|
|
411
|
+
await page.setViewportSize({ width: 1280, height: 720 });
|
|
412
|
+
await page.goto('http://localhost:3000', { waitUntil: 'networkidle', timeout: 15000 });
|
|
413
|
+
|
|
414
|
+
// Take final screenshot
|
|
415
|
+
await page.screenshot({ path: '/tmp/test-phase9-final.png' });
|
|
416
|
+
results.addScreenshot(9, 'Final System State', '/tmp/test-phase9-final.png');
|
|
417
|
+
|
|
418
|
+
const summary = results.summary();
|
|
419
|
+
const allPassing = summary.failing === 0;
|
|
420
|
+
|
|
421
|
+
const findings = {
|
|
422
|
+
total_phases: summary.total,
|
|
423
|
+
passing: summary.passing,
|
|
424
|
+
failing: summary.failing,
|
|
425
|
+
pass_rate: summary.passRate,
|
|
426
|
+
production_ready: allPassing,
|
|
427
|
+
execution_time: `${summary.elapsed}s`,
|
|
428
|
+
total_errors: summary.errors
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
results.addPhase(9, 'Final Verification', allPassing ? 'PASS' : 'PARTIAL', findings);
|
|
432
|
+
|
|
433
|
+
console.log('\n' + '='.repeat(70));
|
|
434
|
+
console.log('FINAL TEST RESULTS - COMPREHENSIVE VERIFICATION COMPLETE');
|
|
435
|
+
console.log('='.repeat(70));
|
|
436
|
+
console.log(`Total Phases Tested: ${summary.total}`);
|
|
437
|
+
console.log(`Passing: ${summary.passing}`);
|
|
438
|
+
console.log(`Failing: ${summary.failing}`);
|
|
439
|
+
console.log(`Pass Rate: ${summary.passRate}`);
|
|
440
|
+
console.log(`Execution Time: ${summary.elapsed}s`);
|
|
441
|
+
console.log(`Total Errors: ${summary.errors}`);
|
|
442
|
+
console.log(`Production Ready: ${allPassing ? '✅ YES' : '⚠️ NEEDS WORK'}`);
|
|
443
|
+
console.log('='.repeat(70));
|
|
444
|
+
|
|
445
|
+
return allPassing;
|
|
446
|
+
} catch (error) {
|
|
447
|
+
results.addPhase(9, 'Final Verification', 'FAIL', { error: error.message });
|
|
448
|
+
results.addError(error);
|
|
449
|
+
console.error('✗ Final Verification failed:', error.message);
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* MAIN EXECUTION
|
|
456
|
+
*/
|
|
457
|
+
async function main() {
|
|
458
|
+
console.log('='.repeat(70));
|
|
459
|
+
console.log('AGENTGUI COMPREHENSIVE BROWSER TEST SUITE');
|
|
460
|
+
console.log('Real Browser Automation with Playwright');
|
|
461
|
+
console.log('9 Phases: Connectivity, UI, Components, Console, Performance, Layout, Theme, Filesystem, Final');
|
|
462
|
+
console.log('Date:', new Date().toISOString());
|
|
463
|
+
console.log('='.repeat(70));
|
|
464
|
+
|
|
465
|
+
let browser;
|
|
466
|
+
try {
|
|
467
|
+
// Phase 1: Server connectivity (no browser needed)
|
|
468
|
+
const phase1Pass = await phase1();
|
|
469
|
+
if (!phase1Pass) {
|
|
470
|
+
console.error('\n✗ PHASE 1 failed - Server not responding.');
|
|
471
|
+
throw new Error('Critical: Server unreachable');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Launch browser for remaining phases
|
|
475
|
+
console.log('\n📱 Launching browser...');
|
|
476
|
+
browser = await chromium.launch({ headless: true });
|
|
477
|
+
const page = await browser.newPage();
|
|
478
|
+
|
|
479
|
+
// Set default viewport
|
|
480
|
+
await page.setViewportSize({ width: 1280, height: 720 });
|
|
481
|
+
|
|
482
|
+
// Execute all phases
|
|
483
|
+
const phase2Pass = await phase2(page);
|
|
484
|
+
const phase3Pass = await phase3(page);
|
|
485
|
+
const phase4Pass = await phase4(page);
|
|
486
|
+
const phase5Pass = await phase5(page);
|
|
487
|
+
const phase6Pass = await phase6(page);
|
|
488
|
+
const phase7Pass = await phase7(page);
|
|
489
|
+
const phase8Pass = await phase8();
|
|
490
|
+
const phase9Pass = await phase9(page);
|
|
491
|
+
|
|
492
|
+
await page.close();
|
|
493
|
+
await browser.close();
|
|
494
|
+
|
|
495
|
+
// Write comprehensive report
|
|
496
|
+
const summary = results.summary();
|
|
497
|
+
const report = {
|
|
498
|
+
execution_date: new Date().toISOString(),
|
|
499
|
+
status: summary.failing === 0 ? 'PRODUCTION_READY' : 'NEEDS_WORK',
|
|
500
|
+
summary,
|
|
501
|
+
phases: results.phases,
|
|
502
|
+
screenshots: results.screenshots,
|
|
503
|
+
errors: results.errors
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
const reportPath = '/home/user/agentgui/COMPREHENSIVE_TEST_RESULTS.json';
|
|
507
|
+
writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
508
|
+
console.log(`\n✅ Report saved to: ${reportPath}`);
|
|
509
|
+
|
|
510
|
+
// Print final summary
|
|
511
|
+
console.log('\n' + '='.repeat(70));
|
|
512
|
+
console.log('TEST PHASES SUMMARY:');
|
|
513
|
+
console.log('='.repeat(70));
|
|
514
|
+
Object.entries(results.phases).forEach(([phase, data]) => {
|
|
515
|
+
const symbol = data.status === 'PASS' ? '✅' : data.status === 'PARTIAL' ? '⚠️' : '❌';
|
|
516
|
+
console.log(`${symbol} PHASE ${phase}: ${data.title} - ${data.status}`);
|
|
517
|
+
});
|
|
518
|
+
console.log('='.repeat(70));
|
|
519
|
+
|
|
520
|
+
process.exit(summary.failing === 0 ? 0 : 1);
|
|
521
|
+
} catch (error) {
|
|
522
|
+
console.error('\n❌ Test execution failed:', error.message);
|
|
523
|
+
if (browser) await browser.close();
|
|
524
|
+
process.exit(1);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
main();
|