Selenium RC (Java): Основные операции в действии. Часть 1

Часть 2

В стандартной документации к селениуму достаточно много примеров тестов, но они в основном направлены на то, чтобы показать структуру тестов, а также некоторый частный случай использования тех или иных операций. При этом мало внимания уделяется обзору имеющихся команд. И это в принципе неудивительно, так как по сути мы используем один клиентский класс, у которого определены все необходимые нам методы. И уже в зависимости от конкретной задачи мы просто ищем нужный метод, который бы эту задачу выполнил. Тем не менее, мелких деталей всегда хватает и на их разбор может уйти много времени, что может вызвать множество проблем, особенно для начинающих. Поэтому, целью данного поста является ознакомление с основными операциями селениума, с которыми так иил иначе придется иметь дело, а также описание возможных нюансов, которые могут возникнуть.

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

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

Для нашего примера нужно создать тестовый HTML файл, в котором будут основные элементы, с которыми мы будем работать. Создадим файл index.htm и поместим его в корневой каталог диска C: . Если вы хотите поместить этот файл в другой каталог, то вам надо будет просто поменять абсолютный путь к файлу и учитывать это вдальнейшем при рассмотрении данного примера.

Итак, поместим в наш HTML-файл содержимое вида:

{syntaxhighlighter brush: xml;fontsize: 100; first-line: 1; }<html> <body> <form name="sample_form"> <table> <tr><td width="100%"><fieldset><legend>Text fields</legend> <table> <tr> <td><label for="text_field">Simple text field:</td> <td><input type=text id="text_field" value="" /></td> </tr> <tr> <td valign=top><label for="text_area">Text Area:</td> <td><textarea id="text_area" name="text_area" cols=30 rows=5></textarea></td> </tr> </table> </fieldset></td></tr> <tr><td width="100%"><fieldset><legend>Radio buttons/Check boxes</legend> <table> <tr> <td><label for="radio_1">Item 1:</td> <td><input type=radio id="radio_1" name="radio_btn" checked /></td> </tr> <tr> <td><label for="radio_2">Item 2:</td> <td><input type=radio id="radio_2" name="radio_btn"/></td> </tr> <tr> <td valign=top><label for="check_box">Check box:</td> <td><input type=checkbox name="check_box" /></td> </tr> <tr> <td valign=top><label for="ev_check_box">Check box with event:</td> <td><input type=checkbox name="ev_check_box" onclick="deactivated_btn.disabled=!this.checked;"/></td> </tr>

		&lt;/table&gt;
	&lt;/fieldset&gt;&lt;/td&gt;&lt;/tr&gt;

	&lt;tr&gt;&lt;td width="100%"&gt;&lt;fieldset&gt;&lt;legend&gt;Buttons&lt;/legend&gt;
		&lt;table&gt;
			&lt;tr&gt;
				&lt;td&gt;&lt;b&gt;&lt;div id="clicked_text"&gt;&lt;/div&gt;&lt;/b&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
				&lt;td&gt;
				&lt;input type=button id="deactivated_btn" value="Deactivated" onclick="clicked_text.innerHTML=deactivated_btn.value;"/&gt;
				&lt;input type=button id="btn_1" value="First"  onclick="clicked_text.innerHTML=btn_1.value;"/&gt;
				&lt;button id="btn_2" onclick="clicked_text.innerHTML=btn_2.innerHTML;return false;"&gt;Second&lt;/button&gt;
				&lt;/td&gt;
			&lt;/tr&gt;

		&lt;/table&gt;
	&lt;/fieldset&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td width="100%"&gt;&lt;fieldset&gt;&lt;legend&gt;Lists&lt;/legend&gt;
		&lt;table&gt;
			&lt;tr&gt;
				&lt;td&gt;&lt;label for="single_list"&gt;Single selection list:&lt;/td&gt;
				&lt;td&gt;
				&lt;select id="single_list" /&gt;
					&lt;option selected&gt;Option 1&lt;/option&gt;
					&lt;option&gt;Option 2&lt;/option&gt;
					&lt;option&gt;Option 3&lt;/option&gt;
				&lt;/select&gt;
				&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
				&lt;td valign=top&gt;&lt;label for="multi_list"&gt;Multi selection list:&lt;/td&gt;
				&lt;td&gt;
					&lt;select id="multi_list" MULTIPLE&gt;
					&lt;option&gt;Multi Option 1&lt;/option&gt;
					&lt;option&gt;Multi Option 2&lt;/option&gt;
					&lt;option&gt;Multi Option 3&lt;/option&gt;
					&lt;/select&gt;
				&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;
	&lt;/fieldset&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;tr width="100%"&gt;&lt;td width="100%"&gt;&lt;fieldset&gt;&lt;legend&gt;File input&lt;/legend&gt;
		&lt;table&gt;
			&lt;tr&gt;
				&lt;td valign=top&gt;&lt;label for="file_input"&gt;File upload:&lt;/td&gt;
				&lt;td&gt;&lt;input type=file name="file_field" /&gt;&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;

	&lt;/fieldset&gt;&lt;/td&gt;&lt;/tr&gt;

	&lt;tr&gt;&lt;td&gt;&lt;fieldset&gt;&lt;legend&gt;Dialog boxes&lt;/legend&gt;
		&lt;table&gt;
			&lt;tr&gt;
				&lt;td&gt;
					&lt;input type=button id="alert_btn" value="Call Alert"onclick="alert('This is Alert');"/&gt;
					&lt;input type=button id="conf_btn" value="Call Confirmation"  onclick="confirm('This is confirmation');"/&gt;
					&lt;input type=button id="prompt_btn" value="Call Prompt"  onclick="prompt('Enter prompt text')"/&gt;&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;

	&lt;/fieldset&gt;&lt;/td&gt;&lt;/tr&gt;

	&lt;/table&gt;
