Simplify mobile page objects and stabilize ID-based components

This commit is contained in:
2026-04-19 12:17:15 +03:00
parent 46f3de4d55
commit bcf831ad99
19 changed files with 416 additions and 246 deletions
@@ -1,25 +1,27 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
import com.google.inject.Inject;
import ru.otus.mobile.config.MobileConfig;
import io.appium.java_client.AppiumBy;
import static com.codeborne.selenide.appium.SelenideAppium.$;
public final class AlertDialogComponent extends BaseMobileComponent {
private final SelenideElement positiveButton;
@Inject
public AlertDialogComponent(MobileConfig config) {
super(config);
public AlertDialogComponent() {
this($(AppiumBy.id("android:id/content")));
}
public AlertDialogComponent(SelenideElement root) {
super(root);
this.positiveButton = byIdInRoot("android:id/button1");
}
public void acceptIfVisible() {
if (exists("android:id/button1")) {
tap("android:id/button1");
return;
}
if (byText("OK").exists()) {
byText("OK").click();
return;
}
if (byText("ОК").exists()) {
byText("ОК").click();
if (positiveButton.exists()) {
positiveButton.click();
}
}
}
@@ -1,10 +1,22 @@
package ru.otus.mobile.component;
import ru.otus.mobile.config.MobileConfig;
import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
import io.appium.java_client.AppiumBy;
import ru.otus.mobile.page.AbsPageObject;
public abstract class BaseMobileComponent extends AbsPageObject {
protected BaseMobileComponent(MobileConfig config) {
super(config);
protected final SelenideElement root;
protected BaseMobileComponent(SelenideElement root) {
this.root = root;
}
protected SelenideElement byIdInRoot(String id) {
return root.$(AppiumBy.id(fullIdValue(id)));
}
protected ElementsCollection allByIdInRoot(String id) {
return root.$$(AppiumBy.id(fullIdValue(id)));
}
}
@@ -1,19 +1,31 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
import com.google.inject.Inject;
import ru.otus.mobile.config.MobileConfig;
import io.appium.java_client.AppiumBy;
import static com.codeborne.selenide.appium.SelenideAppium.$;
public final class BottomNavigationComponent extends BaseMobileComponent {
private final SelenideElement mineMenu;
private final SelenideElement usersMenu;
@Inject
public BottomNavigationComponent(MobileConfig config) {
super(config);
public BottomNavigationComponent() {
this($(AppiumBy.id(fullIdValue("bottom_navigation"))));
}
public BottomNavigationComponent(SelenideElement root) {
super(root);
this.mineMenu = byIdInRoot("mine_menu");
this.usersMenu = byIdInRoot("users_menu");
}
public void openWishlists() {
tap("mine_menu");
mineMenu.click();
}
public void openUsers() {
tap("users_menu");
usersMenu.click();
}
}
@@ -1,17 +1,35 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
import com.google.inject.Inject;
import ru.otus.mobile.config.MobileConfig;
import io.appium.java_client.AppiumBy;
import static com.codeborne.selenide.appium.SelenideAppium.$;
public final class GiftFormComponent extends BaseMobileComponent {
private final SelenideElement nameInput;
private final SelenideElement priceInput;
private final SelenideElement saveButton;
@Inject
public GiftFormComponent(MobileConfig config) {
super(config);
public GiftFormComponent() {
this($(AppiumBy.id("android:id/content")));
}
public GiftFormComponent(SelenideElement root) {
super(root);
this.nameInput = byIdInRoot("name_input");
this.priceInput = byIdInRoot("price_input");
this.saveButton = byIdInRoot("save_button");
}
public void save(String name, String price) {
type("name_input", name);
type("price_input", price);
tap("save_button");
nameInput.click();
nameInput.clear();
nameInput.sendKeys(name);
priceInput.click();
priceInput.clear();
priceInput.sendKeys(price);
saveButton.click();
}
}
@@ -0,0 +1,32 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
import static com.codeborne.selenide.Condition.text;
public final class GiftItemComponent extends BaseMobileComponent {
private final SelenideElement title;
private final SelenideElement editButton;
public GiftItemComponent(SelenideElement root) {
super(root);
this.title = byIdInRoot("title");
this.editButton = byIdInRoot("edit_button");
}
public String titleText() {
return title.getText();
}
public void shouldHaveTitle(String value) {
title.shouldHave(text(value));
}
public void open() {
title.click();
}
public void edit() {
editButton.click();
}
}
@@ -0,0 +1,32 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
import io.appium.java_client.AppiumBy;
public final class GiftsContentComponent extends BaseMobileComponent {
private final ElementsCollection items;
public GiftsContentComponent(SelenideElement root) {
super(root);
this.items = root.$$(AppiumBy.id(fullIdValue("gift_item")));
}
public GiftItemComponent get(int index) {
return new GiftItemComponent(items.get(index));
}
public GiftItemComponent first() {
return get(0);
}
public GiftItemComponent byTitle(String title) {
for (int i = 0; i < items.size(); i++) {
GiftItemComponent item = get(i);
if (title.equals(item.titleText())) {
return item;
}
}
throw new IllegalStateException("Gift with title '" + title + "' was not found.");
}
}
@@ -0,0 +1,29 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
public final class TopBarComponent extends BaseMobileComponent {
public TopBarComponent(SelenideElement root) {
super(root);
}
public void openUsersFilter() {
if (byId("filter").exists()) {
byId("filter").click();
return;
}
if (byId("users_filter").exists()) {
byId("users_filter").click();
return;
}
if (byId("filter_button").exists()) {
byId("filter_button").click();
return;
}
if (byId("action_filter").exists()) {
byId("action_filter").click();
return;
}
throw new IllegalStateException("Filter button was not found on Users screen.");
}
}
@@ -0,0 +1,20 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
public final class UserItemComponent extends BaseMobileComponent {
private final SelenideElement username;
public UserItemComponent(SelenideElement root) {
super(root);
this.username = byIdInRoot("username");
}
public String usernameText() {
return username.getText();
}
public void open() {
username.click();
}
}
@@ -0,0 +1,32 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
import io.appium.java_client.AppiumBy;
public final class UsersContentComponent extends BaseMobileComponent {
private final ElementsCollection items;
public UsersContentComponent(SelenideElement root) {
super(root);
this.items = root.$$(AppiumBy.id(fullIdValue("user_item")));
}
public UserItemComponent get(int index) {
return new UserItemComponent(items.get(index));
}
public UserItemComponent first() {
return get(0);
}
public UserItemComponent byUsername(String username) {
for (int i = 0; i < items.size(); i++) {
UserItemComponent item = get(i);
if (username.equals(item.usernameText())) {
return item;
}
}
throw new IllegalStateException("User with username '" + username + "' was not found.");
}
}
@@ -0,0 +1,38 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
public final class UsersFilterComponent extends BaseMobileComponent {
public UsersFilterComponent(SelenideElement root) {
super(root);
}
public void applyByUsername(String username) {
SelenideElement filterInput = filterInput();
SelenideElement applyButton = applyButton();
filterInput.click();
filterInput.clear();
filterInput.sendKeys(username);
applyButton.click();
}
private SelenideElement filterInput() {
if (byIdInRoot("username_input").exists()) {
return byIdInRoot("username_input");
}
if (byIdInRoot("filter_input").exists()) {
return byIdInRoot("filter_input");
}
if (byIdInRoot("users_filter_input").exists()) {
return byIdInRoot("users_filter_input");
}
return byIdInRoot("username_filter_input");
}
private SelenideElement applyButton() {
if (byIdInRoot("apply_button").exists()) {
return byIdInRoot("apply_button");
}
return byIdInRoot("apply");
}
}
@@ -1,16 +1,30 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
import com.google.inject.Inject;
import ru.otus.mobile.config.MobileConfig;
import io.appium.java_client.AppiumBy;
import static com.codeborne.selenide.appium.SelenideAppium.$;
public final class WishlistFormComponent extends BaseMobileComponent {
private final SelenideElement titleInput;
private final SelenideElement saveButton;
@Inject
public WishlistFormComponent(MobileConfig config) {
super(config);
public WishlistFormComponent() {
this($(AppiumBy.id("android:id/content")));
}
public WishlistFormComponent(SelenideElement root) {
super(root);
this.titleInput = byIdInRoot("title_input");
this.saveButton = byIdInRoot("save_button");
}
public void save(String title) {
type("title_input", title);
tap("save_button");
titleInput.click();
titleInput.clear();
titleInput.sendKeys(title);
saveButton.click();
}
}
@@ -0,0 +1,32 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.SelenideElement;
import static com.codeborne.selenide.Condition.text;
public final class WishlistItemComponent extends BaseMobileComponent {
private final SelenideElement title;
private final SelenideElement editButton;
public WishlistItemComponent(SelenideElement root) {
super(root);
this.title = byIdInRoot("title");
this.editButton = byIdInRoot("edit_button");
}
public String titleText() {
return title.getText();
}
public void shouldHaveTitle(String value) {
title.shouldHave(text(value));
}
public void open() {
title.click();
}
public void edit() {
editButton.click();
}
}
@@ -0,0 +1,32 @@
package ru.otus.mobile.component;
import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
import io.appium.java_client.AppiumBy;
public final class WishlistsContentComponent extends BaseMobileComponent {
private final ElementsCollection items;
public WishlistsContentComponent(SelenideElement root) {
super(root);
this.items = root.$$(AppiumBy.id(fullIdValue("wishlist_item")));
}
public WishlistItemComponent get(int index) {
return new WishlistItemComponent(items.get(index));
}
public WishlistItemComponent first() {
return get(0);
}
public WishlistItemComponent byTitle(String title) {
for (int i = 0; i < items.size(); i++) {
WishlistItemComponent item = get(i);
if (title.equals(item.titleText())) {
return item;
}
}
throw new IllegalStateException("Wishlist with title '" + title + "' was not found.");
}
}
@@ -1,19 +1,11 @@
package ru.otus.mobile.page;
import ru.otus.mobile.component.BottomNavigationComponent;
import ru.otus.mobile.config.MobileConfig;
public abstract class AbsBasePage extends AbsPageObject {
protected final BottomNavigationComponent bottomNavigation;
private final MobileConfig config;
protected AbsBasePage(MobileConfig config, BottomNavigationComponent bottomNavigation) {
super(config);
this.config = config;
protected AbsBasePage(BottomNavigationComponent bottomNavigation) {
this.bottomNavigation = bottomNavigation;
}
protected MobileConfig config() {
return config;
}
}
@@ -1,45 +1,24 @@
package ru.otus.mobile.page;
import com.codeborne.selenide.CollectionCondition;
import com.codeborne.selenide.Condition;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.WebDriverRunner;
import com.codeborne.selenide.appium.SelenideAppiumCollection;
import io.appium.java_client.AppiumBy;
import ru.otus.mobile.config.MobileConfig;
import static com.codeborne.selenide.appium.SelenideAppium.$$;
import static com.codeborne.selenide.appium.SelenideAppium.$;
public abstract class AbsPageObject {
private final MobileConfig config;
protected AbsPageObject(MobileConfig config) {
this.config = config;
}
private static final String APP_PACKAGE_PROPERTY = "app.package";
private static final String DEFAULT_APP_PACKAGE = "ru.otus.wishlist";
protected SelenideElement byId(String id) {
return $(AppiumBy.id(fullId(id)));
return $(AppiumBy.id(fullIdValue(id)));
}
protected SelenideAppiumCollection allById(String id) {
return $$(AppiumBy.id(fullId(id)));
}
protected SelenideElement byText(String text) {
return $(AppiumBy.androidUIAutomator("new UiSelector().text(\"" + escape(text) + "\")"));
}
protected SelenideElement byTextContains(String text) {
return $(AppiumBy.androidUIAutomator("new UiSelector().textContains(\"" + escape(text) + "\")"));
}
protected SelenideElement byUiAutomator(String selector) {
return $(AppiumBy.androidUIAutomator(selector));
}
protected SelenideElement byXpath(String xpath) {
return $(AppiumBy.xpath(xpath));
return $$(AppiumBy.id(fullIdValue(id)));
}
protected void type(String id, String value) {
@@ -57,47 +36,15 @@ public abstract class AbsPageObject {
return byId(id).exists();
}
protected void shouldHaveItems(String id) {
allById(id).shouldHave(CollectionCondition.sizeGreaterThan(0));
}
protected SelenideElement scrollToText(String text) {
String selector = "new UiScrollable(new UiSelector().scrollable(true))"
+ ".scrollIntoView(new UiSelector().textContains(\"" + escape(text) + "\"))";
return $(AppiumBy.androidUIAutomator(selector));
}
protected void back() {
WebDriverRunner.getWebDriver().navigate().back();
}
protected String xpathLiteral(String value) {
if (!value.contains("\"")) {
return "\"" + value + "\"";
}
if (!value.contains("'")) {
return "'" + value + "'";
}
String[] parts = value.split("\"");
StringBuilder builder = new StringBuilder("concat(");
for (int i = 0; i < parts.length; i++) {
if (i > 0) {
builder.append(", '\"', ");
}
builder.append("\"").append(parts[i]).append("\"");
}
builder.append(")");
return builder.toString();
}
private String fullId(String id) {
protected static String fullIdValue(String id) {
if (id.contains(":")) {
return id;
}
return config.appPackage() + ":id/" + id;
}
private String escape(String value) {
return value.replace("\"", "\\\"");
String appPackage = System.getProperty(APP_PACKAGE_PROPERTY, DEFAULT_APP_PACKAGE);
return appPackage + ":id/" + id;
}
}
@@ -3,34 +3,39 @@ package ru.otus.mobile.page;
import com.codeborne.selenide.Condition;
import com.google.inject.Inject;
import ru.otus.mobile.component.BottomNavigationComponent;
import ru.otus.mobile.component.GiftsContentComponent;
import ru.otus.mobile.component.GiftFormComponent;
import ru.otus.mobile.config.MobileConfig;
public final class GiftsPage extends AbsBasePage {
private final GiftFormComponent form;
private final com.codeborne.selenide.SelenideElement addButton = byId("add_button");
@Inject
public GiftsPage(MobileConfig config, BottomNavigationComponent bottomNavigation, GiftFormComponent form) {
super(config, bottomNavigation);
public GiftsPage(BottomNavigationComponent bottomNavigation, GiftFormComponent form) {
super(bottomNavigation);
this.form = form;
}
public void createGift(String name) {
tap("add_button");
addButton.click();
form.save(name, "100");
}
public void editGift(String oldName, String newName) {
openGift(oldName);
tap("edit_button");
content().byTitle(oldName).edit();
form.save(newName, "100");
}
public void shouldSeeGift(String name) {
scrollToText(name).shouldBe(Condition.visible);
content().byTitle(name).shouldHaveTitle(name);
}
private void openGift(String name) {
scrollToText(name).click();
content().byTitle(name).open();
}
private GiftsContentComponent content() {
return new GiftsContentComponent(byId("gifts_content"));
}
}
@@ -2,15 +2,13 @@ package ru.otus.mobile.page;
import com.google.inject.Inject;
import ru.otus.mobile.component.AlertDialogComponent;
import ru.otus.mobile.config.MobileConfig;
import ru.otus.mobile.config.TestAccount;
public final class LoginPage extends AbsPageObject {
private final AlertDialogComponent alertDialog;
@Inject
public LoginPage(MobileConfig config, AlertDialogComponent alertDialog) {
super(config);
public LoginPage(AlertDialogComponent alertDialog) {
this.alertDialog = alertDialog;
}
+37 -109
View File
@@ -1,69 +1,55 @@
package ru.otus.mobile.page;
import com.codeborne.selenide.Condition;
import com.codeborne.selenide.CollectionCondition;
import com.codeborne.selenide.SelenideElement;
import com.google.inject.Inject;
import ru.otus.mobile.component.BottomNavigationComponent;
import ru.otus.mobile.config.MobileConfig;
import ru.otus.mobile.component.GiftsContentComponent;
import ru.otus.mobile.component.TopBarComponent;
import ru.otus.mobile.component.UsersContentComponent;
import ru.otus.mobile.component.UsersFilterComponent;
import ru.otus.mobile.component.WishlistsContentComponent;
import java.time.Duration;
public final class UsersPage extends AbsBasePage {
private final TopBarComponent topBar;
@Inject
public UsersPage(MobileConfig config, BottomNavigationComponent bottomNavigation) {
super(config, bottomNavigation);
public UsersPage(BottomNavigationComponent bottomNavigation) {
super(bottomNavigation);
this.topBar = new TopBarComponent(byId("android:id/content"));
}
public void open() {
bottomNavigation.openUsers();
byId("users_content").shouldBe(Condition.visible);
usersContentRoot().shouldBe(Condition.visible, Duration.ofSeconds(15));
}
public void filterByUsername(String username) {
openFilter();
SelenideElement input = filterInput().shouldBe(Condition.visible, Duration.ofSeconds(15));
input.clear();
input.setValue(username);
applyFilter();
byTextContains(username).shouldBe(Condition.visible, Duration.ofSeconds(15));
topBar.openUsersFilter();
byId("users_filter_bottom_sheet").shouldBe(Condition.visible, Duration.ofSeconds(15));
new UsersFilterComponent(byId("users_filter_bottom_sheet")).applyByUsername(username);
byId("user_item").shouldBe(Condition.visible, Duration.ofSeconds(15));
}
public void openUser(String username) {
String appPackage = config().appPackage();
String xpath = "//android.widget.TextView[@resource-id='" + appPackage + ":id/username'"
+ " and @text=" + xpathLiteral(username) + "]";
SelenideElement user = byXpath(xpath);
if (user.exists()) {
user.shouldBe(Condition.visible, Duration.ofSeconds(15)).click();
} else {
scrollToText(username).shouldBe(Condition.visible, Duration.ofSeconds(15)).click();
}
byTextContains(username).shouldBe(Condition.visible, Duration.ofSeconds(15));
usersContent().byUsername(username).open();
}
public void openFirstWishlist() {
allById("wishlist_item")
.shouldHave(CollectionCondition.sizeGreaterThan(0), Duration.ofSeconds(15))
.first()
.shouldBe(Condition.visible, Duration.ofSeconds(15))
.click();
wishlistsContent().get(0).open();
}
public void openWishlist(String name) {
scrollToText(name).shouldBe(Condition.visible, Duration.ofSeconds(15)).click();
wishlistsContent().byTitle(name).open();
}
public void openFirstGift() {
allById("gift_item")
.shouldHave(CollectionCondition.sizeGreaterThan(0), Duration.ofSeconds(15))
.first()
.shouldBe(Condition.visible, Duration.ofSeconds(15))
.click();
new GiftsContentComponent(byId("gifts_content")).get(0).open();
}
public void openGift(String name) {
scrollToText(name).shouldBe(Condition.visible, Duration.ofSeconds(15)).click();
new GiftsContentComponent(byId("gifts_content")).byTitle(name).open();
}
public boolean isReserved() {
@@ -71,87 +57,29 @@ public final class UsersPage extends AbsBasePage {
}
public void toggleReservation() {
tap("reserved");
byId("reserved").shouldBe(Condition.visible).click();
}
private void openFilter() {
if (byId("users_filter").exists()) {
tap("users_filter");
byId("users_filter_bottom_sheet").shouldBe(Condition.visible, Duration.ofSeconds(15));
return;
}
if (byId("filter_button").exists()) {
tap("filter_button");
byId("users_filter_bottom_sheet").shouldBe(Condition.visible, Duration.ofSeconds(15));
return;
}
if (byId("action_filter").exists()) {
tap("action_filter");
byId("users_filter_bottom_sheet").shouldBe(Condition.visible, Duration.ofSeconds(15));
return;
}
SelenideElement button = byUiAutomator("new UiSelector().descriptionContains(\"Фильтр\")");
if (button.exists()) {
button.click();
byId("users_filter_bottom_sheet").shouldBe(Condition.visible, Duration.ofSeconds(15));
return;
}
button = byUiAutomator("new UiSelector().descriptionContains(\"Filter\")");
if (button.exists()) {
button.click();
byId("users_filter_bottom_sheet").shouldBe(Condition.visible, Duration.ofSeconds(15));
return;
}
throw new IllegalStateException("Filter button was not found on Users screen.");
private UsersContentComponent usersContent() {
return new UsersContentComponent(usersContentRoot());
}
private SelenideElement filterInput() {
if (byId("filter_input").exists()) {
return byId("filter_input");
}
if (byId("username_filter_input").exists()) {
return byId("username_filter_input");
}
if (byId("users_filter_input").exists()) {
return byId("users_filter_input");
}
if (byId("username_input").exists()) {
return byId("username_input");
}
if (byId("search_src_text").exists()) {
return byId("search_src_text");
}
if (byId("query_text").exists()) {
return byId("query_text");
}
String appPackage = config().appPackage();
SelenideElement editText = byXpath(
"//android.view.ViewGroup[@resource-id='" + appPackage + ":id/users_filter_bottom_sheet']"
+ "//android.widget.EditText"
);
if (editText.exists()) {
return editText;
}
throw new IllegalStateException("Filter input was not found on Users screen.");
private WishlistsContentComponent wishlistsContent() {
return new WishlistsContentComponent(wishlistsContentRoot());
}
private void applyFilter() {
if (byId("apply_button").exists()) {
tap("apply_button");
return;
private com.codeborne.selenide.SelenideElement usersContentRoot() {
if (byId("users_content").exists()) {
return byId("users_content");
}
if (byId("apply").exists()) {
tap("apply");
return;
}
if (byText("ПРИМЕНИТЬ").exists()) {
byText("ПРИМЕНИТЬ").click();
return;
}
if (byText("APPLY").exists()) {
byText("APPLY").click();
return;
}
throw new IllegalStateException("Apply filter button was not found on Users filter screen.");
return byId("users");
}
private com.codeborne.selenide.SelenideElement wishlistsContentRoot() {
if (byId("wishlists_content").exists()) {
return byId("wishlists_content");
}
return byId("wishlists");
}
}
@@ -1,72 +1,67 @@
package ru.otus.mobile.page;
import com.codeborne.selenide.Condition;
import com.codeborne.selenide.CollectionCondition;
import com.google.inject.Inject;
import ru.otus.mobile.component.BottomNavigationComponent;
import ru.otus.mobile.component.WishlistsContentComponent;
import ru.otus.mobile.component.WishlistFormComponent;
import ru.otus.mobile.config.MobileConfig;
import java.time.Duration;
public final class WishlistsPage extends AbsBasePage {
private final WishlistFormComponent form;
private final com.codeborne.selenide.SelenideElement addButton = byId("add_button");
@Inject
public WishlistsPage(MobileConfig config, BottomNavigationComponent bottomNavigation, WishlistFormComponent form) {
super(config, bottomNavigation);
public WishlistsPage(BottomNavigationComponent bottomNavigation, WishlistFormComponent form) {
super(bottomNavigation);
this.form = form;
}
public void open() {
bottomNavigation.openWishlists();
byId("wishlists_content").shouldBe(Condition.visible);
contentRoot().shouldBe(Condition.visible);
}
public void createWishlist(String name) {
tap("add_button");
addButton.click();
form.save(name);
}
public void editWishlist(String oldName, String newName) {
ensureWishlistsList();
editButtonFor(oldName).shouldBe(Condition.visible).click();
content().byTitle(oldName).edit();
form.save(newName);
}
public void shouldSeeWishlist(String name) {
scrollToText(name).shouldBe(Condition.visible);
content().byTitle(name).shouldHaveTitle(name);
}
public void openWishlist(String name) {
scrollToText(name).click();
content().byTitle(name).open();
}
public void openFirstWishlist() {
allById("wishlist_item")
.shouldHave(CollectionCondition.sizeGreaterThan(0), Duration.ofSeconds(15))
.first()
.shouldBe(Condition.visible, Duration.ofSeconds(15))
.click();
content().first().open();
}
private void ensureWishlistsList() {
if (exists("wishlist_item") || exists("wishlists")) {
if (exists("wishlist_item") || contentRoot().exists()) {
return;
}
if (exists("gifts_content") || exists("gift_item") || exists("add_button")) {
back();
}
byId("wishlists_content").shouldBe(Condition.visible);
contentRoot().shouldBe(Condition.visible);
}
private com.codeborne.selenide.SelenideElement editButtonFor(String name) {
String full = config().appPackage();
String xpath = "//androidx.recyclerview.widget.RecyclerView[@resource-id='" + full + ":id/wishlists']"
+ "//android.view.ViewGroup[@resource-id='" + full + ":id/wishlist_item'"
+ " and .//android.widget.TextView[@resource-id='" + full + ":id/title'"
+ " and contains(@text," + xpathLiteral(name) + ")]]"
+ "//android.widget.Button[@resource-id='" + full + ":id/edit_button']";
return byXpath(xpath);
private WishlistsContentComponent content() {
return new WishlistsContentComponent(contentRoot());
}
private com.codeborne.selenide.SelenideElement contentRoot() {
if (byId("wishlists_content").exists()) {
return byId("wishlists_content");
}
return byId("wishlists");
}
}