Удаленка для jenkins+selenide+selenoid+allure+docker спецов на 2-3 часа в день. 100% remote! Присоединиться к проекту

Не получается проверить значение по Xpath

bdd
gherkin
behave
python
Теги: #<Tag:0x00007fedc74dddb8> #<Tag:0x00007fedc74ddc28> #<Tag:0x00007fedc74ddae8> #<Tag:0x00007fedc74dd908>

(Gukobrist) #1

Никак не могу сделать assert_equal.

У меня настроен behave. в файле login_steps.py прописан последний шаг проверки, что пользователь залогинился. Когда ввел логин и пароль, пользователь попадает на страницу, в шапке которой текстом отображается имя пользователя. Я пытаюсь получить через xpath это поле и сравнить его с тем, что написано в login.feature.

Последний шаг login.feature

And Проверяю в header наличие имя пользователя "Rmfalx"

Как шаг описан в login_steps.py

@step('Проверяю в header наличие имя пользователя "{search_user}"')
def step_impl(context, search_user):
    assert_equal(context.main_title.find_user_name(search_user), search_user)

Так же у меня есть файл main_title.py, который является описанием главной страницы после авторизации.

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

class MainTitleLocator(object):
    # Элементы страницы входа

    USER_NAME = (By.XPATH, "//b[text()='Rmfalx']")

class MainTitle(Browser):

    def get_element(self, *locator):
        return self.driver.find_element(*locator)

    def find_user_name(self, search_user):
        return self.get_element(By.XPATH, search_user)

А так же файл browser.py с настройками

from selenium import webdriver

class Browser(object):

    driver = webdriver.Chrome()
    driver.implicitly_wait(30)
    driver.set_page_load_timeout(30)
    driver.maximize_window()

    def close(context):
        context.driver.close()

На странице main_title я нажимаю f12 и ctr+f вставляю свой xpath //b[text()=‘Rmfalx’]" и все находится, но проверка в тесте не производится.

В общем не понимаю, что происходит. Пишет вот такую ошибку

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"Rmfalx"}
        (Session info: chrome=60.0.3112.90)
        (Driver info: chromedriver=2.26.436382 (70eb799287ce4c2208441fc057053a5b07ceabac),platform=Linux 4.10.0-30-generic x86_64)

(Maxim Andryushchenkov) #2

Пока читал чуть не вытекли глаза от реализаций, не в обиду.
Чуть надо побольше посмотреть в сторону PageObject паттерна и Selenium реализаций, различных подходов. В чистом виде его нужно прям так хорошо отполировать чтобы было удобно.
Также по поводу проверки xpath путей - попробуй это все делать через FirePath, он прям лучший, честно. Он сперва тебе покажет хардовый путь, а ты потом сможешь переделать на гибкий как тебе надо.


(Gukobrist) #3

Спасибо за совет, попробую. А что не так с реализацией? Я делал все по инструкции. Отдельная директория pages для описания элементов страницы. Отдельная директория steps где находятся мои тесты. Тесты выходят короче, недели если в каждом тесте все в кучу валить, как например в nose_tests


(Maxim Andryushchenkov) #4

Это не нужно, если вы юзаете Behave, то почитаейте про файл environment.py рядом с фичами, через который вы сможете реализовать вызов context.driver, который вы в свою очередь будете передавать в context.page и определять текущую страницу с унаследованными методами от BagePage и своими, если таковые имеются. Если надо могу кинуть образец в лс

Это вообще убрать и не надеяться никогда на эти встроенные вейты (они не гетятся, только сетятся), напишите себе вейты сами, используя классы WebDriverWait и expected_conditions. Обертки, обертки, только так с чистым Selenium’ом.

Это можно связать с предыдущим вейтом типа wait_and_get_element (кастомные таймауты замути и получится тебе implicitly_wait только нормально работающий, хотябы ожидаемо работающий)

Я бы локаторы отдельно хранил в ямле


(Gukobrist) #5

Я лучше еще раз опишу полностью.

login.feature

Feature: Вход

  Scenario: Вход пользователя
    Given Перехожу на страницу входа в ПО
    When Првоеряю, что я на главной ищу title "XXX"
    Then Ввожу логин "rmfalx"
    Then Ввожу пароль "123"
    Then Ввожу код подразделения "777"
    Then Нажимаю кнопку "Войти в систему"
    And Проверяю в header наличие имя пользователя "Rmfalx"