&lt;/form&gt;

</body>
</html>{/syntaxhighlighter}

Достаточно просто скопировать данный текст и вставить его в нужный HTML-файл.

Осталось только создать тестовый класс, в котором мы будем добавлять код. Создайте пакет com.example.tests и создайте в нем класс NewTest, который наследуется от SeleneseTestCase класса. После этого каркас теста имеет вид:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; }package com.example.tests;
// We specify the package of our tests

import com.thoughtworks.selenium.*;
// This is the driver’s import. You’ll use this for instantiating a
// browser and making it do what you need.

import java.util.regex.Pattern;
// Selenium-IDE add the Pattern module because it’s sometimes used for
// regex validations. You can remove the module if it’s not used in your
// script.

public class NewTest extends SeleneseTestCase {
// We create our Selenium test case

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
         // We instantiate and start the browser
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
 }

}{/syntaxhighlighter}

Этот каркас взят из примеров в документации к селениуму. Просто были сделаны небольшие корректировки. Итак, приступаем.

Вводим текст

Итак, откроем нашу страницу и посмотрим на первую секцию. Там содержится 2 текстовых поля:Simple text field и Text Area соответственно. Одно из них - это однострочное поле, а второе - многострочное. Итак, выполним следующий сценарий:

  • Ввести текст в однострочное текстовое поле
  • Убедиться, что введенный текст отображается
  • Ввести текст в однострочное текстовое поле
  • Убедиться, что введенный текст отображается

Для обычного ввода текста используется метод type. Он принимает 2 параметра: локатор и вводимый текст. С локаторами задача довольно проста, так как все элементы управления на данной странице имеют фиксированное значение атрибутов id и name. Наши текстовые поля имеют id text_field и text_area соответственно. С вводимым текстом тоже проблем не должно возникнуть, так как это просто произвольная строка.

Теперь посмотрим, чем мы текст будем извлекать. В однострочном текстовом поле значение введенного текста хранится в свойстве value. Интересно, а ведь у селениума есть метод getValue. Аналогично для многострочных полей. Поскольку нам пока особо не надо заморачиваться над различными вводимыми значениеми, то реализация теста достаточно проста. И выглядит это примерно вот так:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [11,12,13,14]; }import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( getValue( "text_area" ) , "Sample Text" );
 }

}{/syntaxhighlighter}

Внесенные изменения выделенны в коде. Небольшой итог:

  • Для ввода текста используем метод type
  • Для извлечения текста используем getValue

Работаем с радио-кнопками и чек-боксами

Переходим ко второй секции. Здесь мы отработаем функционал для работы с чек-боксами и радио-кнопками. На самом деле интерес представляет помимо прочего и 3-я секция - секция с кнопками, так как по функционалу второй чек-бокс активирует кнопку. Итак, возьмем вот этот фрагмент страницы:

