Handling scrolling in a page object model - selenium

What are the best practices for scrolling to an element in a page when using page object model pattern?
If it matters, my tests are Appium tests that'll run on native iOS and Android apps.
Suppose I have this page:
public class LoginPage {
private AndroidDriver<AndroidElement> driver;
public LoginPage(AndroidDriver<AndroidElement> driver) {
this.driver = driver;
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}
#AndroidFindBy(className = "UIAKeyboard")
private AndroidElement keyboard;
#AndroidFindBy(id = "name")
private AndroidElement nameElement;
#AndroidFindBy(id = "password")
private AndroidElement passwordElement;
#AndroidFindBy(id = "login")
private AndroidElement loginElement;
public void scrollToLoginButton() {
//......
}
}
Is there some built in way/best practice to scroll down to the login button, aside from manually using FluentWait, activating a TouchAction in the until method every time I don't find the button to be clickable?

driver.findElement(MobileBy.AndroidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true)).scrollTextIntoView(\"login\")"));
you can use adroidUIAutomater class uiscrollable, see any method thats suites ui
https://developer.android.com/reference/androidx/test/uiautomator/UiScrollable
If you want to use actions class from selenium use :
import org.openqa.selenium.interactions.Actions;
new Actions(driver).clickAndHold(e2).moveByOffset(0, -500).perform();
Note: you have to click and hold element at the bottom of the screen and scroll backwards thats why -500
or move from last element to first element:
Actions action = new Actions(driver);
action.clickAndHold(e2).moveToElement(e1);
action.perform();

I guess you were expecting for this
#AndroidFindBy(uiAutomator = "new UiScrollable(new UiSelector().scrollable(true))" +
".scrollIntoView(new UiSelector().textContains(\"login\"))")
private AndroidElement loginElement;
public void scrollToLoginButton() {
loginElement.click();
}

Related

Serenity Cucumber - Make sure element is within the viewport

In Serenity Cucumber, some methods do not scroll the element into the view port: for example, the getValue() method will just get that value and not scroll the browser so that the element is in view, which causes the report to just show a screen shot of the top of the page, but not the element that is being interacted with.
Example current method:
#Step("read first name")
public String readFirstName() {
return $(ContactPage.firstNameField).getValue();
}
Example of my attempt(s) to scroll the element into view, so it shows on the screenshot:
#Step("read first name")
public String readFirstName() {
new ScrollToBy(ContactPage.firstNameField).andAlignToTop();
return $(ContactPage.firstNameField).getValue();
}
You could use something like screenplay pattern questions/tasks for reading off-screen text.
#Subject("the displayed text")
public class TextValue implements Question<String> {
private Target target
#Override
public String answeredBy(Actor actor) {
return target.resolveFor(actor).getText();
}
private TextValue(Target target) {
this.target = target;
}
public static Question<String> of(Target target) { return new TextValue(target); }
}
Then in your steps...
theActorInTheSpotlight().wasAbleTo(Scroll.to(ContactPage.firstNameField));
theActorInTheSpotlight().should(eventually(
seeThat(the(TextValue.of(ContactPage.firstNameField)),
isEqualTo(expectedValue))
));

How to handle wait manually in selenium webdriver

I have one end user page which have number of controls (textboxes, checkbox, dropdown) let's say 30 . All these enabled from admin panel .
I have enclosed all these in try catch block individually e.g.
try
{
driver.findElement(By.locator); // For Control 1
}
catch(Exception e)
{
}
try
{
driver.findElement(By.locator); // For Control 2
}
catch(Exception e)
{
}
and So On...
The problem is, suppose admin enabled only 1 field which is last in my code. So while executing the script My script is too slow because it check each element one by one and if not found then handle that in catch block until the last element found.
Is there any way to mitigate this time wastage ?
You can use findElements and check if there are any elements found. If there aren't any you will get an empty list without an exception. You can build a method that returns the element if it exists or null if it doesn't
private WebElement findElement(WebDriver driver, By locator) {
List<WebElement> elements = driver.findElements(By.locator);
return elements.size() > 0 ? elements.get(0) : null;
}
findElements(driver, By.locator); // For Control 1
findElements(driver, By.locator); // For Control 2
// ...
You can manage your timeouts by doing:
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
You can do this if you want at the beginning of your method and then set it again to what you had and fits best the needs of your site.
More on that: http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp
In such scenarios, using FluentWait is the most reliable approach. You should chuck using driver.findElement(By) and instead create a method getElement(By) in a commonly accessible class such as BasePage.class
public class BasePage {
WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public WebElement getElement(By locator) {
// Waiting 30 seconds for an element to be present on the page, checking
// for its presence once every 5 seconds.
Wait wait = new FluentWait(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
// Get the web element
WebElement element = wait.until(new Function() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});
return element;
}
}

intellij plugin development show input dialog with multiple text boxes

