Перейти к содержимому

Alex

Регистрация: 31 июл 2007
Offline Активность: 06 дек 2022 10:25
***--

#175070 Получить текст внутри span

Написано Alex 09 января 2020 - 12:29

Работает, конечно, на тоненького, но в вашем случае должно хватить

public String getTextIgnoringInnerElements(WebElement element) {

     String text = element.getText();
     log("Got text '%s'", text);

     List<WebElement > children = element.findElements(By.xpath(".//*"));

     for(int i = 0; i < children.size(); i++ ){
       text = text.replaceFirst(Pattern.quote(children.get(i).getText()), "");
     }

     return text;
}

  • 2


#170184 Проверка введенных данных в Selenium

Написано Alex 21 декабря 2018 - 08:34

Возможно ли релизовать такую проверку заполнения данных в полях в Selenium'e?

Пример: Есть реквест (или какая-нибудь форма с полями), селениум должен заполнить данные поля данными, которые я уже вбил ( https://drive.google...iz3bUUMVqt2wMcS ) => Создается сам реквест => Селениум ищет название "Requisiton_1712_2018_2" по всем реквестом(которые есть на сайте) и переходит на него ( https://drive.google...st5ZZxb_rZaCPjU ) => Селениум проверяет данные, которые я ввел в первом скрине и скидывает отчёт на почту.

 

P.S. На счет того, что можно отчет прислать на почту - я знаю. Мне важно узнать, ли можно сделать такую проверку введённых данных, которую я описал

а почему не должен мочь? Если это обычная веб страница, то читать текст со страницы селениум умеет


  • 1


#169499 Верификация некликабельности элемента

Написано Alex 16 ноября 2018 - 06:34

Всем добрый день.

 

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

 

Есть ряд элементов(иконок) меню. Часть из них неактивна, а часть - наоборот. В тесте необходимо собственно сделать верификацию, что конкретные разделы тулбара не могут быть выбраны, а другие - могут. Попытки использовать isEnabled не помогли, всегда состояниt true.

 

Собственно код одного из элементов "Add instrument", который собственно Disabled для нажатия.

 

<div class="menu-button ng-binding add disabled" ng-click="action.enabled&amp;&amp;onSelectAction(action)"
ng-class="[{'disabled':!action.enabled},action.class]">Add instrument</div>

 

Какие еще могут быть варианты для проверки состояния элемента?

<div class="menu-button ng-binding add disabled"

не о чем не говорит?


  • 2


#168513 Прочитать все элементы из dropdown в List <String>

Написано Alex 17 сентября 2018 - 06:48

Камрады!

 

Столкнулся с такой проблемой:

- Необходимо прочитать весь список из dropdown и передать его в List<String>

 

23343897.jpg

 

Классически, до этого я использовал заполнение списка List<WebElement> по индексу динаического xpath

i.e.

public static String SOURCE_RACK_NAME_SELECTED = "//span[@formation-id='source-rack-name-%d']";

@Step(description = "Get all WebElements from the dropdown list input")
public List<WebElement> getAllElementsFromDropDownList(By xpathList, String xpathElement) {
      List<WebElement> webElementsArrayList = new ArrayList<>();
         aitForElementToBeVisible(xpathList);

           List<WebElement> webElementsFromDropDown = driver.findElements(xpathList);

     for (int i=0; i<webElementsFromDropDown.size(); i++) {

                  String xpathRackFilter = String.format(xpathElement, i);
                  By xpathRack = By.xpath(xpathRackFilter);
                  WebElement listElement = driver.findElement(xpathRack);
                  webElementsArrayList.add(listElement);

     }
               System.out.println("<------------- The elements List -------------> " + webElementsFromDropDown);
       return webElementsArrayList;
}

Сейчас же для магипуляций с элементами списка, они должны быть String по-умолчанию

1. Открыть dropdown

2. Прочитать весь список в List<String>

3. Random выбрать один элемент

4. Вернуть его

 

Код html:

<div class="ui-select-choices-group optgroup">
<div class="ui-select-choices-group-label optgroup-header ng-binding ng-hide" ng-show="$select.isGrouped" ng-bind="$group.name"/>
<!-- ngRepeat: rack in $select.items -->
<!-- ngIf: $select.open -->
<div class="ui-select-choices-row ng-scope active" role="option" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" 
            ng-repeat="rack in $select.items" ng-if="$select.open" ng-click="$select.select(rack,$select.skipFocusser,$event)" style="">
<div class="option ui-select-choices-row-inner" data-selectable="" uis-transclude-append="">
<span class="ng-binding ng-scope" ng-bind-html="rack | highlight: $select.search" formation-id="source-rack-name-0">VIK6R01</span>
</div>
</div>
<!-- end ngIf: $select.open -->
<!-- end ngRepeat: rack in $select.items -->
<!-- ngIf: $select.open -->
<div class="ui-select-choices-row ng-scope" role="option" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" 
            ng-repeat="rack in $select.items" ng-if="$select.open" ng-click="$select.select(rack,$select.skipFocusser,$event)" style="">
<div class="option ui-select-choices-row-inner" data-selectable="" uis-transclude-append="">
<span class="ng-binding ng-scope" ng-bind-html="rack | highlight: $select.search" formation-id="source-rack-name-1">VIK6R02</span>
</div>
</div>
......

Манипуляции с WebElement --> String после не работают driver.findElement не работатет корректно со String 

Как вообще возможно после открытия DropBox прочитать его размер, чтобы потом заполнить List  [ не используя  driver.findElement(xpath); ]

 

Есть ли решение со стороны Selenium?

На вашем же примере что мешает?

List<WebElement> webElementsFromDropDown = driver.findElements(xpathList);
List<String> names = new ArrayList();

for (WebElement listItem: webElementsFromDropDown) {

names.add(listItem.getText());

}

return names;

  • 1


#167650 Прочитать текст из "Disabled" Input form

Написано Alex 08 августа 2018 - 06:03

вот ребята сейчас вам костылей насоветуютесли что, они вам тут последние пару предложений предлагают сделать следующее: getValue -> replaceValueToNeedValue -> PROFIT TEST SECCED =)

 

