Логикой понимаю как это можно сделать, но толи идентификатор нужный найти не получается толи что-то делаю не так. На сайте
https://arnypraht.com/category/bags/ есть span по клику на который открывается выпадающее меню с различными видами сортировки (конкретно интересуют цена по возврастанию и цена по убыванию)
. При запуске моего теста, осуществляется переход на страницу с сумками, а клика по соответствующему span не происходит.
from selenium.webdriver.common.by import By
from pages.base_page import BasePage
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import TimeoutException
class FiltersPage(BasePage):
# Локатор кнопки "Фильтры"
FILTER_BUTTON = (By.CSS_SELECTOR, "button.button[data-filter-bar-opener]")
# Локатор для списка доступных фильтров (по цветам, например)
FILTER_LIST = (By.CSS_SELECTOR, "ul[data-switches='mse2_tvcolor']")
# Локатор для отдельных пунктов фильтра
FILTER_OPTION = (By.CSS_SELECTOR, "li.swatch.is-sorted.tooltipstered")
# Локатор для закрытия фильтров
CLOSE_FILTER_BUTTON = (By.CSS_SELECTOR, "button.cross[data-filter-bar-closer]")
# Локатор названия цвета в карточке товара
PRODUCT_COLOR_NAME = (By.CSS_SELECTOR, "div.card__subtitle.text--light.color-name[data-card-subtitle]")
# Обновленные локаторы
SORT_BUTTON = (By.CSS_SELECTOR, "span.select2-selection--single.select2-selection--buttoned")
SORT_OPTION = (By.CSS_SELECTOR, "li.select2-results__option")
ITEM_PRICE = (By.CLASS_NAME, "price")
MENU_ITEM = (By.CLASS_NAME, 'header__menu-item') # Локатор для пункта меню
SORT_RENDERED = (By.CSS_SELECTOR, '[class="select2-selection__rendered"]') # Локатор для кнопки сортировки
SORT_ASC_OPTION = (By.ID, 'select2-catalog_sorting-dn-result-fnn9-price:asc') # Локатор для варианта сортировки "Цена по возрастанию"
def open_filters(self):
"""Открывает панель фильтров."""
self.click(self.FILTER_BUTTON)
def select_filter_option_by_index(self, index):
"""
Выбирает пункт фильтра по индексу.
:param index: Позиция элемента в списке фильтров (0 - первый элемент).
"""
filter_options = self.find_elements(self.FILTER_OPTION)
if 0 <= index < len(filter_options):
filter_options[index].click()
else:
raise IndexError(f"Фильтр с индексом {index} не найден.")
def close_filters(self):
"""Закрывает панель фильтров."""
self.click(self.CLOSE_FILTER_BUTTON)
def get_all_displayed_colors(self):
"""
Возвращает список цветов всех отображаемых товаров.
"""
WebDriverWait(self.driver, 10).until(
EC.presence_of_all_elements_located(self.PRODUCT_COLOR_NAME)
)
elements = self.find_elements(self.PRODUCT_COLOR_NAME)
return [element.text.strip() for element in elements if element.text.strip()]
def go_to_page(self):
elements = self.driver.find_elements(By.CSS_SELECTOR, 'a.header__menu-item-link')
menu_item = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'a.header__menu-item-link'))
)
menu_item.click()
def scroll_to_element(self, element):
"""
Прокручивает страницу до указанного элемента.
:param element: Веб-элемент, до которого нужно прокрутить.
"""
self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
def select_sort_option(self, sort_option_text):
"""
Кликает на кликабельный span, открывает выпадающее меню и выбирает нужный вариант сортировки.
"""
try:
# Ожидаем, пока span станет кликабельным
sort_button = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable(self.SORT_BUTTON)
)
self.scroll_to_element(sort_button)
sort_button.click() # Кликаем по span, чтобы открыть выпадающее меню
# Ожидаем появления выпадающего меню с опциями сортировки
WebDriverWait(self.driver, 20).until(
EC.presence_of_all_elements_located(self.SORT_OPTION)
)
# Находим нужный вариант сортировки и кликаем по нему
sort_options = self.find_elements(self.SORT_OPTION)
for option in sort_options:
if option.text.strip() == sort_option_text:
self.scroll_to_element(option)
option.click() # Кликаем по варианту сортировки
WebDriverWait(self.driver, 10).until(EC.staleness_of(option)) # Ждем обновления страницы
return
raise ValueError(f"Не удалось найти вариант сортировки: {sort_option_text}")
except TimeoutException:
raise AssertionError("Не удалось найти span для сортировки или выпадающее меню.")
def sort_by_price(self):
"""
Выполняет сортировку товаров по цене по возрастанию и проверяет результат.
"""
# Кликаем на пункт меню "Товары" (или подходящий пункт)
menu_items = self.find_elements(self.MENU_ITEM)
if len(menu_items) > 2:
self.scroll_to_element(menu_items[2])
menu_items[2].click()
else:
raise IndexError("Пункт меню для выбора товаров не найден.")
# Кликаем на кнопку сортировки
sort_button = self.find_element(self.SORT_RENDERED)
self.scroll_to_element(sort_button)
sort_button.click()
# Выбираем вариант сортировки "Цена по возрастанию"
sort_asc_option = self.find_element(self.SORT_ASC_OPTION)
self.scroll_to_element(sort_asc_option)
sort_asc_option.click()
def get_sorted_prices(self):
"""
Возвращает список цен с текущей страницы как числа.
"""
WebDriverWait(self.driver, 10).until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".card .price"))
)
price_elements = self.find_elements((By.CSS_SELECTOR, ".card .price"))
return [int(price.text.strip().replace(" ", "").replace("₽", "")) for price in price_elements if
price.text.strip()]
import pytest
from pages.filters_page import FiltersPage
@pytest.mark.parametrize(
"sort_option, expected_order",
[
("Цена по возрастанию", "asc"),
("Цена по убыванию", "desc"),
],
)
def test_sort_by_price(browser, sort_option, expected_order):
filters_page = FiltersPage(browser)
filters_page.go_to_page()
# Выбираем опцию сортировки
filters_page.select_sort_option(sort_option)
# Проверяем порядок цен
prices = filters_page.get_sorted_prices()
if expected_order == "asc":
assert prices == sorted(prices), f"Цены не отсортированы по возрастанию: {prices}"
elif expected_order == "desc":
assert prices == sorted(prices, reverse=True), f"Цены не отсортированы по убыванию: {prices}"