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
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Python
__pycache__/
*.py[cod]
*.pyo
.pytest_cache/
*.egg-info/
dist/
build/
.eggs/

# Virtual environment
venv/
.venv/
env/

# IDE
.idea/
.vscode/
*.iml

# OS
.DS_Store
Thumbs.db

# Logs and reports
*.log
reports/
allure-results/

# Selenium / browser
chromedriver
geckodriver
9 changes: 9 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import pytest
from selenium import webdriver


@pytest.fixture
def driver():
driver = webdriver.Chrome()
yield driver
driver.quit()
20 changes: 20 additions & 0 deletions helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import random
import string

BASE_URL = "https://stellarburgers.education-services.ru"
LOGIN_URL = f"{BASE_URL}/login"
REGISTER_URL = f"{BASE_URL}/register"
FORGOT_PASSWORD_URL = f"{BASE_URL}/forgot-password"
PROFILE_URL = f"{BASE_URL}/account/profile"


def generate_email():
"""Генерирует уникальный email в формате имя_фамилия_когорта_XXX@домен."""
digits = "".join(random.choices(string.digits, k=6))
return f"test_testov_999_{digits}@yandex.ru"


def generate_password(length=8):
"""Генерирует случайный пароль заданной длины (минимум 6 символов)."""
chars = string.ascii_letters + string.digits
return "".join(random.choices(chars, k=length))
Empty file added locators/__init__.py
Empty file.
81 changes: 81 additions & 0 deletions locators/locators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from selenium.webdriver.common.by import By


class MainPageLocators:
# Кнопка «Войти в аккаунт» в конструкторе (видна только неавторизованным)
LOGIN_BUTTON = (By.XPATH, "//button[text()='Войти в аккаунт']")

# Ссылка «Личный Кабинет» в шапке (тег <a href="/account">)
PERSONAL_ACCOUNT_LINK = (By.XPATH, "//a[@href='/account']")

# Ссылка «Конструктор» в шапке (тег <a href="/">)
CONSTRUCTOR_LINK = (By.XPATH, "//a[@href='/'][.//p[contains(@class,'AppHeader_header__linkText')]]")

# Логотип Stellar Burgers в шапке (div-обёртка с классом header__logo)
LOGO = (By.XPATH, "//div[contains(@class,'AppHeader_header__logo')]")

# Вкладка «Булки» в конструкторе (кликабельный div с текстом внутри span)
BUNS_TAB = (By.XPATH, "//div[contains(@class,'tab_tab')]//span[text()='Булки']")

# Вкладка «Соусы» в конструкторе
SAUCES_TAB = (By.XPATH, "//div[contains(@class,'tab_tab')]//span[text()='Соусы']")

# Вкладка «Начинки» в конструкторе
FILLINGS_TAB = (By.XPATH, "//div[contains(@class,'tab_tab')]//span[text()='Начинки']")

# Заголовок раздела «Булки» в списке ингредиентов (h2)
BUNS_HEADING = (By.XPATH, "//h2[text()='Булки']")

# Заголовок раздела «Соусы» в списке ингредиентов (h2)
SAUCES_HEADING = (By.XPATH, "//h2[text()='Соусы']")

# Заголовок раздела «Начинки» в списке ингредиентов (h2)
FILLINGS_HEADING = (By.XPATH, "//h2[text()='Начинки']")


class LoginPageLocators:
# Поле ввода email на странице входа (первый fieldset, оба поля имеют name="name")
EMAIL_INPUT = (By.XPATH, "//fieldset[1]//input")

# Поле ввода пароля на странице входа (второй fieldset, name="Пароль")
PASSWORD_INPUT = (By.XPATH, "//input[@name='Пароль']")

# Кнопка «Войти» на странице входа
LOGIN_BUTTON = (By.XPATH, "//button[text()='Войти']")

# Ссылка «Зарегистрироваться» на странице входа (класс Auth_link)
REGISTER_LINK = (By.XPATH, "//a[@href='/register']")

# Ссылка «Восстановить пароль» на странице входа
FORGOT_PASSWORD_LINK = (By.XPATH, "//a[@href='/forgot-password']")


class RegisterPageLocators:
# Поле «Имя» на странице регистрации (первый fieldset)
NAME_INPUT = (By.XPATH, "//fieldset[1]//input")

# Поле «Email» на странице регистрации (второй fieldset)
EMAIL_INPUT = (By.XPATH, "//fieldset[2]//input")

