-
Notifications
You must be signed in to change notification settings - Fork 0
diplom 3 #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
diplom 3 #6
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| .venv | ||
| .idea |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import pytest | ||
| from selenium import webdriver | ||
| from selenium.webdriver.common.by import By | ||
| from selenium.webdriver.support import expected_conditions | ||
| from selenium.webdriver.support.wait import WebDriverWait | ||
| from urls.urls import REGISTER_URL, LOGIN_URL, BASE_URL | ||
| from faker import Faker | ||
|
|
||
| ANY_INPUT_LOCATOR = ".//main//form//input" | ||
| EMAIL_OR_NAME_LOCATOR = ".//main//form//input[@name='name']" | ||
| PASSWORD_LOCATOR = ".//main//form//input[@name='Пароль']" | ||
| REGISTER_BUTTON_LOCATOR = ".//main//form/button" | ||
| EMAIL_LOCATOR = ".//main//form//input[@name='name']" | ||
| LOGIN_BUTTON_LOCATOR = ".//button[text()='Войти']" | ||
|
Comment on lines
+9
to
+14
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: здесь и далее: локаторы должны быть записаны в переменные и хранится отдельно от тестов в модуле locators для удобства дальнейшего переиспользования. |
||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def random_email(): | ||
| return Faker().email() | ||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def random_password(): | ||
| return Faker().password() | ||
|
Comment on lines
+17
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: фикстуры не занимаются прокидыванием данных в тест и выполнением примитивной логики, они выполняют сложную логику предусловий\постусловий. Эти методы необходимо описать в модуле helpers и оттуда вызывать в тестах и методах |
||
|
|
||
|
|
||
| @pytest.fixture(params=["chrome"]) | ||
| def driver(request): | ||
| browser = request.param | ||
| if browser == "chrome": | ||
| driver = webdriver.Chrome() | ||
| elif browser == "firefox": | ||
| driver = webdriver.Firefox() | ||
| else: | ||
| raise ValueError() | ||
| yield driver | ||
| driver.quit() | ||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def driver_registered(driver, random_email, random_password): | ||
| driver.get(REGISTER_URL) | ||
| WebDriverWait(driver, 3).until( | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: здесь и далее: в тестах, фисктурах и методах пейджей не должно быть обращений к драйверу и использований WebdriverWait. Все подобные реализации должны находиться в рамках базового класса пейджей. |
||
| expected_conditions.visibility_of_element_located((By.XPATH, ANY_INPUT_LOCATOR))) | ||
| for input_element in driver.find_elements(By.XPATH, EMAIL_OR_NAME_LOCATOR): | ||
| input_element.send_keys(random_email) | ||
| driver.find_element(By.XPATH, PASSWORD_LOCATOR).send_keys(random_password) | ||
| WebDriverWait(driver, 3).until( | ||
| expected_conditions.visibility_of_element_located((By.XPATH, ANY_INPUT_LOCATOR))) | ||
| driver.find_element(By.XPATH, REGISTER_BUTTON_LOCATOR).click() | ||
| WebDriverWait(driver, 3).until( | ||
| expected_conditions.url_to_be(LOGIN_URL)) | ||
| yield driver | ||
| driver.quit() | ||
|
Comment on lines
+53
to
+54
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: здесь и далее: закрытие драйвера должно происходить в фикстуре, где инициализируется драйвер |
||
|
|
||
|
|
||
| @pytest.fixture() | ||
| def driver_logged_in(driver_registered, random_email, random_password): | ||
| driver_registered.get(LOGIN_URL) | ||
| WebDriverWait(driver_registered, 3).until( | ||
| expected_conditions.url_to_be(LOGIN_URL)) | ||
| driver_registered.find_element(By.XPATH, EMAIL_LOCATOR).send_keys(random_email) | ||
| driver_registered.find_element(By.XPATH, PASSWORD_LOCATOR).send_keys(random_password) | ||
| driver_registered.find_element(By.XPATH, LOGIN_BUTTON_LOCATOR).click() | ||
| WebDriverWait(driver_registered, 3).until( | ||
| expected_conditions.url_to_be(BASE_URL)) | ||
| yield driver_registered | ||
| driver_registered.quit() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| from selenium.webdriver.support import expected_conditions | ||
| from selenium.webdriver.support.wait import WebDriverWait | ||
| from selenium.webdriver.common.action_chains import ActionChains | ||
| import allure | ||
| from urls.urls import LOGIN_URL, FORGOT_PASSWORD_URL, BASE_URL | ||
|
|
||
|
|
||
| class BasePage: | ||
|
|
||
| def __init__(self, driver): | ||
| self.driver = driver | ||
|
|
||
| @allure.step('Скролл до нужного элемента') | ||
| def scroll_to(self, element): | ||
| self.driver.execute_script("arguments[0].scrollIntoView();", element) | ||
|
|
||
| @allure.step('Поиск элемента среди массива по индексу') | ||
| def find_element_by_index(self, locator, index): | ||
| return self.driver.find_elements(*locator)[index] | ||
|
|
||
| @allure.step('Поиск всех элементов') | ||
| def find_all_elements(self, locator): | ||
| return self.driver.find_elements(*locator) | ||
|
|
||
| @allure.step('Поиск элемента') | ||
| def find_element(self, locator): | ||
| return self.driver.find_element(*locator) | ||
|
|
||
| @allure.step('Перетаскивание элемента') | ||
| def drag_and_drop(self, from_element, to_element): | ||
| ActionChains(self.driver).drag_and_drop(from_element, to_element).perform() | ||
|
|
||
| @allure.step('Ожидание кликабельности элемента') | ||
| def wait_to_be_clickable(self, locator): | ||
| WebDriverWait(self.driver, 3).until( | ||
| expected_conditions.element_to_be_clickable(tuple(locator))) | ||
|
|
||
| @allure.step('Ожидание видимости элемента') | ||
| def wait_for_visibility(self, locator): | ||
| WebDriverWait(self.driver, 3).until( | ||
| expected_conditions.visibility_of_element_located(tuple(locator))) | ||
|
|
||
| @allure.step('Ожидание исчезновения элемента') | ||
| def wait_for_invisibility(self, locator): | ||
| WebDriverWait(self.driver, 3).until( | ||
| expected_conditions.invisibility_of_element_located(tuple(locator))) | ||
|
|
||
| @allure.step('Ожидание смены URL') | ||
| def wait_for_url_change(self, url): | ||
| WebDriverWait(self.driver, 3).until( | ||
| expected_conditions.url_to_be(url)) | ||
|
|
||
| @allure.step('Открытие страницы логина') | ||
| def open_login_page(self): | ||
| self.driver.get(LOGIN_URL) | ||
| self.wait_for_url_change(LOGIN_URL) | ||
|
|
||
| @allure.step('Открытие страницы восстановления пароля') | ||
| def open_forgot_password_page(self): | ||
| self.driver.get(FORGOT_PASSWORD_URL) | ||
| self.wait_for_url_change(FORGOT_PASSWORD_URL) | ||
|
|
||
| @allure.step('Открытие страницы конструктора') | ||
| def open_main_page(self): | ||
| self.driver.get(BASE_URL) | ||
| self.wait_for_url_change(BASE_URL) | ||
|
|
||
|
Comment on lines
+53
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: эти методы необходимо разместить в соответствующих пейджах а не в base |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| from selenium.webdriver.common.by import By | ||
| import allure | ||
| from urls.urls import BASE_URL | ||
| from pages.base_page import BasePage | ||
|
|
||
|
|
||
| class ConstructorPage(BasePage): | ||
|
|
||
| constructor_link = (By.XPATH, ".//p[text()='Конструктор']//parent::a[@href='/']") | ||
| ingredient_link = (By.XPATH, ".//a[starts-with(@href,'/ingredient')]") | ||
| ingredient_counter = (By.XPATH, ".//p[starts-with(@class,'counter_counter__num')]") | ||
| close_ingredient_modal = (By.XPATH, ".//h2[text()='Детали ингредиента']/parent::div/following-sibling::button") | ||
| basket_element = (By.XPATH, ".//ul[starts-with(@class,'BurgerConstructor_basket')]") | ||
| create_order_button = (By.XPATH, ".//button[text()='Оформить заказ']") | ||
| order_id_header = (By.XPATH, ".//h2[starts-with(@class, 'Modal_modal__title')]") | ||
|
|
||
| @allure.step('Открытие страницы конструктора') | ||
| def click_to_open_constructor_page(self): | ||
| self.wait_to_be_clickable(self.constructor_link) | ||
| self.find_element(self.constructor_link).click() | ||
| self.wait_for_url_change(BASE_URL) | ||
|
|
||
| @allure.step('Проверка открытия страницы конструктора') | ||
| def check_constructor_page_opens(self): | ||
| assert self.driver.current_url == BASE_URL | ||
|
|
||
| @allure.step('Открытие попапа ингредиента') | ||
| def click_to_open_ingredient_popup(self): | ||
| self.wait_to_be_clickable(self.ingredient_link) | ||
| self.find_element_by_index(self.ingredient_link, 0).click() | ||
| self.wait_for_visibility(self.close_ingredient_modal) | ||
|
|
||
| @allure.step('Проверка открытия попапа ингредиента') | ||
| def check_ingredient_popup_open(self): | ||
| assert self.find_element(self.close_ingredient_modal).is_displayed() | ||
|
|
||
| @allure.step('Закрытие попапа ингредиента') | ||
| def click_to_close_ingredient_popup(self): | ||
| self.wait_to_be_clickable(self.close_ingredient_modal) | ||
| self.find_element(self.close_ingredient_modal).click() | ||
| self.wait_for_invisibility(self.close_ingredient_modal) | ||
|
|
||
| @allure.step('Проверка закрытия попапа ингредиента') | ||
| def check_ingredient_popup_close(self): | ||
| assert self.find_element(self.close_ingredient_modal).is_displayed() is False | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Можно лучше: assert not self.find_element(self.close_ingredient_modal).is_displayed() |
||
|
|
||
| @allure.step('Выбор ингредиента') | ||
| def move_ingredient_to_basket(self): | ||
| self.wait_to_be_clickable(self.ingredient_link) | ||
| ingredient = self.find_element_by_index(self.ingredient_link, 0) | ||
| basket = self.find_element(self.basket_element) | ||
| self.drag_and_drop(ingredient, basket) | ||
|
|
||
| @allure.step('Проерка выбора ингредиента') | ||
| def check_ingredient_counter_increases(self): | ||
| counter = self.find_element_by_index(self.ingredient_counter, 0) | ||
| assert int(counter.text) > 0 | ||
|
|
||
| @allure.step('Оформить заказ') | ||
| def create_order(self): | ||
| self.wait_to_be_clickable(self.create_order_button) | ||
| self.find_element(self.create_order_button).click() | ||
|
|
||
| @allure.step('Проерка оформления заказа') | ||
| def check_create_order(self): | ||
| self.wait_for_visibility(self.order_id_header) | ||
| order_id = self.find_element(self.order_id_header) | ||
| assert int(order_id.text) > 0 | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| from selenium.webdriver.common.by import By | ||
| import allure | ||
| from urls.urls import FEED_URL | ||
| from pages.base_page import BasePage | ||
|
|
||
|
|
||
| class FeedPage(BasePage): | ||
|
|
||
| feed_lnk = (By.XPATH, ".//a[@href='/feed']") | ||
| history_item = (By.XPATH, ".//li[starts-with(@class, 'OrderHistory_listItem')]") | ||
| history_id = (By.XPATH, ".//p[starts-with(@class, 'text text_type_digits-default')]") | ||
| item_info_header = (By.XPATH, ".//p[text()='Cостав']") | ||
| order_counter = (By.XPATH, ".//p[starts-with(@class, 'OrderFeed_number__')]") | ||
| not_ready_orders = (By.XPATH, ".//ul[starts-with(@class, 'OrderFeed_orderListReady__')]/li[starts-with(@class, 'text text_type_digits-default')]") | ||
|
|
||
| @allure.step('Открытие страницы ленты заказа') | ||
| def click_to_open_feed_page(self): | ||
| self.wait_to_be_clickable(self.feed_lnk) | ||
| self.find_element(self.feed_lnk).click() | ||
| self.wait_for_url_change(FEED_URL) | ||
|
|
||
| @allure.step('Проверка открытия страницы ленты заказов') | ||
| def check_feed_page_opens(self): | ||
| assert self.driver.current_url == FEED_URL | ||
|
|
||
| @allure.step('Открытие информации о заказе') | ||
| def click_to_open_order_info(self): | ||
| self.wait_to_be_clickable(self.history_item) | ||
| self.find_element_by_index(self.history_item, 0).click() | ||
|
|
||
| @allure.step('Проверка открытия информации о заказе') | ||
| def check_open_order_info(self): | ||
| self.wait_for_visibility(self.item_info_header) | ||
| assert self.find_element(self.item_info_header).is_displayed() | ||
|
|
||
| @allure.step('Проверка наличия своего заказа в общем списке') | ||
| def check_order_id_in_all_orders(self, order_id): | ||
| self.wait_for_visibility(self.history_id) | ||
| for item in self.find_all_elements(self.history_id): | ||
| if item.text == order_id: | ||
| break | ||
| else: | ||
| assert False | ||
| assert True | ||
|
|
||
| @allure.step('Получение счетчиков заказов') | ||
| def get_order_counters(self): | ||
| self.wait_for_visibility(self.order_counter) | ||
| counters = self.find_all_elements(self.order_counter) | ||
| return int(counters[0].text), int(counters[1].text) | ||
|
|
||
| @allure.step('Получение счетчиков заказов') | ||
| def get_not_ready_order_ids(self): | ||
| self.wait_for_visibility(self.not_ready_orders) | ||
| elements = self.find_all_elements(self.not_ready_orders) | ||
| return list(map(lambda e: e.text, elements)) | ||
|
|
||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| from selenium.webdriver.common.by import By | ||
| import allure | ||
| from urls.urls import FORGOT_PASSWORD_URL | ||
| from pages.base_page import BasePage | ||
| from faker import Faker | ||
|
|
||
|
|
||
| class ForgotPasswordPage(BasePage): | ||
|
|
||
| restore_password_button = [By.XPATH, ".//button[text()='Восстановить']"] | ||
| restore_email_input = [By.XPATH, ".//input[@name='name']"] | ||
| restore_password_div_input = [By.XPATH, ".//input[@name='Введите новый пароль']/parent::div"] | ||
| show_hide_password_button = [By.XPATH, ".//input[@name='Введите новый пароль']/following-sibling::div[starts-with(@class,'input__icon')]"] | ||
|
|
||
| @allure.step('Отправка запроса на восстановление пароля') | ||
| def send_password_restore_request(self): | ||
| fake = Faker("ru_RU") | ||
| self.wait_to_be_clickable(self.restore_password_button) | ||
| self.find_element(self.restore_email_input).send_keys(fake.email()) | ||
| self.find_element(self.restore_password_button).click() | ||
| self.wait_for_visibility(self.restore_password_div_input) | ||
|
|
||
| @allure.step('Проверка отправки запроса на восстановление пароля') | ||
| def check_password_restore_request_sent(self): | ||
| self.wait_for_visibility(self.restore_password_div_input) | ||
| assert self.find_element(self.restore_password_div_input).is_displayed() | ||
|
|
||
| @allure.step('Нажатие на кнопку показать пароль') | ||
| def click_on_focus_password_input_icon(self): | ||
| self.wait_to_be_clickable(self.show_hide_password_button) | ||
| self.find_element(self.show_hide_password_button).click() | ||
|
|
||
| @allure.step('Проверка фокуса на поле пароля') | ||
| def check_password_input_in_active_state(self): | ||
| cls = self.find_element(self.restore_password_div_input).get_attribute('class') | ||
| assert "input_status_active" in cls | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| from selenium.webdriver.common.by import By | ||
| import allure | ||
| from urls.urls import FORGOT_PASSWORD_URL | ||
| from pages.base_page import BasePage | ||
|
|
||
|
|
||
| class LoginPage(BasePage): | ||
|
|
||
| forgot_password_page_link = [By.XPATH, ".//a[@href='/forgot-password']"] | ||
|
|
||
| @allure.step('Проверка открытия страницы восстановления пароля') | ||
| def check_forgot_password_page_opens(self): | ||
| self.wait_to_be_clickable(self.forgot_password_page_link) | ||
| self.find_element(self.forgot_password_page_link).click() | ||
| self.wait_for_url_change(FORGOT_PASSWORD_URL) | ||
| assert self.driver.current_url == FORGOT_PASSWORD_URL | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: здесь и далее по проекту: все прямые обращения к driver необходимо вынести в base, там описать методы взаимодействия с ними и оттуда за счет наследования классов страниц от base переиспользовать |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| from selenium.webdriver.common.by import By | ||
| import allure | ||
| from urls.urls import PROFILE_URL, ORDER_HISTORY_URL, LOGIN_URL | ||
| from pages.base_page import BasePage | ||
|
|
||
|
|
||
| class ProfilePage(BasePage): | ||
|
|
||
| profile_page_link = [By.XPATH, ".//a[@href='/account']"] | ||
| order_history_link = [By.XPATH, ".//a[@href='/account/order-history']"] | ||
| logout_button = [By.XPATH, ".//button[text()='Выход']"] | ||
| order_id = [By.XPATH, ".//p[starts-with(@class, 'text text_type_digits-default')]"] | ||
|
|
||
| @allure.step('Открытие страницы профиля') | ||
| def open_profile_page(self): | ||
| self.wait_to_be_clickable(self.profile_page_link) | ||
| self.find_element(self.profile_page_link).click() | ||
| self.wait_for_url_change(PROFILE_URL) | ||
|
|
||
| @allure.step('Проверка открытия страницы профиля') | ||
| def check_profile_page_opens(self): | ||
| assert self.driver.current_url == PROFILE_URL | ||
|
|
||
| @allure.step('Открытие страницы истории заказов') | ||
| def open_order_history_page(self): | ||
| self.wait_to_be_clickable(self.order_history_link) | ||
| self.find_element(self.order_history_link).click() | ||
| self.wait_for_url_change(ORDER_HISTORY_URL) | ||
|
|
||
| @allure.step('Получение последнего id заказа') | ||
| def get_last_order_id(self): | ||
| self.wait_for_visibility(self.order_id) | ||
| return self.find_element_by_index(self.order_id, 0).text | ||
|
|
||
| @allure.step('Проверка открытия страницы истории заказов') | ||
| def check_order_history_page_opens(self): | ||
| assert self.driver.current_url == ORDER_HISTORY_URL | ||
|
|
||
| @allure.step('Выход из ЛК') | ||
| def logout(self): | ||
| self.wait_to_be_clickable(self.logout_button) | ||
| self.find_element(self.logout_button).click() | ||
| self.wait_for_url_change(LOGIN_URL) | ||
|
|
||
| @allure.step('Проверка выхода из ЛК') | ||
| def check_logout(self): | ||
| assert self.driver.current_url == LOGIN_URL | ||
|
|
||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| [pytest] | ||
| pythonpath = . |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| faker | ||
| pytest | ||
| allure-pytest | ||
| selenium |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Нужно исправить: здесь и далее: использование в локаторе порядкового номера элемента в dom, поиск от html, root, main и абсолютного пути порождает нестабильность локаторов (необходимо привязываться к атрибутам конкретного элемента)