1414from urllib .error import URLError
1515from urllib .request import Request , urlopen
1616
17- from playwright .sync_api import Page , sync_playwright
17+ from playwright .sync_api import (
18+ Page ,
19+ TimeoutError as PlaywrightTimeoutError ,
20+ sync_playwright ,
21+ )
1822
1923
2024PHONE_USER_AGENT = (
@@ -127,7 +131,7 @@ def read_diagnostics(page: Page) -> dict[str, Any]:
127131
128132def mobile_header_snapshot (page : Page ) -> dict [str , Any ]:
129133 return page .evaluate (
130- """() => {
134+ r """() => {
131135 const header = document.querySelector(".app-header");
132136 const context = document.querySelector(".header-context");
133137 const toggle = document.querySelector(".mobile-header-toggle");
@@ -180,22 +184,45 @@ def resize_frames(payloads: list[str | bytes]) -> list[dict[str, Any]]:
180184 return messages
181185
182186
183- def exercise_terminal_wheel_scroll (page : Page ) -> dict [str , float ]:
187+ def visible_history_position (page : Page ) -> int :
188+ position = page .evaluate (
189+ r"""() => {
190+ const rows = Array.from(
191+ document.querySelectorAll(
192+ ".terminal-view .xterm-rows > div",
193+ ),
194+ row => row.textContent ?? "",
195+ );
196+ for (const row of rows) {
197+ const match = /fixture history (\d+)/.exec(row);
198+ if (match !== null) {
199+ return Number(match[1]);
200+ }
201+ }
202+ return null;
203+ }"""
204+ )
205+ if not isinstance (position , int ):
206+ raise AssertionError ("terminal has no visible fixture history row" )
207+ return position
208+
209+
210+ def exercise_terminal_wheel_scroll (page : Page ) -> dict [str , int ]:
184211 scrollable = page .locator (
185212 ".terminal-view .xterm-scrollable-element"
186213 )
187214 scrollable .wait_for (state = "attached" )
188215 page .wait_for_function (
189- """() => {
190- const element = document.querySelector(
191- ".terminal-view .xterm-scrollable-element",
216+ r"""() => {
217+ const rows = document.querySelectorAll(
218+ ".terminal-view .xterm-rows > div",
219+ );
220+ return Array.from(rows).some(
221+ row => /fixture history \d+/.test(row.textContent ?? ""),
192222 );
193- return element !== null &&
194- element.scrollHeight > element.clientHeight &&
195- element.scrollTop > 0;
196223 }"""
197224 )
198- before = scrollable . evaluate ( "element => element.scrollTop" )
225+ before = visible_history_position ( page )
199226 bounds = scrollable .bounding_box ()
200227 if bounds is None :
201228 raise AssertionError ("terminal scroll viewport has no bounds" )
@@ -205,22 +232,56 @@ def exercise_terminal_wheel_scroll(page: Page) -> dict[str, float]:
205232 bounds ["y" ] + bounds ["height" ] / 2 ,
206233 )
207234 page .mouse .wheel (0 , - 1_600 )
208- page .wait_for_function (
209- """before => document.querySelector(
210- ".terminal-view .xterm-scrollable-element",
211- )?.scrollTop < before""" ,
212- arg = before ,
213- )
214- after_up = scrollable .evaluate ("element => element.scrollTop" )
235+ try :
236+ page .wait_for_function (
237+ r"""before => {
238+ for (const row of document.querySelectorAll(
239+ ".terminal-view .xterm-rows > div",
240+ )) {
241+ const match = /fixture history (\d+)/.exec(
242+ row.textContent ?? "",
243+ );
244+ if (match !== null) {
245+ return Number(match[1]) < before;
246+ }
247+ }
248+ return false;
249+ }""" ,
250+ arg = before ,
251+ )
252+ except PlaywrightTimeoutError as error :
253+ current = visible_history_position (page )
254+ raise AssertionError (
255+ "Chrome wheel-up did not move terminal history: "
256+ f"before={ before } , current={ current } "
257+ ) from error
258+ after_up = visible_history_position (page )
215259
216260 page .mouse .wheel (0 , 1_600 )
217- page .wait_for_function (
218- """afterUp => document.querySelector(
219- ".terminal-view .xterm-scrollable-element",
220- )?.scrollTop > afterUp""" ,
221- arg = after_up ,
222- )
223- after_down = scrollable .evaluate ("element => element.scrollTop" )
261+ try :
262+ page .wait_for_function (
263+ r"""afterUp => {
264+ for (const row of document.querySelectorAll(
265+ ".terminal-view .xterm-rows > div",
266+ )) {
267+ const match = /fixture history (\d+)/.exec(
268+ row.textContent ?? "",
269+ );
270+ if (match !== null) {
271+ return Number(match[1]) > afterUp;
272+ }
273+ }
274+ return false;
275+ }""" ,
276+ arg = after_up ,
277+ )
278+ except PlaywrightTimeoutError as error :
279+ current = visible_history_position (page )
280+ raise AssertionError (
281+ "Chrome wheel-down did not move terminal history: "
282+ f"afterUp={ after_up } , current={ current } "
283+ ) from error
284+ after_down = visible_history_position (page )
224285 return {
225286 "before" : before ,
226287 "afterUp" : after_up ,
0 commit comments