256 lines
6.8 KiB
JavaScript
256 lines
6.8 KiB
JavaScript
import { chromium, firefox, webkit } from 'playwright';
|
|
import fs from 'fs/promises';
|
|
import path from 'path';
|
|
|
|
/**
|
|
* PLC Streamer Browser Automation and Testing Suite
|
|
* This class provides MCP-like functionality for browser automation
|
|
*/
|
|
class PLCStreamerBrowserAutomation {
|
|
constructor() {
|
|
this.browser = null;
|
|
this.context = null;
|
|
this.page = null;
|
|
this.baseURL = 'http://localhost:5173';
|
|
this.backendURL = 'http://localhost:5000';
|
|
}
|
|
|
|
/**
|
|
* Initialize browser instance
|
|
* @param {string} browserType - 'chromium', 'firefox', or 'webkit'
|
|
* @param {object} options - Browser launch options
|
|
*/
|
|
async initBrowser(browserType = 'chromium', options = {}) {
|
|
const browserLaunchers = {
|
|
chromium: chromium,
|
|
firefox: firefox,
|
|
webkit: webkit
|
|
};
|
|
|
|
const defaultOptions = {
|
|
headless: false,
|
|
slowMo: 100,
|
|
args: ['--disable-web-security', '--disable-features=VizDisplayCompositor']
|
|
};
|
|
|
|
this.browser = await browserLaunchers[browserType].launch({
|
|
...defaultOptions,
|
|
...options
|
|
});
|
|
|
|
this.context = await this.browser.newContext({
|
|
viewport: { width: 1920, height: 1080 },
|
|
recordVideo: { dir: 'videos/' }
|
|
});
|
|
|
|
this.page = await this.context.newPage();
|
|
|
|
// Add console logging
|
|
this.page.on('console', msg => {
|
|
console.log(`Browser Console [${msg.type()}]: ${msg.text()}`);
|
|
});
|
|
|
|
// Add error logging
|
|
this.page.on('pageerror', error => {
|
|
console.error(`Browser Error: ${error.message}`);
|
|
});
|
|
|
|
return this.page;
|
|
}
|
|
|
|
/**
|
|
* Navigate to the PLC Streamer application
|
|
*/
|
|
async navigateToApp() {
|
|
await this.page.goto(`${this.baseURL}/app`);
|
|
await this.page.waitForLoadState('networkidle');
|
|
return this.page;
|
|
}
|
|
|
|
/**
|
|
* Check if backend server is running
|
|
*/
|
|
async checkBackendStatus() {
|
|
try {
|
|
const response = await this.page.request.get(`${this.backendURL}/api/status`);
|
|
return response.ok();
|
|
} catch (error) {
|
|
console.error('Backend not reachable:', error.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Monitor PLC connection status
|
|
*/
|
|
async monitorPLCConnection() {
|
|
await this.navigateToApp();
|
|
|
|
const connectionStatus = await this.page.locator('[data-testid="connection-status"]').textContent();
|
|
console.log(`PLC Connection Status: ${connectionStatus}`);
|
|
|
|
return connectionStatus;
|
|
}
|
|
|
|
/**
|
|
* Automated configuration testing
|
|
*/
|
|
async testConfigurationFlow() {
|
|
await this.navigateToApp();
|
|
|
|
// Navigate to configuration
|
|
await this.page.click('text=Configuration');
|
|
await this.page.waitForSelector('[data-testid="configuration-panel"]');
|
|
|
|
// Test PLC configuration
|
|
const ipInput = this.page.locator('input[name*="ip"]').first();
|
|
await ipInput.clear();
|
|
await ipInput.fill('192.168.1.100');
|
|
|
|
// Save configuration
|
|
await this.page.click('button:has-text("Save")');
|
|
|
|
// Wait for save confirmation
|
|
await this.page.waitForSelector('text*=saved', { timeout: 5000 });
|
|
|
|
console.log('Configuration test completed successfully');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Automated streaming test
|
|
*/
|
|
async testStreamingFlow() {
|
|
await this.navigateToApp();
|
|
|
|
// Navigate to streaming
|
|
await this.page.click('text=Data Streaming');
|
|
await this.page.waitForSelector('[data-testid="streaming-panel"]');
|
|
|
|
// Start streaming
|
|
await this.page.click('button:has-text("Start Streaming")');
|
|
|
|
// Wait a bit for streaming to initialize
|
|
await this.page.waitForTimeout(3000);
|
|
|
|
// Stop streaming
|
|
await this.page.click('button:has-text("Stop Streaming")');
|
|
|
|
console.log('Streaming test completed successfully');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Take screenshots for documentation
|
|
*/
|
|
async captureScreenshots() {
|
|
await this.navigateToApp();
|
|
|
|
const tabs = ['Dashboard', 'Configuration', 'Data Streaming', 'Plots'];
|
|
|
|
for (const tab of tabs) {
|
|
await this.page.click(`text=${tab}`);
|
|
await this.page.waitForTimeout(1000);
|
|
|
|
const screenshot = await this.page.screenshot({
|
|
path: `screenshots/${tab.toLowerCase().replace(' ', '_')}.png`,
|
|
fullPage: true
|
|
});
|
|
|
|
console.log(`Screenshot saved: ${tab}`);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Performance monitoring
|
|
*/
|
|
async monitorPerformance() {
|
|
await this.navigateToApp();
|
|
|
|
// Start performance monitoring
|
|
await this.page.evaluate(() => performance.mark('test-start'));
|
|
|
|
// Navigate through all tabs
|
|
const tabs = ['Configuration', 'Data Streaming', 'Plots', 'Dashboard'];
|
|
|
|
for (const tab of tabs) {
|
|
const startTime = performance.now();
|
|
await this.page.click(`text=${tab}`);
|
|
await this.page.waitForLoadState('networkidle');
|
|
const endTime = performance.now();
|
|
|
|
console.log(`Tab ${tab} load time: ${endTime - startTime}ms`);
|
|
}
|
|
|
|
// Get performance metrics
|
|
const metrics = await this.page.evaluate(() => {
|
|
return JSON.stringify(performance.getEntriesByType('navigation'));
|
|
});
|
|
|
|
await fs.writeFile('performance-metrics.json', metrics);
|
|
console.log('Performance metrics saved');
|
|
|
|
return JSON.parse(metrics);
|
|
}
|
|
|
|
/**
|
|
* Generate test report
|
|
*/
|
|
async generateReport() {
|
|
const backendStatus = await this.checkBackendStatus();
|
|
const plcStatus = await this.monitorPLCConnection();
|
|
|
|
const report = {
|
|
timestamp: new Date().toISOString(),
|
|
backendStatus: backendStatus ? 'Online' : 'Offline',
|
|
plcConnectionStatus: plcStatus,
|
|
browserInfo: await this.page.evaluate(() => navigator.userAgent),
|
|
url: this.page.url()
|
|
};
|
|
|
|
await fs.writeFile('automation-report.json', JSON.stringify(report, null, 2));
|
|
console.log('Report generated: automation-report.json');
|
|
|
|
return report;
|
|
}
|
|
|
|
/**
|
|
* Cleanup resources
|
|
*/
|
|
async cleanup() {
|
|
if (this.page) await this.page.close();
|
|
if (this.context) await this.context.close();
|
|
if (this.browser) await this.browser.close();
|
|
}
|
|
}
|
|
|
|
// Export for use in other scripts
|
|
export default PLCStreamerBrowserAutomation;
|
|
|
|
// CLI usage example
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
const automation = new PLCStreamerBrowserAutomation();
|
|
|
|
try {
|
|
await automation.initBrowser('chromium', { headless: false });
|
|
|
|
console.log('Starting automated testing...');
|
|
|
|
// Run all tests
|
|
await automation.testConfigurationFlow();
|
|
await automation.testStreamingFlow();
|
|
await automation.captureScreenshots();
|
|
await automation.monitorPerformance();
|
|
await automation.generateReport();
|
|
|
|
console.log('Automation completed successfully!');
|
|
|
|
} catch (error) {
|
|
console.error('Automation failed:', error);
|
|
} finally {
|
|
await automation.cleanup();
|
|
}
|
|
}
|