mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
238 lines
7.5 KiB
JavaScript
238 lines
7.5 KiB
JavaScript
const { chromium, devices } = require('@playwright/test');
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
|
|
const PULSE_URL = process.env.PULSE_URL || 'http://localhost:7655';
|
|
const OUTPUT_DIR = path.join(__dirname, '..', 'docs', 'images');
|
|
|
|
async function ensureOutputDir() {
|
|
try {
|
|
await fs.mkdir(OUTPUT_DIR, { recursive: true });
|
|
} catch (error) {
|
|
console.error('Error creating output directory:', error);
|
|
}
|
|
}
|
|
|
|
async function wait(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
async function takeScreenshot(page, name, options = {}) {
|
|
const { selector = null, fullPage = false } = options;
|
|
|
|
await wait(1500); // Wait for animations
|
|
|
|
let screenshotOptions = {
|
|
type: 'png',
|
|
path: path.join(OUTPUT_DIR, `${name}.png`)
|
|
};
|
|
|
|
if (selector) {
|
|
const element = await page.locator(selector).first();
|
|
await element.waitFor({ state: 'visible', timeout: 10000 });
|
|
screenshotOptions = {
|
|
...screenshotOptions,
|
|
clip: await element.boundingBox()
|
|
};
|
|
} else if (fullPage) {
|
|
screenshotOptions.fullPage = true;
|
|
}
|
|
|
|
await page.screenshot(screenshotOptions);
|
|
console.log(`✅ Saved ${name}.png`);
|
|
}
|
|
|
|
async function clickAndWait(page, selector, waitTime = 1000) {
|
|
try {
|
|
const element = page.locator(selector).first();
|
|
if (await element.count() > 0) {
|
|
await element.click();
|
|
await wait(waitTime);
|
|
return true;
|
|
}
|
|
} catch (e) {
|
|
console.log(`Could not click ${selector}: ${e.message}`);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async function ensureDarkTheme(page) {
|
|
try {
|
|
// Wait a bit for theme system to initialize
|
|
await wait(1000);
|
|
|
|
// First check if we're already in dark mode
|
|
const isDarkMode = await page.evaluate(() => {
|
|
return document.documentElement.classList.contains('dark');
|
|
});
|
|
|
|
console.log(`Current theme mode: ${isDarkMode ? 'dark' : 'light'}`);
|
|
|
|
if (!isDarkMode) {
|
|
// Try to find and click the theme toggle
|
|
// Look for common theme toggle selectors
|
|
const themeSelectors = [
|
|
'button[aria-label="Toggle theme"]',
|
|
'button[title*="theme" i]',
|
|
'button[aria-label*="theme" i]',
|
|
'button:has(svg[class*="moon"])',
|
|
'button:has(svg[class*="sun"])',
|
|
'.theme-toggle',
|
|
'button:has-text("Theme")',
|
|
'[data-theme-toggle]'
|
|
];
|
|
|
|
for (const selector of themeSelectors) {
|
|
try {
|
|
const element = page.locator(selector).first();
|
|
if (await element.count() > 0) {
|
|
await element.click();
|
|
await wait(1000); // Wait for theme transition
|
|
|
|
// Verify dark mode is now active
|
|
const nowDark = await page.evaluate(() => {
|
|
return document.documentElement.classList.contains('dark');
|
|
});
|
|
|
|
if (nowDark) {
|
|
console.log('✅ Successfully switched to dark theme');
|
|
return;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// Continue trying other selectors
|
|
}
|
|
}
|
|
|
|
// If no toggle found, try to force dark mode via localStorage or class
|
|
await page.evaluate(() => {
|
|
document.documentElement.classList.remove('light');
|
|
document.documentElement.classList.add('dark');
|
|
localStorage.setItem('theme', 'dark');
|
|
localStorage.setItem('pulse-theme', 'dark');
|
|
});
|
|
console.log('⚠️ Forced dark mode via DOM manipulation');
|
|
} else {
|
|
console.log('✅ Already in dark mode');
|
|
}
|
|
} catch (e) {
|
|
console.log('Could not set dark theme:', e.message);
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
await ensureOutputDir();
|
|
|
|
const browser = await chromium.launch({
|
|
headless: true
|
|
});
|
|
|
|
// Desktop screenshots
|
|
const desktopContext = await browser.newContext({
|
|
viewport: { width: 1440, height: 900 }
|
|
});
|
|
|
|
const page = await desktopContext.newPage();
|
|
|
|
try {
|
|
console.log(`📸 Starting screenshot capture for ${PULSE_URL}`);
|
|
|
|
// Navigate to Pulse
|
|
await page.goto(PULSE_URL, { waitUntil: 'networkidle' });
|
|
await wait(3000);
|
|
|
|
// Ensure dark theme
|
|
await ensureDarkTheme(page);
|
|
|
|
// 1. Dashboard Screenshot
|
|
console.log('📸 Capturing dashboard...');
|
|
await takeScreenshot(page, '01-dashboard');
|
|
|
|
// 2. Storage View
|
|
console.log('📸 Capturing storage view...');
|
|
const storageClicked = await clickAndWait(page, 'button:has-text("Storage"), a:has-text("Storage"), [role="tab"]:has-text("Storage")', 2000);
|
|
if (storageClicked) {
|
|
await takeScreenshot(page, '02-storage');
|
|
}
|
|
|
|
// 3. Backups View
|
|
console.log('📸 Capturing backups view...');
|
|
const backupsClicked = await clickAndWait(page, 'button:has-text("Backups"), a:has-text("Backups"), [role="tab"]:has-text("Backups")', 2000);
|
|
if (backupsClicked) {
|
|
await takeScreenshot(page, '03-backups');
|
|
}
|
|
|
|
// 4. Alerts View
|
|
console.log('📸 Capturing alerts view...');
|
|
const alertsClicked = await clickAndWait(page, 'button:has-text("Alerts"), a:has-text("Alerts"), [role="tab"]:has-text("Alerts")', 2000);
|
|
if (alertsClicked) {
|
|
await takeScreenshot(page, '04-alerts');
|
|
|
|
// 5. Try to capture Alert History if available
|
|
console.log('📸 Looking for alert history...');
|
|
const historyClicked = await clickAndWait(page, 'button:has-text("History"), button:has-text("Alert History"), [role="tab"]:has-text("History")', 2000);
|
|
if (historyClicked) {
|
|
await takeScreenshot(page, '05-alert-history');
|
|
} else {
|
|
// If no history tab, just use alerts view
|
|
await fs.copyFile(
|
|
path.join(OUTPUT_DIR, '04-alerts.png'),
|
|
path.join(OUTPUT_DIR, '05-alert-history.png')
|
|
);
|
|
console.log('✅ Used alerts view for alert history');
|
|
}
|
|
}
|
|
|
|
// 6. Settings View
|
|
console.log('📸 Capturing settings view...');
|
|
const settingsClicked = await clickAndWait(page, 'button:has-text("Settings"), a:has-text("Settings"), [aria-label="Settings"], .settings-icon', 2000);
|
|
if (settingsClicked) {
|
|
await takeScreenshot(page, '06-settings');
|
|
} else {
|
|
// Try clicking a gear icon
|
|
await clickAndWait(page, 'svg[class*="settings"], svg[class*="gear"], button:has(svg[class*="settings"])', 2000);
|
|
await takeScreenshot(page, '06-settings');
|
|
}
|
|
|
|
// 7. Dark Mode Screenshot (go back to dashboard for a clean dark mode shot)
|
|
console.log('📸 Capturing dark mode view...');
|
|
await clickAndWait(page, 'button:has-text("Dashboard"), a:has-text("Dashboard"), [role="tab"]:has-text("Dashboard")', 2000);
|
|
await wait(1000);
|
|
await takeScreenshot(page, '07-dark-mode');
|
|
|
|
// Close desktop context
|
|
await desktopContext.close();
|
|
|
|
// 8. Mobile Screenshot
|
|
console.log('📸 Capturing mobile view...');
|
|
const mobileContext = await browser.newContext({
|
|
...devices['iPhone 12'],
|
|
viewport: { width: 390, height: 844 }
|
|
});
|
|
|
|
const mobilePage = await mobileContext.newPage();
|
|
await mobilePage.goto(PULSE_URL, { waitUntil: 'networkidle' });
|
|
await wait(2000);
|
|
|
|
// Ensure dark theme on mobile
|
|
await ensureDarkTheme(mobilePage);
|
|
|
|
await takeScreenshot(mobilePage, '08-mobile');
|
|
|
|
await mobileContext.close();
|
|
|
|
console.log('✨ Screenshot capture complete!');
|
|
console.log(`📁 Screenshots saved to: ${OUTPUT_DIR}`);
|
|
|
|
} catch (error) {
|
|
console.error('❌ Error during screenshot capture:', error);
|
|
|
|
// Take error screenshot
|
|
await takeScreenshot(page, 'error-state');
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
}
|
|
|
|
// Run the script
|
|
main().catch(console.error); |