Затем перевожу шаги в код в файле login_steps.py

from nose.tools import assert_equal, assert_true
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

@step('Перехожу на страницу входа в ПО')
def step_impl(context):
    context.login_page.navigate("http://xxx.ru/")

@step('Првоеряю, что я на главной ищу title "{search_title}"')
def step_impl(context, search_title):
    assert_equal(context.login_page.get_page_title(), search_title)

@step('Ввожу логин "{login_term}"')
def step_impl(context, login_term):
    context.login_page.login(login_term)

@step('Ввожу пароль "{password_term}"')
def step_impl(context, password_term):
    context.login_page.password(password_term)

@step('Ввожу код подразделения "{code_division_term}"')
def step_impl(context, code_division_term):
    context.login_page.code_division(code_division_term)
    #time.sleep(5)

@step('Нажимаю кнопку "Войти в систему"')
def step_impl(context):
    context.login_page.signin_button()

@step('Проверяю в header наличие имя пользователя "{search_user}"')
def step_impl(context, search_user):
    assert_equal(context.main_title.find_user_name(search_user), search_user)

В файле login_page.py описана страница логина

from selenium.webdriver.common.by import By
from browser import Browser
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class LoginPageLocator(object):
    # Элементы страницы входа

    LOGIN_FIELD = (By.ID, "ext-comp-1001") #Поле логин
    PASSWORD_FIELD = (By.ID, "ext-comp-1002") #Поле пароль
    CODE_DIVISION_FIELD = (By.ID, "ext-comp-1003") #Поле код подразделения
    BUTTON_SIGNIN = (By.ID, "ext-gen34") #Кнопка войти


class LoginPage(Browser):
    # Действия на странице входа в ПО
    def navigate(self, address): #Переход на страницу входа
        self.driver.get(address)

    def get_page_title(self): #Получаем тайтл страницы для проверки
        return self.driver.title

    def login(self, login_term): #Находим поле ввода логина
        self.fill(login_term, *LoginPageLocator.LOGIN_FIELD)

    def fill(self, text, *locator): # Заполняем поля логина, пароля и кода подразделения
        self.driver.find_element(*locator).send_keys(text)

    def password(self, password_term): # Находим поле ввода пароля
        self.fill(password_term, *LoginPageLocator.PASSWORD_FIELD)

    def code_division(self, code_division_term): #Находим поле ввода Кода подразделения
        self.fill(code_division_term, *LoginPageLocator.CODE_DIVISION_FIELD)

    def signin_button(self): #Находим кнопку войти
        self.click_element(*LoginPageLocator.BUTTON_SIGNIN)

    def click_element(self, *locator): #Нажимаем кнопку войти
        self.driver.find_element(*locator).click()

а в файле home_page.py описана страница, которая идет следом после логина

from selenium.webdriver.common.by import By
from browser import Browser
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class MainTitleLocator(object):
    # Элементы страницы входа

    USER_NAME = (By.XPATH, "//b[text()='Rmfalx']")

class MainTitle(Browser):

    def get_element(self, *locator):
        return self.driver.find_element(*locator)

    def find_user_name(self, search_user):
        return self.get_element(By.XPATH, search_user)

Так же есть файлы с настройками enviroment.py

from selenium import webdriver
from browser import Browser
from pages.home_page import HomePage
from pages.search_results_page import SearchResultsPage
from pages.login_page import LoginPage
from pages.main_title import MainTitle


def before_all(context):
    context.browser = Browser()
    context.home_page = HomePage()
    context.search_results_page = SearchResultsPage()
    context.login_page = LoginPage()
    context.main_title = MainTitle()

def after_all(context):
    context.browser.close()

И browser.py

from selenium import webdriver

class Browser(object):

    driver = webdriver.Chrome()
    driver.implicitly_wait(30)
    driver.set_page_load_timeout(30)
    driver.maximize_window()

    def close(context):
        context.driver.close()

