Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# IDE
.idea/

# Python
__pycache__/
*.py[cod]

# Pytest / Allure
.pytest_cache/
allure-results/
.coverage
htmlcov/

# Venv
.venv/
venv/

# OS
.DS_Store
Thumbs.db
38 changes: 38 additions & 0 deletions 3_task/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest
from selenium import webdriver
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.firefox.service import Service as FirefoxService


BASE_URL = "https://stellarburgers.education-services.ru/"


@pytest.fixture(params=["chrome", "firefox"])
def driver(request):
if request.param == "chrome":
options = ChromeOptions()
options.add_argument("--start-maximized")

driver = webdriver.Chrome(
service=ChromeService(ChromeDriverManager().install()),
options=options
)
else:
options = FirefoxOptions()
options.add_argument("--width=1920")
options.add_argument("--height=1080")

driver = webdriver.Firefox(
service=FirefoxService(GeckoDriverManager().install()),
options=options
)

driver.implicitly_wait(5)
driver.get(BASE_URL)

yield driver
driver.quit()
Empty file added 3_task/pages/__init__.py
Empty file.
65 changes: 65 additions & 0 deletions 3_task/pages/base_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import allure
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class BasePage:

def __init__(self, driver, timeout=10):
self._driver = driver
self._wait = WebDriverWait(driver, timeout)

# ---------- базовые ожидания ----------

@allure.step("Ожидание видимости элемента {locator}")
def wait_visible(self, locator):
return self._wait.until(EC.visibility_of_element_located(locator))

@allure.step("Ожидание кликабельности элемента {locator}")
def wait_clickable(self, locator):
return self._wait.until(EC.element_to_be_clickable(locator))

@allure.step("Ожидание присутствия элемента {locator}")
def wait_present(self, locator):
return self._wait.until(EC.presence_of_element_located(locator))

@allure.step("Ожидание исчезновения элемента {locator}")
def wait_invisible(self, locator):
self._wait.until(EC.invisibility_of_element_located(locator))

# ---------- действия ----------

@allure.step("Клик по элементу {locator}")
def click(self, locator):
element = self.wait_clickable(locator)
self._driver.execute_script(
"arguments[0].scrollIntoView({block: 'center'});",
element
)
self._driver.execute_script("arguments[0].click();", element)

@allure.step("Выполнение JS-скрипта")
def execute_js(self, script, *args):
self._driver.execute_script(script, *args)

@allure.step("Обновление страницы")
def refresh_page(self):
self._driver.refresh()

# ---------- получение данных ----------

@allure.step("Получение текста элемента {locator}")
def get_text(self, locator) -> str:
return self.wait_visible(locator).text

@allure.step("Подсчёт элементов {locator}")
def count_elements(self, locator) -> int:
return len(self._driver.find_elements(*locator))

@allure.step("Проверка видимости элемента {locator}")
def is_visible(self, locator) -> bool:
try:
self.wait_visible(locator)
return True
except Exception:
return False
35 changes: 35 additions & 0 deletions 3_task/pages/feed_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import allure
from selenium.webdriver.common.by import By
from pages.base_page import BasePage


class FeedPage(BasePage):

ORDERS_TOTAL = (
By.XPATH,
"//p[text()='Выполнено за все время:']/following-sibling::p"
)
ORDERS_TODAY = (
By.XPATH,
"//p[text()='Выполнено за сегодня:']/following-sibling::p"
)
ORDERS_IN_PROGRESS = (
By.XPATH,
"//ul[contains(@class,'OrderFeed_orderList')]"
)

@allure.step("Получение количества заказов за всё время")
def get_total_orders(self) -> int:
return int(self.get_text(self.ORDERS_TOTAL))

@allure.step("Получение количества заказов за сегодня")
def get_today_orders(self) -> int:
return int(self.get_text(self.ORDERS_TODAY))

@allure.step("Обновление страницы ленты заказов")
def refresh_feed(self):
self.refresh_page()

@allure.step("Проверка наличия заказов в статусе «В работе»")
def has_orders_in_progress(self) -> bool:
return self.is_visible(self.ORDERS_IN_PROGRESS)
92 changes: 92 additions & 0 deletions 3_task/pages/main_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import allure
from selenium.webdriver.common.by import By
from pages.base_page import BasePage


class MainPage(BasePage):

CONSTRUCTOR_TAB = (By.XPATH, "//p[text()='Конструктор']")
FEED_TAB = (By.XPATH, "//a[contains(@href,'/feed')]")

CONSTRUCTOR_HEADER = (By.XPATH, "//h1[text()='Соберите бургер']")
FEED_HEADER = (By.XPATH, "//h1[text()='Лента заказов']")

INGREDIENT_NAME = "Соус Spicy-X"
INGREDIENT = (By.XPATH, f"//p[text()='{INGREDIENT_NAME}']")

CONSTRUCTOR_SECTION = (
By.XPATH,
"//section[contains(@class,'BurgerConstructor')]"
)

CONSTRUCTOR_ITEMS = (
By.XPATH,
"//section[contains(@class,'BurgerConstructor')]//li"
)

MODAL = (By.XPATH, "//section[contains(@class,'Modal_modal')]")
MODAL_CLOSE_BUTTON = (
By.XPATH,
"//button[contains(@class,'Modal_modal__close')]"
)

# ---------- навигация ----------