Item 1:
Item 2:
Check box:
Check box with event:



И опишем сценарий вида:

  1. Выбрать радио-кнопку Item 2 и убедиться, что элемент выбран
  2. Выбрать радио-кнопку Item 1 и убедиться, что элемент выбран
  3. Установить флаг в поле Check Box и проверить, что флаг установлен
  4. Сбросить флаг с поля Check Box и проверить, что флаг сброшен
  5. Установить флаг в поле Check Box with event, убедиться, что кнопка Deactivated стала активной
  6. Сбросить флаг с поля Check Box with event и проверить, что кнопка Deactivated стала неактивной

Чек-боксы и радио-кнопки объединяет общий набор действий, который нас интересует. Во-первых, и в чек-боксе, и на радио-кнопке можно установить флаг, выбрать. Во-вторых, у этих видов элементов есть 2 состояния: выбран или нет, которое можно проверить.

Какие методы селениума нам для этого нужны:

  • check/uncheck - принудительно устанавливает/сбрасывает флаг из чек-бокса или радио-кнопки. Метод uncheck применим только к чек-боксу.
  • click - имитирует клик по заданному элементу. Это универсальный метод и работает для всех элементов управления. Здесь он упоминается потому, что в некоторых случаях он отрабатывает корректнее check/uncheck
  • isChecked - метод, проверяющий состояние чек-бокса или радио-кнопки (включена/выключена)

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

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [19,20,21,22]; }package com.example.tests; import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );
 }

}{/syntaxhighlighter}

Вот 4 строки подсвеченные показывают, как это реализуется. Это типичные конструкции для работы с чек-боксами. Но появляются нюансы, как тот, что ожидает нас в последних 2-х шагах нашего сценария. Давайте посмотрим на HTML-код второго чек-бокса. Вот он:

{syntaxhighlighter brush: xml;fontsize: 100; first-line: 1; }<input name=“ev_check_box” onclick=“deactivated_btn.disabled=!this.checked;” type=“checkbox”>{/syntaxhighlighter}

Особенно обратим внимание на выделенное. У данного чек-бокса есть дополнительный обработчик события onclick, соответственно, код этого обработчика сработает именно при клике на данный элемент. А теперь ВНИМАНИЕ!!! Если мы установим флажок в этом поле при помощи метода check, то обработчик события onclick в этом случае не сработает! Это связано с тем, что метод check оперирует с обработчиками других событий. Вот в таком случае, с целью привести в соответствие ручное и автоматическое выполнение теста, нам нужно инициировать именно клик на данном чек-боксе. Естественно, если нам надо установить флаг в этом поле, то для начала надо определить, есть ли он уже там и только потом решать, нужен ли еще один клик. То есть надо сделать как-то так:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [29,30,31]; }package com.example.tests;
import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }
 }

}{/syntaxhighlighter}

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

Но на этом трудности не заканчиваются. Следующий шаг - проверить, что кнопка Deactivated неактивна. Это нужно проверить значение свойства disabled у соответствующей кнопки. Вся проблема в том, что у селениума нет выделенного для этой цели метода. Тут нужно вызывать JavaScript. Nут нужно оперировать со свойством disabled, которое есть у всех элементов управления в DOM-структуре страницы. Для вызова JavaScript-инструкций в Selenium-е используется метод getEval. Возвращаемое значение - строка, содержащая результат выполнения кода, передаваемого параметром. По-хорошему, нужно написать отдельный метод-обертку, который бы скрывал прямой вызов JavaScript, да и просто абстрагировал логику выполняемых операций от реализации, но это тема отдельной статьи. Итак, добавим код, проверяющий, что кнопка с ID равным “deactivated_btn” стала активной. Добавим код вида:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [33,34,35]; }package com.example.tests;
import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );
 }

}{/syntaxhighlighter}

Изменения подсвечены жирным. JavaScript-код получился довольно громоздким, но суть его такова: мы знаем ID нужного элемента, соответственно, мы можем найти этот элемент на странице и проверить его свойство disabled. Мы ожидаем, что оно будет равняться false. По аналогии, мы выполняем последний шаг теста, в котором мы сбрасываем флаг с чекбокса и проверяем, что кнопка деактивировалась. Вот так:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [37,38,39,40,41,42,43,44]; }package com.example.tests;
import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );

       if( selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "true" ) );

 }

}{/syntaxhighlighter}

