From 26dca6690fd49b87c18671fa38946be1ab8abeba Mon Sep 17 00:00:00 2001 From: Evgeniya Kozlova Date: Thu, 28 May 2026 02:09:00 +0400 Subject: [PATCH 1/3] =?UTF-8?q?=D0=A4=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=205=20?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 25 +++++++ README.md | Bin 420 -> 420 bytes __init__.py | 0 constants.py | 27 +++++++ locators.py | 29 ++++++++ requirements.txt | 1 + tests/__init__.py | 1 + tests/conftest.py | 10 +++ tests/login.py | 29 ++++++++ tests/logout.py | 40 ++++++++++ tests/registration_page.py | 41 +++++++++++ tests/test_creating_authorized_user.py | 89 +++++++++++++++++++++++ tests/test_creating_unauthorized_user.py | 14 ++++ tests/test_data.py | 20 +++++ tests/test_registration.py | 63 ++++++++++++++++ tests/utils.py | 7 ++ 16 files changed, 396 insertions(+) create mode 100644 .gitignore create mode 100644 __init__.py create mode 100644 constants.py create mode 100644 locators.py create mode 100644 requirements.txt create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/login.py create mode 100644 tests/logout.py create mode 100644 tests/registration_page.py create mode 100644 tests/test_creating_authorized_user.py create mode 100644 tests/test_creating_unauthorized_user.py create mode 100644 tests/test_data.py create mode 100644 tests/test_registration.py create mode 100644 tests/utils.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb0f128 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Virtual Environment +venv/ +env/ +ENV/ + +# IDE +.idea/ +.vscode/ +*.iml + +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# OS +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/README.md b/README.md index 0f5018001061eb7ab7f746a9ae67d2596297408d..27d0a0c6a863ba5a8d828c7154461757db5e49a5 100644 GIT binary patch delta 14 VcmZ3&yo7mz$mDs9Y#XJz7y%@Q1c3km delta 12 TcmZ3&yo7mz2&3^v(SAk%7?T5i diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..b9d4aac --- /dev/null +++ b/constants.py @@ -0,0 +1,27 @@ +BASE_URLS = { + "prod": "https://qa-desk.education-services.ru/", + "staging": "https://staging.qa-desk.education-services.ru/", + "dev": "http://localhost:3000/", + "qa": "https://qa.qa-desk.education-services.ru/" +} + + +CURRENT_ENV = "prod" +BASE_URL = BASE_URLS[CURRENT_ENV] + + +ENDPOINTS = { + "login": "/login", + "dashboard": "/dashboard", + "ads": "/ads", + "profile": "/profile", + "api_users": "/api/v1/users", + "api_ads": "/api/v1/ads" +} + +FULL_URLS = { + "login": BASE_URL + ENDPOINTS["login"], + "dashboard": BASE_URL + ENDPOINTS["dashboard"], + "ads": BASE_URL + ENDPOINTS["ads"], + "profile": BASE_URL + ENDPOINTS["profile"] + } diff --git a/locators.py b/locators.py new file mode 100644 index 0000000..ebf73bf --- /dev/null +++ b/locators.py @@ -0,0 +1,29 @@ +from selenium.webdriver.common.by import By + + +class LoginLocators: + LOGIN_BUTTON = (By.XPATH, "//button[contains(text(), 'Вход и регистрация')]") + EMAIL_INPUT = (By.CSS_SELECTOR, "input[placeholder='Введите Email']") + PASSWORD_INPUT = (By.CSS_SELECTOR, "input[placeholder='Пароль']") + SUBMIT_BUTTON = (By.XPATH, "//button[contains(text(), 'Войти')]") + USER_AVATAR = (By.CLASS_NAME, "circleSmall") + USER_NAME = (By.CLASS_NAME, "profileText") + POST_AD_BUTTON = (By.XPATH, "//button[contains(text(), 'Разместить объявление')]") + + +class RegistrationLocators: + NO_ACCOUNT_BUTTON = (By.XPATH, "//button[contains(text(), 'Нет аккаунта')]") + EMAIL_INPUT = (By.CSS_SELECTOR, "input[placeholder='Введите Email']") + PASSWORD_INPUT = (By.CSS_SELECTOR, "input[placeholder='Пароль']") + CONFIRM_PASSWORD_INPUT = (By.CSS_SELECTOR, "input[placeholder='Повторите пароль']") + CREATE_ACCOUNT_BUTTON = (By.XPATH, "//button[contains(text(), 'Создать аккаунт')]") + + + +class LogoutLocators: + LOGOUT_BUTTON = (By.XPATH, "//button[contains(text(), 'Выйти')]") + LOGIN_BUTTON = (By.XPATH, "//button[contains(text(), 'Вход и регистрация')]") + + +class AdCreationLocators: + MODAL_TITLE = (By.XPATH, "//h1[contains(text(), 'Чтобы разместить объявление, авторизуйтесь')]") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..bc5095a --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +### `requirements.txt` \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..d4308e6 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# tests package \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..e46f766 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,10 @@ +import pytest +from .test_data import LoginData + +@pytest.fixture(params=LoginData.INVALID_USERS) +def invalid_user(request): + return request.param + +@pytest.fixture +def valid_user(): + return LoginData.VALID_USER \ No newline at end of file diff --git a/tests/login.py b/tests/login.py new file mode 100644 index 0000000..92168a9 --- /dev/null +++ b/tests/login.py @@ -0,0 +1,29 @@ +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from ..locators import LoginLocators + +class TestLogin: + def test_successful_login(self, driver, valid_user): + email = valid_user["email"] + password = valid_user["password"] + + driver.find_element(*LoginLocators.LOGIN_BUTTON).click() + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LoginLocators.EMAIL_INPUT) + ) + driver.find_element(*LoginLocators.EMAIL_INPUT).send_keys(email) + driver.find_element(*LoginLocators.PASSWORD_INPUT).send_keys(password) + driver.find_element(*LoginLocators.SUBMIT_BUTTON).click() + + wait = WebDriverWait(driver, 10) + + assert wait.until(EC.visibility_of_element_located(LoginLocators.POST_AD_BUTTON)), \ + "Кнопка 'Разместить объявление' не отображается после входа" + + avatar = wait.until(EC.visibility_of_element_located(LoginLocators.USER_AVATAR)) + assert avatar.is_displayed(), "Аватар пользователя не отображается" + + user_name_element = wait.until(EC.visibility_of_element_located(LoginLocators.USER_NAME)) + assert user_name_element.is_displayed(), "Имя пользователя не отображается" + assert valid_user["expected_username_part"] in user_name_element.text, \ + f"Имя пользователя не содержит '{valid_user['expected_username_part']}', фактическое: '{user_name_element.text}'" \ No newline at end of file diff --git a/tests/logout.py b/tests/logout.py new file mode 100644 index 0000000..de7fb86 --- /dev/null +++ b/tests/logout.py @@ -0,0 +1,40 @@ +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import TimeoutException +from ..locators import LoginLocators, LogoutLocators + +class TestLogout: + + def test_successful_logout(self, driver): + email = "evgeniya_kozlova_1995@mail.ru" + password = "12356" + + driver.find_element(*LoginLocators.LOGIN_BUTTON).click() + try: + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LoginLocators.EMAIL_INPUT) + ) + driver.find_element(*LoginLocators.EMAIL_INPUT).send_keys(email) + driver.find_element(*LoginLocators.PASSWORD_INPUT).send_keys(password) + driver.find_element(*LoginLocators.SUBMIT_BUTTON).click() + + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LogoutLocators.LOGOUT_BUTTON) + ) + + driver.find_element(*LogoutLocators.LOGOUT_BUTTON).click() + + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LogoutLocators.LOGIN_BUTTON) + ) + except TimeoutException as e: + raise AssertionError(f"Timeout while waiting for element: {e}") + + avatars = driver.find_elements(*LoginLocators.USER_AVATAR) + user_names = driver.find_elements(*LoginLocators.USER_NAME) + login_button = driver.find_element(*LogoutLocators.LOGIN_BUTTON) + + assert len(avatars) == 0, "Аватар пользователя всё ещё отображается" + assert len(user_names) == 0, "Имя пользователя всё ещё отображается" + assert login_button.is_displayed(), "Кнопка входа не отображается" + assert "Вход и регистрация" in login_button.text, "Текст кнопки входа не соответствует ожидаемому" \ No newline at end of file diff --git a/tests/registration_page.py b/tests/registration_page.py new file mode 100644 index 0000000..82b4300 --- /dev/null +++ b/tests/registration_page.py @@ -0,0 +1,41 @@ +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from ..locators import LoginLocators, RegistrationLocators + +class RegistrationPage: + def __init__(self, driver): + self.driver = driver + self.wait = WebDriverWait(driver, 10) + + def go_to_registration(self): + + self.driver.find_element(*LoginLocators.LOGIN_BUTTON).click() + self.wait.until( + EC.element_to_be_clickable(RegistrationLocators.NO_ACCOUNT_BUTTON) + ) + self.driver.find_element(*RegistrationLocators.NO_ACCOUNT_BUTTON).click() + + def fill_registration_form(self, email, password): + + self.driver.find_element(*RegistrationLocators.EMAIL_INPUT).send_keys(email) + self.driver.find_element(*RegistrationLocators.PASSWORD_INPUT).send_keys(password) + self.driver.find_element(*RegistrationLocators.CONFIRM_PASSWORD_INPUT).send_keys(password) + + def submit_registration(self): + + self.driver.find_element(*RegistrationLocators.CREATE_ACCOUNT_BUTTON).click() + + def wait_for_registration_completion(self): + + self.wait.until( + EC.presence_of_element_located(LoginLocators.POST_AD_BUTTON) + ) + self.wait.until( + EC.presence_of_element_located(LoginLocators.USER_AVATAR) + ) + + def get_user_avatar(self): + return self.driver.find_element(*LoginLocators.USER_AVATAR) + + def get_user_name(self): + return self.driver.find_element(*LoginLocators.USER_NAME) diff --git a/tests/test_creating_authorized_user.py b/tests/test_creating_authorized_user.py new file mode 100644 index 0000000..7de2064 --- /dev/null +++ b/tests/test_creating_authorized_user.py @@ -0,0 +1,89 @@ +import pytest +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import TimeoutException +from locators import LOGIN, AD_CREATION + +def create_ad(driver, email, password, title, description, price, category, city, condition): + wait = WebDriverWait(driver, 10) + + login_button = wait.until(EC.element_to_be_clickable(LOGIN['login_button'])) + login_button.click() + + email_input = wait.until(EC.visibility_of_element_located(LOGIN['email_input'])) + email_input.send_keys(email) + + password_input = driver.find_element(*LOGIN['password_input']) + password_input.send_keys(password) + + submit_button = driver.find_element(*LOGIN['submit_button']) + submit_button.click() + + wait.until(EC.visibility_of_element_located(LOGIN['user_avatar'])) + + post_ad_button = wait.until(EC.element_to_be_clickable(LOGIN['post_ad_button'])) + post_ad_button.click() + + title_input = wait.until(EC.visibility_of_element_located(AD_CREATION['title_input'])) + title_input.send_keys(title) + + description_input = driver.find_element(*AD_CREATION['description_input']) + description_input.send_keys(description) + + price_input = driver.find_element(*AD_CREATION['price_input']) + price_input.send_keys(str(price)) + + category_dropdown = driver.find_element(*AD_CREATION['category_dropdown']) + category_option = category_dropdown.find_element(By.XPATH, f".//option[@value='{category}']") + category_option.click() + + city_dropdown = driver.find_element(*AD_CREATION['city_dropdown']) + city_option = city_dropdown.find_element(By.XPATH, f".//option[@value='{city}']") + city_option.click() + + condition_radio = driver.find_elements(*AD_CREATION['condition_radio']) + for radio in condition_radio: + if radio.get_attribute("value") == condition: + radio.click() + break + + + publish_button = driver.find_element(*AD_CREATION['publish_button']) + publish_button.click() + + + user_avatar = wait.until(EC.element_to_be_clickable(LOGIN['user_avatar'])) + user_avatar.click() + + + my_ads_section = wait.until(EC.visibility_of_element_located(AD_CREATION['my_ads_section'])) + ad_titles = my_ads_section.find_elements(*AD_CREATION['ad_title_in_list']) + ad_found = any(title in ad.text for ad in ad_titles) + + assert ad_found, f"Объявление с названием '{title}' не найдено в списке 'Мои объявления'" + print(f"Объявление '{title}' успешно создано и отображается в профиле.") + +class TestCreateAdvertisement: + def test_create_advertisement_authorized_user(self, driver): + + email = "evgeniya_kozlova_1995@mail.ru" + password = "123456" + ad_title = "Тестовый товар для продажи" + + try: + create_ad( + driver=driver, + email=email, + password=password, + title=ad_title, + description="Подробное описание тестового товара", + price=5000, + category="Авто", + city="Москва", + condition="Новый" + ) + except TimeoutException as e: + pytest.fail(f"Превышение времени ожидания: {e}") + except Exception as e: + pytest.fail(f"Ошибка при выполнении теста: {e}") + \ No newline at end of file diff --git a/tests/test_creating_unauthorized_user.py b/tests/test_creating_unauthorized_user.py new file mode 100644 index 0000000..50a69d3 --- /dev/null +++ b/tests/test_creating_unauthorized_user.py @@ -0,0 +1,14 @@ +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from ..locators import LoginLocators, AdCreationLocators + +class TestAdCreation: + def test_create_ad_unauthorized(self, driver): + driver.find_element(*LoginLocators.POST_AD_BUTTON).click() + + wait = WebDriverWait(driver, 5) + modal_title = wait.until(EC.visibility_of_element_located(AdCreationLocators.MODAL_TITLE)) + + assert modal_title.is_displayed() and "Чтобы разместить объявление, авторизуйтесь" in modal_title.text, \ + "Модальное окно не отображается или содержит неверный текст" \ No newline at end of file diff --git a/tests/test_data.py b/tests/test_data.py new file mode 100644 index 0000000..4638262 --- /dev/null +++ b/tests/test_data.py @@ -0,0 +1,20 @@ + +VALID_USER = { + "email": "evgeniya_kozlova_1995@mail.ru", + "password": "123456" +} + +INVALID_USER = { + "email": "invalid@example.com", + "password": "wrongpass" +} + +EMPTY_CREDENTIALS = { + "email": "", + "password": "" +} + +SPECIAL_CHAR_USER = { + "email": "test+user@domain.com", + "password": "Pass@123!" + } \ No newline at end of file diff --git a/tests/test_registration.py b/tests/test_registration.py new file mode 100644 index 0000000..81c9001 --- /dev/null +++ b/tests/test_registration.py @@ -0,0 +1,63 @@ +import pytest +import time +import random +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from ..locators import LoginLocators, RegistrationLocators # Предполагается, что locators.py существует + + +class TestRegistration: + + TEST_PASSWORD = "Test123456" + + @staticmethod + def generate_email(): + + timestamp = int(time.time() * 1000) + random_num = random.randint(1, 9999) + return f"testuser_{timestamp}_{random_num}@example.com" + + def test_successful_registration(self, driver): + + email = self.generate_email() + password = self.TEST_PASSWORD + + login_button = WebDriverWait(driver, 10).until( + EC.element_to_be_clickable(LoginLocators.LOGIN_BUTTON) + ) + login_button.click() + + no_account_button = WebDriverWait(driver, 10).until( + EC.element_to_be_clickable(RegistrationLocators.NO_ACCOUNT_BUTTON) + ) + no_account_button.click() + + email_input = WebDriverWait(driver, 10).until( + EC.presence_of_element_located(RegistrationLocators.EMAIL_INPUT) + ) + email_input.send_keys(email) + + password_input = driver.find_element(*RegistrationLocators.PASSWORD_INPUT) + password_input.send_keys(password) + + confirm_password_input = driver.find_element(*RegistrationLocators.CONFIRM_PASSWORD_INPUT) + confirm_password_input.send_keys(password) + create_account_button = driver.find_element(*RegistrationLocators.CREATE_ACCOUNT_BUTTON) + create_account_button.click() + + + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LoginLocators.POST_AD_BUTTON), + "Кнопка 'Post Ad' не появилась после регистрации" + ) + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LoginLocators.USER_AVATAR), + "Аватар пользователя не появился после регистрации" + ) + + avatar = driver.find_element(*LoginLocators.USER_AVATAR) + user_name = driver.find_element(*LoginLocators.USER_NAME) + + assert avatar.is_displayed(), "Аватар пользователя не отображается" + assert user_name.is_displayed(), "Имя пользователя не отображается" + assert "User" in user_name.text, f"Ожидалось 'User' в тексте имени пользователя, получено: {user_name.text}" \ No newline at end of file diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..67d98e8 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,7 @@ +import time +import random + +def generate_email(): + timestamp = int(time.time() * 1000) + random_num = random.randint(1, 9999) + return f"testuser_{timestamp}_{random_num}@example.com" \ No newline at end of file From f7499886315f8a0e2ab8e23aaeb280e644fc7fe8 Mon Sep 17 00:00:00 2001 From: Evgeniya Kozlova Date: Sun, 7 Jun 2026 12:30:31 +0400 Subject: [PATCH 2/3] =?UTF-8?q?=D0=A4=D0=B8=D0=BD=D0=B0=D1=81=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B9=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=205?= =?UTF-8?q?=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __init__.py | 1 + conftest.py | 14 +++ constants.py | 27 ------ tests/utils.py => generate_email.py | 0 locators.py | 14 ++- tests/conftest.py | 10 --- tests/registration_page.py | 41 --------- tests/test_creating_an_ad.py | 62 +++++++++++++ tests/test_creating_authorized_user.py | 89 ------------------- tests/test_creating_unauthorized_user.py | 14 --- tests/test_data.py | 20 ----- tests/{login.py => test_user_login.py} | 0 tests/{logout.py => test_user_logout.py} | 0 ...istration.py => test_user_registration.py} | 0 urls.py | 4 + user_data.py | 16 ++++ 16 files changed, 110 insertions(+), 202 deletions(-) create mode 100644 conftest.py delete mode 100644 constants.py rename tests/utils.py => generate_email.py (100%) delete mode 100644 tests/conftest.py delete mode 100644 tests/registration_page.py create mode 100644 tests/test_creating_an_ad.py delete mode 100644 tests/test_creating_authorized_user.py delete mode 100644 tests/test_creating_unauthorized_user.py delete mode 100644 tests/test_data.py rename tests/{login.py => test_user_login.py} (100%) rename tests/{logout.py => test_user_logout.py} (100%) rename tests/{test_registration.py => test_user_registration.py} (100%) create mode 100644 urls.py create mode 100644 user_data.py diff --git a/__init__.py b/__init__.py index e69de29..d4308e6 100644 --- a/__init__.py +++ b/__init__.py @@ -0,0 +1 @@ +# tests package \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..b195f84 --- /dev/null +++ b/conftest.py @@ -0,0 +1,14 @@ +import pytest +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +from urls import Urls + + +@pytest.fixture(scope="function") +def driver(): + chrome_options = Options() + chrome_options.add_argument("--window-size=1920,1080") + driver = webdriver.Chrome(options=chrome_options) + driver.get(Urls.HOME_PAGE) + yield driver + driver.quit() \ No newline at end of file diff --git a/constants.py b/constants.py deleted file mode 100644 index b9d4aac..0000000 --- a/constants.py +++ /dev/null @@ -1,27 +0,0 @@ -BASE_URLS = { - "prod": "https://qa-desk.education-services.ru/", - "staging": "https://staging.qa-desk.education-services.ru/", - "dev": "http://localhost:3000/", - "qa": "https://qa.qa-desk.education-services.ru/" -} - - -CURRENT_ENV = "prod" -BASE_URL = BASE_URLS[CURRENT_ENV] - - -ENDPOINTS = { - "login": "/login", - "dashboard": "/dashboard", - "ads": "/ads", - "profile": "/profile", - "api_users": "/api/v1/users", - "api_ads": "/api/v1/ads" -} - -FULL_URLS = { - "login": BASE_URL + ENDPOINTS["login"], - "dashboard": BASE_URL + ENDPOINTS["dashboard"], - "ads": BASE_URL + ENDPOINTS["ads"], - "profile": BASE_URL + ENDPOINTS["profile"] - } diff --git a/tests/utils.py b/generate_email.py similarity index 100% rename from tests/utils.py rename to generate_email.py diff --git a/locators.py b/locators.py index ebf73bf..9afaa99 100644 --- a/locators.py +++ b/locators.py @@ -26,4 +26,16 @@ class LogoutLocators: class AdCreationLocators: - MODAL_TITLE = (By.XPATH, "//h1[contains(text(), 'Чтобы разместить объявление, авторизуйтесь')]") \ No newline at end of file + MODAL_TITLE = (By.XPATH, "//h1[contains(text(), 'Чтобы разместить объявление, авторизуйтесь')]") + POST_AD_BUTTON = (By.XPATH, "//button[contains(text(), 'Разместить объявление')]") + TITLE_INPUT = (By.CSS_SELECTOR, "input[placeholder='Название']") + DESCRIPTION_TEXTAREA = (By.CSS_SELECTOR, "textarea[placeholder='Описание товара']") + PRICE_INPUT = (By.CSS_SELECTOR, "input[placeholder='Стоимость']") + DROPDOWN_CATEGORIES = (By.XPATH, '//input[@name="category"]/following-sibling::button[contains(@class, "dropDownMenu_arrowDown__pfGL1")]') + SELECT_CATEGORIES = (By.XPATH, "//span[text()='Авто']") + CITY_DROPDOWN = (By.XPATH, '//input[@name="city"]/following-sibling::button[contains(@class, "dropDownMenu_arrowDown__pfGL1")]') + SELECT_CITY = (By.XPATH, "//span[text()='Казань']") + RADIO_BUTTON = By.XPATH, '//input[@type="radio" and @value="Б/У"]' + PUBLISH_BUTTON = (By.XPATH, "//button[contains(text(), 'Опубликовать')]") + MY_ADS_BLOCK = (By.XPATH, "//h1[contains(text(), 'Мои объявления')]") + AD_TITLE = (By.XPATH, "//div[@class='card']//h2") diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index e46f766..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,10 +0,0 @@ -import pytest -from .test_data import LoginData - -@pytest.fixture(params=LoginData.INVALID_USERS) -def invalid_user(request): - return request.param - -@pytest.fixture -def valid_user(): - return LoginData.VALID_USER \ No newline at end of file diff --git a/tests/registration_page.py b/tests/registration_page.py deleted file mode 100644 index 82b4300..0000000 --- a/tests/registration_page.py +++ /dev/null @@ -1,41 +0,0 @@ -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC -from ..locators import LoginLocators, RegistrationLocators - -class RegistrationPage: - def __init__(self, driver): - self.driver = driver - self.wait = WebDriverWait(driver, 10) - - def go_to_registration(self): - - self.driver.find_element(*LoginLocators.LOGIN_BUTTON).click() - self.wait.until( - EC.element_to_be_clickable(RegistrationLocators.NO_ACCOUNT_BUTTON) - ) - self.driver.find_element(*RegistrationLocators.NO_ACCOUNT_BUTTON).click() - - def fill_registration_form(self, email, password): - - self.driver.find_element(*RegistrationLocators.EMAIL_INPUT).send_keys(email) - self.driver.find_element(*RegistrationLocators.PASSWORD_INPUT).send_keys(password) - self.driver.find_element(*RegistrationLocators.CONFIRM_PASSWORD_INPUT).send_keys(password) - - def submit_registration(self): - - self.driver.find_element(*RegistrationLocators.CREATE_ACCOUNT_BUTTON).click() - - def wait_for_registration_completion(self): - - self.wait.until( - EC.presence_of_element_located(LoginLocators.POST_AD_BUTTON) - ) - self.wait.until( - EC.presence_of_element_located(LoginLocators.USER_AVATAR) - ) - - def get_user_avatar(self): - return self.driver.find_element(*LoginLocators.USER_AVATAR) - - def get_user_name(self): - return self.driver.find_element(*LoginLocators.USER_NAME) diff --git a/tests/test_creating_an_ad.py b/tests/test_creating_an_ad.py new file mode 100644 index 0000000..2ed9125 --- /dev/null +++ b/tests/test_creating_an_ad.py @@ -0,0 +1,62 @@ +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from ..locators import LoginLocators, AdCreationLocators +from ..user_data import UserData + +class TestAdCreation: + + def test_create_ad_unauthorized(self, driver): + + driver.find_element(*LoginLocators.POST_AD_BUTTON).click() + + wait = WebDriverWait(driver, 5) + + assert wait.until(EC.visibility_of_element_located(AdCreationLocators.MODAL_TITLE)) + + def test_create_ad_authorized(self, driver): + email = UserData.USER["email"] + password = UserData.USER["password"] + wait = WebDriverWait(driver, 10) + + driver.find_element(*LoginLocators.LOGIN_BUTTON).click() + wait.until( + EC.presence_of_element_located(LoginLocators.EMAIL_INPUT) + ) + driver.find_element(*LoginLocators.EMAIL_INPUT).send_keys(email) + driver.find_element(*LoginLocators.PASSWORD_INPUT).send_keys(password) + driver.find_element(*LoginLocators.SUBMIT_BUTTON).click() + + wait.until( + EC.visibility_of_element_located(LoginLocators.USER_AVATAR)) + driver.find_element(*AdCreationLocators.POST_AD_BUTTON).click() + + driver.find_element(*AdCreationLocators.TITLE_INPUT).send_keys(UserData.AD_DATA["title"]) + driver.find_element(*AdCreationLocators.DESCRIPTION_TEXTAREA).send_keys(UserData.AD_DATA["description"]) + driver.find_element(*AdCreationLocators.PRICE_INPUT).send_keys(UserData.AD_DATA["price"]) + + driver.find_element(*AdCreationLocators.DROPDOWN_CATEGORIES).click() + driver.find_element(*AdCreationLocators.SELECT_CATEGORIES).click() + + driver.find_element(*AdCreationLocators.CITY_DROPDOWN).click() + driver.find_element(*AdCreationLocators.SELECT_CITY).click() + + radio_button = wait.until(EC.presence_of_element_located(AdCreationLocators.RADIO_BUTTON)) + driver.execute_script("arguments[0].scrollIntoView(true);", radio_button) + driver.execute_script("arguments[0].click();", radio_button) + + driver.find_element(*AdCreationLocators.PUBLISH_BUTTON).click() + + wait.until( + EC.visibility_of_element_located(LoginLocators.USER_AVATAR)) + + driver.find_element(*LoginLocators.USER_AVATAR).click() + + + wait.until( + EC.presence_of_element_located(AdCreationLocators.MY_ADS_BLOCK)) + + ad_title_element = driver.find_element(*AdCreationLocators.AD_TITLE) + + tit = UserData.AD_DATA["title"] + assert tit in ad_title_element.text \ No newline at end of file diff --git a/tests/test_creating_authorized_user.py b/tests/test_creating_authorized_user.py deleted file mode 100644 index 7de2064..0000000 --- a/tests/test_creating_authorized_user.py +++ /dev/null @@ -1,89 +0,0 @@ -import pytest -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC -from selenium.common.exceptions import TimeoutException -from locators import LOGIN, AD_CREATION - -def create_ad(driver, email, password, title, description, price, category, city, condition): - wait = WebDriverWait(driver, 10) - - login_button = wait.until(EC.element_to_be_clickable(LOGIN['login_button'])) - login_button.click() - - email_input = wait.until(EC.visibility_of_element_located(LOGIN['email_input'])) - email_input.send_keys(email) - - password_input = driver.find_element(*LOGIN['password_input']) - password_input.send_keys(password) - - submit_button = driver.find_element(*LOGIN['submit_button']) - submit_button.click() - - wait.until(EC.visibility_of_element_located(LOGIN['user_avatar'])) - - post_ad_button = wait.until(EC.element_to_be_clickable(LOGIN['post_ad_button'])) - post_ad_button.click() - - title_input = wait.until(EC.visibility_of_element_located(AD_CREATION['title_input'])) - title_input.send_keys(title) - - description_input = driver.find_element(*AD_CREATION['description_input']) - description_input.send_keys(description) - - price_input = driver.find_element(*AD_CREATION['price_input']) - price_input.send_keys(str(price)) - - category_dropdown = driver.find_element(*AD_CREATION['category_dropdown']) - category_option = category_dropdown.find_element(By.XPATH, f".//option[@value='{category}']") - category_option.click() - - city_dropdown = driver.find_element(*AD_CREATION['city_dropdown']) - city_option = city_dropdown.find_element(By.XPATH, f".//option[@value='{city}']") - city_option.click() - - condition_radio = driver.find_elements(*AD_CREATION['condition_radio']) - for radio in condition_radio: - if radio.get_attribute("value") == condition: - radio.click() - break - - - publish_button = driver.find_element(*AD_CREATION['publish_button']) - publish_button.click() - - - user_avatar = wait.until(EC.element_to_be_clickable(LOGIN['user_avatar'])) - user_avatar.click() - - - my_ads_section = wait.until(EC.visibility_of_element_located(AD_CREATION['my_ads_section'])) - ad_titles = my_ads_section.find_elements(*AD_CREATION['ad_title_in_list']) - ad_found = any(title in ad.text for ad in ad_titles) - - assert ad_found, f"Объявление с названием '{title}' не найдено в списке 'Мои объявления'" - print(f"Объявление '{title}' успешно создано и отображается в профиле.") - -class TestCreateAdvertisement: - def test_create_advertisement_authorized_user(self, driver): - - email = "evgeniya_kozlova_1995@mail.ru" - password = "123456" - ad_title = "Тестовый товар для продажи" - - try: - create_ad( - driver=driver, - email=email, - password=password, - title=ad_title, - description="Подробное описание тестового товара", - price=5000, - category="Авто", - city="Москва", - condition="Новый" - ) - except TimeoutException as e: - pytest.fail(f"Превышение времени ожидания: {e}") - except Exception as e: - pytest.fail(f"Ошибка при выполнении теста: {e}") - \ No newline at end of file diff --git a/tests/test_creating_unauthorized_user.py b/tests/test_creating_unauthorized_user.py deleted file mode 100644 index 50a69d3..0000000 --- a/tests/test_creating_unauthorized_user.py +++ /dev/null @@ -1,14 +0,0 @@ -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.common.by import By -from selenium.webdriver.support import expected_conditions as EC -from ..locators import LoginLocators, AdCreationLocators - -class TestAdCreation: - def test_create_ad_unauthorized(self, driver): - driver.find_element(*LoginLocators.POST_AD_BUTTON).click() - - wait = WebDriverWait(driver, 5) - modal_title = wait.until(EC.visibility_of_element_located(AdCreationLocators.MODAL_TITLE)) - - assert modal_title.is_displayed() and "Чтобы разместить объявление, авторизуйтесь" in modal_title.text, \ - "Модальное окно не отображается или содержит неверный текст" \ No newline at end of file diff --git a/tests/test_data.py b/tests/test_data.py deleted file mode 100644 index 4638262..0000000 --- a/tests/test_data.py +++ /dev/null @@ -1,20 +0,0 @@ - -VALID_USER = { - "email": "evgeniya_kozlova_1995@mail.ru", - "password": "123456" -} - -INVALID_USER = { - "email": "invalid@example.com", - "password": "wrongpass" -} - -EMPTY_CREDENTIALS = { - "email": "", - "password": "" -} - -SPECIAL_CHAR_USER = { - "email": "test+user@domain.com", - "password": "Pass@123!" - } \ No newline at end of file diff --git a/tests/login.py b/tests/test_user_login.py similarity index 100% rename from tests/login.py rename to tests/test_user_login.py diff --git a/tests/logout.py b/tests/test_user_logout.py similarity index 100% rename from tests/logout.py rename to tests/test_user_logout.py diff --git a/tests/test_registration.py b/tests/test_user_registration.py similarity index 100% rename from tests/test_registration.py rename to tests/test_user_registration.py diff --git a/urls.py b/urls.py new file mode 100644 index 0000000..d0d6960 --- /dev/null +++ b/urls.py @@ -0,0 +1,4 @@ +class Urls: + URL = "https://qa-desk.education-services.ru" + + HOME_PAGE = URL + "/" \ No newline at end of file diff --git a/user_data.py b/user_data.py new file mode 100644 index 0000000..22c14f4 --- /dev/null +++ b/user_data.py @@ -0,0 +1,16 @@ +class UserData: + + USER = { + "email": "eva1x@yandex.ru" , + "password": "Test123456" , + } + + AD_DATA = { + "title": "Лучшее" , + "description": "Почти как новая" , + "price": "1 500 000" , + "category": "Авто" , + "city": "Казань" , + "condition": "new" + + } \ No newline at end of file From bc419fb5624b2f2e97aa21ea6279a5a95124b07e Mon Sep 17 00:00:00 2001 From: Evgeniya Kozlova Date: Tue, 9 Jun 2026 00:36:24 +0400 Subject: [PATCH 3/3] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE=D0=B4=205=20?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_user_logout.py | 57 +++++++++++++++---------------- tests/test_user_registration.py | 59 +++++++++------------------------ user_data.py | 2 +- 3 files changed, 44 insertions(+), 74 deletions(-) diff --git a/tests/test_user_logout.py b/tests/test_user_logout.py index de7fb86..2f0e1a1 100644 --- a/tests/test_user_logout.py +++ b/tests/test_user_logout.py @@ -1,40 +1,37 @@ from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC -from selenium.common.exceptions import TimeoutException from ..locators import LoginLocators, LogoutLocators +from ..user_data import UserData class TestLogout: - + def test_successful_logout(self, driver): - email = "evgeniya_kozlova_1995@mail.ru" - password = "12356" - + email = UserData.USER["email"] + password = UserData.USER["password"] + driver.find_element(*LoginLocators.LOGIN_BUTTON).click() - try: - WebDriverWait(driver, 10).until( - EC.presence_of_element_located(LoginLocators.EMAIL_INPUT) - ) - driver.find_element(*LoginLocators.EMAIL_INPUT).send_keys(email) - driver.find_element(*LoginLocators.PASSWORD_INPUT).send_keys(password) - driver.find_element(*LoginLocators.SUBMIT_BUTTON).click() - - WebDriverWait(driver, 10).until( - EC.presence_of_element_located(LogoutLocators.LOGOUT_BUTTON) - ) - - driver.find_element(*LogoutLocators.LOGOUT_BUTTON).click() - - WebDriverWait(driver, 10).until( - EC.presence_of_element_located(LogoutLocators.LOGIN_BUTTON) - ) - except TimeoutException as e: - raise AssertionError(f"Timeout while waiting for element: {e}") - + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LoginLocators.EMAIL_INPUT) + ) + driver.find_element(*LoginLocators.EMAIL_INPUT).send_keys(email) + driver.find_element(*LoginLocators.PASSWORD_INPUT).send_keys(password) + driver.find_element(*LoginLocators.SUBMIT_BUTTON).click() + + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LogoutLocators.LOGOUT_BUTTON) + ) + + driver.find_element(*LogoutLocators.LOGOUT_BUTTON).click() + + WebDriverWait(driver, 10).until( + EC.presence_of_element_located(LogoutLocators.LOGIN_BUTTON) + ) + avatars = driver.find_elements(*LoginLocators.USER_AVATAR) user_names = driver.find_elements(*LoginLocators.USER_NAME) login_button = driver.find_element(*LogoutLocators.LOGIN_BUTTON) - - assert len(avatars) == 0, "Аватар пользователя всё ещё отображается" - assert len(user_names) == 0, "Имя пользователя всё ещё отображается" - assert login_button.is_displayed(), "Кнопка входа не отображается" - assert "Вход и регистрация" in login_button.text, "Текст кнопки входа не соответствует ожидаемому" \ No newline at end of file + + assert len(avatars) == 0 + assert len(user_names) == 0 + assert login_button.is_displayed() + assert "Вход и регистрация" in login_button.text \ No newline at end of file diff --git a/tests/test_user_registration.py b/tests/test_user_registration.py index 81c9001..dcc2f9d 100644 --- a/tests/test_user_registration.py +++ b/tests/test_user_registration.py @@ -1,63 +1,36 @@ import pytest -import time -import random from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC -from ..locators import LoginLocators, RegistrationLocators # Предполагается, что locators.py существует - +from ..locators import LoginLocators, RegistrationLocators +from ..generate_email import generate_email class TestRegistration: - TEST_PASSWORD = "Test123456" - - @staticmethod - def generate_email(): - - timestamp = int(time.time() * 1000) - random_num = random.randint(1, 9999) - return f"testuser_{timestamp}_{random_num}@example.com" - def test_successful_registration(self, driver): - - email = self.generate_email() - password = self.TEST_PASSWORD - - login_button = WebDriverWait(driver, 10).until( - EC.element_to_be_clickable(LoginLocators.LOGIN_BUTTON) - ) - login_button.click() + email = generate_email() + password = "test12345" - no_account_button = WebDriverWait(driver, 10).until( + driver.find_element(*LoginLocators.LOGIN_BUTTON).click() + WebDriverWait(driver, 10).until( EC.element_to_be_clickable(RegistrationLocators.NO_ACCOUNT_BUTTON) ) - no_account_button.click() - - email_input = WebDriverWait(driver, 10).until( - EC.presence_of_element_located(RegistrationLocators.EMAIL_INPUT) - ) - email_input.send_keys(email) - - password_input = driver.find_element(*RegistrationLocators.PASSWORD_INPUT) - password_input.send_keys(password) + driver.find_element(*RegistrationLocators.NO_ACCOUNT_BUTTON).click() - confirm_password_input = driver.find_element(*RegistrationLocators.CONFIRM_PASSWORD_INPUT) - confirm_password_input.send_keys(password) - create_account_button = driver.find_element(*RegistrationLocators.CREATE_ACCOUNT_BUTTON) - create_account_button.click() + driver.find_element(*RegistrationLocators.EMAIL_INPUT).send_keys(email) + driver.find_element(*RegistrationLocators.PASSWORD_INPUT).send_keys(password) + driver.find_element(*RegistrationLocators.CONFIRM_PASSWORD_INPUT).send_keys(password) + driver.find_element(*RegistrationLocators.CREATE_ACCOUNT_BUTTON).click() - WebDriverWait(driver, 10).until( - EC.presence_of_element_located(LoginLocators.POST_AD_BUTTON), - "Кнопка 'Post Ad' не появилась после регистрации" + EC.presence_of_element_located(LoginLocators.POST_AD_BUTTON) ) WebDriverWait(driver, 10).until( - EC.presence_of_element_located(LoginLocators.USER_AVATAR), - "Аватар пользователя не появился после регистрации" + EC.presence_of_element_located(LoginLocators.USER_AVATAR) ) avatar = driver.find_element(*LoginLocators.USER_AVATAR) user_name = driver.find_element(*LoginLocators.USER_NAME) - assert avatar.is_displayed(), "Аватар пользователя не отображается" - assert user_name.is_displayed(), "Имя пользователя не отображается" - assert "User" in user_name.text, f"Ожидалось 'User' в тексте имени пользователя, получено: {user_name.text}" \ No newline at end of file + assert avatar.is_displayed() + assert user_name.is_displayed() + assert "User" in user_name.text \ No newline at end of file diff --git a/user_data.py b/user_data.py index 22c14f4..1ccfc03 100644 --- a/user_data.py +++ b/user_data.py @@ -2,7 +2,7 @@ class UserData: USER = { "email": "eva1x@yandex.ru" , - "password": "Test123456" , + "password": "test12345" , } AD_DATA = {