From 2aa7a1e9b9c1e984312395e36a2ae24907dca18b Mon Sep 17 00:00:00 2001 From: Alexander Gerasimov Date: Tue, 27 Jan 2026 00:52:26 +0300 Subject: [PATCH] UI tests for Stellar_Burgers --- .gitignore | 21 +++++++++++++++ README.md | Bin 26 -> 2886 bytes conftest.py | 29 ++++++++++++++++++++ curl.py | 5 ++++ data.py | 4 +++ helper.py | 19 +++++++++++++ locators.py | 35 ++++++++++++++++++++++++ requirements.txt | 6 +++++ tests/test_constructor.py | 33 +++++++++++++++++++++++ tests/test_login.py | 53 +++++++++++++++++++++++++++++++++++++ tests/test_profile_page.py | 34 ++++++++++++++++++++++++ tests/test_registration.py | 37 ++++++++++++++++++++++++++ 12 files changed, 276 insertions(+) create mode 100644 .gitignore create mode 100644 conftest.py create mode 100644 curl.py create mode 100644 data.py create mode 100644 helper.py create mode 100644 locators.py create mode 100644 requirements.txt create mode 100644 tests/test_constructor.py create mode 100644 tests/test_login.py create mode 100644 tests/test_profile_page.py create mode 100644 tests/test_registration.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92f250a --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Python +__pycache__/ +*.pyc + +# Virtual environment +.venv/ +venv/ + +# Pytest +.pytest_cache/ + +# IDE +.idea/ +.vscode/ + +# OS +.DS_Store +Thumbs.db + +# Allure +allure-results/ diff --git a/README.md b/README.md index 93ca6f22ecc7a941a762a9044ecd65433bf3f74b..040a92c23b0489d57b3edc7b6683ea22b8bce4e9 100644 GIT binary patch literal 2886 zcmb_e%TC)s6y4`5Mq&dfio~N`R9*EK_y8*e6Rd_fvYn#tLeiE>L8N8bsw(Za8xxXZ z@|5xgcmAm7-f4v`2RUpLIZLAdH zRYZ}(Pn+f@$777(4+nTPP&C9vS6_~SGCr<1!|-<0_5u*gFXwW$?{B9ja4<;{3?Kna z4KxjL`5A@R^wm-@c)S)El%|A5X0#8?PVrr~;2c?{tnZ(>-jQW{p6jikf$7x^EYg*g zBL*=5ClTFJhf84Q_y-7vx(@a`ERyAoV-_YgVZNSvy;ugS*oCgH^+!zEij`Dw^Uhil zf&`%i(5x@Ug5@?2K-Pe6*$quIF)Tn$?(zk=f+h!uWkc;{)Rl(entagRiGR+=~@yASN^6xo}RnWLRkG2lTtb zUU@`_!rcB0tYg>9yTQ~O&)ww(Wb9jX6g>s6CeUJwAwH)rks#ZHAAW*%D9MOdbgU@u z57g0{>kr!$%DRRljg8PaXi#Df^hB~Fn2=6tW{r>rR+eN0ahkA41VW)O5{naS#@+)c ziRT&Fu&7z^bFd&O9*nl^O(Hw*T7hdN!L2eKhxLRZNhBr(aKv(qn|=3xO`D`ZBiNE= zBSldh3%s#WBoN1*1H@y`J)Hr`pmS~!yIwgLtdp)Yn59Xp2t-_Tz;55<0V1OV4MFhB zOBRjQK|`E7-Plf_r#@Dg?wO5uCijq@oaYOzMTMd` zj#L`XA8(|*gyY?Eu-Lm*^~}q5CbU`FF|Ii0AtKKCvDQrjBsKg zo-&k5#+&D%95Iu&uyQA^>pR7~6=V-roW#=DMOokmkYI-!`Me0e6ZlOgCQ0R=66oRi literal 26 hcmezWPnki1A()|np@<=qA&;SiA)djMftP`c0RUn?1#AES diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..21495fd --- /dev/null +++ b/conftest.py @@ -0,0 +1,29 @@ +import pytest +from selenium import webdriver +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.wait import WebDriverWait + +from curl import * +from locators import Locators +from data import Credentials + + +@pytest.fixture(scope="function") +def driver(): + driver = webdriver.Chrome() + driver.maximize_window() + yield driver + driver.quit() + +@pytest.fixture +def login(driver): + driver.get(MAIN_PAGE) + driver.find_element(*Locators.MAIN_LOGIN_BUTTON).click() + + WebDriverWait(driver, 5).until(EC.visibility_of_element_located(Locators.EMAIL)) + driver.find_element(*Locators.EMAIL).send_keys(Credentials.email) + driver.find_element(*Locators.PASSWORD).send_keys(Credentials.password) + driver.find_element(*Locators.LOGIN_BUTTON).click() + + WebDriverWait(driver, 5).until(EC.visibility_of_element_located(Locators.CONSTRUCTOR_TITLE)) + return driver diff --git a/curl.py b/curl.py new file mode 100644 index 0000000..f7a62ba --- /dev/null +++ b/curl.py @@ -0,0 +1,5 @@ +MAIN_PAGE = 'https://stellarburgers.education-services.ru/' #URL главной страницы +AUTH_PAGE = f'{MAIN_PAGE}login' #URL страницы авторизации +REG_PAGE = f'{MAIN_PAGE}register' #URL страницы регистрации +PROFILE_PAGE = f'{MAIN_PAGE}account/profile' #URL личного кабинета +FORGOT_PASSWORD_PAGE = f"{MAIN_PAGE}forgot-password" #URL страницы для восстановления пароля diff --git a/data.py b/data.py new file mode 100644 index 0000000..9a60ad0 --- /dev/null +++ b/data.py @@ -0,0 +1,4 @@ +class Credentials: + email = 'Alexander_Gerasimov_37_505@yandex.ru' + password = 'a15G51' + diff --git a/helper.py b/helper.py new file mode 100644 index 0000000..25ecf8b --- /dev/null +++ b/helper.py @@ -0,0 +1,19 @@ +from faker import Faker + +faker = Faker() + + +def generate_valid_registration_data(): + name = faker.name() + email = faker.email() + password = faker.password(length=6, special_chars=False, digits=True, upper_case=True, lower_case=True) + return name, email, password + + +def generate_registration_data_with_invalid_password(): + name = faker.name() + email = faker.email() + password = faker.password(length=3, special_chars=False, digits=True, upper_case=True, lower_case=True) + return name, email, password + + diff --git a/locators.py b/locators.py new file mode 100644 index 0000000..aabba64 --- /dev/null +++ b/locators.py @@ -0,0 +1,35 @@ +from selenium.webdriver.common.by import By + + +class Locators: + # Форма регистрации + NAME = (By.NAME, "name") # поле ввода Имя + EMAIL = (By.XPATH, "//label[text()='Email']/following-sibling::input") # поле ввода Имейл + PASSWORD = (By.NAME, "Пароль") # поле ввода Пароль + PASSWORD_ERROR = (By.XPATH, "//p[text()='Некорректный пароль']") # сообщение о вводе некорректного пароля + REGISTER_BUTTON = (By.XPATH, "//button[text()='Зарегистрироваться']") # кнопка Зарегистрироваться в форме регистрации + SIGN_BUTTON = (By.LINK_TEXT, "Войти") # кнопка Войти в форме регистрации + + # Форма авторизации + LOGIN_BUTTON = (By.XPATH, "//button[text()='Войти']") # кнопка Войти в форме авторизации + REGISTER_LINK = (By.LINK_TEXT, "Зарегистрироваться") # кнопка Зарегистрироваться в форме авторизации + RESTORE_BUTTON = (By.XPATH, "//button[text()='Восстановить']") # кнопка Восстановить пароль + + # Главная страница + MAIN_LOGIN_BUTTON = (By.XPATH, "//button[text()='Войти в аккаунт']") # кнопка Войти в аккаунт на главной странице + LOGO_BUTTON = (By.XPATH, "//div[@class='AppHeader_header__logo__2D0X2']") # логотип Stellar Burgers + + # Личный кабинет + PROFILE_BUTTON = (By.XPATH, "//p[text()='Личный Кабинет']") # кнопка Личный кабинет + LOGOUT_BUTTON = (By.XPATH, "//button[text()='Выход']") # кнопка Выход из профиля в личном кабинете + + # Конструктор + CONSTRUCTOR_BUTTON = (By.XPATH, ".//p[text() = 'Конструктор']") # вкладка Конструктор + CONSTRUCTOR_TITLE = (By.XPATH, "//h1[text()='Соберите бургер']") # заголовок Соберите бургер + BUNS_TAB = (By.XPATH, "//div[contains(@class,'tab_tab__')][.//span[normalize-space()='Булки']]") # секция Булки + SAUCES_TAB = (By.XPATH, "//div[contains(@class,'tab_tab__')][.//span[normalize-space()='Соусы']]") # секция Соусы + FILLINGS_TAB = (By.XPATH, "//div[contains(@class,'tab_tab__')][.//span[normalize-space()='Начинки']]") # секция Начинки + ACTIVE_TAB_TEXT = (By.XPATH, "//div[contains(@class,'tab_tab_type_current')]//span") # активная вкладка выбора + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..37a48f9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +selenium~=4.27.1 +pytest~=8.3.3 +requests~=2.32.3 +faker~=33.1.0 +webdriver_manager +allure-pytest \ No newline at end of file diff --git a/tests/test_constructor.py b/tests/test_constructor.py new file mode 100644 index 0000000..a6ee2da --- /dev/null +++ b/tests/test_constructor.py @@ -0,0 +1,33 @@ +import pytest +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +from curl import MAIN_PAGE +from locators import Locators + +class TestBurgerConstructor: + + @pytest.mark.parametrize("first_tab, second_tab, expected_name", [ + (Locators.FILLINGS_TAB, Locators.SAUCES_TAB, "Соусы"), + (Locators.SAUCES_TAB, Locators.FILLINGS_TAB, "Начинки"), + (Locators.FILLINGS_TAB, Locators.BUNS_TAB, "Булки"), + ]) + def test_burger_constructor_choosing_tabs(self, driver, first_tab, second_tab, expected_name): + driver.get(MAIN_PAGE) + wait = WebDriverWait(driver, 10) + + first = wait.until(EC.presence_of_element_located(first_tab)) + driver.execute_script("arguments[0].scrollIntoView({block:'center'});", first) + wait.until(EC.element_to_be_clickable(first)).click() + + second = wait.until(EC.presence_of_element_located(second_tab)) + driver.execute_script("arguments[0].scrollIntoView({block:'center'});", second) + wait.until(EC.element_to_be_clickable(second)).click() + + wait.until(lambda d: d.find_element(*Locators.ACTIVE_TAB_TEXT).text.strip() == expected_name) + assert driver.find_element(*Locators.ACTIVE_TAB_TEXT).text.strip() == expected_name + + + + + diff --git a/tests/test_login.py b/tests/test_login.py new file mode 100644 index 0000000..16661e5 --- /dev/null +++ b/tests/test_login.py @@ -0,0 +1,53 @@ +from selenium.webdriver.support.wait import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +from data import Credentials +from locators import Locators +from curl import * + + +class TestLogin: + + def test_login_main_page(self, driver): + driver.get(MAIN_PAGE) + driver.find_element(*Locators.MAIN_LOGIN_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.EMAIL)).send_keys(Credentials.email) + driver.find_element(*Locators.PASSWORD).send_keys(Credentials.password) + driver.find_element(*Locators.LOGIN_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.CONSTRUCTOR_TITLE)) + assert driver.current_url == MAIN_PAGE + + def test_login_profile_page(self, driver): + driver.get(MAIN_PAGE) + driver.find_element(*Locators.PROFILE_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.EMAIL)).send_keys(Credentials.email) + driver.find_element(*Locators.PASSWORD).send_keys(Credentials.password) + driver.find_element(*Locators.LOGIN_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.CONSTRUCTOR_TITLE)) + assert driver.current_url == MAIN_PAGE + + def test_login_registration_page(self, driver): + driver.get(REG_PAGE) + driver.find_element(*Locators.SIGN_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.EMAIL)).send_keys(Credentials.email) + driver.find_element(*Locators.PASSWORD).send_keys(Credentials.password) + driver.find_element(*Locators.LOGIN_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.CONSTRUCTOR_TITLE)) + assert driver.current_url == MAIN_PAGE + + def test_login_forgot_password_page(self, driver): + driver.get(FORGOT_PASSWORD_PAGE) + driver.find_element(*Locators.SIGN_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.EMAIL)).send_keys(Credentials.email) + driver.find_element(*Locators.PASSWORD).send_keys(Credentials.password) + driver.find_element(*Locators.LOGIN_BUTTON).click() + + WebDriverWait(driver, 3).until(EC.visibility_of_element_located(Locators.CONSTRUCTOR_TITLE)) + assert driver.current_url == MAIN_PAGE diff --git a/tests/test_profile_page.py b/tests/test_profile_page.py new file mode 100644 index 0000000..4c9c9e0 --- /dev/null +++ b/tests/test_profile_page.py @@ -0,0 +1,34 @@ +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.wait import WebDriverWait + +from locators import Locators +from curl import * + + +class TestProfilePage: + + def test_go_to_profile_page(self, login): + WebDriverWait(login, 3).until(EC.element_to_be_clickable(Locators.PROFILE_BUTTON)).click() + WebDriverWait(login, 3).until(EC.visibility_of_element_located(Locators.LOGOUT_BUTTON)) + + assert login.current_url == PROFILE_PAGE + + def test_go_from_profile_page_to_constructor(self, login): + WebDriverWait(login, 3).until(EC.element_to_be_clickable(Locators.PROFILE_BUTTON)).click() + WebDriverWait(login, 3).until(EC.visibility_of_element_located(Locators.CONSTRUCTOR_BUTTON)).click() + + assert login.current_url == MAIN_PAGE + + def test_go_from_profile_page_to_main_click_logo(self, login): + WebDriverWait(login, 3).until(EC.element_to_be_clickable(Locators.PROFILE_BUTTON)).click() + WebDriverWait(login, 3).until(EC.visibility_of_element_located(Locators.LOGO_BUTTON)).click() + + assert login.current_url == MAIN_PAGE + + def test_logout_from_profile_page(self, login): + WebDriverWait(login, 3).until(EC.element_to_be_clickable(Locators.PROFILE_BUTTON)).click() + WebDriverWait(login, 3).until(EC.element_to_be_clickable(Locators.LOGOUT_BUTTON)).click() + WebDriverWait(login, 3).until(EC.visibility_of_element_located(Locators.LOGIN_BUTTON)) + + assert login.current_url == AUTH_PAGE + \ No newline at end of file diff --git a/tests/test_registration.py b/tests/test_registration.py new file mode 100644 index 0000000..609dd63 --- /dev/null +++ b/tests/test_registration.py @@ -0,0 +1,37 @@ +from selenium.webdriver.support.wait import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +from helper import * +from locators import Locators +from curl import * + + +class TestRegistration: + + def test_registration_success(self, driver): + driver.get(REG_PAGE) + name, email, password = generate_valid_registration_data() + + driver.find_element(*Locators.NAME).send_keys(name) + driver.find_element(*Locators.EMAIL).send_keys(email) + driver.find_element(*Locators.PASSWORD).send_keys(password) + + driver.find_element(*Locators.REGISTER_BUTTON).click() + + WebDriverWait(driver, 5).until(EC.url_contains("/login")) + assert driver.current_url == AUTH_PAGE + + + def test_registration_with_invalid_password_error(self, driver): + driver.get(REG_PAGE) + name, email, password = generate_registration_data_with_invalid_password() + + driver.find_element(*Locators.NAME).send_keys(name) + driver.find_element(*Locators.EMAIL).send_keys(email) + driver.find_element(*Locators.PASSWORD).send_keys(password) + + driver.find_element(*Locators.REGISTER_BUTTON).click() + + WebDriverWait(driver,3).until(EC.visibility_of_element_located(Locators.PASSWORD_ERROR)) + + assert driver.find_element(*Locators.PASSWORD_ERROR).text == "Некорректный пароль"