mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 00:49:41 +02:00
fix: Ralph wizard uses file-based prompt to avoid screen escaping issues
- Add /api/sessions/:id/ralph-prompt/write endpoint to write prompt to @ralph_prompt.md - Wizard now writes full prompt to file, then sends simple read command to Claude - Fix session readiness check to wait for prompt character instead of notWorking flag - Add E2E test infrastructure for ralph-loop workflow (port 3190) - Add ralph-wizard-prod.mjs script for production testing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Browser fixture for E2E tests
|
||||
* Manages Playwright browser lifecycle with required args for headless Chrome
|
||||
*/
|
||||
|
||||
import { chromium, Browser, BrowserContext, Page } from 'playwright';
|
||||
|
||||
export interface BrowserFixture {
|
||||
browser: Browser;
|
||||
context: BrowserContext;
|
||||
page: Page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and launch a browser fixture
|
||||
* Uses required args for headless Chrome in CI/Linux environments
|
||||
* @returns BrowserFixture with browser, context, and page
|
||||
*/
|
||||
export async function createBrowserFixture(): Promise<BrowserFixture> {
|
||||
const browser = await chromium.launch({
|
||||
headless: true,
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-gpu',
|
||||
'--disable-software-rasterizer',
|
||||
],
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1280, height: 720 },
|
||||
ignoreHTTPSErrors: true,
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
// Set default timeout for all operations
|
||||
page.setDefaultTimeout(15000);
|
||||
|
||||
return {
|
||||
browser,
|
||||
context,
|
||||
page,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Close and cleanup a browser fixture
|
||||
* @param fixture - Browser fixture to destroy
|
||||
*/
|
||||
export async function destroyBrowserFixture(fixture: BrowserFixture): Promise<void> {
|
||||
if (fixture.page) {
|
||||
await fixture.page.close().catch(() => {});
|
||||
}
|
||||
if (fixture.context) {
|
||||
await fixture.context.close().catch(() => {});
|
||||
}
|
||||
if (fixture.browser) {
|
||||
await fixture.browser.close().catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a URL and wait for load
|
||||
* Note: Uses 'domcontentloaded' because SSE streams prevent 'networkidle'
|
||||
* @param page - Playwright page
|
||||
* @param url - URL to navigate to
|
||||
*/
|
||||
export async function navigateTo(page: Page, url: string): Promise<void> {
|
||||
await page.goto(url, { waitUntil: 'domcontentloaded' });
|
||||
// Wait a bit for JS to initialize
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for an element to be visible
|
||||
* @param page - Playwright page
|
||||
* @param selector - CSS selector
|
||||
* @param timeout - Timeout in ms (default 15000)
|
||||
*/
|
||||
export async function waitForVisible(page: Page, selector: string, timeout = 15000): Promise<void> {
|
||||
await page.waitForSelector(selector, { state: 'visible', timeout });
|
||||
}
|
||||
|
||||
/**
|
||||
* Click an element with retry logic
|
||||
* @param page - Playwright page
|
||||
* @param selector - CSS selector
|
||||
*/
|
||||
export async function clickElement(page: Page, selector: string): Promise<void> {
|
||||
await page.click(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type text into an input element
|
||||
* @param page - Playwright page
|
||||
* @param selector - CSS selector
|
||||
* @param text - Text to type
|
||||
*/
|
||||
export async function typeInto(page: Page, selector: string, text: string): Promise<void> {
|
||||
await page.fill(selector, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get text content of an element
|
||||
* @param page - Playwright page
|
||||
* @param selector - CSS selector
|
||||
* @returns Text content or empty string
|
||||
*/
|
||||
export async function getText(page: Page, selector: string): Promise<string> {
|
||||
try {
|
||||
const element = await page.$(selector);
|
||||
if (element) {
|
||||
return (await element.textContent()) || '';
|
||||
}
|
||||
return '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an element is visible
|
||||
* @param page - Playwright page
|
||||
* @param selector - CSS selector
|
||||
* @returns true if visible, false otherwise
|
||||
*/
|
||||
export async function isVisible(page: Page, selector: string): Promise<boolean> {
|
||||
try {
|
||||
const element = await page.$(selector);
|
||||
if (element) {
|
||||
return await element.isVisible();
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of elements matching selector
|
||||
* @param page - Playwright page
|
||||
* @param selector - CSS selector
|
||||
* @returns Number of matching elements
|
||||
*/
|
||||
export async function getElementCount(page: Page, selector: string): Promise<number> {
|
||||
return await page.locator(selector).count();
|
||||
}
|
||||
Reference in New Issue
Block a user