diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1cb570 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__/ +*.pyc +.pytest_cache/ +.venv/ +venv/ +.idea/ +.env \ No newline at end of file diff --git a/README.md b/README.md index 5aa61ea..0ee34c2 100644 --- a/README.md +++ b/README.md @@ -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 символов. diff --git a/config.py b/config.py new file mode 100644 index 0000000..b7d442e --- /dev/null +++ b/config.py @@ -0,0 +1,2 @@ +BASE_URL = "https://stellarburgers.education-services.ru/" + diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..269cc18 --- /dev/null +++ b/conftest.py @@ -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 \ No newline at end of file diff --git a/data.py b/data.py new file mode 100644 index 0000000..fa6f899 --- /dev/null +++ b/data.py @@ -0,0 +1,2 @@ +TEST_EMAIL = "EvaWunder@yandex.ru" +TEST_PASSWORD = "parol123" \ No newline at end of file diff --git a/locators.py b/locators.py new file mode 100644 index 0000000..2a67461 --- /dev/null +++ b/locators.py @@ -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") \ No newline at end of file diff --git a/tests/test_constructor.py b/tests/test_constructor.py new file mode 100644 index 0000000..ccd2b92 --- /dev/null +++ b/tests/test_constructor.py @@ -0,0 +1,37 @@ +from selenium.webdriver.support import expected_conditions as EC +from locators import Locators +from config import BASE_URL + + +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", "..") + + assert "current" in parent.get_attribute("class") \ No newline at end of file diff --git a/tests/test_login.py b/tests/test_login.py new file mode 100644 index 0000000..d21f288 --- /dev/null +++ b/tests/test_login.py @@ -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): + 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) \ No newline at end of file diff --git a/tests/test_logout.py b/tests/test_logout.py new file mode 100644 index 0000000..1a59b60 --- /dev/null +++ b/tests/test_logout.py @@ -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 \ No newline at end of file diff --git a/tests/test_navigation.py b/tests/test_navigation.py new file mode 100644 index 0000000..8cfaa9a --- /dev/null +++ b/tests/test_navigation.py @@ -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)) + + 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 \ No newline at end of file diff --git a/tests/test_registration.py b/tests/test_registration.py new file mode 100644 index 0000000..25bdc3d --- /dev/null +++ b/tests/test_registration.py @@ -0,0 +1,78 @@ +from selenium.webdriver.support import expected_conditions as EC +from locators import Locators +from config import BASE_URL +import pytest +import random + + +class TestRegistration: + + def test_register_user(self, driver, wait, random_user): + email, password = random_user + + 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.visibility_of_element_located(Locators.REGISTER_NAME_INPUT) + ).send_keys("Eva Test") + + wait.until( + EC.visibility_of_element_located(Locators.REGISTER_EMAIL_INPUT) + ).send_keys(email) + + wait.until( + EC.visibility_of_element_located(Locators.REGISTER_PASSWORD_INPUT) + ).send_keys(password) + + wait.until( + EC.element_to_be_clickable(Locators.REGISTER_BUTTON) + ).click() + + login_button = wait.until( + EC.visibility_of_element_located(Locators.LOGIN_BUTTON) + ) + + assert login_button.is_displayed() + + def test_register_with_invalid_password(self, driver, wait, random_user): + email, _ = random_user + + 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.visibility_of_element_located(Locators.REGISTER_NAME_INPUT) + ).send_keys("Eva Test") + + wait.until( + EC.visibility_of_element_located(Locators.REGISTER_EMAIL_INPUT) + ).send_keys(email) + + wait.until( + EC.visibility_of_element_located(Locators.REGISTER_PASSWORD_INPUT) + ).send_keys("123") + + wait.until( + EC.element_to_be_clickable(Locators.REGISTER_BUTTON) + ).click() + + error = wait.until( + EC.visibility_of_element_located(Locators.PASSWORD_ERROR) + ) + + assert error.is_displayed() \ No newline at end of file