Почему методы
getAttribute()
и getCssValue()
возвращают не те значения, которые записаны в атрибуте и css?
Это происходит потому что getAttribute()
, вопреки своему названию, возвращает значение свойства синхронизированного с атрибутом, и только в случае, если такое свойство не найдено, возвращает значение самого атрибута.
Немного теории про атрибуты и свойства.
У DOM-элементов в javascript есть свойства и атрибуты. DOM-элемент можно рассматривать с двух сторон. С первой он представляет собой объект javascript и как любой объект ООП имеет свойства. С другой стороны он является HTML элементом и может иметь любое заданное количество атрибутов. Доступ к свойствам элемента осуществляется через стандартный синтаксис, используя «.» (element.name
). Доступ к атрибутам происходит посредством специальных методов: setAttribute(name, value)
, getAttribute(name)
и т.д. На первый взгляд кажется, что свойства и атрибуты никак не связаны, но на самом деле между ними существует искусственное соответствие. Браузер синхронизирует некоторые свойства с атрибутами элемента, это гарантируется для всех основных стандартных атрибутов. Чаще всего имя атрибута полностью совпадает с именем свойства, но не всегда. Такая синхронизация означает, что изменение значения атрибута влечет за собой изменение значения свойства, и наоборот. Но не всегда значение просто устанавливается в свойство в исходном виде. Атрибут может быть любой строкой, он лишь показывает, что написано в исходном коде документа. Свойства же отображают текущее состояние элемента, и не могут содержать недопустимых значений.
Посмотрим как все это работает на практике. В качестве примера возьмем ползунок слайдера, при его передвижении изменяется значение left внутри атрибута style:
<a href="#" class="ui-slider-handle" style="left: 75%;"></a>
Вот так выглядят интересующие нас атрибуты на закладке «Стиль» плагина Firebug: Свойства объекта можно посмотреть на закладке DOM. Так выглядят синхронизированные с атрибутами свойства:
А теперь посмотрим что возвращает Selenium при попытке получить атрибуты и css значения.
System.out.println("getCssValue(\"left\"): " + slider.getCssValue("left")); System.out.println("getAttribute(\"style\"): " + slider.getAttribute("style")); System.out.println("getAttribute(\"offsetLeft\"): " + slider.getAttribute("offsetLeft")); System.out.println("getAttribute(\"href\"): " + slider.getAttribute("href"));
Вывод в консоль:
getCssValue("left"): 66px getAttribute("style"): left: 75%; getAttribute("offsetLeft"): 66 getAttribute("href"): http://127.0.0.1/ui_test#
Значение, которое возвращает метод getCssValue()
в некоторых случаях отличается от представленного в верстке, потому что getCssValue()
возвращает уже окончательные вычисленные СSS-свойства элемента (в нашем случае проценты были пересчитаны в px).
Selenium вернул нам значение для параметра offsetLeft, хотя такой атрибут у элемента не задан. Фактически получается, что в метод можно передавать не только имена атрибутов, но и свойств. Аналогичным образом можно получить верстку элемента и другие интересующие Вас свойства:
webElement.getAttribute("innerHTML");
Такой подход к получению данных с одной стороны не соответствует названию метода, с другой — позволяет всегда получать текущие параметры элемента. Например, получение текста из input-полей (getAttribute("value")
): атрибут value определяет только начальное значение для текстового поля и больше не изменяется. Текущее же значение хранится в свойстве value и изменяется через него же. Так как Selenium возвращает именно значение свойства, мы всегда можем получить актуальный текст в поле.
Что касается значения href, то здесь можно быть всегда уверенным, что ссылка вернется полной (абсолютной), даже если в атрибуте ссылка указана относительная.
Небольшое исключение составляет браузер IE до 8-мой версии, он старается по возможности уравнять свойства и атрибуты и не выполняет нормализацию ссылки в свойстве. В этом случае Selenium самостоятельно нормализует и возвращает абсолютную ссылку, обеспечивая этим одинаковую работу метода getAttribute()
во всех браузерах.
Теперь о получении текста элемента. Текст можно получить двумя способами — getAttribute("text")
(для input-полей getAttribute("value")
) и методом getText()
.
Метод getAttribute("text")
всегда возвращает значение атрибута без каких-либо преобразований — текст вернется точной копией, записанной в верстке.
В отличии от него метод getText()
возвращает текст, выполняя его нормализацию аналогично браузеру, т.е. текст вернется таким, как отображается в браузере, несмотря на верстку.
getText()
помимо текста самого элемента, склеивает в возвращаемое значение также и текст вложенных в него элементов, если только они видимы.
Что происходит с пробелами при нормализации:
- несколько пробелов (табов или переводов строки), идущих подряд, заменяются одним единственным пробелом (кроме неразрывных (
- обычные пробелы вначале и в конце текста удаляются;
- текст из тега <pre> или элементов со стилем «white-space: pre» возвращается с сохранением всех пробелов.
Татьяна, благодарю Вас за Ваши статьи. Много полезного в них нашел 🙂
Успехов Вам!
Да. Огромное спасибо за статьи. Много интересного и полезного