fix(desktop): require visible tabs for screenshots

This commit is contained in:
LukeParkerDev 2026-09-03 18:54:42 +10:00
parent 1bb804fece
commit 02477c0ad1
4 changed files with 16 additions and 10 deletions

View file

@ -432,6 +432,14 @@ export function createBrowserPage(
}
case "screenshot": {
if (action.ref && action.fullPage) throw new Error("Choose an element ref or fullPage, not both.")
await waitFor(() => view.getVisible() && win.isVisible() && !win.isMinimized(), signal, 3_000).catch(
(error) => {
if (signal.aborted) throw error
throw new Error(
"Screenshot needs a visible tab. Call browser.tabs.focus and keep its desktop window visible.",
)
},
)
const element = action.ref ? await rect(target(action.ref), true) : undefined
const metrics = await cdp.send("Page.getLayoutMetrics")
const bounds = element

View file

@ -26,15 +26,7 @@ export function createCdp(contents: WebContents) {
if (contents.isDestroyed()) throw new Error("Browser tab was closed.")
if (!contents.debugger.isAttached()) contents.debugger.attach("1.3")
// Electron is the CDP boundary. Its native response follows the selected protocol method.
const result = contents.debugger.sendCommand(method, params, sessionID)
if (method !== "Page.captureScreenshot") return result
// Keep a hidden view's compositor awake for CDP (including Lighthouse's
// screenshot gatherer) without changing the selected Review tab.
const [capture] = await Promise.all([
result,
contents.capturePage(undefined, { stayHidden: false, stayAwake: true }),
])
return capture
return contents.debugger.sendCommand(method, params, sessionID)
},
on<Method extends keyof ProtocolMapping.Events>(
method: Method,

View file

@ -89,6 +89,11 @@ async function main() {
}
if (!inventories.get(event.bindingID)?.tabs.some((tab) => tab.id === event.event.tabID))
ipcErrors.push("Focus arrived before its tab inventory")
pane.layout(win, event.bindingID, {
tabID: event.event.tabID,
visible: true,
bounds: { x: 0, y: 0, width: 1000, height: 700 },
})
}),
),
),
@ -197,6 +202,7 @@ async function main() {
)
const found = await call("find", { tabID, text: "Apply" })
assert(found.content.includes("Apply"))
await call("tabs.focus", { tabID })
const screenshot = await call("screenshot", { tabID, fullPage: true, maxWidth: 1000 })
const screenshotBytes = await rpc.read({ path: screenshot.files[0].path }, { location })
assert(

View file

@ -12,7 +12,7 @@ await Effect.gen(function* () {
hostname: "127.0.0.1",
port: 0,
password: process.env.SMOKE_PASSWORD,
app: { name: "browser-suite-test", version: "test", channel: "test" },
app: { name: "browser-suite-test", version: process.env.SMOKE_VERSION ?? "test", channel: "test" },
database: { path: ":memory:" },
models: { fetch: false },
fs: { filewatcher: false, fff: false },