4

I'm working on integrating Robot Framework with Appium, using Python. However I can't figure out how to pass the Appium driver created in the Robot Framework to a custom python script.

My Environment:

  • Mac OS - Mavericks
  • Appium 1.2 (installed via home brew)
  • Latest Robot Framework (installed via pip)
  • Latest Appium Library for Robot Framework (installed via pip)

I have a working Appium script in Python, but I want to start using Robot Framework for handling the actual tests.

partial code for working python script:

wd = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
wd.find_element_by_name("Start").click()
wd.find_element_by_xpath("//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]").click()
wd.execute_script("var vKeyboard = target.frontMostApp().keyboard(); vKeyboard.typeString(\"Test Text\");")
wd.execute_script("var vKeyboard = target.frontMostApp().keyboard(); vKeyboard.buttons()['Return'].tap();")

As you can see, because of how the application is working, I ned to use execute_script as part of the script.

The Appium Library for Robot Framework does not expose execute_script, so I need to write my own in a python library.

Here's my start of the robot testing script, which does work up until the point where I need to execute_script:

TestStart
    Open Application   ${REMOTE_URL}    ${PLATFORM_NAME}    ${PLATFORM_VERSION}    ${DEVICE_NAME}    ${APP}
    Click Element    name=Start
    Click Element    xpath=//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]

My question is how do I get the driver instance created in the Open Application and pass it to a Python script?

I have a python script that has the following:

def KeyboardType(driver):
    driver.execute_script("var vKeyboard = target.frontMostApp().keyboard(); vKeyboard.typeString(\"hi there\");")

However, I can't seem to be able to pass the driver from the Robot Framework script to this python script.

I tried setting the Open Application to a variable via:

${Driver}  Open Application   ${REMOTE_URL}    ${PLATFORM_NAME}    ${PLATFORM_VERSION}    ${DEVICE_NAME}    ${APP}
KeyboardType  ${Driver}

but I received the error:

AttributeError: 'str' object has no attribute 'execute_script'

I also tried passing the result of Get Current Context into the python script, but then I get:

AttributeError: 'unicode' object has no attribute 'execute_script'

How can I pass the driver created by the Robot Framework into the python script?

AaronS
  • 7,649
  • 5
  • 30
  • 56
  • Wait are you using environment variables for this? to try and pass the WD to your keyboard script? – Jess Jul 22 '14 at 13:59

3 Answers3

3

I don't currently use appium so I can't give a definitive answer. However, a similar question was asked about selenium, where someone needed the actual webdriver object. See the question Pass existing Webdriver object to custom Python library for Robot Framework

The short answer is that you can try to subclass the appium library so that your keywords have access to all of the appium internals, or you can get a handle to the library by calling BuiltIn().get_library_instance('Selenium2Library.

For more information on the latter technique see see Getting active library instance from Robot Framework in the Robot Framework User's Guide.

Community
  • 1
  • 1
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • I'll try this. I currently use my solution below, but this might be a good alternative. – Jess Jul 22 '14 at 14:50
  • @sheeptest: there is no "solution below". Remember: the order of answers in stackoverflow changes over time. What was once "below" may be "above" or may have been deleted. – Bryan Oakley Jul 22 '14 at 15:20
  • :) Thank you. Yeah, I deleted it [based on this meta post](http://meta.stackoverflow.com/questions/263046/should-i-delete-my-own-downvoted-answer/263048#263048) – Jess Jul 22 '14 at 15:21
  • Bryan, thanks so much for the help. I added a separate answer with my Appium specific solution, based on your answer you linked above. Thanks again for the help. – AaronS Jul 22 '14 at 18:39
  • btw, which answer do I accept under this situation? mine or yours? – AaronS Jul 22 '14 at 18:41
  • @AaronS: generally speaking, accept the answer that was most helpful. It encourages people to write good answers. If you want to accept your own answer, there are a couple conditions. See http://blog.stackoverflow.com/2009/01/accept-your-own-answers/ and http://blog.stackoverflow.com/2008/11/why-cant-i-accept-my-own-answer/ – Bryan Oakley Jul 22 '14 at 18:54
2

Here is solution for your problem :)

from robot.libraries.BuiltIn import BuiltIn

def get_current_driver():
    return BuiltIn().get_library_instance('AppiumLibrary')._current_application()
tony
  • 21
  • 2
  • I try your solution and got and error `AttributeError: 'CustomClassAndroid' object has no attribute '_current_application'` here is my complete code from AppiumLibrary import AppiumLibrary from robot.libraries.BuiltIn import BuiltIn class CustomClassAndroid(): def get_current_driver(): return BuiltIn().get_library_instance('AppiumLibrary')._current_application() def get_mobile_battery_info(self): self._current_application().execute_script("mobile: batteryInfo") – J. Doem Oct 03 '21 at 07:58
1

Thanks to Bryan Oakley's response, he pointed me to the solution, which is subclassing the Appium library.

I made the following changes to make it work

My main Robot Framework testing file no longer references the Appium framework, but instead only references my custom python file.

My custom python file now subclasses the Appium library, so I have access to the _current_application().

The custom python class now looks like this:

from AppiumLibrary import AppiumLibrary

class Custom(AppiumLibrary):
    def get_driver_instance(self):
        return self._current_application()

    def KeyboardType(self, textToType):
        self._current_application().execute_script("var vKeyboard = target.frontMostApp().keyboard(); vKeyboard.typeString(\"" + textToType + "\");")

    def PressKeyboardButton(self, buttonToPress):
        self._current_application().execute_script("var vKeyboard = target.frontMostApp().keyboard(); vKeyboard.buttons()['" + buttonToPress + "'].tap();")

The Robot Framework file now looks like this:

TestStart
    Open Application   ${REMOTE_URL}    ${PLATFORM_NAME}    ${PLATFORM_VERSION}    ${DEVICE_NAME}    ${APP}
    Click Element    name=Start
    Click Element    xpath=//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]
    KeyboardType    Test 123
    PressKeyboardButton    Return

Note: at this point, I don't need to set the Open Application to a variable because the subclass automatically has access to it. However, I can now easily set it to a variable later via 'get driver instance' should I need it.

Thanks for the help Bryan!

AaronS
  • 7,649
  • 5
  • 30
  • 56
  • Would you able to share your complete custom python library? I try your solution and got no application open while I can see application already open – J. Doem Oct 03 '21 at 08:02