Вот так мы завершили еще одну часть, испытав основные возможности работы с чек-боксами и радио-кнопками. Небольшой итог:

  • check/uncheck позволяет устанавливать/сбрасывать флаг в чек-боксе. Также check позволяет установить отметку в радио-кнопке.
  • Для выбора нужной радио-кнопки методы check/click в целом равнозначны за исключением ряда особых случаев.
  • Состояние радио-кнопки или чек-бокса проверяется методом isChecked
  • Если на чек-боксе или радио-кнопке стоит обработчик события onclick, то корректнее будет использовать метод click для изменения состояния, с предварительной проверкой на isChecked, чтоб четко контролировать состояние элемента управления
  • Активность/неактивность элемента проверяется путем вызова JavaScript-инструкций при помощи метода getEval.

Работа с кнопками и извлечение текста

Переходим к рассмотрению секции кнопок. В предыдущем разделе мы частично с этими кнопками работали, когда проверяли, что одна из кнопок активизируется. Теперь мы рассмотрим сценарий, проверяющий функционал данных кнопок. Итак, вот эта секция:




При клике на ту или иную кнопку появляется текст, который соответствует тексту нажатой кнопки. Соответственно, реализуем сценарий вида:

  1. Установть флаг в Check box with event: чек-боксе, чтобы активировать Deactivated кнопку
  2. Кликнуть на кнопку Deactivated и проверить, что появится текст Deactivated над кнопками
  3. Повторить то же самое для кнопок First и Second. Проверить, что над кнопками отображается текст, соответствующий тексту на нажатой кнопке.

Первый шаг фактически повторяет действия, которые мы делали в предыдущем пункте. Клик на кнопку, как и для других объектов, осуществляется методом click. Тут всё просто. Для проверки существования текста есть общий метод isTextPresent. Для начала воспользуемся им. Итак, первые 2 шага делаются следующим образом:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [[46,47,48,49,50,51]]; }package com.example.tests; import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );

       if( selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "true" ) );

  
       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       selenium.click( "deactivated_btn" );
       assertTrue( selenium.isTextPresent( "Deactivated" ) );
 }

}{/syntaxhighlighter}

Вот этот фрагмент (в частности выделенное) выполнит нужные действия. Но есть несколько замечаний:

  1. Текст, который мы ищем, задан явно, что не очень надежно, так как текст кнопки может быть изменен и данный фрагмент кода будет чувствителен к изменениям. В контексте данной задачи удобно привязаться к значению атрибуты value данной кнопки. Это видно, если посмотреть на обработчик события onclick.
  2. Метод isTextPresent ищет вхождение указанного текста по всей странице. Фактически он берет HTML-код страницы, обрезает весь текст, находящийся внутри тегов и уже оставшийся текст проверяет на вхождение указанной подстроки. Если у нас текст уникальный и мы четко знаем, что такой текст будет присутствовать только в нужном нам месте, то никаких проблем нет. Но если текст простой и может встречаться в разных местах страницы (например, какой-то другой элемент будет иметь подпись, содержащую нужную нам подстроку), то данная проверка не даст точных реузльтатов.

Первый пункт исправляется путем использования метода getValue. Второе замечание приводит нас к тому, что нам надо не просто искать какой-то текст, но искать его в конкретном месте. Если посмотреть на код страницы, то можно обнаружить, что появляющийся текст отображается внутри конструкции вида:

{syntaxhighlighter brush: xml;fontsize: 100; first-line: 1; }<div id=“clicked_text”></div>{/syntaxhighlighter}

То есть у нас есть div с заданным id, а искомый текст - это фактически текстовое содержимое данного элемента. То есть нам надо извечь текст из элемента, зная его локатор. Для этих целей используется метод getText. Если внутри элемента будут содержаться теги, то они будут обрезаны. В данном случае это нам не грозит, поэтому использование данного метода не только возможно, но и наиболее целесообразно. Учитывая вышеназванные замечания, перепишем предыдущий код в виде:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [[51,52,53,54]]; }package com.example.tests;
import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );

       if( selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "true" ) );

  
       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       selenium.click( "deactivated_btn" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "deactivated_btn" )
       );
 }

}{/syntaxhighlighter}

