diff --git a/package.json b/package.json index e5e6e48..2afcdfa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lambdatest/smartui-cli", - "version": "4.1.77", + "version": "4.1.78", "description": "A command line interface (CLI) to run SmartUI tests on LambdaTest", "files": [ "dist/**/*" diff --git a/src/lib/constants.ts b/src/lib/constants.ts index ab1f058..7ec0f44 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -165,6 +165,9 @@ export default { // Default page load time DEFAULT_PAGE_LOAD_TIMEOUT: 180000, + // Cap on page/context teardown; a crashed target never returns from close(). + BROWSER_CLOSE_TIMEOUT: 15000, + // Magic Numbers MAGIC_NUMBERS: [ { ext: 'jpg', magic: Buffer.from([0xFF, 0xD8, 0xFF]) }, diff --git a/src/lib/screenshot.ts b/src/lib/screenshot.ts index 102da46..906d446 100644 --- a/src/lib/screenshot.ts +++ b/src/lib/screenshot.ts @@ -371,8 +371,18 @@ async function captureScreenshotsForConfig( } catch (error) { throw new Error(`captureScreenshotsForConfig failed for browser ${browserName}; error: ${error}`); } finally { - await page?.close(); - await context?.close(); + // A crashed target never resolves close(), which would strand this capture and block + // finalizeBuild. Abandoning it is safe: closeBrowsers() kills the browser process after. + const closed = await Promise.race([ + (async () => { await page?.close(); await context?.close(); return true; })().catch(() => true), + new Promise(resolve => { + const timer = setTimeout(() => resolve(false), constants.BROWSER_CLOSE_TIMEOUT); + (timer as any).unref?.(); + }) + ]); + if (!closed) { + ctx.log.warn(`${browserName}: page/context close timed out after ${constants.BROWSER_CLOSE_TIMEOUT}ms; abandoning it`); + } } }