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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
__pycache__/
*.pyc
.pytest_cache/
.venv/
venv/
.idea/
.env
55 changes: 54 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,54 @@
# Sprint_5
# Sprint_5 — автотесты Stellar Burgers

Проект содержит автотесты для сервиса Stellar Burgers:
https://stellarburgers.education-services.ru/

Тестирование выполнено с использованием:
- Python
- Selenium
- Pytest
- Google Chrome / Mozilla Firefox

## Проверяемый функционал
### Регистрация
- Успешная регистрация
- Ошибка при коротком пароле

### Авторизация
- Вход через кнопку «Войти в аккаунт» на главной странице
- Вход через кнопку «Личный кабинет»
- Вход через кнопку в форме регистрации
- Вход через кнопку в форме восстановления пароля

### Навигация
- Переход в личный кабинет
- Переход из личного кабинета в конструктор (по кнопке «Конструктор»)
- Переход в конструктор по клику на логотип Stellar Burgers

### Выход
- Выход из аккаунта через кнопку «Выйти» в личном кабинете

### Конструктор
- Переключение вкладок:
- Булки
- Соусы
- Начинки

## Структура проекта
│-- tests/
│ ├─ test_login.py
│ ├─ test_logout.py
│ ├─ test_registration.py
│ ├─ test_constructor.py
│ └─ test_navigation.py
│-- locators.py
│-- conftest.py
│-- config.py
│-- data.py
│-- .gitignore
│-- README.md

## Генерация тестовых данных
Email генерируется автоматически в формате:
`eva_test_17_XXX@yandex.ru`
Пароль генерируется автоматически и содержит минимум 6 символов.
2 changes: 2 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
BASE_URL = "https://stellarburgers.education-services.ru/"

65 changes: 65 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import pytest
import random
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from config import BASE_URL
from locators import Locators
from data import TEST_EMAIL, TEST_PASSWORD


def pytest_addoption(parser):
parser.addoption(
"--browser",
action="store",
default="chrome",
help="Choose browser: chrome or firefox"
)


@pytest.fixture
def driver(request):
browser = request.config.getoption("--browser")

if browser == "chrome":
driver = webdriver.Chrome()
elif browser == "firefox":
driver = webdriver.Firefox()
else:
raise ValueError("Browser not supported")

driver.maximize_window()
yield driver
driver.quit()


@pytest.fixture
def wait(driver):
return WebDriverWait(driver, 10)


@pytest.fixture
def authorized_user(driver, wait):
driver.get(BASE_URL)

wait.until(EC.element_to_be_clickable(Locators.LOGIN_BUTTON_MAIN)).click()

wait.until(EC.visibility_of_element_located(
Locators.LOGIN_EMAIL_INPUT)).send_keys(TEST_EMAIL)

wait.until(EC.visibility_of_element_located(
Locators.LOGIN_PASSWORD_INPUT)).send_keys(TEST_PASSWORD)

wait.until(EC.element_to_be_clickable(
Locators.LOGIN_BUTTON)).click()

wait.until(EC.url_to_be(BASE_URL))
return driver

@pytest.fixture
def random_user():
number = random.randint(100, 999)
email = f"eva_test_17_{number}@yandex.ru"
password = f"Pass{random.randint(100000, 999999)}"
return email, password
2 changes: 2 additions & 0 deletions data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TEST_EMAIL = "EvaWunder@yandex.ru"
TEST_PASSWORD = "parol123"
42 changes: 42 additions & 0 deletions locators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from selenium.webdriver.common.by import By


class Locators:
# Главная страница
LOGIN_BUTTON_MAIN = (By.XPATH, "//button[text()='Войти в аккаунт']")
PERSONAL_ACCOUNT_BUTTON = (By.CSS_SELECTOR, "a[href='/account']")
LOGO = (By.CSS_SELECTOR, "div.AppHeader_header__logo__2D0X2 a")
CONSTRUCTOR_BUTTON = (By.XPATH, "//p[text()='Конструктор']")

