Ищу пример простого микрофреймворк и примера паттерна PageObject

pytest
python
selenium
Теги: #<Tag:0x00007fedb792ea08> #<Tag:0x00007fedb792e580> #<Tag:0x00007fedb792e328>

(Дмитрий Золкин) #24

Я не знаю как вынести в отдельный класс отельной страницы тут вечные споры, где они должны храниться. Лично я храню локаторы просто в папке под названием locators там лежит файлик ProjectPageElements.py

class ProjectPageElements():---->Просто класс локаторы!!!
    tooltip_close_button = (By.XPATH, '//msg-module/div/p-growl/div/div/div/div[1]')
    button_create_test = (By.XPATH,'//span[contains(text(),"Создать")]')
    project_page_title = (By.XPATH, '//h5')
    button_menu = (By.XPATH, '//span[contains(text(),"Меню")]')

Потом есть папка pages там лежит такое ProjectPlanPage.py

from project_name.locators.ProjectPageElements import ProjectPageElements
class ProjectPlanPage(Page):--->>(В проекте 5 больших закладок поэтому я выделил каждую в класс)
    def __init__(self, driver):
        super(ProjectPlanPage, self).__init__(driver)
        self.new_test_form = NewRevisionForm(self.driver)-->строка создание нового объекта форма(у менять закладка -Это объект(ProjectPlanPage),  а закладке открывается форма и это тоже объект NewCreateForm)
    def open_new_test_form(self):
        self.click_element(ProjectPageElements.button_menu)
        self.click_button(ProjectPageElements.button_create_test)

Еще я выделил формы как отдельный объект в папке forms лежит

class NewCreateForm(BaseForm):----> В закладке открывается форма создал класс
    def __init__(self, driver):
        super(NewCreateForm, self).__init__(driver)
    def close_form(self):
        self.click_button(NewCreateFormElements.button_cancel)

А в Page лежит что-то такое:

class Page(object):---->>> 

    def __init__(self, driver):
        self.driver = driver
    def click_button(self, locator):
        try:
            WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located(locator)
            ).click()
            angular_not_active()(self.driver)
        except TimeoutException:
            raise Exception(u"Время появления кнопки истекло")

    def click_element(self, locator):
        try:
            WebDriverWait(self.driver, 10).until(
                EC.element_to_be_clickable(locator)
            ).click()
            angular_not_active()(self.driver)
        except TimeoutException:
            raise Exception(u"Время появления кнопки истекло")

У меня так. ак правильно я точно пока не знаю))

Тест выглядит так :

class TestCreate():
    def setup_class(self):
        self.project_page = ProjectPlanPage(self.driver)
    def test_open_new_test_form(self):
        with pytest.allure.step('Проверка открытия формы "Новая проверка" ')
            self.project_page.open_new_test_form()
            assert u'Новая проверка' == self.project_page.new_test_form.check_form_title()

(Gukobrist) #25

Супер. Спасибо тебе огромное. Буду ковырять, смотреть и потом представлю, по крайней мере, на твой суд, что же у меня получилось)


(Дмитрий Золкин) #26

я могу быть не прав)) а другие что то ничего не советуют)).Может могли бы и мое поправить…))


(Roy Obenon) #27

в классе Page должны хранится методы по работе исключительно со страницей: ввести в форму данные, кликнуть по кнопке и т.д. В конструкторе она должна принимать driver и логгер например. Все обёртки на счет выполнения кликов с ожиданием, просто ожиданием элементов - должны хранится в WebDriverWrapper классе, который получает драйвер и использует его методы!

Локаторы должны хранится в классе в педжой, не нужно выносить в отдельный файл, оно скапливается и потом не знаешь, что где используется + не читаемо это (как по мне)


(Дмитрий Золкин) #28

Как понять не знаешь где используется??У менять есть закладка это класс PlanPage на этой закладке есть локаторы PlanPageElements???как тут запутаться можно?По мне так засунуть локаторы в PlanPage это не читаемо))) Можно пример? как понять метод для работы со страницей? как можно ввести в форме не найдя ее??

