apiVersion: v1 kind: ConfigMap metadata: name: playwright-scripts namespace: rdev labels: app.kubernetes.io/name: playwright app.kubernetes.io/part-of: rdev data: capture.js: | #!/usr/bin/env node // capture.js - Playwright screenshot/video capture script // Input: --url, --viewports (comma-separated), --output (dir), // --wait-for (selector), --full-page, --video // Output: JSON manifest to stdout const { chromium } = require('playwright'); const path = require('path'); const fs = require('fs'); async function main() { const args = parseArgs(process.argv.slice(2)); if (!args.url) { console.error('Error: --url is required'); process.exit(1); } const outputDir = args.output || '/captures/default'; const viewports = args.viewports ? args.viewports.split(',') : ['1920x1080', '768x1024', '375x667']; const waitFor = args['wait-for'] || 'body'; const fullPage = args['full-page'] === 'true'; const recordVideo = args.video === 'true'; // Ensure output directory exists fs.mkdirSync(outputDir, { recursive: true }); const browser = await chromium.launch({ headless: true }); const result = { screenshots: {} }; try { for (const viewport of viewports) { const [width, height] = viewport.split('x').map(Number); const viewportName = `${width}x${height}`; const contextOptions = { viewport: { width, height }, }; if (recordVideo && viewport === viewports[0]) { contextOptions.recordVideo = { dir: outputDir, size: { width, height } }; } const context = await browser.newContext(contextOptions); const page = await context.newPage(); await page.goto(args.url, { waitUntil: 'networkidle', timeout: 30000 }); await page.waitForSelector(waitFor, { timeout: 10000 }).catch(() => {}); const screenshotPath = path.join(outputDir, `${viewportName.replace('x', '_')}.png`); await page.screenshot({ path: screenshotPath, fullPage }); result.screenshots[viewportName] = screenshotPath; if (recordVideo && viewport === viewports[0]) { await page.close(); const video = page.video(); if (video) { const videoPath = await video.path(); const finalVideoPath = path.join(outputDir, 'recording.webm'); fs.renameSync(videoPath, finalVideoPath); result.video = finalVideoPath; } } await context.close(); } } finally { await browser.close(); } console.log(JSON.stringify(result)); } function parseArgs(argv) { const args = {}; for (let i = 0; i < argv.length; i++) { if (argv[i].startsWith('--')) { const key = argv[i].slice(2); const eqIdx = key.indexOf('='); if (eqIdx !== -1) { args[key.slice(0, eqIdx)] = key.slice(eqIdx + 1); } else if (argv[i + 1] && !argv[i + 1].startsWith('--')) { args[key] = argv[++i]; } else { args[key] = 'true'; } } } return args; } main().catch(err => { console.error('Error:', err.message); process.exit(1); });