1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
class WebAppTester {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.browser = null;
this.testResults = [];
}
async init() {
this.browser = await puppeteer.launch({
headless: false, // Show browser for debugging
devtools: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
}
async runUserFlow(userFlow) {
const page = await this.browser.newPage();
const startTime = Date.now();
try {
// Set up page monitoring
await this.setupPageMonitoring(page);
// Execute user flow steps
for (const step of userFlow.steps) {
await this.executeStep(page, step);
}
const endTime = Date.now();
const duration = endTime - startTime;
this.testResults.push({
flowName: userFlow.name,
success: true,
duration,
timestamp: new Date().toISOString()
});
return { success: true, duration };
} catch (error) {
this.testResults.push({
flowName: userFlow.name,
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
return { success: false, error: error.message };
} finally {
await page.close();
}
}
async executeStep(page, step) {
switch (step.action) {
case 'navigate':
await page.goto(`${this.baseUrl}${step.url}`, { waitUntil: 'networkidle2' });
break;
case 'click':
await page.waitForSelector(step.selector);
await page.click(step.selector);
break;
case 'type':
await page.waitForSelector(step.selector);
await page.type(step.selector, step.value);
break;
case 'wait':
await page.waitForTimeout(step.duration);
break;
case 'assert':
const element = await page.$(step.selector);
if (!element) {
throw new Error(`Element not found: ${step.selector}`);
}
break;
case 'screenshot':
await page.screenshot({ path: `screenshots/${step.name}.png` });
break;
}
}
async setupPageMonitoring(page) {
// Monitor console errors
page.on('console', msg => {
if (msg.type() === 'error') {
console.error('Browser console error:', msg.text());
}
});
// Monitor network requests
page.on('request', request => {
console.log('Request:', request.url());
});
page.on('response', response => {
if (!response.ok()) {
console.error('Failed request:', response.url(), response.status());
}
});
}
async generateTestReport() {
const report = {
totalTests: this.testResults.length,
passedTests: this.testResults.filter(r => r.success).length,
failedTests: this.testResults.filter(r => !r.success).length,
averageDuration: this.testResults.reduce((sum, r) => sum + (r.duration || 0), 0) / this.testResults.length,
results: this.testResults
};
return report;
}
}
// Usage
const tester = new WebAppTester('https://myapp.com');
await tester.init();
const userFlow = {
name: 'User Registration Flow',
steps: [
{ action: 'navigate', url: '/register' },
{ action: 'type', selector: 'input[name="email"]', value: 'test@example.com' },
{ action: 'type', selector: 'input[name="password"]', value: 'password123' },
{ action: 'click', selector: 'button[type="submit"]' },
{ action: 'wait', duration: 2000 },
{ action: 'assert', selector: '.success-message' },
{ action: 'screenshot', name: 'registration-success' }
]
};
const result = await tester.runUserFlow(userFlow);
console.log('Test result:', result);
|