I'm creating intelliJ plugin and registering my action , inside my action i want to show an input dialog with multiple text boxes, how do I do that ?
I have an example of showing only one text box -
String txt= Messages.showInputDialog(project, "What is your name?",
"Input your name", Messages.getQuestionIcon());
I agree with #AKT with extending the DialogWrapper but suggest overriding doOKAction:
#Override
protected void doOKAction() {
if (getOKAction().isEnabled()) {
// custom logic
System.out.println("custom ok action logic");
close(OK_EXIT_CODE);
}
}
Or, if you just want your data out without the Action mess, add a custom method:
public class SearchDialog extends DialogWrapper {
...
public String getQuery() {
return "my custom query";
}
}
You can use it like:
SearchDialog dialog = new SearchDialog();
dialog.showAndGet(); // Maybe check if ok or cancel was pressed
String myQuery = dialog.getQuery();
System.out.println("my query: " + myQuery);
Create a new GUI Form (form + class). Class should extend DialogWrapper and override methods.
Inside createCenterPanel() return your root JPanel. You can set any default values, add event listeners to text box, etc., before returning JPanel.
Implement an Action interface where you want to get the value when OK button is clicked. Pass this action to your form class.
getOKAction() should return this action.
Following code is from a plugin i'm currently working on. Hopefully this will give you some idea but will have to adapt it to your need.
public class ReleaseNoteDialog extends DialogWrapper implements Action {
private JTextArea txtReleaseNote;
private JPanel panelWrapper;
.......
protected JComponent createCenterPanel() {
......
return panelWrapper;
}
......
#Override
protected Action getOKAction() {
return this;
}
.......
#Override
public void actionPerformed(ActionEvent e) {
// save value to project state
super.doOKAction();
}

How to press "ALT+T" in Selenium webdriver with java. I want to switch tabs by pressing it

I have used below code, but it throws an error saying "Cannot focus on element". Please help.
String selectAll = Keys.chord(Keys.ALT,"T");
driver.findElement(By.tagName("html")).sendKeys(selectAll);
The best way to switch tabs would be to use switchTo(), if you know the new window name:
driver.switchTo().window(WINDOW_NAME);
Otherwise get a list of the open windows and switch using that:
List<String> openTabs = driver.getWindowHandles();
for(String tab in openTabs) {
driver.switchTo().window(openTabs.get(tab);
}
So you can iterate over the open windows until you find the one you need.
You can send ShortcutKeys like Alt + Tab to driver without using element by using Actions.
public static void sendShortCut(WebDriver driver) {
Actions action = new Actions(driver);
action.sendKeys(Keys.chord(Keys.CONTROL, "T")).build().perform();
}
However your goal was to switch to the window/tab.In Selenium both window and tab are same.
I've provided you two solutions which is self explanatory from the name of the functions
public static void switchToWindowByTitle(WebDriver driver, String title) {
Set<String> Handles = driver.getWindowHandles();
for (String handle : Handles) {
driver.switchTo().window(handle);
String drivertitle = driver.getTitle().trim();
if (drivertitle.equals(title)) {
break;
}
}
}
//Index is 0 based
public static void switchToWindowByIndex(WebDriver driver, int index) {
Set<String> handles = driver.getWindowHandles();
if (handles.size() > index) {
String handle = handles.toArray()[index].toString();
driver.switchTo().window(handle);
}
}
You can open another tab using:
driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL + "t");
and switch to tabs by using:
driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL, Keys.PAGE_DOWN);

Swiping Past Last Tab App Crashes

I'm using ActionBarSherlock with a ViewPager with navigation mode set to display my tabs. I have 3 tabs that work fine. My problem is that if I were to try to swipe to a non-existant 4th tab it crashes my app. I'm not sure where this is happening, need some help. This is my first attempt at an app, any feedback is welcome.
fragments:
private ViewPager mViewPager;
private SherlockFragment mFragCodes;
private SherlockFragment mFragDeals;
private SherlockFragment mFragProgInfo;
private SherlockFragment mFragTemp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(new MainPagerAdapter(
getSupportFragmentManager()));
mViewPager.setOnPageChangeListener(this);
//mViewPager.setPageMarginDrawable(R.drawable.border);
mViewPager.setPageMargin(16);
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.addTab(actionBar.newTab()
.setText(R.string.tab_codes_title)
.setTabListener(this));
actionBar.addTab(actionBar.newTab()
.setText(R.string.tab_deals_title)
.setTabListener(this));
actionBar.addTab(actionBar.newTab()
.setText(R.string.tab_program_info_title)
.setTabListener(this));
and my pageradapter:
private class MainPagerAdapter extends FragmentPagerAdapter {
public MainPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public SherlockFragment getItem(int position) {
switch (position) {
case 0:
return (mFragCodes = new frag_codes());
case 1:
return (mFragDeals = new frag_deals());
case 2:
return (mFragProgInfo = new frag_programming());
}
//if nothing is returned
return mFragTemp = new SherlockFragment();
}
#Override
public int getCount() {
return R.string.tab_count;
}
}
Any other info I should include?
Go over Swipey Tabs example and the example included in the samples folder that comes with the ActionBarSherlock library (FragmentTabsPager) to see working examples of a tabs adapter.
Furthermore, please include additional info, mostly the stack trace from the exception, the layouts and the full classes including the declaration and imports.
From what I see you are missing the implements part where you should be implementing ActionBar.TabListener, ViewPager.OnPageChangeListener.
Just put:
#Override
public int getCount() {
return 3;
}