# Поле «Пароль» на странице регистрации (третий fieldset)
PASSWORD_INPUT = (By.XPATH, "//fieldset[3]//input")

# Кнопка «Зарегистрироваться»
REGISTER_BUTTON = (By.XPATH, "//button[text()='Зарегистрироваться']")

# Ссылка «Войти» на странице регистрации (ведёт на /login)
LOGIN_LINK = (By.XPATH, "//a[@href='/login']")

# Сообщение об ошибке при некорректном пароле
PASSWORD_ERROR = (By.XPATH, "//p[text()='Некорректный пароль']")


class ForgotPasswordPageLocators:
# Ссылка «Войти» на странице восстановления пароля (ведёт на /login)
LOGIN_LINK = (By.XPATH, "//a[@href='/login']")


class ProfilePageLocators:
# Кнопка «Выйти» в боковом меню личного кабинета
LOGOUT_BUTTON = (By.XPATH, "//button[text()='Выход']")

Empty file added praktikum/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions praktikum/bun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Bun:
def __init__(self, name: str, price: float):
self.name = name
self.price = price

def get_name(self) -> str:
return self.name

def get_price(self) -> float:
return self.price
34 changes: 34 additions & 0 deletions praktikum/burger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import List
from praktikum.bun import Bun
from praktikum.ingredient import Ingredient

class Burger:
def __init__(self):
self.bun = None
self.ingredients: List[Ingredient] = []

def set_buns(self, bun: Bun):
self.bun = bun

def add_ingredient(self, ingredient: Ingredient):
self.ingredients.append(ingredient)

def remove_ingredient(self, index: int):
del self.ingredients[index]

def move_ingredient(self, index: int, new_index: int):
self.ingredients.insert(new_index, self.ingredients.pop(index))

def get_price(self) -> float:
price = self.bun.get_price() * 2
for ingredient in self.ingredients:
price += ingredient.get_price()
return price

def get_receipt(self) -> str:
receipt: List[str] = [f'(==== {self.bun.get_name()} ====)']
for ingredient in self.ingredients:
receipt.append(f'= {str(ingredient.get_type()).lower()} {ingredient.get_name()} =')
receipt.append(f'(==== {self.bun.get_name()} ====)\n')
receipt.append(f'Price: {self.get_price()}')
return '\n'.join(receipt)
27 changes: 27 additions & 0 deletions praktikum/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import List
from praktikum.bun import Bun
from praktikum.ingredient import Ingredient
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING

class Database:
def __init__(self):
self.buns: List[Bun] = []
self.ingredients: List[Ingredient] = []

self.buns.append(Bun("black bun", 100))
self.buns.append(Bun("white bun", 200))
self.buns.append(Bun("red bun", 300))

self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "hot sauce", 100))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "sour cream", 200))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_SAUCE, "chili sauce", 300))

self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "cutlet", 100))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "dinosaur", 200))
self.ingredients.append(Ingredient(INGREDIENT_TYPE_FILLING, "sausage", 300))

def available_buns(self) -> List[Bun]:
return self.buns

def available_ingredients(self) -> List[Ingredient]:
return self.ingredients
14 changes: 14 additions & 0 deletions praktikum/ingredient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Ingredient:
def __init__(self, ingredient_type: str, name: str, price: float):
self.type = ingredient_type
self.name = name
self.price = price

def get_price(self) -> float:
return self.price

def get_name(self) -> str:
return self.name

def get_type(self) -> str:
return self.type
2 changes: 2 additions & 0 deletions praktikum/ingredient_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INGREDIENT_TYPE_SAUCE = 'SAUCE'
INGREDIENT_TYPE_FILLING = 'FILLING'
2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
pythonpath = .
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytest==8.2.0
pytest-cov==5.0.0
Empty file added tests/__init__.py
Empty file.
23 changes: 23 additions & 0 deletions tests/test_bun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import pytest
from praktikum.bun import Bun


class TestBun:

@pytest.mark.parametrize('name, price', [
('black bun', 100),
('white bun', 200.5),
('red bun', 0),
])
def test_get_name(self, name, price):
bun = Bun(name, price)
assert bun.get_name() == name

@pytest.mark.parametrize('name, price', [
('black bun', 100),
('white bun', 200.5),
('red bun', 0),
])
def test_get_price(self, name, price):
bun = Bun(name, price)
assert bun.get_price() == price
Loading