Atlas – Next Generation of Page Object, which uses the interfaces instead of classes, Page Object tree structure, embedded waits and clear assertions. In talk, I will tell about the core functionality of the framework, the developer, which I am and show it extension points.
1. Let’s talk about ATLAS
АРТЕМ СОКОВЕЦ
@SokovetsArtem
(ext. HTML Elements)
2. ОБ АВТОРЕ
СОКОВЕЦ АРТЕМ ВЛАДИМИРОВИЧ
Leading Engineer of AutoQA @SberTech
@SokovetsArtem
Avsokovets.sbt@sberbank.ru
#java, #kotlin #autoQA
3. ПЛАН
• Эволюция PO
• Открытые вопросы
• Atlas - Ваш новый путеводитель в автоматизации UI
• Основные возможности инструмента
• Модель расширений
• Выводы
6. ЭВОЛЮЦИЯ PAGE OBJECT
1. Page Object
2. Page Factory
3. Fluent/Chain of invocations
4. Page Element
5. Loadable Component
6. ScreenPlay
2009
2019
HTML ELEMENTS
7. ЭВОЛЮЦИЯ PAGE OBJECT
1. Page Object
2. Page Factory
3. Fluent/Chain of invocations
4. Page Element
5. Loadable Component
6. ScreenPlay
2009
2019
HTML ELEMENTS
1. JDK 7
2. JDK 8
3. JDK 9
4. JDK 10
5. JDK 11
- A LOT OF SYNTACTIC SUGAR
- LAMBDA
- MODULES and G1 by default
- VAR
- CLEANUP
8. ОТКРЫТЫЙ ВОПРОС №1
public class MainPage {
@FindBy(xpath = ".//div[@class = 'header']")
private Header header;
}
public class AnyOtherPage {
@FindBy(xpath = ".//div[@class = 'header']")
private Header header;
}
9. ОТКРЫТЫЙ ВОПРОС №1
public class MainPage {
@FindBy(xpath = ".//div[@class = 'header']")
private Header header;
}
public class AnyOtherPage {
@FindBy(xpath = ".//div[@class = 'header']")
private Header header;
}
Дублирование элементов
10. ОТКРЫТЫЙ ВОПРОС №2
public class EditUserPage {
@FindBy(xpath = "//div[text()='Text_1']")
private TextBlock lastActivity;
@FindBy(xpath = "//div[text()='Text_2']")
private TextBlock blockReason;
}
11. ОТКРЫТЫЙ ВОПРОС №2
public class EditUserPage {
@FindBy(xpath = "//div[text()='Text_1']")
private TextBlock lastActivity;
@FindBy(xpath = "//div[text()='Text_2']")
private TextBlock blockReason;
}
Нет параметризации у элементов
12. ОТКРЫТЫЙ ВОПРОС №3
public class UserPage {
@FindBy(xpath = "//div[text()='Телефон']/input")
private UfsTextInput innerPhone;
@FindBy(xpath = "//div[text()='Email']/input")
private UfsTextInput email;
@FindBy(xpath = "//button[text()='Сохранить']")
private UfsButton save;
@FindBy(xpath = "//button[text()='Список']")
private UfsButton toUsersList;
}
13. ОТКРЫТЫЙ ВОПРОС №3
public class UserPage {
@FindBy(xpath = "//div[text()='Телефон']/input")
private UfsTextInput innerPhone;
@FindBy(xpath = "//div[text()='Email']/input")
private UfsTextInput email;
@FindBy(xpath = "//button[text()='Сохранить']")
private UfsButton save;
@FindBy(xpath = "//button[text()='Список']")
private UfsButton toUsersList;
}
Однотипный код
14. ОТКРЫТЫЙ ВОПРОС №4
public class MainSteps {
public void hasText (HtmlElement e, Matcher m)
public void hasValue (HtmlElement e, Matcher m)
public void linkContains (HtmlElement e, String s)
public void hasSize (List<HtmlElement> e, Matcher m)
public void hasItem (List<HtmlElement> e, Matcher m)
...
}
15. ОТКРЫТЫЙ ВОПРОС №4
public class MainSteps {
public void hasText (HtmlElement e, Matcher m)
public void hasValue (HtmlElement e, Matcher m)
public void linkContains (HtmlElement e, String s)
public void hasSize (List<HtmlElement> e, Matcher m)
public void hasItem (List<HtmlElement> e, Matcher m)
...
}
Уменьшить слой с шагами
37. ПРИМЕР
public interface MainPage extends WithHeader
public interface AnyPage extends WithHeader
public interface MainPage extends WithHeader,
WithFooter,
WithSidebar
38. НАСЛЕДОВАНИЕ ЭЛЕМЕНТОВ
public interface Button extends AtlasWebElement {
@FindBy(".//a[contains(., '{{ value }}')]")
AtlasWebElement selectButton(@Param("value")
String value);
}
Button
51. ИТОГИ
qПоменялась работа с Page Object;
qУшли от дублирование кода;
qСпецифические действия вынесли в элементы;
qРабота со списком элементов (ElementsCollection);
qПоддержка мобильной автоматизации.
58. НЕ ДУМАЙТЕ О ОЖИДАНИЯХ
mainSteps.shouldVisible(mainPage().header().rentLink());
mainSteps.click(mainPage().header().rentLink());
Было
Стало
onMainPage().header().button(…).click();
69. ИТОГИ
• Встроенные утверждения;
• should -> AssertionError;
• waitUntil -> RuntimeException;
• Проверки для работы со списком элементов;
• Ушли шаги с проверками.
74. ПРИМЕР
public void beforeMethodCall(MethodInfo m, Configuration c) {
stepUUID = UUID.randomUUID().toString();
allureLifecycle.startStep(stepUUID, new
StepResult().withName(m.toString()).withStatus(Status.PASSED));
}
public void afterMethodCall(MethodInfo m, Configuration c) {
allureLifecycle.stopStep(stepUUID);
}
public void onMethodFailure(MethodInfo m, Configuration c, Throwable t) {
allureLifecycle.updateStep(stepResult -> {
stepResult.setStatus(Status.FAILED);
});
}
75. КАК ПОДКЛЮЧИТЬ?
@Before
public void setUp() {
…
atlas = new Atlas(new
WebDriverConfiguration(driver, "site"))
.listener(new AllureListener());
}
79. ПЕРЕОПРЕДЕЛИТЬ ПОВЕДЕНИЕ
public interface MainPage extends WebPage {
@FindBy("//…")
AtlasWebElement trial();
}
onMainPage().header().button("En").click();
onMainPage().header().input("RU").clear();
onMainPage().header().input("UA").sendKeys(".");
80. КАК СДЕЛАТЬ?
public class MyExtension implements MethodExtension {
@Override
public boolean test(Method method) {…}
@Override
public Object invoke(…) throws Throwable {…}
}
91. ИНТЕГРАЦИЯ СО СВОИМ ФРЕЙМВОРКОМ
• Определить свой loader;
• Определить decorator;
• Пользовательская Page.
https://github.com/sbtqa/page-factory-2/
93. ВЫВОДЫ
• Новое представление PageObject на интерфейсах;
• Параметризированный элемент;
• Множественное наследование;
• Дополнительные возможности;
• Точки расширения;
• Не серебряная пуля;
• Ждем в ряды контрибьюторов;