вы либо ожидайте в результате теста не просто ЛОЛ, а ЛОЛ с пробелами, либо говорите программистам, что у них баг.

А если с программистами поговорить нельзя? Проблема с переносами видна только на уровне Selenium и для пользователя все выглядит корректно. Наиболее вероятно, что разработчики либо вообще не будут этим заниматься, либо поставят самый низкий приоритет. Никто ведь не предлагает делать нечто этакое. Речь идет лишь об удалении доп. пробелов и переносов.


  • 1


#167648 Как уменьшить количество вызовов классов?

Написано Alex 08 августа 2018 - 05:58

Всем доброго времени суток.

С недавних пор работаю авто-тестировщиком, пишу тесты на java и selenium webdriver, в процессе изучения того и другого. 
В данный момент у меня возник вопрос ответ на который мне в данный момент совершенно неочевиден, а проблема стоит остро и в дальнейшем неизбежно будет прогрессировать.. очень прошу помочь с решением.

Я написал что-то вроде надстройки над селениумом, которая выглядит следующим образом:

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

Иерархически схема в данный момент выглядит так:
class A

class B extends A

class C extends B

class Buttons extends C

class Breadcrumbs extends C

class Table extends C

...

class Page собирает все что после C (там около полутора десятка элементов каждому из которых посвящен отдельный класс)
и от Page как раз наследуются все тестируемые "страницы".