Собственно говоря, поменять надо было только последнюю строку. Теперь осталось реализовать последний шаг сценария. Нужно кликнуть на кнопки First и Second, после чего проверить, что отобразился текст этих кнопок. Для кнопки First всё делается аналогично предыдущим шагам:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [[56,57,58,59,60]]; }package com.example.tests;
import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );

       if( selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "true" ) );

  
       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       selenium.click( "deactivated_btn" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "deactivated_btn" )
       );

       selenium.click( "btn_1" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "btn_1" )
       );
 }

}{/syntaxhighlighter}

Фактически код для работы с кнопкой Deactivated был продублирован для кнопки First. Для кнопки Second всё практически то же самое. Но есть одно НО. Вот HTML-код данной кнопки:

{syntaxhighlighter brush: bash;fontsize: 100; first-line: 1; }<button id=“btn_2” onclick=“clicked_text.innerHTML=btn_2.innerHTML;return false;”>Second</button>{/syntaxhighlighter}

Данная кнопка описана с использованием тега button, в отличие от предыдущих кнопок, которые были описаны через тег input. Это вносит ряд корректив, но в нашем случае она всего одна: метод getValue не сработает, так как атрибут value для данной кнопки не определен. Тут нужно использовать getText. С учетом данных замечаний, последний шаг реализуем так:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [[62,63,64,65,66]]; }package com.example.tests;
import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );

       if( selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "true" ) );

  
       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       selenium.click( "deactivated_btn" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "deactivated_btn" )
       );

       selenium.click( "btn_1" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "btn_1" )
       );

       selenium.click( "btn_2" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getText( "btn_2" )
       );
 }

}{/syntaxhighlighter}

Вот, собственно, и всё по части кнопок. Небольшой итог по данной части:

  • Для нажатия кнопоки в основном используется метод click.
  • Существование текста на странице проверяется методом isTextPresent, но если есть возможность локализовать текст в пределах некоторого элемента, то лучше извлечь текст методом getText, после чего сравнить полученный текст с ожидаемым.
  • Если нужно извлечь текст кнопки, то нужно посмотреть, как она реализована на уровне HTML. Если используется тег input, то скорее всего текст будет задаваться значением атрибута value и прочесть его можно методом getValue. Если же используется тег button и текст кнопки находится между соответствующим открывающимся и закрывающимся тегами, то в этом случае мы получим текст, используя метод getText.

Работа со списками

Переходим к расмотрению следующей секции нашей тестовой страницы. А именно:

Single selection list:
Option 1 Option 2 Option 3
Multi selection list:
Multi Option 1 Multi Option 2 Multi Option 3

Для данной секции автоматизируем следующий сценарий:

  • Выбрать элемент Option 2 в поле Single Select и проверить, что элемент выбран
  • В поле Multi selection list выбрать опции Multi Option 2 и Multi Option 3 и убедиться, что только эти опции выбраны.

Для реализации первого шага нам нужен метод select. Первым параметром он принимает локатор выпадающего списка, в котором надо выбрать опцию. Второй параметр описывает опцию, которую надо выбрать. Опция может быть задана 4-мя способами:

  • label=labelText - наиболее часто используемый способ нахождения элемента исходя из текста выбираемого элемента. Это может быть как точный текст, так и регулярное выражение, по которому ищется опция, которую надо выбрать
  • value=valueText - используется, когда каждая опция имеет атрибут value. Соответственно, будет выбран элемент, атрибут value которого будет соответствовать выражению справа от знака =.
  • id=id - используется в случае, если выбираемая опция имеет атрибут id.
  • index=index - позволяет задать порядковый номер выбираемой опции. Нумерация начинается с 0.

По умолчанию используется label=. Далее, надо извлечь выбранный текст и проверить, что он соответствует ожидаемому. В этом нам поможет метод getSelectedLabel. Итак, реализуем первый шаг:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [[68,69,70,71,72]]; }package com.example.tests; import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );

       if( selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "true" ) );

  
       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       selenium.click( "deactivated_btn" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "deactivated_btn" )
       );

       selenium.click( "btn_1" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "btn_1" )
       );

       selenium.click( "btn_2" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getText( "btn_2" )
       );

       selenium.select( "single_list" , "Option 2" );
       assertEquals( 
            selenium.getSelectedLabel( "single_list" ) ,
            "Option 2"
       );
 }

}{/syntaxhighlighter}