# Регистрация / Вход
REGISTER_LINK = (By.LINK_TEXT, "Зарегистрироваться")
FORGOT_PASSWORD_LINK = (By.LINK_TEXT, "Восстановить пароль")
# Внутри формы регистрации
LOGIN_LINK_IN_REGISTER = (By.LINK_TEXT, "Войти")

# Внутри формы восстановления
LOGIN_LINK_IN_FORGOT = (By.LINK_TEXT, "Войти")

# Поля регистрации
REGISTER_NAME_INPUT = (By.XPATH, "(//input[@type='text'])[1]")
REGISTER_EMAIL_INPUT = (By.XPATH, "(//input[@type='text'])[2]")
REGISTER_PASSWORD_INPUT = (By.NAME, "Пароль")
REGISTER_BUTTON = (By.XPATH, "//button[normalize-space()='Зарегистрироваться']")

# Логин
LOGIN_EMAIL_INPUT = (By.XPATH, "//input[@type='text']")
LOGIN_PASSWORD_INPUT = (By.NAME, "Пароль")
LOGIN_BUTTON = (By.XPATH, "//button[normalize-space()='Войти']")

PASSWORD_ERROR = (By.XPATH, "//p[contains(text(),'Некорректный пароль')]")

# Личный кабинет
LOGOUT_BUTTON = (By.XPATH, "//button[contains(text(),'Выход')]")

# Конструктор
BUNS_TAB = (By.XPATH, "//span[text()='Булки']")
SAUCES_TAB = (By.XPATH, "//span[text()='Соусы']")
FILLINGS_TAB = (By.XPATH, "//span[text()='Начинки']")

# Overlay
MODAL_OVERLAY = (By.CSS_SELECTOR, "div.Modal_modal_overlay__x2ZCr")
37 changes: 37 additions & 0 deletions tests/test_constructor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from selenium.webdriver.support import expected_conditions as EC
from locators import Locators
from config import BASE_URL


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно исправить: все тесты должны быть разделены на тестовые классы

class TestConstructor:

def click_tab(self, driver, wait, locator):
tab = wait.until(EC.element_to_be_clickable(locator))
driver.execute_script("arguments[0].click();", tab)
return tab

def test_switch_to_sauces(self, driver, wait):
driver.get(BASE_URL)

tab = self.click_tab(driver, wait, Locators.SAUCES_TAB)
parent = tab.find_element("xpath", "..")

assert "current" in parent.get_attribute("class")

def test_switch_to_fillings(self, driver, wait):
driver.get(BASE_URL)

tab = self.click_tab(driver, wait, Locators.FILLINGS_TAB)
parent = tab.find_element("xpath", "..")

assert "current" in parent.get_attribute("class")

def test_switch_to_buns(self, driver, wait):
driver.get(BASE_URL)

self.click_tab(driver, wait, Locators.SAUCES_TAB)

tab = self.click_tab(driver, wait, Locators.BUNS_TAB)
parent = tab.find_element("xpath", "..")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно исправить: этот таб активен по умолчанию Для проверки тебе нужно сначала переключится на другой

assert "current" in parent.get_attribute("class")
80 changes: 80 additions & 0 deletions tests/test_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from locators import Locators
from config import BASE_URL
from data import TEST_EMAIL, TEST_PASSWORD


class TestLogin:

def login(self, driver, wait):
Copy link

@Ayantea1 Ayantea1 Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно улучшить: большая часть дублирует фикстуру authorized_user. Возможно стоит убрать из фикстуры точку входа в форму логина, тогда не понадобится отдельный метод для тестирования разных точек входа. В идеале - передавать данные для входа в метод, тогда оя регистрации нового пользователя тоже не придется писать отдельный код

wait.until(
EC.visibility_of_element_located(Locators.LOGIN_EMAIL_INPUT)
).send_keys(TEST_EMAIL)

