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 0f50180..27d0a0c 100644 Binary files a/README.md and b/README.md differ diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..d4308e6 --- /dev/null +++ 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/generate_email.py b/generate_email.py new file mode 100644 index 0000000..67d98e8 --- /dev/null +++ b/generate_email.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 diff --git a/locators.py b/locators.py new file mode 100644 index 0000000..9afaa99 --- /dev/null +++ b/locators.py @@ -0,0 +1,41 @@ +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(), 'Чтобы разместить объявление, авторизуйтесь')]") + 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/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/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_user_login.py b/tests/test_user_login.py new file mode 100644 index 0000000..92168a9 --- /dev/null +++ b/tests/test_user_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/test_user_logout.py b/tests/test_user_logout.py new file mode 100644 index 0000000..2f0e1a1 --- /dev/null +++ b/tests/test_user_logout.py @@ -0,0 +1,37 @@ +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from ..locators import LoginLocators, LogoutLocators +from ..user_data import UserData + +class TestLogout: + + def test_successful_logout(self, driver): + email = UserData.USER["email"] + password = UserData.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() + + 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 diff --git a/tests/test_user_registration.py b/tests/test_user_registration.py new file mode 100644 index 0000000..dcc2f9d --- /dev/null +++ b/tests/test_user_registration.py @@ -0,0 +1,36 @@ +import pytest +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from ..locators import LoginLocators, RegistrationLocators +from ..generate_email import generate_email + +class TestRegistration: + + def test_successful_registration(self, driver): + email = generate_email() + password = "test12345" + + driver.find_element(*LoginLocators.LOGIN_BUTTON).click() + WebDriverWait(driver, 10).until( + EC.element_to_be_clickable(RegistrationLocators.NO_ACCOUNT_BUTTON) + ) + driver.find_element(*RegistrationLocators.NO_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) + ) + 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 \ No newline at end of file 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..1ccfc03 --- /dev/null +++ b/user_data.py @@ -0,0 +1,16 @@ +class UserData: + + USER = { + "email": "eva1x@yandex.ru" , + "password": "test12345" , + } + + AD_DATA = { + "title": "Лучшее" , + "description": "Почти как новая" , + "price": "1 500 000" , + "category": "Авто" , + "city": "Казань" , + "condition": "new" + + } \ No newline at end of file