diff --git a/src/executor.js b/src/executor.js index d50b74a..15ec27d 100644 --- a/src/executor.js +++ b/src/executor.js @@ -46,11 +46,26 @@ class TestExecutor { for (let i = 0; i < commands.length; i++) { const command = commands[i]; + // Check for pause before executing command (only for interactive commands) + if (!this.headless && this.isInteractiveCommand(command)) { + const wasStepRequested = await this.checkPauseState(); + + // If this was a step request, set pause state after this command + if (wasStepRequested) { + this.shouldPauseAfterStep = true; + } + } + // Update status before executing command if (!this.headless) { await this.updateStatus(command, false); } + // Check for manual dump requests + if (!this.headless) { + await this.checkDumpRequests(); + } + const jumpCount = await this.executeCommand(command); // Handle jump commands @@ -62,6 +77,15 @@ class TestExecutor { // Update status after completing command if (!this.headless) { await this.updateStatus(command, true); + + // If this was a step request, pause again after this interactive command + if (this.shouldPauseAfterStep && this.isInteractiveCommand(command)) { + this.shouldPauseAfterStep = false; + await this.statusPage.evaluate(() => { + window.playwrongPaused = true; + }); + console.log('⏸️ Paused after executing one interactive step'); + } } } @@ -86,6 +110,7 @@ class TestExecutor { headless: this.headless, args: this.headless ? [] : [ `--window-size=${profile.viewport.width},${profile.viewport.height + 100}`, // Add space for browser chrome + '--window-position=0,0', // Position main window at top-left '--disable-web-security', '--disable-features=VizDisplayCompositor', '--disable-infobars', @@ -725,12 +750,28 @@ class TestExecutor { async createStatusWindow() { try { - // Create a separate browser context for the status window (opens in new window) - this.statusContext = await this.browser.newContext({ - viewport: { width: 700, height: 500 } + // Calculate position for status window (to the right of main window) + const mainWindowWidth = this.currentProfile.viewport.width; + const statusWindowX = mainWindowWidth + 50; // 50px gap between windows + + // Launch a separate browser instance for the status window + this.statusBrowser = await chromium.launch({ + headless: false, + args: [ + '--window-size=700,680', + `--window-position=${statusWindowX},0`, // Position to the right + '--disable-web-security', + '--disable-features=VizDisplayCompositor', + '--disable-infobars', + '--disable-extensions' + ] + }); + + // Create a context and page for the status window + this.statusContext = await this.statusBrowser.newContext({ + viewport: { width: 700, height: 680 } }); - // Create a page in the new context (this will be in a separate window) this.statusPage = await this.statusContext.newPage(); // Create the status window HTML @@ -827,12 +868,80 @@ class TestExecutor { .status-running { background: #4CAF50; animation: pulse 2s infinite; } .status-waiting { background: #FF9800; } .status-error { background: #F44336; } + .status-paused { background: #FF5722; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } } + + .controls-section { + display: flex; + gap: 10px; + margin-top: 15px; + } + + .control-button { + flex: 1; + padding: 12px; + border: none; + border-radius: 8px; + font-size: 14px; + font-weight: bold; + cursor: pointer; + transition: all 0.3s ease; + background: rgba(255,255,255,0.2); + color: white; + backdrop-filter: blur(5px); + } + + .control-button:hover { + background: rgba(255,255,255,0.3); + transform: translateY(-2px); + } + + .control-button:active { + transform: translateY(0); + } + + .control-button.pause-btn { + background: rgba(255, 87, 34, 0.8); + } + + .control-button.pause-btn:hover { + background: rgba(255, 87, 34, 1); + } + + .control-button.resume-btn { + background: rgba(76, 175, 80, 0.8); + } + + .control-button.resume-btn:hover { + background: rgba(76, 175, 80, 1); + } + + .control-button.dump-btn { + background: rgba(33, 150, 243, 0.8); + } + + .control-button.dump-btn:hover { + background: rgba(33, 150, 243, 1); + } + + .control-button.step-btn { + background: rgba(156, 39, 176, 0.8); + } + + .control-button.step-btn:hover { + background: rgba(156, 39, 176, 1); + } + + .control-button:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; + }
@@ -869,7 +978,91 @@ class TestExecutor { + +