From f9d3a03c688e4f0dac2b6242f61191024c5791dd Mon Sep 17 00:00:00 2001 From: Radislav Date: Fri, 17 Oct 2025 08:45:59 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=B2=20scroll=20=D0=BF=D1=80=D0=BE=D0=BA=D1=80=D1=83=D1=82?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B4=D0=BE=20=D0=BA=D1=80=D0=B0=D0=B5=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/base_component.py | 216 ++++++++++++++++++++++++++++------- 1 file changed, 177 insertions(+), 39 deletions(-) diff --git a/components/base_component.py b/components/base_component.py index f960f3e..12df71d 100644 --- a/components/base_component.py +++ b/components/base_component.py @@ -114,79 +114,217 @@ class BaseComponent: return loc.evaluate("el => el.scrollWidth > el.clientWidth") # Методы прокрутки: - def scroll_up(self, locator: str | Locator) -> None: - """Прокрутка элемента вверх. + def scroll_up(self, locator: str | Locator, timeout: int = 10000) -> None: + """Прокрутка элемента до самого верха. Args: locator: локатор элемента. + timeout: максимальное время ожидания в мс. + + Raises: + AssertionError: если прокрутка не выполнена до верха. + """ + + loc = self.get_locator(locator) + max_attempts = 3 + attempt = 0 + + while attempt < max_attempts: + # Получаем текущую позицию прокрутки + previous_position = loc.evaluate("el => el.scrollTop") + + # Прокручиваем до верха + loc.evaluate("el => el.scrollTo(0, 0)") + + # Ждем завершения прокрутки с использованием timeout + loc.wait_for(timeout=min(2000, timeout)) + + # Получаем новую позицию прокрутки + current_position = loc.evaluate("el => el.scrollTop") + + # Проверяем, достигли ли мы верха + if current_position <= 1: # <= 1 для учета погрешности + return # Успешно прокрутили до верха + + # Проверяем, была ли вообще прокрутка + if current_position >= previous_position: + attempt += 1 + else: + attempt = 0 # Сбрасываем счетчик, если была прокрутка + + # Если вышли из цикла - не смогли прокрутить до верха + final_position = loc.evaluate("el => el.scrollTop") + scroll_height = loc.evaluate("el => el.scrollHeight") + client_height = loc.evaluate("el => el.clientHeight") + + raise AssertionError( + f"Не удалось прокрутить до верха. " + f"Текущая позиция: {final_position}, ожидалось: 0, " + f"Высота контента: {scroll_height}, " + f"Высота видимой области: {client_height}" + ) + + def scroll_down(self, locator: str | Locator, timeout: int = 10000) -> None: + """Прокрутка элемента до самого конца. + + Args: + locator: локатор элемента. + timeout: максимальное время ожидания в мс. Raises: AssertionError: если прокрутка не выполнена до конца. """ loc = self.get_locator(locator) - loc.evaluate("el => el.scrollTo(0, 0)") - loc.wait_for(timeout=2000) + max_attempts = 3 + attempt = 0 - # Проверка позиции прокрутки - scroll_position = loc.evaluate("el => el.scrollTop") - assert scroll_position == 0, "Invalid postion after scroll up" + while attempt < max_attempts: + # Получаем текущую позицию прокрутки и размеры + current_position = loc.evaluate("el => el.scrollTop") + scroll_height = loc.evaluate("el => el.scrollHeight") + client_height = loc.evaluate("el => el.clientHeight") - def scroll_down(self, locator: str | Locator) -> None: - """Прокрутка элемента вниз. + # Проверяем, достигли ли мы конца ДО прокрутки + if current_position + client_height >= scroll_height - 5: # -5 для учета погрешности + return # Уже прокручено до конца + + # Прокручиваем до конца + loc.evaluate("el => el.scrollTo(0, el.scrollHeight)") + + # Ждем загрузки контента + loc.wait_for(timeout=min(2000, timeout)) + + # Получаем новую позицию прокрутки + new_position = loc.evaluate("el => el.scrollTop") + new_scroll_height = loc.evaluate("el => el.scrollHeight") + new_client_height = loc.evaluate("el => el.clientHeight") + + # Проверяем, достигли ли мы конца + if new_position + new_client_height >= new_scroll_height - 5: # -5 для учета погрешности + return # Успешно прокрутили до конца + + # Проверяем, была ли прокрутка + if new_position <= current_position and new_scroll_height <= scroll_height: + # Прокрутки не произошло или контент не изменился + attempt += 1 + else: + attempt = 0 # Сбрасываем счетчик, если была прокрутка + + # Если вышли из цикла - не смогли прокрутить до конца + final_position = loc.evaluate("el => el.scrollTop") + final_scroll_height = loc.evaluate("el => el.scrollHeight") + final_client_height = loc.evaluate("el => el.clientHeight") + max_scroll_y = final_scroll_height - final_client_height + + raise AssertionError( + f"Не удалось прокрутить до конца. " + f"Текущая позиция: {final_position}, ожидалось: {max_scroll_y}, " + f"Высота контента: {final_scroll_height}, " + f"Высота видимой области: {final_client_height}, " + f"Сумма: {final_position + final_client_height}" + ) + + def scroll_left(self, locator: str | Locator, timeout: int = 10000) -> None: + """Прокрутка элемента до самого левого края. Args: locator: локатор элемента. + timeout: максимальное время ожидания в мс. Raises: - AssertionError: если прокрутка не выполнена до конца. + AssertionError: если прокрутка не выполнена до левого края. """ loc = self.get_locator(locator) - loc.evaluate("el => el.scrollTo(0, el.scrollHeight)") - loc.wait_for(timeout=2000) + max_attempts = 3 + attempt = 0 - # Проверка позиции прокрутки - scroll_position = loc.evaluate("el => el.scrollTop") - assert scroll_position > 0, "Invalid postion after scroll down" + while attempt < max_attempts: + # Получаем текущую позицию прокрутки + previous_position = loc.evaluate("el => el.scrollLeft") - def scroll_left(self, locator: str | Locator) -> None: - """Прокрутка элемента влево. + # Прокручиваем до левого края + loc.evaluate("el => el.scrollTo(0, el.scrollTop)") + + # Ждем завершения прокрутки с использованием timeout + loc.wait_for(timeout=min(2000, timeout)) + + # Получаем новую позицию прокрутки + current_position = loc.evaluate("el => el.scrollLeft") + + # Проверяем, достигли ли мы левого края + if current_position <= 1: # <= 1 для учета погрешности + return # Успешно прокрутили до левого края + + # Проверяем, была ли вообще прокрутка + if current_position >= previous_position: + attempt += 1 + else: + attempt = 0 # Сбрасываем счетчик, если была прокрутка + + # Если вышли из цикла - не смогли прокрутить до левого края + final_position = loc.evaluate("el => el.scrollLeft") + scroll_width = loc.evaluate("el => el.scrollWidth") + client_width = loc.evaluate("el => el.clientWidth") + + raise AssertionError( + f"Не удалось прокрутить до левого края. " + f"Текущая позиция: {final_position}, ожидалось: 0, " + f"Ширина контента: {scroll_width}, " + f"Ширина видимой области: {client_width}" + ) + + def scroll_right(self, locator: str | Locator, timeout: int = 10000) -> None: + """Прокрутка элемента до самого правого края. Args: locator: локатор элемента. + timeout: максимальное время ожидания в мс. Raises: - AssertionError: если прокрутка не выполнена до конца. + AssertionError: если прокрутка не выполнена до правого края. """ loc = self.get_locator(locator) + max_attempts = 3 + attempt = 0 - loc.evaluate("el => el.scrollBy(-el.scrollWidth, 0)") + while attempt < max_attempts: + # Получаем текущую позицию прокрутки + previous_position = loc.evaluate("el => el.scrollLeft") - loc.wait_for(timeout=2000) + # Прокручиваем до правого края + loc.evaluate("el => el.scrollTo(el.scrollWidth, el.scrollTop)") - # Проверка позиции прокрутки - scroll_position = loc.evaluate("el => el.scrollLeft") - assert scroll_position == 0, "Invalid postion after scroll left" + # Ждем завершения прокрутки с использованием timeout + loc.wait_for(timeout=min(2000, timeout)) - def scroll_right(self, locator: str | Locator) -> None: - """Прокрутка элемента вправо. + # Получаем новую позицию прокрутки + current_position = loc.evaluate("el => el.scrollLeft") + scroll_width = loc.evaluate("el => el.scrollWidth") + client_width = loc.evaluate("el => el.clientWidth") - Args: - locator: локатор элемента. + # Проверяем, достигли ли мы правого края + max_scroll_x = scroll_width - client_width + if current_position >= max_scroll_x - 1: # -1 для учета погрешности + return # Успешно прокрутили до правого края - Raises: - AssertionError: если прокрутка не выполнена до конца. - """ + # Проверяем, была ли вообще прокрутка + if current_position <= previous_position: + attempt += 1 + else: + attempt = 0 # Сбрасываем счетчик, если была прокрутка - loc = self.get_locator(locator) + # Если вышли из цикла - не смогли прокрутить до правого края + final_position = loc.evaluate("el => el.scrollLeft") + scroll_width = loc.evaluate("el => el.scrollWidth") + client_width = loc.evaluate("el => el.clientWidth") + max_scroll_x = scroll_width - client_width - loc.evaluate("el => el.scrollBy(el.scrollWidth, 0)") - - loc.wait_for(timeout=2000) - - # Проверка позиции прокрутки - scroll_position = loc.evaluate("el => el.scrollLeft") - max_scroll_x = loc.evaluate("el => el.scrollWidth - el.clientWidth") - assert scroll_position >= max_scroll_x, "Invalid postion after scroll right" + raise AssertionError( + f"Не удалось прокрутить до правого края. " + f"Текущая позиция: {final_position}, ожидалось: {max_scroll_x}, " + f"Ширина контента: {scroll_width}, " + f"Ширина видимой области: {client_width}" + )