Все шаги проходят, кроме последней првоерки(


(Gukobrist) #6

Я вот тут ниже описал всю систему полностью.


(Maxim Andryushchenkov) #7

Дай DOM локатор проверим


(Gukobrist) #8

Извините, Максим, а вы не моглиб немного подробнее объяснить, что такое DOM локатор, я просто 3 день автоматизацией занимаюсь)


(Nmcreature) #9

В метод передается имя пользователя, а не xpath


(Gukobrist) #10

Не понял, ето где?


(Nmcreature) #11

этот метод ожидает xpath, а получает:“Rmfalx”

And Проверяю в header наличие имя пользователя “Rmfalx”

@step(‘Проверяю в header наличие имя пользователя “{search_user}”’)
def step_impl(context, search_user):
assert_equal(context.main_title.find_user_name(search_user), search_user)


#12

Не нужно в xpath запихивать ваше имя пользователя, берите общий xpath для этого тега, получаете некий WebElement element, потом у него берете атрибут
String login = element.getAttribute(“innerHTML”) и мачите его со своим Rmfalx


(Maxim Andryushchenkov) #13

Ахаха) он все понял) тут надо начинать с понятия xpath


(Gukobrist) #14

Я в итоге поменял код. Скажите, как по вашему - это правильно?

Файл main_title.py

class MainTitleLocator(object):
    # Элементы страницы входа

    USER_NAME = (By.XPATH, "//b[text()='Rmfalx']")

class MainTitle(Browser):

    def get_element(self, *locator):
        return self.driver.find_element(*locator)

    def find_user_name(self, serch_user):
        return self.get_element(*MainTitleLocator.USER_NAME)

А в login_steps.py

@step('Проверяю в header наличие имя пользователя "{search_user}"')
def step_impl(context, search_user):
    assert_true(context.main_title.find_user_name(search_user))

Теперь происходит assert_true . сравнивается, то что я получил в функции find_user_name и search_user. И я так понимаю это True

А может и нет, я если честно немного запутался.


(Gukobrist) #15

Да. Уже читаю. Я видимо, что-то не то себе представил.


(Gukobrist) #16

Спасибо. Вроде абстрактно понял. Буду изучать дальше, что такое есть xpath. Не могли б глянуть обновленный код. Я там поменял проверку.


(Nmcreature) #17

Вам Марина все правильно написала, нужно брать у хедера (локатор хедера не должен включать его текстовое значение, это бессмысленно и беспощадно) текст и сравнивать его с ожидаемым.
При данной реализации мы получим тот же NoSuchElementException, если текст хедера !=‘Rmfalx’

P.S. и зачем теперь передавать в метод search_user? Он нигде не используется.


(Gukobrist) #18

Марина, вы меня простите, возможно это наглость, но на примере будет яснее наверное. Вы не могли бы мне продемонстрировать, как будет выглядеть правильный xpath. Вот это код хэдэра

<div id="ext-comp-1039" class=" body-bg body-bg-noborder x-border-panel" style="left: 0px; top: 0px; width: 1859px;"><div class="body-bg-bwrap" id="ext-gen13"><div class="body-bg-body body-bg-body-noheader body-bg-body-noborder" id="ext-gen14" style="height: 40px; width: 1859px;"><div style="height:40px; width: 100%; overflow:hidden;"><div class="company-title"><i>ПО<sup style="font-size:12px;">®<sup></sup></sup></i>&nbsp;&nbsp;&nbsp;</div><div class="button-title" id="lk-btn1"><div class="x-form-field-wrap x-form-field-trigger-wrap" id="ext-gen299" style="width: 201px;"><span>Подразделение:&nbsp;<b>Отдел по работе с задолженностью (777-77)</b></span></li><li>&nbsp;</li><li class="box"><span>Пользователь:&nbsp;<b>Rmfalx</b></span></li><li>&nbsp;</li><li><a href="javaScript:void(0)" id="lk-logout">Выход</a></li></ul></div></div></div></div>

Вот


#19

Возвращаясь к вопросу в данной теме - по xpath-у скорее всего не находит, поскольку в xpath-e указывается //b[text()='Rmfalx'], а вводится текст rmfalx - то бишь с маленькой буквы. Скорее всего и не находит поэтому :slight_smile:
Там даже в самой фиче это видно


(Gukobrist) #20

Нет. Сверка идет в последнем шаге

And Проверяю в header наличие имя пользователя "Rmfalx"