stemedb/applications/pitch/capture-screenshots.ts
jordan 157dbbb9eb feat: Complete Aphoria Phase 8-9 + UAT suite (90/90 tests passing)
## Phase 8: Enterprise Extractor Improvements 
- 14 security extractors (TLS, JWT, SQL injection, XSS, etc.)
- 10 framework-specific extractors (Spring, Django, Rails, etc.)
- Config file security detection (YAML, TOML)

## Phase 9: Autonomous Extractor Generation 
- Shadow mode executor with TP/FP tracking
- Graduation pipeline with confidence thresholds
- Auto-rollback on regression detection
- Cross-project pattern syncing

## UAT Suite Complete (14 scripts, 90 tests)
- test-core-detection.sh (6 tests)
- test-declarative-extractors.sh (5 tests)
- test-domain-frameworks.sh (5 tests)
- test-domain-unreal.sh (3 tests)
- test-llm-extraction.sh (6 tests)
- test-eval-harness.sh (5 tests)
- test-cross-language.sh (3 tests)
- test-precommit-performance.sh (4 tests)
- test-output-formats.sh (8 tests)
- test-drift-detection.sh (6 tests)
- test-exit-codes.sh (12 tests)
+ 3 more scripts

## Other Changes
- Updated roadmap to mark Phase 8-9 complete
- Added .gitignore entries for build artifacts
- Updated pre-commit: 800 line limit, exclude tests/data/cmd

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 22:50:55 -07:00

122 lines
3.2 KiB
TypeScript

import { chromium, Browser, Page } from '@playwright/test';
import * as fs from 'fs/promises';
export interface FormAction {
type: 'fill' | 'click' | 'check';
selector: string;
value?: string;
}
export interface ScreenshotConfig {
url: string;
name: string;
waitFor?: string; // CSS selector to wait for
delay?: number; // ms to wait after page load
actions?: FormAction[]; // Actions to perform before screenshot
}
export interface CaptureOptions {
baseUrl: string;
outputDir: string;
viewport?: { width: number; height: number };
}
const DEFAULT_OPTIONS: CaptureOptions = {
baseUrl: 'http://localhost:18188',
outputDir: 'screenshots',
viewport: { width: 1920, height: 1080 },
};
export async function captureScreenshots(
screenshots: ScreenshotConfig[],
options: Partial<CaptureOptions> = {}
): Promise<string[]> {
const opts = { ...DEFAULT_OPTIONS, ...options };
const browser = await chromium.launch();
const page = await browser.newPage();
await page.setViewportSize(opts.viewport!);
const captured: string[] = [];
for (const config of screenshots) {
const url = config.url.startsWith('http')
? config.url
: `${opts.baseUrl}${config.url}`;
await page.goto(url, { waitUntil: 'networkidle' });
// Execute any form actions before screenshot
if (config.actions) {
for (const action of config.actions) {
if (action.type === 'fill' && action.value) {
await page.fill(action.selector, action.value);
} else if (action.type === 'click') {
await page.click(action.selector);
} else if (action.type === 'check') {
await page.check(action.selector);
}
}
}
if (config.waitFor) {
await page.waitForSelector(config.waitFor, { timeout: 10000 });
}
if (config.delay) {
await page.waitForTimeout(config.delay);
}
const path = `${opts.outputDir}/${config.name}`;
await page.screenshot({ path, type: 'png' });
console.log(`${config.name}`);
captured.push(path);
}
await browser.close();
return captured;
}
export async function captureSingle(
url: string,
name: string,
options: Partial<CaptureOptions> = {}
): Promise<string> {
const [path] = await captureScreenshots([{ url, name }], options);
return path;
}
export { Browser, Page };
// CLI runner
async function main() {
const configPath = process.argv[2];
if (!configPath) {
console.error('Usage: pnpm capture <config.json>');
console.error('');
console.error('Config format:');
console.error(JSON.stringify({
baseUrl: 'http://localhost:18188',
outputDir: 'screenshots',
screenshots: [
{ url: '/page', name: 'screenshot.png' },
{ url: '/other', name: 'other.png', waitFor: '.selector', delay: 500 },
],
}, null, 2));
process.exit(1);
}
const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));
// Ensure output directory exists
await fs.mkdir(config.outputDir || 'screenshots', { recursive: true });
await captureScreenshots(config.screenshots, {
baseUrl: config.baseUrl,
outputDir: config.outputDir,
});
console.log(`\nDone! ${config.screenshots.length} screenshots saved to ${config.outputDir || 'screenshots'}/`);
}
main();