UNPKG

debugg-ai-mcp

Version:

MCP Server for debugg ai web browsing

128 lines (127 loc) 4.88 kB
import { downloadBinary, start, stop } from '../tunnels/ngrok/index.js'; async function startTunnel(localPort, domain) { try { await start({ addr: localPort, hostname: domain, onLogEvent: (data) => { console.error(`${localPort} | ${domain} | ngrok log: ${data}`); }, }); return domain; } catch (err) { console.error('Error starting ngrok tunnel:', err); } } export class E2eTestRunner { client; constructor(client) { this.client = client; this.setup(); } async setup() { await this.configureNgrok(); } async configureNgrok() { await downloadBinary(); } async startTunnel(port, url) { await startTunnel(port, url); console.error(`Tunnel started at: ${url}`); return url; } /** * Run E2E test generator for a single file *quietly* in the background. * @param filePath absolute path of the file to test */ async runTests(e2eRun) { // Start by opening an ngrok tunnel. // call the debugg ai endpoint to start running the test // retrieve the results when done // save files locally somewhere const listener = await startTunnel(3011, `${e2eRun.key}.ngrok.debugg.ai`); console.error(`Tunnel started at: ${listener}`); const interval = setInterval(async () => { const newE2eRun = await this.client.e2es?.getE2eRun(e2eRun.id); console.error(`E2E run - ${newE2eRun}`); if (newE2eRun?.status === 'completed') { console.error(`E2E run completed - ${newE2eRun}`); clearInterval(interval); await stop(listener); } }, 1000); // if the run doesn't complete in time, disconnect the tunnel const setTimer = setTimeout(async () => { clearInterval(interval); clearTimeout(setTimer); await stop(listener); }, 300000); return undefined; } /** * Create a new E2E test and run it. * @param testPort - The port to use for the test. * @param testDescription - The description of the test. * @param filePath - The path to the file to test. * @param repoName - The name of the repository. * @param branchName - The name of the branch. * @param repoPath - The path to the repository. */ async createNewE2eTest(testPort, testDescription, repoName, branchName, repoPath, filePath) { console.error(`Creating new E2E test with description: ${testDescription}`); const e2eTest = await this.client.e2es?.createE2eTest(testDescription, filePath ?? "", repoName, branchName, { repoPath: repoPath }); console.error(`E2E test created - ${e2eTest}`); if (!e2eTest) { console.error("Failed to create E2E test."); return null; } if (!e2eTest.curRun) { console.error("Failed to create E2E test run."); return null; } return this.handleE2eRun(testPort, e2eTest.curRun); } async handleE2eRun(port, e2eRun) { console.error(`🔧 Handling E2E run - ${e2eRun.uuid}`); // Start ngrok tunnel await startTunnel(port, `${e2eRun.key}.ngrok.debugg.ai`); console.error(`🌐 Tunnel started at: ${e2eRun.key}.ngrok.debugg.ai`); let stopped = false; let lastStep = 0; let updatedRun = e2eRun; // Poll every second for completion const interval = setInterval(async () => { updatedRun = await this.client.e2es?.getE2eRun(e2eRun.id); if (!updatedRun) return; console.error(`📡 Polled E2E run status: ${updatedRun.status}`); if (updatedRun.status === 'completed') { clearInterval(interval); clearTimeout(timeout); await stop(`https://${e2eRun.key}.ngrok.debugg.ai`); // if (updatedRun.runGif) { // fetchAndOpenGif(this.repoPath ?? "", updatedRun.runGif, updatedRun.test?.name ?? "", updatedRun.uuid); // } stopped = true; } }, 5000); // Timeout safeguard const timeout = setTimeout(async () => { if (stopped) return; clearInterval(interval); await stop(`https://${e2eRun.key}.ngrok.debugg.ai`); console.error(`⏰ E2E test timed out after 15 minutes\n`); stopped = true; }, 900_000); // Wait for the polling to complete or timeout to expire while (!stopped) { await new Promise(resolve => setTimeout(resolve, 1000)); } return updatedRun; } } export default E2eTestRunner;