Not recommended to use Robot Framework with Electron app?

I would like to use robot framework with an electron app, but based on the forum posts I’ve found this is not recommended / quite difficult to setup?

For example, how would I use robot framework to do the equivalent for an electron app like signal-desktop for instance. If I start Signal desktop like so:

signal-desktop --args --rempte-debugging-port=9000

And then I can run for instance this python-script to use selenium-library to print output if the app name is not Signal:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options

options = Options()
options.debugger_address = "localhost:9000"

webdriver_path = '/usr/bin/chromedriver'

service = Service(webdriver_path)

driver = webdriver.Chrome(service=service, options=options)

assert "Signal" in driver.title

driver.quit()

Does anybody know how to initiate something similar with robot framework? In theory after the app is running in a way that exposes it properly it should theoretically work. This doesn’t, because localhost:9000 is not the app as a website:

*** Settings ***

Documentation   Failing test case for integrating Electron with robot framework.

Library         SeleniumLibrary

*** Variables ***
${LOGIN URL}      http://localhost:9000
${BROWSER}        Chrome

*** Test Cases ***
Valid Login
    Open Browser To Login Page
    [Teardown]    Close Browser

*** Keywords ***
Open Browser To Login Page
    Open Browser    ${LOGIN URL}    ${BROWSER}
    Title Should Be    Signal

Instead of open browser, you use Create Webdriver and tell the webdriver where the “chrome binary” is, eg, your electron app. Maybe Testing Electron Applications With Robot Framework's Selenium2Library gives you enough hints ?

Difference between that example of yours is that you started the signal app on your own and pass the correct command line arguments, where as the example in that linked page, the process goes that “use this binary as it would be chrome” so you dont need to start it outside of the rf …


addition edit;

I’ve done quite extensive testing overhaul for electron app and there was 0 issues with testing that with SeleniumLibrary and rf - only issue was getting rid of some sleeps here and there but thats somewhat normal with Selenium in certain cases…

1 Like

Nice to hear it’s possible! I’m still facing issues however…

First, when running that example, syntax have changed:

TypeError: WebDriver.__init__() got an unexpected keyword argument 'desired_capabilities'

I can not figure out how to use the new syntax, I even tested to just change so /usr/bin/chromedriver is a symlink to /usr/bin/signal-desktop, which makes Signal open, but it just freezes after that, does not check the title. I also tested:

*** Settings ***
Library    SeleniumLibrary

*** Test Cases ***
Foo
    Open Browser	None	Chrome	options=binary_location="/usr/bin/signal-desktop"
    Title Should Be    Signal
    [Teardown]    Close All Browsers

However, same result :confused:

You don’t happen to have one of your robot test cases to share? Or do you know the proper syntax for specifying custom path in Create Webdriver without the tests not running after the Electron app is open?

First off - desired_capabilities has been deprecated, either downgrade your selenium (not seleniumlibrary, but python selenium)

Second, you still need chromedriver, you are not changing that, you should be changing the browser binary.

At least way back then, we used chromedriver binary from appium’s release page - but this was 3 years ago. Dunno if thats changed since.

I got a raw hacky version working after reading your two replies and retrying like 100 times. :blush:

(Using poetry) I install the dependencies robotframework, selenium2 and robotframework-selenium2library.

Since I have not figured out how to actually manually set a custom path for chromedriver and chrome I simply move them away from /usr/bin/ temporarily and then I symlink /usr/bin/signal-desktop to /usr/bin/chromium and the needed chromedriver version (122.0.6261.57) to /usr/bin/chromedriver. :see_no_evil:

After that this works:

*** Settings ***
Library    Selenium2Library
Variables    vars.py

*** Test Cases ***
Foo
    Create Webdriver    Chrome    desired_capabilities=${binary_location}
    Title Should Be    Signal
    [Teardown]    Close All Browsers

And vars.py (even though it doesn’t seem to work since I still need to symlink) looks like this:

binary_location = {"goog:chromeOptions": {"binary": "/usr/bin/signal-desktop"}}

So as soon as I figure out the proper way to set the custom binaries (ideally with Selenium3) it’s a proper setup!

There’s 0 need to use Selenium2Library. It does nothing except installs a somewhat random version of actual SeleniumLibrary. Usage of it is not recommended but again, it should still “just work” but its completely unnecessary.

1 Like

If I change to robotframework-seleniumlibrary it uses selenium instead of selenium2. When I run the test Signal launches but it just stays there, it does not continue tot the next step.

If I try to use robotframework-seleniumlibrary and selenium2 (I think that’s what you mean earlier) I get:

Because no versions of selenium2 match >0.1,<0.2
 and selenium2 (0.1) depends on selenium (4.2.0), selenium2 (>=0.1,<0.2) requires selenium (4.2.0).
And because robotframework-seleniumlibrary (6.3.0) depends on selenium (>=4.3.0)
 and no versions of robotframework-seleniumlibrary match >6.3.0,<7.0.0, selenium2 (>=0.1,<0.2) is incompatible with robotframework-seleniumlibrary (>=6.3.0,<7.0.0).
So, because sel2 depends on both robotframework-seleniumlibrary (^6.3.0) and selenium2 (^0.1), version solving failed.

My guess; your package directory is messed up …