В данный момент все отлично работает (с точки зрения затраченного на тесты времени), но.. я поместил в конструктор каждого класса код вида System.out.println("init classname"); и ужаснулся количеству инициализаций этих классов, сообщений об инициализации в консоли больше трех десятков. :(

С ростом кода во вспомогательных страницах а так же с количеством тестов или тестируемых страниц мне кажется что вся эта конструкция грозит неоправданным расходом ресурсов тестовой машины, или дикими тормозами при прогонах.

У меня устойчивое ощущение что я что-то делаю не так, и что количество инициализаций можно значительно сократить или вообще свести к одному-единственному.
Подскажите пожалуйста, что можно для этого сделать? Буду рад любым предложениям или советам.

1. Инициализация класса неизбежно приводит к "инициализации" и родительских классов. Т.е., у вас класс C наследует сразу два класса. Соответственно new C() породит три записи в консоли, хотя класс создали только 1

2. Перерасход ресурсов в современном мире для тестовых целей маловероятен. Если бы вы писали высоконагруженное приложение, то имело бы смысл сильно беспокоится об этом. А так, вряд ли это сильно повлияет

3. Не понятно зачем А и B классы, если в конечном счете все равно все используют только класс C или вы не так отразили зависимость в своем примере.

 

Ну и по части классов, у нас, например, во фрэймворке количество классов исчисляется сотнями (без учета классов самих тестов). Сколько там порождается объектов даже представить не могу, но вроде норм все.


  • 2


#166868 Параметризация в Web Tours

Написано Alex 29 июня 2018 - 07:55

web_reg_save_param - этой функцией у меня параметризировано залогинивание на сайте, так как там каждый раз используется динамический ID. А для параметризации выбора рейсов прописываю в следующей строке эту же функцию с вставленными данными из респонса? Я правильно понял? 

web_reg_save_param - сохраняем все возможные рейсы 

web_req - некоторый запрос, где мы выбираем второй город и приложение после него предлагает нам доступные рейсы

web_req - выбираем параметризованный рейс или сразу сабмитим


  • 1


#166856 Параметризация в Web Tours

Написано Alex 27 июня 2018 - 15:14

 

 

 

 

 

 

Прошу прощения если данный вопрос уже поднимался, не смог найти. Изучаю HP Loadrunner и столкнулся с одной проблемой связанной с параметризацией. В WebTours параметризирую один параметр (выбор города убытия), скрипт завершается норм, в логах реплея все хорошо, параметр меняется как нужно, при проверке в WebTours данный параметр остается по дефолту. Сможете подсказать куда копать? Версия Vugen 12.55, версия ос Win 10 (64 bit).

Нужно больше информации. Какая именно проверка? То есть вы запустили скрипт Выбрали город убытия,  отправили данные на сервер и в ответе получили город, который был по умолчанию?

 

Почти. Опишу коротко свои шаги. Запускаю запись скрипта, выбираю два города (Например: Лондон-Париж), выбираю номер рейса, оплачиваю, выхожу из аккаунта, останавливаю запись. В полученном скрипте параметризирую  города убытия и прибытия. Для этого создаю файл, куда вношу все города и ставлю в настройках параметра рандомный выбор на каждой итерации. Запускаю скрипт, по завершению статус - pass. Смотрю в логах реплея скрипта - где есть запись о том, что покупка совершена, билет куплен, горда убытия и прибытия, например : Денвер-Лос-Анджелес. Чтобы убедиться, что покупка действительно осуществленна, захожу на WebTours,в разделе купленных билетов появилась вторая запись, но билет куплен опять в города: Лондон-Париж. Вот у меня и вопрос, почему так произошло? Что я упустил в параметризации?

 

Либо нет рандомной генерации в настройках (перепроверить), либо нет итераций (используется программный цикл). Покажите как выглядит Run план (или как он там называется, где отмечено какие Action в каком порядке выполнять)

 

Оно? https://cloud.mail.r.../5nk8/fXhWtH3a8

 

Нет. Нужен скрин из Run Configuration (F4), секция в которой настраиваются блоки и Action, их порядок выполнения.

Также не лишним будет скрин настройки параметров (F7 или F12 не помню уже), где указано, что параметр рандомизирован на каждую итерацию

 

https://cloud.mail.r.../s8Uz/Lu7YWHL8shttps://cloud.mail.r.../7ugf/qtReugrdd. Меня тут мысль посетила, возможен ли этот сброс из-за того, что я не параметризировал выбор номера рейса? Если да, то с помощью какой функции это можно реализовать?

 

Это может быть. Если логика приложения такова (приложение не валидирует город вылета/прилета и для определения использует только номер рейса).

Попробуйте параметризовать и его, web_reg_save_param чтобы сохранить значение из response


  • 1


#166298 Не запускаются тесты в IE11 и в Firefox

Написано Alex 23 мая 2018 - 05:20

 

Весь текст ошибки в консоли:

"C:\Program Files\Java\jdk-9.0.1\bin\java" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.5\lib\idea_rt.jar=50643:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.5\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.5\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.5\plugins\junit\lib\junit-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.5\plugins\junit\lib\junit5-rt.jar;D:\ОБЩИЕ_ДОКУМЕНТЫ\IT\autotest\lesson-20\target\test-classes;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-java\2.53.0\selenium-java-2.53.0.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-chrome-driver\2.53.0\selenium-chrome-driver-2.53.0.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-remote-driver\2.53.0\selenium-remote-driver-2.53.0.jar;C:\Users\alexw\.m2\repository\cglib\cglib-nodep\2.1_3\cglib-nodep-2.1_3.jar;C:\Users\alexw\.m2\repository\com\google\code\gson\gson\2.3.1\gson-2.3.1.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-api\2.53.0\selenium-api-2.53.0.jar;C:\Users\alexw\.m2\repository\org\apache\httpcomponents\httpclient\4.5.1\httpclient-4.5.1.jar;C:\Users\alexw\.m2\repository\org\apache\httpcomponents\httpcore\4.4.3\httpcore-4.4.3.jar;C:\Users\alexw\.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;C:\Users\alexw\.m2\repository\commons-codec\commons-codec\1.9\commons-codec-1.9.jar;C:\Users\alexw\.m2\repository\com\google\guava\guava\19.0\guava-19.0.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-edge-driver\2.53.0\selenium-edge-driver-2.53.0.jar;C:\Users\alexw\.m2\repository\commons-io\commons-io\2.4\commons-io-2.4.jar;C:\Users\alexw\.m2\repository\org\apache\commons\commons-exec\1.3\commons-exec-1.3.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-firefox-driver\2.53.0\selenium-firefox-driver-2.53.0.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-ie-driver\2.53.0\selenium-ie-driver-2.53.0.jar;C:\Users\alexw\.m2\repository\net\java\dev\jna\jna\4.1.0\jna-4.1.0.jar;C:\Users\alexw\.m2\repository\net\java\dev\jna\jna-platform\4.1.0\jna-platform-4.1.0.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-safari-driver\2.53.0\selenium-safari-driver-2.53.0.jar;C:\Users\alexw\.m2\repository\io\netty\netty\3.5.7.Final\netty-3.5.7.Final.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-support\2.53.0\selenium-support-2.53.0.jar;C:\Users\alexw\.m2\repository\org\seleniumhq\selenium\selenium-leg-rc\2.53.0\selenium-leg-rc-2.53.0.jar;C:\Users\alexw\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\alexw\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 com.gmail.alex.MyTest
Started InternetExplorerDriver server (32-bit)
3.12.0.0
Listening on port 24367
Only local connections are allowed

org.openqa.selenium.remote.SessionNotFoundException: session null does not exist (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 0 milliseconds
Build info: version: '2.53.0', revision: '35ae25b1534ae328c771e0856c93e187490ca824', time: '2016-03-15 10:43:46'
System info: host: 'DESKTOP-3RL45DT', ip: '192.168.0.98', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '9.0.1'
Driver info: org.openqa.selenium.ie.InternetExplorerDriver
Capabilities [{capabilities={proxy={}, acceptInsecureCerts=false, browserVersion=11, se:ieOptions={nativeEvents=true, browserAttachTimeout=0, ie.ensureCleanSession=false, elementScrollBehavior=0, enablePersistentHover=true, ie.browserCommandLineSwitches=, ie.forceCreateProcessApi=false, requireWindowFocus=false, initialBrowserUrl=http://localhost:24367/, ignoreZoomSetting=false, ie.fileUploadDialogTimeout=3000, ignoreProtectedModeSettings=false}, timeouts={implicit=0, pageLoad=300000, script=30000}, browserName=internet explorer, pageLoadStrategy=normal, unhandledPromptBehavior=dismiss, platformName=windows, setWindowRect=true}, sessionId=e437cd11-b249-4d88-b5ea-8cdcc0156ac4, platform=ANY}]
Session ID: null

    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:206)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:158)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:678)
    at org.openqa.selenium.remote.RemoteWebDriver$RemoteWebDriverOptions$RemoteTimeouts.implicitlyWait(RemoteWebDriver.java:865)
    at com.gmail.alex.MyTest.start(MyTest.java:33)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)


Test ignored.

Process finished with exit code -1

Судя по всему есть какая-то несовеместимость. IEDriver 64 или 32 бит? Если 64, то нужно пробовать 32. Версия драйвера последняя? Какой IE хотите запустить (версия)?


  • 1


#161699 C# - NUnit - WebDriver. Внедрение Page Object. Типовой пример

Написано Alex 21 августа 2017 - 07:07

И сразу ещё один вопрос по тому, как преобразовывать некоторые методы, использующие локаторы By в методы, использующие сразу веб-элементы страниц.

Например, ранее в HelperBase.cs у меня был метод ожидания элемента:

        public IWebElement WaitForElement(By locator)
        {
            WebDriverWait waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
            return waitForElement.Until(ExpectedConditions.ElementIsVisible(locator));
        }

Как мне его переписать, чтобы на вход можно было подавать IWebElement?

Или, может, как-нибудь можно получить локатор, зная нужный нам IWebElement?

Не понял, а зачем? Если вопрос к использованию PageFactory, то... просто не пользуйтесь фабрикой там, где это неудобно. PageObject не обязывает использовать PageFactory


  • 1


#161698 C# - NUnit - WebDriver. Внедрение Page Object. Типовой пример

Написано Alex 21 августа 2017 - 07:06

 

Спасибо за помощь.

В общих чертах всё стало понятно. Попробовал реализовать - со скрипом, но заработало.

 

Сейчас структура выглядит так:

 

attachicon.gif2017-08-18_124609.png

 

Но есть большие сомнения в том, что правильно всё с кодом в плане архитектуры классов страниц (инициализация, ссылки на классы и т.д.).

Очень хотел бы услышать конструктивную критику того, что я накодил на данный момент.

 

 

ApplicationManager.cs

    public class ApplicationManager
    {
        protected IWebDriver driver;
        protected string baseURL;


        protected PageManager pageManager;


        protected LoginHelper loginHelper;
        protected NavigationHelper navigator;
        protected ContactHelper contactHelper;


        private static ThreadLocal<ApplicationManager> app = new ThreadLocal<ApplicationManager>();


        private ApplicationManager()
        {
            driver = new FirefoxDriver();
            baseURL = "...";


            pageManager = new PageManager(this);


            loginHelper = new LoginHelper(this);
            navigator = new NavigationHelper(this, baseURL);
            contactHelper = new ContactHelper(this);
        }


        ~ApplicationManager()
        {
            try
            {
                driver.Quit();
            }
            catch (Exception)
            {
                // Ignore errors if unable to close the browser
            }
        }




        public static ApplicationManager GetInstance()
        {
            if (! app.IsValueCreated)
            {
                ApplicationManager newInstance = new ApplicationManager();
                newInstance.Navigator.GoToLoginPage();
                app.Value = newInstance;
            }
            return app.Value;
        }
        
        public IWebDriver Driver
        {
            get
            {
                return driver;
            }
        }


        public PageManager Pages
        {
            get
            {
                return pageManager;
            }
        }


        public LoginHelper Auth
        {
            get
            {
                return loginHelper;
            }
        }


        public NavigationHelper Navigator
        {
            get
            {
                return navigator;
            }
        }


        public ContactHelper Contacts
        {
            get
            {
                return contactHelper;
            }
        }
    }

 

PageManager.cs

    public class PageManager    {
        protected IWebDriver driver;
        protected ApplicationManager manager;


        public PageManager(ApplicationManager manager)
        {
            this.manager = manager;
            driver = manager.Driver;


            Login = InitElements(new LoginPage(this));
        }


        private T InitElements<T>(T page) where T : AnyPage
        {
            PageFactory.InitElements(driver, page);
            return page;
        }


        public LoginPage Login { get; set; }
    }

AnyPage.cs

    public class AnyPage    {
        protected IWebDriver driver;
        private PageManager pageManager;


        public AnyPage(PageManager pageManager)
        {
            this.pageManager = pageManager;
        }
    }

LoginPage.cs

    public class LoginPage : AnyPage    {
        public LoginPage(PageManager pages) : base(pages)
        {
        }


        [FindsBy(How = How.Name, Using = "Email")]
        public IWebElement UsernameField;


        [FindsBy(How = How.Name, Using = "Password")]
        public IWebElement PasswordField;


        [FindsBy(How = How.CssSelector, Using = "button[type=\"submit\"]")]
        public IWebElement SubmitButton;




        public LoginPage LoginAsUser(string username, string password)
        {
            // type text to fields
            SubmitButton.Click();
            return this;
        }

А зачем везде передавать ApplicationManager, если он реализует Singleton?

Почему метод LoginPage.LoginAsUser возвращает страницу логина? Мы же попадаем на другую страницу по итогу. Ее и нужно возвращать.


  • 1


#161666 C# - NUnit - WebDriver. Внедрение Page Object. Типовой пример

Написано Alex 18 августа 2017 - 07:42

 

А как это будет тогда выглядеть с точки зрения структуры тестового приложения? ApplicationManager, получается, будет управлять и хелперами, и объектами страниц?

 

Можно для страниц сделать отдельный менеджер, если так удобнее.

Главное, чтобы зависимость была однонаправленная:

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

- драйвер используется только в страницах

 

+1

 

У нас как правило структура такая:

 

- tests (сами тесты)

- ui.pages - классы страниц

- ui.elements - обертки для элементов (это вовсе не обязательно)

- ui.utils - различные расширения для работы с драйвером, элементами

- helpers - собственно различные хелперы. Как минимум упомянутый AdministrationHelper. далее уже в зависимости от нужд тестов и самого приложения

- data - данные

- utils - различные утилиты

 

Это усредненно, если брать. Ограничения: страницы могут обращаться к элементам. И только. Ни тесты, ни кто либо другой с элементами не работает. Страницы работают внутри себя, могут использовать данные/утилиты, но не другие страницы (кроме варианта возвращения объекта новой страницы) и не хелперы. Хелперы могут дергать друг друга, а также методы страниц. В тестах возможно использование страниц и хелперов.


  • 1


#161625 C# - NUnit - WebDriver. Внедрение Page Object. Типовой пример

Написано Alex 17 августа 2017 - 08:09

Друзья.

Я не так давно в автоматизации тестировании и только недавно начал изучать программирование.
Работаю над своим первым проектом (C# - NUnit - Selenium WebDriver).

Написал первые тесты и осознал, что упустил по сути самое главное - про Page Object я совсем забыл. В итоге у меня все запросы написаны в хелперах, и иногда даже в тестах (что не есть хорошо, я знаю - но сейчас не об этом).

Структура проекта сейчас выглядит следующим образом:

 

attachicon.gif2017-08-16_163727.png

 

attachicon.gif2017-08-16_162548.png

 

В тестах - тесты, в хелперах - сценарии с запросами, ну и в менеджере приложений - запуск/остановка браузера.

Пример теста:

    [TestFixture]
    public class Login : TestBase
    {
        [Test]
        public void Login_LoginWithValidCredentials()
        {
            // prepare
            app.Auth.Logout();


            // action
            AccountData account = new AccountData("autotests-1@replyteam.io", "reply-auto");
            app.Auth.Login(account);


            // verification      
            //app.Auth.WaitForElement(By.TagName("rp-dropdown-menu"));
            Assert.IsTrue(app.Auth.IsLoggedIn(account));
        }
    }

И пример хелпера:

{
    public class LoginHelper : HelperBase
    {
        public LoginHelper(ApplicationManager manager) : base(manager)
        {
        }




        public void Login(AccountData account)
        {
            if (IsLoggedIn())
            {
                if (IsLoggedIn(account))
                {
                    return;
                }
                Logout();
            }


            manager.Navigator.GoToLoginPage();


            Type(By.Name("Email"), account.Username);
            Type(By.Name("Password"), account.Password);
            driver.FindElement(By.CssSelector("button[type=\"submit\"]")).Click();


            WaitForElement(By.TagName("rp-dropdown-menu"));
        }


        public bool IsLoggedIn()
        {
            return IsElementPresent(By.TagName("rp-dropdown-menu"));
        }


        public bool IsLoggedIn(AccountData account)
        {
            return IsLoggedIn()
                && GetLoggedUserName() == account.Username;
        }


        public string GetLoggedUserName()
        {
            string text = driver.FindElement(By.CssSelector(".menu-title")).Text;
            //System.Console.Out.Write(text);
            return text;
        }


        public void Logout()
        {
            if (IsLoggedIn())
            {
                driver.FindElement(By.TagName("rp-dropdown-menu")).Click();
                driver.FindElement(By.LinkText("Logout")).Click();
            }            
        }
    }
}

Гуглил много на эту тему достаточно много, но ничего подходящего, к сожалению, не нашёл. Видел пару примеров, в которых сценарии пишутся прямо в объектах страниц, без менеджера приложений, минуя хелперы, и всё...
Т.е. в целом я понимаю что такое Page Object, но не знаю что делать мне конкретно... т.е. застрял на архитектурном вопросе + его коддинге.

Подскажите, пожалуйста, как будет наиболее просто и эффективно внедрить Page Object Pattern в мой проект? 
В идеале увидеть какой-то работающий пример кода, который бы мне позволил взять его структуру 'as is' и на его основании строить и наращивать свой проект.

Ну, в целом не так и плохо, чего уж. Только ваш LoginHelper на 80% можно просто переименовать в LoginPage и получить тот же PageObject.

 

В общем случае PageObject - это реализация классов страниц 1 в 1 как в приложении. Т.е. для LoginPage создаются поля userNameEdit, passwordEdit, btnLogin. И метод login(). При необходимости могут быть добавлены loginFail, getUserName, setUserName, getPassword, setPassword и т.п. Но суть в том, что вы ограничены именно этой страницей. Соответственно там не будет методов IsLoggedIn или Logout. Потому что этой функциональности нет на странице. Вот эти части конкретно в вашем примере, мы, как правило, выносим в AdministrationHelper, который отвечает за контроль сессии пользователя в приложении.

 

Также в Helper выносится логика, которая затрагивает за раз несколько страниц (как правило, это часто повторяющиеся сценарии работы с приложением: создать документ/заказ, перевести сущность в другой статус и т.п.).


  • 1


#160347 Keys в Chrome и совместимость кода для FF и Chrome.

Написано Alex 30 мая 2017 - 09:08

 

Доброго времени суток. Я использую Python 3.6 и Selenium 3.4.2. У меня несколько вопросов. Буду признателен, если поможете.

  1. Chrome версии 58.0 не поддерживает webdriver.common.keys это зарегистрированный баг, но вот не нашёл ответа, что использовать вместо Keys. Например чтобы переключиться на соседнюю вкладку send_keys(Keys.LEFT_CONTROL+ Keys.TAB) и закрыть её send_keys(Keys.LEFT_CONTROL + "w"). Как вы выходите из такой ситуации, используете какие-то определённые версии Chrome или пишите скрипты аки javascript ниндзя?
  2. wd.find_element_by_xpath("//input[@name = 'login']").clear()
    wd.find_element_by_xpath("//input[@name = 'login']").send_keys("mylogin")
    

    С драйвером Chrome это выполняется отлично, а вот с FireFox на второй строчке выдаёт

    selenium.common.exceptions.WebDriverException: Message: Expected [object Undefined] undefined to be a string
    

    в чём может быть проблема?

  3. Должен ли (как правило или просто на ваш взгляд) тестировщик автоматизатор написанные тесты запускать на разных браузерах если тестирование только UI?

 

1. В настройках браузера отключается использование вкладок (вместо этого новые окна). Для переключения между окнами и закрытия у драйвера есть свои команды (driver.manage().switchTo() и driver.close())

2. Не  подскажу. Впервые вижу такую ошибку, может специфика phyton-а, а может в новых версиях wd действительно что-то намудрили.

3. Тема для холивара. Объективно только запуск во всех браузерах даст 100% гарантию того, что все работает в этих браузерах. Но это дорого и долго. Потому тут нужно на проектном уровне скорее определять риски и необходимость кроссбраузерного тестирования в зависимости от применяемых технологий разработки.


  • 1


#158334 Рекурсия при WebDriverTimeoutException

Написано Alex 13 февраля 2017 - 08:28

 

Ну и как эти пользователи терпят эти 180 секунд? Кофе себе делают или ещё что?

Может чинить надо не тесты а систему?

Если бы кто то за это взялся... у нас в компании изначально разрабов возвели в этакие боги всего и вся, вобщем в любом случае надо мне подправить решение которое я  продемонстрировал, как это сделать я не совсем понимаю в силу своей  неопытности. Есть какие то предложения или советы?

 

А что конкретно мешает сделать TimeSpan.FromSeconds(60) конфигурируемым? То, что время отклика разное в разных окружениях - не новость. Потому, собственно, таймауты  и выносятся в набор настроек теста


  • 1