Делаем кроссбраузерные тесты поверх webdriver
DESCRIPTION
Презентация доклада Игоря Павлова на конференции SQADays-14, Львов 8-9 ноября 2013TRANSCRIPT
Делаем кроссбраузерные тестыповерх WebdriverПавлов Игорь
2gis.ru @rnd2gis
Обо мне• В 2ГИС 1+ год
• Команда автоматизации тестрования
• Работал над инструменами тестирования для всех внешних web-
проектов
2
О чем будет• Откуда проблемы кроссбраузерности?
• Примеры проблем кроссбраузерности
• Решение - фреймворк
• Практические рекомендации
3
Откудапроблемы?
Webdriver
5
Webdriver Local End
The WebDriver Wire Protocol (Json Wire Protocol)
https://code.google.com/p/selenium/wiki/JsonWireProtocol
6
Webdriver Remote End
WebDriver W3C Draft
http://www.w3.org/TR/webdriver
7
Интерфейс команды один8
Реализация разная
9
О чем будет• Откуда проблемы кроссбраузерности?
• Примеры проблем кроссбраузерности
• Решение - фреймворк
• Практические рекомендации
10
Примеры
Click
1. В центр элемента
2. Viewport содержит элемент
• MAY: scrollIntoView
3. Должен быть видим*
WebDriver W3C Clicking
http://www.w3.org/TR/webdriver/#clicking
12
Click: все хорошо?Chrome OK
Firefox OK
Opera OK
Internet Explorer OK
клик в желтый div
13
Click: а так?Chrome FAIL
Firefox OK
Opera OK
Internet Explorer NOTHING
клик в желтый div
14
Click: или даже так?Chrome FAIL
Firefox OK
Opera OK
Internet Explorer NOTHING
клик в желтый div
15
Click: динамический контент16
Click: другие проблемы• прозрачность (opacity)?
• анимации?
• ...
17
onload
AJAX:
• проверить отсутствие элемента
18
resize
Опера не поддерживает
19
С Оперой все грустно. Пока...20
Решенияпримеров
Дождаться элементаdriver.implicitly_wait(5)
start = time.time()
while not result and time.time() < start + timeout:
try:
result = driver.find_element_by_id("id")
except:
pass
01.
02.
03.
04.
05.
06.
22
JS в помощь23
Маркеры
24
JQuery clickscript = "arguments[0].click();"
driver.execute_script(script, element)
01.
02.
25
Поднимаем нужный маркер26
Поднимаем нужный маркер27
Поднимаем нужный маркерscript = "arguments[0].style.zIndex++;"
driver.execute_script(script, marker)
marker.click()
01.
02.
03.
28
Итог
Расширяем свои возможности засчет:
1. Продуманных обработок ошибок
2. Инъекции JS
Проблема
Как не умереть от поддержки тестов с этим всем?
29
О чем будет• Откуда проблемы кроссбраузерности?
• Примеры проблем кроссбраузерности
• Решение - фреймворк
• Практические рекомендации
30
Фреймворк
Цель фреймворка:1. сделать тесты понятными и читаемыми
2. контролировать ньюансы кроссбраузерного запуска
32
Пять уровней33
Уровень Driver34
Уровень DriverЦель: расширить возможности базового элемента
Driver inheritance36
Driver inheritanceclass TestDriver(Remote):
def __init__(self, *args, **kwargs):
super(TestDriver, self).__init__(*args, **kwargs)
self._browser = None
01.
02.
03.
04.
37
WebElement inheritance38
WebElement inheritanceclass TestWebElement(WebElement):
def __init__(self, driver,web_element):
self.__dict__.update(web_element.__dict__)
self.driver = driver
01.
02.
03.
04.
39
find_element(s) override40
find_element(s) override:with onload solutiondef find_element(self, *args, **kwargs):
try:
wait_for_element_appear(*args, **kwargs)
element = self.driver.find_element(*args, **kwargs)
except TimeoutException:
raise ElementNotFound(kwargs["value"], kwargs["by"])
return TestWebElement(self.driver, element)
01.
02.
03.
04.
05.
06.
07.08.
41
TextWebElement extension42
TextWebElement extensionclass TestWebElement(WebElement):
***
def find_element_by_sizzle(self, sizzle_selector):
pass
def javascript_click(self):
pass
01.
02.
03.
04.
05.
06.
07.
08.
43
Итог
TestWebElement — "всему голова"
44
Уровень PageObject45
УровеньPageObject
Цель: описать приложение компонентами* и связать их
Page
47
Map
48
Markers
49
Page
50
Page
class Page(object):
def __init__(self, driver):
self.driver = driver
self._map = None
01.
02.
03.
04.
51
Components
52
Components
class Map(TestWebElement):
pass
class Marker(TestWebElement):
pass
01.
02.
03.
04.
05.
53
Связь page.map: map()54
map()
@property
def map(self):
selector = Map.selectors['self']
if self._map is None:
element = self.driver. ### перенос
find_element_by_css_selector(selector)
self._map = Map(self.driver, element)
return self._map
01.
02.
03.
04.
05.
06.
07.
08.
55
Изолируем взаимодействие слокаторами
class Map(TestWebElement):
selectors = {self': '#map'}
class Marker(TestWebElement):
selectors = {'self': '.marker'}
01.
02.
03.
04.
05.
56
Связь map.markers: markers()57
markers()
class Map(TestWebElement):
...
def get_markers(self):
selector = Marker.selectors['self']
elements = self. ### перенос
find_elements_by_css_selector(selector)
return [Marker(elem) for elem in elements]
01.
02.
03.
04.
05.
06.
07.
58
Итог
Получили удобные* методы доступа к карте и маркерам
*Удобно для нас, это:
1. Работа в контексте приложения,
2. Легче контролировать изменения локаторов.
59
Уровень Action60
УровеньAction
Цель: добавить компонентам действия (из бизнес-логики)
Определяем клик в маркерclass Marker(TestWebElement):
def _original_click(self, *args, **kwargs):
super(Marker, self).click(*args, **kwargs)
def click(self):
self.bring_to_front()
self._original_click()
01.
02.
03.
04.
05.
06.
07.
62
Итог
Описали какими функциональными действия обладают компоненты
63
Уровень Test64
УровеньTest
Цель: реализовывать тест кейсы понятно
Test Case"""
- Делаем поиск
- На карте кликаем в маркер
- Название фирмы в коллауте ищем в результатах поиска
ОР: Название фирмы в коллуте есть в результатах поиска
"""
01.
02.
03.
04.
05.
06.
07.
66
Test
def test_firmcallout_title_in_firmcards_titles(self):
self.page.searchBar.catalogTab.search('пиво')
self.page.map.markers[0].click()
title = self.page.map.firmCallout.title
self.assertTrue(title in self.page.searchResults)
01.
02.
03.
04.
05.
67
Уровень Framework68
УровеньFramework
Цель: предоставить все необходимое для организации и запуска тестов
Framework
Фреймворк для юнит-тестов:
• runner
• data providers
• ...
70
О чем будет• Откуда проблемы кроссбраузерности?
• Примеры проблем кроссбраузерности
• Решение - фреймворк
• Практические рекомендации
72
Рекомендации
1. А нужно ли оно вам?74
Статистика пользователей 2gis.ruChrome 37,58 %
Opera 23,49 %
Firefox 14,33 %
Internet Explorer 9,99 %
за период с 14 сентября по 14 октября 2013г
75
2gis.ru
• Одностраничное приложение
• И это очень много JS
• А JS в разных браузерах...нужно тестировать
76
2. Проверенные методы selenium77
3. Проблемный* браузер - вперед78
4. chrome -> ie -> firefox79
О чем будет• Откуда проблемы кроссбраузерности?
• Примеры проблем кроссбраузерности
• Решение - фреймворк
• Практические рекомендации
80