Skip to content
Closed
137 changes: 137 additions & 0 deletions tests/e2e_ui/sessions/test_inline_panel_resize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
"""Touch resizing for the inline Workspace panel."""

from __future__ import annotations

from playwright.sync_api import Page, expect

from tests.e2e_ui.conftest import open_right_rail, seed_committed_turn

_VIEWPORT = {"width": 1280, "height": 700}
_GUTTER = "[data-workspace-panel-resize-gutter]"
_STORAGE_KEY = "omnigent:session-workspace-state"


def _touch_drag(page: Page, *, start: tuple[float, float], end: tuple[float, float]) -> None:
"""Drive trusted touch input so Chromium exercises pointer capture."""
client = page.context.new_cdp_session(page)
try:
client.send(
"Input.dispatchTouchEvent",
{"type": "touchStart", "touchPoints": [{"x": start[0], "y": start[1]}]},
)
client.send(
"Input.dispatchTouchEvent",
{"type": "touchMove", "touchPoints": [{"x": end[0], "y": end[1]}]},
)
client.send("Input.dispatchTouchEvent", {"type": "touchEnd", "touchPoints": []})
finally:
client.detach()


def _panel_width(page: Page) -> float:
box = page.get_by_role("complementary", name="Workspace").bounding_box()
assert box is not None
return box["width"]


def _stored_width(page: Page, session_id: str) -> float | None:
return page.evaluate(
"""([key, id]) => {
const entries = JSON.parse(localStorage.getItem(key) || "[]");
return entries.find((entry) => entry.id === id)?.state?.widthPx ?? null;
}""",
[_STORAGE_KEY, session_id],
)


def test_touch_resize_persists_without_stealing_transcript_scroll(
page: Page,
seeded_session: tuple[str, str],
) -> None:
base_url, session_id = seeded_session
for index in range(6):
seed_committed_turn(
session_id,
prompt=f"Question {index}?",
reply=f"Paragraph {index}. " + ("filler sentence for height. " * 12),
response_id=f"resp_resize_{index}",
)

page.set_viewport_size(_VIEWPORT)
page.goto(f"{base_url}/c/{session_id}")
open_right_rail(page)

gutter = page.locator(_GUTTER)
expect(gutter).to_be_visible()
gutter_box = gutter.bounding_box()
assert gutter_box is not None
initial_width = _panel_width(page)

_touch_drag(
page,
start=(gutter_box["x"] + gutter_box["width"] / 2, gutter_box["y"] + 200),
end=(gutter_box["x"] + 120, gutter_box["y"] + 200),
)

resized_width = _panel_width(page)
assert resized_width <= initial_width - 100
page.wait_for_function(
"""([key, id, width]) => {
const entries = JSON.parse(localStorage.getItem(key) || "[]");
const stored = entries.find((entry) => entry.id === id)?.state?.widthPx;
return Math.abs(stored - width) <= 1;
}""",
arg=[_STORAGE_KEY, session_id, resized_width],
)

page.reload()
open_right_rail(page)
expect(page.get_by_role("log")).to_be_visible(timeout=30_000)
page.wait_for_function(
"""(width) => {
const panel = document.querySelector('[aria-label="Workspace"]');
return Math.abs(panel.getBoundingClientRect().width - width) <= 1;
}""",
arg=resized_width,
)

transcript_box = page.get_by_role("log").bounding_box()
assert transcript_box is not None
# The 8px hit test catches a widened gutter without dragging the scrollbar
# thumb; the 16px gesture separately proves transcript scrolling stays owned.
hit = page.evaluate(
"""([x, y]) => {
const target = document.elementFromPoint(x, y);
return {
isGutter: target?.closest('[data-workspace-panel-resize-gutter]') !== null,
touchAction: target ? getComputedStyle(target).touchAction : null,
};
}""",
arg=[transcript_box["x"] + transcript_box["width"] - 8, transcript_box["y"] + 400],
)
assert hit["isGutter"] is False
assert hit["touchAction"] != "none"

scroll_top = page.evaluate(
"""() => {
const log = document.querySelector('[role="log"]');
const scroller = [...log.querySelectorAll('*')].find(
(element) => element.scrollHeight > element.clientHeight + 4,
);
if (!scroller) return null;
scroller.dataset.inlineResizeScroller = "true";
scroller.scrollTop = 0;
return scroller.scrollTop;
}"""
)
assert scroll_top == 0
width_before_scroll = _panel_width(page)
_touch_drag(
page,
start=(transcript_box["x"] + transcript_box["width"] - 16, transcript_box["y"] + 400),
end=(transcript_box["x"] + transcript_box["width"] - 16, transcript_box["y"] + 280),
)

page.wait_for_function("document.querySelector('[data-inline-resize-scroller]').scrollTop > 0")
assert _panel_width(page) == width_before_scroll
assert _stored_width(page, session_id) == resized_width
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading