Error:
E playwright._impl._errors.TimeoutError: Page.click: Timeout 30000ms exceeded.
E Call log:
E - waiting for locator("#overlay-wip")
Trace:
messy_repo = '/tmp/tmpaptlthfv', page =
@pytest.mark.ui
def test_interactivity_toggling(messy_repo, page):
"""Test that clicking legend items updates the Cytoscape visuals using Playwright."""
config = GitLogConfig(engine=Engine.HTML)
graph = process_repo(messy_repo, config)
with tempfile.TemporaryDirectory() as tmp_out:
html_path = os.path.join(tmp_out, "interactive.html")
export_graph(graph, html_path, config, engine=Engine.HTML)
# Load the file in the browser
page.goto(f"file://{os.path.abspath(html_path)}")
# Wait for Cytoscape to initialize (checking window.cyGraph)
page.wait_for_function("typeof window.cyGraph !== 'undefined'")
# Helper to get node colors
def get_node_colors():
return page.evaluate("window.cyGraph.nodes().map(n => n.style('background-color'))")
# 1. Verify initial state (all blue #007bff -> rgb(0, 123, 255))
initial_colors = get_node_colors()
# Remove spaces for robust comparison
def normalize_rgb(c):
return c.replace(" ", "")
assert all("rgb(0,123,255)" in normalize_rgb(c) for c in initial_colors)
# 2. Toggle 'Authors' mode
# Clicking the label or radio button
page.click("#mode-authors")
# Verify colors changed
page.wait_for_timeout(200) # Small wait for style application
author_colors = get_node_colors()
assert any("rgb(0,123,255)" not in normalize_rgb(c) for c in author_colors)
# 3. Toggle 'WIP' overlay
# First verify it's OFF by default (border-width should be 0)
def get_wip_border_widths():
return page.evaluate(
"window.cyGraph.nodes().filter(n => (n.data('tags') || []).includes('wip')).map(n => n.style('border-width'))"
)
# Debug: list all checkbox IDs
checkbox_ids = page.evaluate("Array.from(document.querySelectorAll('input[type=checkbox]')).map(el => el.id)")
print(f"DEBUG: Checkbox IDs found: {checkbox_ids}")
assert all(w == "0px" for w in get_wip_border_widths())
# Toggle it ON
> page.click("#overlay-wip")
tests/test_ui_interactive.py:90:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.13/site-packages/playwright/sync_api/_generated.py:9962: in click
self._sync(
.venv/lib/python3.13/site-packages/playwright/_impl/_page.py:854: in click
return await self._main_frame._click(**locals_to_params(locals()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.13/site-packages/playwright/_impl/_frame.py:566: in _click
await self._channel.send("click", self._timeout, locals_to_params(locals()))
.venv/lib/python3.13/site-packages/playwright/_impl/_connection.py:69: in send
return await self._connection.wrap_api_call(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , cb = . at 0x7bbe4e34e480>, is_internal = False
title = None
async def wrap_api_call(
self, cb: Callable[[], Any], is_internal: bool = False, title: str = None
) -> Any:
if self._api_zone.get():
return await cb()
task = asyncio.current_task(self._loop)
st: List[inspect.FrameInfo] = getattr(
task, "__pw_stack__", None
) or inspect.stack(0)
parsed_st = _extract_stack_trace_information_from_stack(st, is_internal, title)
self._api_zone.set(parsed_st)
try:
return await cb()
except Exception as error:
> raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None