ricardorlg / serenityappiumbug

Test project for an Appium-serenityBdd Issue
0 stars 0 forks source link

MobilePageObject(final WebDriver driver) need clarification #1

Open vikramvi opened 6 years ago

vikramvi commented 6 years ago

Can you please clarify what exactly the method MobilePageObject(final WebDriver driver) doing ?

Serenity web client doesn't need this kind of method but I'm not sure why is it needed for mobile

Thanks in advance.

not sure if this is related to https://github.com/serenity-bdd/serenity-core/issues/936#issuecomment-331286524

ricardorlg commented 6 years ago

this is needed in order to load the PageFactory because we are using appium native finders and elements, serenity doesn't know how to instantiate those fields, also, because we are in a native app we don't have an open method call, and serenity doesn't lazy load the fields.

Right now I'm also integrating appium serenity with testObject if you want we can create a sample project to be used by serenity community.

vikramvi commented 6 years ago

@ricardorlg Thanks for reply but still I'm not very clear. Can you please clarify below in detail ?

  1. wrt MobilePageObject.java class constructor, how did you found this solution ?

  2. super(driver, new Predicate(), why are you using Predicate here ?

  3. apply(PageObject page), is this appium related method ?

  4. I already have sample project https://github.com/vikramvi/AppiumSerenityPOC , can you please review the code and let me know if any improvements needed.

Thanks in advance.

ricardorlg commented 6 years ago
  1. I create MobilePageObject.java class to have a base class, so every page object extends this and has the common mobile methods, like init fields (constructor) or get AndroidDriver or IosDriver if needed.
  2. I use super(driver, new Predicate()) because is a feature of serenity, in this way you say the page Object to use the method passed in the predicate to init fields.
  3. apply(PageObject page) is just the way a predicate works, here I just said to the PageObject that applies the code in the predicate, in this case, init the fields.

to be more clear that constructor is the way PageFactory works, in the appium documentation in page object you can find related things.

vikramvi commented 6 years ago

@ricardorlg Thanks for clarification.

Please let me know if you got chance to review sample project; we can collaborate and expand it; which can be useful to serenity community

ricardorlg commented 6 years ago

we can add some basic configuration to run the tests on TestObject cloud platform. Using serenity customdriver,

vikramvi commented 6 years ago

@ricardorlg can you please update your demo project showing how do you create ios / android driver instead of remoteWebDriver to run on TestObject ?

I read your comment on issue serenity-core/issues/988, how did you create custom driver ?

With current way of creating driver; I can't run test cases on Saucelabs. Thanks in advance.

I tried casting remoteWebDriver as per https://github.com/serenity-bdd/serenity-core/issues/660#issuecomment-274548940, but with current version of Serenity getting exception that casting is not possible

public MobilePageObject(final WebDriver driver) {
        super(driver, new Predicate<PageObject>() {
            @Override
            public boolean apply(PageObject page) {

                PageFactory
                        .initElements(new AppiumFieldDecorator((IOSDriver<IOSElement>) ((WebDriverFacade) page.getDriver()).getProxiedDriver(),
                                page.getImplicitWaitTimeout().in(TimeUnit.SECONDS), TimeUnit.SECONDS), page);
                return true;
            }

        });

    }

[main] WARN net.thucydides.core.pages.Pages - Failed to instantiate page of type class com.serenity.appium.poc.pages.WineAppPageObject ({}) java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebDriver cannot be cast to io.appium.java_client.ios.IOSDriver

ricardorlg commented 6 years ago

@vikramvi use this:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.net.MalformedURLException;
import java.net.URL;

import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.ios.IOSElement;
import net.thucydides.core.webdriver.DriverSource;

public class SauceLabsDriver implements DriverSource {

     public static final String USERNAME = "youruser";
        public static final String ACCESS_KEY = "<my key>";
        public static final String URL = "https://" + USERNAME + ":" + ACCESS_KEY + "@ondemand.saucelabs.com:443/wd/hub";

    @Override
    public WebDriver newDriver() {      
        try {
            DesiredCapabilities capabilities = new DesiredCapabilities();
            capabilities.setCapability("platformName", "iOS");
            capabilities.setCapability("deviceName", "iPhone 6");
            capabilities.setCapability("platformVersion", "10.3");
            capabilities.setCapability("app", "sauce-storage:tw_mobile.zip");
            capabilities.setCapability("deviceOrientation", "portrait");
            capabilities.setCapability("appiumVersion", "1.6.5");
            WebDriver driver= new IOSDriver<IOSElement>(new URL(URL), capabilities);
             return driver;
        } catch (MalformedURLException e) {
            throw new Error(e);
        }

    }

    @Override
    public boolean takesScreenshots() {
        // TODO Auto-generated method stub
        return true;
    }

}

Change what you need, then in your serenity.properties u have to set this:

webdriver.driver = provided webdriver.provided.type = mydriver webdriver.provided.mydriver = package.path.to.SauceLabsDriver thucydides.driver.capabilities = mydriver

ricardorlg commented 6 years ago

@vikramvi if you want to use testObject your custom driver should look like this

public class TestObjectDriver implements DriverSource {

    @Override
    public WebDriver newDriver() {
        // TODO Auto-generated method stub
        try {
            DesiredCapabilities dc = new DesiredCapabilities();
            dc.setCapability("testobject_api_key", "yourkey");
            dc.setCapability("deviceName", "LG Nexus 5X Free"); // Optional
            dc.setCapability("appiumVersion", "1.6.6-beta3");
            dc.setCapability("automationName", "uiautomator2");

            return new AndroidDriver<AndroidElement>(new URL("https://eu1.appium.testobject.com/wd/hub"), dc);

        } catch (IOException e) {
            throw new Error(e);
        }
    }

    @Override
    public boolean takesScreenshots() {
        // TODO Auto-generated method stub
        return false;
    }

}
vikramvi commented 6 years ago

@ricardorlg Thanks for detailed answers; I'll try it out and update back to you.

Can you please clarify below

  1. How did you approach / came across this way of implementation ?

  2. Does remaining code stays same ? PageFactory and constructor definition etc ?

ricardorlg commented 6 years ago

@vikramvi I use this way of implementation because I suppose if we use a remote web driver when working with some native code, tests will fail, also right now in serenity there is not TestObject functionality, I am working on that.

  1. all the code remains equal.
vikramvi commented 6 years ago

@ricardorlg sorry my question earlier was not clear I guess.

I understood that SauceLabsDriver needs to run on Saucelabs cloud with Appium Driver, but I am interested / curious to know how did you debug or got to know about DriverSource or usage of custom driver ?

Last few days I was wondering how to solve this issue and curious to know your approach to this problem and how you come to particular solutions which I missed to understand from Serenity.

vikramvi commented 6 years ago

@ricardorlg can you please clarify per above comment ?

vikramvi commented 6 years ago

@ricardorlg did you try testobject execution with latest version of serenity ? I think custom driver is no more needed

ricardorlg commented 6 years ago

@vikramvi I didn´t try it yet, but if we don´t use a custom driver how do we pass the capabilities, I have to read the release notes.