wait.until(
EC.visibility_of_element_located(Locators.LOGIN_PASSWORD_INPUT)
).send_keys(TEST_PASSWORD)

wait.until(
EC.element_to_be_clickable(Locators.LOGIN_BUTTON)
).click()

wait.until(
EC.text_to_be_present_in_element(
(By.XPATH, "//button[contains(text(),'Оформить заказ')]"),
"Оформить заказ"
)
)

def test_login_from_main_button(self, driver, wait):
driver.get(BASE_URL)

wait.until(
EC.element_to_be_clickable(Locators.LOGIN_BUTTON_MAIN)
).click()

self.login(driver, wait)

def test_login_from_personal_account(self, driver, wait):
driver.get(BASE_URL)

wait.until(
EC.element_to_be_clickable(Locators.PERSONAL_ACCOUNT_BUTTON)
).click()

self.login(driver, wait)

def test_login_from_forgot_password(self, driver, wait):
driver.get(BASE_URL)

wait.until(
EC.element_to_be_clickable(Locators.PERSONAL_ACCOUNT_BUTTON)
).click()

wait.until(
EC.element_to_be_clickable(Locators.FORGOT_PASSWORD_LINK)
).click()

wait.until(
EC.element_to_be_clickable(Locators.LOGIN_LINK_IN_FORGOT)
).click()

self.login(driver, wait)

def test_login_from_registration_form(self, driver, wait):
driver.get(BASE_URL)

wait.until(
EC.element_to_be_clickable(Locators.PERSONAL_ACCOUNT_BUTTON)
).click()

wait.until(
EC.element_to_be_clickable(Locators.REGISTER_LINK)
).click()

wait.until(
EC.element_to_be_clickable(Locators.LOGIN_LINK_IN_REGISTER)
).click()

self.login(driver, wait)
20 changes: 20 additions & 0 deletions tests/test_logout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from selenium.webdriver.support import expected_conditions as EC
from locators import Locators


class TestLogout:

def test_logout(self, authorized_user, wait):
driver = authorized_user

wait.until(EC.element_to_be_clickable(
Locators.PERSONAL_ACCOUNT_BUTTON)).click()

wait.until(EC.url_contains("/account"))

wait.until(EC.element_to_be_clickable(
Locators.LOGOUT_BUTTON)).click()

wait.until(EC.url_contains("login"))

assert "login" in driver.current_url
57 changes: 57 additions & 0 deletions tests/test_navigation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from selenium.webdriver.support import expected_conditions as EC
from locators import Locators
from config import BASE_URL


class TestNavigation:

def test_go_to_personal_account(self, authorized_user, wait):
driver = authorized_user

wait.until(
EC.invisibility_of_element_located(Locators.MODAL_OVERLAY)
)

wait.until(
EC.element_to_be_clickable(Locators.PERSONAL_ACCOUNT_BUTTON)
).click()

wait.until(EC.url_contains("/account"))

assert "/account" in driver.current_url


def test_go_to_constructor_via_button(self, authorized_user, wait):
driver = authorized_user

wait.until(
EC.element_to_be_clickable(Locators.PERSONAL_ACCOUNT_BUTTON)
).click()

wait.until(EC.url_contains("/account"))

wait.until(
EC.element_to_be_clickable(Locators.CONSTRUCTOR_BUTTON)
).click()

wait.until(EC.url_to_be(BASE_URL))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно исправить: не проверен переход по лого

assert driver.current_url == BASE_URL


def test_go_to_constructor_via_logo(self, authorized_user, wait):
driver = authorized_user

wait.until(
EC.element_to_be_clickable(Locators.PERSONAL_ACCOUNT_BUTTON)
).click()

wait.until(EC.url_contains("/account"))

wait.until(
EC.element_to_be_clickable(Locators.LOGO)
).click()

wait.until(EC.url_to_be(BASE_URL))

assert driver.current_url == BASE_URL
Loading