class Page(object):

    def __init__(self, driver):
        self.driver = driver
    def click_button(self, locator):
        try:
            WebDriverWait(self.driver, 10).until(
                EC.element_to_be_clickable(locator)
            ).click()
            angular_not_active()(self.driver)
        except TimeoutException:
            raise Exception(u"Время появления кнопки истекло")

Чем не метод для работы с любой кнопкой??
Для конкретной пейджи например будет так:

class PlanPage(Page):
def click_save(self):
     self.click_button(PlanPageElements.button_save)

(Eugene Stogniy) #29

Там содержаться общие функции для всех страниц


(Eugene Stogniy) #30

PageElements обычно используються для повторяющихся на многих страницах / либо одинаковых элементах - например фильтры или поиск


(Gukobrist) #31

Блин, я все не могу понять как же вывести локаторы в отдельную переменную

Если я делаю так

LOGIN = (By.XPATH, "//input[@id='mailbox:login']")

а потом пытаюсь использовать

    def fill_login_field(self, login):
        login_field = self.driver.find_element(LOGIN)
        login_field.send_keys(login)

То он выдает ошибку, говорит так нельзя, нужно чтобы был аргумент value=

В итоге пока только так получается.
conftest.py - конфигурация сессии

import pytest
from selenium import webdriver

@pytest.fixture(scope='session', autouse=True)
def driver(request):
    print("\nstart SESSION")
    driver = webdriver.Chrome()
    driver.implicitly_wait(2)
    driver.maximize_window()
    request.addfinalizer(driver.quit)
    print("end SESSION")

    return driver

test_login_form.py - содержит тесты

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from page import MailRuLoginFormMainPage

hostname = 'https://mail.ru/'
login = 'fbs_test1203@mail.ru'
password = '1Passw0rd'

"""
Тест на заполнение формы корректными данными. Тест является пройденным при проверке на наличии фразы "Входящие"
в заголовке Title после нажатия кнопки Войти.
"""

def test_input_login_password_correct(driver):
    driver.get(hostname)
    wait = WebDriverWait(driver, 10)
    main_page = MailRuLoginFormMainPage(driver)
    assert "Mail.Ru" in main_page.get_title()
    print(main_page.get_title())

    main_page.fill_login_field(login)
    main_page.fill_password_field(password)
    main_page.click_submit_button()

    try:
        element = wait.until(EC.title_contains("Входящие"))
    finally:
        assert "Входящие" in main_page.get_title()

page.py - по моей задумке это файл с элементами на странице и с методами для работы с этими элементами.

from selenium.webdriver.common.by import By

class BasePage(object):

    def __init__(self, driver):
        self.driver = driver

    def get_title(self):
        return self.driver.title


class MailRuLoginFormMainPage(BasePage):

    # actions
    def fill_login_field(self, login):
        login_field = self.driver.find_element(By.XPATH, value="//input[@id='mailbox:login']")
        login_field.send_keys(login)

    def fill_password_field(self, password):
        login_field = self.driver.find_element(By.XPATH, value="//input[@id='mailbox:password']")
        login_field.send_keys(password)

    def click_submit_button(self):
        submit_button = self.driver.find_element(By.XPATH, value="//input[@value='Войти']")
        submit_button.click()

Подскажите, в правильном ли я направлении двигаюсь? Чего не хватает? Что лишнее? Как мне сделать фикстуру, которая будет сохранять куки? Например я залогинился, сохранил куки и дальше запускать сессию с этими куки, чтобы пользователь в тесте уже был залогиненным?


(Gukobrist) #32

Подскажите пожалуйста. Есть тесты, которые должны запускаться каждый по отдельности - например проверка логина с правильными данными и неправильными, как в примере ниже. Как сделать так, чтобы тесты находились в одном файле, но при этом, чтобы для каждого теста окрывалось новое окно браузера, где нужно авторизоваться, даже если пользователь уже авторизовывался в прошлом тесте.