Теперь приступим ко второму шагу. Нам опять предстоит выбрать элементы в списке, но теперь нужно взять несколько элементов одновременно. Нам по-прежнему будет нужна помощь метода select, но помимо него надо воспользоваться еще каким-то методом, так как select выполняет те же действия, что и обычный клик на элементе. Для multiselect-листов это означает, что предыдущая выборка сбрасывается. Для того, чтобы выбрать некоторый элемент в дополнение к уже выбранным элементам, нам нужно воспользоваться методом addSelection. Параметры у него такие же, что и у метода select.

Этого достаточно для выполнения действий. Осталось определиться, чего нам нехватает для верификаций. Нам нужно получить список выбранных элементов. Метод getSelectedLabel нам не подойдет, так как он возвращает только один элемент, а по сценарию их должно быть 2. Для этого у нас есть метод getSelectedLabels, который вернет массив строк, содержащих текст выбранных элементов. Всё, нужные методы мы подобрали, осталось только всё это реализовать. Как-то так:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; highlight: [[74,75,76,77,78,79,80,81,82,83,84]]; }package com.example.tests;
import com.thoughtworks.selenium.*;

import java.util.regex.Pattern;

public class NewTest extends SeleneseTestCase {

  public void setUp() throws Exception {
    setUp("c:\\index.htm", "*firefox");
  }

  public void testNew() throws Exception {
       selenium.open("c:\\index.htm");
       selenium.type("text_field" , "Sample Text" );
       assertEquals( selenium.getValue( "text_field" ) , "Sample Text" );
       selenium.type("text_area" , "Sample Text" );
       assertEquals( selenium.getValue( "text_area" ) , "Sample Text" );

       selenium.click( "radio_2" ); // Select item via click
       assertTrue( selenium.isChecked( "radio_2" ) );
       selenium.check( "radio_1" ); // Select item via check
       assertTrue( selenium.isChecked( "radio_1" ) );

       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );
       selenium.check( "check_box" );
       assertTrue( selenium.isChecked( "check_box" ) );

       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "false" ) );

       if( selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       assertTrue( selenium.getEval( "var win = selenium.browserbot.getCurrentWindow();" +
                "var element = win.getElementById('deactivated_btn',win);" +
                "element.disabled;" ).toLower().equals( "true" ) );

  
       if( !selenium.isChecked( "ev_check_box" ) ){
             selenium.click( "ev_check_box" ); // Set check mark initiating onclick event
       }

       selenium.click( "deactivated_btn" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "deactivated_btn" )
       );

       selenium.click( "btn_1" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getValue( "btn_1" )
       );

       selenium.click( "btn_2" );
       assertEquals( 
            selenium.getText( "clicked_text" ),
            selenium.getText( "btn_2" )
       );

       selenium.select( "single_list" , "Option 2" );
       assertEquals( 
            selenium.getSelectedLabel( "single_list" ),
            "Option 2"
       );

       selenium.select( "multi_list" , "Multi Option 2" );
       selenium.addSelection( "multi_list" , "Multi Option 3" );
       String[] selectedOpts = selenium.getSelectedLabels( "multi_list" );
       assertEquals( 
            selectedOpts[0], 
            "Multi Option 2"
       );
       assertEquals( 
            selectedOpts[1],
            "Multi Option 3"
       );
 }

}{/syntaxhighlighter}

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

Итак, в очередной раз мы рассмотрели раздел, на основе чего можем подытожить следующее:

  • Для выбора одного элемента используется метод select
  • При выборе нескольких элементов, каждый последующий элемент выбирается методом addSelection
  • Текст выбранной опции возвращается методом getSelectedLabel. В случае multiselect-списка массив выбранных элементов извлекается при помощи метода getSelectedLabels.

Продолжение следует …

Часть 2

не могу запустить скрипт в эклипсе, ругается на toLower(): The method toLower() is undefined for the type String 

Пожалуйста, подскажите причину.

Я думаю, данный метод был в предыщущей версии java. Он преобразует оригинальную строку и строку, где все символы с нижним регистром. Попробуйте переименовать toLower() в toLowerCase()

Описания класса String http://download.oracle.com/javase/6/docs/api/java/lang/String.html