robotframework-selenium2library (if you download it from pypi via pip or poetry) will always install the latest robotframework-seleniumlibrary and use what ever keywords it provides. If you have selenium2 installed, its pretty clear that you have already messed up your package installations by installing random packages/versions without actually knowing better.

Also, pretty sure you are not using virtual envs

I am using virtual environment. I was able to switch to robotframework-seleniumlibrary, but only when using an older version. Latest version does not work with selenium2 and without selenium2, signal-desktop just launches, but no tests are run. In order to run the tests I need selenium2 for some reason.

This works though:

Dependencies:

python = "^3.10"
robotframework = "^7.0"
selenium2 = "^0.1"
robotframework-seleniumlibrary = "^3.3.1"  # newer version than this fails because of selenium2-dep.
*** Test Cases ***
Check title
    Init application
    Title Should Be     Signal
    Close All Browsers

*** Keywords ***
Init application
    ${electron_app}= 	Evaluate 	selenium.webdriver.ChromeOptions() 	modules=selenium, selenium.webdriver
    ${electron_app.binary_location}= 	Set Variable 	/usr/bin/signal-desktop
    Create Webdriver 	Chrome 	options=${electron_app} 

And then I symlink the chromedriver to /usr/bin/chromedriver as mentioned earlier, because I have not figured out how to set custom path for that in robot framework syntax. That’s basically the only thing missing now.

And for Library i set SeleniumLibrary. ^

Why do you think you need selenium2 ?

Because when I run the exact same setup without it signal-desktop launches but no tests are run. With selenium2 signal-desktop launches and the tests run.

First off, selenium2 is a extra layer on top of Selenium itself. I originally thought it it would be old release of selenium version 2.xx something …

That said, Essentially what it does for you is that it enforces selenium 4.2.0 to be installed. If you intend to use nothing but SeleniumLibrary, you can omit the installation of selenium2 and just install appropriate version of selenium on your own. Quick try and 4.9.1 should still be fine.

With fresh venv:

pip install robotframework robotframework-seleniumlibrary selenium==4.9.1

Since the original blog post i shared is quite dated and there has been changes in Selenium since then, here’s changes that to blog’s example code:

vars.py

from selenium.webdriver.chrome.options import Options
signal_electron = Options()
signal_electron.binary_location = "/Applications/Signal.app/Contents/MacOS/Signal"

In here, binary location points to executable of signal itself.

test suite

*** Settings ***
Library     SeleniumLibrary
Variables   vars.py

*** Test Cases ***
Foo
    Create Webdriver    Chrome    options=${signal_electron}
    Wait Until Page Contains Element    css=.workspace
    [Teardown]    Close All Browsers

And here, the change was using options instead of desired_capabilities and options is ofcourse generated in vars.py

On top of this, chromedriver binary has to match the electron version. On MacOS, signal has following file: /Applications/Signal.app/Contents/Frameworks/Electron Framework.framework/Resources/Info.plist that has following

        <key>CFBundleVersion</key>
        <string>29.1.5</string>

So current signal is made with electron 29.1.5 so the chromedriver for it can be downloaded from: Release electron v29.1.5 · electron/electron · GitHub

Digging out the version of electron on other platforms is most likely very different…

I placed the downloaded chromedriver from github into my virtual env’s bin directory (Scripts on windows) and ran robot … Worked fine, failed ofcourse cuz as there’s no matches with selector css=.workspace

Eg, no need for Selenium2, with latest robotframework-seleniumlibrary and a bit older version of selenium.

Here’s my installed packages for a reference

attrs==23.2.0
certifi==2024.2.2
h11==0.14.0
idna==3.7
outcome==1.3.0.post0
PySocks==1.7.1
robotframework==7.0
robotframework-pythonlibcore==4.4.1
robotframework-seleniumlibrary==6.3.0
selenium==4.9.1
setuptools==69.5.1
sniffio==1.3.1
sortedcontainers==2.4.0
trio==0.25.0
trio-websocket==0.11.1
typing_extensions==4.11.0
urllib3==2.2.1
wheel==0.43.0
wsproto==1.2.0

Additional information, if you also pass ChromeService to Create Webdriver keyword, there’s no more hangups.

After digging and consulting on selenium slack, vars.py looks something like this:

vars.py

from selenium.webdriver.chrome.options import Options
from selenium.webdriver import ChromeService

signal_service = ChromeService(executable_path=r"/Users/rasjani/src/omat/electron-test/venv/bin/chromedriver")

signal_electron = Options()
signal_electron.binary_location = "/Applications/Signal.app/Contents/MacOS/Signal"

So, there you need to point chromedriver into correct location…

And changes to Create Webdriver look like this;

Create Webdriver    Chrome    options=${signal_electron}    service=${signal_service}

And so at least i have working setup with latest seleniumlibrary and latest selenium without extra troubles.

Full example here; GitHub - rasjani/robotframework-electron-example

4 Likes

Thank you so much for the time put in, I got it working like it should with your help!

(For people in the future in case it’s not clear directly, the dependencies when using the latter solution, i.e. custom chromedriver path, you can use latest of python, robotframework and robotframework-seleniumlibrary. If not setting custom chromedriver (the earlier example), the dependencies are the same, with the exception selenium need to be manually set to version 4.9.1.)

2 Likes