И если есть тесты, где нужно чтобы авторизация сохранялась (куки чтоб сохранялись) и например я протестировал вход - все ок. в следующем тесте я тестирую выход - для этого должно открыться окно в котором сохранился вход с прошлого теста и мне например нужно просто нажать кнопку выход.

test_login_form.py - файл с тестами

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from page import MailRuLoginFormMainPage
import time

hostname = 'https://mail.ru/'
login = 'fbs_test1203@mail.ru'
login_incorrrect = 'fbs_test1204@mail.ru'
password = '1Passw0rd'
password_incorrect = '1Password'

"""
Тест на заполнение формы корректными данными.
"""
def test_input_login_password_correct(driver):

    driver.get(hostname)
    wait = WebDriverWait(driver, 10)
    main_page = MailRuLoginFormMainPage(driver)
    assert "Mail.Ru" in main_page.get_title()

    main_page.fill_login_field(login)
    main_page.fill_password_field(password)
    main_page.click_submit_button()

    try:
        element = wait.until(EC.title_contains("Входящие"))
    finally:
        assert "Входящие" in main_page.get_title()

"""
Тест на заполнение формы c некорректным логином.
"""
def test_input_login_incorrect(driver):

    driver.get(hostname)
    wait = WebDriverWait(driver, 10)
    main_page = MailRuLoginFormMainPage(driver)
    assert "Mail.Ru" in main_page.get_title()

    main_page.fill_login_field(login_incorrrect)
    main_page.fill_password_field(password)
    main_page.click_submit_button()

    assert "Неверное имя или пароль" in main_page.get_errors

"""
Тест на заполнение формы c некорректным паролем.
"""
def test_input_password_incorrect(driver):

    driver.get(hostname)
    wait = WebDriverWait(driver, 10)
    main_page = MailRuLoginFormMainPage(driver)
    assert "Mail.Ru" in main_page.get_title()

    main_page.fill_login_field(login)
    main_page.fill_password_field(password_incorrect)
    main_page.click_submit_button()

    assert "Неверное имя или пароль" in main_page.get_errors

conftest.py - настройки

import pytest
from selenium import webdriver

@pytest.fixture(scope='session', autouse=True)
def driver(request):
    print("\nstart SESSION")
    driver = webdriver.Chrome()
    driver.implicitly_wait(2)
    driver.maximize_window()
    request.addfinalizer(driver.quit)
    print("end SESSION")

    return driver

page.py - page objects

from selenium import webdriver
from selenium.webdriver.common.by import By

class BasePage(object):

    def __init__(self, driver):
        self.driver = driver

    def get_title(self):
        return self.driver.title


class MailRuLoginFormMainPage(BasePage):

    # actions
    def fill_login_field(self, login):
        login_field = self.driver.find_element(By.XPATH, value="//input[@id='mailbox:login']")
        login_field.send_keys(login)

    def fill_password_field(self, password):
        login_field = self.driver.find_element(By.XPATH, value="//input[@id='mailbox:password']")
        login_field.send_keys(password)

    def click_submit_button(self):
        submit_button = self.driver.find_element(By.XPATH, value="//input[@value='Войти']")
        submit_button.click()

    def get_errors(self):
        error_login_form = self.driver.find_element(By.XPATH, value="//div[@id='mailbox:error']")
        error_text = error_login_form.text

        return error_text

(Eugene Stogniy) #33

Я в питоне полный 0 так что больше теоретик:
Чтобы каждый раз заново логиниться - надо каждый раз открывать и закрывать драйвер
например в BeforeTest and AfterTest (Java ТестНДЖ)
чтобы сохранять куки между сессиями
user.sessionId = driver.manage().getCookieNamed(“sessionid”).getValue();
driver.manage().addCookie(new Cookie(“sessionid”, user.sessionId));