@allure.step("Открыть конструктор")
def open_constructor(self):
self.click(self.CONSTRUCTOR_TAB)

@allure.step("Открыть ленту заказов")
def open_feed(self):
self.click(self.FEED_TAB)

# ---------- проверки ----------

@allure.step("Проверить, что конструктор открыт")
def is_constructor_opened(self) -> bool:
return self.count_elements(self.CONSTRUCTOR_HEADER) > 0

@allure.step("Проверить, что лента заказов открыта")
def is_feed_opened(self) -> bool:
return self.count_elements(self.FEED_HEADER) > 0

# ---------- модалка ----------

@allure.step("Открыть модальное окно ингредиента")
def open_ingredient_modal(self):
self.click(self.INGREDIENT)
self.wait_visible(self.MODAL)

@allure.step("Закрыть модальное окно ингредиента")
def close_ingredient_modal(self):
self.click(self.MODAL_CLOSE_BUTTON)

@allure.step("Дождаться закрытия модального окна")
def wait_modal_closed(self):
self.wait_invisible(self.MODAL)

# ---------- конструктор ----------

@allure.step("Добавить ингредиент в конструктор")
def add_ingredient_to_constructor(self):
ingredient = self.wait_present(self.INGREDIENT)
target = self.wait_present(self.CONSTRUCTOR_SECTION)

self.execute_js(
"""
const source = arguments[0];
const target = arguments[1];
const dataTransfer = new DataTransfer();

source.dispatchEvent(new DragEvent('dragstart', { dataTransfer }));
target.dispatchEvent(new DragEvent('dragover', { dataTransfer }));
target.dispatchEvent(new DragEvent('drop', { dataTransfer }));
source.dispatchEvent(new DragEvent('dragend', { dataTransfer }));
""",
ingredient,
target
)

@allure.step("Проверить, что в конструкторе есть ингредиенты")
def constructor_has_items(self) -> bool:
return self.count_elements(self.CONSTRUCTOR_ITEMS) > 0
Empty file added 3_task/requirements.txt
Empty file.
Empty file added 3_task/tests/__init__.py
Empty file.
53 changes: 53 additions & 0 deletions 3_task/tests/test_feed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import allure

from pages.feed_page import FeedPage
from pages.main_page import MainPage


@allure.feature("Лента заказов")
class TestFeed:

@allure.title("Отображение и обновление счётчиков заказов в ленте")
def test_orders_counters_display_and_update(self, driver):
main_page = MainPage(driver)
feed_page = FeedPage(driver)

with allure.step("Переход в конструктор"):
main_page.open_constructor()

with allure.step("Добавление ингредиента в конструктор"):
main_page.add_ingredient_to_constructor()
assert main_page.constructor_has_items()

with allure.step("Переход в ленту заказов"):
main_page.open_feed()

with allure.step("Фиксация текущих значений счётчиков"):
total_before = feed_page.get_total_orders()

with allure.step("Обновление ленты заказов"):
feed_page.refresh_feed()

with allure.step("Проверка, что счётчик выполненных заказов не уменьшился"):
assert feed_page.get_total_orders() >= total_before

@allure.title("В ленте заказов отображается раздел «В работе»")
def test_orders_in_progress_section_displayed(self, driver):
main_page = MainPage(driver)
feed_page = FeedPage(driver)

with allure.step("Переход в конструктор"):
main_page.open_constructor()

with allure.step("Добавление ингредиента в конструктор"):
main_page.add_ingredient_to_constructor()
assert main_page.constructor_has_items()

with allure.step("Переход в ленту заказов"):
main_page.open_feed()

with allure.step("Обновление ленты заказов"):
feed_page.refresh_feed()

with allure.step("Проверка наличия раздела «В работе»"):
assert feed_page.has_orders_in_progress()
48 changes: 48 additions & 0 deletions 3_task/tests/test_main_functional.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import allure

from pages.main_page import MainPage


@allure.feature("Главная страница")
class TestMainFunctional:

@allure.title("Переход по клику на вкладку «Конструктор»")
def test_open_constructor(self, driver):
main_page = MainPage(driver)

with allure.step("Клик по вкладке «Конструктор»"):
main_page.open_constructor()

with allure.step("Проверка открытия конструктора"):
assert main_page.is_constructor_opened()

@allure.title("Переход по клику на вкладку «Лента заказов»")
def test_open_feed(self, driver):
main_page = MainPage(driver)

with allure.step("Клик по вкладке «Лента заказов»"):
main_page.open_feed()

with allure.step("Проверка открытия ленты заказов"):
assert main_page.is_feed_opened()

@allure.title("Открытие и закрытие модального окна ингредиента")
def test_ingredient_modal_open_and_close(self, driver):
main_page = MainPage(driver)

with allure.step("Открытие модального окна ингредиента"):
main_page.open_ingredient_modal()

with allure.step("Закрытие модального окна ингредиента"):
main_page.close_ingredient_modal()
main_page.wait_modal_closed()

@allure.title("Ингредиент добавляется в конструктор")
def test_ingredient_added_to_constructor(self, driver):
main_page = MainPage(driver)

with allure.step("Добавление ингредиента в конструктор"):
main_page.add_ingredient_to_constructor()

with allure.step("Проверка наличия ингредиента в конструкторе"):
assert main_page.constructor_has_items()