Skip to content

Commit 6862078

Browse files
authored
fix(workbench): reactivate Positron console tab before concluding no console (#521)
1 parent 030ddfd commit 6862078

1 file changed

Lines changed: 22 additions & 6 deletions

File tree

src/vip_tests/workbench/exec.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ def rstudio_eval(page: Page, expr: str, timeout: int = 30_000) -> str:
277277
# selecting immediately can miss R and fall back to the (less reliable) Python
278278
# console. Bounded so a genuinely R-less deployment settles quickly.
279279
_POSITRON_R_GRACE_POLLS = 10
280+
# Polls to let .positron-console re-render after activating the Console tab. A
281+
# console hidden behind the Terminal is removed from the DOM on some Positron
282+
# builds, so we activate + briefly poll before concluding no console exists.
283+
_POSITRON_REACTIVATE_POLLS = 3
280284

281285

282286
def ensure_positron_console(page: Page, timeout: int = 45_000) -> bool:
@@ -302,8 +306,24 @@ def ensure_positron_console(page: Page, timeout: int = 45_000) -> bool:
302306
Returns:
303307
``True`` if a console is running, ``False`` otherwise.
304308
"""
305-
if page.locator(PositronSession.CONSOLE_PANEL).count() > 0:
306-
return True
309+
# One poll budget is shared across every phase below so the total wait is
310+
# bounded by *timeout* rather than a multiple of it.
311+
remaining = max(1, timeout // _POSITRON_POLL_MS)
312+
313+
# A console started earlier may be hidden behind the Terminal tab (a prior
314+
# terminal_run selects it), which removes .positron-console from the DOM on
315+
# some Positron builds. Activate the Console tab first and give the panel a
316+
# moment to re-render, so an existing console is detected instead of being
317+
# missed -- once a session exists its "Start New Console Session" button is
318+
# gone, so a missed console would otherwise look like "no console" and fail.
319+
_activate_positron_console(page)
320+
reactivate = min(remaining, _POSITRON_REACTIVATE_POLLS)
321+
while reactivate > 0:
322+
if page.locator(PositronSession.CONSOLE_PANEL).count() > 0:
323+
return True
324+
page.wait_for_timeout(_POSITRON_POLL_MS)
325+
reactivate -= 1
326+
remaining -= 1
307327

308328
start = page.locator(_POSITRON_START_BUTTON)
309329
if start.count() == 0:
@@ -313,10 +333,6 @@ def ensure_positron_console(page: Page, timeout: int = 45_000) -> bool:
313333
except Exception:
314334
return False
315335

316-
# A single poll budget is shared across both phases below so the total wait
317-
# is bounded by *timeout* rather than ~2x it.
318-
remaining = max(1, timeout // _POSITRON_POLL_MS)
319-
320336
# Phase 1: poll the interpreter quickpick — discovery lags the click on a
321337
# cold session (~10s live).
322338
while page.locator(_POSITRON_QUICKPICK_ROW).count() == 0 and remaining > 0:

0 commit comments

Comments
 (0)